From c7e9f79200ac487f3acda117358d739e042c0893 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 30 Jan 2019 13:55:12 -0800 Subject: [PATCH 001/566] Include the new scale float in min remaining size calculation --- libraries/avatars/src/AvatarData.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 4e95774efb..c733cfa291 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -632,9 +632,11 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent // include jointData if there is room for the most minimal section. i.e. no translations or rotations. IF_AVATAR_SPACE(PACKET_HAS_JOINT_DATA, AvatarDataPacket::minJointDataSize(numJoints)) { - // Allow for faux joints + translation bit-vector: - const ptrdiff_t minSizeForJoint = sizeof(AvatarDataPacket::SixByteQuat) - + jointBitVectorSize + AvatarDataPacket::FAUX_JOINTS_SIZE; + // Minimum space required for another rotation joint - + // size of joint + following translation bit-vector + translation scale + faux joints: + const ptrdiff_t minSizeForJoint = sizeof(AvatarDataPacket::SixByteQuat) + jointBitVectorSize + + sizeof(float) + AvatarDataPacket::FAUX_JOINTS_SIZE; + auto startSection = destinationBuffer; // compute maxTranslationDimension before we send any joint data. @@ -724,6 +726,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent const JointData& data = joints[i]; const JointData& last = lastSentJointData[i]; + // Note minSizeForJoint is conservative since there isn't a following bit-vector + scale. if (packetEnd - destinationBuffer >= minSizeForJoint) { if (!data.translationIsDefaultPose) { if (sendAll || last.translationIsDefaultPose || (!cullSmallChanges && last.translation != data.translation) From b09a9390666707506ba482c2999fe4d54bf3dccf Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 30 Jan 2019 17:03:16 -0800 Subject: [PATCH 002/566] Fix reload mechanic for entity server scripts --- .../src/scripts/EntityScriptServer.cpp | 16 ++++++++-------- .../src/scripts/EntityScriptServer.h | 2 +- .../entities-renderer/src/EntityTreeRenderer.cpp | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index ef0c807bc4..f1a6c97831 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -112,7 +112,6 @@ void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointerunloadEntityScript(entityID); checkAndCallPreload(entityID, true); } } @@ -184,7 +183,6 @@ void EntityScriptServer::updateEntityPPS() { pps = std::min(_maxEntityPPS, pps); } _entityEditSender.setPacketsPerSecond(pps); - qDebug() << QString("Updating entity PPS to: %1 @ %2 PPS per script = %3 PPS").arg(numRunningScripts).arg(_entityPPSPerScript).arg(pps); } void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -525,23 +523,25 @@ void EntityScriptServer::deletingEntity(const EntityItemID& entityID) { void EntityScriptServer::entityServerScriptChanging(const EntityItemID& entityID, bool reload) { if (_entityViewer.getTree() && !_shuttingDown) { - _entitiesScriptEngine->unloadEntityScript(entityID, true); checkAndCallPreload(entityID, reload); } } -void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool reload) { +void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool forceRedownload) { if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptEngine) { EntityItemPointer entity = _entityViewer.getTree()->findEntityByEntityItemID(entityID); EntityScriptDetails details; - bool notRunning = !_entitiesScriptEngine->getEntityScriptDetails(entityID, details); - if (entity && (reload || notRunning || details.scriptText != entity->getServerScripts())) { + bool isRunning = _entitiesScriptEngine->getEntityScriptDetails(entityID, details); + if (entity && (forceRedownload || !isRunning || details.scriptText != entity->getServerScripts())) { + if (isRunning) { + _entitiesScriptEngine->unloadEntityScript(entityID, true); + } + QString scriptUrl = entity->getServerScripts(); if (!scriptUrl.isEmpty()) { scriptUrl = DependencyManager::get()->normalizeURL(scriptUrl); - qCDebug(entity_script_server) << "Loading entity server script" << scriptUrl << "for" << entityID; - _entitiesScriptEngine->loadEntityScript(entityID, scriptUrl, reload); + _entitiesScriptEngine->loadEntityScript(entityID, scriptUrl, forceRedownload); } } } diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index 9c6c4c752e..944fee36a3 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -67,7 +67,7 @@ private: void addingEntity(const EntityItemID& entityID); void deletingEntity(const EntityItemID& entityID); void entityServerScriptChanging(const EntityItemID& entityID, bool reload); - void checkAndCallPreload(const EntityItemID& entityID, bool reload = false); + void checkAndCallPreload(const EntityItemID& entityID, bool forceRedownload = false); void cleanupOldKilledListeners(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c71b296a74..44025fc8f4 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -1048,7 +1048,7 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool QString scriptUrl = entity->getScript(); if ((shouldLoad && unloadFirst) || scriptUrl.isEmpty()) { if (_entitiesScriptEngine) { - _entitiesScriptEngine->unloadEntityScript(entityID); + _entitiesScriptEngine->unloadEntityScript(entityID); } entity->scriptHasUnloaded(); } From e2f82eb94927cc306e802131112c3f0d2fbba6b8 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 31 Jan 2019 09:35:42 -0700 Subject: [PATCH 003/566] Fix assertion on shapeInfo --- .../src/avatars-renderer/Avatar.cpp | 18 ++++++++++-------- libraries/shared/src/ShapeInfo.cpp | 3 ++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 07c1ca9a32..ba5529e1c0 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1733,15 +1733,17 @@ void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) { void Avatar::computeDetailedShapeInfo(ShapeInfo& shapeInfo, int jointIndex) { if (jointIndex > -1 && jointIndex < (int)_multiSphereShapes.size()) { auto& data = _multiSphereShapes[jointIndex].getSpheresData(); - std::vector positions; - std::vector radiuses; - positions.reserve(data.size()); - radiuses.reserve(data.size()); - for (auto& sphere : data) { - positions.push_back(sphere._position); - radiuses.push_back(sphere._radius); + if (data.size() > 0) { + std::vector positions; + std::vector radiuses; + positions.reserve(data.size()); + radiuses.reserve(data.size()); + for (auto& sphere : data) { + positions.push_back(sphere._position); + radiuses.push_back(sphere._radius); + } + shapeInfo.setMultiSphere(positions, radiuses); } - shapeInfo.setMultiSphere(positions, radiuses); } } diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 564d79bfda..c256cf2b76 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -152,7 +152,8 @@ void ShapeInfo::setSphere(float radius) { void ShapeInfo::setMultiSphere(const std::vector& centers, const std::vector& radiuses) { _url = ""; _type = SHAPE_TYPE_MULTISPHERE; - assert(centers.size() == radiuses.size() && centers.size() > 0); + assert(centers.size() == radiuses.size()); + assert(centers.size() > 0); for (size_t i = 0; i < centers.size(); i++) { SphereData sphere = SphereData(centers[i], radiuses[i]); _sphereCollection.push_back(sphere); From fbdae1824505bca0d4b831f17cb5a2c8200b1b98 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 31 Jan 2019 19:37:21 +0100 Subject: [PATCH 004/566] ignore pickRay for zone shape visualizers --- scripts/system/modules/entityShapeVisualizer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/modules/entityShapeVisualizer.js b/scripts/system/modules/entityShapeVisualizer.js index fe950c2e2b..fdf8ee81e7 100644 --- a/scripts/system/modules/entityShapeVisualizer.js +++ b/scripts/system/modules/entityShapeVisualizer.js @@ -135,6 +135,7 @@ EntityShape.prototype = { overlayProperties.canCastShadows = false; overlayProperties.parentID = this.entityID; overlayProperties.collisionless = true; + overlayProperties.ignorePickIntersection = true; this.entity = Entities.addEntity(overlayProperties, "local"); var PROJECTED_MATERIALS = false; this.materialEntity = Entities.addEntity({ From 9082a3f4e5bed7b1f8365652a7dc1a086f2a9a6d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 31 Jan 2019 10:52:48 -0800 Subject: [PATCH 005/566] to the spot on first launch --- interface/src/ui/AddressBarDialog.cpp | 2 +- libraries/networking/src/AddressManager.cpp | 3 ++- libraries/networking/src/AddressManager.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 789a2a2bdf..799d7ea182 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -59,7 +59,7 @@ void AddressBarDialog::loadHome() { auto locationBookmarks = DependencyManager::get(); QString homeLocation = locationBookmarks->addressForBookmark(LocationBookmarks::HOME_BOOKMARK); if (homeLocation == "") { - homeLocation = DEFAULT_HIFI_ADDRESS; + homeLocation = DEFAULT_HOME_ADDRESS; } DependencyManager::get()->handleLookupString(homeLocation); } diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index e6957728e8..9145b4a79e 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -30,7 +30,8 @@ #include "UserActivityLogger.h" #include "udt/PacketHeaders.h" -const QString DEFAULT_HIFI_ADDRESS = "file:///~/serverless/tutorial.json"; +const QString DEFAULT_HIFI_ADDRESS = "hifi://welcome"; +const QString DEFAULT_HOME_ADDRESS = "file:///~/serverless/tutorial.json"; const QString REDIRECT_HIFI_ADDRESS = "file:///~/serverless/redirect.json"; const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager"; const QString SETTINGS_CURRENT_ADDRESS_KEY = "address"; diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 5318822cdc..450b71023c 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -24,6 +24,7 @@ extern const QString DEFAULT_HIFI_ADDRESS; extern const QString REDIRECT_HIFI_ADDRESS; +extern const QString DEFAULT_HOME_ADDRESS; const QString SANDBOX_HIFI_ADDRESS = "hifi://localhost"; const QString INDEX_PATH = "/"; From ca4695377fe5db088a78b4fa78b428842f2665ad Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 31 Jan 2019 22:12:35 +0100 Subject: [PATCH 006/566] also ignore picking on the material entity --- scripts/system/modules/entityShapeVisualizer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/modules/entityShapeVisualizer.js b/scripts/system/modules/entityShapeVisualizer.js index fdf8ee81e7..da28369cdd 100644 --- a/scripts/system/modules/entityShapeVisualizer.js +++ b/scripts/system/modules/entityShapeVisualizer.js @@ -147,6 +147,7 @@ EntityShape.prototype = { priority: 1, materialMappingMode: PROJECTED_MATERIALS ? "projected" : "uv", materialURL: Script.resolvePath("../assets/images/materials/GridPattern.json"), + ignorePickIntersection: true, }, "local"); }, update: function() { From ab6048e92296b5594bf7f30bb09baf33352b7339 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 1 Feb 2019 10:12:04 -0800 Subject: [PATCH 007/566] give tablet root color --- .../qml/hifi/commerce/common/sendAsset/SendAsset.qml | 3 +-- interface/resources/qml/hifi/tablet/TabletRoot.qml | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml index bc8816e0ea..68d437a346 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml @@ -21,11 +21,10 @@ import "../../../../controls" as HifiControls import "../" as HifiCommerceCommon import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. -Rectangle { +Item { HifiConstants { id: hifi; } id: root; - color: hifi.colors.baseGray property int parentAppTitleBarHeight; property int parentAppNavBarHeight; property string currentActiveView: "sendAssetHome"; diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index b19dcbb919..93a23f1b9d 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -3,10 +3,13 @@ import Hifi 1.0 import "../../dialogs" import "../../controls" +import stylesUit 1.0 -Item { +Rectangle { + HifiConstants { id: hifi; } id: tabletRoot objectName: "tabletRoot" + color: hifi.colors.baseGray property string username: "Unknown user" property string usernameShort: "Unknown user" property var rootMenu; From 5f3e3309b8a26fca581c7fbff49addb45764a9d2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Feb 2019 09:47:04 -0800 Subject: [PATCH 008/566] 0.79.0: trust the data in the packet, Luke --- libraries/octree/src/OctreePacketData.cpp | 27 ----------------------- 1 file changed, 27 deletions(-) diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index a79f0a0c2b..8ab502e951 100755 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -729,12 +729,6 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVecto uint16_t length; memcpy(&length, dataBytes, sizeof(uint16_t)); dataBytes += sizeof(length); - - // FIXME - this size check is wrong if we allow larger packets - if (length * sizeof(glm::vec3) > MAX_OCTREE_UNCOMRESSED_PACKET_SIZE) { - result.resize(0); - return sizeof(uint16_t); - } result.resize(length); memcpy(result.data(), dataBytes, length * sizeof(glm::vec3)); return sizeof(uint16_t) + length * sizeof(glm::vec3); @@ -744,14 +738,7 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVecto uint16_t length; memcpy(&length, dataBytes, sizeof(uint16_t)); dataBytes += sizeof(length); - - // FIXME - this size check is wrong if we allow larger packets - if (length * sizeof(glm::quat) > MAX_OCTREE_UNCOMRESSED_PACKET_SIZE) { - result.resize(0); - return sizeof(uint16_t); - } result.resize(length); - const unsigned char *start = dataBytes; for (int i = 0; i < length; i++) { dataBytes += unpackOrientationQuatFromBytes(dataBytes, result[i]); @@ -764,12 +751,6 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto uint16_t length; memcpy(&length, dataBytes, sizeof(uint16_t)); dataBytes += sizeof(length); - - // FIXME - this size check is wrong if we allow larger packets - if (length * sizeof(float) > MAX_OCTREE_UNCOMRESSED_PACKET_SIZE) { - result.resize(0); - return sizeof(uint16_t); - } result.resize(length); memcpy(result.data(), dataBytes, length * sizeof(float)); return sizeof(uint16_t) + length * sizeof(float); @@ -779,14 +760,7 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto uint16_t length; memcpy(&length, dataBytes, sizeof(uint16_t)); dataBytes += sizeof(length); - - // FIXME - this size check is wrong if we allow larger packets - if (length / 8 > MAX_OCTREE_UNCOMRESSED_PACKET_SIZE) { - result.resize(0); - return sizeof(uint16_t); - } result.resize(length); - int bit = 0; unsigned char current = 0; const unsigned char *start = dataBytes; @@ -797,7 +771,6 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto result[i] = (bool)(current & (1 << bit)); bit = (bit + 1) % BITS_IN_BYTE; } - return (dataBytes - start) + (int)sizeof(uint16_t); } From 17cafe7cce02e78fbe748292b646d133b053a00b Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 30 Jan 2019 17:17:39 -0800 Subject: [PATCH 009/566] fix getEntityProperties (cherry picked from commit 6e61c02d04b65bcc32211b7b6e1667d5cab06bcd) --- libraries/entities/src/EntityItem.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 41e4f43a5d..1fb1ebb1bc 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -88,13 +88,13 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_REGISTRATION_POINT; requestedProperties += PROP_CREATED; requestedProperties += PROP_LAST_EDITED_BY; - //requestedProperties += PROP_ENTITY_HOST_TYPE; // not sent over the wire - //requestedProperties += PROP_OWNING_AVATAR_ID; // not sent over the wire + requestedProperties += PROP_ENTITY_HOST_TYPE; + requestedProperties += PROP_OWNING_AVATAR_ID; requestedProperties += PROP_PARENT_ID; requestedProperties += PROP_PARENT_JOINT_INDEX; requestedProperties += PROP_QUERY_AA_CUBE; requestedProperties += PROP_CAN_CAST_SHADOW; - // requestedProperties += PROP_VISIBLE_IN_SECONDARY_CAMERA; // not sent over the wire + requestedProperties += PROP_VISIBLE_IN_SECONDARY_CAMERA; requestedProperties += PROP_RENDER_LAYER; requestedProperties += PROP_PRIMITIVE_MODE; requestedProperties += PROP_IGNORE_PICK_INTERSECTION; @@ -180,6 +180,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); EntityPropertyFlags requestedProperties = getEntityProperties(params); + // these properties are not sent over the wire + requestedProperties -= PROP_ENTITY_HOST_TYPE; + requestedProperties -= PROP_OWNING_AVATAR_ID; + requestedProperties -= PROP_VISIBLE_IN_SECONDARY_CAMERA; + // If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item, // then our entityTreeElementExtraEncodeData should include data about which properties we need to append. if (entityTreeElementExtraEncodeData && entityTreeElementExtraEncodeData->entities.contains(getEntityItemID())) { From c8a0d61fd15dedf0ec28f1970a0c58436f8d1e97 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 5 Feb 2019 17:00:18 -0800 Subject: [PATCH 010/566] don't flushRepeatedMessages() in LogHandler dtor --- libraries/shared/src/LogHandler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 65651373be..c51d9bf611 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -38,7 +38,6 @@ LogHandler::LogHandler() { } LogHandler::~LogHandler() { - flushRepeatedMessages(); } const char* stringForLogType(LogMsgType msgType) { From e0cb37af4b680b3754eb1b6acc92583a0ce64b5a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 7 Feb 2019 10:14:10 -0800 Subject: [PATCH 011/566] fix black albedo coloring (cherry picked from commit 7fe0e5909e7ef4e13eaeb8cfe7b94e5c40f36465) --- libraries/graphics/src/graphics/Material.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index 7befb7e053..7743c4bf50 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -87,7 +87,7 @@ void Material::setUnlit(bool value) { } void Material::setAlbedo(const glm::vec3& albedo, bool isSRGB) { - _key.setAlbedo(glm::any(glm::greaterThan(albedo, glm::vec3(0.0f)))); + _key.setAlbedo(true); _albedo = (isSRGB ? ColorUtils::sRGBToLinearVec3(albedo) : albedo); } From 0e9e4b33321edb0ae14629d206511258f6592d04 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 7 Feb 2019 11:22:33 -0800 Subject: [PATCH 012/566] Fix normal textures not being visible --- .../model-baker/src/model-baker/CalculateMeshTangentsTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp index e94e15507e..c561a745b5 100644 --- a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp +++ b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp @@ -47,7 +47,7 @@ void CalculateMeshTangentsTask::run(const baker::BakeContextPointer& context, co break; } } - if (needTangents) { + if (!needTangents) { continue; } From 466c2261937dd532e493bb1b4ae14525badd15e9 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 7 Feb 2019 11:27:08 -0800 Subject: [PATCH 013/566] Do not use continues in logic checking if we should calculate mesh tangents --- .../model-baker/CalculateMeshTangentsTask.cpp | 53 ++++++++----------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp index c561a745b5..6e12ec546d 100644 --- a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp +++ b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp @@ -13,6 +13,17 @@ #include "ModelMath.h" +bool needTangents(const hfm::Mesh& mesh, const QHash& materials) { + // Check if we actually need to calculate the tangents + for (const auto& meshPart : mesh.parts) { + auto materialIt = materials.find(meshPart.materialID); + if (materialIt != materials.end() && (*materialIt).needTangentSpace()) { + return true; + } + } + return false; +} + void CalculateMeshTangentsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { const auto& normalsPerMesh = input.get0(); const std::vector& meshes = input.get1(); @@ -28,38 +39,20 @@ void CalculateMeshTangentsTask::run(const baker::BakeContextPointer& context, co auto& tangentsOut = tangentsPerMeshOut[tangentsPerMeshOut.size()-1]; // Check if we already have tangents and therefore do not need to do any calculation + // Otherwise confirm if we have the normals needed, and need to calculate the tangents if (!tangentsIn.empty()) { tangentsOut = tangentsIn.toStdVector(); - continue; + } else if (!normals.empty() && needTangents(mesh, materials)) { + tangentsOut.resize(normals.size()); + baker::calculateTangents(mesh, + [&mesh, &normals, &tangentsOut](int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec2* outTexCoords, glm::vec3& outNormal) { + outVertices[0] = mesh.vertices[firstIndex]; + outVertices[1] = mesh.vertices[secondIndex]; + outNormal = normals[firstIndex]; + outTexCoords[0] = mesh.texCoords[firstIndex]; + outTexCoords[1] = mesh.texCoords[secondIndex]; + return &(tangentsOut[firstIndex]); + }); } - - // Check if we have normals, and if not then tangents can't be calculated - if (normals.empty()) { - continue; - } - - // Check if we actually need to calculate the tangents - bool needTangents = false; - for (const auto& meshPart : mesh.parts) { - auto materialIt = materials.find(meshPart.materialID); - if (materialIt != materials.end() && (*materialIt).needTangentSpace()) { - needTangents = true; - break; - } - } - if (!needTangents) { - continue; - } - - tangentsOut.resize(normals.size()); - baker::calculateTangents(mesh, - [&mesh, &normals, &tangentsOut](int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec2* outTexCoords, glm::vec3& outNormal) { - outVertices[0] = mesh.vertices[firstIndex]; - outVertices[1] = mesh.vertices[secondIndex]; - outNormal = normals[firstIndex]; - outTexCoords[0] = mesh.texCoords[firstIndex]; - outTexCoords[1] = mesh.texCoords[secondIndex]; - return &(tangentsOut[firstIndex]); - }); } } From 68480f67607728ae080557fc8ce7b75b378e1c39 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 9 Feb 2019 10:49:18 -0800 Subject: [PATCH 014/566] Replace glm::packSnorm3x10_1x2() with fast SIMD implementation --- .../src/graphics/BufferViewHelpers.cpp | 4 +-- .../src/model-baker/BuildGraphicsMeshTask.cpp | 4 +-- libraries/render-utils/src/Model.cpp | 6 ++-- libraries/shared/src/GLMHelpers.h | 36 +++++++++++++++++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/libraries/graphics/src/graphics/BufferViewHelpers.cpp b/libraries/graphics/src/graphics/BufferViewHelpers.cpp index 4c57abdfd4..301f5d8d73 100644 --- a/libraries/graphics/src/graphics/BufferViewHelpers.cpp +++ b/libraries/graphics/src/graphics/BufferViewHelpers.cpp @@ -257,7 +257,7 @@ template struct GpuVec3ToGlm : GpuToGlmAdapter { static T get(con case gpu::FLOAT: view.edit(index) = value; return true; case gpu::NUINT8: CHECK_SIZE(glm::uint32); view.edit(index) = glm::packUnorm4x8(glm::fvec4(value,0.0f)); return true; case gpu::UINT8: view.edit(index) = value; return true; - case gpu::NINT2_10_10_10: view.edit(index) = glm::packSnorm3x10_1x2(glm::fvec4(value,0.0f)); return true; + case gpu::NINT2_10_10_10: view.edit(index) = glm_packSnorm3x10_1x2(glm::fvec4(value,0.0f)); return true; default: break; } error("GpuVec3ToGlm::set", view, index, hint); return false; } @@ -295,7 +295,7 @@ template struct GpuVec4ToGlm : GpuToGlmAdapter { static T get(const case gpu::FLOAT: view.edit(index) = value; return true; case gpu::HALF: CHECK_SIZE(glm::uint64); view.edit(index) = glm::packHalf4x16(value); return true; case gpu::UINT8: view.edit(index) = value; return true; - case gpu::NINT2_10_10_10: view.edit(index) = glm::packSnorm3x10_1x2(value); return true; + case gpu::NINT2_10_10_10: view.edit(index) = glm_packSnorm3x10_1x2(value); return true; case gpu::NUINT16: CHECK_SIZE(glm::uint64); view.edit(index) = glm::packUnorm4x16(value); return true; case gpu::NUINT8: CHECK_SIZE(glm::uint32); view.edit(index) = glm::packUnorm4x8(value); return true; default: break; diff --git a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp index 370add2c2e..c41431f940 100644 --- a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp +++ b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp @@ -125,8 +125,8 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics #if HFM_PACK_NORMALS const auto normal = normalizeDirForPacking(*normalIt); const auto tangent = normalizeDirForPacking(*tangentIt); - const auto packedNormal = glm::packSnorm3x10_1x2(glm::vec4(normal, 0.0f)); - const auto packedTangent = glm::packSnorm3x10_1x2(glm::vec4(tangent, 0.0f)); + const auto packedNormal = glm_packSnorm3x10_1x2(glm::vec4(normal, 0.0f)); + const auto packedTangent = glm_packSnorm3x10_1x2(glm::vec4(tangent, 0.0f)); #else const auto packedNormal = *normalIt; const auto packedTangent = *tangentIt; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index da8dceb176..9489166f43 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1594,9 +1594,9 @@ void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& pac packed = glm::uvec4( glm::floatBitsToUint(len), - glm::packSnorm3x10_1x2(glm::vec4(normalizedPos, 0.0f)), - glm::packSnorm3x10_1x2(glm::vec4(unpacked.normalOffset, 0.0f)), - glm::packSnorm3x10_1x2(glm::vec4(unpacked.tangentOffset, 0.0f)) + glm_packSnorm3x10_1x2(glm::vec4(normalizedPos, 0.0f)), + glm_packSnorm3x10_1x2(glm::vec4(unpacked.normalOffset, 0.0f)), + glm_packSnorm3x10_1x2(glm::vec4(unpacked.tangentOffset, 0.0f)) ); } diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index e7aaace1ae..e50162d8a4 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -315,6 +315,42 @@ inline void glm_mat4u_mul(const glm::mat4& m1, const glm::mat4& m2, glm::mat4& r #endif } +// +// Fast replacement of glm::packSnorm3x10_1x2() +// The SSE2 version quantizes using round to nearest even. +// The glm version quantizes using round away from zero. +// +inline uint32_t glm_packSnorm3x10_1x2(vec4 const& v) { + + union i10i10i10i2 { + struct { + int x : 10; + int y : 10; + int z : 10; + int w : 2; + } data; + uint32_t pack; + } Result; + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + __m128 vclamp = _mm_min_ps(_mm_max_ps(_mm_loadu_ps((float*)&v[0]), _mm_set1_ps(-1.0f)), _mm_set1_ps(1.0f)); + __m128i vpack = _mm_cvtps_epi32(_mm_mul_ps(vclamp, _mm_setr_ps(511.f, 511.f, 511.f, 1.f))); + + Result.data.x = _mm_cvtsi128_si32(vpack); + Result.data.y = _mm_cvtsi128_si32(_mm_shuffle_epi32(vpack, _MM_SHUFFLE(1,1,1,1))); + Result.data.z = _mm_cvtsi128_si32(_mm_shuffle_epi32(vpack, _MM_SHUFFLE(2,2,2,2))); + Result.data.w = _mm_cvtsi128_si32(_mm_shuffle_epi32(vpack, _MM_SHUFFLE(3,3,3,3))); +#else + ivec4 const Pack(round(clamp(v, -1.0f, 1.0f) * vec4(511.f, 511.f, 511.f, 1.f))); + + Result.data.x = Pack.x; + Result.data.y = Pack.y; + Result.data.z = Pack.z; + Result.data.w = Pack.w; +#endif + return Result.pack; +} + // convert float to int, using round-to-nearest-even (undefined on overflow) inline int fastLrintf(float x) { #if GLM_ARCH & GLM_ARCH_SSE2_BIT From 6f5514b5e3cfe920c3b634c4370c52071eaf30ab Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 9 Feb 2019 10:57:06 -0800 Subject: [PATCH 015/566] Remove dead code --- .../graphics/src/graphics/BufferViewHelpers.h | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/libraries/graphics/src/graphics/BufferViewHelpers.h b/libraries/graphics/src/graphics/BufferViewHelpers.h index 8a48c17007..3635ef64e5 100644 --- a/libraries/graphics/src/graphics/BufferViewHelpers.h +++ b/libraries/graphics/src/graphics/BufferViewHelpers.h @@ -46,30 +46,6 @@ namespace buffer_helpers { gpu::BufferView clone(const gpu::BufferView& input); gpu::BufferView resized(const gpu::BufferView& input, glm::uint32 numElements); - inline void packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint32& packedNormal, glm::uint32& packedTangent) { - auto absNormal = glm::abs(normal); - auto absTangent = glm::abs(tangent); - normal /= glm::max(1e-6f, glm::max(glm::max(absNormal.x, absNormal.y), absNormal.z)); - tangent /= glm::max(1e-6f, glm::max(glm::max(absTangent.x, absTangent.y), absTangent.z)); - normal = glm::clamp(normal, -1.0f, 1.0f); - tangent = glm::clamp(tangent, -1.0f, 1.0f); - normal *= 511.0f; - tangent *= 511.0f; - - glm::detail::i10i10i10i2 normalStruct; - glm::detail::i10i10i10i2 tangentStruct; - normalStruct.data.x = fastLrintf(normal.x); - normalStruct.data.y = fastLrintf(normal.y); - normalStruct.data.z = fastLrintf(normal.z); - normalStruct.data.w = 0; - tangentStruct.data.x = fastLrintf(tangent.x); - tangentStruct.data.y = fastLrintf(tangent.y); - tangentStruct.data.z = fastLrintf(tangent.z); - tangentStruct.data.w = 0; - packedNormal = normalStruct.pack; - packedTangent = tangentStruct.pack; - } - namespace mesh { glm::uint32 forEachVertex(const graphics::MeshPointer& mesh, std::function func); bool setVertexAttributes(const graphics::MeshPointer& mesh, glm::uint32 index, const QVariantMap& attributes); From 7236d63da0c544c4196095dcbeac151fcbb52de6 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 9 Feb 2019 12:16:26 -0800 Subject: [PATCH 016/566] Fix tabs --- libraries/shared/src/GLMHelpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index e50162d8a4..6deae695cd 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -322,7 +322,7 @@ inline void glm_mat4u_mul(const glm::mat4& m1, const glm::mat4& m2, glm::mat4& r // inline uint32_t glm_packSnorm3x10_1x2(vec4 const& v) { - union i10i10i10i2 { + union i10i10i10i2 { struct { int x : 10; int y : 10; From ff746c31413d2aebe4a651dd1681a8cff31f227c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 11 Feb 2019 12:19:33 -0800 Subject: [PATCH 017/566] flag collision group/mask dirty after grab --- libraries/entities/src/EntityItem.cpp | 33 +++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1fb1ebb1bc..777f9ba167 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1897,7 +1897,7 @@ glm::vec3 EntityItem::getUnscaledDimensions() const { void EntityItem::setRotation(glm::quat rotation) { if (getLocalOrientation() != rotation) { setLocalOrientation(rotation); - _flags |= Simulation::DIRTY_ROTATION; + markDirtyFlags(Simulation::DIRTY_ROTATION); forEachDescendant([&](SpatiallyNestablePointer object) { if (object->getNestableType() == NestableType::Entity) { EntityItemPointer entity = std::static_pointer_cast(object); @@ -1927,7 +1927,7 @@ void EntityItem::setVelocity(const glm::vec3& value) { velocity = value; } setLocalVelocity(velocity); - _flags |= Simulation::DIRTY_LINEAR_VELOCITY; + markDirtyFlags(Simulation::DIRTY_LINEAR_VELOCITY); } } } @@ -1982,7 +1982,7 @@ void EntityItem::setAngularVelocity(const glm::vec3& value) { angularVelocity = value; } setLocalAngularVelocity(angularVelocity); - _flags |= Simulation::DIRTY_ANGULAR_VELOCITY; + markDirtyFlags(Simulation::DIRTY_ANGULAR_VELOCITY); } } } @@ -2168,8 +2168,14 @@ bool EntityItem::addAction(EntitySimulationPointer simulation, EntityDynamicPoin void EntityItem::enableNoBootstrap() { if (!(bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) { - _flags |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING; - _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar + markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP); + markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING); + + // NOTE: unlike disableNoBootstrap() below, we do not call simulation->changeEntity() here + // because most enableNoBootstrap() cases are already correctly handled outside this scope + // and I didn't want to add redundant work. + // TODO: cleanup Grabs & dirtySimulationFlags to be more efficient and make more sense. + forEachDescendant([&](SpatiallyNestablePointer child) { if (child->getNestableType() == NestableType::Entity) { EntityItemPointer entity = std::static_pointer_cast(child); @@ -2182,13 +2188,21 @@ void EntityItem::enableNoBootstrap() { void EntityItem::disableNoBootstrap() { if (!stillHasGrabActions()) { - _flags &= ~Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING; - _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar + markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP); + clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING); + + EntityTreePointer entityTree = getTree(); + assert(entityTree); + EntitySimulationPointer simulation = entityTree->getSimulation(); + assert(simulation); + simulation->changeEntity(getThisPointer()); + forEachDescendant([&](SpatiallyNestablePointer child) { if (child->getNestableType() == NestableType::Entity) { EntityItemPointer entity = std::static_pointer_cast(child); entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP); entity->clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING); + simulation->changeEntity(entity); } }); } @@ -2574,7 +2588,7 @@ QList EntityItem::getActionsOfType(EntityDynamicType typeT void EntityItem::locationChanged(bool tellPhysics) { requiresRecalcBoxes(); if (tellPhysics) { - _flags |= Simulation::DIRTY_TRANSFORM; + markDirtyFlags(Simulation::DIRTY_TRANSFORM); EntityTreePointer tree = getTree(); if (tree) { tree->entityChanged(getThisPointer()); @@ -3445,7 +3459,7 @@ void EntityItem::addGrab(GrabPointer grab) { if (useAction) { EntityTreePointer entityTree = getTree(); assert(entityTree); - EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr; + EntitySimulationPointer simulation = entityTree->getSimulation(); assert(simulation); auto actionFactory = DependencyManager::get(); @@ -3494,7 +3508,6 @@ void EntityItem::removeGrab(GrabPointer grab) { setLocalVelocity(glm::vec3(0.0f)); setAngularVelocity(glm::vec3(0.0f)); } - markDirtyFlags(Simulation::DIRTY_MOTION_TYPE); QUuid actionID = grab->getActionID(); if (!actionID.isNull()) { From fab3e5e3fd32a8b61f7c110f045f10eed9cc20ba Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 11 Feb 2019 16:13:56 -0800 Subject: [PATCH 018/566] remember hash of AvatarEntityItemData --- interface/src/avatar/OtherAvatar.cpp | 5 +++++ interface/src/avatar/OtherAvatar.h | 10 ++++++++++ .../avatars-renderer/src/avatars-renderer/Avatar.cpp | 5 ----- .../avatars-renderer/src/avatars-renderer/Avatar.h | 6 ++---- libraries/avatars/src/AvatarData.h | 2 +- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index a3950c8e96..67eb919b73 100755 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -510,6 +510,11 @@ void OtherAvatar::handleChangedAvatarEntityData() { } } stateItr.value().success = success; + if (success) { + stateItr.value().hash = newHash; + } else { + stateItr.value().hash = 0; + } } AvatarEntityIDs recentlyRemovedAvatarEntities = getAndClearRecentlyRemovedIDs(); diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index 3ecd35413f..6461a0107c 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -76,6 +76,16 @@ protected: void onAddAttachedAvatarEntity(const QUuid& id); void onRemoveAttachedAvatarEntity(const QUuid& id); + class AvatarEntityDataHash { + public: + AvatarEntityDataHash(uint32_t h) : hash(h) {}; + uint32_t hash { 0 }; + bool success { false }; + }; + + using MapOfAvatarEntityDataHashes = QMap; + MapOfAvatarEntityDataHashes _avatarEntityDataHashes; + std::vector _attachedAvatarEntities; std::shared_ptr _otherAvatarOrbMeshPlaceholder { nullptr }; OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID }; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index ba5529e1c0..36ad6c6b82 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -305,11 +305,6 @@ void Avatar::setTargetScale(float targetScale) { } } -void Avatar::setAvatarEntityDataChanged(bool value) { - AvatarData::setAvatarEntityDataChanged(value); - _avatarEntityDataHashes.clear(); -} - void Avatar::removeAvatarEntitiesFromTree() { auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index b43fe012b7..39b77f2b65 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -480,8 +480,6 @@ public: virtual void setModelScale(float scale) { _modelScale = scale; } virtual glm::vec3 scaleForChildren() const override { return glm::vec3(getModelScale()); } - virtual void setAvatarEntityDataChanged(bool value) override; - // Show hide the model representation of the avatar virtual void setEnableMeshVisible(bool isEnabled); virtual bool getEnableMeshVisible() const; @@ -647,8 +645,8 @@ protected: bool success { false }; }; - using MapOfAvatarEntityDataHashes = QMap; - MapOfAvatarEntityDataHashes _avatarEntityDataHashes; + //using MapOfAvatarEntityDataHashes = QMap; + //MapOfAvatarEntityDataHashes _avatarEntityDataHashes; uint64_t _lastRenderUpdateTime { 0 }; int _leftPointerGeometryID { 0 }; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index d071b74d6e..63396a59ac 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1147,7 +1147,7 @@ public: */ Q_INVOKABLE virtual void setAvatarEntityData(const AvatarEntityMap& avatarEntityData); - virtual void setAvatarEntityDataChanged(bool value) { _avatarEntityDataChanged = value; } + void setAvatarEntityDataChanged(bool value) { _avatarEntityDataChanged = value; } AvatarEntityIDs getAndClearRecentlyRemovedIDs(); /**jsdoc From a7e28f7a6618bc733c666184ff6b316d437ff515 Mon Sep 17 00:00:00 2001 From: danteruiz Date: Mon, 11 Feb 2019 16:48:34 -0800 Subject: [PATCH 019/566] fix spatially nestable parent overwrite --- interface/src/avatar/OtherAvatar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index a3950c8e96..8ad9c6b121 100755 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -489,6 +489,9 @@ void OtherAvatar::handleChangedAvatarEntityData() { bool success = true; if (entity) { QUuid oldParentID = entity->getParentID(); + const QUuid NULL_ID = QUuid("{00000000-0000-0000-0000-000000000005}"); + entity->setParentID(NULL_ID); + entity->setParentID(oldParentID); if (entityTree->updateEntity(entityID, properties)) { entity->updateLastEditedFromRemote(); } else { From 3ea6241cc91e9eafe224ebcaf1d313d3624dad2a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Feb 2019 12:50:47 -0800 Subject: [PATCH 020/566] send update for AvatarEntity on deleteGrab --- interface/src/avatar/MyAvatar.cpp | 12 ++++++++++++ interface/src/avatar/MyAvatar.h | 1 + .../avatars-renderer/src/avatars-renderer/Avatar.cpp | 7 +++++++ .../avatars-renderer/src/avatars-renderer/Avatar.h | 5 ++--- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 92d9270d20..1c7f2ae400 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -5312,3 +5312,15 @@ void MyAvatar::releaseGrab(const QUuid& grabID) { } } +void MyAvatar::sendPacket(const QUuid& entityID, const EntityItemProperties& properties) const { + auto treeRenderer = DependencyManager::get(); + EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; + if (entityTree) { + entityTree->withWriteLock([&] { + // force an update packet + EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender(); + packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entityID, properties); + }); + } +} + diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0d27988543..c279673486 100755 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1882,6 +1882,7 @@ private: bool didTeleport(); bool getIsAway() const { return _isAway; } void setAway(bool value); + void sendPacket(const QUuid& entityID, const EntityItemProperties& properties) const override; std::mutex _pinnedJointsMutex; std::vector _pinnedJoints; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 36ad6c6b82..c17c7d9fc5 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -363,6 +363,13 @@ bool Avatar::applyGrabChanges() { target->removeGrab(grab); _avatarGrabs.erase(itr); grabAddedOrRemoved = true; + if (isMyAvatar()) { + const EntityItemPointer& entity = std::dynamic_pointer_cast(target); + if (entity && entity->getEntityHostType() == entity::HostType::AVATAR && entity->getSimulationOwner().getID() == getID()) { + EntityItemProperties properties = entity->getProperties(); + sendPacket(entity->getID(), properties); + } + } } else { undeleted.push_back(id); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 39b77f2b65..06942a13d8 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -601,6 +602,7 @@ protected: // protected methods... bool isLookingAtMe(AvatarSharedPointer avatar) const; + virtual void sendPacket(const QUuid& entityID, const EntityItemProperties& properties) const { } bool applyGrabChanges(); void relayJointDataToChildren(); @@ -645,9 +647,6 @@ protected: bool success { false }; }; - //using MapOfAvatarEntityDataHashes = QMap; - //MapOfAvatarEntityDataHashes _avatarEntityDataHashes; - uint64_t _lastRenderUpdateTime { 0 }; int _leftPointerGeometryID { 0 }; int _rightPointerGeometryID { 0 }; From 9f9f512c59f9132bcc3799d573536f85a3df1a5e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Feb 2019 13:22:22 -0800 Subject: [PATCH 021/566] undoing markDirty() overhead because _flags is atomic --- libraries/entities/src/EntityItem.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 777f9ba167..5c423b2fe5 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1897,7 +1897,7 @@ glm::vec3 EntityItem::getUnscaledDimensions() const { void EntityItem::setRotation(glm::quat rotation) { if (getLocalOrientation() != rotation) { setLocalOrientation(rotation); - markDirtyFlags(Simulation::DIRTY_ROTATION); + _flags |= Simulation::DIRTY_ROTATION; forEachDescendant([&](SpatiallyNestablePointer object) { if (object->getNestableType() == NestableType::Entity) { EntityItemPointer entity = std::static_pointer_cast(object); @@ -1927,7 +1927,7 @@ void EntityItem::setVelocity(const glm::vec3& value) { velocity = value; } setLocalVelocity(velocity); - markDirtyFlags(Simulation::DIRTY_LINEAR_VELOCITY); + _flags |= Simulation::DIRTY_LINEAR_VELOCITY; } } } @@ -1982,7 +1982,7 @@ void EntityItem::setAngularVelocity(const glm::vec3& value) { angularVelocity = value; } setLocalAngularVelocity(angularVelocity); - markDirtyFlags(Simulation::DIRTY_ANGULAR_VELOCITY); + _flags |= Simulation::DIRTY_ANGULAR_VELOCITY; } } } @@ -2168,8 +2168,8 @@ bool EntityItem::addAction(EntitySimulationPointer simulation, EntityDynamicPoin void EntityItem::enableNoBootstrap() { if (!(bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) { - markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP); - markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING); + _flags |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING; + _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar // NOTE: unlike disableNoBootstrap() below, we do not call simulation->changeEntity() here // because most enableNoBootstrap() cases are already correctly handled outside this scope @@ -2188,8 +2188,8 @@ void EntityItem::enableNoBootstrap() { void EntityItem::disableNoBootstrap() { if (!stillHasGrabActions()) { - markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP); - clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING); + _flags &= ~Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING; + _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar EntityTreePointer entityTree = getTree(); assert(entityTree); @@ -2588,7 +2588,7 @@ QList EntityItem::getActionsOfType(EntityDynamicType typeT void EntityItem::locationChanged(bool tellPhysics) { requiresRecalcBoxes(); if (tellPhysics) { - markDirtyFlags(Simulation::DIRTY_TRANSFORM); + _flags |= Simulation::DIRTY_TRANSFORM; EntityTreePointer tree = getTree(); if (tree) { tree->entityChanged(getThisPointer()); From d604f9adfb265b9311c2b66a2027256e9cd8b064 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 13 Feb 2019 18:18:47 -0800 Subject: [PATCH 022/566] Add AudioSoloRequest, BulkAvatarTraitsAck; also decode obfuscated protocols --- tools/dissectors/1-hfudt.lua | 98 ++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/tools/dissectors/1-hfudt.lua b/tools/dissectors/1-hfudt.lua index de99c1ce3c..8179276dbb 100644 --- a/tools/dissectors/1-hfudt.lua +++ b/tools/dissectors/1-hfudt.lua @@ -152,7 +152,9 @@ local packet_types = { [97] = "OctreeDataPersist", [98] = "EntityClone", [99] = "EntityQueryInitialResultsComplete", - [100] = "BulkAvatarTraits" + [100] = "BulkAvatarTraits", + [101] = "AudioSoloRequest", + [102] = "BulkAvatarTraitsAck" } local unsourced_packet_types = { @@ -301,55 +303,53 @@ function p_hfudt.dissector(buf, pinfo, tree) -- check if we have part of a message that we need to re-assemble -- before it can be dissected - if obfuscation_bits == 0 then - if message_bit == 1 and message_position ~= 0 then - if fragments[message_number] == nil then - fragments[message_number] = {} - end - - if fragments[message_number][message_part_number] == nil then - fragments[message_number][message_part_number] = {} - end - - -- set the properties for this fragment - fragments[message_number][message_part_number] = { - payload = buf(i):bytes() - } - - -- if this is the last part, set our maximum part number - if message_position == 1 then - fragments[message_number].last_part_number = message_part_number - end - - -- if we have the last part - -- enumerate our parts for this message and see if everything is present - if fragments[message_number].last_part_number ~= nil then - local i = 0 - local has_all = true - - local finalMessage = ByteArray.new() - local message_complete = true - - while i <= fragments[message_number].last_part_number do - if fragments[message_number][i] ~= nil then - finalMessage = finalMessage .. fragments[message_number][i].payload - else - -- missing this part, have to break until we have it - message_complete = false - end - - i = i + 1 - end - - if message_complete then - debug("Message " .. message_number .. " is " .. finalMessage:len()) - payload_to_dissect = ByteArray.tvb(finalMessage, message_number) - end - end - - else - payload_to_dissect = buf(i):tvb() + if message_bit == 1 and message_position ~= 0 then + if fragments[message_number] == nil then + fragments[message_number] = {} end + + if fragments[message_number][message_part_number] == nil then + fragments[message_number][message_part_number] = {} + end + + -- set the properties for this fragment + fragments[message_number][message_part_number] = { + payload = buf(i):bytes() + } + + -- if this is the last part, set our maximum part number + if message_position == 1 then + fragments[message_number].last_part_number = message_part_number + end + + -- if we have the last part + -- enumerate our parts for this message and see if everything is present + if fragments[message_number].last_part_number ~= nil then + local i = 0 + local has_all = true + + local finalMessage = ByteArray.new() + local message_complete = true + + while i <= fragments[message_number].last_part_number do + if fragments[message_number][i] ~= nil then + finalMessage = finalMessage .. fragments[message_number][i].payload + else + -- missing this part, have to break until we have it + message_complete = false + end + + i = i + 1 + end + + if message_complete then + debug("Message " .. message_number .. " is " .. finalMessage:len()) + payload_to_dissect = ByteArray.tvb(finalMessage, message_number) + end + end + + else + payload_to_dissect = buf(i):tvb() end if payload_to_dissect ~= nil then From 20d7e00ea8d0b66d48e18853711ff88ca994f0ce Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Thu, 14 Feb 2019 08:48:37 -0800 Subject: [PATCH 023/566] Standalone Tags - Checkpoint --- interface/resources/qml/hifi/Card.qml | 20 ++++ .../hifi/commerce/marketplace/Marketplace.qml | 5 +- .../commerce/marketplace/MarketplaceItem.qml | 97 +++++++++++++++---- .../marketplace/MarketplaceListItem.qml | 33 ++++++- .../hifi/commerce/purchases/PurchasedItem.qml | 21 ++++ .../qml/hifi/commerce/purchases/Purchases.qml | 2 + 6 files changed, 158 insertions(+), 20 deletions(-) diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index 238c26236f..67abc1c3f9 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -39,6 +39,7 @@ Item { property bool isConcurrency: action === 'concurrency'; property bool isAnnouncement: action === 'announcement'; property bool isStacked: !isConcurrency && drillDownToPlace; + property bool standaloneOptimized: true; property int textPadding: 10; property int smallMargin: 4; @@ -281,7 +282,26 @@ Item { right: parent.right; margins: smallMargin; } + } + HiFiGlyphs { + id: standaloneOptomizedBadge + + anchors { + right: actionIcon.left + verticalCenter: parent.verticalCenter + bottom: parent.bottom; + } + height: root.standaloneOptimized ? 34 : 0 + + visible: standaloneOptimized + + text: hifi.glyphs.hmd + size: 34 + horizontalAlignment: Text.AlignHCenter + color: hifi.colors.blueHighlight + } + function go() { Tablet.playSound(TabletEnums.ButtonClick); goFunction(drillDownToPlace ? ("/places/" + placeName) : ("/user_stories/" + storyId)); diff --git a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml index 0d42cb599e..ba83b0b61f 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml @@ -122,6 +122,8 @@ Rectangle { marketplaceItem.license = result.data.license; marketplaceItem.available = result.data.availability === "available"; marketplaceItem.created_at = result.data.created_at; + marketplaceItem.standaloneOptimized = result.data.standalone_optimized; + marketplaceItem.standaloneVisible = result.data.standalone_optimized || result.data.standalone_incompatible; marketplaceItemScrollView.contentHeight = marketplaceItemContent.height; itemsList.visible = false; marketplaceItemView.visible = true; @@ -534,7 +536,8 @@ Rectangle { price: model.cost available: model.availability === "available" isLoggedIn: root.isLoggedIn; - + standaloneOptimized: model.standalone_optimized + onShowItem: { MarketplaceScriptingInterface.getMarketplaceItem(item_id); } diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml index 0a57e56099..9784e422f1 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml @@ -39,9 +39,11 @@ Rectangle { property string posted: "" property bool available: false property string created_at: "" - property bool isLoggedIn: false; - property int edition: -1; - property bool supports3DHTML: false; + property bool isLoggedIn: false + property int edition: -1 + property bool supports3DHTML: false + property bool standaloneVisible: false + property bool standaloneOptimized: false onCategoriesChanged: { @@ -50,16 +52,6 @@ Rectangle { categoriesListModel.append({"category":category}); }); } - - onDescriptionChanged: { - - if(root.supports3DHTML) { - descriptionTextModel.clear(); - descriptionTextModel.append({text: description}); - } else { - descriptionText.text = description; - } - } onAttributionsChanged: { attributionsModel.clear(); @@ -246,11 +238,38 @@ Rectangle { right: parent.right; top: itemImage.bottom; } - height: categoriesList.y - buyButton.y + categoriesList.height + height: categoriesList.y - badges.y + categoriesList.height function evalHeight() { - height = categoriesList.y - buyButton.y + categoriesList.height; - console.log("HEIGHT: " + height); + height = categoriesList.y - badges.y + categoriesList.height; + } + + Item { + id: badges + + anchors { + left: parent.left + top: parent.top + right: parent.right + } + height: childrenRect.height + + HiFiGlyphs { + id: standaloneOptomizedBadge + + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + height: root.standaloneOptimized ? 34 : 0 + + visible: root.standaloneOptimized + + text: hifi.glyphs.hmd + size: 34 + horizontalAlignment: Text.AlignHCenter + color: hifi.colors.blueHighlight + } } HifiControlsUit.Button { @@ -258,7 +277,7 @@ Rectangle { anchors { right: parent.right - top: parent.top + top: badges.bottom left: parent.left topMargin: 15 } @@ -529,13 +548,55 @@ Rectangle { } } } + + Item { + id: standaloneItem + + anchors { + top: licenseItem.bottom + topMargin: 15 + left: parent.left + right: parent.right + } + height: root.standaloneVisible ? childrenRect.height : 0 + + visible: root.standaloneVisible + + RalewaySemiBold { + id: standaloneLabel + + anchors.top: parent.top + anchors.left: parent.left + width: paintedWidth + height: 20 + + text: root.standaloneOptimized ? "STAND-ALONE OPTIMIZED:" : "STAND-ALONE INCOMPATIBLE:" + size: 14 + color: hifi.colors.lightGrayText + verticalAlignment: Text.AlignVCenter + } + + RalewaySemiBold { + id: standaloneOptimizedText + + anchors.top: standaloneLabel.bottom + anchors.left: parent.left + anchors.topMargin: 5 + width: paintedWidth + + text: root.standaloneOptimized ? "This item is stand-alone optimized" : "This item is incompatible with stand-alone devices" + size: 14 + color: hifi.colors.lightGray + verticalAlignment: Text.AlignVCenter + } + } Item { id: descriptionItem property string text: "" anchors { - top: licenseItem.bottom + top: standaloneItem.bottom topMargin: 15 left: parent.left right: parent.right diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml index 2f37637e40..9da6d8552e 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml @@ -35,7 +35,8 @@ Rectangle { property string category: "" property int price: 0 property bool available: false - property bool isLoggedIn: false; + property bool isLoggedIn: false + property bool standaloneOptimized: false signal buy() signal showItem() @@ -288,8 +289,38 @@ Rectangle { onClicked: root.categoryClicked(root.category); } } + Item { + id: badges + + anchors { + left: parent.left + top: categoryLabel.bottom + right: buyButton.left + } + height: childrenRect.height + + HiFiGlyphs { + id: standaloneOptomizedBadge + + anchors { + left: parent.left + leftMargin: 15 + verticalCenter: parent.verticalCenter + + } + height: 24 + + visible: root.standaloneOptimized + + text: hifi.glyphs.hmd + size: 24 + horizontalAlignment: Text.AlignHCenter + color: hifi.colors.blueHighlight + } + } HifiControlsUit.Button { + id: buyButton anchors { right: parent.right top: parent.top diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index df6e216b32..ec49b596bc 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -50,6 +50,8 @@ Item { property string upgradeTitle; property bool updateAvailable: root.updateItemId && root.updateItemId !== ""; property bool valid; + property bool standaloneOptimized; + property bool standaloneIncompatible; property string originalStatusText; property string originalStatusColor; @@ -838,6 +840,25 @@ Item { root.sendToPurchases({ method: 'flipCard' }); } } + } + + HiFiGlyphs { + id: standaloneOptomizedBadge + + anchors { + right: parent.right + bottom: parent.bottom + rightMargin: 15 + bottomMargin:12 + } + height: root.standaloneOptimized ? 34 : 0 + + visible: root.standaloneOptimized + + text: hifi.glyphs.hmd + size: 34 + horizontalAlignment: Text.AlignHCenter + color: hifi.colors.blueHighlight } } diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index dc892e6640..a5446202a8 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -553,6 +553,8 @@ Rectangle { upgradeTitle: model.upgrade_title; itemType: model.item_type; valid: model.valid; + standaloneOptimized: model.standalone_optimized + standaloneIncompatible: model.standalone_incompatible anchors.topMargin: 10; anchors.bottomMargin: 10; From be98fb1ac763b5ad305ab0819cebb38f17afb9b7 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 15 Feb 2019 11:21:40 -0800 Subject: [PATCH 024/566] Standalone Tags - checkpoint --- .../InspectionCertificate.qml | 63 +++++++++++++++++-- .../hifi/commerce/purchases/PurchasedItem.qml | 13 +++- .../qml/hifi/commerce/purchases/Purchases.qml | 19 +++++- interface/src/Application.cpp | 8 +++ .../PlatformInfoScriptingInterface.cpp | 12 +++- .../PlatformInfoScriptingInterface.h | 8 ++- .../shared/src/shared/GlobalAppProperties.cpp | 1 + .../shared/src/shared/GlobalAppProperties.h | 1 + 8 files changed, 113 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index 8ca34af28a..16faf2feb7 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -30,6 +30,8 @@ Rectangle { property string dateAcquired: "--"; property string itemCost: "--"; property string marketplace_item_id: ""; + property bool standaloneOptimized: false; + property bool standaloneIncompatible: false; property string certTitleTextColor: hifi.colors.darkGray; property string certTextColor: hifi.colors.white; property string infoTextColor: hifi.colors.blueAccent; @@ -71,6 +73,8 @@ Rectangle { } else { root.marketplace_item_id = result.data.marketplace_item_id; root.isMyCert = result.isMyCert ? result.isMyCert : false; + root.standaloneOptimized = result.data.standalone_optimized; + root.standaloneIncompatible = result.data.standalone_incompatible; if (root.certInfoReplaceMode > 3) { root.itemName = result.data.marketplace_item_name; @@ -421,6 +425,24 @@ Rectangle { anchors.rightMargin: 24; height: root.useGoldCert ? 220 : 372; + HiFiGlyphs { + id: standaloneOptomizedBadge + + anchors { + right: parent.right + top: ownedByHeader.top + rightMargin: 15 + topMargin: 28 + } + + visible: root.standaloneOptimized + + text: hifi.glyphs.hmd + size: 34 + horizontalAlignment: Text.AlignHCenter + color: hifi.colors.blueHighlight + } + RalewayRegular { id: errorText; visible: !root.useGoldCert; @@ -467,6 +489,7 @@ Rectangle { color: root.infoTextColor; elide: Text.ElideRight; } + AnonymousProRegular { id: isMyCertText; visible: root.isMyCert && ownedBy.text !== "--" && ownedBy.text !== ""; @@ -485,14 +508,46 @@ Rectangle { verticalAlignment: Text.AlignVCenter; } + RalewayRegular { + id: standaloneHeader; + text: root.standaloneOptimized ? "STAND-ALONE OPTIMIZED" : "STAND-ALONE INCOMPATIBLE"; + // Text size + size: 16; + // Anchors + anchors.top: ownedBy.bottom; + anchors.topMargin: 15; + anchors.left: parent.left; + anchors.right: parent.right; + visible: root.standaloneOptimized || root.standaloneIncompatible; + height: visible ? paintedHeight : 0; + // Style + color: hifi.colors.darkGray; + } + + RalewayRegular { + id: standaloneText; + text: root.standaloneOptimized ? "This item is stand-alone optimized" : "This item is incompatible with stand-alone devices"; + // Text size + size: 18; + // Anchors + anchors.top: standaloneHeader.bottom; + anchors.topMargin: 8; + anchors.left: standaloneHeader.left; + visible: root.standaloneOptimized || root.standaloneIncompatible; + height: visible ? paintedHeight : 0; + // Style + color: root.infoTextColor; + elide: Text.ElideRight; + } + RalewayRegular { id: dateAcquiredHeader; text: "ACQUISITION DATE"; // Text size size: 16; // Anchors - anchors.top: ownedBy.bottom; - anchors.topMargin: 28; + anchors.top: standaloneText.bottom; + anchors.topMargin: 20; anchors.left: parent.left; anchors.right: parent.horizontalCenter; anchors.rightMargin: 8; @@ -521,8 +576,8 @@ Rectangle { // Text size size: 16; // Anchors - anchors.top: ownedBy.bottom; - anchors.topMargin: 28; + anchors.top: standaloneText.bottom; + anchors.topMargin: 20; anchors.left: parent.horizontalCenter; anchors.right: parent.right; height: paintedHeight; diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index ec49b596bc..22792e5727 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -405,7 +405,9 @@ Item { id: permissionExplanationText; anchors.fill: parent; text: { - if (root.itemType === "contentSet") { + if (root.standaloneIncompatible) { + "This item is incompatible with stand-alone devices. Learn more"; + } else if (root.itemType === "contentSet") { "You do not have 'Replace Content' permissions in this domain. Learn more"; } else if (root.itemType === "entity") { "You do not have 'Rez Certified' permissions in this domain. Learn more"; @@ -419,7 +421,11 @@ Item { verticalAlignment: Text.AlignVCenter; onLinkActivated: { - sendToPurchases({method: 'showPermissionsExplanation', itemType: root.itemType}); + if(link == "#standaloneIncompatible") { + sendToPurchases({method: 'showStandaloneIncompatibleExplanation'}); + } else { + sendToPurchases({method: 'showPermissionsExplanation', itemType: root.itemType}); + } } } } @@ -701,7 +707,8 @@ Item { anchors.bottomMargin: 8; width: 160; height: 40; - enabled: root.hasPermissionToRezThis && + enabled: !root.standaloneIncompatible && + root.hasPermissionToRezThis && MyAvatar.skeletonModelURL !== root.itemHref && !root.wornEntityID && root.valid; diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index a5446202a8..4b285e5402 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -12,7 +12,7 @@ // import Hifi 1.0 as Hifi -import QtQuick 2.5 +import QtQuick 2.9 import stylesUit 1.0 import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls @@ -33,6 +33,7 @@ Rectangle { property bool purchasesReceived: false; property bool punctuationMode: false; property bool isDebuggingFirstUseTutorial: false; + property bool isStandalone: false; property string installedApps; property bool keyboardRaised: false; property int numUpdatesAvailable: 0; @@ -44,6 +45,7 @@ Rectangle { purchasesModel.getFirstPage(); Commerce.getAvailableUpdates(); } + Connections { target: Commerce; @@ -110,6 +112,11 @@ Rectangle { } } + Component.onCompleted: { + isStandalone = PlatformInfo.isStandalone(); + console.log(isStandalone ? "IS STANDALONE" : "ISN'T STANDALONE"); + } + HifiCommerceCommon.CommerceLightbox { id: lightboxPopup; z: 999; @@ -554,7 +561,7 @@ Rectangle { itemType: model.item_type; valid: model.valid; standaloneOptimized: model.standalone_optimized - standaloneIncompatible: model.standalone_incompatible + standaloneIncompatible: root.isStandalone && model.standalone_incompatible anchors.topMargin: 10; anchors.bottomMargin: 10; @@ -675,6 +682,14 @@ Rectangle { lightboxPopup.visible = false; } lightboxPopup.visible = true; + } else if (msg.method === "showStandaloneIncompatibleExplanation") { + lightboxPopup.titleText = "Stand-alone Incompatible"; + lightboxPopup.bodyText = "The item is incompatible with stand-alone devices."; + lightboxPopup.button1text = "CLOSE"; + lightboxPopup.button1method = function() { + lightboxPopup.visible = false; + } + lightboxPopup.visible = true; } else if (msg.method === "setFilterText") { filterBar.text = msg.filterText; } else if (msg.method === "flipCard") { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1029398794..bdb19b7c90 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -768,6 +768,11 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { bool isStore = cmdOptionExists(argc, const_cast(argv), OCULUS_STORE_ARG); qApp->setProperty(hifi::properties::OCULUS_STORE, isStore); + // emulate standalone device + static const auto STANDALONE_ARG = "--standalone"; + bool isStandalone = cmdOptionExists(argc, const_cast(argv), STANDALONE_ARG); + qApp->setProperty(hifi::properties::STANDALONE, isStandalone); + // Ignore any previous crashes if running from command line with a test script. bool inTestMode { false }; for (int i = 0; i < argc; ++i) { @@ -3029,6 +3034,9 @@ void Application::initializeUi() { }; OffscreenQmlSurface::addWhitelistContextHandler({ QUrl{ "hifi/commerce/marketplace/Marketplace.qml" }, + QUrl{ "hifi/commerce/purchases/Purchases.qml" }, + QUrl{ "hifi/commerce/wallet/Wallet.qml" }, + QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, }, platformInfoCallback); QmlContextCallback ttsCallback = [](QQmlContext* context) { diff --git a/interface/src/scripting/PlatformInfoScriptingInterface.cpp b/interface/src/scripting/PlatformInfoScriptingInterface.cpp index b390ab7119..89d609810c 100644 --- a/interface/src/scripting/PlatformInfoScriptingInterface.cpp +++ b/interface/src/scripting/PlatformInfoScriptingInterface.cpp @@ -7,7 +7,7 @@ // #include "PlatformInfoScriptingInterface.h" #include "Application.h" - +#include #include #ifdef Q_OS_WIN @@ -138,6 +138,14 @@ bool PlatformInfoScriptingInterface::has3DHTML() { #if defined(Q_OS_ANDROID) return false; #else - return true; + return !qApp->property(hifi::properties::STANDALONE).toBool(); +#endif +} + +bool PlatformInfoScriptingInterface::isStandalone() { +#if defined(Q_OS_ANDROID) + return false; +#else + return qApp->property(hifi::properties::STANDALONE).toBool(); #endif } diff --git a/interface/src/scripting/PlatformInfoScriptingInterface.h b/interface/src/scripting/PlatformInfoScriptingInterface.h index aece09b008..31f0058585 100644 --- a/interface/src/scripting/PlatformInfoScriptingInterface.h +++ b/interface/src/scripting/PlatformInfoScriptingInterface.h @@ -68,9 +68,15 @@ public slots: /**jsdoc * Returns true if device supports 3d HTML - * @function Window.hasRift + * @function Window.has3DHTML * @returns {boolean} true if device supports 3d HTML, otherwise false.*/ bool has3DHTML(); + + /**jsdoc + * Returns true if device is standalone + * @function Window.hasRift + * @returns {boolean} true if device is a standalone device, otherwise false.*/ + bool isStandalone(); }; #endif // hifi_PlatformInfoScriptingInterface_h diff --git a/libraries/shared/src/shared/GlobalAppProperties.cpp b/libraries/shared/src/shared/GlobalAppProperties.cpp index 54e50da3ea..1fd6c191b2 100644 --- a/libraries/shared/src/shared/GlobalAppProperties.cpp +++ b/libraries/shared/src/shared/GlobalAppProperties.cpp @@ -14,6 +14,7 @@ namespace hifi { namespace properties { const char* STEAM = "com.highfidelity.launchedFromSteam"; const char* LOGGER = "com.highfidelity.logger"; const char* OCULUS_STORE = "com.highfidelity.oculusStore"; + const char* STANDALONE = "com.highfidelity.standalone"; const char* TEST = "com.highfidelity.test"; const char* TRACING = "com.highfidelity.tracing"; const char* HMD = "com.highfidelity.hmd"; diff --git a/libraries/shared/src/shared/GlobalAppProperties.h b/libraries/shared/src/shared/GlobalAppProperties.h index 174be61939..6809d5530a 100644 --- a/libraries/shared/src/shared/GlobalAppProperties.h +++ b/libraries/shared/src/shared/GlobalAppProperties.h @@ -16,6 +16,7 @@ namespace hifi { namespace properties { extern const char* STEAM; extern const char* LOGGER; extern const char* OCULUS_STORE; + extern const char* STANDALONE; extern const char* TEST; extern const char* TRACING; extern const char* HMD; From 7446fa9e7eb81ae3476b70baea885518b6cc54a9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Feb 2019 11:21:06 -0800 Subject: [PATCH 025/566] allow mesh shapes to use MOTION_TYPE_KINEMATIC --- libraries/physics/src/EntityMotionState.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index ce9cb20c21..91c4c43c1d 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -205,6 +205,16 @@ PhysicsMotionType EntityMotionState::computePhysicsMotionType() const { if (_entity->getShapeType() == SHAPE_TYPE_STATIC_MESH || (_body && _body->getCollisionShape()->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)) { + if (_entity->isMoving()) { + // DANGER: Bullet doesn't support non-zero velocity for these shapes --> collision details may be wrong + // in ways that allow other DYNAMIC objects to tunnel/penetrate/snag. + // However, in practice low-velocity collisions work OK most of the time, and if we enforce these objects + // to be MOTION_TYPE_STATIC then some other bugs can be worse (e.g. when Grabbing --> Grab Action fails) + // so we're making a tradeoff here. + // TODO: The Correct Solution is to NOT use btBvhTriangleMesh shape for moving objects and instead compute the convex + // decomposition and build a btCompoundShape with convex sub-shapes. + return MOTION_TYPE_KINEMATIC; + } return MOTION_TYPE_STATIC; } From e46b9479131bd6ffa1840ced1de938918b14797d Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 15 Feb 2019 15:31:11 -0800 Subject: [PATCH 026/566] properly disable draggable numbers, fix disable script and collision sound --- scripts/system/html/js/entityProperties.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index c1a8f363b5..32b576c1f5 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1485,6 +1485,8 @@ const ENTITY_SCRIPT_STATUS = { unloaded: "Unloaded" }; +const ENABLE_DISABLE_SELECTOR = "input, textarea, span, .dropdown dl, .color-picker"; + const PROPERTY_NAME_DIVISION = { GROUP: 0, PROPERTY: 1, @@ -1584,8 +1586,7 @@ function disableChildren(el, selector) { } function enableProperties() { - enableChildren(document.getElementById("properties-list"), - "input, textarea, checkbox, .dropdown dl, .color-picker , .draggable-number.text"); + enableChildren(document.getElementById("properties-list"), ENABLE_DISABLE_SELECTOR); enableChildren(document, ".colpick"); let elLocked = getPropertyInputElement("locked"); @@ -1596,8 +1597,7 @@ function enableProperties() { } function disableProperties() { - disableChildren(document.getElementById("properties-list"), - "input, textarea, checkbox, .dropdown dl, .color-picker, .draggable-number.text"); + disableChildren(document.getElementById("properties-list"), ENABLE_DISABLE_SELECTOR); disableChildren(document, ".colpick"); for (let pickKey in colorPickers) { colorPickers[pickKey].colpickHide(); @@ -3349,8 +3349,8 @@ function loaded() { let shouldHide = selectedEntityProperties.certificateID !== ""; if (shouldHide) { propertyValue = "** Certified **"; + property.elInput.disabled = true; } - property.elInput.disabled = shouldHide; } let isPropertyNotNumber = false; From 46768c2a6e516d6be213839939f4663cc9bd1f36 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sat, 16 Feb 2019 00:42:19 +0100 Subject: [PATCH 027/566] remove the code that prevented the crash from happening, since it is not reproducible anymore --- scripts/system/modules/createWindow.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/system/modules/createWindow.js b/scripts/system/modules/createWindow.js index 0c4412abfb..7369cf91f8 100644 --- a/scripts/system/modules/createWindow.js +++ b/scripts/system/modules/createWindow.js @@ -125,9 +125,6 @@ module.exports = (function() { Script.scriptEnding.connect(this, function() { this.window.close(); - // FIXME: temp solution for reload crash (MS18269), - // we should decide on proper object ownership strategy for InteractiveWindow API - this.window = null; }); }, setVisible: function(visible) { From 59a1e92dd8641aa630c0dc7106449ca66eeae573 Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 15 Feb 2019 16:25:04 -0800 Subject: [PATCH 028/566] fix git ignore for avatar exporter --- .gitignore | 9 +++------ tools/unity-avatar-exporter/Assets/Editor.meta | 8 -------- .../Assets/Editor/AvatarExporter.cs.meta | 11 ----------- tools/unity-avatar-exporter/Assets/README.txt.meta | 7 ------- 4 files changed, 3 insertions(+), 32 deletions(-) delete mode 100644 tools/unity-avatar-exporter/Assets/Editor.meta delete mode 100644 tools/unity-avatar-exporter/Assets/Editor/AvatarExporter.cs.meta delete mode 100644 tools/unity-avatar-exporter/Assets/README.txt.meta diff --git a/.gitignore b/.gitignore index 5a965b494c..e8527bbaf4 100644 --- a/.gitignore +++ b/.gitignore @@ -98,12 +98,9 @@ tools/jsdoc/package-lock.json # Python compile artifacts **/__pycache__ -# ignore unneeded unity project files for avatar exporter -tools/unity-avatar-exporter/Library -tools/unity-avatar-exporter/Logs -tools/unity-avatar-exporter/Packages -tools/unity-avatar-exporter/ProjectSettings -tools/unity-avatar-exporter/Temp +# ignore local unity project files for avatar exporter +tools/unity-avatar-exporter + server-console/package-lock.json vcpkg/ /tools/nitpick/compiledResources diff --git a/tools/unity-avatar-exporter/Assets/Editor.meta b/tools/unity-avatar-exporter/Assets/Editor.meta deleted file mode 100644 index cf7dcf12dd..0000000000 --- a/tools/unity-avatar-exporter/Assets/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 02111c50e71dd664da8ad5c6a6eca767 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter.cs.meta b/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter.cs.meta deleted file mode 100644 index 373aecc6a8..0000000000 --- a/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 00403fdc52187214c8418bc0a7f387e2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/tools/unity-avatar-exporter/Assets/README.txt.meta b/tools/unity-avatar-exporter/Assets/README.txt.meta deleted file mode 100644 index 148fd21fdd..0000000000 --- a/tools/unity-avatar-exporter/Assets/README.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 30b2b6221fd08234eb07c4d6d525d32e -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: From 304f993391b9f187e7b079b837fb570175485a62 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Feb 2019 16:50:45 -0800 Subject: [PATCH 029/566] remove enforcement of MOTION_TYPE_STATIC for mesh shapes --- libraries/physics/src/EntityMotionState.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 91c4c43c1d..4d210c96c5 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -203,21 +203,6 @@ PhysicsMotionType EntityMotionState::computePhysicsMotionType() const { } assert(entityTreeIsLocked()); - if (_entity->getShapeType() == SHAPE_TYPE_STATIC_MESH - || (_body && _body->getCollisionShape()->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)) { - if (_entity->isMoving()) { - // DANGER: Bullet doesn't support non-zero velocity for these shapes --> collision details may be wrong - // in ways that allow other DYNAMIC objects to tunnel/penetrate/snag. - // However, in practice low-velocity collisions work OK most of the time, and if we enforce these objects - // to be MOTION_TYPE_STATIC then some other bugs can be worse (e.g. when Grabbing --> Grab Action fails) - // so we're making a tradeoff here. - // TODO: The Correct Solution is to NOT use btBvhTriangleMesh shape for moving objects and instead compute the convex - // decomposition and build a btCompoundShape with convex sub-shapes. - return MOTION_TYPE_KINEMATIC; - } - return MOTION_TYPE_STATIC; - } - if (_entity->getLocked()) { if (_entity->isMoving()) { return MOTION_TYPE_KINEMATIC; From 2fdc9bce7734ff32a424576bac580a3638b4d8c9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Feb 2019 16:59:18 -0800 Subject: [PATCH 030/566] remove velocity restrictions on SHAPE_TYPE_STATIC_MESH --- libraries/entities/src/EntityItem.cpp | 78 +++++++++++---------------- 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 2c6d679b46..049b46ec7e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1912,25 +1912,19 @@ void EntityItem::setRotation(glm::quat rotation) { void EntityItem::setVelocity(const glm::vec3& value) { glm::vec3 velocity = getLocalVelocity(); if (velocity != value) { - if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { - if (velocity != Vectors::ZERO) { - setLocalVelocity(Vectors::ZERO); - } - } else { - float speed = glm::length(value); - if (!glm::isnan(speed)) { - const float MIN_LINEAR_SPEED = 0.001f; - const float MAX_LINEAR_SPEED = 270.0f; // 3m per step at 90Hz - if (speed < MIN_LINEAR_SPEED) { - velocity = ENTITY_ITEM_ZERO_VEC3; - } else if (speed > MAX_LINEAR_SPEED) { - velocity = (MAX_LINEAR_SPEED / speed) * value; - } else { - velocity = value; - } - setLocalVelocity(velocity); - _flags |= Simulation::DIRTY_LINEAR_VELOCITY; + float speed = glm::length(value); + if (!glm::isnan(speed)) { + const float MIN_LINEAR_SPEED = 0.001f; + const float MAX_LINEAR_SPEED = 270.0f; // 3m per step at 90Hz + if (speed < MIN_LINEAR_SPEED) { + velocity = ENTITY_ITEM_ZERO_VEC3; + } else if (speed > MAX_LINEAR_SPEED) { + velocity = (MAX_LINEAR_SPEED / speed) * value; + } else { + velocity = value; } + setLocalVelocity(velocity); + _flags |= Simulation::DIRTY_LINEAR_VELOCITY; } } } @@ -1948,19 +1942,15 @@ void EntityItem::setDamping(float value) { void EntityItem::setGravity(const glm::vec3& value) { withWriteLock([&] { if (_gravity != value) { - if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { - _gravity = Vectors::ZERO; - } else { - float magnitude = glm::length(value); - if (!glm::isnan(magnitude)) { - const float MAX_ACCELERATION_OF_GRAVITY = 10.0f * 9.8f; // 10g - if (magnitude > MAX_ACCELERATION_OF_GRAVITY) { - _gravity = (MAX_ACCELERATION_OF_GRAVITY / magnitude) * value; - } else { - _gravity = value; - } - _flags |= Simulation::DIRTY_LINEAR_VELOCITY; + float magnitude = glm::length(value); + if (!glm::isnan(magnitude)) { + const float MAX_ACCELERATION_OF_GRAVITY = 10.0f * 9.8f; // 10g + if (magnitude > MAX_ACCELERATION_OF_GRAVITY) { + _gravity = (MAX_ACCELERATION_OF_GRAVITY / magnitude) * value; + } else { + _gravity = value; } + _flags |= Simulation::DIRTY_LINEAR_VELOCITY; } } }); @@ -1969,23 +1959,19 @@ void EntityItem::setGravity(const glm::vec3& value) { void EntityItem::setAngularVelocity(const glm::vec3& value) { glm::vec3 angularVelocity = getLocalAngularVelocity(); if (angularVelocity != value) { - if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { - setLocalAngularVelocity(Vectors::ZERO); - } else { - float speed = glm::length(value); - if (!glm::isnan(speed)) { - const float MIN_ANGULAR_SPEED = 0.0002f; - const float MAX_ANGULAR_SPEED = 9.0f * TWO_PI; // 1/10 rotation per step at 90Hz - if (speed < MIN_ANGULAR_SPEED) { - angularVelocity = ENTITY_ITEM_ZERO_VEC3; - } else if (speed > MAX_ANGULAR_SPEED) { - angularVelocity = (MAX_ANGULAR_SPEED / speed) * value; - } else { - angularVelocity = value; - } - setLocalAngularVelocity(angularVelocity); - _flags |= Simulation::DIRTY_ANGULAR_VELOCITY; + float speed = glm::length(value); + if (!glm::isnan(speed)) { + const float MIN_ANGULAR_SPEED = 0.0002f; + const float MAX_ANGULAR_SPEED = 9.0f * TWO_PI; // 1/10 rotation per step at 90Hz + if (speed < MIN_ANGULAR_SPEED) { + angularVelocity = ENTITY_ITEM_ZERO_VEC3; + } else if (speed > MAX_ANGULAR_SPEED) { + angularVelocity = (MAX_ANGULAR_SPEED / speed) * value; + } else { + angularVelocity = value; } + setLocalAngularVelocity(angularVelocity); + _flags |= Simulation::DIRTY_ANGULAR_VELOCITY; } } } From 50a1e07ed275fec230f771663bea8536b81317bb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 18 Feb 2019 18:32:49 +1300 Subject: [PATCH 031/566] Stub missing MyAvatar, Avatar, and Agent functions and properties JSDoc --- .../src/avatars/ScriptableAvatar.h | 3 + interface/src/avatar/MyAvatar.h | 76 ++++++++++++++----- .../src/avatars-renderer/Avatar.h | 6 ++ 3 files changed, 68 insertions(+), 17 deletions(-) diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index e93be897d5..4562ad6134 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -213,6 +213,9 @@ public: Q_INVOKABLE void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) override; public slots: + /**jsdoc + * @function MyAvatar.update + */ void update(float deltatime); /**jsdoc diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 984d7b297b..4e75c93403 100755 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -69,6 +69,7 @@ class MyAvatar : public Avatar { * @hifi-avatar * * @property {Vec3} qmlPosition - A synonym for position for use by QML. + * * @property {boolean} shouldRenderLocally=true - If true then your avatar is rendered for you in Interface, * otherwise it is not rendered for you (but it is still rendered for other users). * @property {Vec3} motorVelocity=Vec3.ZERO - The target velocity of your avatar to be achieved by a scripted motor. @@ -90,29 +91,38 @@ class MyAvatar : public Avatar { * @property {number} audioListenerModeCamera=1 - The audio listening position is at the camera. Read-only. * @property {number} audioListenerModeCustom=2 - The audio listening position is at a the position specified by set by the * customListenPosition and customListenOrientation property values. Read-only. + * @property {Vec3} customListenPosition=Vec3.ZERO - The listening position used when the audioListenerMode + * property value is audioListenerModeCustom. + * @property {Quat} customListenOrientation=Quat.IDENTITY - The listening orientation used when the + * audioListenerMode property value is audioListenerModeCustom. * @property {boolean} hasScriptedBlendshapes=false - Blendshapes will be transmitted over the network if set to true. * @property {boolean} hasProceduralBlinkFaceMovement=true - procedural blinking will be turned on if set to true. * @property {boolean} hasProceduralEyeFaceMovement=true - procedural eye movement will be turned on if set to true. * @property {boolean} hasAudioEnabledFaceMovement=true - If set to true, voice audio will move the mouth Blendshapes while MyAvatar.hasScriptedBlendshapes is enabled. - * @property {Vec3} customListenPosition=Vec3.ZERO - The listening position used when the audioListenerMode - * property value is audioListenerModeCustom. - * @property {Quat} customListenOrientation=Quat.IDENTITY - The listening orientation used when the - * audioListenerMode property value is audioListenerModeCustom. + * @property {number} rotationRecenterFilterLength + * @property {number} rotationThreshold + * @property {boolean} enableStepResetRotation + * @property {boolean} enableDrawAverageFacing + * * @property {Vec3} leftHandPosition - The position of the left hand in avatar coordinates if it's being positioned by * controllers, otherwise {@link Vec3(0)|Vec3.ZERO}. Read-only. * @property {Vec3} rightHandPosition - The position of the right hand in avatar coordinates if it's being positioned by * controllers, otherwise {@link Vec3(0)|Vec3.ZERO}. Read-only. - * @property {Vec3} leftHandTipPosition - The position 30cm offset from the left hand in avatar coordinates if it's being * positioned by controllers, otherwise {@link Vec3(0)|Vec3.ZERO}. Read-only. * @property {Vec3} rightHandTipPosition - The position 30cm offset from the right hand in avatar coordinates if it's being * positioned by controllers, otherwise {@link Vec3(0)|Vec3.ZERO}. Read-only. + * * @property {Pose} leftHandPose - The pose of the left hand as determined by the hand controllers. Read-only. * @property {Pose} rightHandPose - The pose right hand position as determined by the hand controllers. Read-only. * @property {Pose} leftHandTipPose - The pose of the left hand as determined by the hand controllers, with the position * by 30cm. Read-only. * @property {Pose} rightHandTipPose - The pose of the right hand as determined by the hand controllers, with the position * by 30cm. Read-only. + * + * @property {number} energy + * @property {boolean} isAway + * * @property {boolean} centerOfGravityModelEnabled=true - If true then the avatar hips are placed according to the center of * gravity model that balance the center of gravity over the base of support of the feet. Setting the value false * will result in the default behaviour where the hips are placed under the head. @@ -122,30 +132,38 @@ class MyAvatar : public Avatar { * @property {boolean} collisionsEnabled - Set to true to enable collisions for the avatar, false * to disable collisions. May return true even though the value was set false because the * zone may disallow collisionless avatars. + * @property {boolean} otherAvatarsCollisionsEnabled * @property {boolean} characterControllerEnabled - Synonym of collisionsEnabled. * Deprecated: Use collisionsEnabled instead. * @property {boolean} useAdvancedMovementControls - Returns and sets the value of the Interface setting, Settings > * Walking and teleporting. Note: Setting the value has no effect unless Interface is restarted. * @property {boolean} showPlayArea - Returns and sets the value of the Interface setting, Settings > Show room boundaries * while teleporting. Note: Setting the value has no effect unless Interface is restarted. + * * @property {number} yawSpeed=75 * @property {number} pitchSpeed=50 + * * @property {boolean} hmdRollControlEnabled=true - If true, the roll angle of your HMD turns your avatar * while flying. * @property {number} hmdRollControlDeadZone=8 - The amount of HMD roll, in degrees, required before your avatar turns if * hmdRollControlEnabled is enabled. * @property {number} hmdRollControlRate If hmdRollControlEnabled is true, this value determines the maximum turn rate of * your avatar when rolling your HMD in degrees per second. + * * @property {number} userHeight=1.75 - The height of the user in sensor space. * @property {number} userEyeHeight=1.65 - The estimated height of the user's eyes in sensor space. Read-only. + * * @property {Uuid} SELF_ID - UUID representing "my avatar". Only use for local-only entities in situations * where MyAvatar.sessionUUID is not available (e.g., if not connected to a domain). Note: Likely to be deprecated. * Read-only. + * * @property {number} walkSpeed * @property {number} walkBackwardSpeed * @property {number} sprintSpeed * @property {number} isInSittingState - * @property {number} userRecenterModel + * @property {MyAvatar.SitStandModelType} userRecenterModel + * @property {boolean} isSitStandStateLocked + * @property {boolean} allowTeleporting * * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the * registration point of the 3D model. @@ -160,6 +178,7 @@ class MyAvatar : public Avatar { * sometimes called "elevation". * @property {number} bodyRoll - The rotation about an axis running from the chest to the back of the avatar. Roll is * sometimes called "bank". + * * @property {Quat} orientation * @property {Quat} headOrientation - The orientation of the avatar's head. * @property {number} headPitch - The rotation about an axis running from ear to ear of the avatar's head. Pitch is @@ -168,18 +187,24 @@ class MyAvatar : public Avatar { * head. Yaw is sometimes called "heading". * @property {number} headRoll - The rotation about an axis running from the nose to the back of the avatar's head. Roll is * sometimes called "bank". + * * @property {Vec3} velocity * @property {Vec3} angularVelocity + * * @property {number} audioLoudness * @property {number} audioAverageLoudness + * * @property {string} displayName * @property {string} sessionDisplayName - Sanitized, defaulted version displayName that is defined by the AvatarMixer * rather than by Interface clients. The result is unique among all avatars present at the time. * @property {boolean} lookAtSnappingEnabled * @property {string} skeletonModelURL * @property {AttachmentData[]} attachmentData + * * @property {string[]} jointNames - The list of joints in the current avatar model. Read-only. + * * @property {Uuid} sessionUUID Read-only. + * * @property {Mat4} sensorToWorldMatrix Read-only. * @property {Mat4} controllerLeftHandMatrix Read-only. * @property {Mat4} controllerRightHandMatrix Read-only. @@ -196,11 +221,11 @@ class MyAvatar : public Avatar { Q_PROPERTY(QString motorMode READ getScriptedMotorMode WRITE setScriptedMotorMode) Q_PROPERTY(QString collisionSoundURL READ getCollisionSoundURL WRITE setCollisionSoundURL) Q_PROPERTY(AudioListenerMode audioListenerMode READ getAudioListenerMode WRITE setAudioListenerMode) - Q_PROPERTY(glm::vec3 customListenPosition READ getCustomListenPosition WRITE setCustomListenPosition) - Q_PROPERTY(glm::quat customListenOrientation READ getCustomListenOrientation WRITE setCustomListenOrientation) Q_PROPERTY(AudioListenerMode audioListenerModeHead READ getAudioListenerModeHead) Q_PROPERTY(AudioListenerMode audioListenerModeCamera READ getAudioListenerModeCamera) Q_PROPERTY(AudioListenerMode audioListenerModeCustom READ getAudioListenerModeCustom) + Q_PROPERTY(glm::vec3 customListenPosition READ getCustomListenPosition WRITE setCustomListenPosition) + Q_PROPERTY(glm::quat customListenOrientation READ getCustomListenOrientation WRITE setCustomListenOrientation) Q_PROPERTY(bool hasScriptedBlendshapes READ getHasScriptedBlendshapes WRITE setHasScriptedBlendshapes) Q_PROPERTY(bool hasProceduralBlinkFaceMovement READ getHasProceduralBlinkFaceMovement WRITE setHasProceduralBlinkFaceMovement) Q_PROPERTY(bool hasProceduralEyeFaceMovement READ getHasProceduralEyeFaceMovement WRITE setHasProceduralEyeFaceMovement) @@ -277,6 +302,9 @@ public: }; Q_ENUM(DriveKeys) + /**jsdoc + * @typedef {number} MyAvatar.SitStandModelType + */ enum SitStandModelType { ForceSit = 0, ForceStand, @@ -491,6 +519,9 @@ public: // adding one of the other handlers. While any handler may change a value in animStateDictionaryIn (or supply different values in animStateDictionaryOut) // a handler must not remove properties from animStateDictionaryIn, nor change property values that it does not intend to change. // It is not specified in what order multiple handlers are called. + /**jsdoc + * @function MyAvatar.addAnimationStateHandler + */ Q_INVOKABLE QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { return _skeletonModel->getRig().addAnimationStateHandler(handler, propertiesList); } /**jsdoc @@ -530,7 +561,7 @@ public: */ Q_INVOKABLE void setHmdAvatarAlignmentType(const QString& hand); /**jsdoc - * @function MyAvatar.setHmdAvatarAlignmentType + * @function MyAvatar.getHmdAvatarAlignmentType * @returns {string} */ Q_INVOKABLE QString getHmdAvatarAlignmentType() const; @@ -649,7 +680,7 @@ public: /**jsdoc * Recenter the avatar in the horizontal direction, if {@link MyAvatar|MyAvatar.hmdLeanRecenterEnabled} is * false. - * @ function MyAvatar.triggerHorizontalRecenter + * @function MyAvatar.triggerHorizontalRecenter */ Q_INVOKABLE void triggerHorizontalRecenter(); @@ -935,7 +966,7 @@ public: /**jsdoc * Function returns list of avatar entities - * @function MyAvatar.getAvatarEntitiesVariant() + * @function MyAvatar.getAvatarEntitiesVariant * @returns {object[]} */ Q_INVOKABLE QVariantList getAvatarEntitiesVariant(); @@ -1244,7 +1275,6 @@ public slots: * @param {boolean} [shouldFaceLocation=false] - Set to true to position the avatar a short distance away from * the new position and orientate the avatar to face the position. */ - void goToFeetLocation(const glm::vec3& newPosition, bool hasOrientation, const glm::quat& newOrientation, bool shouldFaceLocation); @@ -1382,8 +1412,20 @@ public slots: */ bool getEnableMeshVisible() const override; + /**jsdoc + * @function MyAvatar.storeAvatarEntityDataPayload + */ void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload) override; + + /**jsdoc + * @function MyAvatar.clearAvatarEntity + * @param {Uuid} entityID + * @param {boolean} requiresRemovalFromTree + */ void clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree = true) override; + /**jsdoc + * @function MyAvatar.sanitizeAvatarEntityProperties + */ void sanitizeAvatarEntityProperties(EntityItemProperties& properties) const; /**jsdoc @@ -1489,11 +1531,11 @@ signals: void collisionsEnabledChanged(bool enabled); /**jsdoc - * Triggered when collisions with other avatars enabled or disabled - * @function MyAvatar.otherAvatarsCollisionsEnabledChanged - * @param {boolean} enabled - * @returns {Signal} - */ + * Triggered when collisions with other avatars enabled or disabled + * @function MyAvatar.otherAvatarsCollisionsEnabledChanged + * @param {boolean} enabled + * @returns {Signal} + */ void otherAvatarsCollisionsEnabledChanged(bool enabled); /**jsdoc diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 06942a13d8..7ebb8cad01 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -499,6 +499,9 @@ public: void tearDownGrabs(); signals: + /**jsdoc + * @function MyAvatar.targetScaleChanged + */ void targetScaleChanged(float targetScale); public slots: @@ -541,6 +544,9 @@ public slots: */ glm::quat getRightPalmRotation() const; + /**jsdoc + * @function MyAvatar.setModelURLFinished + */ // hooked up to Model::setURLFinished signal void setModelURLFinished(bool success); From f58a5db0b0931ce0244007a748ed545d51196194 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 19 Feb 2019 09:47:51 +1300 Subject: [PATCH 032/566] Reorganize JSDoc inheritance for MyAvatar and Avatar --- .../src/avatars/ScriptableAvatar.h | 109 +++------- interface/src/avatar/MyAvatar.h | 146 +++++++++----- .../src/avatars-renderer/Avatar.h | 7 +- libraries/avatars/src/AvatarData.h | 189 ++++++++++++------ 4 files changed, 262 insertions(+), 189 deletions(-) diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 4562ad6134..b2ad4527b0 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -22,17 +22,16 @@ * The Avatar API is used to manipulate scriptable avatars on the domain. This API is a subset of the * {@link MyAvatar} API. * - *

Note: In the examples, use "Avatar" instead of "MyAvatar".

- * * @namespace Avatar * * @hifi-assignment-client * + * @comment IMPORTANT: This group of properties is copied from AvatarData.h; they should NOT be edited here. * @property {Vec3} position - * @property {number} scale + * @property {number} scale - Returns the clamped scale of the avatar. * @property {number} density Read-only. * @property {Vec3} handPosition - * @property {number} bodyYaw - The rotation left or right about an axis running from the head to the feet of the avatar. + * @property {number} bodyYaw - The rotation left or right about an axis running from the head to the feet of the avatar. * Yaw is sometimes called "heading". * @property {number} bodyPitch - The rotation about an axis running from shoulder to shoulder of the avatar. Pitch is * sometimes called "elevation". @@ -63,62 +62,6 @@ * @property {Mat4} controllerRightHandMatrix Read-only. * @property {number} sensorToWorldScale Read-only. * - * @borrows MyAvatar.getDomainMinScale as getDomainMinScale - * @borrows MyAvatar.getDomainMaxScale as getDomainMaxScale - * @borrows MyAvatar.canMeasureEyeHeight as canMeasureEyeHeight - * @borrows MyAvatar.getEyeHeight as getEyeHeight - * @borrows MyAvatar.getHeight as getHeight - * @borrows MyAvatar.setHandState as setHandState - * @borrows MyAvatar.getHandState as getHandState - * @borrows MyAvatar.setRawJointData as setRawJointData - * @borrows MyAvatar.setJointData as setJointData - * @borrows MyAvatar.setJointRotation as setJointRotation - * @borrows MyAvatar.setJointTranslation as setJointTranslation - * @borrows MyAvatar.clearJointData as clearJointData - * @borrows MyAvatar.isJointDataValid as isJointDataValid - * @borrows MyAvatar.getJointRotation as getJointRotation - * @borrows MyAvatar.getJointTranslation as getJointTranslation - * @borrows MyAvatar.getJointRotations as getJointRotations - * @borrows MyAvatar.getJointTranslations as getJointTranslations - * @borrows MyAvatar.setJointRotations as setJointRotations - * @borrows MyAvatar.setJointTranslations as setJointTranslations - * @borrows MyAvatar.clearJointsData as clearJointsData - * @borrows MyAvatar.getJointIndex as getJointIndex - * @borrows MyAvatar.getJointNames as getJointNames - * @borrows MyAvatar.setBlendshape as setBlendshape - * @borrows MyAvatar.getAttachmentsVariant as getAttachmentsVariant - * @borrows MyAvatar.setAttachmentsVariant as setAttachmentsVariant - * @borrows MyAvatar.updateAvatarEntity as updateAvatarEntity - * @borrows MyAvatar.clearAvatarEntity as clearAvatarEntity - * @borrows MyAvatar.setForceFaceTrackerConnected as setForceFaceTrackerConnected - * @borrows MyAvatar.getAttachmentData as getAttachmentData - * @borrows MyAvatar.setAttachmentData as setAttachmentData - * @borrows MyAvatar.attach as attach - * @borrows MyAvatar.detachOne as detachOne - * @borrows MyAvatar.detachAll as detachAll - * @borrows MyAvatar.getAvatarEntityData as getAvatarEntityData - * @borrows MyAvatar.setAvatarEntityData as setAvatarEntityData - * @borrows MyAvatar.getSensorToWorldMatrix as getSensorToWorldMatrix - * @borrows MyAvatar.getSensorToWorldScale as getSensorToWorldScale - * @borrows MyAvatar.getControllerLeftHandMatrix as getControllerLeftHandMatrix - * @borrows MyAvatar.getControllerRightHandMatrix as getControllerRightHandMatrix - * @borrows MyAvatar.getDataRate as getDataRate - * @borrows MyAvatar.getUpdateRate as getUpdateRate - * @borrows MyAvatar.displayNameChanged as displayNameChanged - * @borrows MyAvatar.sessionDisplayNameChanged as sessionDisplayNameChanged - * @borrows MyAvatar.skeletonModelURLChanged as skeletonModelURLChanged - * @borrows MyAvatar.lookAtSnappingChanged as lookAtSnappingChanged - * @borrows MyAvatar.sessionUUIDChanged as sessionUUIDChanged - * @borrows MyAvatar.sendAvatarDataPacket as sendAvatarDataPacket - * @borrows MyAvatar.sendIdentityPacket as sendIdentityPacket - * @borrows MyAvatar.setJointMappingsFromNetworkReply as setJointMappingsFromNetworkReply - * @borrows MyAvatar.setSessionUUID as setSessionUUID - * @borrows MyAvatar.getAbsoluteJointRotationInObjectFrame as getAbsoluteJointRotationInObjectFrame - * @borrows MyAvatar.getAbsoluteJointTranslationInObjectFrame as getAbsoluteJointTranslationInObjectFrame - * @borrows MyAvatar.setAbsoluteJointRotationInObjectFrame as setAbsoluteJointRotationInObjectFrame - * @borrows MyAvatar.setAbsoluteJointTranslationInObjectFrame as setAbsoluteJointTranslationInObjectFrame - * @borrows MyAvatar.getTargetScale as getTargetScale - * @borrows MyAvatar.resetLastSent as resetLastSent */ class ScriptableAvatar : public AvatarData, public Dependency { @@ -159,23 +102,25 @@ public: Q_INVOKABLE AnimationDetails getAnimationDetails(); /**jsdoc - * Get the names of all the joints in the current avatar. - * @function MyAvatar.getJointNames - * @returns {string[]} The joint names. - * @example Report the names of all the joints in your current avatar. - * print(JSON.stringify(MyAvatar.getJointNames())); - */ + * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc.
+ * Get the names of all the joints in the current avatar. + * @function Avatar.getJointNames + * @returns {string[]} The joint names. + * @example Report the names of all the joints in your current avatar. + * print(JSON.stringify(Avatar.getJointNames())); + */ Q_INVOKABLE virtual QStringList getJointNames() const override; /**jsdoc - * Get the joint index for a named joint. The joint index value is the position of the joint in the array returned by - * {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}. - * @function MyAvatar.getJointIndex - * @param {string} name - The name of the joint. - * @returns {number} The index of the joint. - * @example Report the index of your avatar's left arm joint. - * print(JSON.stringify(MyAvatar.getJointIndex("LeftArm")); - */ + * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc.
+ * Get the joint index for a named joint. The joint index value is the position of the joint in the array returned by + * {@link Avatar.getJointNames}. + * @function Avatar.getJointIndex + * @param {string} name - The name of the joint. + * @returns {number} The index of the joint. + * @example Report the index of your avatar's left arm joint. + * print(JSON.stringify(Avatar.getJointIndex("LeftArm")); + */ /// Returns the index of the joint with the specified name, or -1 if not found/unknown. Q_INVOKABLE virtual int getJointIndex(const QString& name) const override; @@ -193,6 +138,8 @@ public: bool getHasAudioEnabledFaceMovement() const override { return _headData->getHasAudioEnabledFaceMovement(); } /**jsdoc + * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc.
+ * ####### Also need to resolve with MyAvatar.
* Potentially Very Expensive. Do not use. * @function Avatar.getAvatarEntityData * @returns {object} @@ -200,13 +147,15 @@ public: Q_INVOKABLE AvatarEntityMap getAvatarEntityData() const override; /**jsdoc - * @function MyAvatar.setAvatarEntityData - * @param {object} avatarEntityData - */ + * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc. + * @function Avatar.setAvatarEntityData + * @param {object} avatarEntityData + */ Q_INVOKABLE void setAvatarEntityData(const AvatarEntityMap& avatarEntityData) override; /**jsdoc - * @function MyAvatar.updateAvatarEntity + * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc. + * @function Avatar.updateAvatarEntity * @param {Uuid} entityID * @param {string} entityData */ @@ -214,12 +163,12 @@ public: public slots: /**jsdoc - * @function MyAvatar.update + * @function Avatar.update */ void update(float deltatime); /**jsdoc - * @function MyAvatar.setJointMappingsFromNetworkReply + * @function Avatar.setJointMappingsFromNetworkReply */ void setJointMappingsFromNetworkReply(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4e75c93403..d689d2f215 100755 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -68,6 +68,46 @@ class MyAvatar : public Avatar { * @hifi-client-entity * @hifi-avatar * + * @comment IMPORTANT: This group of properties is copied from AvatarData.h; they should NOT be edited here. + * @property {Vec3} position + * @property {number} scale - Returns the clamped scale of the avatar. + * @property {number} density Read-only. + * @property {Vec3} handPosition + * @property {number} bodyYaw - The rotation left or right about an axis running from the head to the feet of the avatar. + * Yaw is sometimes called "heading". + * @property {number} bodyPitch - The rotation about an axis running from shoulder to shoulder of the avatar. Pitch is + * sometimes called "elevation". + * @property {number} bodyRoll - The rotation about an axis running from the chest to the back of the avatar. Roll is + * sometimes called "bank". + * @property {Quat} orientation + * @property {Quat} headOrientation - The orientation of the avatar's head. + * @property {number} headPitch - The rotation about an axis running from ear to ear of the avatar's head. Pitch is + * sometimes called "elevation". + * @property {number} headYaw - The rotation left or right about an axis running from the base to the crown of the avatar's + * head. Yaw is sometimes called "heading". + * @property {number} headRoll - The rotation about an axis running from the nose to the back of the avatar's head. Roll is + * sometimes called "bank". + * @property {Vec3} velocity + * @property {Vec3} angularVelocity + * @property {number} audioLoudness + * @property {number} audioAverageLoudness + * @property {string} displayName + * @property {string} sessionDisplayName - Sanitized, defaulted version displayName that is defined by the AvatarMixer + * rather than by Interface clients. The result is unique among all avatars present at the time. + * @property {boolean} lookAtSnappingEnabled + * @property {string} skeletonModelURL + * @property {AttachmentData[]} attachmentData + * @property {string[]} jointNames - The list of joints in the current avatar model. Read-only. + * @property {Uuid} sessionUUID Read-only. + * @property {Mat4} sensorToWorldMatrix Read-only. + * @property {Mat4} controllerLeftHandMatrix Read-only. + * @property {Mat4} controllerRightHandMatrix Read-only. + * @property {number} sensorToWorldScale Read-only. + * + * @comment IMPORTANT: This group of properties is copied from Avatar.h; they should NOT be edited here. + * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the + * registration point of the 3D model. + * * @property {Vec3} qmlPosition - A synonym for position for use by QML. * * @property {boolean} shouldRenderLocally=true - If true then your avatar is rendered for you in Interface, @@ -165,50 +205,60 @@ class MyAvatar : public Avatar { * @property {boolean} isSitStandStateLocked * @property {boolean} allowTeleporting * - * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the - * registration point of the 3D model. - * - * @property {Vec3} position - * @property {number} scale - Returns the clamped scale of the avatar. - * @property {number} density Read-only. - * @property {Vec3} handPosition - * @property {number} bodyYaw - The rotation left or right about an axis running from the head to the feet of the avatar. - * Yaw is sometimes called "heading". - * @property {number} bodyPitch - The rotation about an axis running from shoulder to shoulder of the avatar. Pitch is - * sometimes called "elevation". - * @property {number} bodyRoll - The rotation about an axis running from the chest to the back of the avatar. Roll is - * sometimes called "bank". - * - * @property {Quat} orientation - * @property {Quat} headOrientation - The orientation of the avatar's head. - * @property {number} headPitch - The rotation about an axis running from ear to ear of the avatar's head. Pitch is - * sometimes called "elevation". - * @property {number} headYaw - The rotation left or right about an axis running from the base to the crown of the avatar's - * head. Yaw is sometimes called "heading". - * @property {number} headRoll - The rotation about an axis running from the nose to the back of the avatar's head. Roll is - * sometimes called "bank". - * - * @property {Vec3} velocity - * @property {Vec3} angularVelocity - * - * @property {number} audioLoudness - * @property {number} audioAverageLoudness - * - * @property {string} displayName - * @property {string} sessionDisplayName - Sanitized, defaulted version displayName that is defined by the AvatarMixer - * rather than by Interface clients. The result is unique among all avatars present at the time. - * @property {boolean} lookAtSnappingEnabled - * @property {string} skeletonModelURL - * @property {AttachmentData[]} attachmentData - * - * @property {string[]} jointNames - The list of joints in the current avatar model. Read-only. - * - * @property {Uuid} sessionUUID Read-only. - * - * @property {Mat4} sensorToWorldMatrix Read-only. - * @property {Mat4} controllerLeftHandMatrix Read-only. - * @property {Mat4} controllerRightHandMatrix Read-only. - * @property {number} sensorToWorldScale Read-only. + * @borrows Avatar.getDomainMinScale as getDomainMinScale + * @borrows Avatar.getDomainMaxScale as getDomainMaxScale + * @borrows Avatar.getEyeHeight as getEyeHeight + * @borrows Avatar.getHeight as getHeight + * @borrows Avatar.setHandState as setHandState + * @borrows Avatar.getHandState as getHandState + * @borrows Avatar.setRawJointData as setRawJointData + * @borrows Avatar.setJointData as setJointData + * @borrows Avatar.setJointRotation as setJointRotation + * @borrows Avatar.setJointTranslation as setJointTranslation + * @borrows Avatar.clearJointData as clearJointData + * @borrows Avatar.isJointDataValid as isJointDataValid + * @borrows Avatar.getJointRotation as getJointRotation + * @borrows Avatar.getJointTranslation as getJointTranslation + * @borrows Avatar.getJointRotations as getJointRotations + * @borrows Avatar.getJointTranslations as getJointTranslations + * @borrows Avatar.setJointRotations as setJointRotations + * @borrows Avatar.setJointTranslations as setJointTranslations + * @borrows Avatar.clearJointsData as clearJointsData + * @borrows Avatar.getJointIndex as getJointIndex + * @borrows Avatar.getJointNames as getJointNames + * @borrows Avatar.setBlendshape as setBlendshape + * @borrows Avatar.getAttachmentsVariant as getAttachmentsVariant + * @borrows Avatar.setAttachmentsVariant as setAttachmentsVariant + * @borrows Avatar.updateAvatarEntity as updateAvatarEntity + * @borrows Avatar.clearAvatarEntity as clearAvatarEntity + * @borrows Avatar.setForceFaceTrackerConnected as setForceFaceTrackerConnected + * @borrows Avatar.getAttachmentData as getAttachmentData + * @borrows Avatar.setAttachmentData as setAttachmentData + * @borrows Avatar.attach as attach + * @borrows Avatar.detachOne as detachOne + * @borrows Avatar.detachAll as detachAll + * @borrows Avatar.getAvatarEntityData as getAvatarEntityData + * @borrows Avatar.setAvatarEntityData as setAvatarEntityData + * @borrows Avatar.getSensorToWorldMatrix as getSensorToWorldMatrix + * @borrows Avatar.getSensorToWorldScale as getSensorToWorldScale + * @borrows Avatar.getControllerLeftHandMatrix as getControllerLeftHandMatrix + * @borrows Avatar.getControllerRightHandMatrix as getControllerRightHandMatrix + * @borrows Avatar.getDataRate as getDataRate + * @borrows Avatar.getUpdateRate as getUpdateRate + * @borrows Avatar.displayNameChanged as displayNameChanged + * @borrows Avatar.sessionDisplayNameChanged as sessionDisplayNameChanged + * @borrows Avatar.skeletonModelURLChanged as skeletonModelURLChanged + * @borrows Avatar.lookAtSnappingChanged as lookAtSnappingChanged + * @borrows Avatar.sessionUUIDChanged as sessionUUIDChanged + * @borrows Avatar.sendAvatarDataPacket as sendAvatarDataPacket + * @borrows Avatar.sendIdentityPacket as sendIdentityPacket + * @borrows Avatar.setSessionUUID as setSessionUUID + * @borrows Avatar.getAbsoluteJointRotationInObjectFrame as getAbsoluteJointRotationInObjectFrame + * @borrows Avatar.getAbsoluteJointTranslationInObjectFrame as getAbsoluteJointTranslationInObjectFrame + * @borrows Avatar.setAbsoluteJointRotationInObjectFrame as setAbsoluteJointRotationInObjectFrame + * @borrows Avatar.setAbsoluteJointTranslationInObjectFrame as setAbsoluteJointTranslationInObjectFrame + * @borrows Avatar.getTargetScale as getTargetScale + * @borrows Avatar.resetLastSent as resetLastSent */ // FIXME: `glm::vec3 position` is not accessible from QML, so this exposes position in a QML-native type Q_PROPERTY(QVector3D qmlPosition READ getQmlPosition) @@ -1314,7 +1364,7 @@ public slots: /**jsdoc * @function MyAvatar.restrictScaleFromDomainSettings - * @param {objecct} domainSettingsObject + * @param {object} domainSettingsObject */ void restrictScaleFromDomainSettings(const QJsonObject& domainSettingsObject); @@ -1345,6 +1395,7 @@ public slots: /**jsdoc + * ####### Why Q_INVOKABLE? * @function MyAvatar.updateMotionBehaviorFromMenu */ Q_INVOKABLE void updateMotionBehaviorFromMenu(); @@ -1413,16 +1464,19 @@ public slots: bool getEnableMeshVisible() const override; /**jsdoc + * ####### TODO; Should this really be exposed in the API? * @function MyAvatar.storeAvatarEntityDataPayload */ void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload) override; /**jsdoc + * ####### Does override change functionality? If so, document here and don't borrow; if not, borrow and don't document here. * @function MyAvatar.clearAvatarEntity * @param {Uuid} entityID - * @param {boolean} requiresRemovalFromTree + * @param {boolean} [requiresRemovalFromTree] */ void clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree = true) override; + /**jsdoc * @function MyAvatar.sanitizeAvatarEntityProperties */ diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 7ebb8cad01..1aa6829160 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -127,7 +127,12 @@ private: class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaModelPayload { Q_OBJECT - // This property has JSDoc in MyAvatar.h. + /*jsdoc + * @comment IMPORTANT: The JSDoc for the following properties should be copied to MyAvatar.h. + * + * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the + * registration point of the 3D model. + */ Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 63396a59ac..7a4d235565 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -411,7 +411,43 @@ class ClientTraitsHandler; class AvatarData : public QObject, public SpatiallyNestable { Q_OBJECT - // The following properties have JSDoc in MyAvatar.h and ScriptableAvatar.h + // IMPORTANT: The JSDoc for the following properties should be copied to MyAvatar.h and ScriptableAvatar.h. + /* + * @property {Vec3} position + * @property {number} scale - Returns the clamped scale of the avatar. + * @property {number} density Read-only. + * @property {Vec3} handPosition + * @property {number} bodyYaw - The rotation left or right about an axis running from the head to the feet of the avatar. + * Yaw is sometimes called "heading". + * @property {number} bodyPitch - The rotation about an axis running from shoulder to shoulder of the avatar. Pitch is + * sometimes called "elevation". + * @property {number} bodyRoll - The rotation about an axis running from the chest to the back of the avatar. Roll is + * sometimes called "bank". + * @property {Quat} orientation + * @property {Quat} headOrientation - The orientation of the avatar's head. + * @property {number} headPitch - The rotation about an axis running from ear to ear of the avatar's head. Pitch is + * sometimes called "elevation". + * @property {number} headYaw - The rotation left or right about an axis running from the base to the crown of the avatar's + * head. Yaw is sometimes called "heading". + * @property {number} headRoll - The rotation about an axis running from the nose to the back of the avatar's head. Roll is + * sometimes called "bank". + * @property {Vec3} velocity + * @property {Vec3} angularVelocity + * @property {number} audioLoudness + * @property {number} audioAverageLoudness + * @property {string} displayName + * @property {string} sessionDisplayName - Sanitized, defaulted version displayName that is defined by the AvatarMixer + * rather than by Interface clients. The result is unique among all avatars present at the time. + * @property {boolean} lookAtSnappingEnabled + * @property {string} skeletonModelURL + * @property {AttachmentData[]} attachmentData + * @property {string[]} jointNames - The list of joints in the current avatar model. Read-only. + * @property {Uuid} sessionUUID Read-only. + * @property {Mat4} sensorToWorldMatrix Read-only. + * @property {Mat4} controllerLeftHandMatrix Read-only. + * @property {Mat4} controllerRightHandMatrix Read-only. + * @property {number} sensorToWorldScale Read-only. + */ Q_PROPERTY(glm::vec3 position READ getWorldPosition WRITE setPositionViaScript) Q_PROPERTY(float scale READ getDomainLimitedScale WRITE setTargetScale) Q_PROPERTY(float density READ getDensity) @@ -567,7 +603,7 @@ public: /**jsdoc * Returns the minimum scale allowed for this avatar in the current domain. * This value can change as the user changes avatars or when changing domains. - * @function MyAvatar.getDomainMinScale + * @function Avatar.getDomainMinScale * @returns {number} minimum scale allowed for this avatar in the current domain. */ Q_INVOKABLE float getDomainMinScale() const; @@ -575,7 +611,7 @@ public: /**jsdoc * Returns the maximum scale allowed for this avatar in the current domain. * This value can change as the user changes avatars or when changing domains. - * @function MyAvatar.getDomainMaxScale + * @function Avatar.getDomainMaxScale * @returns {number} maximum scale allowed for this avatar in the current domain. */ Q_INVOKABLE float getDomainMaxScale() const; @@ -591,7 +627,7 @@ public: /**jsdoc * Provides read only access to the current eye height of the avatar. * This height is only an estimate and might be incorrect for avatars that are missing standard joints. - * @function MyAvatar.getEyeHeight + * @function Avatar.getEyeHeight * @returns {number} Eye height of avatar in meters. */ Q_INVOKABLE virtual float getEyeHeight() const { return _targetScale * getUnscaledEyeHeight(); } @@ -599,7 +635,7 @@ public: /**jsdoc * Provides read only access to the current height of the avatar. * This height is only an estimate and might be incorrect for avatars that are missing standard joints. - * @function MyAvatar.getHeight + * @function Avatar.getHeight * @returns {number} Height of avatar in meters. */ Q_INVOKABLE virtual float getHeight() const; @@ -610,13 +646,13 @@ public: void setDomainMaximumHeight(float domainMaximumHeight); /**jsdoc - * @function MyAvatar.setHandState + * @function Avatar.setHandState * @param {string} state */ Q_INVOKABLE void setHandState(char s) { _handState = s; } /**jsdoc - * @function MyAvatar.getHandState + * @function Avatar.getHandState * @returns {string} */ Q_INVOKABLE char getHandState() const { return _handState; } @@ -624,7 +660,7 @@ public: const QVector& getRawJointData() const { return _jointData; } /**jsdoc - * @function MyAvatar.setRawJointData + * @function Avatar.setRawJointData * @param {JointData[]} data */ Q_INVOKABLE void setRawJointData(QVector data); @@ -636,7 +672,7 @@ public: * the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate * joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set * the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.

- * @function MyAvatar.setJointData + * @function Avatar.setJointData * @param {number} index - The index of the joint. * @param {Quat} rotation - The rotation of the joint relative to its parent. * @param {Vec3} translation - The translation of the joint relative to its parent. @@ -654,6 +690,8 @@ public: * Script.setTimeout(function () { * MyAvatar.clearJointsData(); * }, 5000); + * + * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation); @@ -664,7 +702,7 @@ public: * the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate * joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set * the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.

- * @function MyAvatar.setJointRotation + * @function Avatar.setJointRotation * @param {number} index - The index of the joint. * @param {Quat} rotation - The rotation of the joint relative to its parent. */ @@ -677,7 +715,7 @@ public: * the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate * joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set * the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.

- * @function MyAvatar.setJointTranslation + * @function Avatar.setJointTranslation * @param {number} index - The index of the joint. * @param {Vec3} translation - The translation of the joint relative to its parent. */ @@ -687,13 +725,13 @@ public: * Clear joint translations and rotations set by script for a specific joint. This restores all motion from the default * animation system including inverse kinematics for that joint. *

Note: This is slightly faster than the function variation that specifies the joint name.

- * @function MyAvatar.clearJointData + * @function Avatar.clearJointData * @param {number} index - The index of the joint. */ Q_INVOKABLE virtual void clearJointData(int index); /**jsdoc - * @function MyAvatar.isJointDataValid + * @function Avatar.isJointDataValid * @param {number} index * @returns {boolean} */ @@ -702,7 +740,7 @@ public: /**jsdoc * Get the rotation of a joint relative to its parent. For information on the joint hierarchy used, see * Avatar Standards. - * @function MyAvatar.getJointRotation + * @function Avatar.getJointRotation * @param {number} index - The index of the joint. * @returns {Quat} The rotation of the joint relative to its parent. */ @@ -711,7 +749,7 @@ public: /**jsdoc * Get the translation of a joint relative to its parent. For information on the joint hierarchy used, see * Avatar Standards. - * @function MyAvatar.getJointTranslation + * @function Avatar.getJointTranslation * @param {number} index - The index of the joint. * @returns {Vec3} The translation of the joint relative to its parent. */ @@ -724,7 +762,7 @@ public: * the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate * joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set * the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.

- * @function MyAvatar.setJointData + * @function Avatar.setJointData * @param {string} name - The name of the joint. * @param {Quat} rotation - The rotation of the joint relative to its parent. * @param {Vec3} translation - The translation of the joint relative to its parent. @@ -738,7 +776,7 @@ public: * the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate * joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set * the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.

- * @function MyAvatar.setJointRotation + * @function Avatar.setJointRotation * @param {string} name - The name of the joint. * @param {Quat} rotation - The rotation of the joint relative to its parent. * @example Set your avatar to its default T-pose then rotate its right arm.
@@ -759,6 +797,8 @@ public: * Script.setTimeout(function () { * MyAvatar.clearJointsData(); * }, 5000); + * + * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual void setJointRotation(const QString& name, const glm::quat& rotation); @@ -769,7 +809,7 @@ public: * the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate * joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set * the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.

- * @function MyAvatar.setJointTranslation + * @function Avatar.setJointTranslation * @param {string} name - The name of the joint. * @param {Vec3} translation - The translation of the joint relative to its parent. * @example Stretch your avatar's neck. Depending on the avatar you are using, you will either see a gap between @@ -782,6 +822,8 @@ public: * Script.setTimeout(function () { * MyAvatar.clearJointData("Neck"); * }, 5000); + * + * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual void setJointTranslation(const QString& name, const glm::vec3& translation); @@ -789,7 +831,7 @@ public: * Clear joint translations and rotations set by script for a specific joint. This restores all motion from the default * animation system including inverse kinematics for that joint. *

Note: This is slightly slower than the function variation that specifies the joint index.

- * @function MyAvatar.clearJointData + * @function Avatar.clearJointData * @param {string} name - The name of the joint. * @example Offset and restore the position of your avatar's head. * // Move your avatar's head up by 25cm from where it should be. @@ -799,11 +841,13 @@ public: * Script.setTimeout(function () { * MyAvatar.clearJointData("Neck"); * }, 5000); + * + * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual void clearJointData(const QString& name); /**jsdoc - * @function MyAvatar.isJointDataValid + * @function Avatar.isJointDataValid * @param {string} name * @returns {boolean} */ @@ -812,37 +856,43 @@ public: /**jsdoc * Get the rotation of a joint relative to its parent. For information on the joint hierarchy used, see * Avatar Standards. - * @function MyAvatar.getJointRotation + * @function Avatar.getJointRotation * @param {string} name - The name of the joint. * @returns {Quat} The rotation of the joint relative to its parent. * @example Report the rotation of your avatar's hips joint. * print(JSON.stringify(MyAvatar.getJointRotation("Hips"))); + * + * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual glm::quat getJointRotation(const QString& name) const; /**jsdoc * Get the translation of a joint relative to its parent. For information on the joint hierarchy used, see * Avatar Standards. - * @function MyAvatar.getJointTranslation + * @function Avatar.getJointTranslation * @param {number} name - The name of the joint. * @returns {Vec3} The translation of the joint relative to its parent. * @example Report the translation of your avatar's hips joint. * print(JSON.stringify(MyAvatar.getJointRotation("Hips"))); + * + * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual glm::vec3 getJointTranslation(const QString& name) const; /**jsdoc * Get the rotations of all joints in the current avatar. Each joint's rotation is relative to its parent joint. - * @function MyAvatar.getJointRotations + * @function Avatar.getJointRotations * @returns {Quat[]} The rotations of all joints relative to each's parent. The values are in the same order as the array * returned by {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}. * @example Report the rotations of all your avatar's joints. * print(JSON.stringify(MyAvatar.getJointRotations())); + * + * // Note: If using from the Avatar API, replace all "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual QVector getJointRotations() const; /**jsdoc - * @function MyAvatar.getJointTranslations + * @function Avatar.getJointTranslations * @returns {Vec3[]} */ Q_INVOKABLE virtual QVector getJointTranslations() const; @@ -854,7 +904,7 @@ public: * the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate * joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set * the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.

- * @function MyAvatar.setJointRotations + * @function Avatar.setJointRotations * @param {Quat[]} jointRotations - The rotations for all joints in the avatar. The values are in the same order as the * array returned by {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}. * @example Set your avatar to its default T-pose then rotate its right arm.
@@ -880,11 +930,13 @@ public: * Script.setTimeout(function () { * MyAvatar.clearJointsData(); * }, 5000); + * + * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual void setJointRotations(const QVector& jointRotations); /**jsdoc - * @function MyAvatar.setJointTranslations + * @function Avatar.setJointTranslations * @param {Vec3[]} translations */ Q_INVOKABLE virtual void setJointTranslations(const QVector& jointTranslations); @@ -892,7 +944,7 @@ public: /**jsdoc * Clear all joint translations and rotations that have been set by script. This restores all motion from the default * animation system including inverse kinematics for all joints. - * @function MyAvatar.clearJointsData + * @function Avatar.clearJointsData * @example Set your avatar to it's default T-pose for a while. * // Set all joint translations and rotations to defaults. * var i, length, rotation, translation; @@ -906,33 +958,39 @@ public: * Script.setTimeout(function () { * MyAvatar.clearJointsData(); * }, 5000); + * + * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual void clearJointsData(); /**jsdoc * Get the joint index for a named joint. The joint index value is the position of the joint in the array returned by * {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}. - * @function MyAvatar.getJointIndex + * @function Avatar.getJointIndex * @param {string} name - The name of the joint. * @returns {number} The index of the joint. * @example Report the index of your avatar's left arm joint. * print(JSON.stringify(MyAvatar.getJointIndex("LeftArm")); + * + * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ /// Returns the index of the joint with the specified name, or -1 if not found/unknown. Q_INVOKABLE virtual int getJointIndex(const QString& name) const; /**jsdoc * Get the names of all the joints in the current avatar. - * @function MyAvatar.getJointNames + * @function Avatar.getJointNames * @returns {string[]} The joint names. * @example Report the names of all the joints in your current avatar. * print(JSON.stringify(MyAvatar.getJointNames())); + * + * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual QStringList getJointNames() const; /**jsdoc - * @function MyAvatar.setBlendshape + * @function Avatar.setBlendshape * @param {string} name * @param {number} value */ @@ -940,14 +998,14 @@ public: /**jsdoc - * @function MyAvatar.getAttachmentsVariant + * @function Avatar.getAttachmentsVariant * @returns {object} */ // FIXME: Can this name be improved? Can it be deprecated? Q_INVOKABLE virtual QVariantList getAttachmentsVariant() const; /**jsdoc - * @function MyAvatar.setAttachmentsVariant + * @function Avatar.setAttachmentsVariant * @param {object} variant */ // FIXME: Can this name be improved? Can it be deprecated? @@ -956,21 +1014,22 @@ public: virtual void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload); /**jsdoc - * @function MyAvatar.updateAvatarEntity + * @function Avatar.updateAvatarEntity * @param {Uuid} entityID * @param {string} entityData */ Q_INVOKABLE virtual void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData); /**jsdoc - * @function MyAvatar.clearAvatarEntity + * @function Avatar.clearAvatarEntity * @param {Uuid} entityID + * @param {boolean} [requiresRemovalFromTree] */ Q_INVOKABLE virtual void clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree = true); /**jsdoc - * @function MyAvatar.setForceFaceTrackerConnected + * @function Avatar.setForceFaceTrackerConnected * @param {boolean} connected */ Q_INVOKABLE void setForceFaceTrackerConnected(bool connected) { _forceFaceTrackerConnected = connected; } @@ -1023,13 +1082,15 @@ public: /**jsdoc * Get information about all models currently attached to your avatar. - * @function MyAvatar.getAttachmentData + * @function Avatar.getAttachmentData * @returns {AttachmentData[]} Information about all models attached to your avatar. * @example Report the URLs of all current attachments. * var attachments = MyAvatar.getaAttachmentData(); * for (var i = 0; i < attachments.length; i++) { * print (attachments[i].modelURL); * } + * + * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual QVector getAttachmentData() const; @@ -1037,7 +1098,7 @@ public: * Set all models currently attached to your avatar. For example, if you retrieve attachment data using * {@link MyAvatar.getAttachmentData} or {@link Avatar.getAttachmentData}, make changes to it, and then want to update your avatar's attachments per the * changed data. You can also remove all attachments by using setting attachmentData to null. - * @function MyAvatar.setAttachmentData + * @function Avatar.setAttachmentData * @param {AttachmentData[]} attachmentData - The attachment data defining the models to have attached to your avatar. Use * null to remove all attachments. * @example Remove a hat attachment if your avatar is wearing it. @@ -1051,6 +1112,8 @@ public: * break; * } * } + * + * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual void setAttachmentData(const QVector& attachmentData); @@ -1059,7 +1122,7 @@ public: * stand on. *

Note: Attached models are models only; they are not entities and can not be manipulated using the {@link Entities} API. * Nor can you use this function to attach an entity (such as a sphere or a box) to your avatar.

- * @function MyAvatar.attach + * @function Avatar.attach * @param {string} modelURL - The URL of the model to attach. Models can be .FBX or .OBJ format. * @param {string} [jointName=""] - The name of the avatar joint (see {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}) to attach the model * to. @@ -1089,6 +1152,8 @@ public: * attachment.rotation, * attachment.scale, * attachment.isSoft); + * + * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ Q_INVOKABLE virtual void attach(const QString& modelURL, const QString& jointName = QString(), const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), @@ -1097,7 +1162,7 @@ public: /**jsdoc * Detach the most recently attached instance of a particular model from either a specific joint or any joint. - * @function MyAvatar.detachOne + * @function Avatar.detachOne * @param {string} modelURL - The URL of the model to detach. * @param {string} [jointName=""] - The name of the joint to detach the model from. If "", then the most * recently attached model is removed from which ever joint it was attached to. @@ -1106,7 +1171,7 @@ public: /**jsdoc * Detach all instances of a particular model from either a specific joint or all joints. - * @function MyAvatar.detachAll + * @function Avatar.detachAll * @param {string} modelURL - The URL of the model to detach. * @param {string} [jointName=""] - The name of the joint to detach the model from. If "", then the model is * detached from all joints. @@ -1136,13 +1201,13 @@ public: AABox getDefaultBubbleBox() const; /**jsdoc - * @function MyAvatar.getAvatarEntityData + * @function Avatar.getAvatarEntityData * @returns {object} */ Q_INVOKABLE virtual AvatarEntityMap getAvatarEntityData() const; /**jsdoc - * @function MyAvatar.setAvatarEntityData + * @function Avatar.setAvatarEntityData * @param {object} avatarEntityData */ Q_INVOKABLE virtual void setAvatarEntityData(const AvatarEntityMap& avatarEntityData); @@ -1151,28 +1216,28 @@ public: AvatarEntityIDs getAndClearRecentlyRemovedIDs(); /**jsdoc - * @function MyAvatar.getSensorToWorldMatrix + * @function Avatar.getSensorToWorldMatrix * @returns {Mat4} */ // thread safe Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const; /**jsdoc - * @function MyAvatar.getSensorToWorldScale + * @function Avatar.getSensorToWorldScale * @returns {number} */ // thread safe Q_INVOKABLE float getSensorToWorldScale() const; /**jsdoc - * @function MyAvatar.getControllerLeftHandMatrix + * @function Avatar.getControllerLeftHandMatrix * @returns {Mat4} */ // thread safe Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const; /**jsdoc - * @function MyAvatar.getControllerRightHandMatrix + * @function Avatar.getControllerRightHandMatrix * @returns {Mat4} */ // thread safe @@ -1180,14 +1245,14 @@ public: /**jsdoc - * @function MyAvatar.getDataRate + * @function Avatar.getDataRate * @param {string} [rateName=""] * @returns {number} */ Q_INVOKABLE float getDataRate(const QString& rateName = QString("")) const; /**jsdoc - * @function MyAvatar.getUpdateRate + * @function Avatar.getUpdateRate * @param {string} [rateName=""] * @returns {number} */ @@ -1235,32 +1300,32 @@ public: signals: /**jsdoc - * @function MyAvatar.displayNameChanged + * @function Avatar.displayNameChanged * @returns {Signal} */ void displayNameChanged(); /**jsdoc - * @function MyAvatar.sessionDisplayNameChanged + * @function Avatar.sessionDisplayNameChanged * @returns {Signal} */ void sessionDisplayNameChanged(); /**jsdoc - * @function MyAvatar.skeletonModelURLChanged + * @function Avatar.skeletonModelURLChanged * @returns {Signal} */ void skeletonModelURLChanged(); /**jsdoc - * @function MyAvatar.lookAtSnappingChanged + * @function Avatar.lookAtSnappingChanged * @param {boolean} enabled * @returns {Signal} */ void lookAtSnappingChanged(bool enabled); /**jsdoc - * @function MyAvatar.sessionUUIDChanged + * @function Avatar.sessionUUIDChanged * @returns {Signal} */ void sessionUUIDChanged(); @@ -1268,18 +1333,18 @@ signals: public slots: /**jsdoc - * @function MyAvatar.sendAvatarDataPacket + * @function Avatar.sendAvatarDataPacket * @param {boolean} [sendAll=false] */ virtual int sendAvatarDataPacket(bool sendAll = false); /**jsdoc - * @function MyAvatar.sendIdentityPacket + * @function Avatar.sendIdentityPacket */ int sendIdentityPacket(); /**jsdoc - * @function MyAvatar.setSessionUUID + * @function Avatar.setSessionUUID * @param {Uuid} sessionUUID */ virtual void setSessionUUID(const QUuid& sessionUUID) { @@ -1294,21 +1359,21 @@ public slots: } /**jsdoc - * @function MyAvatar.getAbsoluteJointRotationInObjectFrame + * @function Avatar.getAbsoluteJointRotationInObjectFrame * @param {number} index * @returns {Quat} */ virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override; /**jsdoc - * @function MyAvatar.getAbsoluteJointTranslationInObjectFrame + * @function Avatar.getAbsoluteJointTranslationInObjectFrame * @param {number} index * @returns {Vec3} */ virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override; /**jsdoc - * @function MyAvatar.setAbsoluteJointRotationInObjectFrame + * @function Avatar.setAbsoluteJointRotationInObjectFrame * @param {number} index * @param {Quat} rotation * @returns {boolean} @@ -1316,7 +1381,7 @@ public slots: virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } /**jsdoc - * @function MyAvatar.setAbsoluteJointTranslationInObjectFrame + * @function Avatar.setAbsoluteJointTranslationInObjectFrame * @param {number} index * @param {Vec3} translation * @returns {boolean} @@ -1324,13 +1389,13 @@ public slots: virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } /**jsdoc - * @function MyAvatar.getTargetScale + * @function Avatar.getTargetScale * @returns {number} */ float getTargetScale() const { return _targetScale; } // why is this a slot? /**jsdoc - * @function MyAvatar.resetLastSent + * @function Avatar.resetLastSent */ void resetLastSent() { _lastToByteArray = 0; } From 8033e93eda84b482f9806d39dbb3d2e09e5fcaab Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 19 Feb 2019 17:38:37 -0800 Subject: [PATCH 033/566] Add avatar-priority boolean to zone entities RC-79 version --- libraries/entities/src/EntityItemProperties.cpp | 14 ++++++++++++++ libraries/entities/src/EntityItemProperties.h | 3 +++ libraries/entities/src/EntityPropertyFlags.h | 3 +++ libraries/entities/src/ZoneEntityItem.cpp | 5 +++++ libraries/entities/src/ZoneEntityItem.h | 7 +++++++ libraries/networking/src/udt/PacketHeaders.h | 1 + scripts/system/assets/data/createAppTooltips.json | 3 +++ scripts/system/edit.js | 3 ++- scripts/system/html/js/entityProperties.js | 6 ++++++ 9 files changed, 44 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7cafaece7a..103f5dbab7 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -616,6 +616,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_FLYING_ALLOWED, flyingAllowed); CHECK_PROPERTY_CHANGE(PROP_GHOSTING_ALLOWED, ghostingAllowed); CHECK_PROPERTY_CHANGE(PROP_FILTER_URL, filterURL); + CHECK_PROPERTY_CHANGE(PROP_AVATAR_PRIORITY, avatarPriority); CHECK_PROPERTY_CHANGE(PROP_KEY_LIGHT_MODE, keyLightMode); CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode); CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode); @@ -1420,7 +1421,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {string} filterURL="" - The URL of a JavaScript file that filters changes to properties of entities within the * zone. It is periodically executed for each entity in the zone. It can, for example, be used to not allow changes to * certain properties.
+ * + * @property {boolean} avatarPriority=false - If true avatars within this zone will have their movements distributed to other + * clients with priority over other avatars. Use, for example, on a performance stage with a few presenters. *
+ *
  * function filter(properties) {
  *     // Test and edit properties object values,
  *     // e.g., properties.modelURL, as required.
@@ -1748,6 +1753,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
         COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FLYING_ALLOWED, flyingAllowed);
         COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
         COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FILTER_URL, filterURL);
+        COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_AVATAR_PRIORITY, avatarPriority);
 
         COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString());
         COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString());
@@ -2108,6 +2114,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
     COPY_PROPERTY_FROM_QSCRIPTVALUE(flyingAllowed, bool, setFlyingAllowed);
     COPY_PROPERTY_FROM_QSCRIPTVALUE(ghostingAllowed, bool, setGhostingAllowed);
     COPY_PROPERTY_FROM_QSCRIPTVALUE(filterURL, QString, setFilterURL);
+    COPY_PROPERTY_FROM_QSCRIPTVALUE(avatarPriority, bool, setAvatarPriority);
     COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(keyLightMode, KeyLightMode);
     COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode);
     COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode);
@@ -2386,6 +2393,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
     COPY_PROPERTY_IF_CHANGED(flyingAllowed);
     COPY_PROPERTY_IF_CHANGED(ghostingAllowed);
     COPY_PROPERTY_IF_CHANGED(filterURL);
+    COPY_PROPERTY_IF_CHANGED(avatarPriority);
     COPY_PROPERTY_IF_CHANGED(keyLightMode);
     COPY_PROPERTY_IF_CHANGED(ambientLightMode);
     COPY_PROPERTY_IF_CHANGED(skyboxMode);
@@ -2770,6 +2778,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
         ADD_PROPERTY_TO_MAP(PROP_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool);
         ADD_PROPERTY_TO_MAP(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool);
         ADD_PROPERTY_TO_MAP(PROP_FILTER_URL, FilterURL, filterURL, QString);
+        ADD_PROPERTY_TO_MAP(PROP_AVATAR_PRIORITY, AvatarPriority, avatarPriority, bool);
         ADD_PROPERTY_TO_MAP(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t);
         ADD_PROPERTY_TO_MAP(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t);
         ADD_PROPERTY_TO_MAP(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t);
@@ -3169,6 +3178,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
                 APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, properties.getFlyingAllowed());
                 APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, properties.getGhostingAllowed());
                 APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, properties.getFilterURL());
+                APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, properties.getAvatarPriority());
 
                 APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)properties.getKeyLightMode());
                 APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)properties.getAmbientLightMode());
@@ -3631,6 +3641,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
         READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
         READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
         READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FILTER_URL, QString, setFilterURL);
+        READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AVATAR_PRIORITY, bool, setAvatarPriority);
 
         READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode);
         READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode);
@@ -4596,6 +4607,9 @@ QList EntityItemProperties::listChangedProperties() {
     if (filterURLChanged()) {
         out += "filterURL";
     }
+    if (avatarPriorityChanged()) {
+        out += "avatarPriority";
+    }
     if (keyLightModeChanged()) {
         out += "keyLightMode";
     }
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index dcba60b004..ff5204efe2 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -315,6 +315,7 @@ public:
     DEFINE_PROPERTY(PROP_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool, ZoneEntityItem::DEFAULT_FLYING_ALLOWED);
     DEFINE_PROPERTY(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool, ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED);
     DEFINE_PROPERTY(PROP_FILTER_URL, FilterURL, filterURL, QString, ZoneEntityItem::DEFAULT_FILTER_URL);
+    DEFINE_PROPERTY(PROP_AVATAR_PRIORITY, AvatarPriority, avatarPriority, bool, ZoneEntityItem::DEFAULT_AVATAR_PRIORITY);
     DEFINE_PROPERTY_REF_ENUM(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
     DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
     DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
@@ -679,6 +680,8 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
     DEBUG_PROPERTY_IF_CHANGED(debug, properties, GhostingAllowed, ghostingAllowed, "");
     DEBUG_PROPERTY_IF_CHANGED(debug, properties, FilterURL, filterURL, "");
 
+    DEBUG_PROPERTY_IF_CHANGED(debug, properties, AvatarPriority, avatarPriority, "");
+
     DEBUG_PROPERTY_IF_CHANGED(debug, properties, EntityHostTypeAsString, entityHostType, "");
     DEBUG_PROPERTY_IF_CHANGED(debug, properties, OwningAvatarID, owningAvatarID, "");
 
diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h
index b11ecff5bb..79303e3d61 100644
--- a/libraries/entities/src/EntityPropertyFlags.h
+++ b/libraries/entities/src/EntityPropertyFlags.h
@@ -155,6 +155,7 @@ enum EntityPropertyList {
     PROP_DERIVED_28,
     PROP_DERIVED_29,
     PROP_DERIVED_30,
+    PROP_DERIVED_31,
 
     PROP_AFTER_LAST_ITEM,
 
@@ -275,6 +276,8 @@ enum EntityPropertyList {
     PROP_SKYBOX_MODE = PROP_DERIVED_28,
     PROP_HAZE_MODE = PROP_DERIVED_29,
     PROP_BLOOM_MODE = PROP_DERIVED_30,
+    // Avatar priority
+    PROP_AVATAR_PRIORITY = PROP_DERIVED_31,
 
     // Polyvox
     PROP_VOXEL_VOLUME_SIZE = PROP_DERIVED_0,
diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp
index 7f7f6170d4..13c7273d94 100644
--- a/libraries/entities/src/ZoneEntityItem.cpp
+++ b/libraries/entities/src/ZoneEntityItem.cpp
@@ -65,6 +65,7 @@ EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& de
     COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed);
     COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed);
     COPY_ENTITY_PROPERTY_TO_PROPERTIES(filterURL, getFilterURL);
+    COPY_ENTITY_PROPERTY_TO_PROPERTIES(avatarPriority, getAvatarPriority);
 
     COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightMode, getKeyLightMode);
     COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientLightMode, getAmbientLightMode);
@@ -111,6 +112,7 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
     SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
     SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
     SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL);
+    SET_ENTITY_PROPERTY_FROM_PROPERTIES(avatarPriority, setAvatarPriority);
 
     SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightMode, setKeyLightMode);
     SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode);
@@ -186,6 +188,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
     READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
     READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
     READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL);
+    READ_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, bool, setAvatarPriority);
 
     READ_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode);
     READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode);
@@ -211,6 +214,7 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p
     requestedProperties += PROP_FLYING_ALLOWED;
     requestedProperties += PROP_GHOSTING_ALLOWED;
     requestedProperties += PROP_FILTER_URL;
+    requestedProperties += PROP_AVATAR_PRIORITY;
 
     requestedProperties += PROP_KEY_LIGHT_MODE;
     requestedProperties += PROP_AMBIENT_LIGHT_MODE;
@@ -250,6 +254,7 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
     APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed());
     APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed());
     APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL());
+    APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, getAvatarPriority());
 
     APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode());
     APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode());
diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h
index 813115add9..20bab7c710 100644
--- a/libraries/entities/src/ZoneEntityItem.h
+++ b/libraries/entities/src/ZoneEntityItem.h
@@ -96,6 +96,9 @@ public:
     QString getFilterURL() const;
     void setFilterURL(const QString url); 
 
+    bool getAvatarPriority() const { return _avatarPriority; }
+    void setAvatarPriority(bool value) { _avatarPriority = value; }
+
     bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; }
     bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; }
     bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; }
@@ -125,6 +128,7 @@ public:
     static const bool DEFAULT_FLYING_ALLOWED;
     static const bool DEFAULT_GHOSTING_ALLOWED;
     static const QString DEFAULT_FILTER_URL;
+    static const bool DEFAULT_AVATAR_PRIORITY = false;
 
 protected:
     KeyLightPropertyGroup _keyLightProperties;
@@ -149,6 +153,9 @@ protected:
     bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED };
     QString _filterURL { DEFAULT_FILTER_URL };
 
+    // Avatar-updates priority
+    bool _avatarPriority { DEFAULT_AVATAR_PRIORITY };
+
     // Dirty flags turn true when either keylight properties is changing values.
     bool _keyLightPropertiesChanged { false };
     bool _ambientLightPropertiesChanged { false };
diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h
index d898c03597..c0983f24db 100644
--- a/libraries/networking/src/udt/PacketHeaders.h
+++ b/libraries/networking/src/udt/PacketHeaders.h
@@ -260,6 +260,7 @@ enum class EntityVersion : PacketVersion {
     MissingWebEntityProperties,
     PulseProperties,
     RingGizmoEntities,
+    AvatarPriorityZone,
 
     // Add new versions above here
     NUM_PACKET_TYPE,
diff --git a/scripts/system/assets/data/createAppTooltips.json b/scripts/system/assets/data/createAppTooltips.json
index 4c78da7306..7e5f2c8659 100644
--- a/scripts/system/assets/data/createAppTooltips.json
+++ b/scripts/system/assets/data/createAppTooltips.json
@@ -134,6 +134,9 @@
     "bloom.bloomSize": {
         "tooltip": "The radius of bloom. The higher the value, the larger the bloom."
     },
+    "avatarPriority": {
+        "tooltip":  "Avatars in this zone will have a higher update priority."
+    },
     "modelURL": {
         "tooltip": "A mesh model from an FBX or OBJ file."
     },
diff --git a/scripts/system/edit.js b/scripts/system/edit.js
index 9d807264aa..67a789c266 100644
--- a/scripts/system/edit.js
+++ b/scripts/system/edit.js
@@ -382,7 +382,8 @@ const DEFAULT_ENTITY_PROPERTIES = {
             },
         },
         shapeType: "box",
-        bloomMode: "inherit"
+        bloomMode: "inherit",
+        avatarPriority: false
     },
     Model: {
         collisionShape: "none",
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js
index ee95312fa4..404ded6ae2 100644
--- a/scripts/system/html/js/entityProperties.js
+++ b/scripts/system/html/js/entityProperties.js
@@ -428,6 +428,12 @@ const GROUPS = [
                 propertyID: "bloom.bloomSize",
                 showPropertyRule: { "bloomMode": "enabled" },
             },
+            {
+                label: "Avatar Priority",
+                type: "bool",
+                propertyID: "avatarPriority",
+            },
+
         ]
     },
     {

From d7c2231f336e7a4045332ed6900251f1c63cac2c Mon Sep 17 00:00:00 2001
From: unknown 
Date: Wed, 20 Feb 2019 10:19:44 -0800
Subject: [PATCH 034/566] use root bone name from skeleton list

---
 .../Assets/Editor/AvatarExporter.cs           |  26 ++++++++++++------
 tools/unity-avatar-exporter/Assets/README.txt |   2 +-
 .../avatarExporter.unitypackage               | Bin 13667 -> 13822 bytes
 3 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter.cs b/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter.cs
index 7b90145223..65ba0312a6 100644
--- a/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter.cs
+++ b/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter.cs
@@ -14,7 +14,7 @@ using System.Collections.Generic;
 
 class AvatarExporter : MonoBehaviour {
     // update version number for every PR that changes this file, also set updated version in README file
-    static readonly string AVATAR_EXPORTER_VERSION = "0.2";
+    static readonly string AVATAR_EXPORTER_VERSION = "0.3";
     
     static readonly float HIPS_GROUND_MIN_Y = 0.01f;
     static readonly float HIPS_SPINE_CHEST_MIN_SEPARATION = 0.001f;
@@ -264,7 +264,7 @@ class AvatarExporter : MonoBehaviour {
     static string assetName = "";
     static HumanDescription humanDescription;
     static Dictionary dependencyTextures = new Dictionary();
-
+    
     [MenuItem("High Fidelity/Export New Avatar")]
     static void ExportNewAvatar() {
         ExportSelectedAvatar(false);
@@ -302,11 +302,11 @@ class AvatarExporter : MonoBehaviour {
                                                  " the Rig section of it's Inspector window.", "Ok");
             return;
         }
-
+        
         humanDescription = modelImporter.humanDescription;
         SetUserBoneInformation();
         string textureWarnings = SetTextureDependencies();
-        
+
         // check if we should be substituting a bone for a missing UpperChest mapping
         AdjustUpperChestMapping();
 
@@ -334,7 +334,7 @@ class AvatarExporter : MonoBehaviour {
             EditorUtility.DisplayDialog("Error", boneErrors, "Ok");
             return;
         }
-
+        
         string documentsFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
         string hifiFolder = documentsFolder + "\\High Fidelity Projects";
         if (updateAvatar) { // Update Existing Avatar menu option
@@ -630,12 +630,14 @@ class AvatarExporter : MonoBehaviour {
             string boneName = modelBone.name;
             if (modelBone.parent == null) {
                 // if no parent then this is actual root bone node of the user avatar, so consider it's parent as "root"
+                boneName = GetRootBoneName(); // ensure we use the root bone name from the skeleton list for consistency
                 userBoneTree = new BoneTreeNode(boneName); // initialize root of tree
                 userBoneInfo.parentName = "root";
                 userBoneInfo.boneTreeNode = userBoneTree;
             } else {
                 // otherwise add this bone node as a child to it's parent's children list
-                string parentName = modelBone.parent.name;
+                // if its a child of the root bone, use the root bone name from the skeleton list as the parent for consistency
+                string parentName = modelBone.parent.parent == null ? GetRootBoneName() : modelBone.parent.name;
                 BoneTreeNode boneTreeNode = new BoneTreeNode(boneName);
                 userBoneInfos[parentName].boneTreeNode.children.Add(boneTreeNode);
                 userBoneInfo.parentName = parentName;
@@ -658,7 +660,7 @@ class AvatarExporter : MonoBehaviour {
         }
         return result;
     }
-    
+
     static void AdjustUpperChestMapping() {
         if (!humanoidToUserBoneMappings.ContainsKey("UpperChest")) {
             // if parent of Neck is not Chest then map the parent to UpperChest
@@ -682,6 +684,14 @@ class AvatarExporter : MonoBehaviour {
         }
     }
     
+    static string GetRootBoneName() {
+        // the "root" bone is the first element in the human skeleton bone list
+        if (humanDescription.skeleton.Length > 0) {
+            return humanDescription.skeleton[0].name;
+        }
+        return "";
+    }
+    
     static void SetFailedBoneRules() {
         failedBoneRules.Clear();
         
@@ -901,7 +911,7 @@ class AvatarExporter : MonoBehaviour {
         textureDirectory = textureDirectory.Replace("\\\\", "\\");
         return textureDirectory;
     }
-    
+
     static string SetTextureDependencies() {
         string textureWarnings = "";
         dependencyTextures.Clear();
diff --git a/tools/unity-avatar-exporter/Assets/README.txt b/tools/unity-avatar-exporter/Assets/README.txt
index b81a620406..6516e4b150 100644
--- a/tools/unity-avatar-exporter/Assets/README.txt
+++ b/tools/unity-avatar-exporter/Assets/README.txt
@@ -1,6 +1,6 @@
 High Fidelity, Inc.
 Avatar Exporter
-Version 0.2
+Version 0.3
 
 Note: It is recommended to use Unity versions between 2017.4.17f1 and 2018.2.12f1 for this Avatar Exporter.
 
diff --git a/tools/unity-avatar-exporter/avatarExporter.unitypackage b/tools/unity-avatar-exporter/avatarExporter.unitypackage
index 95c000e7c61b7623e0da0a1f9974e0744375014e..4c1474631204788903d573f18fc418d9c8cb1027 100644
GIT binary patch
literal 13822
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
As{jB1

literal 13667
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
B&65BC


From 2202b695751a70837e321240581eeab51a955ec1 Mon Sep 17 00:00:00 2001
From: David Kelly 
Date: Wed, 20 Feb 2019 10:18:55 -0700
Subject: [PATCH 035/566] Guard against accidentally calling wrong
 api/v1/places endpoint

spaces
---
 domain-server/src/DomainServer.cpp          | 2 +-
 libraries/networking/src/AddressManager.cpp | 6 ++++--
 scripts/system/interstitialPage.js          | 5 +++++
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp
index 258038b8f1..85b116129c 100644
--- a/domain-server/src/DomainServer.cpp
+++ b/domain-server/src/DomainServer.cpp
@@ -2548,7 +2548,7 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite
         _pendingFileContent.seek(_pendingFileContent.size());
         _pendingFileContent.write(dataChunk);
         _pendingFileContent.close();
-        
+
         // Respond immediately - will timeout if we wait for restore.
         connection->respond(HTTPConnection::StatusCode200);
         if (itemName == "restore-file" || itemName == "restore-file-chunk-final" || itemName == "restore-file-chunk-only") {
diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp
index 9145b4a79e..f4221e3d49 100644
--- a/libraries/networking/src/AddressManager.cpp
+++ b/libraries/networking/src/AddressManager.cpp
@@ -315,7 +315,9 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
 
                 // wasn't an address - lookup the place name
                 // we may have a path that defines a relative viewpoint - pass that through the lookup so we can go to it after
-                attemptPlaceNameLookup(lookupUrl.host(), lookupUrl.path(), trigger);
+                if (!lookupUrl.host().isNull() && !lookupUrl.host().isEmpty()) {
+                    attemptPlaceNameLookup(lookupUrl.host(), lookupUrl.path(), trigger);
+                }
             }
         }
 
@@ -337,7 +339,7 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
         // be loaded over http(s)
         // lookupUrl.scheme() == URL_SCHEME_HTTP ||
         // lookupUrl.scheme() == HIFI_URL_SCHEME_HTTPS ||
-        // TODO once a file can return a connection refusal if there were to be some kind of load error, we'd 
+        // TODO once a file can return a connection refusal if there were to be some kind of load error, we'd
         // need to store the previous domain tried in _lastVisitedURL. For now , do not store it.
 
         _previousAPILookup.clear();
diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js
index 8dd94623b7..8ecc982dab 100644
--- a/scripts/system/interstitialPage.js
+++ b/scripts/system/interstitialPage.js
@@ -325,6 +325,11 @@
                 leftMargin: domainNameLeftMargin
             };
 
+            // check to be sure we are going to look for an actual domain
+            if (!domain) {
+                doRequest = false;
+            }
+
             if (doRequest) {
                 var url = Account.metaverseServerURL + '/api/v1/places/' + domain;
                 request({

From 01119a5b5d980be426bcb20bb773d2be6591ed9e Mon Sep 17 00:00:00 2001
From: David Rowe 
Date: Thu, 21 Feb 2019 11:19:29 +1300
Subject: [PATCH 036/566] Fill in Agent API JSDoc

---
 .../src/AgentScriptingInterface.h             | 31 +++++++++++++------
 .../src/avatars/ScriptableAvatar.h            |  2 +-
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/assignment-client/src/AgentScriptingInterface.h b/assignment-client/src/AgentScriptingInterface.h
index 9fa7688778..1f592a9f18 100644
--- a/assignment-client/src/AgentScriptingInterface.h
+++ b/assignment-client/src/AgentScriptingInterface.h
@@ -18,16 +18,25 @@
 #include "Agent.h"
 
 /**jsdoc
+ * The Agent API enables an assignment client to emulate an avatar. In particular, setting isAvatar = 
+ * true connects the assignment client to the avatar and audio mixers and enables the {@link Avatar} API to be used.
+ *
  * @namespace Agent
  *
  * @hifi-assignment-client
  *
- * @property {boolean} isAvatar
- * @property {boolean} isPlayingAvatarSound Read-only.
- * @property {boolean} isListeningToAudioStream
- * @property {boolean} isNoiseGateEnabled
- * @property {number} lastReceivedAudioLoudness Read-only.
- * @property {Uuid} sessionUUID Read-only.
+ * @property {boolean} isAvatar - true if the assignment client script is emulating an avatar, otherwise 
+ *     false.
+ * @property {boolean} isPlayingAvatarSound - true if the script has a sound to play, otherwise false. 
+ *     Sounds are played when isAvatar is true, from the position and with the orientation of the 
+ *     scripted avatar's head.Read-only.
+ * @property {boolean} isListeningToAudioStream - true if the agent is "listening" to the audio stream from the 
+ *     domain, otherwise false.
+ * @property {boolean} isNoiseGateEnabled - true if the noise gate is enabled, otherwise false. When 
+ * enabled, the input audio stream is blocked (fully attenuated) if it falls below an adaptive threshold.
+ * @property {number} lastReceivedAudioLoudness - The current loudness of the audio input, nominal range 0.0 (no 
+ *     sound) – 1.0 (the onset of clipping). Read-only.
+ * @property {Uuid} sessionUUID - The unique ID associated with the agent's current session in the domain. Read-only.
  */
 class AgentScriptingInterface : public QObject {
     Q_OBJECT
@@ -54,20 +63,24 @@ public:
 
 public slots:
     /**jsdoc
+     * Set whether or not the script should emulate an avatar.
      * @function Agent.setIsAvatar
-     * @param {boolean} isAvatar
+     * @param {boolean} isAvatar - true if the script should act as if an avatar, otherwise false.
      */
     void setIsAvatar(bool isAvatar) const { _agent->setIsAvatar(isAvatar); }
 
     /**jsdoc
+     * Check whether or not the script is emulating an avatar.
      * @function Agent.isAvatar
-     * @returns {boolean}
+     * @returns {boolean} true if the script is acting as if an avatar, otherwise false.
      */
     bool isAvatar() const { return _agent->isAvatar(); }
 
     /**jsdoc
+     * Play a sound from the position and with the orientation of the emulated avatar's head. No sound is played unless 
+     * isAvatar == true.
      * @function Agent.playAvatarSound
-     * @param {object} avatarSound
+     * @param {SoundObject} avatarSound - The sound to play.
      */
     void playAvatarSound(SharedSoundPointer avatarSound) const { _agent->playAvatarSound(avatarSound); }
 
diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h
index b2ad4527b0..6b78f666e1 100644
--- a/assignment-client/src/avatars/ScriptableAvatar.h
+++ b/assignment-client/src/avatars/ScriptableAvatar.h
@@ -20,7 +20,7 @@
 
 /**jsdoc
  * The Avatar API is used to manipulate scriptable avatars on the domain. This API is a subset of the 
- * {@link MyAvatar} API.
+ * {@link MyAvatar} API. To enable this API, set {@link Agent|Agent.isAvatatr} to true.
  *
  * @namespace Avatar
  *

From dca166f8219909e1a1f921638d1fc4794ec66b35 Mon Sep 17 00:00:00 2001
From: Roxanne Skelly 
Date: Wed, 20 Feb 2019 14:23:54 -0800
Subject: [PATCH 037/566] Stand-alone Optimized Tagging - Add tagging for GOTO
 User Stories

---
 interface/resources/qml/hifi/Card.qml         | 39 ++++++++++---------
 interface/resources/qml/hifi/Feed.qml         |  2 +
 .../hifi/commerce/marketplace/Marketplace.qml |  8 ++++
 3 files changed, 30 insertions(+), 19 deletions(-)

diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml
index 67abc1c3f9..9beb108b36 100644
--- a/interface/resources/qml/hifi/Card.qml
+++ b/interface/resources/qml/hifi/Card.qml
@@ -30,6 +30,7 @@ Item {
     property string imageUrl: "";
     property var goFunction: null;
     property string storyId: "";
+    property bool standaloneOptimized: false;
 
     property bool drillDownToPlace: false;
     property bool showPlace: isConcurrency;
@@ -39,7 +40,7 @@ Item {
     property bool isConcurrency: action === 'concurrency';
     property bool isAnnouncement: action === 'announcement';
     property bool isStacked: !isConcurrency && drillDownToPlace;
-    property bool standaloneOptimized: true;
+
 
     property int textPadding: 10;
     property int smallMargin: 4;
@@ -271,6 +272,24 @@ Item {
             goFunction("hifi://" + hifiUrl);
         }
     }
+
+    HiFiGlyphs {
+        id: standaloneOptomizedBadge
+
+        anchors {
+            right: actionIcon.left
+            bottom: parent.bottom;
+        }
+        height: (root.isConcurrency && root.standaloneOptimized) ? 34 : 0
+
+        visible: root.isConcurrency && root.standaloneOptimized
+
+        text: hifi.glyphs.hmd
+        size: 34
+        horizontalAlignment: Text.AlignHCenter
+        color: messageColor
+     }
+
     StateImage {
         id: actionIcon;
         visible: !isAnnouncement;
@@ -282,24 +301,6 @@ Item {
             right: parent.right;
             margins: smallMargin;
         }
-        
-    }
-    HiFiGlyphs {
-        id: standaloneOptomizedBadge
-
-        anchors {
-            right: actionIcon.left
-            verticalCenter: parent.verticalCenter
-            bottom: parent.bottom;
-        }
-        height: root.standaloneOptimized ? 34 : 0
-        
-        visible: standaloneOptimized
-
-        text: hifi.glyphs.hmd
-        size: 34
-        horizontalAlignment: Text.AlignHCenter
-        color: hifi.colors.blueHighlight
     }  
 
     function go() {
diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml
index 1e89971938..68aab2fdd2 100644
--- a/interface/resources/qml/hifi/Feed.qml
+++ b/interface/resources/qml/hifi/Feed.qml
@@ -82,6 +82,7 @@ Column {
             action: data.action || "",
             thumbnail_url: resolveUrl(thumbnail_url),
             image_url: resolveUrl(data.details && data.details.image_url),
+            standalone_optimized: data.standalone_optimized,
 
             metaverseId: (data.id || "").toString(), // Some are strings from server while others are numbers. Model objects require uniformity.
 
@@ -127,6 +128,7 @@ Column {
             hifiUrl: model.place_name + model.path;
             thumbnail: model.thumbnail_url;
             imageUrl: model.image_url;
+            standaloneOptimized: model.standalone_optimized;
             action: model.action;
             timestamp: model.created_at;
             onlineUsers: model.online_users;
diff --git a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml
index 8c7e050ec2..5f97e64e6c 100644
--- a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml
+++ b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml
@@ -90,6 +90,14 @@ Rectangle {
                     id: -1,
                     name: "Everything"
                 });
+                categoriesModel.append({
+                    id: -1,
+                    name: "Standalone Optimized"
+                });
+                categoriesModel.append({
+                    id: -1,
+                    name: "Standalone Compatible"
+                });
                 result.data.items.forEach(function(category) {
                     categoriesModel.append({
                         id: category.id,

From 7f1ae634391eb8dce84f086ad60835b109c93b2f Mon Sep 17 00:00:00 2001
From: David Rowe 
Date: Thu, 21 Feb 2019 14:30:38 +1300
Subject: [PATCH 038/566] Revise current Avatar API JSDoc

---
 .../src/avatars/ScriptableAvatar.h            | 48 +++++++----------
 libraries/avatars/src/AvatarData.h            | 54 ++++++++++---------
 2 files changed, 47 insertions(+), 55 deletions(-)

diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h
index 6b78f666e1..3cf10cc129 100644
--- a/assignment-client/src/avatars/ScriptableAvatar.h
+++ b/assignment-client/src/avatars/ScriptableAvatar.h
@@ -28,7 +28,8 @@
  *
  * @comment IMPORTANT: This group of properties is copied from AvatarData.h; they should NOT be edited here.
  * @property {Vec3} position
- * @property {number} scale - Returns the clamped scale of the avatar.
+ * @property {number} scale=1.0 - The scale of the avatar. When setting, the value is limited to between 0.005
+ *     and 1000.0. When getting, the value may temporarily be further limited by the domain's settings.
  * @property {number} density Read-only.
  * @property {Vec3} handPosition
  * @property {number} bodyYaw - The rotation left or right about an axis running from the head to the feet of the avatar.
@@ -50,8 +51,9 @@
  * @property {number} audioLoudness
  * @property {number} audioAverageLoudness
  * @property {string} displayName
- * @property {string} sessionDisplayName - Sanitized, defaulted version displayName that is defined by the AvatarMixer
- *     rather than by Interface clients. The result is unique among all avatars present at the time.
+ * @property {string} sessionDisplayName - Sanitized, defaulted version of displayName that is defined by the
+ *     avatar mixer rather than by Interface clients. The result is unique among all avatars present on the domain at the
+ *     time.
  * @property {boolean} lookAtSnappingEnabled
  * @property {string} skeletonModelURL
  * @property {AttachmentData[]} attachmentData
@@ -102,24 +104,12 @@ public:
     Q_INVOKABLE AnimationDetails getAnimationDetails();
 
     /**jsdoc
-     * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc.
- * Get the names of all the joints in the current avatar. - * @function Avatar.getJointNames - * @returns {string[]} The joint names. - * @example Report the names of all the joints in your current avatar. - * print(JSON.stringify(Avatar.getJointNames())); + * @comment Uses the base class's JSDoc. */ Q_INVOKABLE virtual QStringList getJointNames() const override; /**jsdoc - * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc.
- * Get the joint index for a named joint. The joint index value is the position of the joint in the array returned by - * {@link Avatar.getJointNames}. - * @function Avatar.getJointIndex - * @param {string} name - The name of the joint. - * @returns {number} The index of the joint. - * @example Report the index of your avatar's left arm joint. - * print(JSON.stringify(Avatar.getJointIndex("LeftArm")); + * @comment Uses the base class's JSDoc. */ /// Returns the index of the joint with the specified name, or -1 if not found/unknown. Q_INVOKABLE virtual int getJointIndex(const QString& name) const override; @@ -137,39 +127,37 @@ public: void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement); bool getHasAudioEnabledFaceMovement() const override { return _headData->getHasAudioEnabledFaceMovement(); } - /**jsdoc - * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc.
- * ####### Also need to resolve with MyAvatar.
- * Potentially Very Expensive. Do not use. + /**jsdoc + * Get the avatar entities as binary data. + *

Warning: Potentially a very expensive call. Do not use if possible.

* @function Avatar.getAvatarEntityData - * @returns {object} + * @returns {AvatarEntityMap} */ Q_INVOKABLE AvatarEntityMap getAvatarEntityData() const override; /**jsdoc - * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc. + * Set the avatar entities from binary data. + *

Warning: Potentially an expensive call. Do not use if possible.

* @function Avatar.setAvatarEntityData - * @param {object} avatarEntityData + * @param {AvatarEntityMap} avatarEntityData */ Q_INVOKABLE void setAvatarEntityData(const AvatarEntityMap& avatarEntityData) override; /**jsdoc - * ####### TODO: If this override changes the function use @override and do JSDoc here, otherwise @comment that uses base class's JSDoc. - * @function Avatar.updateAvatarEntity - * @param {Uuid} entityID - * @param {string} entityData + * @comment Uses the base class's JSDoc. */ Q_INVOKABLE void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) override; public slots: /**jsdoc * @function Avatar.update + * @param {number} deltaTime */ void update(float deltatime); /**jsdoc - * @function Avatar.setJointMappingsFromNetworkReply - */ + * @function Avatar.setJointMappingsFromNetworkReply + */ void setJointMappingsFromNetworkReply(); private: diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7a4d235565..0a5509f46c 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -61,6 +61,10 @@ using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; using AvatarHash = QHash; +/**jsdoc + * An object with the UUIDs of avatar entities as keys and binary blobs, being the entity properties, as values. + * @typedef {Object.>} AvatarEntityMap + */ using AvatarEntityMap = QMap; using PackedAvatarEntityMap = QMap; // similar to AvatarEntityMap, but different internal format using AvatarEntityIDs = QSet; @@ -414,7 +418,8 @@ class AvatarData : public QObject, public SpatiallyNestable { // IMPORTANT: The JSDoc for the following properties should be copied to MyAvatar.h and ScriptableAvatar.h. /* * @property {Vec3} position - * @property {number} scale - Returns the clamped scale of the avatar. + * @property {number} scale=1.0 - The scale of the avatar. When setting, the value is limited to between 0.005 + * and 1000.0. When getting, the value may temporarily be further limited by the domain's settings. * @property {number} density Read-only. * @property {Vec3} handPosition * @property {number} bodyYaw - The rotation left or right about an axis running from the head to the feet of the avatar. @@ -436,8 +441,9 @@ class AvatarData : public QObject, public SpatiallyNestable { * @property {number} audioLoudness * @property {number} audioAverageLoudness * @property {string} displayName - * @property {string} sessionDisplayName - Sanitized, defaulted version displayName that is defined by the AvatarMixer - * rather than by Interface clients. The result is unique among all avatars present at the time. + * @property {string} sessionDisplayName - Sanitized, defaulted version of displayName that is defined by the + * avatar mixer rather than by Interface clients. The result is unique among all avatars present on the domain at the + * time. * @property {boolean} lookAtSnappingEnabled * @property {string} skeletonModelURL * @property {AttachmentData[]} attachmentData @@ -601,18 +607,18 @@ public: virtual bool getHasAudioEnabledFaceMovement() const { return false; } /**jsdoc - * Returns the minimum scale allowed for this avatar in the current domain. + * Get the minimum scale allowed for this avatar in the current domain. * This value can change as the user changes avatars or when changing domains. * @function Avatar.getDomainMinScale - * @returns {number} minimum scale allowed for this avatar in the current domain. + * @returns {number} The minimum scale allowed for this avatar in the current domain. */ Q_INVOKABLE float getDomainMinScale() const; /**jsdoc - * Returns the maximum scale allowed for this avatar in the current domain. + * Get the maximum scale allowed for this avatar in the current domain. * This value can change as the user changes avatars or when changing domains. * @function Avatar.getDomainMaxScale - * @returns {number} maximum scale allowed for this avatar in the current domain. + * @returns {number} The maximum scale allowed for this avatar in the current domain. */ Q_INVOKABLE float getDomainMaxScale() const; @@ -625,18 +631,18 @@ public: virtual bool canMeasureEyeHeight() const { return false; } /**jsdoc - * Provides read only access to the current eye height of the avatar. + * Get the current eye height of the avatar. * This height is only an estimate and might be incorrect for avatars that are missing standard joints. * @function Avatar.getEyeHeight - * @returns {number} Eye height of avatar in meters. + * @returns {number} The eye height of the avatar. */ Q_INVOKABLE virtual float getEyeHeight() const { return _targetScale * getUnscaledEyeHeight(); } /**jsdoc - * Provides read only access to the current height of the avatar. + * Get the current height of the avatar. * This height is only an estimate and might be incorrect for avatars that are missing standard joints. * @function Avatar.getHeight - * @returns {number} Height of avatar in meters. + * @returns {number} The height of the avatar. */ Q_INVOKABLE virtual float getHeight() const; @@ -739,7 +745,7 @@ public: /**jsdoc * Get the rotation of a joint relative to its parent. For information on the joint hierarchy used, see - * Avatar Standards. + * Avatar Standards. * @function Avatar.getJointRotation * @param {number} index - The index of the joint. * @returns {Quat} The rotation of the joint relative to its parent. @@ -748,7 +754,7 @@ public: /**jsdoc * Get the translation of a joint relative to its parent. For information on the joint hierarchy used, see - * Avatar Standards. + * Avatar Standards. * @function Avatar.getJointTranslation * @param {number} index - The index of the joint. * @returns {Vec3} The translation of the joint relative to its parent. @@ -855,7 +861,7 @@ public: /**jsdoc * Get the rotation of a joint relative to its parent. For information on the joint hierarchy used, see - * Avatar Standards. + * Avatar Standards. * @function Avatar.getJointRotation * @param {string} name - The name of the joint. * @returns {Quat} The rotation of the joint relative to its parent. @@ -868,7 +874,7 @@ public: /**jsdoc * Get the translation of a joint relative to its parent. For information on the joint hierarchy used, see - * Avatar Standards. + * Avatar Standards. * @function Avatar.getJointTranslation * @param {number} name - The name of the joint. * @returns {Vec3} The translation of the joint relative to its parent. @@ -883,7 +889,7 @@ public: * Get the rotations of all joints in the current avatar. Each joint's rotation is relative to its parent joint. * @function Avatar.getJointRotations * @returns {Quat[]} The rotations of all joints relative to each's parent. The values are in the same order as the array - * returned by {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}. + * returned by {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the Avatar API. * @example Report the rotations of all your avatar's joints. * print(JSON.stringify(MyAvatar.getJointRotations())); * @@ -906,7 +912,7 @@ public: * the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.

* @function Avatar.setJointRotations * @param {Quat[]} jointRotations - The rotations for all joints in the avatar. The values are in the same order as the - * array returned by {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}. + * array returned by {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the Avatar API. * @example Set your avatar to its default T-pose then rotate its right arm.
* Avatar in T-pose * // Set all joint translations and rotations to defaults. @@ -965,10 +971,10 @@ public: /**jsdoc * Get the joint index for a named joint. The joint index value is the position of the joint in the array returned by - * {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}. + * {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the Avatar API. * @function Avatar.getJointIndex * @param {string} name - The name of the joint. - * @returns {number} The index of the joint. + * @returns {number} The index of the joint if valid, otherwise -1. * @example Report the index of your avatar's left arm joint. * print(JSON.stringify(MyAvatar.getJointIndex("LeftArm")); * @@ -1016,14 +1022,14 @@ public: /**jsdoc * @function Avatar.updateAvatarEntity * @param {Uuid} entityID - * @param {string} entityData + * @param {Array.} entityData */ Q_INVOKABLE virtual void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData); /**jsdoc * @function Avatar.clearAvatarEntity * @param {Uuid} entityID - * @param {boolean} [requiresRemovalFromTree] + * @param {boolean} [requiresRemovalFromTree=true] */ Q_INVOKABLE virtual void clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree = true); @@ -1201,14 +1207,12 @@ public: AABox getDefaultBubbleBox() const; /**jsdoc - * @function Avatar.getAvatarEntityData - * @returns {object} + * @comment Documented in derived classes' JSDoc. */ Q_INVOKABLE virtual AvatarEntityMap getAvatarEntityData() const; /**jsdoc - * @function Avatar.setAvatarEntityData - * @param {object} avatarEntityData + * @comment Documented in derived classes' JSDoc. */ Q_INVOKABLE virtual void setAvatarEntityData(const AvatarEntityMap& avatarEntityData); From 4fdf556d5dc37bd62df39f7e4cd001a513a922de Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 21 Feb 2019 10:29:21 -0800 Subject: [PATCH 039/566] fix billboard mode in secondary camera --- interface/src/Application.cpp | 18 +++++++++--------- .../src/RenderableImageEntityItem.cpp | 2 +- .../src/RenderableTextEntityItem.cpp | 2 +- .../src/RenderableWebEntityItem.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 3 ++- libraries/entities/src/EntityItem.h | 9 ++++++--- libraries/entities/src/ImageEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.cpp | 2 +- 9 files changed, 23 insertions(+), 19 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a611738445..83b287b7ae 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2301,31 +2301,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get()->setPrecisionPicking(rayPickID, value); }); - EntityItem::setBillboardRotationOperator([this](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode) { + EntityItem::setBillboardRotationOperator([this](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos) { if (billboardMode == BillboardMode::YAW) { //rotate about vertical to face the camera - ViewFrustum frustum; - copyViewFrustum(frustum); - glm::vec3 dPosition = frustum.getPosition() - position; + glm::vec3 dPosition = frustumPos - position; // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); return glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); } else if (billboardMode == BillboardMode::FULL) { - ViewFrustum frustum; - copyViewFrustum(frustum); - glm::vec3 cameraPos = frustum.getPosition(); // use the referencial from the avatar, y isn't always up glm::vec3 avatarUP = DependencyManager::get()->getMyAvatar()->getWorldOrientation() * Vectors::UP; // check to see if glm::lookAt will work / using glm::lookAt variable name - glm::highp_vec3 s(glm::cross(position - cameraPos, avatarUP)); + glm::highp_vec3 s(glm::cross(position - frustumPos, avatarUP)); // make sure s is not NaN for any component if (glm::length2(s) > 0.0f) { - return glm::conjugate(glm::toQuat(glm::lookAt(cameraPos, position, avatarUP))); + return glm::conjugate(glm::toQuat(glm::lookAt(frustumPos, position, avatarUP))); } } return rotation; }); + EntityItem::setPrimaryViewFrustumPositionOperator([this]() { + ViewFrustum viewFrustum; + copyViewFrustum(viewFrustum); + return viewFrustum.getPosition(); + }); render::entities::WebEntityRenderer::setAcquireWebSurfaceOperator([this](const QString& url, bool htmlContent, QSharedPointer& webSurface, bool& cachedWebSurface) { bool isTablet = url == TabletScriptingInterface::QML; diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index 96dd1733e7..6638bc0687 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -170,7 +170,7 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch* batch = args->_batch; - transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode)); + transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition())); transform.postScale(dimensions); batch->setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 99912e9d91..dfc9277bf0 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -181,7 +181,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { gpu::Batch& batch = *args->_batch; auto transformToTopLeft = modelTransform; - transformToTopLeft.setRotation(EntityItem::getBillboardRotation(transformToTopLeft.getTranslation(), transformToTopLeft.getRotation(), _billboardMode)); + transformToTopLeft.setRotation(EntityItem::getBillboardRotation(transformToTopLeft.getTranslation(), transformToTopLeft.getRotation(), _billboardMode, args->getViewFrustum().getPosition())); transformToTopLeft.postTranslate(dimensions * glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index bf7820fecd..ccd815b74a 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -323,7 +323,7 @@ void WebEntityRenderer::doRender(RenderArgs* args) { }); batch.setResourceTexture(0, _texture); - transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode)); + transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition())); batch.setModelTransform(transform); // Turn off jitter for these entities diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9f11b3c018..a431c82390 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -49,7 +49,8 @@ int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; QString EntityItem::_marketplacePublicKey; -std::function EntityItem::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode) { return rotation; }; +std::function EntityItem::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode, const glm::vec3&) { return rotation; }; +std::function EntityItem::_getPrimaryViewFrustumPositionOperator = []() { return glm::vec3(0.0f); }; EntityItem::EntityItem(const EntityItemID& entityItemID) : SpatiallyNestable(NestableType::Entity, entityItemID) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 824261c022..0ca851e228 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -557,8 +557,10 @@ public: virtual void removeGrab(GrabPointer grab) override; virtual void disableGrab(GrabPointer grab) override; - static void setBillboardRotationOperator(std::function getBillboardRotationOperator) { _getBillboardRotationOperator = getBillboardRotationOperator; } - static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode) { return _getBillboardRotationOperator(position, rotation, billboardMode); } + static void setBillboardRotationOperator(std::function getBillboardRotationOperator) { _getBillboardRotationOperator = getBillboardRotationOperator; } + static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos) { return _getBillboardRotationOperator(position, rotation, billboardMode, frustumPos); } + static void setPrimaryViewFrustumPositionOperator(std::function getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; } + static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); } signals: void requestRenderUpdate(); @@ -748,7 +750,8 @@ protected: QHash _grabActions; private: - static std::function _getBillboardRotationOperator; + static std::function _getBillboardRotationOperator; + static std::function _getPrimaryViewFrustumPositionOperator; }; #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp index 837e824f4a..090ae91277 100644 --- a/libraries/entities/src/ImageEntityItem.cpp +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -159,7 +159,7 @@ bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::quat rotation = getWorldOrientation(); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); - rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode); + rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition()); if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { glm::vec3 forward = rotation * Vectors::FRONT; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index bc98c61ff7..5dff645c89 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -199,7 +199,7 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::quat rotation = getWorldOrientation(); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); - rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode); + rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition()); if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { glm::vec3 forward = rotation * Vectors::FRONT; diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 5a948fbfd4..0748790df9 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -180,7 +180,7 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::quat rotation = getWorldOrientation(); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); - rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode); + rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition()); if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { glm::vec3 forward = rotation * Vectors::FRONT; From 77d4060fdb8b78ac2e1bdfeffaa9d75502bb3861 Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Thu, 21 Feb 2019 11:37:50 -0800 Subject: [PATCH 040/566] bypassing onStop invoke.Delegate command which prevents the disconnect from Java hooks that are not initiated on restart. On Destroy, the onstop function is called to allow the hooks to finally disconnect and then terminate the app. --- .../oculus/OculusMobileActivity.java | 24 +++++++++++-------- .../qt5/android/bindings/QtActivity.java | 7 +++++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java b/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java index 9ab07bb4dd..2aa7b4da05 100644 --- a/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java +++ b/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java @@ -34,7 +34,6 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca private native void questNativeOnResume(); private native void questOnAppAfterLoad(); - private SurfaceView mView; private SurfaceHolder mSurfaceHolder; @@ -57,12 +56,15 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca setContentView(mView); questOnAppAfterLoad(); }); + + } @Override protected void onDestroy() { Log.w(TAG, "QQQ onDestroy"); - + isPausing=false; + super.onStop(); nativeOnSurfaceChanged(null); Log.w(TAG, "QQQ onDestroy -- SUPER onDestroy"); @@ -78,6 +80,7 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca questNativeOnResume(); nativeOnResume(); + isPausing=false; } @Override @@ -87,40 +90,41 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca questNativeOnPause(); nativeOnPause(); + isPausing=true; } @Override protected void onStop(){ super.onStop(); - Log.w(TAG, "QQQ Onstop called"); + Log.w(TAG, "QQQ_ Onstop called"); } @Override - protected void onRestart(){ + protected void onRestart() { super.onRestart(); - Log.w(TAG, "QQQ onRestart called ****"); + Log.w(TAG, "QQQ_ onRestart called ****"); questOnAppAfterLoad(); } @Override public void surfaceCreated(SurfaceHolder holder) { - Log.w(TAG, "QQQ surfaceCreated ************************************"); + Log.w(TAG, "QQQ_ surfaceCreated ************************************"); nativeOnSurfaceChanged(holder.getSurface()); mSurfaceHolder = holder; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.w(TAG, "QQQ surfaceChanged"); + Log.w(TAG, "QQQ_ surfaceChanged"); nativeOnSurfaceChanged(holder.getSurface()); mSurfaceHolder = holder; } @Override public void surfaceDestroyed(SurfaceHolder holder) { - Log.w(TAG, "QQQ surfaceDestroyed ***************************************************"); - nativeOnSurfaceChanged(null); - mSurfaceHolder = null; + Log.w(TAG, "QQQ_ surfaceDestroyed ***************************************************"); + // nativeOnSurfaceChanged(null); + // mSurfaceHolder = null; } } \ No newline at end of file diff --git a/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java b/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java index 46f2af46e7..85e93a4267 100644 --- a/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java @@ -70,6 +70,7 @@ public class QtActivity extends Activity { public final String QT_ANDROID_DEFAULT_THEME = QT_ANDROID_THEMES[0]; // sets the default theme. private QtActivityLoader m_loader = new QtActivityLoader(this); + public boolean isPausing=false; public QtActivity() { } @@ -650,9 +651,13 @@ public class QtActivity extends Activity { @Override protected void onStop() { super.onStop(); - QtApplication.invokeDelegate(); + + if(!isPausing){ + QtApplication.invokeDelegate(); + } } + //--------------------------------------------------------------------------- @Override From 544f54e69a7b55e2b01b0008a26f257dd7c04f4b Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 21 Feb 2019 14:10:36 -0800 Subject: [PATCH 041/566] fix model scale --- interface/src/ui/overlays/Overlays.cpp | 15 +++++++-- .../entities/src/EntityItemProperties.cpp | 10 ++++++ libraries/entities/src/EntityItemProperties.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 31 ++++++++++--------- libraries/entities/src/ModelEntityItem.cpp | 17 ++++++++++ libraries/entities/src/ModelEntityItem.h | 4 +++ libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/shared/src/SpatiallyNestable.cpp | 2 +- 8 files changed, 62 insertions(+), 19 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 660220c731..081085408d 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -311,7 +311,11 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove RENAME_PROP(start, position); } RENAME_PROP(point, position); - RENAME_PROP(scale, dimensions); + if (type != "Model") { + RENAME_PROP(scale, dimensions); + } else { + RENAME_PROP(scale, modelScale); + } RENAME_PROP(size, dimensions); RENAME_PROP(orientation, rotation); RENAME_PROP(localOrientation, localRotation); @@ -636,7 +640,11 @@ QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemPropertie RENAME_PROP(position, start); } RENAME_PROP(position, point); - RENAME_PROP(dimensions, scale); + if (type != "Model") { + RENAME_PROP(dimensions, scale); + } else { + RENAME_PROP(modelScale, scale); + } RENAME_PROP(dimensions, size); RENAME_PROP(ignorePickIntersection, ignoreRayIntersection); @@ -1718,7 +1726,8 @@ QVector Overlays::findOverlays(const glm::vec3& center, float radius) { * * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and * start. - * @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: scale, size. + * @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: size. + * @property {Vec3} scale - The scale factor applied to the model's dimensions. * @property {Quat} rotation - The orientation of the overlay. Synonym: orientation. * @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a * parentID set, otherwise the same value as position. diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 6738b1cedd..75e2069471 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -580,6 +580,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { // Model CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); + CHECK_PROPERTY_CHANGE(PROP_MODEL_SCALE, modelScale); CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet); CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS, jointRotations); CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); @@ -1012,6 +1013,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. When adding an entity, if no dimensions * value is specified then the model is automatically sized to its * {@link Entities.EntityProperties|naturalDimensions}. + * @property {Vec3} modelScale - The scale factor applied to the model's dimensions. * @property {Color} color=255,255,255 - Currently not used. * @property {string} modelURL="" - The URL of the FBX of OBJ model. Baked FBX models' URLs end in ".baked.fbx".
* @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the @@ -1683,6 +1685,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_SCALE, modelScale); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS, jointRotations); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); @@ -2078,6 +2081,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool // Model COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE(modelScale, vec3, setModelScale); COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotationsSet, qVectorBool, setJointRotationsSet); COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotations, qVectorQuat, setJointRotations); COPY_PROPERTY_FROM_QSCRIPTVALUE(jointTranslationsSet, qVectorBool, setJointTranslationsSet); @@ -2357,6 +2361,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { // Model COPY_PROPERTY_IF_CHANGED(modelURL); + COPY_PROPERTY_IF_CHANGED(modelScale); COPY_PROPERTY_IF_CHANGED(jointRotationsSet); COPY_PROPERTY_IF_CHANGED(jointRotations); COPY_PROPERTY_IF_CHANGED(jointTranslationsSet); @@ -2700,6 +2705,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr // Model ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString); + ADD_PROPERTY_TO_MAP(PROP_MODEL_SCALE, ModelScale, modelScale, vec3); ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector); ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector); ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector); @@ -3989,6 +3995,7 @@ void EntityItemProperties::markAllChanged() { // Model _modelURLChanged = true; + _modelScaleChanged = true; _jointRotationsSetChanged = true; _jointRotationsChanged = true; _jointTranslationsSetChanged = true; @@ -4526,6 +4533,9 @@ QList EntityItemProperties::listChangedProperties() { if (modelURLChanged()) { out += "modelURL"; } + if (modelScaleChanged()) { + out += "scale"; + } if (jointRotationsSetChanged()) { out += "jointRotationsSet"; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 712f2d120f..afc3537559 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -279,6 +279,7 @@ public: // Model DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString, ""); + DEFINE_PROPERTY_REF(PROP_MODEL_SCALE, ModelScale, modelScale, glm::vec3, glm::vec3(1.0f)); DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector, QVector()); DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector, QVector()); DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector, QVector()); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 093df92dc1..cce30c9614 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -202,22 +202,23 @@ enum EntityPropertyList { // Model PROP_MODEL_URL = PROP_DERIVED_0, - PROP_JOINT_ROTATIONS_SET = PROP_DERIVED_1, - PROP_JOINT_ROTATIONS = PROP_DERIVED_2, - PROP_JOINT_TRANSLATIONS_SET = PROP_DERIVED_3, - PROP_JOINT_TRANSLATIONS = PROP_DERIVED_4, - PROP_RELAY_PARENT_JOINTS = PROP_DERIVED_5, - PROP_GROUP_CULLED = PROP_DERIVED_6, + PROP_MODEL_SCALE = PROP_DERIVED_1, + PROP_JOINT_ROTATIONS_SET = PROP_DERIVED_2, + PROP_JOINT_ROTATIONS = PROP_DERIVED_3, + PROP_JOINT_TRANSLATIONS_SET = PROP_DERIVED_4, + PROP_JOINT_TRANSLATIONS = PROP_DERIVED_5, + PROP_RELAY_PARENT_JOINTS = PROP_DERIVED_6, + PROP_GROUP_CULLED = PROP_DERIVED_7, // Animation - PROP_ANIMATION_URL = PROP_DERIVED_7, - PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_8, - PROP_ANIMATION_FPS = PROP_DERIVED_9, - PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_10, - PROP_ANIMATION_PLAYING = PROP_DERIVED_11, - PROP_ANIMATION_LOOP = PROP_DERIVED_12, - PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_13, - PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_14, - PROP_ANIMATION_HOLD = PROP_DERIVED_15, + PROP_ANIMATION_URL = PROP_DERIVED_8, + PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_9, + PROP_ANIMATION_FPS = PROP_DERIVED_10, + PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_11, + PROP_ANIMATION_PLAYING = PROP_DERIVED_12, + PROP_ANIMATION_LOOP = PROP_DERIVED_13, + PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_14, + PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_15, + PROP_ANIMATION_HOLD = PROP_DERIVED_16, // Light PROP_IS_SPOTLIGHT = PROP_DERIVED_0, diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index e365d0a7b6..bb8f375302 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -63,6 +63,7 @@ EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& d COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelScale, getModelScale); COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotationsSet, getJointRotationsSet); COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotations, getJointRotations); COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointTranslationsSet, getJointTranslationsSet); @@ -85,6 +86,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelScale, setModelScale); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotationsSet, setJointRotationsSet); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotations, setJointRotations); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslationsSet, setJointTranslationsSet); @@ -128,6 +130,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL); + READ_ENTITY_PROPERTY(PROP_MODEL_SCALE, glm::vec3, setModelScale); READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, QVector, setJointRotationsSet); READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, QVector, setJointRotations); READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); @@ -165,6 +168,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& requestedProperties += PROP_TEXTURES; requestedProperties += PROP_MODEL_URL; + requestedProperties += PROP_MODEL_SCALE; requestedProperties += PROP_JOINT_ROTATIONS_SET; requestedProperties += PROP_JOINT_ROTATIONS; requestedProperties += PROP_JOINT_TRANSLATIONS_SET; @@ -192,6 +196,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL()); + APPEND_ENTITY_PROPERTY(PROP_MODEL_SCALE, getModelScale()); APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, getJointRotationsSet()); APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, getJointRotations()); APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, getJointTranslationsSet()); @@ -708,3 +713,15 @@ bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProp } return somethingChanged; } + +glm::vec3 ModelEntityItem::getModelScale() const { + return _modelScaleLock.resultWithReadLock([&] { + return getSNScale(); + }); +} + +void ModelEntityItem::setModelScale(const glm::vec3& modelScale) { + _modelScaleLock.withWriteLock([&] { + setSNScale(modelScale); + }); +} \ No newline at end of file diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 649a6cb50f..234cfa435e 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -126,6 +126,9 @@ public: QVector getJointTranslations() const; QVector getJointTranslationsSet() const; + glm::vec3 getModelScale() const; + void setModelScale(const glm::vec3& modelScale); + private: void setAnimationSettings(const QString& value); // only called for old bitstream format bool applyNewAnimationProperties(AnimationPropertyGroup newProperties); @@ -141,6 +144,7 @@ protected: // they aren't currently updated from data in the model/rig, and they don't have a direct effect // on what's rendered. ReadWriteLockable _jointDataLock; + ReadWriteLockable _modelScaleLock; bool _jointRotationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 5f55c189ce..b6fcd2f2ce 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -262,6 +262,7 @@ enum class EntityVersion : PacketVersion { RingGizmoEntities, ShowKeyboardFocusHighlight, WebBillboardMode, + ModelScale, // Add new versions above here NUM_PACKET_TYPE, diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 19fafdccf4..b48b8d0e16 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -861,7 +861,7 @@ void SpatiallyNestable::setSNScale(const glm::vec3& scale, bool& success) { } }); if (success && changed) { - locationChanged(); + dimensionsChanged(); } } From fe33aadd698c6cc415b960418ca7de111e877509 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 21 Feb 2019 14:58:06 -0800 Subject: [PATCH 042/566] Assigning the default world detail and max render rate target in vr quest --- interface/src/LODManager.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 559bae1779..5817eafc25 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -19,13 +19,20 @@ #include #include +#include + #ifdef Q_OS_ANDROID -const float LOD_DEFAULT_QUALITY_LEVEL = 0.75f; // default quality level setting is High (lower framerate) +const float LOD_DEFAULT_QUALITY_LEVEL = 0.2; // default quality level setting is High (lower framerate) #else const float LOD_DEFAULT_QUALITY_LEVEL = 0.5f; // default quality level setting is Mid #endif const float LOD_MAX_LIKELY_DESKTOP_FPS = 60.0f; // this is essentially, V-synch fps +#ifdef Q_OS_ANDROID +const float LOD_MAX_LIKELY_HMD_FPS = 36.0f; // this is essentially, V-synch fps +#else const float LOD_MAX_LIKELY_HMD_FPS = 90.0f; // this is essentially, V-synch fps +#endif + const float LOD_OFFSET_FPS = 5.0f; // offset of FPS to add for computing the target framerate class AABox; From 9097d9c57cdf1416c32e1a661144d096fd8f8f79 Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Thu, 21 Feb 2019 16:33:25 -0800 Subject: [PATCH 043/566] working on pause -> away mode. Even doesn't seem to be firing. Also found a spot where I left commented out code from lifecycle testing. --- android/apps/questInterface/src/main/cpp/native.cpp | 6 +++++- .../io/highfidelity/oculus/OculusMobileActivity.java | 10 +++++++--- interface/src/AndroidHelper.cpp | 4 ++++ interface/src/AndroidHelper.h | 3 ++- interface/src/Application.cpp | 10 ++++++++++ interface/src/Application.h | 3 ++- scripts/+android_questInterface/defaultScripts.js | 4 ++-- scripts/system/away.js | 3 ++- 8 files changed, 34 insertions(+), 9 deletions(-) diff --git a/android/apps/questInterface/src/main/cpp/native.cpp b/android/apps/questInterface/src/main/cpp/native.cpp index 3c1563c93d..547874b84e 100644 --- a/android/apps/questInterface/src/main/cpp/native.cpp +++ b/android/apps/questInterface/src/main/cpp/native.cpp @@ -61,7 +61,7 @@ extern "C" { Java_io_highfidelity_oculus_OculusMobileActivity_nativeInitOculusPlatform(JNIEnv *env, jobject obj){ initOculusPlatform(env, obj); } -QAndroidJniObject __interfaceActivity; + QAndroidJniObject __interfaceActivity; JNIEXPORT void JNICALL Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnCreate(JNIEnv *env, jobject obj) { @@ -80,6 +80,10 @@ QAndroidJniObject __interfaceActivity; }); } + JNIEXPORT void JNICALL + Java_io_highfidelity_oculus_OculusMobileActivity_questNativeAwayMode(JNIEnv *env, jobject obj) { + AndroidHelper::instance().toggleAwayMode(); + } JNIEXPORT void Java_io_highfidelity_oculus_OculusMobileActivity_questOnAppAfterLoad(JNIEnv* env, jobject obj) { diff --git a/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java b/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java index 2aa7b4da05..71ccfa84cd 100644 --- a/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java +++ b/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java @@ -34,6 +34,7 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca private native void questNativeOnResume(); private native void questOnAppAfterLoad(); + private native void questNativeAwayMode(); private SurfaceView mView; private SurfaceHolder mSurfaceHolder; @@ -55,6 +56,7 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca runOnUiThread(() -> { setContentView(mView); questOnAppAfterLoad(); + }); @@ -91,12 +93,14 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca questNativeOnPause(); nativeOnPause(); isPausing=true; + } @Override protected void onStop(){ super.onStop(); Log.w(TAG, "QQQ_ Onstop called"); + questNativeAwayMode(); } @Override @@ -104,6 +108,7 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca super.onRestart(); Log.w(TAG, "QQQ_ onRestart called ****"); questOnAppAfterLoad(); + questNativeAwayMode(); } @Override @@ -123,8 +128,7 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.w(TAG, "QQQ_ surfaceDestroyed ***************************************************"); - // nativeOnSurfaceChanged(null); - // mSurfaceHolder = null; - + nativeOnSurfaceChanged(null); + mSurfaceHolder = null; } } \ No newline at end of file diff --git a/interface/src/AndroidHelper.cpp b/interface/src/AndroidHelper.cpp index 4f75d5bdb2..e5007d706e 100644 --- a/interface/src/AndroidHelper.cpp +++ b/interface/src/AndroidHelper.cpp @@ -45,6 +45,10 @@ void AndroidHelper::notifyBeforeEnterBackground() { emit beforeEnterBackground(); } +void AndroidHelper::notifyToggleAwayMode() { + emit toggleAwayMode(); +} + void AndroidHelper::notifyEnterBackground() { emit enterBackground(); } diff --git a/interface/src/AndroidHelper.h b/interface/src/AndroidHelper.h index f1cec6a43b..fca035a217 100644 --- a/interface/src/AndroidHelper.h +++ b/interface/src/AndroidHelper.h @@ -31,6 +31,7 @@ public: void notifyEnterForeground(); void notifyBeforeEnterBackground(); void notifyEnterBackground(); + void notifyToggleAwayMode(); void performHapticFeedback(int duration); void processURL(const QString &url); @@ -55,7 +56,7 @@ signals: void enterForeground(); void beforeEnterBackground(); void enterBackground(); - + void toggleAwayMode(); void hapticFeedbackRequested(int duration); void handleSignupCompleted(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a611738445..a8d0cf6125 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2411,6 +2411,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&AndroidHelper::instance(), &AndroidHelper::beforeEnterBackground, this, &Application::beforeEnterBackground); connect(&AndroidHelper::instance(), &AndroidHelper::enterBackground, this, &Application::enterBackground); connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground); + connect(&AndroidHelper::instance(), &AndroidHelper::toggleAwayMode, this, &Application::toggleAwayMode); + AndroidHelper::instance().notifyLoadComplete(); #endif pauseUntilLoginDetermined(); @@ -9135,6 +9137,8 @@ void Application::beforeEnterBackground() { clearDomainOctreeDetails(); } + + void Application::enterBackground() { QMetaObject::invokeMethod(DependencyManager::get().data(), "stop", Qt::BlockingQueuedConnection); @@ -9160,4 +9164,10 @@ void Application::enterForeground() { } #endif +void Application::toggleAwayMode(){ + auto key = QKeyEvent(QEvent::KeyPress,Qt::Key_Escape,Qt::NoModifier); + _keyboardMouseDevice->keyPressEvent(&key); + qDebug()<<"QQQ_ AWAY MODE "; +} + #include "Application.moc" diff --git a/interface/src/Application.h b/interface/src/Application.h index afd9f5f12f..d856297e41 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -338,7 +338,8 @@ public: void beforeEnterBackground(); void enterBackground(); void enterForeground(); -#endif + void toggleAwayMode(); + #endif signals: void svoImportRequested(const QString& url); diff --git a/scripts/+android_questInterface/defaultScripts.js b/scripts/+android_questInterface/defaultScripts.js index d22716302c..e996f71908 100644 --- a/scripts/+android_questInterface/defaultScripts.js +++ b/scripts/+android_questInterface/defaultScripts.js @@ -14,8 +14,8 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/request-service.js", "system/progress.js", - //"system/away.js", - "system/hmd.js", + "system/away.js", + //"system/hmd.js", "system/menu.js", "system/bubble.js", "system/pal.js", // "system/mod.js", // older UX, if you prefer diff --git a/scripts/system/away.js b/scripts/system/away.js index 45b6f43b73..c75d58a240 100644 --- a/scripts/system/away.js +++ b/scripts/system/away.js @@ -154,7 +154,7 @@ function goAway(fromStartup) { if (!isEnabled || isAway) { return; } - + console.warn('QQQ_ JS going away); // If we're entering away mode from some other state than startup, then we create our move timer immediately. // However if we're just stating up, we need to delay this process so that we don't think the initial teleport // is actually a move. @@ -176,6 +176,7 @@ function goActive() { return; } + console.warn('QQQ_ JS going active); UserActivityLogger.toggledAway(false); MyAvatar.isAway = false; From 982c4c2bc40d607bbd152f09454eda5428b63441 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 21 Feb 2019 16:33:31 -0800 Subject: [PATCH 044/566] do not Space::clear() in clearNonLocalEntities() --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 9d55d936a2..914c0f97a0 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -219,7 +219,6 @@ void EntityTreeRenderer::clearNonLocalEntities() { std::unordered_map savedEntities; // remove all entities from the scene - _space->clear(); auto scene = _viewState->getMain3DScene(); if (scene) { render::Transaction transaction; @@ -1392,4 +1391,4 @@ bool EntityTreeRenderer::removeMaterialFromAvatar(const QUuid& avatarID, graphic return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialName); } return false; -} \ No newline at end of file +} From 94fc60f28517a2409be134ebfe359fedb09f507f Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 21 Feb 2019 16:34:50 -0800 Subject: [PATCH 045/566] Bad idea to include global here --- interface/src/LODManager.h | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 5817eafc25..87e871a3ab 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -19,7 +19,6 @@ #include #include -#include #ifdef Q_OS_ANDROID const float LOD_DEFAULT_QUALITY_LEVEL = 0.2; // default quality level setting is High (lower framerate) From ddc42585d81e53386c2213b4a8af3aaacc3430a6 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 21 Feb 2019 16:41:50 -0800 Subject: [PATCH 046/566] Cleanup syntax --- interface/src/LODManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 87e871a3ab..77cb1a0d39 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -21,7 +21,7 @@ #ifdef Q_OS_ANDROID -const float LOD_DEFAULT_QUALITY_LEVEL = 0.2; // default quality level setting is High (lower framerate) +const float LOD_DEFAULT_QUALITY_LEVEL = 0.2f; // default quality level setting is High (lower framerate) #else const float LOD_DEFAULT_QUALITY_LEVEL = 0.5f; // default quality level setting is Mid #endif From ae6a73c71033cd0d4815a7e7f754a8793e835f46 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 21 Feb 2019 16:42:47 -0800 Subject: [PATCH 047/566] Automatically go to quest-dev domain on startup --- .../src/OculusMobileDisplayPlugin.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp b/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp index 78d80443d8..bc8e1a5113 100644 --- a/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp +++ b/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp @@ -168,10 +168,8 @@ bool OculusMobileDisplayPlugin::isHmdMounted() const { static void goToDevMobile() { auto addressManager = DependencyManager::get(); auto currentAddress = addressManager->currentAddress().toString().toStdString(); - if (std::string::npos == currentAddress.find("dev-mobile")) { - addressManager->handleLookupString("hifi://dev-mobile/495.236,501.017,482.434/0,0.97452,0,-0.224301"); - //addressManager->handleLookupString("hifi://dev-mobile/504,498,491/0,0,0,0"); - //addressManager->handleLookupString("hifi://dev-mobile/0,-1,1"); + if (std::string::npos == currentAddress.find("quest-dev")) { + addressManager->handleLookupString("hifi://quest-dev"); } } @@ -217,12 +215,12 @@ bool OculusMobileDisplayPlugin::beginFrameRender(uint32_t frameIndex) { }); } - // static uint32_t count = 0; - // if ((++count % 1000) == 0) { - // AbstractViewStateInterface::instance()->postLambdaEvent([] { - // goToDevMobile(); - // }); - // } + static uint32_t count = 0; + if ((++count % 1000) == 0) { + AbstractViewStateInterface::instance()->postLambdaEvent([] { + goToDevMobile(); + }); + } return result && Parent::beginFrameRender(frameIndex); } From be2d4272da65adc644064abb68a55b7cb395bafd Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 21 Feb 2019 18:11:16 -0800 Subject: [PATCH 048/566] remove the other unnecessary _space->clear() --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 914c0f97a0..efd1399f30 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -258,8 +258,6 @@ void EntityTreeRenderer::clear() { resetEntitiesScriptEngine(); } // remove all entities from the scene - - _space->clear(); auto scene = _viewState->getMain3DScene(); if (scene) { render::Transaction transaction; From c1786edc2445797631c2c87a9d448c4ff42f7e35 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 21 Feb 2019 17:47:28 -0800 Subject: [PATCH 049/566] Emulate the old behavior of _lastInputLoudness --- interface/src/scripting/Audio.cpp | 5 +++-- libraries/audio-client/src/AudioClient.cpp | 20 ++++++++++++++------ libraries/audio-client/src/AudioClient.h | 6 ++++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index fb64dbe098..2c4c29ff65 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -27,8 +27,9 @@ QString Audio::HMD { "VR" }; Setting::Handle enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true }; float Audio::loudnessToLevel(float loudness) { - float level = 6.02059991f * fastLog2f(loudness); // level in dBFS - level = (level + 48.0f) * (1/39.0f); // map [-48, -9] dBFS to [0, 1] + float level = loudness * (1/32768.0f); // level in [0, 1] + level = 6.02059991f * fastLog2f(level); // convert to dBFS + level = (level + 48.0f) * (1/42.0f); // map [-48, -6] dBFS to [0, 1] return glm::clamp(level, 0.0f, 1.0f); } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 60a95ff58a..8c50a195ee 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -175,7 +175,7 @@ static float computeLoudness(int16_t* samples, int numSamples, int numChannels, const int32_t CLIPPING_THRESHOLD = 32392; // -0.1 dBFS const int32_t CLIPPING_DETECTION = 3; // consecutive samples over threshold - float scale = numSamples ? 1.0f / (numSamples * 32768.0f) : 0.0f; + float scale = numSamples ? 1.0f / numSamples : 0.0f; int32_t loudness = 0; isClipping = false; @@ -249,6 +249,8 @@ AudioClient::AudioClient() : _outputBufferSizeFrames("audioOutputBufferFrames", DEFAULT_BUFFER_FRAMES), _sessionOutputBufferSizeFrames(_outputBufferSizeFrames.get()), _outputStarveDetectionEnabled("audioOutputStarveDetectionEnabled", DEFAULT_STARVE_DETECTION_ENABLED), + _lastRawInputLoudness(0.0f), + _lastSmoothedRawInputLoudness(0.0f), _lastInputLoudness(0.0f), _timeSinceLastClip(-1.0f), _muted(false), @@ -1144,6 +1146,9 @@ void AudioClient::handleAudioInput(QByteArray& audioBuffer) { emit inputReceived(audioBuffer); } + // loudness after mute/gate + _lastInputLoudness = (_muted || !audioGateOpen) ? 0.0f : _lastRawInputLoudness; + // detect gate opening and closing bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed @@ -1222,12 +1227,15 @@ void AudioClient::handleMicAudioInput() { // detect loudness and clipping on the raw input bool isClipping = false; - float inputLoudness = computeLoudness(inputAudioSamples.get(), inputSamplesRequired, _inputFormat.channelCount(), isClipping); + float loudness = computeLoudness(inputAudioSamples.get(), inputSamplesRequired, _inputFormat.channelCount(), isClipping); + _lastRawInputLoudness = loudness; - float tc = (inputLoudness > _lastInputLoudness) ? 0.378f : 0.967f; // 10ms attack, 300ms release @ 100Hz - inputLoudness += tc * (_lastInputLoudness - inputLoudness); - _lastInputLoudness = inputLoudness; + // envelope detection + float tc = (loudness > _lastSmoothedRawInputLoudness) ? 0.378f : 0.967f; // 10ms attack, 300ms release @ 100Hz + loudness += tc * (_lastSmoothedRawInputLoudness - loudness); + _lastSmoothedRawInputLoudness = loudness; + // clipping indicator if (isClipping) { _timeSinceLastClip = 0.0f; } else if (_timeSinceLastClip >= 0.0f) { @@ -1235,7 +1243,7 @@ void AudioClient::handleMicAudioInput() { } isClipping = (_timeSinceLastClip >= 0.0f) && (_timeSinceLastClip < 2.0f); // 2 second hold time - emit inputLoudnessChanged(_lastInputLoudness, isClipping); + emit inputLoudnessChanged(_lastSmoothedRawInputLoudness, isClipping); if (!_muted) { possibleResampling(_inputToNetworkResampler, diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 94ed2ce132..29036b7c71 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -127,7 +127,7 @@ public: const QAudioFormat& getOutputFormat() const { return _outputFormat; } - float getLastInputLoudness() const { return _lastInputLoudness; } // TODO: relative to noise floor? + float getLastInputLoudness() const { return _lastInputLoudness; } float getTimeSinceLastClip() const { return _timeSinceLastClip; } float getAudioAverageInputLoudness() const { return _lastInputLoudness; } @@ -355,7 +355,9 @@ private: StDev _stdev; QElapsedTimer _timeSinceLastReceived; - float _lastInputLoudness; + float _lastRawInputLoudness; // before mute/gate + float _lastSmoothedRawInputLoudness; + float _lastInputLoudness; // after mute/gate float _timeSinceLastClip; int _totalInputAudioSamples; From 3072ca43de06bc413c61673ace32ad1ba20ba966 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 22 Feb 2019 09:24:38 -0700 Subject: [PATCH 050/566] Detailed picking if avatar is not null --- interface/src/avatar/AvatarManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 22f8e7112a..55025b3b23 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -719,7 +719,7 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic } } - if (rayAvatarResult._intersect && pickAgainstMesh) { + if (avatar && rayAvatarResult._intersect && pickAgainstMesh) { glm::vec3 localRayOrigin = avatar->worldToJointPoint(ray.origin, rayAvatarResult._intersectWithJoint); glm::vec3 localRayPoint = avatar->worldToJointPoint(ray.origin + rayAvatarResult._distance * rayDirection, rayAvatarResult._intersectWithJoint); From f04fdb2187a8d30fb50ffaf23d2254ee2d729307 Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Fri, 22 Feb 2019 09:11:24 -0800 Subject: [PATCH 051/566] added esc key event to fire for the away animation when cycling pause/resume. Reverted change on surface destroy that nullified the surface. Forgot to remove that during testin. Removed comment in away.js with syntax error. Setting cpu/gpu levels back to 1/1 after vr mode is released. Noticed that OS stays in same cpu/gpu level after app closes. Hoping this will help reduce battery drain for user --- interface/src/Application.cpp | 12 ++++++++---- libraries/oculusMobile/src/ovr/VrHandler.cpp | 4 ++++ scripts/system/away.js | 3 +-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a8d0cf6125..730f1007a4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1756,6 +1756,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo #endif }); + // Setup the _keyboardMouseDevice, _touchscreenDevice, _touchscreenVirtualPadDevice and the user input mapper with the default bindings userInputMapper->registerDevice(_keyboardMouseDevice->getInputDevice()); // if the _touchscreenDevice is not supported it will not be registered @@ -9162,12 +9163,15 @@ void Application::enterForeground() { auto nodeList = DependencyManager::get(); nodeList->setSendDomainServerCheckInEnabled(true); } -#endif + void Application::toggleAwayMode(){ - auto key = QKeyEvent(QEvent::KeyPress,Qt::Key_Escape,Qt::NoModifier); - _keyboardMouseDevice->keyPressEvent(&key); - qDebug()<<"QQQ_ AWAY MODE "; + QKeyEvent event = QKeyEvent (QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier); + QCoreApplication::sendEvent (this, &event); } + +#endif + + #include "Application.moc" diff --git a/libraries/oculusMobile/src/ovr/VrHandler.cpp b/libraries/oculusMobile/src/ovr/VrHandler.cpp index b3b1416785..3fe3901517 100644 --- a/libraries/oculusMobile/src/ovr/VrHandler.cpp +++ b/libraries/oculusMobile/src/ovr/VrHandler.cpp @@ -140,7 +140,11 @@ struct VrSurface : public TaskQueue { if (vrReady != vrRunning) { if (vrRunning) { __android_log_write(ANDROID_LOG_WARN, "QQQ_OVR", "vrapi_LeaveVrMode"); + vrapi_SetClockLevels(session, 1, 1); + vrapi_SetExtraLatencyMode(session, VRAPI_EXTRA_LATENCY_MODE_OFF); + vrapi_SetDisplayRefreshRate(session, 60); vrapi_LeaveVrMode(session); + session = nullptr; oculusActivity = nullptr; } else { diff --git a/scripts/system/away.js b/scripts/system/away.js index c75d58a240..2407678bb7 100644 --- a/scripts/system/away.js +++ b/scripts/system/away.js @@ -154,7 +154,7 @@ function goAway(fromStartup) { if (!isEnabled || isAway) { return; } - console.warn('QQQ_ JS going away); + // If we're entering away mode from some other state than startup, then we create our move timer immediately. // However if we're just stating up, we need to delay this process so that we don't think the initial teleport // is actually a move. @@ -176,7 +176,6 @@ function goActive() { return; } - console.warn('QQQ_ JS going active); UserActivityLogger.toggledAway(false); MyAvatar.isAway = false; From 9c833f7e64f575912216ee9593e13de6e23331a9 Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Fri, 22 Feb 2019 09:21:51 -0800 Subject: [PATCH 052/566] clean up --- .../java/io/highfidelity/oculus/OculusMobileActivity.java | 5 +---- interface/src/Application.cpp | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java b/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java index 71ccfa84cd..7672ddf271 100644 --- a/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java +++ b/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java @@ -51,15 +51,13 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca nativeOnCreate(); questNativeOnCreate(); } + public void onAppLoadedComplete() { Log.w(TAG, "QQQ Load Completed"); runOnUiThread(() -> { setContentView(mView); questOnAppAfterLoad(); - }); - - } @Override @@ -93,7 +91,6 @@ public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Ca questNativeOnPause(); nativeOnPause(); isPausing=true; - } @Override diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 730f1007a4..e8fed1b2da 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -9166,7 +9166,7 @@ void Application::enterForeground() { void Application::toggleAwayMode(){ - QKeyEvent event = QKeyEvent (QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier); + QKeyEvent event = QKeyEvent (QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier); QCoreApplication::sendEvent (this, &event); } From aa8563f3feb96f2a9f7bc48bf7ff9acc0acff786 Mon Sep 17 00:00:00 2001 From: danteruiz Date: Fri, 22 Feb 2019 10:10:34 -0800 Subject: [PATCH 053/566] fix quest ui elements --- .../src/RenderablePolyLineEntityItem.cpp | 15 +++++++- .../src/RenderableShapeEntityItem.cpp | 9 ++++- .../entities-renderer/paintStroke_forward.slp | 1 + .../src/paintStroke_forward.slf | 35 +++++++++++++++++++ .../render-utils/src/RenderForwardTask.cpp | 2 +- 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 libraries/entities-renderer/src/entities-renderer/paintStroke_forward.slp create mode 100644 libraries/entities-renderer/src/paintStroke_forward.slf diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 64c05b576b..c4ea6a2fea 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -29,6 +29,13 @@ gpu::PipelinePointer PolyLineEntityRenderer::_glowPipeline = nullptr; static const QUrl DEFAULT_POLYLINE_TEXTURE = PathUtils::resourcesUrl("images/paintStroke.png"); +#if defined(USE_GLES) +static bool DISABLE_DEFERRED = true; +#else +static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" }; +static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD); +#endif + PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { _texture = DependencyManager::get()->getTexture(DEFAULT_POLYLINE_TEXTURE); @@ -44,7 +51,13 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity) void PolyLineEntityRenderer::buildPipeline() { // FIXME: opaque pipeline - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke); + gpu::ShaderPointer program; + if (DISABLE_DEFERRED) { + program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke_forward); + } else { + program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke); + } + { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setCullMode(gpu::State::CullMode::CULL_NONE); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index d42a766faa..c3dae762c5 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -30,6 +30,13 @@ using namespace render::entities; // is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down. static const float SPHERE_ENTITY_SCALE = 0.5f; +#if defined(USE_GLES) +static bool DISABLE_DEFERRED = true; +#else +static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" }; +static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD); +#endif + static_assert(shader::render_utils::program::simple != 0, "Validate simple program exists"); static_assert(shader::render_utils::program::simple_transparent != 0, "Validate simple transparent program exists"); @@ -276,7 +283,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { // FIXME, support instanced multi-shape rendering using multidraw indirect outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; render::ShapePipelinePointer pipeline; - if (_renderLayer == RenderLayer::WORLD) { + if (_renderLayer == RenderLayer::WORLD && !DISABLE_DEFERRED) { pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); } else { pipeline = outColor.a < 1.0f ? geometryCache->getForwardTransparentShapePipeline() : geometryCache->getForwardOpaqueShapePipeline(); diff --git a/libraries/entities-renderer/src/entities-renderer/paintStroke_forward.slp b/libraries/entities-renderer/src/entities-renderer/paintStroke_forward.slp new file mode 100644 index 0000000000..4d49e0d3a4 --- /dev/null +++ b/libraries/entities-renderer/src/entities-renderer/paintStroke_forward.slp @@ -0,0 +1 @@ +VERTEX paintStroke \ No newline at end of file diff --git a/libraries/entities-renderer/src/paintStroke_forward.slf b/libraries/entities-renderer/src/paintStroke_forward.slf new file mode 100644 index 0000000000..b949332826 --- /dev/null +++ b/libraries/entities-renderer/src/paintStroke_forward.slf @@ -0,0 +1,35 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// paintStroke.frag +// fragment shader +// +// Created by Eric Levin on 8/10/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include paintStroke.slh@> +<$declarePolyLineBuffers()$> + +LAYOUT(binding=0) uniform sampler2D _texture; + +layout(location=0) in vec3 _normalWS; +layout(location=1) in vec2 _texCoord; +layout(location=2) in vec4 _color; +layout(location=3) in float _distanceFromCenter; +layout(location=0) out vec4 _fragColor0; + +void main(void) { + vec4 texel = texture(_texture, _texCoord); + int frontCondition = 1 - 2 * int(gl_FrontFacing); + vec3 color = _color.rgb * texel.rgb; + float alpha = texel.a * _color.a; + + alpha *= mix(1.0, pow(1.0 - abs(_distanceFromCenter), 10.0), _polylineData.faceCameraGlow.y); + + _fragColor0 = vec4(color, alpha); +} diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index df82d4b56d..c6f49bc92a 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -101,7 +101,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, nullJitter).asVarying(); const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, nullJitter).asVarying(); task.addJob("DrawInFrontOpaque", inFrontOpaquesInputs, true); - task.addJob("DrawInFrontTransparent", inFrontTransparentsInputs, false); // Draw opaques forward const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel).asVarying(); @@ -114,6 +113,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // Draw transparent objects forward const auto transparentInputs = DrawForward::Inputs(transparents, lightingModel).asVarying(); task.addJob("DrawTransparents", transparentInputs, shapePlumber); + task.addJob("DrawInFrontTransparent", inFrontTransparentsInputs, false); { // Debug the bounds of the rendered items, still look at the zbuffer From 109eb6288682c4116deee1fdfd3741814144f3f9 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 22 Feb 2019 11:07:40 -0800 Subject: [PATCH 054/566] requested changes --- libraries/render-utils/src/RenderForwardTask.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index c6f49bc92a..73692b41c2 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -96,12 +96,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", framebuffer); - // Layered - const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); - const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, nullJitter).asVarying(); - const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, nullJitter).asVarying(); - task.addJob("DrawInFrontOpaque", inFrontOpaquesInputs, true); - // Draw opaques forward const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel).asVarying(); task.addJob("DrawOpaques", opaqueInputs, shapePlumber); @@ -113,6 +107,12 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // Draw transparent objects forward const auto transparentInputs = DrawForward::Inputs(transparents, lightingModel).asVarying(); task.addJob("DrawTransparents", transparentInputs, shapePlumber); + + // Layered + const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); + const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, nullJitter).asVarying(); + const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, nullJitter).asVarying(); + task.addJob("DrawInFrontOpaque", inFrontOpaquesInputs, true); task.addJob("DrawInFrontTransparent", inFrontTransparentsInputs, false); { // Debug the bounds of the rendered items, still look at the zbuffer From 87d98e5b858828bba6a21d73cb496e7aef0b967b Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 8 Jan 2019 15:26:46 -0800 Subject: [PATCH 055/566] These are the squashed commits for the ik optimization for the Quest Implmented using a new AnimSplineIK node in the anim graph (cherry picked from commit 4fe03ba238659fee7763991f2499a315482b351f) --- CMakeLists.txt | 8 +- .../avatar-animation_withSplineIKNode.json | 2229 +++++++++++++++++ interface/src/avatar/MyAvatar.cpp | 4 + interface/src/avatar/MySkeletonModel.cpp | 30 + libraries/animation/src/AnimContext.h | 1 + .../animation/src/AnimInverseKinematics.cpp | 5 + libraries/animation/src/AnimNodeLoader.cpp | 51 + .../src/AnimPoleVectorConstraint.cpp | 2 +- libraries/animation/src/AnimSplineIK.cpp | 473 ++++ libraries/animation/src/AnimSplineIK.h | 104 + libraries/animation/src/AnimStateMachine.cpp | 1 - libraries/animation/src/IKTarget.h | 3 +- libraries/animation/src/Rig.cpp | 76 +- .../src/avatars-renderer/Avatar.cpp | 36 + .../src/avatars-renderer/Avatar.h | 9 + libraries/fbx/src/FBXSerializer.cpp | 14 + libraries/shared/src/AvatarConstants.h | 1 + libraries/shared/src/CubicHermiteSpline.h | 41 +- tools/unity-avatar-exporter/Assets/README.txt | 1 + 19 files changed, 3061 insertions(+), 28 deletions(-) create mode 100644 interface/resources/avatar/avatar-animation_withSplineIKNode.json create mode 100644 libraries/animation/src/AnimSplineIK.cpp create mode 100644 libraries/animation/src/AnimSplineIK.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c126dce56a..1ba5e1264f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ else() set(MOBILE 0) endif() +set(HIFI_USE_OPTIMIZED_IK OFF) set(BUILD_CLIENT_OPTION ON) set(BUILD_SERVER_OPTION ON) set(BUILD_TESTS_OPTION OFF) @@ -115,7 +116,7 @@ if (USE_GLES AND (NOT ANDROID)) set(DISABLE_QML_OPTION ON) endif() - +option(HIFI_USE_OPTIMIZED_IK "USE OPTIMIZED IK" ${HIFI_USE_OPTIMIZED_IK_OPTION}) option(BUILD_CLIENT "Build client components" ${BUILD_CLIENT_OPTION}) option(BUILD_SERVER "Build server components" ${BUILD_SERVER_OPTION}) option(BUILD_TESTS "Build tests" ${BUILD_TESTS_OPTION}) @@ -146,6 +147,7 @@ foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS}) list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}") endforeach() +MESSAGE(STATUS "USE OPTIMIZED IK: " ${HIFI_USE_OPTIMIZED_IK}) MESSAGE(STATUS "Build server: " ${BUILD_SERVER}) MESSAGE(STATUS "Build client: " ${BUILD_CLIENT}) MESSAGE(STATUS "Build tests: " ${BUILD_TESTS}) @@ -191,6 +193,10 @@ find_package( Threads ) add_definitions(-DGLM_FORCE_RADIANS) add_definitions(-DGLM_ENABLE_EXPERIMENTAL) add_definitions(-DGLM_FORCE_CTOR_INIT) +if (HIFI_USE_OPTIMIZED_IK) + MESSAGE(STATUS "SET THE USE IK DEFINITION ") + add_definitions(-DHIFI_USE_OPTIMIZED_IK) +endif() set(HIFI_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries") set(EXTERNAL_PROJECT_PREFIX "project") diff --git a/interface/resources/avatar/avatar-animation_withSplineIKNode.json b/interface/resources/avatar/avatar-animation_withSplineIKNode.json new file mode 100644 index 0000000000..b1f198c52c --- /dev/null +++ b/interface/resources/avatar/avatar-animation_withSplineIKNode.json @@ -0,0 +1,2229 @@ +{ + "version": "1.1", + "root": { + "id": "userAnimStateMachine", + "type": "stateMachine", + "data": { + "currentState": "userAnimNone", + "states": [ + { + "id": "userAnimNone", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { + "var": "userAnimA", + "state": "userAnimA" + }, + { + "var": "userAnimB", + "state": "userAnimB" + } + ] + }, + { + "id": "userAnimA", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { + "var": "userAnimNone", + "state": "userAnimNone" + }, + { + "var": "userAnimB", + "state": "userAnimB" + } + ] + }, + { + "id": "userAnimB", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { + "var": "userAnimNone", + "state": "userAnimNone" + }, + { + "var": "userAnimA", + "state": "userAnimA" + } + ] + } + ] + }, + "children": [ + { + "id": "userAnimNone", + "type": "poleVectorConstraint", + "data": { + "enabled": false, + "referenceVector": [ 0, 0, 1 ], + "baseJointName": "RightUpLeg", + "midJointName": "RightLeg", + "tipJointName": "RightFoot", + "enabledVar": "rightFootPoleVectorEnabled", + "poleVectorVar": "rightFootPoleVector" + }, + "children": [ + { + "id": "rightFootIK", + "type": "twoBoneIK", + "data": { + "alpha": 1.0, + "enabled": false, + "interpDuration": 15, + "baseJointName": "RightUpLeg", + "midJointName": "RightLeg", + "tipJointName": "RightFoot", + "midHingeAxis": [ -1, 0, 0 ], + "alphaVar": "rightFootIKAlpha", + "enabledVar": "rightFootIKEnabled", + "endEffectorRotationVarVar": "rightFootIKRotationVar", + "endEffectorPositionVarVar": "rightFootIKPositionVar" + }, + "children": [ + { + "id": "leftFootPoleVector", + "type": "poleVectorConstraint", + "data": { + "enabled": false, + "referenceVector": [ 0, 0, 1 ], + "baseJointName": "LeftUpLeg", + "midJointName": "LeftLeg", + "tipJointName": "LeftFoot", + "enabledVar": "leftFootPoleVectorEnabled", + "poleVectorVar": "leftFootPoleVector" + }, + "children": [ + { + "id": "leftFootIK", + "type": "twoBoneIK", + "data": { + "alpha": 1.0, + "enabled": false, + "interpDuration": 15, + "baseJointName": "LeftUpLeg", + "midJointName": "LeftLeg", + "tipJointName": "LeftFoot", + "midHingeAxis": [ -1, 0, 0 ], + "alphaVar": "leftFootIKAlpha", + "enabledVar": "leftFootIKEnabled", + "endEffectorRotationVarVar": "leftFootIKRotationVar", + "endEffectorPositionVarVar": "leftFootIKPositionVar" + }, + "children": [ + { + "id": "rightHandPoleVector", + "type": "poleVectorConstraint", + "data": { + "enabled": false, + "referenceVector": [ -1, 0, 0 ], + "baseJointName": "RightArm", + "midJointName": "RightForeArm", + "tipJointName": "RightHand", + "enabledVar": "rightHandPoleVectorEnabled", + "poleVectorVar": "rightHandPoleVector" + }, + "children": [ + { + "id": "rightHandIK", + "type": "twoBoneIK", + "data": { + "alpha": 1.0, + "enabled": false, + "interpDuration": 15, + "baseJointName": "RightArm", + "midJointName": "RightForeArm", + "tipJointName": "RightHand", + "midHingeAxis": [ 0, 0, -1 ], + "alphaVar": "rightHandIKAlpha", + "enabledVar": "rightHandIKEnabled", + "endEffectorRotationVarVar": "rightHandIKRotationVar", + "endEffectorPositionVarVar": "rightHandIKPositionVar" + }, + "children": [ + { + "id": "leftHandPoleVector", + "type": "poleVectorConstraint", + "data": { + "enabled": false, + "referenceVector": [ 1, 0, 0 ], + "baseJointName": "LeftArm", + "midJointName": "LeftForeArm", + "tipJointName": "LeftHand", + "enabledVar": "leftHandPoleVectorEnabled", + "poleVectorVar": "leftHandPoleVector" + }, + "children": [ + { + "id": "leftHandIK", + "type": "twoBoneIK", + "data": { + "alpha": 1.0, + "enabled": false, + "interpDuration": 15, + "baseJointName": "LeftArm", + "midJointName": "LeftForeArm", + "tipJointName": "LeftHand", + "midHingeAxis": [ 0, 0, 1 ], + "alphaVar": "leftHandIKAlpha", + "enabledVar": "leftHandIKEnabled", + "endEffectorRotationVarVar": "leftHandIKRotationVar", + "endEffectorPositionVarVar": "leftHandIKPositionVar" + }, + "children": [ + { + "id": "userSplineIK", + "type": "splineIK", + "data": { + "alpha": 1.0, + "enabled": false, + "interpDuration": 15, + "baseJointName": "Hips", + "midJointName": "Spine2", + "tipJointName": "Head", + "basePositionVar": "hipsPosition", + "baseRotationVar": "hipsRotation", + "midPositionVar": "spine2Position", + "midRotationVar": "spine2Rotation", + "tipPositionVar": "headPosition", + "tipRotationVar": "headRotation", + "alphaVar": "splineIKAlpha", + "enabledVar": "splineIKEnabled", + "tipTargetFlexCoefficients": [ 1.0, 1.0, 1.0, 1.0, 1.0 ], + "midTargetFlexCoefficients": [ 1.0, 1.0, 1.0 ] + }, + "children": [ + { + "id": "defaultPoseOverlay", + "type": "overlay", + "data": { + "alpha": 0.0, + "alphaVar": "defaultPoseOverlayAlpha", + "boneSet": "fullBody", + "boneSetVar": "defaultPoseOverlayBoneSet" + }, + "children": [ + { + "id": "defaultPose", + "type": "defaultPose", + "data": { + }, + "children": [] + }, + { + "id": "rightHandOverlay", + "type": "overlay", + "data": { + "alpha": 0.0, + "boneSet": "rightHand", + "alphaVar": "rightHandOverlayAlpha" + }, + "children": [ + { + "id": "rightHandStateMachine", + "type": "stateMachine", + "data": { + "currentState": "rightHandGrasp", + "states": [ + { + "id": "rightHandGrasp", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { + "var": "isRightIndexPoint", + "state": "rightIndexPoint" + }, + { + "var": "isRightThumbRaise", + "state": "rightThumbRaise" + }, + { + "var": "isRightIndexPointAndThumbRaise", + "state": "rightIndexPointAndThumbRaise" + } + ] + }, + { + "id": "rightIndexPoint", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { + "var": "isRightHandGrasp", + "state": "rightHandGrasp" + }, + { + "var": "isRightThumbRaise", + "state": "rightThumbRaise" + }, + { + "var": "isRightIndexPointAndThumbRaise", + "state": "rightIndexPointAndThumbRaise" + } + ] + }, + { + "id": "rightThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { + "var": "isRightHandGrasp", + "state": "rightHandGrasp" + }, + { + "var": "isRightIndexPoint", + "state": "rightIndexPoint" + }, + { + "var": "isRightIndexPointAndThumbRaise", + "state": "rightIndexPointAndThumbRaise" + } + ] + }, + { + "id": "rightIndexPointAndThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { + "var": "isRightHandGrasp", + "state": "rightHandGrasp" + }, + { + "var": "isRightIndexPoint", + "state": "rightIndexPoint" + }, + { + "var": "isRightThumbRaise", + "state": "rightThumbRaise" + } + ] + } + ] + }, + "children": [ + { + "id": "rightHandGrasp", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightHandGraspOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/hydra_pose_open_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightHandGraspClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/hydra_pose_closed_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "rightIndexPoint", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightIndexPointOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_point_open_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightIndexPointClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_point_closed_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "rightThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightThumbRaiseOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_open_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightThumbRaiseClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_closed_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "rightIndexPointAndThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightIndexPointAndThumbRaiseOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_point_open_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightIndexPointAndThumbRaiseClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_point_closed_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + } + ] + }, + { + "id": "leftHandOverlay", + "type": "overlay", + "data": { + "alpha": 0.0, + "boneSet": "leftHand", + "alphaVar": "leftHandOverlayAlpha" + }, + "children": [ + { + "id": "leftHandStateMachine", + "type": "stateMachine", + "data": { + "currentState": "leftHandGrasp", + "states": [ + { + "id": "leftHandGrasp", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { + "var": "isLeftIndexPoint", + "state": "leftIndexPoint" + }, + { + "var": "isLeftThumbRaise", + "state": "leftThumbRaise" + }, + { + "var": "isLeftIndexPointAndThumbRaise", + "state": "leftIndexPointAndThumbRaise" + } + ] + }, + { + "id": "leftIndexPoint", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { + "var": "isLeftHandGrasp", + "state": "leftHandGrasp" + }, + { + "var": "isLeftThumbRaise", + "state": "leftThumbRaise" + }, + { + "var": "isLeftIndexPointAndThumbRaise", + "state": "leftIndexPointAndThumbRaise" + } + ] + }, + { + "id": "leftThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { + "var": "isLeftHandGrasp", + "state": "leftHandGrasp" + }, + { + "var": "isLeftIndexPoint", + "state": "leftIndexPoint" + }, + { + "var": "isLeftIndexPointAndThumbRaise", + "state": "leftIndexPointAndThumbRaise" + } + ] + }, + { + "id": "leftIndexPointAndThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { + "var": "isLeftHandGrasp", + "state": "leftHandGrasp" + }, + { + "var": "isLeftIndexPoint", + "state": "leftIndexPoint" + }, + { + "var": "isLeftThumbRaise", + "state": "leftThumbRaise" + } + ] + } + ] + }, + "children": [ + { + "id": "leftHandGrasp", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftHandGraspOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/hydra_pose_open_left.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftHandGraspClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/hydra_pose_closed_left.fbx", + "startFrame": 10.0, + "endFrame": 10.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "leftIndexPoint", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftIndexPointOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_point_open_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftIndexPointClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_point_closed_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "leftThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftThumbRaiseOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_open_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftThumbRaiseClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_closed_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "leftIndexPointAndThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftIndexPointAndThumbRaiseOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_point_open_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftIndexPointAndThumbRaiseClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_point_closed_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + } + ] + }, + { + "id": "mainStateMachine", + "type": "stateMachine", + "data": { + "outputJoints": [ "LeftFoot", "RightFoot" ], + "currentState": "idle", + "states": [ + { + "id": "idle", + "interpTarget": 20, + "interpDuration": 8, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + } + ] + }, + { + "id": "idleToWalkFwd", + "interpTarget": 12, + "interpDuration": 8, + "transitions": [ + { + "var": "idleToWalkFwdOnDone", + "state": "WALKFWD" + }, + { + "var": "isNotMoving", + "state": "idle" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + } + ] + }, + { + "id": "idleSettle", + "interpTarget": 15, + "interpDuration": 8, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "idleSettleOnDone", + "state": "idle" + }, + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + } + ] + }, + { + "id": "WALKFWD", + "interpTarget": 35, + "interpDuration": 10, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "isNotMoving", + "state": "idleSettle" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + } + ] + }, + { + "id": "WALKBWD", + "interpTarget": 35, + "interpDuration": 10, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "isNotMoving", + "state": "idleSettle" + }, + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + } + ] + }, + { + "id": "STRAFERIGHT", + "interpTarget": 25, + "interpDuration": 8, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "isNotMoving", + "state": "idleSettle" + }, + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + } + ] + }, + { + "id": "STRAFELEFT", + "interpTarget": 25, + "interpDuration": 8, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "isNotMoving", + "state": "idleSettle" + }, + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + } + ] + }, + { + "id": "turnRight", + "interpTarget": 6, + "interpDuration": 8, + "transitions": [ + { + "var": "isNotTurning", + "state": "idle" + }, + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + } + ] + }, + { + "id": "turnLeft", + "interpTarget": 6, + "interpDuration": 8, + "transitions": [ + { + "var": "isNotTurning", + "state": "idle" + }, + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + } + ] + }, + { + "id": "strafeRightHmd", + "interpTarget": 5, + "interpDuration": 8, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "isNotMoving", + "state": "idleSettle" + }, + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + } + ] + }, + { + "id": "strafeLeftHmd", + "interpTarget": 5, + "interpDuration": 8, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "isNotMoving", + "state": "idleSettle" + }, + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + } + ] + }, + { + "id": "fly", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { + "var": "isNotFlying", + "state": "idleSettle" + } + ] + }, + { + "id": "takeoffStand", + "interpTarget": 2, + "interpDuration": 2, + "transitions": [ + { + "var": "isNotTakeoff", + "state": "inAirStand" + } + ] + }, + { + "id": "TAKEOFFRUN", + "interpTarget": 2, + "interpDuration": 2, + "transitions": [ + { + "var": "isNotTakeoff", + "state": "INAIRRUN" + } + ] + }, + { + "id": "inAirStand", + "interpTarget": 3, + "interpDuration": 3, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "isNotInAir", + "state": "landStandImpact" + } + ] + }, + { + "id": "INAIRRUN", + "interpTarget": 3, + "interpDuration": 3, + "interpType": "snapshotPrev", + "transitions": [ + { + "var": "isNotInAir", + "state": "WALKFWD" + } + ] + }, + { + "id": "landStandImpact", + "interpTarget": 1, + "interpDuration": 1, + "transitions": [ + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "landStandImpactOnDone", + "state": "landStand" + } + ] + }, + { + "id": "landStand", + "interpTarget": 1, + "interpDuration": 1, + "transitions": [ + { + "var": "isMovingForward", + "state": "WALKFWD" + }, + { + "var": "isMovingBackward", + "state": "WALKBWD" + }, + { + "var": "isMovingRight", + "state": "STRAFERIGHT" + }, + { + "var": "isMovingLeft", + "state": "STRAFELEFT" + }, + { + "var": "isTurningRight", + "state": "turnRight" + }, + { + "var": "isTurningLeft", + "state": "turnLeft" + }, + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "isInAirStand", + "state": "inAirStand" + }, + { + "var": "isInAirRun", + "state": "INAIRRUN" + }, + { + "var": "landStandOnDone", + "state": "idle" + }, + { + "var": "isMovingRightHmd", + "state": "strafeRightHmd" + }, + { + "var": "isMovingLeftHmd", + "state": "strafeLeftHmd" + } + ] + }, + { + "id": "LANDRUN", + "interpTarget": 2, + "interpDuration": 2, + "transitions": [ + { + "var": "isFlying", + "state": "fly" + }, + { + "var": "isTakeoffStand", + "state": "takeoffStand" + }, + { + "var": "isTakeoffRun", + "state": "TAKEOFFRUN" + }, + { + "var": "landRunOnDone", + "state": "WALKFWD" + } + ] + } + ] + }, + "children": [ + { + "id": "idle", + "type": "stateMachine", + "data": { + "currentState": "idleStand", + "states": [ + { + "id": "idleStand", + "interpTarget": 6, + "interpDuration": 10, + "transitions": [ + { + "var": "isTalking", + "state": "idleTalk" + } + ] + }, + { + "id": "idleTalk", + "interpTarget": 6, + "interpDuration": 10, + "transitions": [ + { + "var": "notIsTalking", + "state": "idleStand" + } + ] + } + ] + }, + "children": [ + { + "id": "idleStand", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/idle.fbx", + "startFrame": 0.0, + "endFrame": 300.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "idleTalk", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/talk.fbx", + "startFrame": 0.0, + "endFrame": 800.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "WALKFWD", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [ 0.5, 1.8, 2.3, 3.2, 4.5 ], + "alphaVar": "moveForwardAlpha", + "desiredSpeedVar": "moveForwardSpeed" + }, + "children": [ + { + "id": "walkFwdShort_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_short_fwd.fbx", + "startFrame": 0.0, + "endFrame": 39.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkFwdNormal_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_fwd.fbx", + "startFrame": 0.0, + "endFrame": 30.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkFwdFast_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_fwd_fast.fbx", + "startFrame": 0.0, + "endFrame": 25.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkFwdJog_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jog_fwd.fbx", + "startFrame": 0.0, + "endFrame": 25.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkFwdRun_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/run_fwd.fbx", + "startFrame": 0.0, + "endFrame": 21.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "idleToWalkFwd", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/idle_to_walk.fbx", + "startFrame": 1.0, + "endFrame": 13.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "idleSettle", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/settle_to_idle.fbx", + "startFrame": 1.0, + "endFrame": 59.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "WALKBWD", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [ 0.6, 1.6, 2.3, 3.1 ], + "alphaVar": "moveBackwardAlpha", + "desiredSpeedVar": "moveBackwardSpeed" + }, + "children": [ + { + "id": "walkBwdShort_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_short_bwd.fbx", + "startFrame": 0.0, + "endFrame": 38.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkBwdFast_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_bwd_fast.fbx", + "startFrame": 0.0, + "endFrame": 27.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "jogBwd_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jog_bwd.fbx", + "startFrame": 0.0, + "endFrame": 24.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "runBwd_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/run_bwd.fbx", + "startFrame": 0.0, + "endFrame": 16.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "turnLeft", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/turn_left.fbx", + "startFrame": 0.0, + "endFrame": 32.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "turnRight", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/turn_left.fbx", + "startFrame": 0.0, + "endFrame": 32.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + }, + { + "id": "STRAFELEFT", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [ 0.1, 0.5, 1.0, 2.6, 3.0 ], + "alphaVar": "moveLateralAlpha", + "desiredSpeedVar": "moveLateralSpeed" + }, + "children": [ + { + "id": "strafeLeftShortStep_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_short_left.fbx", + "startFrame": 0.0, + "endFrame": 29.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeLeftStep_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_left.fbx", + "startFrame": 0.0, + "endFrame": 20.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeLeftWalk_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_left.fbx", + "startFrame": 0.0, + "endFrame": 35.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeLeftWalkFast_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_left_fast.fbx", + "startFrame": 0.0, + "endFrame": 21.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeLeftJog_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jog_left.fbx", + "startFrame": 0.0, + "endFrame": 24.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "STRAFERIGHT", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [ 0.1, 0.5, 1.0, 2.6, 3.0 ], + "alphaVar": "moveLateralAlpha", + "desiredSpeedVar": "moveLateralSpeed" + }, + "children": [ + { + "id": "strafeRightShortStep_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_short_left.fbx", + "startFrame": 0.0, + "endFrame": 29.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + }, + { + "id": "strafeRightStep_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_left.fbx", + "startFrame": 0.0, + "endFrame": 20.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + }, + { + "id": "strafeRightWalk_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_left.fbx", + "startFrame": 0.0, + "endFrame": 35.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + }, + { + "id": "strafeRightFast_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_left_fast.fbx", + "startFrame": 0.0, + "endFrame": 21.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + }, + { + "id": "strafeRightJog_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jog_left.fbx", + "startFrame": 0.0, + "endFrame": 24.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + } + ] + }, + { + "id": "strafeLeftHmd", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [ 0, 0.5, 2.5 ], + "alphaVar": "moveLateralAlpha", + "desiredSpeedVar": "moveLateralSpeed" + }, + "children": [ + { + "id": "stepLeftShort_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_short_left.fbx", + "startFrame": 0.0, + "endFrame": 29.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "stepLeft_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_left.fbx", + "startFrame": 0.0, + "endFrame": 20.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeLeftAnim_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_left_fast.fbx", + "startFrame": 0.0, + "endFrame": 16.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "strafeRightHmd", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [ 0, 0.5, 2.5 ], + "alphaVar": "moveLateralAlpha", + "desiredSpeedVar": "moveLateralSpeed" + }, + "children": [ + { + "id": "stepRightShort_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_short_left.fbx", + "startFrame": 0.0, + "endFrame": 29.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + }, + { + "id": "stepRight_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_left.fbx", + "startFrame": 0.0, + "endFrame": 20.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + }, + { + "id": "strafeRightAnim_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_left_fast.fbx", + "startFrame": 0.0, + "endFrame": 16.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + } + ] + }, + { + "id": "fly", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/fly.fbx", + "startFrame": 1.0, + "endFrame": 80.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "takeoffStand", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_launch.fbx", + "startFrame": 2.0, + "endFrame": 16.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "TAKEOFFRUN", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 4.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirStand", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "inAirAlpha" + }, + "children": [ + { + "id": "inAirStandPreApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_apex.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirStandApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_apex.fbx", + "startFrame": 1.0, + "endFrame": 1.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirStandPostApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_apex.fbx", + "startFrame": 2.0, + "endFrame": 2.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + } + ] + }, + { + "id": "INAIRRUN", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "inAirAlpha" + }, + "children": [ + { + "id": "inAirRunPreApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 16.0, + "endFrame": 16.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirRunApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 22.0, + "endFrame": 22.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirRunPostApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 33.0, + "endFrame": 33.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + } + ] + }, + { + "id": "landStandImpact", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_land_settle.fbx", + "startFrame": 1.0, + "endFrame": 6.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "landStand", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_land_settle.fbx", + "startFrame": 6.0, + "endFrame": 68.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "LANDRUN", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 29.0, + "endFrame": 40.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "id": "userAnimA", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/idle.fbx", + "startFrame": 0.0, + "endFrame": 90.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "userAnimB", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/idle.fbx", + "startFrame": 0.0, + "endFrame": 90.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + } +} diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index afb7a218f6..ff865172ae 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2951,6 +2951,10 @@ void MyAvatar::initAnimGraph() { graphUrl = _fstAnimGraphOverrideUrl; } else { graphUrl = PathUtils::resourcesUrl("avatar/avatar-animation.json"); + +#if defined(Q_OS_ANDROID) || defined(HIFI_USE_OPTIMIZED_IK) + graphUrl = PathUtils::resourcesUrl("avatar/avatar-animation_withSplineIKNode.json"); +#endif } emit animGraphUrlChanged(graphUrl); diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 26d69841d0..55c29b66c1 100755 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -10,12 +10,14 @@ #include #include +#include #include "Application.h" #include "InterfaceLogging.h" #include "AnimUtil.h" + MySkeletonModel::MySkeletonModel(Avatar* owningAvatar, QObject* parent) : SkeletonModel(owningAvatar, parent) { } @@ -33,6 +35,22 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle }; } +#if defined(Q_OS_ANDROID) || defined(HIFI_USE_OPTIMIZED_IK) +static glm::vec3 computeSpine2WithHeadHipsSpline(MyAvatar* myAvatar, AnimPose hipsIKTargetPose, AnimPose headIKTargetPose) { + + // the the ik targets to compute the spline with + CubicHermiteSplineFunctorWithArcLength splineFinal(headIKTargetPose.rot(), headIKTargetPose.trans(), hipsIKTargetPose.rot(), hipsIKTargetPose.trans()); + + // measure the total arc length along the spline + float totalArcLength = splineFinal.arcLength(1.0f); + float tFinal = splineFinal.arcLengthInverse(myAvatar->getSpine2SplineRatio() * totalArcLength); + glm::vec3 spine2Translation = splineFinal(tFinal); + + return spine2Translation + myAvatar->getSpine2SplineOffset(); + +} +#endif + static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { glm::mat4 worldToSensorMat = glm::inverse(myAvatar->getSensorToWorldMatrix()); @@ -233,6 +251,12 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { +#if defined(Q_OS_ANDROID) || defined(HIFI_USE_OPTIMIZED_IK) + AnimPose headAvatarSpace(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation()); + AnimPose headRigSpace = avatarToRigPose * headAvatarSpace; + AnimPose hipsRigSpace = sensorToRigPose * sensorHips; + glm::vec3 spine2TargetTranslation = computeSpine2WithHeadHipsSpline(myAvatar, hipsRigSpace, headRigSpace); +#endif const float SPINE2_ROTATION_FILTER = 0.5f; AnimPose currentSpine2Pose; AnimPose currentHeadPose; @@ -243,6 +267,9 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { if (spine2Exists && headExists && hipsExists) { AnimPose rigSpaceYaw(myAvatar->getSpine2RotationRigSpace()); +#if defined(Q_OS_ANDROID) || defined(HIFI_USE_OPTIMIZED_IK) + rigSpaceYaw.rot() = safeLerp(Quaternions::IDENTITY, rigSpaceYaw.rot(), 0.5f); +#endif glm::vec3 u, v, w; glm::vec3 fwd = rigSpaceYaw.rot() * glm::vec3(0.0f, 0.0f, 1.0f); glm::vec3 up = currentHeadPose.trans() - currentHipsPose.trans(); @@ -253,6 +280,9 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { } generateBasisVectors(up, fwd, u, v, w); AnimPose newSpinePose(glm::mat4(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f))); +#if defined(Q_OS_ANDROID) || defined(HIFI_USE_OPTIMIZED_IK) + currentSpine2Pose.trans() = spine2TargetTranslation; +#endif currentSpine2Pose.rot() = safeLerp(currentSpine2Pose.rot(), newSpinePose.rot(), SPINE2_ROTATION_FILTER); params.primaryControllerPoses[Rig::PrimaryControllerType_Spine2] = currentSpine2Pose; params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; diff --git a/libraries/animation/src/AnimContext.h b/libraries/animation/src/AnimContext.h index c455dd9c8f..e3ab5d9788 100644 --- a/libraries/animation/src/AnimContext.h +++ b/libraries/animation/src/AnimContext.h @@ -28,6 +28,7 @@ enum class AnimNodeType { InverseKinematics, DefaultPose, TwoBoneIK, + SplineIK, PoleVectorConstraint, NumTypes }; diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index d710e9d8ff..37859c939a 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -866,6 +866,11 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar //virtual const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut, const AnimPoseVec& underPoses) { +#ifdef Q_OS_ANDROID + // disable IK on android + return underPoses; +#endif + // allows solutionSource to be overridden by an animVar auto solutionSource = animVars.lookup(_solutionSourceVar, (int)_solutionSource); diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index dfa61e9fea..b637d131f8 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -26,6 +26,7 @@ #include "AnimInverseKinematics.h" #include "AnimDefaultPose.h" #include "AnimTwoBoneIK.h" +#include "AnimSplineIK.h" #include "AnimPoleVectorConstraint.h" using NodeLoaderFunc = AnimNode::Pointer (*)(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); @@ -41,6 +42,7 @@ 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 AnimNode::Pointer loadTwoBoneIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); +static AnimNode::Pointer loadSplineIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); static AnimNode::Pointer loadPoleVectorConstraintNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f; @@ -61,6 +63,7 @@ static const char* animNodeTypeToString(AnimNode::Type type) { case AnimNode::Type::InverseKinematics: return "inverseKinematics"; case AnimNode::Type::DefaultPose: return "defaultPose"; case AnimNode::Type::TwoBoneIK: return "twoBoneIK"; + case AnimNode::Type::SplineIK: return "splineIK"; case AnimNode::Type::PoleVectorConstraint: return "poleVectorConstraint"; case AnimNode::Type::NumTypes: return nullptr; }; @@ -123,6 +126,7 @@ static NodeLoaderFunc animNodeTypeToLoaderFunc(AnimNode::Type type) { case AnimNode::Type::InverseKinematics: return loadInverseKinematicsNode; case AnimNode::Type::DefaultPose: return loadDefaultPoseNode; case AnimNode::Type::TwoBoneIK: return loadTwoBoneIKNode; + case AnimNode::Type::SplineIK: return loadSplineIKNode; case AnimNode::Type::PoleVectorConstraint: return loadPoleVectorConstraintNode; case AnimNode::Type::NumTypes: return nullptr; }; @@ -140,6 +144,7 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) { case AnimNode::Type::InverseKinematics: return processDoNothing; case AnimNode::Type::DefaultPose: return processDoNothing; case AnimNode::Type::TwoBoneIK: return processDoNothing; + case AnimNode::Type::SplineIK: return processDoNothing; case AnimNode::Type::PoleVectorConstraint: return processDoNothing; case AnimNode::Type::NumTypes: return nullptr; }; @@ -574,6 +579,52 @@ static AnimNode::Pointer loadDefaultPoseNode(const QJsonObject& jsonObj, const Q return node; } +static AnimNode::Pointer loadSplineIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { + READ_FLOAT(alpha, jsonObj, id, jsonUrl, nullptr); + READ_BOOL(enabled, jsonObj, id, jsonUrl, nullptr); + READ_FLOAT(interpDuration, jsonObj, id, jsonUrl, nullptr); + READ_STRING(baseJointName, jsonObj, id, jsonUrl, nullptr); + READ_STRING(midJointName, jsonObj, id, jsonUrl, nullptr); + READ_STRING(tipJointName, jsonObj, id, jsonUrl, nullptr); + READ_STRING(basePositionVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(baseRotationVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(midPositionVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(midRotationVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(tipPositionVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(tipRotationVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(alphaVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(enabledVar, jsonObj, id, jsonUrl, nullptr); + + auto tipFlexCoefficientsValue = jsonObj.value("tipTargetFlexCoefficients"); + if (!tipFlexCoefficientsValue.isArray()) { + qCCritical(animation) << "AnimNodeLoader, bad or missing tip flex array"; + return nullptr; + } + auto tipFlexCoefficientsArray = tipFlexCoefficientsValue.toArray(); + std::vector tipTargetFlexCoefficients; + for (const auto& value : tipFlexCoefficientsArray) { + tipTargetFlexCoefficients.push_back((float)value.toDouble()); + } + + auto midFlexCoefficientsValue = jsonObj.value("midTargetFlexCoefficients"); + if (!midFlexCoefficientsValue.isArray()) { + qCCritical(animation) << "AnimNodeLoader, bad or missing mid flex array"; + return nullptr; + } + auto midFlexCoefficientsArray = midFlexCoefficientsValue.toArray(); + std::vector midTargetFlexCoefficients; + for (const auto& midValue : midFlexCoefficientsArray) { + midTargetFlexCoefficients.push_back((float)midValue.toDouble()); + } + + auto node = std::make_shared(id, alpha, enabled, interpDuration, + baseJointName, midJointName, tipJointName, + basePositionVar, baseRotationVar, midPositionVar, midRotationVar, + tipPositionVar, tipRotationVar, alphaVar, enabledVar, + tipTargetFlexCoefficients, midTargetFlexCoefficients); + return node; +} + static AnimNode::Pointer loadTwoBoneIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { READ_FLOAT(alpha, jsonObj, id, jsonUrl, nullptr); READ_BOOL(enabled, jsonObj, id, jsonUrl, nullptr); diff --git a/libraries/animation/src/AnimPoleVectorConstraint.cpp b/libraries/animation/src/AnimPoleVectorConstraint.cpp index f017fe2348..c0600ee253 100644 --- a/libraries/animation/src/AnimPoleVectorConstraint.cpp +++ b/libraries/animation/src/AnimPoleVectorConstraint.cpp @@ -117,7 +117,7 @@ const AnimPoseVec& AnimPoleVectorConstraint::evaluate(const AnimVariantMap& anim if (axisLength > MIN_LENGTH && refVectorLength > MIN_LENGTH && sideVectorLength > MIN_LENGTH && refVectorProjLength > MIN_LENGTH && poleVectorProjLength > MIN_LENGTH) { - float dot = glm::clamp(glm::dot(refVectorProj / refVectorProjLength, poleVectorProj / poleVectorProjLength), 0.0f, 1.0f); + float dot = glm::clamp(glm::dot(refVectorProj / refVectorProjLength, poleVectorProj / poleVectorProjLength), -1.0f, 1.0f); float sideDot = glm::dot(poleVector, sideVector); float theta = copysignf(1.0f, sideDot) * acosf(dot); diff --git a/libraries/animation/src/AnimSplineIK.cpp b/libraries/animation/src/AnimSplineIK.cpp new file mode 100644 index 0000000000..cfb34560ff --- /dev/null +++ b/libraries/animation/src/AnimSplineIK.cpp @@ -0,0 +1,473 @@ +// +// AnimSplineIK.cpp +// +// Created by Angus Antley on 1/7/19. +// Copyright (c) 2019 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AnimSplineIK.h" +#include "AnimationLogging.h" +#include "CubicHermiteSpline.h" +#include +#include "AnimUtil.h" + +static const float FRAMES_PER_SECOND = 30.0f; + +AnimSplineIK::AnimSplineIK(const QString& id, float alpha, bool enabled, float interpDuration, + const QString& baseJointName, + const QString& midJointName, + const QString& tipJointName, + const QString& basePositionVar, + const QString& baseRotationVar, + const QString& midPositionVar, + const QString& midRotationVar, + const QString& tipPositionVar, + const QString& tipRotationVar, + const QString& alphaVar, + const QString& enabledVar, + const std::vector tipTargetFlexCoefficients, + const std::vector midTargetFlexCoefficients) : + AnimNode(AnimNode::Type::SplineIK, id), + _alpha(alpha), + _enabled(enabled), + _interpDuration(interpDuration), + _baseJointName(baseJointName), + _midJointName(midJointName), + _tipJointName(tipJointName), + _basePositionVar(basePositionVar), + _baseRotationVar(baseRotationVar), + _midPositionVar(midPositionVar), + _midRotationVar(midRotationVar), + _tipPositionVar(tipPositionVar), + _tipRotationVar(tipRotationVar), + _alphaVar(alphaVar), + _enabledVar(enabledVar) +{ + + for (int i = 0; i < (int)tipTargetFlexCoefficients.size(); i++) { + if (i < MAX_NUMBER_FLEX_VARIABLES) { + _tipTargetFlexCoefficients[i] = tipTargetFlexCoefficients[i]; + } + } + _numTipTargetFlexCoefficients = std::min((int)tipTargetFlexCoefficients.size(), MAX_NUMBER_FLEX_VARIABLES); + + for (int i = 0; i < (int)midTargetFlexCoefficients.size(); i++) { + if (i < MAX_NUMBER_FLEX_VARIABLES) { + _midTargetFlexCoefficients[i] = midTargetFlexCoefficients[i]; + } + } + _numMidTargetFlexCoefficients = std::min((int)midTargetFlexCoefficients.size(), MAX_NUMBER_FLEX_VARIABLES); + +} + +AnimSplineIK::~AnimSplineIK() { + +} + +const AnimPoseVec& AnimSplineIK::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { + assert(_children.size() == 1); + if (_children.size() != 1) { + return _poses; + } + + const float MIN_ALPHA = 0.0f; + const float MAX_ALPHA = 1.0f; + float alpha = glm::clamp(animVars.lookup(_alphaVar, _alpha), MIN_ALPHA, MAX_ALPHA); + + // evaluate underPoses + AnimPoseVec underPoses = _children[0]->evaluate(animVars, context, dt, triggersOut); + + // if we don't have a skeleton, or jointName lookup failed or the spline alpha is 0 or there are no underposes. + if (!_skeleton || _baseJointIndex == -1 || _midJointIndex == -1 || _tipJointIndex == -1 || alpha < EPSILON || underPoses.size() == 0) { + // pass underPoses through unmodified. + _poses = underPoses; + return _poses; + } + + // guard against size change + if (underPoses.size() != _poses.size()) { + _poses = underPoses; + } + + // determine if we should interpolate + bool enabled = animVars.lookup(_enabledVar, _enabled); + if (enabled != _enabled) { + AnimChain poseChain; + poseChain.buildFromRelativePoses(_skeleton, _poses, _tipJointIndex); + if (enabled) { + beginInterp(InterpType::SnapshotToSolve, poseChain); + } else { + beginInterp(InterpType::SnapshotToUnderPoses, poseChain); + } + } + _enabled = enabled; + + // now that we have saved the previous _poses in _snapshotChain, we can update to the current underposes + _poses = underPoses; + + // don't build chains or do IK if we are disabled & not interping. + if (_interpType == InterpType::None && !enabled) { + return _poses; + } + + // compute under chain for possible interpolation + AnimChain underChain; + underChain.buildFromRelativePoses(_skeleton, underPoses, _tipJointIndex); + + AnimPose baseTargetAbsolutePose; + // if there is a baseJoint ik target in animvars then set the joint to that + // otherwise use the underpose + AnimPose baseJointUnderPose = _skeleton->getAbsolutePose(_baseJointIndex, _poses); + baseTargetAbsolutePose.rot() = animVars.lookupRigToGeometry(_baseRotationVar, baseJointUnderPose.rot()); + baseTargetAbsolutePose.trans() = animVars.lookupRigToGeometry(_basePositionVar, baseJointUnderPose.trans()); + + int baseParentIndex = _skeleton->getParentIndex(_baseJointIndex); + AnimPose baseParentAbsPose(Quaternions::IDENTITY,glm::vec3()); + if (baseParentIndex >= 0) { + baseParentAbsPose = _skeleton->getAbsolutePose(baseParentIndex, _poses); + } + _poses[_baseJointIndex] = baseParentAbsPose.inverse() * baseTargetAbsolutePose; + _poses[_baseJointIndex].scale() = glm::vec3(1.0f); + + // initialize the middle joint target + IKTarget midTarget; + midTarget.setType((int)IKTarget::Type::Spline); + midTarget.setIndex(_midJointIndex); + AnimPose absPoseMid = _skeleton->getAbsolutePose(_midJointIndex, _poses); + glm::quat midTargetRotation = animVars.lookupRigToGeometry(_midRotationVar, absPoseMid.rot()); + glm::vec3 midTargetPosition = animVars.lookupRigToGeometry(_midPositionVar, absPoseMid.trans()); + midTarget.setPose(midTargetRotation, midTargetPosition); + midTarget.setWeight(1.0f); + midTarget.setFlexCoefficients(_numMidTargetFlexCoefficients, _midTargetFlexCoefficients); + + // solve the lower spine spline + AnimChain midJointChain; + AnimPoseVec absolutePosesAfterBaseTipSpline; + absolutePosesAfterBaseTipSpline.resize(_poses.size()); + computeAbsolutePoses(absolutePosesAfterBaseTipSpline); + midJointChain.buildFromRelativePoses(_skeleton, _poses, midTarget.getIndex()); + solveTargetWithSpline(context, _baseJointIndex, midTarget, absolutePosesAfterBaseTipSpline, context.getEnableDebugDrawIKChains(), midJointChain); + midJointChain.outputRelativePoses(_poses); + + // initialize the tip target + IKTarget tipTarget; + tipTarget.setType((int)IKTarget::Type::Spline); + tipTarget.setIndex(_tipJointIndex); + AnimPose absPoseTip = _skeleton->getAbsolutePose(_tipJointIndex, _poses); + glm::quat tipRotation = animVars.lookupRigToGeometry(_tipRotationVar, absPoseTip.rot()); + glm::vec3 tipTranslation = animVars.lookupRigToGeometry(_tipPositionVar, absPoseTip.trans()); + tipTarget.setPose(tipRotation, tipTranslation); + tipTarget.setWeight(1.0f); + tipTarget.setFlexCoefficients(_numTipTargetFlexCoefficients, _tipTargetFlexCoefficients); + + // solve the upper spine spline + AnimChain upperJointChain; + AnimPoseVec finalAbsolutePoses; + finalAbsolutePoses.resize(_poses.size()); + computeAbsolutePoses(finalAbsolutePoses); + upperJointChain.buildFromRelativePoses(_skeleton, _poses, tipTarget.getIndex()); + solveTargetWithSpline(context, _midJointIndex, tipTarget, finalAbsolutePoses, context.getEnableDebugDrawIKChains(), upperJointChain); + upperJointChain.buildDirtyAbsolutePoses(); + upperJointChain.outputRelativePoses(_poses); + + // compute chain + AnimChain ikChain; + ikChain.buildFromRelativePoses(_skeleton, _poses, _tipJointIndex); + // blend with the underChain + ikChain.blend(underChain, alpha); + + // apply smooth interpolation when turning ik on and off + if (_interpType != InterpType::None) { + _interpAlpha += _interpAlphaVel * dt; + + // ease in expo + float easeInAlpha = 1.0f - powf(2.0f, -10.0f * _interpAlpha); + + if (_interpAlpha < 1.0f) { + AnimChain interpChain; + if (_interpType == InterpType::SnapshotToUnderPoses) { + interpChain = underChain; + interpChain.blend(_snapshotChain, easeInAlpha); + } else if (_interpType == InterpType::SnapshotToSolve) { + interpChain = ikChain; + interpChain.blend(_snapshotChain, easeInAlpha); + } + // copy interpChain into _poses + interpChain.outputRelativePoses(_poses); + } else { + // interpolation complete + _interpType = InterpType::None; + } + } + + if (_interpType == InterpType::None) { + if (enabled) { + // copy chain into _poses + ikChain.outputRelativePoses(_poses); + } else { + // copy under chain into _poses + underChain.outputRelativePoses(_poses); + } + } + + // debug render ik targets + if (context.getEnableDebugDrawIKTargets()) { + const vec4 WHITE(1.0f); + const vec4 GREEN(0.0f, 1.0f, 0.0f, 1.0f); + glm::mat4 rigToAvatarMat = createMatFromQuatAndPos(Quaternions::Y_180, glm::vec3()); + + glm::mat4 geomTargetMat = createMatFromQuatAndPos(tipTarget.getRotation(), tipTarget.getTranslation()); + glm::mat4 avatarTargetMat = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat; + QString name = QString("ikTargetSplineTip"); + DebugDraw::getInstance().addMyAvatarMarker(name, glmExtractRotation(avatarTargetMat), extractTranslation(avatarTargetMat), WHITE); + + glm::mat4 geomTargetMat2 = createMatFromQuatAndPos(midTarget.getRotation(), midTarget.getTranslation()); + glm::mat4 avatarTargetMat2 = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat2; + QString name2 = QString("ikTargetSplineMid"); + DebugDraw::getInstance().addMyAvatarMarker(name2, glmExtractRotation(avatarTargetMat2), extractTranslation(avatarTargetMat2), WHITE); + + glm::mat4 geomTargetMat3 = createMatFromQuatAndPos(baseTargetAbsolutePose.rot(), baseTargetAbsolutePose.trans()); + glm::mat4 avatarTargetMat3 = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat3; + QString name3 = QString("ikTargetSplineBase"); + DebugDraw::getInstance().addMyAvatarMarker(name3, glmExtractRotation(avatarTargetMat3), extractTranslation(avatarTargetMat3), WHITE); + + + } else if (context.getEnableDebugDrawIKTargets() != _previousEnableDebugIKTargets) { + + // remove markers if they were added last frame. + QString name = QString("ikTargetSplineTip"); + DebugDraw::getInstance().removeMyAvatarMarker(name); + QString name2 = QString("ikTargetSplineMid"); + DebugDraw::getInstance().removeMyAvatarMarker(name2); + QString name3 = QString("ikTargetSplineBase"); + DebugDraw::getInstance().removeMyAvatarMarker(name3); + } + _previousEnableDebugIKTargets = context.getEnableDebugDrawIKTargets(); + + return _poses; +} + +void AnimSplineIK::lookUpIndices() { + assert(_skeleton); + + // look up bone indices by name + std::vector indices = _skeleton->lookUpJointIndices({ _baseJointName, _tipJointName, _midJointName }); + + // cache the results + _baseJointIndex = indices[0]; + _tipJointIndex = indices[1]; + _midJointIndex = indices[2]; +} + +void AnimSplineIK::computeAbsolutePoses(AnimPoseVec& absolutePoses) const { + int numJoints = (int)_poses.size(); + assert(numJoints <= _skeleton->getNumJoints()); + assert(numJoints == (int)absolutePoses.size()); + for (int i = 0; i < numJoints; ++i) { + int parentIndex = _skeleton->getParentIndex(i); + if (parentIndex < 0) { + absolutePoses[i] = _poses[i]; + } else { + absolutePoses[i] = absolutePoses[parentIndex] * _poses[i]; + } + } +} + +// for AnimDebugDraw rendering +const AnimPoseVec& AnimSplineIK::getPosesInternal() const { + return _poses; +} + +void AnimSplineIK::setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) { + AnimNode::setSkeletonInternal(skeleton); + lookUpIndices(); +} + +void AnimSplineIK::solveTargetWithSpline(const AnimContext& context, int base, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug, AnimChain& chainInfoOut) const { + + // build spline from tip to base + AnimPose tipPose = AnimPose(glm::vec3(1.0f), target.getRotation(), target.getTranslation()); + AnimPose basePose = absolutePoses[base]; + + CubicHermiteSplineFunctorWithArcLength spline; + if (target.getIndex() == _tipJointIndex) { + // set gain factors so that more curvature occurs near the tip of the spline. + const float HIPS_GAIN = 0.5f; + const float HEAD_GAIN = 1.0f; + spline = CubicHermiteSplineFunctorWithArcLength(tipPose.rot(), tipPose.trans(), basePose.rot(), basePose.trans(), HIPS_GAIN, HEAD_GAIN); + } else { + spline = CubicHermiteSplineFunctorWithArcLength(tipPose.rot(),tipPose.trans(), basePose.rot(), basePose.trans()); + } + float totalArcLength = spline.arcLength(1.0f); + + // This prevents the rotation interpolation from rotating the wrong physical way (but correct mathematical way) + // when the head is arched backwards very far. + glm::quat halfRot = safeLerp(basePose.rot(), tipPose.rot(), 0.5f); + if (glm::dot(halfRot * Vectors::UNIT_Z, basePose.rot() * Vectors::UNIT_Z) < 0.0f) { + tipPose.rot() = -tipPose.rot(); + } + + // find or create splineJointInfo for this target + const std::vector* splineJointInfoVec = findOrCreateSplineJointInfo(context, base, target); + + if (splineJointInfoVec && splineJointInfoVec->size() > 0) { + const int baseParentIndex = _skeleton->getParentIndex(base); + AnimPose parentAbsPose = (baseParentIndex >= 0) ? absolutePoses[baseParentIndex] : AnimPose(); + // go thru splineJointInfoVec backwards (base to tip) + for (int i = (int)splineJointInfoVec->size() - 1; i >= 0; i--) { + const SplineJointInfo& splineJointInfo = (*splineJointInfoVec)[i]; + float t = spline.arcLengthInverse(splineJointInfo.ratio * totalArcLength); + glm::vec3 trans = spline(t); + + // for base->tip splines, preform most twist toward the tip by using ease in function. t^2 + float rotT = t; + if (target.getIndex() == _tipJointIndex) { + rotT = t * t; + } + glm::quat twistRot = safeLerp(basePose.rot(), tipPose.rot(), rotT); + + // compute the rotation by using the derivative of the spline as the y-axis, and the twistRot x-axis + glm::vec3 y = glm::normalize(spline.d(t)); + glm::vec3 x = twistRot * Vectors::UNIT_X; + glm::vec3 u, v, w; + generateBasisVectors(y, x, v, u, w); + glm::mat3 m(u, v, glm::cross(u, v)); + glm::quat rot = glm::normalize(glm::quat_cast(m)); + + AnimPose desiredAbsPose = AnimPose(glm::vec3(1.0f), rot, trans) * splineJointInfo.offsetPose; + + // apply flex coefficent + AnimPose flexedAbsPose; + // get the number of flex coeff for this spline + float interpedCoefficient = 1.0f; + int numFlexCoeff = target.getNumFlexCoefficients(); + if (numFlexCoeff == (int)splineJointInfoVec->size()) { + // then do nothing special + interpedCoefficient = target.getFlexCoefficient(i); + } else { + // interp based on ratio of the joint. + if (splineJointInfo.ratio < 1.0f) { + float flexInterp = splineJointInfo.ratio * (float)(numFlexCoeff - 1); + int startCoeff = (int)glm::floor(flexInterp); + float partial = flexInterp - startCoeff; + interpedCoefficient = target.getFlexCoefficient(startCoeff) * (1.0f - partial) + target.getFlexCoefficient(startCoeff + 1) * partial; + } else { + interpedCoefficient = target.getFlexCoefficient(numFlexCoeff - 1); + } + } + ::blend(1, &absolutePoses[splineJointInfo.jointIndex], &desiredAbsPose, interpedCoefficient, &flexedAbsPose); + + AnimPose relPose = parentAbsPose.inverse() * flexedAbsPose; + + if (splineJointInfo.jointIndex != base) { + // constrain the amount the spine can stretch or compress + float length = glm::length(relPose.trans()); + const float EPSILON = 0.0001f; + if (length > EPSILON) { + float defaultLength = glm::length(_skeleton->getRelativeDefaultPose(splineJointInfo.jointIndex).trans()); + const float STRETCH_COMPRESS_PERCENTAGE = 0.15f; + const float MAX_LENGTH = defaultLength * (1.0f + STRETCH_COMPRESS_PERCENTAGE); + const float MIN_LENGTH = defaultLength * (1.0f - STRETCH_COMPRESS_PERCENTAGE); + if (length > MAX_LENGTH) { + relPose.trans() = (relPose.trans() / length) * MAX_LENGTH; + } else if (length < MIN_LENGTH) { + relPose.trans() = (relPose.trans() / length) * MIN_LENGTH; + } + } else { + relPose.trans() = glm::vec3(0.0f); + } + } + + if (!chainInfoOut.setRelativePoseAtJointIndex(splineJointInfo.jointIndex, relPose)) { + qCDebug(animation) << "error: joint not found in spline chain"; + } + + parentAbsPose = flexedAbsPose; + } + } + + if (debug) { + const vec4 CYAN(0.0f, 1.0f, 1.0f, 1.0f); + chainInfoOut.debugDraw(context.getRigToWorldMatrix() * context.getGeometryToRigMatrix(), CYAN); + } +} + +const std::vector* AnimSplineIK::findOrCreateSplineJointInfo(const AnimContext& context, int base, const IKTarget& target) const { + // find or create splineJointInfo for this target + auto iter = _splineJointInfoMap.find(target.getIndex()); + if (iter != _splineJointInfoMap.end()) { + return &(iter->second); + } else { + computeAndCacheSplineJointInfosForIKTarget(context, base, target); + auto iter = _splineJointInfoMap.find(target.getIndex()); + if (iter != _splineJointInfoMap.end()) { + return &(iter->second); + } + } + return nullptr; +} + +// pre-compute information about each joint influenced by this spline IK target. +void AnimSplineIK::computeAndCacheSplineJointInfosForIKTarget(const AnimContext& context, int base, const IKTarget& target) const { + std::vector splineJointInfoVec; + + // build spline between the default poses. + AnimPose tipPose = _skeleton->getAbsoluteDefaultPose(target.getIndex()); + AnimPose basePose = _skeleton->getAbsoluteDefaultPose(base); + + CubicHermiteSplineFunctorWithArcLength spline; + if (target.getIndex() == _tipJointIndex) { + // set gain factors so that more curvature occurs near the tip of the spline. + const float HIPS_GAIN = 0.5f; + const float HEAD_GAIN = 1.0f; + spline = CubicHermiteSplineFunctorWithArcLength(tipPose.rot(), tipPose.trans(), basePose.rot(), basePose.trans(), HIPS_GAIN, HEAD_GAIN); + } else { + spline = CubicHermiteSplineFunctorWithArcLength(tipPose.rot(), tipPose.trans(), basePose.rot(), basePose.trans()); + } + // measure the total arc length along the spline + float totalArcLength = spline.arcLength(1.0f); + + glm::vec3 baseToTip = tipPose.trans() - basePose.trans(); + float baseToTipLength = glm::length(baseToTip); + glm::vec3 baseToTipNormal = baseToTip / baseToTipLength; + + int index = target.getIndex(); + int endIndex = _skeleton->getParentIndex(base); + + while (index != endIndex) { + AnimPose defaultPose = _skeleton->getAbsoluteDefaultPose(index); + glm::vec3 baseToCurrentJoint = defaultPose.trans() - basePose.trans(); + float ratio = glm::dot(baseToCurrentJoint, baseToTipNormal) / baseToTipLength; + + // compute offset from spline to the default pose. + float t = spline.arcLengthInverse(ratio * totalArcLength); + + // compute the rotation by using the derivative of the spline as the y-axis, and the defaultPose x-axis + glm::vec3 y = glm::normalize(spline.d(t)); + glm::vec3 x = defaultPose.rot() * Vectors::UNIT_X; + glm::vec3 u, v, w; + generateBasisVectors(y, x, v, u, w); + glm::mat3 m(u, v, glm::cross(u, v)); + glm::quat rot = glm::normalize(glm::quat_cast(m)); + + AnimPose pose(glm::vec3(1.0f), rot, spline(t)); + AnimPose offsetPose = pose.inverse() * defaultPose; + + SplineJointInfo splineJointInfo = { index, ratio, offsetPose }; + splineJointInfoVec.push_back(splineJointInfo); + index = _skeleton->getParentIndex(index); + } + _splineJointInfoMap[target.getIndex()] = splineJointInfoVec; +} + +void AnimSplineIK::beginInterp(InterpType interpType, const AnimChain& chain) { + // capture the current poses in a snapshot. + _snapshotChain = chain; + + _interpType = interpType; + _interpAlphaVel = FRAMES_PER_SECOND / _interpDuration; + _interpAlpha = 0.0f; +} diff --git a/libraries/animation/src/AnimSplineIK.h b/libraries/animation/src/AnimSplineIK.h new file mode 100644 index 0000000000..a4d8da37ca --- /dev/null +++ b/libraries/animation/src/AnimSplineIK.h @@ -0,0 +1,104 @@ +// +// AnimSplineIK.h +// +// Created by Angus Antley on 1/7/19. +// Copyright (c) 2019 High Fidelity, Inc. All rights reserved. +// +// 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_AnimSplineIK_h +#define hifi_AnimSplineIK_h + +#include "AnimNode.h" +#include "IKTarget.h" +#include "AnimChain.h" + +static const int MAX_NUMBER_FLEX_VARIABLES = 10; + +// Spline IK for the spine +class AnimSplineIK : public AnimNode { +public: + AnimSplineIK(const QString& id, float alpha, bool enabled, float interpDuration, + const QString& baseJointName, const QString& midJointName, const QString& tipJointName, + const QString& basePositionVar, const QString& baseRotationVar, + const QString& midPositionVar, const QString& midRotationVar, + const QString& tipPositionVar, const QString& tipRotationVar, + const QString& alphaVar, const QString& enabledVar, + const std::vector tipTargetFlexCoefficients, + const std::vector midTargetFlexCoefficients); + + virtual ~AnimSplineIK() override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; + +protected: + + enum class InterpType { + None = 0, + SnapshotToUnderPoses, + SnapshotToSolve, + NumTypes + }; + + void computeAbsolutePoses(AnimPoseVec& absolutePoses) const; + void loadPoses(const AnimPoseVec& poses); + + // for AnimDebugDraw rendering + virtual const AnimPoseVec& getPosesInternal() const override; + virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override; + + void lookUpIndices(); + void beginInterp(InterpType interpType, const AnimChain& chain); + + AnimPoseVec _poses; + + float _alpha; + bool _enabled; + float _interpDuration; + QString _baseJointName; + QString _midJointName; + QString _tipJointName; + QString _basePositionVar; + QString _baseRotationVar; + QString _midPositionVar; + QString _midRotationVar; + QString _tipPositionVar; + QString _tipRotationVar; + QString _alphaVar; // float - (0, 1) 0 means underPoses only, 1 means IK only. + QString _enabledVar; + + float _tipTargetFlexCoefficients[MAX_NUMBER_FLEX_VARIABLES]; + float _midTargetFlexCoefficients[MAX_NUMBER_FLEX_VARIABLES]; + int _numTipTargetFlexCoefficients { 0 }; + int _numMidTargetFlexCoefficients { 0 }; + + int _baseJointIndex { -1 }; + int _midJointIndex { -1 }; + int _tipJointIndex { -1 }; + + bool _previousEnableDebugIKTargets { false }; + + InterpType _interpType{ InterpType::None }; + float _interpAlphaVel{ 0.0f }; + float _interpAlpha{ 0.0f }; + AnimChain _snapshotChain; + + // used to pre-compute information about each joint influenced by a spline IK target. + struct SplineJointInfo { + int jointIndex; // joint in the skeleton that this information pertains to. + float ratio; // percentage (0..1) along the spline for this joint. + AnimPose offsetPose; // local offset from the spline to the joint. + }; + + void solveTargetWithSpline(const AnimContext& context, int base, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug, AnimChain& chainInfoOut) const; + void computeAndCacheSplineJointInfosForIKTarget(const AnimContext& context, int base, const IKTarget& target) const; + const std::vector* findOrCreateSplineJointInfo(const AnimContext& context, int base, const IKTarget& target) const; + mutable std::map> _splineJointInfoMap; + + // no copies + AnimSplineIK(const AnimSplineIK&) = delete; + AnimSplineIK& operator=(const AnimSplineIK&) = delete; + +}; +#endif // hifi_AnimSplineIK_h diff --git a/libraries/animation/src/AnimStateMachine.cpp b/libraries/animation/src/AnimStateMachine.cpp index fb13b8e71c..2c5d4ad0f3 100644 --- a/libraries/animation/src/AnimStateMachine.cpp +++ b/libraries/animation/src/AnimStateMachine.cpp @@ -22,7 +22,6 @@ AnimStateMachine::~AnimStateMachine() { } const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { - float parentDebugAlpha = context.getDebugAlpha(_id); QString desiredStateID = animVars.lookup(_currentStateVar, _currentState->getID()); diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h index 325a1b40b6..57eaff9c30 100644 --- a/libraries/animation/src/IKTarget.h +++ b/libraries/animation/src/IKTarget.h @@ -35,6 +35,8 @@ public: bool getPoleVectorEnabled() const { return _poleVectorEnabled; } int getIndex() const { return _index; } Type getType() const { return _type; } + int getNumFlexCoefficients() const { return (int)_numFlexCoefficients; } + float getFlexCoefficient(size_t chainDepth) const; void setPose(const glm::quat& rotation, const glm::vec3& translation); void setPoleVector(const glm::vec3& poleVector) { _poleVector = poleVector; } @@ -43,7 +45,6 @@ public: void setIndex(int index) { _index = index; } void setType(int); void setFlexCoefficients(size_t numFlexCoefficientsIn, const float* flexCoefficientsIn); - float getFlexCoefficient(size_t chainDepth) const; void setWeight(float weight) { _weight = weight; } float getWeight() const { return _weight; } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index a9c57a4a15..be6240017f 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -34,7 +34,6 @@ #include "IKTarget.h" #include "PathUtils.h" - static int nextRigId = 1; static std::map rigRegistry; static std::mutex rigRegistryMutex; @@ -74,6 +73,20 @@ static const QString RIGHT_FOOT_IK_ROTATION_VAR("rightFootIKRotationVar"); static const QString MAIN_STATE_MACHINE_RIGHT_FOOT_ROTATION("mainStateMachineRightFootRotation"); static const QString MAIN_STATE_MACHINE_RIGHT_FOOT_POSITION("mainStateMachineRightFootPosition"); +static const QString LEFT_HAND_POSITION("leftHandPosition"); +static const QString LEFT_HAND_ROTATION("leftHandRotation"); +static const QString LEFT_HAND_IK_POSITION_VAR("leftHandIKPositionVar"); +static const QString LEFT_HAND_IK_ROTATION_VAR("leftHandIKRotationVar"); +static const QString MAIN_STATE_MACHINE_LEFT_HAND_POSITION("mainStateMachineLeftHandPosition"); +static const QString MAIN_STATE_MACHINE_LEFT_HAND_ROTATION("mainStateMachineLeftHandRotation"); + +static const QString RIGHT_HAND_POSITION("rightHandPosition"); +static const QString RIGHT_HAND_ROTATION("rightHandRotation"); +static const QString RIGHT_HAND_IK_POSITION_VAR("rightHandIKPositionVar"); +static const QString RIGHT_HAND_IK_ROTATION_VAR("rightHandIKRotationVar"); +static const QString MAIN_STATE_MACHINE_RIGHT_HAND_ROTATION("mainStateMachineRightHandRotation"); +static const QString MAIN_STATE_MACHINE_RIGHT_HAND_POSITION("mainStateMachineRightHandPosition"); + Rig::Rig() { // Ensure thread-safe access to the rigRegistry. @@ -1051,16 +1064,29 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos t += deltaTime; - if (_enableInverseKinematics != _lastEnableInverseKinematics) { - if (_enableInverseKinematics) { - _animVars.set("ikOverlayAlpha", 1.0f); - } else { - _animVars.set("ikOverlayAlpha", 0.0f); - } + if (_enableInverseKinematics) { + _animVars.set("ikOverlayAlpha", 1.0f); + _animVars.set("splineIKEnabled", true); + _animVars.set("leftHandIKEnabled", true); + _animVars.set("rightHandIKEnabled", true); + _animVars.set("leftFootIKEnabled", true); + _animVars.set("rightFootIKEnabled", true); + _animVars.set("leftFootPoleVectorEnabled", true); + _animVars.set("rightFootPoleVectorEnabled", true); + } else { + _animVars.set("ikOverlayAlpha", 0.0f); + _animVars.set("splineIKEnabled", false); + _animVars.set("leftHandIKEnabled", false); + _animVars.set("rightHandIKEnabled", false); + _animVars.set("leftFootIKEnabled", false); + _animVars.set("rightFootIKEnabled", false); + _animVars.set("leftHandPoleVectorEnabled", false); + _animVars.set("rightHandPoleVectorEnabled", false); + _animVars.set("leftFootPoleVectorEnabled", false); + _animVars.set("rightFootPoleVectorEnabled", false); } _lastEnableInverseKinematics = _enableInverseKinematics; } - _lastForward = forward; _lastPosition = worldPosition; _lastVelocity = workingVelocity; @@ -1251,6 +1277,7 @@ void Rig::computeHeadFromHMD(const AnimPose& hmdPose, glm::vec3& headPositionOut void Rig::updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headPose) { if (_animSkeleton) { if (headEnabled) { + _animVars.set("splineIKEnabled", true); _animVars.set("headPosition", headPose.trans()); _animVars.set("headRotation", headPose.rot()); if (hipsEnabled) { @@ -1265,6 +1292,7 @@ void Rig::updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headPos _animVars.set("headWeight", 8.0f); } } else { + _animVars.set("splineIKEnabled", false); _animVars.unset("headPosition"); _animVars.set("headRotation", headPose.rot()); _animVars.set("headType", (int)IKTarget::Type::RotationOnly); @@ -1396,8 +1424,22 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab const bool ENABLE_POLE_VECTORS = true; + if (headEnabled) { + // always do IK if head is enabled + _animVars.set("leftHandIKEnabled", true); + _animVars.set("rightHandIKEnabled", true); + } else { + // only do IK if we have a valid foot. + _animVars.set("leftHandIKEnabled", leftHandEnabled); + _animVars.set("rightHandIKEnabled", rightHandEnabled); + } + if (leftHandEnabled) { + // we need this for twoBoneIK version of hands. + _animVars.set(LEFT_HAND_IK_POSITION_VAR, LEFT_HAND_POSITION); + _animVars.set(LEFT_HAND_IK_ROTATION_VAR, LEFT_HAND_ROTATION); + glm::vec3 handPosition = leftHandPose.trans(); glm::quat handRotation = leftHandPose.rot(); @@ -1430,8 +1472,11 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab _animVars.set("leftHandPoleVectorEnabled", false); } } else { - _animVars.set("leftHandPoleVectorEnabled", false); + // need this for two bone ik + _animVars.set(LEFT_HAND_IK_POSITION_VAR, MAIN_STATE_MACHINE_LEFT_HAND_POSITION); + _animVars.set(LEFT_HAND_IK_ROTATION_VAR, MAIN_STATE_MACHINE_LEFT_HAND_ROTATION); + _animVars.set("leftHandPoleVectorEnabled", false); _animVars.unset("leftHandPosition"); _animVars.unset("leftHandRotation"); @@ -1445,6 +1490,10 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab if (rightHandEnabled) { + // need this for two bone IK + _animVars.set(RIGHT_HAND_IK_POSITION_VAR, RIGHT_HAND_POSITION); + _animVars.set(RIGHT_HAND_IK_ROTATION_VAR, RIGHT_HAND_ROTATION); + glm::vec3 handPosition = rightHandPose.trans(); glm::quat handRotation = rightHandPose.rot(); @@ -1478,8 +1527,12 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab _animVars.set("rightHandPoleVectorEnabled", false); } } else { - _animVars.set("rightHandPoleVectorEnabled", false); + // need this for two bone IK + _animVars.set(RIGHT_HAND_IK_POSITION_VAR, MAIN_STATE_MACHINE_RIGHT_HAND_POSITION); + _animVars.set(RIGHT_HAND_IK_ROTATION_VAR, MAIN_STATE_MACHINE_RIGHT_HAND_ROTATION); + + _animVars.set("rightHandPoleVectorEnabled", false); _animVars.unset("rightHandPosition"); _animVars.unset("rightHandRotation"); @@ -1697,6 +1750,7 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex, correctionVector = forwardAmount * frontVector; } poleVector = glm::normalize(attenuationVector + fullPoleVector + correctionVector); + return true; } @@ -1819,7 +1873,7 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo std::shared_ptr ikNode = getAnimInverseKinematicsNode(); for (int i = 0; i < (int)NumSecondaryControllerTypes; i++) { int index = indexOfJoint(secondaryControllerJointNames[i]); - if (index >= 0) { + if ((index >= 0) && (ikNode)) { if (params.secondaryControllerFlags[i] & (uint8_t)ControllerFlags::Enabled) { ikNode->setSecondaryTargetInRigFrame(index, params.secondaryControllerPoses[i]); } else { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 395fc3b7b4..b842597b88 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -37,6 +37,7 @@ #include "RenderableModelEntityItem.h" #include +#include #include "Logging.h" @@ -1535,11 +1536,13 @@ void Avatar::setModelURLFinished(bool success) { void Avatar::rigReady() { buildUnscaledEyeHeightCache(); computeMultiSphereShapes(); + buildSpine2SplineRatioCache(); } // rig has been reset. void Avatar::rigReset() { clearUnscaledEyeHeightCache(); + clearSpine2SplineRatioCache(); } void Avatar::computeMultiSphereShapes() { @@ -1994,10 +1997,43 @@ void Avatar::buildUnscaledEyeHeightCache() { } } +void Avatar::buildSpine2SplineRatioCache() { + if (_skeletonModel) { + auto& rig = _skeletonModel->getRig(); + AnimPose hipsRigDefaultPose = rig.getAbsoluteDefaultPose(rig.indexOfJoint("Hips")); + AnimPose headRigDefaultPose(rig.getAbsoluteDefaultPose(rig.indexOfJoint("Head"))); + glm::vec3 basePosition = hipsRigDefaultPose.trans(); + glm::vec3 tipPosition = headRigDefaultPose.trans(); + glm::vec3 spine2Position = rig.getAbsoluteDefaultPose(rig.indexOfJoint("Spine2")).trans(); + + glm::vec3 baseToTip = tipPosition - basePosition; + float baseToTipLength = glm::length(baseToTip); + glm::vec3 baseToTipNormal = baseToTip / baseToTipLength; + glm::vec3 baseToSpine2 = spine2Position - basePosition; + + _spine2SplineRatio = glm::dot(baseToSpine2, baseToTipNormal) / baseToTipLength; + + CubicHermiteSplineFunctorWithArcLength defaultSpline(headRigDefaultPose.rot(), headRigDefaultPose.trans(), hipsRigDefaultPose.rot(), hipsRigDefaultPose.trans()); + + // measure the total arc length along the spline + float totalDefaultArcLength = defaultSpline.arcLength(1.0f); + float t = defaultSpline.arcLengthInverse(_spine2SplineRatio * totalDefaultArcLength); + glm::vec3 defaultSplineSpine2Translation = defaultSpline(t); + + _spine2SplineOffset = spine2Position - defaultSplineSpine2Translation; + } + +} + void Avatar::clearUnscaledEyeHeightCache() { _unscaledEyeHeightCache.set(DEFAULT_AVATAR_EYE_HEIGHT); } +void Avatar::clearSpine2SplineRatioCache() { + _spine2SplineRatio = DEFAULT_AVATAR_EYE_HEIGHT; + _spine2SplineOffset = glm::vec3(); +} + float Avatar::getUnscaledEyeHeightFromSkeleton() const { // TODO: if performance becomes a concern we can cache this value rather then computing it everytime. diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 1e6893a410..1acee7439f 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -236,6 +236,7 @@ public: virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } +<<<<<<< HEAD // world-space to avatar-space rigconversion functions /**jsdoc * @function MyAvatar.worldToJointPoint @@ -285,6 +286,10 @@ public: * @returns {Quat} */ Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; +======= + virtual glm::vec3 getSpine2SplineOffset() const { return _spine2SplineOffset; } + virtual float getSpine2SplineRatio() const { return _spine2SplineRatio; } +>>>>>>> cache the spine2 spline default offset and ratio virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; virtual void setAttachmentData(const QVector& attachmentData) override; @@ -563,7 +568,9 @@ public slots: protected: float getUnscaledEyeHeightFromSkeleton() const; void buildUnscaledEyeHeightCache(); + void buildSpine2SplineRatioCache(); void clearUnscaledEyeHeightCache(); + void clearSpine2SplineRatioCache(); virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send. QString _empty{}; virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter! @@ -669,6 +676,8 @@ protected: float _displayNameAlpha { 1.0f }; ThreadSafeValueCache _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT }; + float _spine2SplineRatio { DEFAULT_SPINE2_SPLINE_PROPORTION }; + glm::vec3 _spine2SplineOffset; std::unordered_map _materials; std::mutex _materialsLock; diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 9e7f422b40..30bd527546 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1288,6 +1288,20 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr } joint.inverseBindRotation = joint.inverseDefaultRotation; joint.name = fbxModel.name; +<<<<<<< HEAD +======= + if (hfmModel.hfmToHifiJointNameMapping.contains(hfmModel.hfmToHifiJointNameMapping.key(joint.name))) { + joint.name = hfmModel.hfmToHifiJointNameMapping.key(fbxModel.name); + } + + foreach (const QString& childID, _connectionChildMap.values(modelID)) { + QString type = typeFlags.value(childID); + if (!type.isEmpty()) { + hfmModel.hasSkeletonJoints |= (joint.isSkeletonJoint = type.toLower().contains("Skeleton")); + break; + } + } +>>>>>>> implemented the splineIK in animSplineIK.cpp, todo: disable animinversekinematic.cpp joint.bindTransformFoundInCluster = false; diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index 103782bd3f..d55a63b960 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -20,6 +20,7 @@ const float DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD = 0.11f; // meters const float DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD = 0.185f; // meters const float DEFAULT_AVATAR_NECK_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD; const float DEFAULT_AVATAR_EYE_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD; +const float DEFAULT_SPINE2_SPLINE_PROPORTION = 0.71f; const float DEFAULT_AVATAR_SUPPORT_BASE_LEFT = -0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f; diff --git a/libraries/shared/src/CubicHermiteSpline.h b/libraries/shared/src/CubicHermiteSpline.h index cdbc64308d..c83000996b 100644 --- a/libraries/shared/src/CubicHermiteSpline.h +++ b/libraries/shared/src/CubicHermiteSpline.h @@ -66,19 +66,19 @@ public: memset(_values, 0, sizeof(float) * (NUM_SUBDIVISIONS + 1)); } CubicHermiteSplineFunctorWithArcLength(const glm::vec3& p0, const glm::vec3& m0, const glm::vec3& p1, const glm::vec3& m1) : CubicHermiteSplineFunctor(p0, m0, p1, m1) { - // initialize _values with the accumulated arcLength along the spline. - const float DELTA = 1.0f / NUM_SUBDIVISIONS; - float alpha = 0.0f; - float accum = 0.0f; - _values[0] = 0.0f; - glm::vec3 prevValue = this->operator()(alpha); - for (int i = 1; i < NUM_SUBDIVISIONS + 1; i++) { - glm::vec3 nextValue = this->operator()(alpha + DELTA); - accum += glm::distance(prevValue, nextValue); - alpha += DELTA; - _values[i] = accum; - prevValue = nextValue; - } + + initValues(); + } + + CubicHermiteSplineFunctorWithArcLength(const glm::quat& tipRot, const glm::vec3& tipTrans, const glm::quat& baseRot, const glm::vec3& baseTrans, float baseGain = 1.0f, float tipGain = 1.0f) : CubicHermiteSplineFunctor() { + + float linearDistance = glm::length(baseTrans - tipTrans); + _p0 = baseTrans; + _m0 = baseGain * linearDistance * (baseRot * Vectors::UNIT_Y); + _p1 = tipTrans; + _m1 = tipGain * linearDistance * (tipRot * Vectors::UNIT_Y); + + initValues(); } CubicHermiteSplineFunctorWithArcLength(const CubicHermiteSplineFunctorWithArcLength& orig) : CubicHermiteSplineFunctor(orig) { @@ -110,6 +110,21 @@ public: } protected: float _values[NUM_SUBDIVISIONS + 1]; + + void initValues() { + // initialize _values with the accumulated arcLength along the spline. + const float DELTA = 1.0f / NUM_SUBDIVISIONS; + float alpha = 0.0f; + float accum = 0.0f; + _values[0] = 0.0f; + for (int i = 1; i < NUM_SUBDIVISIONS + 1; i++) { + accum += glm::distance(this->operator()(alpha), + this->operator()(alpha + DELTA)); + alpha += DELTA; + _values[i] = accum; + } + + } }; #endif // hifi_CubicHermiteSpline_h diff --git a/tools/unity-avatar-exporter/Assets/README.txt b/tools/unity-avatar-exporter/Assets/README.txt index b81a620406..c84cec2978 100644 --- a/tools/unity-avatar-exporter/Assets/README.txt +++ b/tools/unity-avatar-exporter/Assets/README.txt @@ -2,6 +2,7 @@ High Fidelity, Inc. Avatar Exporter Version 0.2 + Note: It is recommended to use Unity versions between 2017.4.17f1 and 2018.2.12f1 for this Avatar Exporter. To create a new avatar project: From a6ad53e79e74c5cfeb79264431555c0b2ab9198e Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 22 Feb 2019 11:30:26 -0800 Subject: [PATCH 056/566] TEST --- tools/CMakeLists.txt | 2 +- tools/nitpick/CMakeLists.txt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6cda67db2d..ed66ab1ed1 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -20,7 +20,7 @@ endfunction() if (BUILD_TOOLS) # Allow different tools for stable builds - if (RELEASE_TYPE STREQUAL "PRODUCTION") + if (NOT STABLE_BUILD) set(ALL_TOOLS udt-test vhacd-util diff --git a/tools/nitpick/CMakeLists.txt b/tools/nitpick/CMakeLists.txt index e69b16b866..44eace5e70 100644 --- a/tools/nitpick/CMakeLists.txt +++ b/tools/nitpick/CMakeLists.txt @@ -80,7 +80,9 @@ else () add_executable(${TARGET_NAME} ${NITPICK_SRCS} ${QM}) endif () -add_dependencies(${TARGET_NAME} resources) +if (NOT UNIX) + add_dependencies(${TARGET_NAME} resources) +endif() # disable /OPT:REF and /OPT:ICF for the Debug builds # This will prevent the following linker warnings From 9b73c83ebc048a8a2c384332c61d777b5558b247 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 22 Feb 2019 11:50:38 -0800 Subject: [PATCH 057/566] removed merge markers (cherry picked from commit 4286142daac70269de155c99c9bbdb1f951eaff6) --- .../avatars-renderer/src/avatars-renderer/Avatar.h | 3 --- libraries/fbx/src/FBXSerializer.cpp | 14 -------------- 2 files changed, 17 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 1acee7439f..3d25c275b1 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -236,7 +236,6 @@ public: virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } -<<<<<<< HEAD // world-space to avatar-space rigconversion functions /**jsdoc * @function MyAvatar.worldToJointPoint @@ -286,10 +285,8 @@ public: * @returns {Quat} */ Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; -======= virtual glm::vec3 getSpine2SplineOffset() const { return _spine2SplineOffset; } virtual float getSpine2SplineRatio() const { return _spine2SplineRatio; } ->>>>>>> cache the spine2 spline default offset and ratio virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; virtual void setAttachmentData(const QVector& attachmentData) override; diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 30bd527546..9e7f422b40 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1288,20 +1288,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr } joint.inverseBindRotation = joint.inverseDefaultRotation; joint.name = fbxModel.name; -<<<<<<< HEAD -======= - if (hfmModel.hfmToHifiJointNameMapping.contains(hfmModel.hfmToHifiJointNameMapping.key(joint.name))) { - joint.name = hfmModel.hfmToHifiJointNameMapping.key(fbxModel.name); - } - - foreach (const QString& childID, _connectionChildMap.values(modelID)) { - QString type = typeFlags.value(childID); - if (!type.isEmpty()) { - hfmModel.hasSkeletonJoints |= (joint.isSkeletonJoint = type.toLower().contains("Skeleton")); - break; - } - } ->>>>>>> implemented the splineIK in animSplineIK.cpp, todo: disable animinversekinematic.cpp joint.bindTransformFoundInCluster = false; From 6d6cd42adbdf78fc07f2317b90f7b4941c1a5c38 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 22 Feb 2019 12:00:00 -0800 Subject: [PATCH 058/566] fix bound scaling --- libraries/entities/src/EntityItem.cpp | 10 +++++----- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/render-utils/src/CauterizedModel.cpp | 1 + libraries/render-utils/src/Model.cpp | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9f11b3c018..72246f8229 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -266,7 +266,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_HREF, getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription()); APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition()); - APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getUnscaledDimensions()); + APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getScaledDimensions()); APPEND_ENTITY_PROPERTY(PROP_ROTATION, getLocalOrientation()); APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint()); APPEND_ENTITY_PROPERTY(PROP_CREATED, getCreated()); @@ -818,7 +818,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef }; READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, customUpdatePositionFromNetwork); } - READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setUnscaledDimensions); + READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setScaledDimensions); { // See comment above auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value) { if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) { @@ -1315,7 +1315,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription); COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getUnscaledDimensions); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getScaledDimensions); COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getLocalOrientation); COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint); COPY_ENTITY_PROPERTY_TO_PROPERTIES(created, getCreated); @@ -1462,7 +1462,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref); SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setUnscaledDimensions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setScaledDimensions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, setCreated); @@ -1872,7 +1872,7 @@ glm::vec3 EntityItem::getScaledDimensions() const { void EntityItem::setScaledDimensions(const glm::vec3& value) { glm::vec3 parentScale = getSNScale(); - setUnscaledDimensions(value * parentScale); + setUnscaledDimensions(value / parentScale); } void EntityItem::setUnscaledDimensions(const glm::vec3& value) { diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 75e2069471..7575763bf9 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1013,7 +1013,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. When adding an entity, if no dimensions * value is specified then the model is automatically sized to its * {@link Entities.EntityProperties|naturalDimensions}. - * @property {Vec3} modelScale - The scale factor applied to the model's dimensions. + * @property {Vec3} modelScale - The scale factor applied to the model's dimensions. Deprecated. * @property {Color} color=255,255,255 - Currently not used. * @property {string} modelURL="" - The URL of the FBX of OBJ model. Baked FBX models' URLs end in ".baked.fbx".
* @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 81a81c5602..cfb78d6bbc 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -178,6 +178,7 @@ void CauterizedModel::updateClusterMatrices() { } } } + computeMeshPartLocalBounds(); // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b9b294d0e3..02c6562f61 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1385,6 +1385,7 @@ void Model::updateClusterMatrices() { } } } + computeMeshPartLocalBounds(); // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); From a31b09b204ac32d1cccc3906fdca7e9e9224db55 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 22 Feb 2019 13:17:13 -0800 Subject: [PATCH 059/566] handle models with no materials --- libraries/graphics/src/graphics/Material.h | 4 ++++ libraries/render-utils/src/RenderPipelines.cpp | 8 ++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index fdddf3640a..2fce8e1195 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -462,6 +462,9 @@ public: void setTexturesLoading(bool value) { _texturesLoading = value; } bool areTexturesLoading() const { return _texturesLoading; } + bool isInitialized() const { return _initialized; } + void setInitialized() { _initialized = true; } + int getTextureCount() const { calculateMaterialInfo(); return _textureCount; } size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } @@ -471,6 +474,7 @@ private: gpu::TextureTablePointer _textureTable { std::make_shared() }; bool _needsUpdate { false }; bool _texturesLoading { false }; + bool _initialized { false }; mutable size_t _textureSize { 0 }; mutable int _textureCount { 0 }; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 6f6f2ab856..67c3b526b9 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -382,11 +382,6 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Bat void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial) { auto& schemaBuffer = multiMaterial.getSchemaBuffer(); - if (multiMaterial.size() == 0) { - schemaBuffer.edit() = graphics::MultiMaterial::Schema(); - return; - } - auto& drawMaterialTextures = multiMaterial.getTextureTable(); multiMaterial.setTexturesLoading(false); @@ -732,6 +727,7 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial schema._key = (uint32_t)schemaKey._flags.to_ulong(); schemaBuffer.edit() = schema; multiMaterial.setNeedsUpdate(false); + multiMaterial.setInitialized(); } void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures) { @@ -739,7 +735,7 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu: return; } - if (multiMaterial.needsUpdate() || multiMaterial.areTexturesLoading()) { + if (!multiMaterial.isInitialized() || multiMaterial.needsUpdate() || multiMaterial.areTexturesLoading()) { updateMultiMaterial(multiMaterial); } From dbc3ae3793480bf0021341b33863914fffc98f03 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 22 Feb 2019 14:18:59 -0800 Subject: [PATCH 060/566] hmmm not working --- .../entities-renderer/src/RenderableShapeEntityItem.cpp | 4 ++-- libraries/graphics/src/graphics/Material.h | 7 ++----- libraries/render-utils/src/MeshPartPayload.cpp | 6 +++--- libraries/render-utils/src/RenderPipelines.cpp | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index d42a766faa..5f3f4c9e81 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -53,7 +53,7 @@ bool ShapeEntityRenderer::needsRenderUpdate() const { } auto mat = _materials.find("0"); - if (mat != _materials.end() && (mat->second.needsUpdate() || mat->second.areTexturesLoading())) { + if (mat != _materials.end() && mat->second.shouldUpdate()) { return true; } @@ -188,7 +188,7 @@ bool ShapeEntityRenderer::useMaterialPipeline(const graphics::MultiMaterial& mat ShapeKey ShapeEntityRenderer::getShapeKey() { auto mat = _materials.find("0"); - if (mat != _materials.end() && (mat->second.needsUpdate() || mat->second.areTexturesLoading())) { + if (mat != _materials.end() && mat->second.shouldUpdate()) { RenderPipelines::updateMultiMaterial(mat->second); } diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 2fce8e1195..d24e906f98 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -456,15 +456,12 @@ public: graphics::MaterialKey getMaterialKey() const { return graphics::MaterialKey(_schemaBuffer.get()._key); } const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; } - bool needsUpdate() const { return _needsUpdate; } void setNeedsUpdate(bool needsUpdate) { _needsUpdate = needsUpdate; } - void setTexturesLoading(bool value) { _texturesLoading = value; } - bool areTexturesLoading() const { return _texturesLoading; } - - bool isInitialized() const { return _initialized; } void setInitialized() { _initialized = true; } + bool shouldUpdate() const { return !_initialized || _needsUpdate || _texturesLoading; } + int getTextureCount() const { calculateMaterialInfo(); return _textureCount; } size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 6409cdd231..b1104b8aad 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -83,7 +83,7 @@ void MeshPartPayload::updateKey(const render::ItemKey& key) { ItemKey::Builder builder(key); builder.withTypeShape(); - if (_drawMaterials.needsUpdate() || _drawMaterials.areTexturesLoading()) { + if (_drawMaterials.shouldUpdate()) { RenderPipelines::updateMultiMaterial(_drawMaterials); } @@ -329,7 +329,7 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { builder.withDeformed(); } - if (_drawMaterials.needsUpdate() || _drawMaterials.areTexturesLoading()) { + if (_drawMaterials.shouldUpdate()) { RenderPipelines::updateMultiMaterial(_drawMaterials); } @@ -347,7 +347,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode pr return; } - if (_drawMaterials.needsUpdate() || _drawMaterials.areTexturesLoading()) { + if (_drawMaterials.shouldUpdate()) { RenderPipelines::updateMultiMaterial(_drawMaterials); } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 67c3b526b9..83216ddf84 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -735,7 +735,7 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu: return; } - if (!multiMaterial.isInitialized() || multiMaterial.needsUpdate() || multiMaterial.areTexturesLoading()) { + if (multiMaterial.shouldUpdate()) { updateMultiMaterial(multiMaterial); } From 081e62a64758ff2187edad65c73ff32d9d695676 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 22 Feb 2019 14:26:15 -0800 Subject: [PATCH 061/566] fix parent loop crash --- libraries/shared/src/SpatiallyNestable.cpp | 9 +++++++-- libraries/shared/src/SpatiallyNestable.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 19fafdccf4..8d2e5ea45b 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -1420,11 +1420,16 @@ QUuid SpatiallyNestable::getEditSenderID() { return editSenderID; } -void SpatiallyNestable::bumpAncestorChainRenderableVersion() const { +void SpatiallyNestable::bumpAncestorChainRenderableVersion(int depth) const { + if (depth > MAX_PARENTING_CHAIN_SIZE) { + breakParentingLoop(); + return; + } + _ancestorChainRenderableVersion++; bool success = false; auto parent = getParentPointer(success); if (success && parent) { - parent->bumpAncestorChainRenderableVersion(); + parent->bumpAncestorChainRenderableVersion(depth + 1); } } \ No newline at end of file diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 495c941c07..a802a25e89 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -221,7 +221,7 @@ public: bool hasGrabs(); virtual QUuid getEditSenderID(); - void bumpAncestorChainRenderableVersion() const; + void bumpAncestorChainRenderableVersion(int depth = 0) const; protected: QUuid _id; From a87e49bb23ea6c23f979468f624bfe3ec112cb18 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 22 Feb 2019 15:01:30 -0800 Subject: [PATCH 062/566] start in quest dev --- interface/src/Application.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a611738445..3864ba30c0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2414,6 +2414,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo AndroidHelper::instance().notifyLoadComplete(); #endif pauseUntilLoginDetermined(); + +#if defined(Q_OS_ANDROID) + const QString QUEST_DEV = "hifi://quest-dev"; + DependencyManager::get()->handleLookupString(QUEST_DEV); +#endif } void Application::updateVerboseLogging() { From 7cf79c11081209537e74ee123daa42bee963804c Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 22 Feb 2019 15:06:42 -0800 Subject: [PATCH 063/566] Now WITH installation of nitpick. --- tools/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index ed66ab1ed1..b9ae635a4f 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -20,7 +20,7 @@ endfunction() if (BUILD_TOOLS) # Allow different tools for stable builds - if (NOT STABLE_BUILD) + if (STABLE_BUILD) set(ALL_TOOLS udt-test vhacd-util From 5bf994626ca14723a9cd6cc3104052da48b3c07b Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Fri, 22 Feb 2019 16:28:36 -0800 Subject: [PATCH 064/566] scaling culling projection matrix by 1.5 to help reduce teh ugly effect of stuff getting cut off too early --- .../oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp b/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp index bc8e1a5113..3b8bf50724 100644 --- a/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp +++ b/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp @@ -120,7 +120,10 @@ QRectF OculusMobileDisplayPlugin::getPlayAreaRect() { } glm::mat4 OculusMobileDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& baseProjection) const { + qDebug()<< "QQQ_ " << __FUNCTION__; + glm::mat4 result = baseProjection; + VrHandler::withOvrMobile([&](ovrMobile* session){ auto trackingState = vrapi_GetPredictedTracking2(session, 0.0); result = ovr::Fov{ trackingState.Eye[eye].ProjectionMatrix }.withZ(baseProjection); @@ -136,9 +139,13 @@ glm::mat4 OculusMobileDisplayPlugin::getCullingProjection(const glm::mat4& baseP for (size_t i = 0; i < 2; ++i) { fovs[i].extract(trackingState.Eye[i].ProjectionMatrix); } + fovs[0].extend(fovs[1]); - return fovs[0].withZ(baseProjection); + result= glm::scale( fovs[0].withZ(baseProjection),glm::vec3(1.5f)); }); + + + return result; } From 5c1e5e0c460f3fc2ce2771bac33d52a7a433b22e Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Fri, 22 Feb 2019 16:30:17 -0800 Subject: [PATCH 065/566] cleanup --- .../oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp b/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp index 3b8bf50724..cf82d7aba5 100644 --- a/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp +++ b/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp @@ -120,8 +120,6 @@ QRectF OculusMobileDisplayPlugin::getPlayAreaRect() { } glm::mat4 OculusMobileDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& baseProjection) const { - qDebug()<< "QQQ_ " << __FUNCTION__; - glm::mat4 result = baseProjection; VrHandler::withOvrMobile([&](ovrMobile* session){ @@ -142,10 +140,9 @@ glm::mat4 OculusMobileDisplayPlugin::getCullingProjection(const glm::mat4& baseP fovs[0].extend(fovs[1]); result= glm::scale( fovs[0].withZ(baseProjection),glm::vec3(1.5f)); + return result; }); - - return result; } From 30b6b7f21ba7062b274e32a0b2528ac8b36600ea Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Fri, 22 Feb 2019 16:30:36 -0800 Subject: [PATCH 066/566] let's try that again --- libraries/shared/src/SpatiallyNestable.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 8d2e5ea45b..6d8140a95d 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -1422,7 +1422,7 @@ QUuid SpatiallyNestable::getEditSenderID() { void SpatiallyNestable::bumpAncestorChainRenderableVersion(int depth) const { if (depth > MAX_PARENTING_CHAIN_SIZE) { - breakParentingLoop(); + // can't break the parent chain here, because it will call setParentID, which calls this return; } @@ -1432,4 +1432,4 @@ void SpatiallyNestable::bumpAncestorChainRenderableVersion(int depth) const { if (success && parent) { parent->bumpAncestorChainRenderableVersion(depth + 1); } -} \ No newline at end of file +} From 37720e9daafc252d75379f0f8d68588f71973ba2 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 22 Feb 2019 16:53:03 -0800 Subject: [PATCH 067/566] fix nametag rotation --- interface/src/ui/overlays/Overlays.cpp | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 660220c731..62a6b88fc0 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -559,6 +559,42 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove SET_OVERLAY_PROP_DEFAULT(textures, PathUtils::resourcesUrl() + "images/whitePixel.png"); } + { // Overlays did this conversion for rotation + auto iter = overlayProps.find("rotation"); + if (iter != overlayProps.end() && !overlayProps.contains("localRotation")) { + QUuid parentID; + { + auto iter = overlayProps.find("parentID"); + if (iter != overlayProps.end()) { + parentID = iter.value().toUuid(); + } else if (!add) { + EntityPropertyFlags desiredProperties; + desiredProperties += PROP_PARENT_ID; + parentID = DependencyManager::get()->getEntityProperties(id, desiredProperties).getParentID(); + } + } + + int parentJointIndex = -1; + { + auto iter = overlayProps.find("parentJointIndex"); + if (iter != overlayProps.end()) { + parentJointIndex = iter.value().toInt(); + } else if (!add) { + EntityPropertyFlags desiredProperties; + desiredProperties += PROP_PARENT_JOINT_INDEX; + parentJointIndex = DependencyManager::get()->getEntityProperties(id, desiredProperties).getParentJointIndex(); + } + } + + glm::quat rotation = quatFromVariant(iter.value()); + bool success = false; + glm::quat localRotation = SpatiallyNestable::worldToLocal(rotation, parentID, parentJointIndex, false, success); + if (success) { + overlayProps["rotation"] = quatToVariant(localRotation); + } + } + } + if (type == "Text" || type == "Image" || type == "Grid" || type == "Web") { glm::quat originalRotation = ENTITY_ITEM_DEFAULT_ROTATION; { From dab0df1113ffe663f93ff20246353b6bf2408cfe Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 22 Feb 2019 18:03:23 -0800 Subject: [PATCH 068/566] Trying to fix the damn gamma --- .../display-plugins/OpenGLDisplayPlugin.cpp | 5 ++++- .../src/display-plugins/SrgbToLinear.slf | 3 ++- .../src/OculusMobileDisplayPlugin.cpp | 13 ++++++++++-- .../utilities/render/deferredLighting.qml | 21 +++++++++++++++++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 20fc9a2290..28de13d8c2 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -516,6 +516,7 @@ void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::Textur #ifndef USE_GLES batch.setPipeline(_presentPipeline); #else + //batch.setPipeline(_presentPipeline); batch.setPipeline(_simplePipeline); #endif batch.draw(gpu::TRIANGLE_STRIP, 4); @@ -630,7 +631,8 @@ void OpenGLDisplayPlugin::compositeScene() { batch.setStateScissorRect(ivec4(uvec2(), _compositeFramebuffer->getSize())); batch.resetViewTransform(); batch.setProjectionTransform(mat4()); - batch.setPipeline(_simplePipeline); + // batch.setPipeline(_simplePipeline); + batch.setPipeline(_presentPipeline); batch.setResourceTexture(0, _currentFrame->framebuffer->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); }); @@ -885,6 +887,7 @@ void OpenGLDisplayPlugin::updateCompositeFramebuffer() { auto renderSize = glm::uvec2(getRecommendedRenderSize()); if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) { _compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y)); + // _compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_SRGBA_32, renderSize.x, renderSize.y)); } } diff --git a/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf b/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf index 8b324c81a5..428ec821a6 100644 --- a/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf +++ b/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf @@ -18,5 +18,6 @@ vec3 colorToLinearRGB(vec3 srgb) { void main(void) { outFragColor.a = 1.0; - outFragColor.rgb = colorToLinearRGB(texture(colorMap, varTexCoord0).rgb); + // outFragColor.rgb = colorToLinearRGB(texture(colorMap, varTexCoord0).rgb); + outFragColor.rgb = pow(texture(colorMap, varTexCoord0).rgb, vec3(1.0 / 2.2)); } diff --git a/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp b/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp index bc8e1a5113..ea1a81c4ae 100644 --- a/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp +++ b/libraries/oculusMobilePlugin/src/OculusMobileDisplayPlugin.cpp @@ -6,6 +6,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OculusMobileDisplayPlugin.h" +#include "../../oculusMobile/src/ovr/Helpers.h" #include #include @@ -58,7 +59,7 @@ void OculusMobileDisplayPlugin::deinit() { bool OculusMobileDisplayPlugin::internalActivate() { _renderTargetSize = { 1024, 512 }; - _cullingProjection = ovr::toGlm(ovrMatrix4f_CreateProjectionFov(90.0f, 90.0f, 0.0f, 0.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); + _cullingProjection = ovr::toGlm(ovrMatrix4f_CreateProjectionFov(90.0f, 90.0f, 90.0f, 90.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); withOvrJava([&](const ovrJava* java){ @@ -130,6 +131,7 @@ glm::mat4 OculusMobileDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& glm::mat4 OculusMobileDisplayPlugin::getCullingProjection(const glm::mat4& baseProjection) const { glm::mat4 result = baseProjection; + VrHandler::withOvrMobile([&](ovrMobile* session){ auto trackingState = vrapi_GetPredictedTracking2(session, 0.0); ovr::Fov fovs[2]; @@ -137,7 +139,14 @@ glm::mat4 OculusMobileDisplayPlugin::getCullingProjection(const glm::mat4& baseP fovs[i].extract(trackingState.Eye[i].ProjectionMatrix); } fovs[0].extend(fovs[1]); - return fovs[0].withZ(baseProjection); + float horizontalMargin = 1.1f; + float verticalMargin = 1.5f; + fovs[0].leftRightUpDown[0] *= horizontalMargin; + fovs[0].leftRightUpDown[1] *= horizontalMargin; + fovs[0].leftRightUpDown[2] *= verticalMargin; + fovs[0].leftRightUpDown[3] *= verticalMargin; + + return fovs[0].withZ(baseProjection); }); return result; } diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index f5c0b8c5da..d147585212 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -148,6 +148,27 @@ Rectangle { } } Separator {} + Column { + anchors.left: parent.left + anchors.right: parent.right + spacing: 5 + Repeater { + model: [ "MSAA:PrepareFramebuffer:numSamples:4:1" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: true + config: render.mainViewTask.getConfig(modelData.split(":")[1]) + property: modelData.split(":")[2] + max: modelData.split(":")[3] + min: modelData.split(":")[4] + + anchors.left: parent.left + anchors.right: parent.right + } + } + } + Separator {} Item { height: childrenRect.height From 16bc667b95860b89f20e25494582cbf18fe9bdc0 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 22 Feb 2019 18:17:30 -0800 Subject: [PATCH 069/566] Looks like serialization order must be same a flag enum order!? Also resuscitate EntityItem debug dumps. --- assignment-client/src/avatars/AvatarMixer.cpp | 62 ++++++++++++++++++- assignment-client/src/avatars/AvatarMixer.h | 8 +++ .../src/avatars/AvatarMixerClientData.cpp | 54 +++++++++++++++- .../src/avatars/AvatarMixerClientData.h | 2 +- .../src/avatars/AvatarMixerSlave.h | 4 ++ assignment-client/src/octree/OctreeServer.cpp | 3 +- libraries/entities/src/EntityItem.cpp | 13 ++-- libraries/entities/src/EntityItem.h | 2 +- .../entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 20 +++++- libraries/entities/src/ZoneEntityItem.h | 2 + 11 files changed, 156 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 500772c1b5..f352e02afa 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,8 @@ #include #include #include +#include "../AssignmentDynamicFactory.h" +#include "../entities/AssignmentParentFinder.h" const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer"; @@ -42,6 +45,9 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : ThreadedAssignment(message), _slavePool(&_slaveSharedData) { + DependencyManager::registerInheritance(); + DependencyManager::set(); + // make sure we hear about node kills so we can tell the other nodes connect(DependencyManager::get().data(), &NodeList::nodeKilled, this, &AvatarMixer::handleAvatarKilled); @@ -56,6 +62,8 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); packetReceiver.registerListener(PacketType::SetAvatarTraits, this, "queueIncomingPacket"); packetReceiver.registerListener(PacketType::BulkAvatarTraitsAck, this, "queueIncomingPacket"); + packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, + this, "handleOctreePacket"); packetReceiver.registerListenerForTypes({ PacketType::ReplicatedAvatarIdentity, @@ -227,6 +235,10 @@ void AvatarMixer::start() { int lockWait, nodeTransform, functor; + { + _entityViewer.queryOctree(); + } + // Allow nodes to process any pending/queued packets across our worker threads { auto start = usecTimestampNow(); @@ -847,13 +859,15 @@ AvatarMixerClientData* AvatarMixer::getOrCreateClientData(SharedNodePointer node void AvatarMixer::domainSettingsRequestComplete() { auto nodeList = DependencyManager::get(); nodeList->addSetOfNodeTypesToNodeInterestSet({ - NodeType::Agent, NodeType::EntityScriptServer, + NodeType::Agent, NodeType::EntityScriptServer, NodeType::EntityServer, NodeType::UpstreamAvatarMixer, NodeType::DownstreamAvatarMixer }); // parse the settings to pull out the values we need parseDomainServerSettings(nodeList->getDomainHandler().getSettingsObject()); + setupEntityQuery(); + // start our tight loop... start(); } @@ -941,3 +955,49 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) { qCDebug(avatars) << "Avatars other than" << _slaveSharedData.skeletonURLWhitelist << "will be replaced by" << (_slaveSharedData.skeletonReplacementURL.isEmpty() ? "default" : _slaveSharedData.skeletonReplacementURL.toString()); } } + +void AvatarMixer::setupEntityQuery() { + static char queryJsonString[] = R"({"avatarPriority": true})"; + + _entityViewer.init(); + DependencyManager::registerInheritance(); + DependencyManager::set(_entityViewer.getTree()); + _slaveSharedData.entityTree = _entityViewer.getTree(); + + QJsonParseError jsonParseError; + const QJsonDocument priorityZoneQuery(QJsonDocument::fromJson(queryJsonString, &jsonParseError)); + if (jsonParseError.error != QJsonParseError::NoError) { + qCDebug(avatars) << "Error parsing:" << queryJsonString << " - " << jsonParseError.errorString(); + return; + } + _entityViewer.getOctreeQuery().setJSONParameters(priorityZoneQuery.object()); + +} + +void AvatarMixer::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { + PacketType packetType = message->getType(); + + switch (packetType) { + case PacketType::OctreeStats: + break; + + case PacketType::EntityData: + _entityViewer.processDatagram(*message, senderNode); + break; + + case PacketType::EntityErase: + _entityViewer.processEraseMessage(*message, senderNode); + break; + + default: + qCDebug(avatars) << "Unexpected packet type:" << packetType; + break; + } +} + +void AvatarMixer::aboutToFinish() { + DependencyManager::destroy(); + DependencyManager::destroy(); + + ThreadedAssignment::aboutToFinish(); +} diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 764656a2d5..6d82172995 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -19,6 +19,7 @@ #include #include +#include "../entities/EntityTreeHeadlessViewer.h" #include "AvatarMixerClientData.h" #include "AvatarMixerSlavePool.h" @@ -28,6 +29,7 @@ class AvatarMixer : public ThreadedAssignment { Q_OBJECT public: AvatarMixer(ReceivedMessage& message); + virtual void aboutToFinish() override; static bool shouldReplicateTo(const Node& from, const Node& to) { return to.getType() == NodeType::DownstreamAvatarMixer && @@ -56,6 +58,7 @@ private slots: void handleReplicatedBulkAvatarPacket(QSharedPointer message); void domainSettingsRequestComplete(); void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID); + void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); void start(); private: @@ -70,8 +73,13 @@ private: void optionallyReplicatePacket(ReceivedMessage& message, const Node& node); + void setupEntityQuery(); + p_high_resolution_clock::time_point _lastFrameTimestamp; + // Attach to entity tree for avatar-priority zone info. + EntityTreeHeadlessViewer _entityViewer; + // FIXME - new throttling - use these values somehow float _trailingMixRatio { 0.0f }; float _throttlingRatio { 0.0f }; diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index b7d2f5cdf8..9edbae12d8 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -16,6 +16,8 @@ #include #include +#include +#include #include "AvatarMixerSlave.h" @@ -62,7 +64,7 @@ int AvatarMixerClientData::processPackets(const SlaveSharedData& slaveSharedData switch (packet->getType()) { case PacketType::AvatarData: - parseData(*packet); + parseData(*packet, slaveSharedData); break; case PacketType::SetAvatarTraits: processSetTraitsMessage(*packet, slaveSharedData, *node); @@ -80,7 +82,38 @@ int AvatarMixerClientData::processPackets(const SlaveSharedData& slaveSharedData return packetsProcessed; } -int AvatarMixerClientData::parseData(ReceivedMessage& message) { +namespace { + using std::static_pointer_cast; + + // Operator to find if a point is within an avatar-priority (hero) Zone Entity. + struct FindPriorityZone { + glm::vec3 position; + bool isInPriorityZone { false }; + static bool operation(const OctreeElementPointer& element, void* extraData) { + auto findPriorityZone = static_cast(extraData); + if (element->getAACube().contains(findPriorityZone->position)) { + const EntityTreeElementPointer entityTreeElement = static_pointer_cast(element); + entityTreeElement->forEachEntity([&findPriorityZone](EntityItemPointer item) { + if (item->getType() == EntityTypes::Zone + && item->contains(findPriorityZone->position) + && static_pointer_cast(item)->getAvatarPriority()) { + findPriorityZone->isInPriorityZone = true; + } + }); + if (findPriorityZone->isInPriorityZone) { + return false; // For now, stop at first hit. + } else { + return true; + } + } else { // Position isn't within this subspace, so end recursion. + return false; + } + } + }; + +} // Close anonymous namespace. + +int AvatarMixerClientData::parseData(ReceivedMessage& message, const SlaveSharedData& slaveSharedData) { // pull the sequence number from the data first uint16_t sequenceNumber; @@ -90,9 +123,24 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message) { incrementNumOutOfOrderSends(); } _lastReceivedSequenceNumber = sequenceNumber; + glm::vec3 oldPosition = getPosition(); // compute the offset to the data payload - return _avatar->parseDataFromBuffer(message.readWithoutCopy(message.getBytesLeftToRead())); + if (!_avatar->parseDataFromBuffer(message.readWithoutCopy(message.getBytesLeftToRead()))) { + return false; + } + + auto newPosition = getPosition(); + if (newPosition != oldPosition) { + EntityTree& entityTree = *slaveSharedData.entityTree; + FindPriorityZone findPriorityZone { newPosition, false } ; + entityTree.recurseTreeWithOperation(&FindPriorityZone::operation, &findPriorityZone); + if (findPriorityZone.isInPriorityZone) { + // Tag avatar as hero ... + } + } + + return true; } void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message, diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 843f19cf22..45d508088c 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -45,7 +45,7 @@ public: using HRCTime = p_high_resolution_clock::time_point; using PerNodeTraitVersions = std::unordered_map; - int parseData(ReceivedMessage& message) override; + int parseData(ReceivedMessage& message, const SlaveSharedData& SlaveSharedData); AvatarData& getAvatar() { return *_avatar; } const AvatarData& getAvatar() const { return *_avatar; } const AvatarData* getConstAvatarData() const { return _avatar.get(); } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.h b/assignment-client/src/avatars/AvatarMixerSlave.h index 91bb02fd55..28d99748fa 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.h +++ b/assignment-client/src/avatars/AvatarMixerSlave.h @@ -90,9 +90,13 @@ public: } }; +class EntityTree; +using EntityTreePointer = std::shared_ptr; + struct SlaveSharedData { QStringList skeletonURLWhitelist; QUrl skeletonReplacementURL; + EntityTreePointer entityTree; }; class AvatarMixerSlave { diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index e993bea358..477d3dd612 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1203,7 +1203,8 @@ void OctreeServer::beginRunning() { auto nodeList = DependencyManager::get(); // we need to ask the DS about agents so we can ping/reply with them - nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::EntityScriptServer }); + nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::EntityScriptServer, + NodeType::AvatarMixer }); beforeRun(); // after payload has been processed diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5c423b2fe5..25e5893078 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -41,6 +41,7 @@ #include "EntitySimulation.h" #include "EntityDynamicFactoryInterface.h" +//#define WANT_DEBUG Q_DECLARE_METATYPE(EntityItemPointer); int entityItemPointernMetaTypeId = qRegisterMetaType(); @@ -499,6 +500,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } #ifdef WANT_DEBUG + { quint64 lastEdited = getLastEdited(); float editedAgo = getEditedAgo(); QString agoAsString = formatSecondsElapsed(editedAgo); @@ -512,6 +514,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qCDebug(entities) << " age=" << getAge() << "seconds - " << ageAsString; qCDebug(entities) << " lastEdited =" << lastEdited; qCDebug(entities) << " ago=" << editedAgo << "seconds - " << agoAsString; + } #endif quint64 lastEditedFromBuffer = 0; @@ -1096,7 +1099,7 @@ void EntityItem::simulate(const quint64& now) { qCDebug(entities) << " hasGravity=" << hasGravity(); qCDebug(entities) << " hasAcceleration=" << hasAcceleration(); qCDebug(entities) << " hasAngularVelocity=" << hasAngularVelocity(); - qCDebug(entities) << " getAngularVelocity=" << getAngularVelocity(); + qCDebug(entities) << " getAngularVelocity=" << getLocalAngularVelocity(); qCDebug(entities) << " isMortal=" << isMortal(); qCDebug(entities) << " getAge()=" << getAge(); qCDebug(entities) << " getLifetime()=" << getLifetime(); @@ -1108,12 +1111,12 @@ void EntityItem::simulate(const quint64& now) { qCDebug(entities) << " hasGravity=" << hasGravity(); qCDebug(entities) << " hasAcceleration=" << hasAcceleration(); qCDebug(entities) << " hasAngularVelocity=" << hasAngularVelocity(); - qCDebug(entities) << " getAngularVelocity=" << getAngularVelocity(); + qCDebug(entities) << " getAngularVelocity=" << getLocalAngularVelocity(); } if (hasAngularVelocity()) { qCDebug(entities) << " CHANGING...="; qCDebug(entities) << " hasAngularVelocity=" << hasAngularVelocity(); - qCDebug(entities) << " getAngularVelocity=" << getAngularVelocity(); + qCDebug(entities) << " getAngularVelocity=" << getLocalAngularVelocity(); } if (isMortal()) { qCDebug(entities) << " MORTAL...="; @@ -2649,13 +2652,13 @@ bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const { // ALL entity properties. Some work will need to be done to the property system so that it can be more flexible // (to grab the value and default value of a property given the string representation of that property, for example) - // currently the only property filter we handle is '+' for serverScripts + // currently the only property filter we handle in EntityItem is '+' for serverScripts // which means that we only handle a filtered query asking for entities where the serverScripts property is non-default static const QString SERVER_SCRIPTS_PROPERTY = "serverScripts"; foreach(const auto& property, jsonFilters.keys()) { - if (property == SERVER_SCRIPTS_PROPERTY && jsonFilters[property] == EntityQueryFilterSymbol::NonDefault) { + if (property == SERVER_SCRIPTS_PROPERTY && jsonFilters[property] == EntityQueryFilterSymbol::NonDefault) { // check if this entity has a non-default value for serverScripts if (_serverScripts != ENTITY_ITEM_DEFAULT_SERVER_SCRIPTS) { return true; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ec7ad78313..87dca3f314 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -516,7 +516,7 @@ public: QUuid getLastEditedBy() const { return _lastEditedBy; } void setLastEditedBy(QUuid value) { _lastEditedBy = value; } - bool matchesJSONFilters(const QJsonObject& jsonFilters) const; + virtual bool matchesJSONFilters(const QJsonObject& jsonFilters) const; virtual bool getMeshes(MeshProxyList& result) { return true; } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 103f5dbab7..96160ebd93 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -3178,13 +3178,13 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, properties.getFlyingAllowed()); APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, properties.getGhostingAllowed()); APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, properties.getFilterURL()); - APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, properties.getAvatarPriority()); APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)properties.getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)properties.getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)properties.getSkyboxMode()); APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)properties.getHazeMode()); APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode()); + APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, properties.getAvatarPriority()); } if (properties.getType() == EntityTypes::PolyVox) { diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 13c7273d94..83619caa3c 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -112,13 +112,13 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(avatarPriority, setAvatarPriority); SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightMode, setKeyLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(skyboxMode, setSkyboxMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(avatarPriority, setAvatarPriority); somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged || _stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged; @@ -188,13 +188,13 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed); READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed); READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL); - READ_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, bool, setAvatarPriority); READ_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode); READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode); + READ_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, bool, setAvatarPriority); return bytesRead; } @@ -254,13 +254,13 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed()); APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed()); APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL()); - APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, getAvatarPriority()); APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)getSkyboxMode()); APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode()); APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode()); + APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, getAvatarPriority()); } void ZoneEntityItem::debugDump() const { @@ -274,6 +274,7 @@ void ZoneEntityItem::debugDump() const { qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeAsString(_ambientLightMode); qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeAsString(_skyboxMode); qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeAsString(_bloomMode); + qCDebug(entities) << " _avatarPriority:" << getAvatarPriority(); _keyLightProperties.debugDump(); _ambientLightProperties.debugDump(); @@ -469,3 +470,16 @@ void ZoneEntityItem::fetchCollisionGeometryResource() { _shapeResource = DependencyManager::get()->getCollisionGeometryResource(hullURL); } } + +bool ZoneEntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const { + // currently the only property filter we handle in ZoneEntityItem is value of avatarPriority + + static const QString AVATAR_PRIORITY_PROPERTY = "avatarPriority"; + + if (jsonFilters.contains(AVATAR_PRIORITY_PROPERTY)) { + return (jsonFilters[AVATAR_PRIORITY_PROPERTY].toBool() == _avatarPriority); + } + + // Chain to base: + return EntityItem::matchesJSONFilters(jsonFilters); +} diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 20bab7c710..a3e668b6f6 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -66,6 +66,8 @@ public: QString getCompoundShapeURL() const; virtual void setCompoundShapeURL(const QString& url); + virtual bool matchesJSONFilters(const QJsonObject& jsonFilters) const override; + KeyLightPropertyGroup getKeyLightProperties() const { return resultWithReadLock([&] { return _keyLightProperties; }); } AmbientLightPropertyGroup getAmbientLightProperties() const { return resultWithReadLock([&] { return _ambientLightProperties; }); } From d040803391511f864ee5f116e1e082f92682f168 Mon Sep 17 00:00:00 2001 From: Clement Date: Fri, 22 Feb 2019 18:07:26 -0800 Subject: [PATCH 070/566] Delete old nodes with identical socket --- libraries/networking/src/LimitedNodeList.cpp | 176 +++++++++---------- 1 file changed, 84 insertions(+), 92 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 8b9e37569c..eaa02f059e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -645,103 +645,95 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, Node::LocalID localID, bool isReplicated, bool isUpstream, const QUuid& connectionSecret, const NodePermissions& permissions) { - QReadLocker readLocker(&_nodeMutex); - NodeHash::const_iterator it = _nodeHash.find(uuid); + { + QReadLocker readLocker(&_nodeMutex); + NodeHash::const_iterator it = _nodeHash.find(uuid); - if (it != _nodeHash.end()) { - SharedNodePointer& matchingNode = it->second; + if (it != _nodeHash.end()) { + SharedNodePointer& matchingNode = it->second; - matchingNode->setPublicSocket(publicSocket); - matchingNode->setLocalSocket(localSocket); - matchingNode->setPermissions(permissions); - matchingNode->setConnectionSecret(connectionSecret); - matchingNode->setIsReplicated(isReplicated); - matchingNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType)); - matchingNode->setLocalID(localID); + matchingNode->setPublicSocket(publicSocket); + matchingNode->setLocalSocket(localSocket); + matchingNode->setPermissions(permissions); + matchingNode->setConnectionSecret(connectionSecret); + matchingNode->setIsReplicated(isReplicated); + matchingNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType)); + matchingNode->setLocalID(localID); - return matchingNode; - } else { - auto it = _connectionIDs.find(uuid); - if (it == _connectionIDs.end()) { - _connectionIDs[uuid] = INITIAL_CONNECTION_ID; + return matchingNode; } - - // we didn't have this node, so add them - Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket); - newNode->setIsReplicated(isReplicated); - newNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType)); - newNode->setConnectionSecret(connectionSecret); - newNode->setPermissions(permissions); - newNode->setLocalID(localID); - - // move the newly constructed node to the LNL thread - newNode->moveToThread(thread()); - - if (nodeType == NodeType::AudioMixer) { - LimitedNodeList::flagTimeForConnectionStep(LimitedNodeList::AddedAudioMixer); - } - - SharedNodePointer newNodePointer(newNode, &QObject::deleteLater); - - // if this is a solo node type, we assume that the DS has replaced its assignment and we should kill the previous node - if (SOLO_NODE_TYPES.count(newNode->getType())) { - // while we still have the read lock, see if there is a previous solo node we'll need to remove - auto previousSoloIt = std::find_if(_nodeHash.cbegin(), _nodeHash.cend(), [newNode](const UUIDNodePair& nodePair){ - return nodePair.second->getType() == newNode->getType(); - }); - - if (previousSoloIt != _nodeHash.cend()) { - // we have a previous solo node, switch to a write lock so we can remove it - readLocker.unlock(); - - QWriteLocker writeLocker(&_nodeMutex); - - auto oldSoloNode = previousSoloIt->second; - - _localIDMap.unsafe_erase(oldSoloNode->getLocalID()); - _nodeHash.unsafe_erase(previousSoloIt); - handleNodeKill(oldSoloNode); - - // convert the current lock back to a read lock for insertion of new node - writeLocker.unlock(); - readLocker.relock(); - } - } - - // insert the new node and release our read lock -#if defined(Q_OS_ANDROID) || (defined(__clang__) && defined(Q_OS_LINUX)) - _nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer)); - _localIDMap.insert(std::pair(localID, newNodePointer)); -#else - _nodeHash.emplace(newNode->getUUID(), newNodePointer); - _localIDMap.emplace(localID, newNodePointer); -#endif - readLocker.unlock(); - - qCDebug(networking) << "Added" << *newNode; - - auto weakPtr = newNodePointer.toWeakRef(); // We don't want the lambdas to hold a strong ref - - emit nodeAdded(newNodePointer); - if (newNodePointer->getActiveSocket()) { - emit nodeActivated(newNodePointer); - } else { - connect(newNodePointer.data(), &NetworkPeer::socketActivated, this, [this, weakPtr] { - auto sharedPtr = weakPtr.lock(); - if (sharedPtr) { - emit nodeActivated(sharedPtr); - disconnect(sharedPtr.data(), &NetworkPeer::socketActivated, this, 0); - } - }); - } - - // Signal when a socket changes, so we can start the hole punch over. - connect(newNodePointer.data(), &NetworkPeer::socketUpdated, this, [this, weakPtr] { - emit nodeSocketUpdated(weakPtr); - }); - - return newNodePointer; } + + auto removeOldNode = [&](auto node) { + if (node) { + QWriteLocker writeLocker(&_nodeMutex); + _localIDMap.unsafe_erase(node->getLocalID()); + _nodeHash.unsafe_erase(node->getUUID()); + handleNodeKill(node); + } + }; + + // if this is a solo node type, we assume that the DS has replaced its assignment and we should kill the previous node + if (SOLO_NODE_TYPES.count(nodeType)) { + removeOldNode(soloNodeOfType(nodeType)); + } + // If there is a new node with the same socket, this is a reconnection, kill the old node + removeOldNode(findNodeWithAddr(publicSocket)); + removeOldNode(findNodeWithAddr(localSocket)); + + auto it = _connectionIDs.find(uuid); + if (it == _connectionIDs.end()) { + _connectionIDs[uuid] = INITIAL_CONNECTION_ID; + } + + // we didn't have this node, so add them + Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket); + newNode->setIsReplicated(isReplicated); + newNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType)); + newNode->setConnectionSecret(connectionSecret); + newNode->setPermissions(permissions); + newNode->setLocalID(localID); + + // move the newly constructed node to the LNL thread + newNode->moveToThread(thread()); + + if (nodeType == NodeType::AudioMixer) { + LimitedNodeList::flagTimeForConnectionStep(LimitedNodeList::AddedAudioMixer); + } + + SharedNodePointer newNodePointer(newNode, &QObject::deleteLater); + + + { + QReadLocker readLocker(&_nodeMutex); + // insert the new node and release our read lock + _nodeHash.insert({ newNode->getUUID(), newNodePointer }); + _localIDMap.insert({ localID, newNodePointer }); + } + + qCDebug(networking) << "Added" << *newNode; + + auto weakPtr = newNodePointer.toWeakRef(); // We don't want the lambdas to hold a strong ref + + emit nodeAdded(newNodePointer); + if (newNodePointer->getActiveSocket()) { + emit nodeActivated(newNodePointer); + } else { + connect(newNodePointer.data(), &NetworkPeer::socketActivated, this, [this, weakPtr] { + auto sharedPtr = weakPtr.lock(); + if (sharedPtr) { + emit nodeActivated(sharedPtr); + disconnect(sharedPtr.data(), &NetworkPeer::socketActivated, this, 0); + } + }); + } + + // Signal when a socket changes, so we can start the hole punch over. + connect(newNodePointer.data(), &NetworkPeer::socketUpdated, this, [this, weakPtr] { + emit nodeSocketUpdated(weakPtr); + }); + + return newNodePointer; } std::unique_ptr LimitedNodeList::constructPingPacket(const QUuid& nodeId, PingType_t pingType) { From 4e9d162172c7c28c3d813373e1d8d4566ec164a3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 24 Feb 2019 13:23:20 +1300 Subject: [PATCH 071/566] AccountServices, HifiAbout, and WalletScriptingInterface JSDoc review --- interface/src/AboutUtil.h | 14 ++++---- interface/src/commerce/Wallet.h | 8 ++--- .../AccountServicesScriptingInterface.cpp | 4 +-- .../AccountServicesScriptingInterface.h | 32 +++++++++---------- .../src/scripting/WalletScriptingInterface.h | 22 ++++++------- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/interface/src/AboutUtil.h b/interface/src/AboutUtil.h index c06255aaa5..4a5074857d 100644 --- a/interface/src/AboutUtil.h +++ b/interface/src/AboutUtil.h @@ -16,8 +16,8 @@ #include /**jsdoc - * The HifiAbout API provides information about the version of Interface that is currently running. It also - * provides the ability to open a Web page in an Interface browser window. + * The HifiAbout API provides information about the version of Interface that is currently running. It also + * has the functionality to open a web page in an Interface browser window. * * @namespace HifiAbout * @@ -30,9 +30,9 @@ * @property {string} qtVersion - The Qt version used in Interface that is currently running. Read-only. * * @example Report build information for the version of Interface currently running. - * print("HiFi build date: " + HifiAbout.buildDate); // 11 Feb 2019 - * print("HiFi version: " + HifiAbout.buildVersion); // 0.78.0 - * print("Qt version: " + HifiAbout.qtVersion); // 5.10.1 + * print("HiFi build date: " + HifiAbout.buildDate); // Returns the build date of the version of Interface currently running on your machine. + * print("HiFi version: " + HifiAbout.buildVersion); // Returns the build version of Interface currently running on your machine. + * print("Qt version: " + HifiAbout.qtVersion); // Returns the Qt version details of the version of Interface currently running on your machine. */ class AboutUtil : public QObject { @@ -52,9 +52,9 @@ public: public slots: /**jsdoc - * Display a Web page in an Interface browser window. + * Display a web page in an Interface browser window. * @function HifiAbout.openUrl - * @param {string} url - The URL of the Web page to display. + * @param {string} url - The URL of the web page you want to view in Interface. */ void openUrl(const QString &url) const; private: diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index 5e5e6c9b4f..fdd6b5e2a6 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -62,8 +62,8 @@ public: * ValueMeaningDescription * * - * 0Not logged inThe user isn't logged in. - * 1Not set upThe user's wallet isn't set up. + * 0Not logged inThe user is not logged in. + * 1Not set upThe user's wallet has not been set up. * 2Pre-existingThere is a wallet present on the server but not one * locally. * 3ConflictingThere is a wallet present on the server plus one present locally, @@ -73,8 +73,8 @@ public: * 5ReadyThe wallet is ready for use. * * - *

Wallets used to be stored locally but now they're stored on the server, unless the computer once had a wallet stored - * locally in which case the wallet may be present in both places.

+ *

Wallets used to be stored locally but now they're only stored on the server. A wallet is present in both places if + * your computer previously stored its information locally.

* @typedef {number} WalletScriptingInterface.WalletStatus */ enum WalletStatus { diff --git a/interface/src/scripting/AccountServicesScriptingInterface.cpp b/interface/src/scripting/AccountServicesScriptingInterface.cpp index a3597886e9..5ede7c7a98 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.cpp +++ b/interface/src/scripting/AccountServicesScriptingInterface.cpp @@ -115,8 +115,8 @@ DownloadInfoResult::DownloadInfoResult() : /**jsdoc * Information on the assets currently being downloaded and pending download. * @typedef {object} AccountServices.DownloadInfoResult - * @property {number[]} downloading - The percentage complete for each asset currently being downloaded. - * @property {number} pending - The number of assets waiting to be download. + * @property {number[]} downloading - The download percentage of each asset currently downloading. + * @property {number} pending - The number of assets pending download. */ QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result) { QScriptValue object = engine->newObject(); diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index c08181d7c9..b5c4a6e0df 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -38,19 +38,19 @@ class AccountServicesScriptingInterface : public QObject { Q_OBJECT /**jsdoc - * The AccountServices API provides functions related to user connectivity, visibility, and asset download - * progress. + * The AccountServices API provides functions that give information on user connectivity, visibility, and + * asset download progress. * * @hifi-interface * @hifi-client-entity * @hifi-avatar * * @namespace AccountServices - * @property {string} username - The user name if the user is logged in, otherwise "Unknown user". - * Read-only. + * @property {string} username - The user name of the user logged in. If there is no user logged in, it is + * "Unknown user". Read-only. * @property {boolean} loggedIn - true if the user is logged in, otherwise false. * Read-only. - * @property {string} findableBy - The user's visibility to other people:
+ * @property {string} findableBy - The user's visibility to other users:
* "none" - user appears offline.
* "friends" - user is visible only to friends.
* "connections" - user is visible to friends and connections.
@@ -74,23 +74,23 @@ public: public slots: /**jsdoc - * Get information on the progress of downloading assets in the domain. + * Gets information on the download progress of assets in the domain. * @function AccountServices.getDownloadInfo - * @returns {AccountServices.DownloadInfoResult} Information on the progress of assets download. + * @returns {AccountServices.DownloadInfoResult} Information on the download progress of assets. */ DownloadInfoResult getDownloadInfo(); /**jsdoc - * Cause a {@link AccountServices.downloadInfoChanged|downloadInfoChanged} signal to be triggered with information on the - * current progress of the download of assets in the domain. + * Triggers a {@link AccountServices.downloadInfoChanged|downloadInfoChanged} signal with information on the current + * download progress of the assets in the domain. * @function AccountServices.updateDownloadInfo */ void updateDownloadInfo(); /**jsdoc - * Check whether the user is logged in. + * Checks whether the user is logged in. * @function AccountServices.isLoggedIn - * @returns {boolean} true if the user is logged in, false otherwise. + * @returns {boolean} true if the user is logged in, false if not. * @example Report whether you are logged in. * var isLoggedIn = AccountServices.isLoggedIn(); * print("You are logged in: " + isLoggedIn); // true or false @@ -100,7 +100,7 @@ public slots: /**jsdoc * Prompts the user to log in (the login dialog is displayed) if they're not already logged in. * @function AccountServices.checkAndSignalForAccessToken - * @returns {boolean} true if the user is already logged in, false otherwise. + * @returns {boolean} true if the user is logged in, false if not. */ bool checkAndSignalForAccessToken(); @@ -140,7 +140,7 @@ signals: /**jsdoc * Triggered when the username logged in with changes, i.e., when the user logs in or out. * @function AccountServices.myUsernameChanged - * @param {string} username - The username logged in with if the user is logged in, otherwise "". + * @param {string} username - The user name of the user logged in. If there is no user logged in, it is "". * @returns {Signal} * @example Report when your username changes. * AccountServices.myUsernameChanged.connect(function (username) { @@ -150,9 +150,9 @@ signals: void myUsernameChanged(const QString& username); /**jsdoc - * Triggered when the progress of the download of assets for the domain changes. + * Triggered when the download progress of the assets in the domain changes. * @function AccountServices.downloadInfoChanged - * @param {AccountServices.DownloadInfoResult} downloadInfo - Information on the progress of assets download. + * @param {AccountServices.DownloadInfoResult} downloadInfo - Information on the download progress of assets. * @returns {Signal} */ void downloadInfoChanged(DownloadInfoResult info); @@ -186,7 +186,7 @@ signals: /**jsdoc * Triggered when the login status of the user changes. * @function AccountServices.loggedInChanged - * @param {boolean} loggedIn - true if the user is logged in, otherwise false. + * @param {boolean} loggedIn - true if the user is logged in, false if not. * @returns {Signal} * @example Report when your login status changes. * AccountServices.loggedInChanged.connect(function(loggedIn) { diff --git a/interface/src/scripting/WalletScriptingInterface.h b/interface/src/scripting/WalletScriptingInterface.h index 7482b8be00..3ef9c7953a 100644 --- a/interface/src/scripting/WalletScriptingInterface.h +++ b/interface/src/scripting/WalletScriptingInterface.h @@ -41,8 +41,8 @@ public: * * @property {WalletScriptingInterface.WalletStatus} walletStatus - The status of the user's wallet. Read-only. * @property {boolean} limitedCommerce - true if Interface is running in limited commerce mode. In limited commerce - * mode, certain Interface functionality is disabled, e.g., users can't buy non-free items from the Marketplace. The Oculus - * Store version of Interface runs in limited commerce mode. Read-only. + * mode, certain Interface functionalities are disabled, e.g., users can't buy items that are not free from the Marketplace. + * The Oculus Store version of Interface runs in limited commerce mode. Read-only. */ class WalletScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -55,16 +55,16 @@ public: WalletScriptingInterface(); /**jsdoc - * Check and update the user's wallet status. + * Checks and updates the user's wallet status. * @function WalletScriptingInterface.refreshWalletStatus */ Q_INVOKABLE void refreshWalletStatus(); /**jsdoc - * Get the current status of the user's wallet. + * Gets the current status of the user's wallet. * @function WalletScriptingInterface.getWalletStatus * @returns {WalletScriptingInterface.WalletStatus} - * @example Two ways to report your wallet status. + * @example Use two methods to report your wallet's status. * print("Wallet status: " + WalletScriptingInterface.walletStatus); // Same value as next line. * print("Wallet status: " + WalletScriptingInterface.getWalletStatus()); */ @@ -74,11 +74,11 @@ public: * Check that a certified avatar entity is owned by the avatar whose entity it is. The result of the check is provided via * the {@link WalletScriptingInterface.ownershipVerificationSuccess|ownershipVerificationSuccess} and * {@link WalletScriptingInterface.ownershipVerificationFailed|ownershipVerificationFailed} signals.
- * Warning: Neither of these signals fire if the entity is not an avatar entity or it's not a certified - * entity. + * Warning: Neither of these signals are triggered if the entity is not an avatar entity or is not + * certified. * @function WalletScriptingInterface.proveAvatarEntityOwnershipVerification - * @param {Uuid} entityID - The ID of the avatar entity to check. - * @example Check ownership of all nearby certified avatar entities. + * @param {Uuid} entityID - The avatar entity's ID. + * @example Check the ownership of all nearby certified avatar entities. * // Set up response handling. * function ownershipSuccess(entityID) { * print("Ownership test succeeded for: " + entityID); @@ -118,7 +118,7 @@ public: signals: /**jsdoc - * Triggered when the status of the user's wallet changes. + * Triggered when the user's wallet status changes. * @function WalletScriptingInterface.walletStatusChanged * @returns {Signal} * @example Report when your wallet status changes, e.g., when you log in and out. @@ -136,7 +136,7 @@ signals: void limitedCommerceChanged(); /**jsdoc - * Triggered when the user rezzes a certified entity but the user's wallet is not ready and so the certified location of the + * Triggered when the user rezzes a certified entity but the user's wallet is not ready. So the certified location of the * entity cannot be updated in the metaverse. * @function WalletScriptingInterface.walletNotSetup * @returns {Signal} From 36c66f019d1fcf79bdf7a49b90f789470da293b3 Mon Sep 17 00:00:00 2001 From: ingerjm0 Date: Sat, 23 Feb 2019 21:10:40 -0800 Subject: [PATCH 072/566] Add @signal tag to jsdoc; use custom jsdoc templates --- tools/jsdoc/config.json | 13 + tools/jsdoc/hifi-jsdoc-template/LICENSE.md | 61 ++ tools/jsdoc/hifi-jsdoc-template/README.md | 42 + tools/jsdoc/hifi-jsdoc-template/package.json | 59 ++ tools/jsdoc/hifi-jsdoc-template/publish.js | 772 ++++++++++++++++++ .../static/fonts/Cairo-Bold.ttf | Bin 0 -> 170996 bytes .../static/fonts/proximanova-regular.otf | Bin 0 -> 62892 bytes .../static/images/white-logo.png | Bin 0 -> 31280 bytes .../static/scripts/collapse.js | 11 + .../static/scripts/jquery-3.1.1.min.js | 4 + .../static/scripts/linenumber.js | 25 + .../scripts/prettify/Apache-License-2.0.txt | 202 +++++ .../static/scripts/prettify/lang-css.js | 2 + .../static/scripts/prettify/prettify.js | 28 + .../static/scripts/search.js | 42 + .../static/styles/jsdoc.css | 731 +++++++++++++++++ .../static/styles/prettify.css | 132 +++ .../hifi-jsdoc-template/tmpl/augments.tmpl | 10 + .../hifi-jsdoc-template/tmpl/container.tmpl | 283 +++++++ .../hifi-jsdoc-template/tmpl/details.tmpl | 143 ++++ .../hifi-jsdoc-template/tmpl/example.tmpl | 141 ++++ .../hifi-jsdoc-template/tmpl/examples.tmpl | 13 + .../hifi-jsdoc-template/tmpl/exceptions.tmpl | 32 + .../hifi-jsdoc-template/tmpl/layout.tmpl | 73 ++ .../hifi-jsdoc-template/tmpl/mainpage.tmpl | 10 + .../hifi-jsdoc-template/tmpl/members.tmpl | 41 + .../hifi-jsdoc-template/tmpl/method.tmpl | 119 +++ .../hifi-jsdoc-template/tmpl/methodList.tmpl | 107 +++ .../hifi-jsdoc-template/tmpl/paramList.tmpl | 67 ++ .../hifi-jsdoc-template/tmpl/params.tmpl | 115 +++ .../hifi-jsdoc-template/tmpl/properties.tmpl | 103 +++ .../hifi-jsdoc-template/tmpl/returns.tmpl | 8 + .../hifi-jsdoc-template/tmpl/returnsSimp.tmpl | 6 + .../hifi-jsdoc-template/tmpl/signal.tmpl | 123 +++ .../hifi-jsdoc-template/tmpl/signalList.tmpl | 92 +++ .../hifi-jsdoc-template/tmpl/source.tmpl | 8 + .../hifi-jsdoc-template/tmpl/tutorial.tmpl | 19 + .../jsdoc/hifi-jsdoc-template/tmpl/type.tmpl | 7 + tools/jsdoc/plugins/hifi.js | 35 +- 39 files changed, 3664 insertions(+), 15 deletions(-) create mode 100644 tools/jsdoc/hifi-jsdoc-template/LICENSE.md create mode 100644 tools/jsdoc/hifi-jsdoc-template/README.md create mode 100644 tools/jsdoc/hifi-jsdoc-template/package.json create mode 100644 tools/jsdoc/hifi-jsdoc-template/publish.js create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/fonts/Cairo-Bold.ttf create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/fonts/proximanova-regular.otf create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/images/white-logo.png create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/scripts/collapse.js create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/scripts/jquery-3.1.1.min.js create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/scripts/linenumber.js create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/scripts/prettify/Apache-License-2.0.txt create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/scripts/prettify/lang-css.js create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/scripts/prettify/prettify.js create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/scripts/search.js create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/styles/jsdoc.css create mode 100644 tools/jsdoc/hifi-jsdoc-template/static/styles/prettify.css create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/augments.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/container.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/details.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/example.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/examples.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/exceptions.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/layout.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/mainpage.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/members.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/method.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/methodList.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/paramList.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/params.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/properties.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/returns.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/returnsSimp.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/signal.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/signalList.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/source.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/tutorial.tmpl create mode 100644 tools/jsdoc/hifi-jsdoc-template/tmpl/type.tmpl diff --git a/tools/jsdoc/config.json b/tools/jsdoc/config.json index a24e248661..5074362225 100644 --- a/tools/jsdoc/config.json +++ b/tools/jsdoc/config.json @@ -1,4 +1,17 @@ { + "opts": { + "template": "hifi-jsdoc-template" + }, + "docdash": { + "meta": { + "title": "", + "description": "", + "keyword": "" + }, + "search": [true], + "collapse": [true], + "typedefs": [false] + }, "templates": { "default": { "outputSourceFiles": false diff --git a/tools/jsdoc/hifi-jsdoc-template/LICENSE.md b/tools/jsdoc/hifi-jsdoc-template/LICENSE.md new file mode 100644 index 0000000000..ff66af581b --- /dev/null +++ b/tools/jsdoc/hifi-jsdoc-template/LICENSE.md @@ -0,0 +1,61 @@ +# License + +Docdash is free software, licensed under the Apache License, Version 2.0 (the +"License"). Commercial and non-commercial use are permitted in compliance with +the License. + +Copyright (c) 2016 Clement Moron and the +[contributors to docdash](https://github.com/clenemt/docdash/graphs/contributors). +All rights reserved. + +You may obtain a copy of the License at: +http://www.apache.org/licenses/LICENSE-2.0 + +In addition, a copy of the License is included with this distribution. + +As stated in Section 7, "Disclaimer of Warranty," of the License: + +> Licensor provides the Work (and each Contributor provides its Contributions) +> on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +> express or implied, including, without limitation, any warranties or +> conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +> PARTICULAR PURPOSE. You are solely responsible for determining the +> appropriateness of using or redistributing the Work and assume any risks +> associated with Your exercise of permissions under this License. + +The source code for docdash is available at: +https://github.com/clenemt/docdash + +# Third-Party Software + +Docdash includes or depends upon the following third-party software, either in +whole or in part. Each third-party software package is provided under its own +license. + +## JSDoc 3 + +JSDoc 3 is free software, licensed under the Apache License, Version 2.0 (the +"License"). Commercial and non-commercial use are permitted in compliance with +the License. + +Copyright (c) 2011-2016 Michael Mathews and the +[contributors to JSDoc](https://github.com/jsdoc3/jsdoc/graphs/contributors). +All rights reserved. + +You may obtain a copy of the License at: +http://www.apache.org/licenses/LICENSE-2.0 + +In addition, a copy of the License is included with this distribution. + +As stated in Section 7, "Disclaimer of Warranty," of the License: + +> Licensor provides the Work (and each Contributor provides its Contributions) +> on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +> express or implied, including, without limitation, any warranties or +> conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +> PARTICULAR PURPOSE. You are solely responsible for determining the +> appropriateness of using or redistributing the Work and assume any risks +> associated with Your exercise of permissions under this License. + +The source code for JSDoc 3 is available at: +https://github.com/jsdoc3/jsdoc diff --git a/tools/jsdoc/hifi-jsdoc-template/README.md b/tools/jsdoc/hifi-jsdoc-template/README.md new file mode 100644 index 0000000000..797beaa79a --- /dev/null +++ b/tools/jsdoc/hifi-jsdoc-template/README.md @@ -0,0 +1,42 @@ +# hifi-jsdoc-template +The hifi-jsdoc-template is based on the [DocDash](https://github.com/clenemt/docdash) template. + +## Usage +Clone repository to your designated `jsdoc/node_modules` template directory. + +In your `config.json` file, add a template option. + +```json +"opts": { + "template": "node_modules/hifi-jsdoc-template" +} +``` + +## Sample `config.json` + +```json +{ + "opts": { + "template": "node_modules/hifi-jsdoc-template" + }, + "docdash": { + "meta": { + "title": "", + "description": "", + "keyword": "" + }, + "search": [true], + "collapse": [true], + "typedefs": [false] + }, + "templates": { + "default": { + "outputSourceFiles": false + } + }, + "plugins": [ + "plugins/hifi", + "plugins/hifiJSONExport" + ] +} +``` diff --git a/tools/jsdoc/hifi-jsdoc-template/package.json b/tools/jsdoc/hifi-jsdoc-template/package.json new file mode 100644 index 0000000000..f011adc2ba --- /dev/null +++ b/tools/jsdoc/hifi-jsdoc-template/package.json @@ -0,0 +1,59 @@ +{ + "_from": "docdash", + "_id": "docdash@1.0.0", + "_inBundle": false, + "_integrity": "sha512-HhK72PT4z55og8FDqskO/tTYXxU+LovRz+9pCDHLnUoPchkxjdIJidS+96LqW3CLrRdBmnkDRrcVrDFGLIluTw==", + "_location": "/docdash", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "docdash", + "name": "docdash", + "escapedName": "docdash", + "rawSpec": "", + "saveSpec": null, + "fetchSpec": "latest" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "https://registry.npmjs.org/docdash/-/docdash-1.0.0.tgz", + "_shasum": "5b7df10fed3d341fc4416a8978c65ad561869d18", + "_spec": "docdash", + "_where": "D:\\hifi\\tools\\jsdoc", + "author": { + "name": "Clement Moron", + "email": "clement.moron@gmail.com" + }, + "bugs": { + "url": "https://github.com/clenemt/docdash/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "A clean, responsive documentation template theme for JSDoc 3 inspired by lodash and minami", + "devDependencies": { + "browser-sync": "latest", + "jsdoc": "latest", + "watch-run": "latest" + }, + "homepage": "https://github.com/clenemt/docdash#readme", + "keywords": [ + "jsdoc", + "template" + ], + "license": "Apache-2.0", + "main": "publish.js", + "name": "docdash", + "repository": { + "type": "git", + "url": "git+https://github.com/clenemt/docdash.git" + }, + "scripts": { + "sync": "browser-sync start -s ../fixtures-doc -f ../fixtures-doc --reload-delay 1000 --no-ui --no-notify", + "test": "jsdoc -c fixtures/fixtures.conf.json", + "watch": "watch-run -d 1000 -p tmpl/**,static/** \"npm run test\"" + }, + "version": "1.0.0" +} diff --git a/tools/jsdoc/hifi-jsdoc-template/publish.js b/tools/jsdoc/hifi-jsdoc-template/publish.js new file mode 100644 index 0000000000..9cd428bbbb --- /dev/null +++ b/tools/jsdoc/hifi-jsdoc-template/publish.js @@ -0,0 +1,772 @@ +/*global env: true */ +'use strict'; + +var doop = require('jsdoc/util/doop'); +var fs = require('jsdoc/fs'); +var helper = require('jsdoc/util/templateHelper'); +var logger = require('jsdoc/util/logger'); +var path = require('jsdoc/path'); +var taffy = require('taffydb').taffy; +var template = require('jsdoc/template'); +var util = require('util'); + +var htmlsafe = helper.htmlsafe; +var linkto = helper.linkto; +var resolveAuthorLinks = helper.resolveAuthorLinks; +var scopeToPunc = helper.scopeToPunc; +var hasOwnProp = Object.prototype.hasOwnProperty; + +var data; +var view; + +var outdir = path.normalize(env.opts.destination); + +function copyFile(source, target, cb) { + var cbCalled = false; + + var rd = fs.createReadStream(source); + rd.on("error", function(err) { + done(err); + }); + var wr = fs.createWriteStream(target); + wr.on("error", function(err) { + done(err); + }); + wr.on("close", function(ex) { + done(); + }); + rd.pipe(wr); + + function done(err) { + if (!cbCalled) { + cb(err); + cbCalled = true; + } + } +} + +function find(spec) { + return helper.find(data, spec); +} + +function tutoriallink(tutorial) { + return helper.toTutorial(tutorial, null, { tag: 'em', classname: 'disabled', prefix: 'Tutorial: ' }); +} + +function getAncestorLinks(doclet) { + return helper.getAncestorLinks(data, doclet); +} + +function hashToLink(doclet, hash) { + if ( !/^(#.+)/.test(hash) ) { return hash; } + + var url = helper.createLink(doclet); + + url = url.replace(/(#.+|$)/, hash); + return '' + hash + ''; +} + +function needsSignature(doclet) { + var needsSig = false; + + // function and class definitions always get a signature + if (doclet.kind === 'function' || doclet.kind === 'class' && !doclet.hideconstructor) { + needsSig = true; + } + // typedefs that contain functions get a signature, too + else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names && + doclet.type.names.length) { + for (var i = 0, l = doclet.type.names.length; i < l; i++) { + if (doclet.type.names[i].toLowerCase() === 'function') { + needsSig = true; + break; + } + } + } + + return needsSig; +} + +function getSignatureAttributes(item) { + var attributes = []; + + if (item.optional) { + attributes.push('opt'); + } + + if (item.nullable === true) { + attributes.push('nullable'); + } + else if (item.nullable === false) { + attributes.push('non-null'); + } + + return attributes; +} + +function updateItemName(item) { + var attributes = getSignatureAttributes(item); + var itemName = item.name || ''; + + if (item.variable) { + itemName = '…' + itemName; + } + + if (attributes && attributes.length) { + itemName = util.format( '%s%s', itemName, + attributes.join(', ') ); + } + + return itemName; +} + +function addParamAttributes(params) { + return params.filter(function(param) { + return param.name && param.name.indexOf('.') === -1; + }).map(updateItemName); +} + +function buildItemTypeStrings(item) { + var types = []; + + if (item && item.type && item.type.names) { + item.type.names.forEach(function(name) { + types.push( linkto(name, htmlsafe(name)) ); + }); + } + + return types; +} + +function buildAttribsString(attribs) { + var attribsString = ''; + + if (attribs && attribs.length) { + attribsString = htmlsafe( util.format('(%s) ', attribs.join(', ')) ); + } + + return attribsString; +} + +function addNonParamAttributes(items) { + var types = []; + + items.forEach(function(item) { + types = types.concat( buildItemTypeStrings(item) ); + }); + + return types; +} + +function addSignatureParams(f) { + var params = f.params ? addParamAttributes(f.params) : []; + f.signature = util.format( '%s( %s )', (f.signature || ''), params.join(', ') ); +} + +function addSignatureReturns(f) { + var attribs = []; + var attribsString = ''; + var returnTypes = []; + var returnTypesString = ''; + + // jam all the return-type attributes into an array. this could create odd results (for example, + // if there are both nullable and non-nullable return types), but let's assume that most people + // who use multiple @return tags aren't using Closure Compiler type annotations, and vice-versa. + if (f.returns) { + f.returns.forEach(function(item) { + helper.getAttribs(item).forEach(function(attrib) { + if (attribs.indexOf(attrib) === -1) { + attribs.push(attrib); + } + }); + }); + + attribsString = buildAttribsString(attribs); + } + + if (f.returns) { + returnTypes = addNonParamAttributes(f.returns); + } + if (returnTypes.length) { + returnTypesString = util.format( ' → %s{%s}', attribsString, returnTypes.join('|') ); + } + + f.signature = '' + (f.signature || '') + '' + + '' + returnTypesString + ''; +} + +function addSignatureTypes(f) { + var types = f.type ? buildItemTypeStrings(f) : []; + + f.signature = (f.signature || '') + '' + + (types.length ? ' :' + types.join('|') : '') + ''; +} + +function addAttribs(f) { + var attribs = helper.getAttribs(f); + var attribsString = buildAttribsString(attribs); + + f.attribs = util.format('%s', attribsString); +} + +function shortenPaths(files, commonPrefix) { + Object.keys(files).forEach(function(file) { + files[file].shortened = files[file].resolved.replace(commonPrefix, '') + // always use forward slashes + .replace(/\\/g, '/'); + }); + + return files; +} + +function getPathFromDoclet(doclet) { + if (!doclet.meta) { + return null; + } + + return doclet.meta.path && doclet.meta.path !== 'null' ? + path.join(doclet.meta.path, doclet.meta.filename) : + doclet.meta.filename; +} + +function generate(type, title, docs, filename, resolveLinks) { + resolveLinks = resolveLinks === false ? false : true; + + var docData = { + type: type, + title: title, + docs: docs + }; + + var outpath = path.join(outdir, filename), + html = view.render('container.tmpl', docData); + + if (resolveLinks) { + html = helper.resolveLinks(html); // turn {@link foo} into foo + } + + fs.writeFileSync(outpath, html, 'utf8'); +} + +function generateSourceFiles(sourceFiles, encoding) { + encoding = encoding || 'utf8'; + Object.keys(sourceFiles).forEach(function(file) { + var source; + // links are keyed to the shortened path in each doclet's `meta.shortpath` property + var sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened); + helper.registerLink(sourceFiles[file].shortened, sourceOutfile); + + try { + source = { + kind: 'source', + code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, encoding) ) + }; + } + catch(e) { + logger.error('Error while generating source file %s: %s', file, e.message); + } + + generate('Source', sourceFiles[file].shortened, [source], sourceOutfile, false); + }); +} + +/** + * Look for classes or functions with the same name as modules (which indicates that the module + * exports only that class or function), then attach the classes or functions to the `module` + * property of the appropriate module doclets. The name of each class or function is also updated + * for display purposes. This function mutates the original arrays. + * + * @private + * @param {Array.} doclets - The array of classes and functions to + * check. + * @param {Array.} modules - The array of module doclets to search. + */ +function attachModuleSymbols(doclets, modules) { + var symbols = {}; + + // build a lookup table + doclets.forEach(function(symbol) { + symbols[symbol.longname] = symbols[symbol.longname] || []; + symbols[symbol.longname].push(symbol); + }); + + return modules.map(function(module) { + if (symbols[module.longname]) { + module.modules = symbols[module.longname] + // Only show symbols that have a description. Make an exception for classes, because + // we want to show the constructor-signature heading no matter what. + .filter(function(symbol) { + return symbol.description || symbol.kind === 'class'; + }) + .map(function(symbol) { + symbol = doop(symbol); + + if (symbol.kind === 'class' || symbol.kind === 'function' && !symbol.hideconstructor) { + symbol.name = symbol.name.replace('module:', '(require("') + '"))'; + } + + return symbol; + }); + } + }); +} + +function buildMemberNav(items, itemHeading, itemsSeen, linktoFn) { + var nav = ''; + + if (items && items.length) { + var itemsNav = ''; + + items.forEach(function(item) { + var displayName; + var methods = find({kind:'function', memberof: item.longname}); + var signals = find({kind:'signal', memberof: item.longname}); + var members = find({kind:'member', memberof: item.longname}); + var docdash = env && env.conf && env.conf.docdash || {}; + var conf = env && env.conf || {}; + if ( !hasOwnProp.call(item, 'longname') ) { + itemsNav += '
  • ' + linktoFn('', item.name); + itemsNav += '
  • '; + } else if ( !hasOwnProp.call(itemsSeen, item.longname) ) { + if (conf.templates.default.useLongnameInNav) { + displayName = item.longname; + } else { + displayName = item.name; + } + itemsNav += '
  • ' + linktoFn(item.longname, displayName.replace(/\b(module|event):/g, '')); + + if (docdash.static && members.find(function (m) { return m.scope === 'static'; } )) { + itemsNav += "