From 3578df7a0e296107c786781c957ed41affc02b2f Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 19 Dec 2018 13:28:33 -0800 Subject: [PATCH 01/46] material targeting --- .../entities/src/EntityItemProperties.cpp | 12 ++-- libraries/render-utils/src/Model.cpp | 61 +++++++++++++------ libraries/render-utils/src/Model.h | 2 +- 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index b6307a83da..72c90092f0 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -779,10 +779,14 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {number} priority=0 - The priority for applying the material to its parent. Only the highest priority material is * applied, with materials of the same priority randomly assigned. Materials that come with the model have a priority of * 0. - * @property {string|number} parentMaterialName="0" - Selects the submesh or submeshes within the parent to apply the material - * to. If in the format "mat::string", all submeshes with material name "string" are replaced. - * Otherwise the property value is parsed as an unsigned integer, specifying the mesh index to modify. Invalid values are - * parsed to 0. + * @property {string} parentMaterialName="0" - Selects the mesh part or parts within the parent to which to apply the material. + * If in the format "mat::string", all mesh parts with material name "string" are replaced. + * Otherwise the property value is parsed as an unsigned integer, specifying the mesh parth index to modify. If "all", + * all mesh parts will be replaced. If an array (starts with "[" and ends with "]"), the string will be + * split at each "," and each element will be parsed as either a number or a string if it starts with + * "mat::". In other words, "[0,1,mat::string,mat::string2]" will replace mesh parts 1 and 2, and any + * mesh parts with material "string" or "string2". Do not put spaces around the commas. Invalid values + * are parsed to 0. * @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either "uv" or * "projected". In "uv" mode, the material will be evaluated within the UV space of the mesh it is applied to. In * "projected" mode, the 3D transform of the Material Entity will be used to evaluate the texture coordinates for the material. diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9cefbf65a8..f3c6ceb178 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1533,29 +1533,56 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } -std::vector Model::getMeshIDsFromMaterialID(QString parentMaterialName) { - // try to find all meshes with materials that match parentMaterialName as a string - // if none, return parentMaterialName as a uint - std::vector toReturn; - const QString MATERIAL_NAME_PREFIX = "mat::"; - if (parentMaterialName.startsWith(MATERIAL_NAME_PREFIX)) { - parentMaterialName.replace(0, MATERIAL_NAME_PREFIX.size(), QString("")); - for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) { - if (_modelMeshMaterialNames[i] == parentMaterialName.toStdString()) { - toReturn.push_back(i); - } - } - } +std::set Model::getMeshIDsFromMaterialID(QString parentMaterialName) { + std::set toReturn; - if (toReturn.empty()) { - toReturn.push_back(parentMaterialName.toUInt()); + const QString all("all"); + if (parentMaterialName == all) { + for (unsigned int i = 0; i < (unsigned int)_modelMeshRenderItemIDs.size(); i++) { + toReturn.insert(i); + } + } else if (!parentMaterialName.isEmpty()) { + auto parseFunc = [this, &toReturn] (QString& target) { + if (target.isEmpty()) { + return; + } + // if target starts with "mat::", try to find all meshes with materials that match target as a string + // otherwise, return target as a uint + const QString MATERIAL_NAME_PREFIX("mat::"); + if (target.startsWith(MATERIAL_NAME_PREFIX)) { + std::string targetStdString = target.replace(0, MATERIAL_NAME_PREFIX.size(), "").toStdString(); + for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) { + if (_modelMeshMaterialNames[i] == targetStdString) { + toReturn.insert(i); + } + } + return; + } + toReturn.insert(target.toUInt()); + }; + + if (parentMaterialName.length() > 2 && parentMaterialName.startsWith("[") && parentMaterialName.endsWith("]")) { + QStringList list = parentMaterialName.split(",", QString::SkipEmptyParts); + for (int i = 0; i < list.length(); i++) { + auto& target = list[i]; + if (i == 0) { + target = target.replace(0, 1, ""); + } + if (i == list.length() - 1) { + target = target.replace(target.length() - 1, 1, ""); + } + parseFunc(target); + } + } else { + parseFunc(parentMaterialName); + } } return toReturn; } void Model::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) { - std::vector shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str())); + std::set shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str())); render::Transaction transaction; for (auto shapeID : shapeIDs) { if (shapeID < _modelMeshRenderItemIDs.size()) { @@ -1578,7 +1605,7 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par } void Model::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) { - std::vector shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str())); + std::set shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str())); render::Transaction transaction; for (auto shapeID : shapeIDs) { if (shapeID < _modelMeshRenderItemIDs.size()) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 93a0626d28..da06eb7ef0 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -513,7 +513,7 @@ private: void calculateTextureInfo(); - std::vector getMeshIDsFromMaterialID(QString parentMaterialName); + std::set getMeshIDsFromMaterialID(QString parentMaterialName); }; Q_DECLARE_METATYPE(ModelPointer) From b609cfaa2bcccc7de4bd788a6b0de60608e4d431 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 4 Jan 2019 10:43:48 -0800 Subject: [PATCH 02/46] renderLayer --- interface/src/ui/overlays/ModelOverlay.cpp | 15 +++---- interface/src/ui/overlays/ModelOverlay.h | 3 +- .../src/RenderableEntityItem.cpp | 18 ++++++-- .../src/RenderableEntityItem.h | 3 ++ .../src/RenderableMaterialEntityItem.cpp | 2 +- .../src/RenderableModelEntityItem.cpp | 17 +++++++- .../src/RenderableModelEntityItem.h | 1 + .../RenderableParticleEffectEntityItem.cpp | 4 +- .../src/RenderablePolyLineEntityItem.cpp | 2 +- .../src/RenderablePolyVoxEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 27 +++++++++++- libraries/entities/src/EntityItem.h | 4 ++ .../entities/src/EntityItemProperties.cpp | 39 ++++++++++++++++++ libraries/entities/src/EntityItemProperties.h | 2 + libraries/entities/src/EntityPropertyFlags.h | 1 + .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 7 +++- libraries/octree/src/OctreePacketData.h | 2 + libraries/render-utils/src/Model.cpp | 22 ++-------- libraries/render-utils/src/Model.h | 6 +-- libraries/shared/src/BillboardMode.cpp | 4 +- libraries/shared/src/MaterialMappingMode.cpp | 2 +- libraries/shared/src/RenderLayer.cpp | 25 +++++++++++ libraries/shared/src/RenderLayer.h | 41 +++++++++++++++++++ 24 files changed, 199 insertions(+), 52 deletions(-) create mode 100644 libraries/shared/src/RenderLayer.cpp create mode 100644 libraries/shared/src/RenderLayer.h diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 14b8182abf..14e5cdc7f5 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -114,14 +114,9 @@ void ModelOverlay::update(float deltatime) { _model->setVisibleInScene(getVisible(), scene); metaDirty = true; } - if (_drawInFrontDirty) { - _drawInFrontDirty = false; - _model->setLayeredInFront(getDrawInFront(), scene); - metaDirty = true; - } - if (_drawInHUDDirty) { - _drawInHUDDirty = false; - _model->setLayeredInHUD(getDrawHUDLayer(), scene); + if (_renderLayerDirty) { + _renderLayerDirty = false; + _model->setHifiRenderLayer(_drawHUDLayer ? render::hifi::LAYER_3D_HUD : (_drawInFront ? render::hifi::LAYER_3D_FRONT : render::hifi::LAYER_3D), scene); metaDirty = true; } if (_groupCulledDirty) { @@ -175,14 +170,14 @@ void ModelOverlay::setVisible(bool visible) { void ModelOverlay::setDrawInFront(bool drawInFront) { if (drawInFront != getDrawInFront()) { Base3DOverlay::setDrawInFront(drawInFront); - _drawInFrontDirty = true; + _renderLayerDirty = true; } } void ModelOverlay::setDrawHUDLayer(bool drawHUDLayer) { if (drawHUDLayer != getDrawHUDLayer()) { Base3DOverlay::setDrawHUDLayer(drawHUDLayer); - _drawInHUDDirty = true; + _renderLayerDirty = true; } } diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index bd922e258a..17a2327d02 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -126,8 +126,7 @@ private: QVector _jointMapping; // domain is index into model-joints, range is index into animation-joints bool _visibleDirty { true }; - bool _drawInFrontDirty { false }; - bool _drawInHUDDirty { false }; + bool _renderLayerDirty { false }; bool _isGroupCulled { false }; bool _groupCulledDirty { false }; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 5fb5a15d2c..8416e8d0e2 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -163,16 +163,27 @@ render::hifi::Tag EntityRenderer::getTagMask() const { return _isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW; } +render::hifi::Layer EntityRenderer::getHifiRenderLayer() const { + switch (_renderLayer) { + case RenderLayer::WORLD: + return render::hifi::LAYER_3D; + case RenderLayer::FRONT: + return render::hifi::LAYER_3D_FRONT; + case RenderLayer::HUD: + return render::hifi::LAYER_3D_HUD; + } +} + ItemKey EntityRenderer::getKey() { if (isTransparent()) { - return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()); + return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); } // This allows shapes to cast shadows if (_canCastShadow) { - return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()).withShadowCaster(); + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()).withShadowCaster().withLayer(getHifiRenderLayer()); } else { - return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()); + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); } } @@ -411,6 +422,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa _moving = entity->isMovingRelativeToParent(); _visible = entity->getVisible(); setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera()); + setRenderLayer(entity->getRenderLayer()); _canCastShadow = entity->getCanCastShadow(); _cauterized = entity->getCauterized(); _needsRenderUpdate = false; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 9c4d10190c..1c83aecdbe 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -77,6 +77,7 @@ protected: virtual void render(RenderArgs* args) override final; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override; virtual render::hifi::Tag getTagMask() const; + virtual render::hifi::Layer getHifiRenderLayer() const; // Returns true if the item in question needs to have updateInScene called because of internal rendering state changes virtual bool needsRenderUpdate() const; @@ -103,6 +104,7 @@ protected: inline bool isValidRenderItem() const { return _renderItemID != Item::INVALID_ITEM_ID; } virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } + virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; } template T withReadLockResult(const std::function& f) { @@ -136,6 +138,7 @@ protected: bool _visible { false }; bool _isVisibleInSecondaryCamera { false }; bool _canCastShadow { false }; + RenderLayer _renderLayer { RenderLayer::WORLD }; bool _cauterized { false }; bool _moving { false }; bool _needsRenderUpdate { false }; diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 6451e873c9..8cc1b0f193 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -55,7 +55,7 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& ItemKey MaterialEntityRenderer::getKey() { ItemKey::Builder builder; - builder.withTypeShape().withTagBits(getTagMask()); + builder.withTypeShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); if (!_visible) { builder.withInvisible(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index dcad562ba7..255446287d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1070,9 +1070,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) { if (didVisualGeometryRequestSucceed) { - _itemKey = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()); + _itemKey = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); } else { - _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(getTagMask()); + _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); } } @@ -1346,6 +1346,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate); connect(model.get(), &Model::setURLFinished, this, [&](bool didVisualGeometryRequestSucceed) { setKey(didVisualGeometryRequestSucceed); + _model->setTagMask(getTagMask()); + _model->setHifiRenderLayer(getHifiRenderLayer()); emit requestRenderUpdate(); if(didVisualGeometryRequestSucceed) { emit DependencyManager::get()-> @@ -1489,6 +1491,17 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) { Parent::setIsVisibleInSecondaryCamera(value); setKey(_didLastVisualGeometryRequestSucceed); + if (_model) { + _model->setTagMask(getTagMask()); + } +} + +void ModelEntityRenderer::setRenderLayer(RenderLayer value) { + Parent::setRenderLayer(value); + setKey(_didLastVisualGeometryRequestSucceed); + if (_model) { + _model->setHifiRenderLayer(getHifiRenderLayer()); + } } // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index ba185dee96..cd4b636e33 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -169,6 +169,7 @@ protected: render::hifi::Tag getTagMask() const override; void setIsVisibleInSecondaryCamera(bool value) override; + void setRenderLayer(RenderLayer value) override; private: void animate(const TypedEntityPointer& entity); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 38027a80ed..8f6fd5383e 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -159,9 +159,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn ItemKey ParticleEffectEntityRenderer::getKey() { if (_visible) { - return ItemKey::Builder::transparentShape().withTagBits(getTagMask()); + return ItemKey::Builder::transparentShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); } else { - return ItemKey::Builder().withInvisible().withTagBits(getTagMask()).build(); + return ItemKey::Builder().withInvisible().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()).build(); } } diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index de224103ce..e3bfa04bdc 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -55,7 +55,7 @@ void PolyLineEntityRenderer::buildPipeline() { } ItemKey PolyLineEntityRenderer::getKey() { - return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()); + return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); } ShapeKey PolyLineEntityRenderer::getShapeKey() { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 366a3fdc70..7aea87535e 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -173,7 +173,7 @@ public: } protected: - virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(getTagMask()); } + virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); } virtual ShapeKey getShapeKey() override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index bfa238d695..6f8e764973 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -94,6 +94,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_QUERY_AA_CUBE; requestedProperties += PROP_CAN_CAST_SHADOW; // requestedProperties += PROP_VISIBLE_IN_SECONDARY_CAMERA; // not sent over wire + requestedProperties += PROP_RENDER_LAYER; withReadLock([&] { requestedProperties += _grabProperties.getEntityProperties(params); }); @@ -265,7 +266,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint()); // TODO: handle created? APPEND_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, getLastEditedBy()); - // APPEND_ENTITY_PROPERTY(PROP_ENTITY_HOST_TYPE, getEntityHostType()); // not sent over wire + // APPEND_ENTITY_PROPERTY(PROP_ENTITY_HOST_TYPE, (uint32_t)getEntityHostType()); // not sent over wire // APPEND_ENTITY_PROPERTY(PROP_OWNING_AVATAR_ID, getOwningAvatarID()); // not sent over wire // convert AVATAR_SELF_ID to actual sessionUUID. QUuid actualParentID = getParentID(); @@ -278,6 +279,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, getQueryAACube()); APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, getCanCastShadow()); // APPEND_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, getIsVisibleInSecondaryCamera()); // not sent over wire + APPEND_ENTITY_PROPERTY(PROP_RENDER_LAYER, (uint32_t)getRenderLayer()); withReadLock([&] { _grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); @@ -841,6 +843,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } READ_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); // READ_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, bool, setIsVisibleInSecondaryCamera); // not sent over wire + READ_ENTITY_PROPERTY(PROP_RENDER_LAYER, RenderLayer, setRenderLayer); withWriteLock([&] { int bytesFromGrab = _grabProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, @@ -1310,6 +1313,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire COPY_ENTITY_PROPERTY_TO_PROPERTIES(queryAACube, getQueryAACube); COPY_ENTITY_PROPERTY_TO_PROPERTIES(canCastShadow, getCanCastShadow); // COPY_ENTITY_PROPERTY_TO_PROPERTIES(isVisibleInSecondaryCamera, getIsVisibleInSecondaryCamera); // not sent over wire + COPY_ENTITY_PROPERTY_TO_PROPERTIES(renderLayer, getRenderLayer); withReadLock([&] { _grabProperties.getProperties(properties); }); @@ -1454,6 +1458,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube); SET_ENTITY_PROPERTY_FROM_PROPERTIES(canCastShadow, setCanCastShadow); SET_ENTITY_PROPERTY_FROM_PROPERTIES(isVisibleInSecondaryCamera, setIsVisibleInSecondaryCamera); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(renderLayer, setRenderLayer); withWriteLock([&] { bool grabPropertiesChanged = _grabProperties.setProperties(properties); somethingChanged |= grabPropertiesChanged; @@ -2888,6 +2893,26 @@ void EntityItem::setIsVisibleInSecondaryCamera(bool value) { } } +RenderLayer EntityItem::getRenderLayer() const { + return resultWithReadLock([&] { + return _renderLayer; + }); +} + +void EntityItem::setRenderLayer(RenderLayer value) { + bool changed = false; + withWriteLock([&] { + if (_renderLayer != value) { + changed = true; + _renderLayer = value; + } + }); + + if (changed) { + emit requestRenderUpdate(); + } +} + bool EntityItem::getCanCastShadow() const { bool result; withReadLock([&] { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 826a9c34a0..5053389a7b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -293,6 +293,9 @@ public: bool isVisibleInSecondaryCamera() const; void setIsVisibleInSecondaryCamera(bool value); + RenderLayer getRenderLayer() const; + void setRenderLayer(RenderLayer value); + bool getCanCastShadow() const; void setCanCastShadow(bool value); @@ -621,6 +624,7 @@ protected: float _angularDamping { ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING }; bool _visible { ENTITY_ITEM_DEFAULT_VISIBLE }; bool _isVisibleInSecondaryCamera { ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA }; + RenderLayer _renderLayer { RenderLayer::WORLD }; bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW }; bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS }; uint16_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index eda1eae5d1..00263b771e 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -343,6 +343,33 @@ void EntityItemProperties::setBillboardModeFromString(const QString& materialMap } } +QHash stringToRenderLayerLookup; + +void addRenderLayer(RenderLayer mode) { + stringToRenderLayerLookup[RenderLayerHelpers::getNameForRenderLayer(mode)] = mode; +} + +void buildStringToRenderLayerLookup() { + addRenderLayer(RenderLayer::WORLD); + addRenderLayer(RenderLayer::FRONT); + addRenderLayer(RenderLayer::HUD); +} + +QString EntityItemProperties::getRenderLayerAsString() const { + return RenderLayerHelpers::getNameForRenderLayer(_renderLayer); +} + +void EntityItemProperties::setRenderLayerFromString(const QString& materialMappingMode) { + if (stringToRenderLayerLookup.empty()) { + buildStringToRenderLayerLookup(); + } + auto renderLayerItr = stringToRenderLayerLookup.find(materialMappingMode.toLower()); + if (renderLayerItr != stringToRenderLayerLookup.end()) { + _renderLayer = renderLayerItr.value(); + _renderLayerChanged = true; + } +} + EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; @@ -367,6 +394,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_QUERY_AA_CUBE, queryAACube); CHECK_PROPERTY_CHANGE(PROP_CAN_CAST_SHADOW, canCastShadow); CHECK_PROPERTY_CHANGE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); + CHECK_PROPERTY_CHANGE(PROP_RENDER_LAYER, renderLayer); changedProperties += _grab.getChangedProperties(); // Physics @@ -603,6 +631,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * {@link Entities.EntityType|Zone} entity with castShadows enabled in its * {@link Entities.EntityProperties-Zone|keyLight} property. * @property {boolean} isVisibleInSecondaryCamera=true - Whether or not the entity is rendered in the secondary camera. If true then the entity is rendered. + * @property {RenderLayer} renderLayer="world" - In which layer this entity renders. * * @property {Vec3} position=0,0,0 - The position of the entity. * @property {Quat} rotation=0,0,0,1 - The orientation of the entity with respect to world coordinates. @@ -1413,6 +1442,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_QUERY_AA_CUBE, queryAACube); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CAN_CAST_SHADOW, canCastShadow); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_RENDER_LAYER, renderLayer, getRenderLayerAsString()); _grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); // Physics @@ -1799,6 +1829,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(queryAACube, AACube, setQueryAACube); // TODO: should scripts be able to set this? COPY_PROPERTY_FROM_QSCRIPTVALUE(canCastShadow, bool, setCanCastShadow); COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(renderLayer, RenderLayer); _grab.copyFromScriptValue(object, _defaultSettings); // Physics @@ -2056,6 +2087,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(queryAACube); COPY_PROPERTY_IF_CHANGED(canCastShadow); COPY_PROPERTY_IF_CHANGED(isVisibleInSecondaryCamera); + COPY_PROPERTY_IF_CHANGED(renderLayer); _grab.merge(other._grab); // Physics @@ -2309,6 +2341,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue //ADD_PROPERTY_TO_MAP(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube); // not yet handled ADD_PROPERTY_TO_MAP(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool); ADD_PROPERTY_TO_MAP(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool); + ADD_PROPERTY_TO_MAP(PROP_RENDER_LAYER, RenderLayer, renderLayer, RenderLayer); { // Grab ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable); ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic); @@ -2701,6 +2734,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, properties.getQueryAACube()); APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, properties.getCanCastShadow()); // APPEND_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, properties.getIsVisibleInSecondaryCamera()); // Not sent over the wire + APPEND_ENTITY_PROPERTY(PROP_RENDER_LAYER, (uint32_t)properties.getRenderLayer()); _staticGrab.setProperties(properties); _staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); @@ -3147,6 +3181,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_QUERY_AA_CUBE, AACube, setQueryAACube); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); // READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE_IN_SECONDARY_CAMERA, bool, setIsVisibleInSecondaryCamera); // Not sent over the wire + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_LAYER, RenderLayer, setRenderLayer); properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); // Physics @@ -3529,6 +3564,7 @@ void EntityItemProperties::markAllChanged() { _queryAACubeChanged = true; _canCastShadowChanged = true; _isVisibleInSecondaryCameraChanged = true; + _renderLayerChanged = true; _grab.markAllChanged(); // Physics @@ -3902,6 +3938,9 @@ QList EntityItemProperties::listChangedProperties() { if (isVisibleInSecondaryCameraChanged()) { out += "isVisibleInSecondaryCamera"; } + if (renderLayerChanged()) { + out += "renderLayer"; + } getGrab().listChangedProperties(out); // Physics diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 1590832236..e0781bab21 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -50,6 +50,7 @@ #include "MaterialMappingMode.h" #include "BillboardMode.h" +#include "RenderLayer.h" const quint64 UNKNOWN_CREATED_TIME = 0; @@ -149,6 +150,7 @@ public: DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube()); DEFINE_PROPERTY(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool, ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW); DEFINE_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool, ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA); + DEFINE_PROPERTY_REF_ENUM(PROP_RENDER_LAYER, RenderLayer, renderLayer, RenderLayer, RenderLayer::WORLD); DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup); // Physics diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 34f6402a22..77e14db3a0 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -39,6 +39,7 @@ enum EntityPropertyList { PROP_QUERY_AA_CUBE, PROP_CAN_CAST_SHADOW, PROP_VISIBLE_IN_SECONDARY_CAMERA, // not sent over wire + PROP_RENDER_LAYER, // Grab PROP_GRAB_GRABBABLE, PROP_GRAB_KINEMATIC, diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 41eaa0ded0..d9eb9d32fa 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::UpdatedPolyLines); + return static_cast(EntityVersion::LAST_PACKET_TYPE); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 1b031e80dc..904ed6045d 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -253,7 +253,12 @@ enum class EntityVersion : PacketVersion { MissingTextProperties, GrabTraits, MorePropertiesCleanup, - UpdatedPolyLines + UpdatedPolyLines, + RenderLayer, + + // Add new versions above here + NUM_PACKET_TYPE, + LAST_PACKET_TYPE = NUM_PACKET_TYPE - 1 }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index bd1abf8744..68c9f8e5f7 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -35,6 +35,7 @@ #include "MaterialMappingMode.h" #include "BillboardMode.h" +#include "RenderLayer.h" #include "OctreeConstants.h" #include "OctreeElement.h" @@ -263,6 +264,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, MaterialMappingMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, BillboardMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, RenderLayer& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9cefbf65a8..3ee9118252 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -925,30 +925,14 @@ bool Model::canCastShadow() const { return _renderItemKeyGlobalFlags.isShadowCaster(); } -void Model::setLayeredInFront(bool layeredInFront, const render::ScenePointer& scene) { - if (Model::isLayeredInFront() != layeredInFront) { +void Model::setHifiRenderLayer(render::hifi::Layer renderLayer, const render::ScenePointer& scene) { + if (_renderItemKeyGlobalFlags.getLayer() != renderLayer) { auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags); - _renderItemKeyGlobalFlags = (layeredInFront ? keyBuilder.withLayer(render::hifi::LAYER_3D_FRONT) : keyBuilder.withoutLayer()); + _renderItemKeyGlobalFlags = keyBuilder.withLayer(renderLayer); updateRenderItemsKey(scene); } } -bool Model::isLayeredInFront() const { - return _renderItemKeyGlobalFlags.isLayer(render::hifi::LAYER_3D_FRONT); -} - -void Model::setLayeredInHUD(bool layeredInHUD, const render::ScenePointer& scene) { - if (Model::isLayeredInHUD() != layeredInHUD) { - auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags); - _renderItemKeyGlobalFlags = (layeredInHUD ? keyBuilder.withLayer(render::hifi::LAYER_3D_HUD) : keyBuilder.withoutLayer()); - updateRenderItemsKey(scene); - } -} - -bool Model::isLayeredInHUD() const { - return _renderItemKeyGlobalFlags.isLayer(render::hifi::LAYER_3D_HUD); -} - void Model::setTagMask(uint8_t mask, const render::ScenePointer& scene) { if (Model::getTagMask() != mask) { auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 93a0626d28..9dec94e0d5 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -123,11 +123,7 @@ public: bool canCastShadow() const; void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene = nullptr); - void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene = nullptr); - void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene = nullptr); - - bool isLayeredInFront() const; - bool isLayeredInHUD() const; + void setHifiRenderLayer(render::hifi::Layer layer, const render::ScenePointer& scene = nullptr); // Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model. const render::ItemKey getRenderItemKeyGlobalFlags() const; diff --git a/libraries/shared/src/BillboardMode.cpp b/libraries/shared/src/BillboardMode.cpp index 56251f53f2..4b6af5db33 100644 --- a/libraries/shared/src/BillboardMode.cpp +++ b/libraries/shared/src/BillboardMode.cpp @@ -14,10 +14,10 @@ const char* billboardModeNames[] = { "full" }; -static const size_t MATERIAL_MODE_NAMES = (sizeof(billboardModeNames) / sizeof((billboardModeNames)[0])); +static const size_t BILLBOARD_MODE_NAMES = (sizeof(billboardModeNames) / sizeof(billboardModeNames[0])); QString BillboardModeHelpers::getNameForBillboardMode(BillboardMode mode) { - if (((int)mode <= 0) || ((int)mode >= (int)MATERIAL_MODE_NAMES)) { + if (((int)mode <= 0) || ((int)mode >= (int)BILLBOARD_MODE_NAMES)) { mode = (BillboardMode)0; } diff --git a/libraries/shared/src/MaterialMappingMode.cpp b/libraries/shared/src/MaterialMappingMode.cpp index 1ddad178a2..09a7cfd6d9 100644 --- a/libraries/shared/src/MaterialMappingMode.cpp +++ b/libraries/shared/src/MaterialMappingMode.cpp @@ -13,7 +13,7 @@ const char* materialMappingModeNames[] = { "projected" }; -static const size_t MATERIAL_MODE_NAMES = (sizeof(materialMappingModeNames) / sizeof((materialMappingModeNames)[0])); +static const size_t MATERIAL_MODE_NAMES = (sizeof(materialMappingModeNames) / sizeof(materialMappingModeNames[0])); QString MaterialMappingModeHelpers::getNameForMaterialMappingMode(MaterialMappingMode mode) { if (((int)mode <= 0) || ((int)mode >= (int)MATERIAL_MODE_NAMES)) { diff --git a/libraries/shared/src/RenderLayer.cpp b/libraries/shared/src/RenderLayer.cpp new file mode 100644 index 0000000000..7e072631e0 --- /dev/null +++ b/libraries/shared/src/RenderLayer.cpp @@ -0,0 +1,25 @@ +// +// Created by Sam Gondelman on 1/3/19 +// Copyright 2019 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 "RenderLayer.h" + +const char* renderLayerNames[] = { + "world", + "front", + "hud" +}; + +static const size_t RENDER_LAYER_NAMES = (sizeof(renderLayerNames) / sizeof(renderLayerNames[0])); + +QString RenderLayerHelpers::getNameForRenderLayer(RenderLayer mode) { + if (((int)mode <= 0) || ((int)mode >= (int)RENDER_LAYER_NAMES)) { + mode = (RenderLayer)0; + } + + return renderLayerNames[(int)mode]; +} \ No newline at end of file diff --git a/libraries/shared/src/RenderLayer.h b/libraries/shared/src/RenderLayer.h new file mode 100644 index 0000000000..b5bf885616 --- /dev/null +++ b/libraries/shared/src/RenderLayer.h @@ -0,0 +1,41 @@ +// +// Created by Sam Gondelman on 1/3/19. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_RenderLayer_h +#define hifi_RenderLayer_h + +#include "QString" + +/**jsdoc + *

In which layer an entity is rendered.

+ * + * + * + * + * + * + * + * + * + *
ValueDescription
worldThe entity will be drawn in the world with everything else.
frontThe entity will be drawn on top of the world layer, but behind the HUD sphere.
hudThe entity will be drawn on top of other layers and the HUD sphere.
+ * @typedef {string} RenderLayer + */ + +enum class RenderLayer { + WORLD = 0, + FRONT, + HUD +}; + +class RenderLayerHelpers { +public: + static QString getNameForRenderLayer(RenderLayer mode); +}; + +#endif // hifi_RenderLayer_h + From 1b5c1d06777fffc64563465854fc0df2b9c9a4ca Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 8 Jan 2019 10:02:03 -0800 Subject: [PATCH 03/46] working on primitiveMode and groupCulled --- .../src/RenderableEntityItem.cpp | 10 +++ .../src/RenderableEntityItem.h | 4 +- .../src/RenderableGridEntityItem.cpp | 4 ++ .../src/RenderableImageEntityItem.cpp | 4 ++ .../src/RenderableMaterialEntityItem.cpp | 4 ++ .../src/RenderableModelEntityItem.cpp | 18 +++++ .../src/RenderableModelEntityItem.h | 1 + .../RenderableParticleEffectEntityItem.cpp | 6 +- .../src/RenderablePolyLineEntityItem.cpp | 6 +- .../src/RenderablePolyVoxEntityItem.cpp | 6 +- .../src/RenderableShapeEntityItem.cpp | 10 ++- .../src/RenderableTextEntityItem.cpp | 3 + libraries/entities/src/EntityItem.cpp | 25 +++++++ libraries/entities/src/EntityItem.h | 4 ++ .../entities/src/EntityItemProperties.cpp | 65 +++++++++++++++++-- libraries/entities/src/EntityItemProperties.h | 3 + libraries/entities/src/EntityPropertyFlags.h | 20 +++--- libraries/entities/src/ModelEntityItem.cpp | 17 +++++ libraries/entities/src/ModelEntityItem.h | 4 ++ libraries/networking/src/udt/PacketHeaders.h | 2 +- libraries/octree/src/OctreePacketData.h | 2 + .../render-utils/src/CauterizedModel.cpp | 6 +- .../render-utils/src/MeshPartPayload.cpp | 3 +- libraries/render-utils/src/MeshPartPayload.h | 2 +- libraries/render-utils/src/Model.cpp | 25 ++++--- libraries/render-utils/src/Model.h | 7 +- libraries/shared/src/PrimitiveMode.cpp | 24 +++++++ libraries/shared/src/PrimitiveMode.h | 39 +++++++++++ 28 files changed, 284 insertions(+), 40 deletions(-) create mode 100644 libraries/shared/src/PrimitiveMode.cpp create mode 100644 libraries/shared/src/PrimitiveMode.h diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 8416e8d0e2..53e62ee35f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -159,6 +159,13 @@ Item::Bound EntityRenderer::getBound() { return _bound; } +ShapeKey EntityRenderer::getShapeKey() { + if (_primitiveMode == PrimitiveMode::LINES) { + return ShapeKey::Builder().withOwnPipeline().withWireframe(); + } + return ShapeKey::Builder().withOwnPipeline(); +} + render::hifi::Tag EntityRenderer::getTagMask() const { return _isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW; } @@ -171,6 +178,8 @@ render::hifi::Layer EntityRenderer::getHifiRenderLayer() const { return render::hifi::LAYER_3D_FRONT; case RenderLayer::HUD: return render::hifi::LAYER_3D_HUD; + default: + return render::hifi::LAYER_3D; } } @@ -423,6 +432,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa _visible = entity->getVisible(); setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera()); setRenderLayer(entity->getRenderLayer()); + setPrimitiveMode(entity->getPrimitiveMode()); _canCastShadow = entity->getCanCastShadow(); _cauterized = entity->getCauterized(); _needsRenderUpdate = false; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 1c83aecdbe..fde63f78fa 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -72,7 +72,7 @@ protected: // Implementing the PayloadProxyInterface methods virtual ItemKey getKey() override; - virtual ShapeKey getShapeKey() override { return ShapeKey::Builder::ownPipeline(); } + virtual ShapeKey getShapeKey() override; virtual Item::Bound getBound() override; virtual void render(RenderArgs* args) override final; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override; @@ -105,6 +105,7 @@ protected: virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; } + virtual void setPrimitiveMode(PrimitiveMode value) { _primitiveMode = value; } template T withReadLockResult(const std::function& f) { @@ -139,6 +140,7 @@ protected: bool _isVisibleInSecondaryCamera { false }; bool _canCastShadow { false }; RenderLayer _renderLayer { RenderLayer::WORLD }; + PrimitiveMode _primitiveMode { PrimitiveMode::SOLID }; bool _cauterized { false }; bool _moving { false }; bool _needsRenderUpdate { false }; diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp index 22cf72cec6..4576358699 100644 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp @@ -97,6 +97,10 @@ ShapeKey GridEntityRenderer::getShapeKey() { builder.withTranslucent(); } + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } + return builder.build(); } diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index 7c5b7fc0da..c1d6d3211d 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -123,6 +123,10 @@ ShapeKey ImageEntityRenderer::getShapeKey() { if (_emissive) { builder.withUnlit(); } + + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } }); return builder.build(); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 8cc1b0f193..483f9ffe1c 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -98,6 +98,10 @@ ShapeKey MaterialEntityRenderer::getShapeKey() { builder.withUnlit(); } + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } + return builder.build(); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 255446287d..6cde85bed0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1290,6 +1290,10 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin model->getRegistrationPoint() != entity->getRegistrationPoint()) { return true; } + + if (model->isGroupCulled() != entity->getGroupCulled()) { + return true; + } } return false; @@ -1434,6 +1438,13 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce model->setCanCastShadow(_canCastShadow, scene); } + { + bool groupCulled = entity->getGroupCulled(); + if (model->isGroupCulled() != groupCulled) { + model->setGroupCulled(groupCulled); + } + } + { DETAILED_PROFILE_RANGE(simulation_physics, "Fixup"); if (model->needsFixupInScene()) { @@ -1504,6 +1515,13 @@ void ModelEntityRenderer::setRenderLayer(RenderLayer value) { } } +void ModelEntityRenderer::setPrimitiveMode(PrimitiveMode value) { + Parent::setPrimitiveMode(value); + if (_model) { + _model->setPrimitiveMode(_primitiveMode); + } +} + // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items void ModelEntityRenderer::doRender(RenderArgs* args) { DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender"); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index cd4b636e33..ff266e14bb 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -170,6 +170,7 @@ protected: void setIsVisibleInSecondaryCamera(bool value) override; void setRenderLayer(RenderLayer value) override; + void setPrimitiveMode(PrimitiveMode value) override; private: void animate(const TypedEntityPointer& entity); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 8f6fd5383e..351d72baf5 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -166,7 +166,11 @@ ItemKey ParticleEffectEntityRenderer::getKey() { } ShapeKey ParticleEffectEntityRenderer::getShapeKey() { - return ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER).withTranslucent().build(); + auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER).withTranslucent(); + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } + return builder.build(); } Item::Bound ParticleEffectEntityRenderer::getBound() { diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index aaf2b58bea..68371e4e13 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -59,7 +59,11 @@ ItemKey PolyLineEntityRenderer::getKey() { } ShapeKey PolyLineEntityRenderer::getShapeKey() { - return ShapeKey::Builder().withOwnPipeline().withTranslucent().withoutCullFace(); + auto builder = ShapeKey::Builder().withOwnPipeline().withTranslucent().withoutCullFace(); + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } + return builder.build(); } bool PolyLineEntityRenderer::needsRenderUpdate() const { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 514ed3cec1..183d2881f3 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1613,7 +1613,11 @@ PolyVoxEntityRenderer::PolyVoxEntityRenderer(const EntityItemPointer& entity) : } ShapeKey PolyVoxEntityRenderer::getShapeKey() { - return ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER).build(); + auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER); + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } + return builder.build(); } bool PolyVoxEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 1569c75eec..978341bb39 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -186,6 +186,10 @@ ShapeKey ShapeEntityRenderer::getShapeKey() { builder.withUnlit(); } + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } + return builder.build(); } else { ShapeKey::Builder builder; @@ -198,6 +202,10 @@ ShapeKey ShapeEntityRenderer::getShapeKey() { if (isTransparent()) { builder.withTranslucent(); } + + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } return builder.build(); } } @@ -242,7 +250,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { // FIXME, support instanced multi-shape rendering using multidraw indirect outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); - if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { + if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) { geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline); } else { geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 4ddb398fbf..d7da8e7e1a 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -49,6 +49,9 @@ ShapeKey TextEntityRenderer::getShapeKey() { if (isTransparent()) { builder.withTranslucent(); } + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } return builder.build(); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1a32b414c7..cf97e43b5f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -95,6 +95,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_CAN_CAST_SHADOW; // requestedProperties += PROP_VISIBLE_IN_SECONDARY_CAMERA; // not sent over the wire requestedProperties += PROP_RENDER_LAYER; + requestedProperties += PROP_PRIMITIVE_MODE; withReadLock([&] { requestedProperties += _grabProperties.getEntityProperties(params); }); @@ -277,6 +278,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, getCanCastShadow()); // APPEND_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, getIsVisibleInSecondaryCamera()); // not sent over the wire APPEND_ENTITY_PROPERTY(PROP_RENDER_LAYER, (uint32_t)getRenderLayer()); + APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)getPrimitiveMode()); withReadLock([&] { _grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); @@ -841,6 +843,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); // READ_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, bool, setIsVisibleInSecondaryCamera); // not sent over the wire READ_ENTITY_PROPERTY(PROP_RENDER_LAYER, RenderLayer, setRenderLayer); + READ_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode); withWriteLock([&] { int bytesFromGrab = _grabProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, @@ -1313,6 +1316,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire COPY_ENTITY_PROPERTY_TO_PROPERTIES(canCastShadow, getCanCastShadow); COPY_ENTITY_PROPERTY_TO_PROPERTIES(isVisibleInSecondaryCamera, isVisibleInSecondaryCamera); COPY_ENTITY_PROPERTY_TO_PROPERTIES(renderLayer, getRenderLayer); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(primitiveMode, getPrimitiveMode); withReadLock([&] { _grabProperties.getProperties(properties); }); @@ -1458,6 +1462,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(canCastShadow, setCanCastShadow); SET_ENTITY_PROPERTY_FROM_PROPERTIES(isVisibleInSecondaryCamera, setIsVisibleInSecondaryCamera); SET_ENTITY_PROPERTY_FROM_PROPERTIES(renderLayer, setRenderLayer); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(primitiveMode, setPrimitiveMode); withWriteLock([&] { bool grabPropertiesChanged = _grabProperties.setProperties(properties); somethingChanged |= grabPropertiesChanged; @@ -2912,6 +2917,26 @@ void EntityItem::setRenderLayer(RenderLayer value) { } } +PrimitiveMode EntityItem::getPrimitiveMode() const { + return resultWithReadLock([&] { + return _primitiveMode; + }); +} + +void EntityItem::setPrimitiveMode(PrimitiveMode value) { + bool changed = false; + withWriteLock([&] { + if (_primitiveMode != value) { + changed = true; + _primitiveMode = value; + } + }); + + if (changed) { + emit requestRenderUpdate(); + } +} + bool EntityItem::getCanCastShadow() const { bool result; withReadLock([&] { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5053389a7b..cac4192cd5 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -296,6 +296,9 @@ public: RenderLayer getRenderLayer() const; void setRenderLayer(RenderLayer value); + PrimitiveMode getPrimitiveMode() const; + void setPrimitiveMode(PrimitiveMode value); + bool getCanCastShadow() const; void setCanCastShadow(bool value); @@ -625,6 +628,7 @@ protected: bool _visible { ENTITY_ITEM_DEFAULT_VISIBLE }; bool _isVisibleInSecondaryCamera { ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA }; RenderLayer _renderLayer { RenderLayer::WORLD }; + PrimitiveMode _primitiveMode { PrimitiveMode::SOLID }; bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW }; bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS }; uint16_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index fee0935955..647861120c 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -328,11 +328,11 @@ QString EntityItemProperties::getBillboardModeAsString() const { return BillboardModeHelpers::getNameForBillboardMode(_billboardMode); } -void EntityItemProperties::setBillboardModeFromString(const QString& materialMappingMode) { +void EntityItemProperties::setBillboardModeFromString(const QString& billboardMode) { if (stringToBillboardModeLookup.empty()) { buildStringToBillboardModeLookup(); } - auto billboardModeItr = stringToBillboardModeLookup.find(materialMappingMode.toLower()); + auto billboardModeItr = stringToBillboardModeLookup.find(billboardMode.toLower()); if (billboardModeItr != stringToBillboardModeLookup.end()) { _billboardMode = billboardModeItr.value(); _billboardModeChanged = true; @@ -355,17 +355,43 @@ QString EntityItemProperties::getRenderLayerAsString() const { return RenderLayerHelpers::getNameForRenderLayer(_renderLayer); } -void EntityItemProperties::setRenderLayerFromString(const QString& materialMappingMode) { +void EntityItemProperties::setRenderLayerFromString(const QString& renderLayer) { if (stringToRenderLayerLookup.empty()) { buildStringToRenderLayerLookup(); } - auto renderLayerItr = stringToRenderLayerLookup.find(materialMappingMode.toLower()); + auto renderLayerItr = stringToRenderLayerLookup.find(renderLayer.toLower()); if (renderLayerItr != stringToRenderLayerLookup.end()) { _renderLayer = renderLayerItr.value(); _renderLayerChanged = true; } } +QHash stringToPrimitiveModeLookup; + +void addPrimitiveMode(PrimitiveMode mode) { + stringToPrimitiveModeLookup[PrimitiveModeHelpers::getNameForPrimitiveMode(mode)] = mode; +} + +void buildStringToPrimitiveModeLookup() { + addPrimitiveMode(PrimitiveMode::SOLID); + addPrimitiveMode(PrimitiveMode::LINES); +} + +QString EntityItemProperties::getPrimitiveModeAsString() const { + return PrimitiveModeHelpers::getNameForPrimitiveMode(_primitiveMode); +} + +void EntityItemProperties::setPrimitiveModeFromString(const QString& primitiveMode) { + if (stringToPrimitiveModeLookup.empty()) { + buildStringToPrimitiveModeLookup(); + } + auto primitiveModeItr = stringToPrimitiveModeLookup.find(primitiveMode.toLower()); + if (primitiveModeItr != stringToPrimitiveModeLookup.end()) { + _primitiveMode = primitiveModeItr.value(); + _primitiveModeChanged = true; + } +} + EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; @@ -391,6 +417,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_CAN_CAST_SHADOW, canCastShadow); CHECK_PROPERTY_CHANGE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); CHECK_PROPERTY_CHANGE(PROP_RENDER_LAYER, renderLayer); + CHECK_PROPERTY_CHANGE(PROP_PRIMITIVE_MODE, primitiveMode); changedProperties += _grab.getChangedProperties(); // Physics @@ -490,6 +517,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS, jointTranslations); CHECK_PROPERTY_CHANGE(PROP_RELAY_PARENT_JOINTS, relayParentJoints); + CHECK_PROPERTY_CHANGE(PROP_GROUP_CULLED, groupCulled); changedProperties += _animation.getChangedProperties(); // Light @@ -595,15 +623,15 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * the shape property set for entities of these types.) Read-only. * @property {EntityHostType} entityHostType="domain" - How this entity will behave, including if and how it is sent to other people. * The value can only be set at entity creation by using the entityHostType parameter in - * {@link Entities.addEntity}. + * {@link Entities.addEntity}. Read-only. * @property {boolean} avatarEntity=false - If true then the entity is an avatar entity; An avatar entity follows you to each domain you visit, * rendering at the same world coordinates unless it's parented to your avatar. Value cannot be changed after the entity is created.
* The value can only be set at entity creation by using the entityHostType parameter in - * {@link Entities.addEntity}. clientOnly is an alias. + * {@link Entities.addEntity}. clientOnly is an alias. Read-only. * @property {boolean} localEntity=false - If true then the entity is a local entity; Local entities only render for you and are not sent over the wire. * Value cannot be changed after the entity is created.
* The value can only be set at entity creation by using the entityHostType parameter in - * {@link Entities.addEntity}. + * {@link Entities.addEntity}. Read-only. * @property {Uuid} owningAvatarID=Uuid.NULL - The session ID of the owning avatar if avatarEntity is * true, otherwise {@link Uuid|Uuid.NULL}. Read-only. * @@ -628,6 +656,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * {@link Entities.EntityProperties-Zone|keyLight} property. * @property {boolean} isVisibleInSecondaryCamera=true - Whether or not the entity is rendered in the secondary camera. If true then the entity is rendered. * @property {RenderLayer} renderLayer="world" - In which layer this entity renders. + * @property {PrimitiveMode} primitiveMode="solid" - How this entity's geometry is rendered. * * @property {Vec3} position=0,0,0 - The position of the entity. * @property {Quat} rotation=0,0,0,1 - The orientation of the entity with respect to world coordinates. @@ -942,6 +971,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * {@link Entities.getJointIndex|getJointIndex}. * @property {boolean} relayParentJoints=false - If true and the entity is parented to an avatar, then the * avatar's joint rotations are applied to the entity's joints. + * @property {boolean} groupCulled=false - If true, the mesh parts of the model are LOD culled as a group. + * If false, separate mesh parts will be LOD culled individually. * * @example Rez a Vive tracker puck. * var entity = Entities.addEntity({ @@ -1434,6 +1465,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CAN_CAST_SHADOW, canCastShadow); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_RENDER_LAYER, renderLayer, getRenderLayerAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_PRIMITIVE_MODE, primitiveMode, getPrimitiveModeAsString()); _grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); // Physics @@ -1550,6 +1582,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS, jointTranslations); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RELAY_PARENT_JOINTS, relayParentJoints); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GROUP_CULLED, groupCulled); if (!psuedoPropertyFlagsButDesiredEmpty) { _animation.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); } @@ -1816,6 +1849,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(canCastShadow, bool, setCanCastShadow); COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(renderLayer, RenderLayer); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(primitiveMode, PrimitiveMode); _grab.copyFromScriptValue(object, _defaultSettings); // Physics @@ -1920,6 +1954,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(jointTranslationsSet, qVectorBool, setJointTranslationsSet); COPY_PROPERTY_FROM_QSCRIPTVALUE(jointTranslations, qVectorVec3, setJointTranslations); COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); + COPY_PROPERTY_FROM_QSCRIPTVALUE(groupCulled, bool, setGroupCulled); _animation.copyFromScriptValue(object, _defaultSettings); // Light @@ -2076,6 +2111,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(canCastShadow); COPY_PROPERTY_IF_CHANGED(isVisibleInSecondaryCamera); COPY_PROPERTY_IF_CHANGED(renderLayer); + COPY_PROPERTY_IF_CHANGED(primitiveMode); _grab.merge(other._grab); // Physics @@ -2175,6 +2211,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(jointTranslationsSet); COPY_PROPERTY_IF_CHANGED(jointTranslations); COPY_PROPERTY_IF_CHANGED(relayParentJoints); + COPY_PROPERTY_IF_CHANGED(groupCulled); _animation.merge(other._animation); // Light @@ -2330,6 +2367,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool); ADD_PROPERTY_TO_MAP(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool); ADD_PROPERTY_TO_MAP(PROP_RENDER_LAYER, RenderLayer, renderLayer, RenderLayer); + ADD_PROPERTY_TO_MAP(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode); { // Grab ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable); ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic); @@ -2453,6 +2491,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector); ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS, JointTranslations, jointTranslations, QVector); ADD_PROPERTY_TO_MAP(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool); + ADD_PROPERTY_TO_MAP(PROP_GROUP_CULLED, GroupCulled, groupCulled, bool); { // Animation ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_URL, Animation, animation, URL, url); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation); @@ -2722,6 +2761,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, properties.getCanCastShadow()); // APPEND_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, properties.getIsVisibleInSecondaryCamera()); // not sent over the wire APPEND_ENTITY_PROPERTY(PROP_RENDER_LAYER, (uint32_t)properties.getRenderLayer()); + APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)properties.getPrimitiveMode()); _staticGrab.setProperties(properties); _staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); @@ -2828,6 +2868,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, properties.getJointTranslationsSet()); APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, properties.getJointTranslations()); APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, properties.getRelayParentJoints()); + APPEND_ENTITY_PROPERTY(PROP_GROUP_CULLED, properties.getGroupCulled()); _staticAnimation.setProperties(properties); _staticAnimation.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); @@ -3164,6 +3205,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); // READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE_IN_SECONDARY_CAMERA, bool, setIsVisibleInSecondaryCamera); // not sent over the wire READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_LAYER, RenderLayer, setRenderLayer); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode); properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); // Physics @@ -3268,6 +3310,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS, QVector, setJointTranslations); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GROUP_CULLED, bool, setGroupCulled); properties.getAnimation().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); } @@ -3547,6 +3590,7 @@ void EntityItemProperties::markAllChanged() { _canCastShadowChanged = true; _isVisibleInSecondaryCameraChanged = true; _renderLayerChanged = true; + _primitiveModeChanged = true; _grab.markAllChanged(); // Physics @@ -3639,6 +3683,7 @@ void EntityItemProperties::markAllChanged() { _jointTranslationsSetChanged = true; _jointTranslationsChanged = true; _relayParentJointsChanged = true; + _groupCulledChanged = true; _animation.markAllChanged(); // Light @@ -3922,6 +3967,9 @@ QList EntityItemProperties::listChangedProperties() { if (renderLayerChanged()) { out += "renderLayer"; } + if (primitiveModeChanged()) { + out += "primitiveMode"; + } getGrab().listChangedProperties(out); // Physics @@ -4168,6 +4216,9 @@ QList EntityItemProperties::listChangedProperties() { if (relayParentJointsChanged()) { out += "relayParentJoints"; } + if (groupCulledChanged()) { + out += "groupCulled"; + } getAnimation().listChangedProperties(out); // Light diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index a7992ea1ab..524f72f5b7 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -52,6 +52,7 @@ #include "MaterialMappingMode.h" #include "BillboardMode.h" #include "RenderLayer.h" +#include "PrimitiveMode.h" const quint64 UNKNOWN_CREATED_TIME = 0; @@ -152,6 +153,7 @@ public: DEFINE_PROPERTY(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool, ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW); DEFINE_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool, ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA); DEFINE_PROPERTY_REF_ENUM(PROP_RENDER_LAYER, RenderLayer, renderLayer, RenderLayer, RenderLayer::WORLD); + DEFINE_PROPERTY_REF_ENUM(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode, PrimitiveMode::SOLID); DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup); // Physics @@ -251,6 +253,7 @@ public: DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector, QVector()); DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS, JointTranslations, jointTranslations, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS); + DEFINE_PROPERTY_REF(PROP_GROUP_CULLED, GroupCulled, groupCulled, bool, false); DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup); // Light diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 9d9e7ffa01..a3d0d937cb 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -40,6 +40,7 @@ enum EntityPropertyList { PROP_CAN_CAST_SHADOW, PROP_VISIBLE_IN_SECONDARY_CAMERA, // not sent over the wire PROP_RENDER_LAYER, + PROP_PRIMITIVE_MODE, // Grab PROP_GRAB_GRABBABLE, PROP_GRAB_KINEMATIC, @@ -199,16 +200,17 @@ enum EntityPropertyList { 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, // Animation - PROP_ANIMATION_URL = PROP_DERIVED_6, - PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_7, - PROP_ANIMATION_FPS = PROP_DERIVED_8, - PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_9, - PROP_ANIMATION_PLAYING = PROP_DERIVED_10, - PROP_ANIMATION_LOOP = PROP_DERIVED_11, - PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_12, - PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_13, - PROP_ANIMATION_HOLD = PROP_DERIVED_14, + 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, // Light PROP_IS_SPOTLIGHT = PROP_DERIVED_0, diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 55ae1c6c3b..ddbb028b6e 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -67,6 +67,7 @@ EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& d COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointTranslationsSet, getJointTranslationsSet); COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointTranslations, getJointTranslations); COPY_ENTITY_PROPERTY_TO_PROPERTIES(relayParentJoints, getRelayParentJoints); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(groupCulled, getGroupCulled); withReadLock([&] { _animationProperties.getProperties(properties); }); @@ -88,6 +89,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslationsSet, setJointTranslationsSet); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslations, setJointTranslations); SET_ENTITY_PROPERTY_FROM_PROPERTIES(relayParentJoints, setRelayParentJoints); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(groupCulled, setGroupCulled); withWriteLock([&] { AnimationPropertyGroup animationProperties = _animationProperties; @@ -130,6 +132,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, QVector, setJointTranslations); READ_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints); + READ_ENTITY_PROPERTY(PROP_GROUP_CULLED, bool, setGroupCulled); // grab a local copy of _animationProperties to avoid multiple locks int bytesFromAnimation; @@ -166,6 +169,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& requestedProperties += PROP_JOINT_TRANSLATIONS_SET; requestedProperties += PROP_JOINT_TRANSLATIONS; requestedProperties += PROP_RELAY_PARENT_JOINTS; + requestedProperties += PROP_GROUP_CULLED; requestedProperties += _animationProperties.getEntityProperties(params); return requestedProperties; @@ -192,6 +196,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, getJointTranslationsSet()); APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, getJointTranslations()); APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, getRelayParentJoints()); + APPEND_ENTITY_PROPERTY(PROP_GROUP_CULLED, getGroupCulled()); withReadLock([&] { _animationProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -548,6 +553,18 @@ bool ModelEntityItem::getRelayParentJoints() const { }); } +void ModelEntityItem::setGroupCulled(bool value) { + withWriteLock([&] { + _groupCulled = value; + }); +} + +bool ModelEntityItem::getGroupCulled() const { + return resultWithReadLock([&] { + return _groupCulled; + }); +} + QString ModelEntityItem::getCompoundShapeURL() const { return _compoundShapeURL.get(); } diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 5ca3e2caa1..8c9fbdc45f 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -100,6 +100,9 @@ public: void setRelayParentJoints(bool relayJoints); bool getRelayParentJoints() const; + void setGroupCulled(bool value); + bool getGroupCulled() const; + bool getAnimationIsPlaying() const; float getAnimationCurrentFrame() const; float getAnimationFPS() const; @@ -154,6 +157,7 @@ protected: glm::u8vec3 _color; QString _modelURL; bool _relayParentJoints; + bool _groupCulled { false }; ThreadSafeValueCache _compoundShapeURL; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index c57e1966b9..b7f8dffa13 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -255,7 +255,7 @@ enum class EntityVersion : PacketVersion { MorePropertiesCleanup, FixPropertiesFromCleanup, UpdatedPolyLines, - RenderLayer, + MigrateOverlayRenderProperties, // Add new versions above here NUM_PACKET_TYPE, diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 68c9f8e5f7..debc6786f1 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -36,6 +36,7 @@ #include "MaterialMappingMode.h" #include "BillboardMode.h" #include "RenderLayer.h" +#include "PrimitiveMode.h" #include "OctreeConstants.h" #include "OctreeElement.h" @@ -265,6 +266,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, MaterialMappingMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, BillboardMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, RenderLayer& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, PrimitiveMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result); diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 3e32d19b49..81a81c5602 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -215,7 +215,7 @@ void CauterizedModel::updateRenderItems() { modelTransform.setTranslation(self->getTranslation()); modelTransform.setRotation(self->getRotation()); - bool isWireframe = self->isWireframe(); + PrimitiveMode primitiveMode = self->getPrimitiveMode(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); bool enableCauterization = self->getEnableCauterization(); @@ -232,7 +232,7 @@ void CauterizedModel::updateRenderItems() { bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, - isWireframe, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) { + primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) { CauterizedMeshPartPayload& data = static_cast(mmppData); if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions, @@ -276,7 +276,7 @@ void CauterizedModel::updateRenderItems() { data.setEnableCauterization(enableCauterization); data.updateKey(renderItemKeyGlobalFlags); - data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); + data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index ca2e56862d..7a52ad77da 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -342,7 +342,7 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { _itemKey = builder.build(); } -void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning) { +void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode primitiveMode, bool useDualQuaternionSkinning) { if (invalidateShapeKey) { _shapeKey = ShapeKey::Builder::invalid(); return; @@ -359,6 +359,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe bool isUnlit = drawMaterialKey.isUnlit(); bool isDeformed = _isBlendShaped || _isSkinned; + bool isWireframe = primitiveMode == PrimitiveMode::LINES; if (isWireframe) { isTranslucent = hasTangents = hasLightmap = false; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 29c0091f11..3b0590b4a9 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -109,7 +109,7 @@ public: render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) override; - void setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning); + void setShapeKey(bool invalidateShapeKey, PrimitiveMode primitiveMode, bool useDualQuaternionSkinning); // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3ee9118252..ed9f7f1a3d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -62,7 +62,6 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : _snapModelToRegistrationPoint(false), _snappedToRegistrationPoint(false), _url(HTTP_INVALID_COM), - _isWireframe(false), _renderItemKeyGlobalFlags(render::ItemKey::Builder().withVisible().withTagBits(render::hifi::TAG_ALL_VIEWS).build()) { // we may have been created in the network thread, but we live in the main thread @@ -223,7 +222,7 @@ void Model::updateRenderItems() { Transform modelTransform = self->getTransform(); modelTransform.setScale(glm::vec3(1.0f)); - bool isWireframe = self->isWireframe(); + PrimitiveMode primitiveMode = self->getPrimitiveMode(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); render::Transaction transaction; @@ -238,7 +237,7 @@ void Model::updateRenderItems() { bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, - invalidatePayloadShapeKey, isWireframe, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) { + invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); } else { @@ -263,7 +262,7 @@ void Model::updateRenderItems() { data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateKey(renderItemKeyGlobalFlags); - data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); + data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); } @@ -276,6 +275,11 @@ void Model::setRenderItemsNeedUpdate() { emit requestRenderUpdate(); } +void Model::setPrimitiveMode(PrimitiveMode primitiveMode) { + _primitiveMode = primitiveMode; + setRenderItemsNeedUpdate(); +} + void Model::reset() { if (isLoaded()) { const HFMModel& hfmModel = getHFMModel(); @@ -951,6 +955,7 @@ void Model::setGroupCulled(bool groupCulled, const render::ScenePointer& scene) updateRenderItemsKey(scene); } } + bool Model::isGroupCulled() const { return _renderItemKeyGlobalFlags.isSubMetaCulled(); } @@ -1545,16 +1550,16 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par if (shapeID < _modelMeshRenderItemIDs.size()) { auto itemID = _modelMeshRenderItemIDs[shapeID]; auto renderItemsKey = _renderItemKeyGlobalFlags; - bool wireframe = isWireframe(); + PrimitiveMode primitiveMode = getPrimitiveMode(); auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; transaction.updateItem(itemID, [material, renderItemsKey, - invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { + invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) { data.addMaterial(material); // if the material changed, we might need to update our item key or shape key data.updateKey(renderItemsKey); - data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning); + data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); } } @@ -1568,16 +1573,16 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string if (shapeID < _modelMeshRenderItemIDs.size()) { auto itemID = _modelMeshRenderItemIDs[shapeID]; auto renderItemsKey = _renderItemKeyGlobalFlags; - bool wireframe = isWireframe(); + PrimitiveMode primitiveMode = getPrimitiveMode(); auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; transaction.updateItem(itemID, [material, renderItemsKey, - invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { + invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) { data.removeMaterial(material); // if the material changed, we might need to update our item key or shape key data.updateKey(renderItemsKey); - data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning); + data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 9dec94e0d5..08ba13b714 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -37,6 +37,7 @@ #include "GeometryCache.h" #include "TextureCache.h" #include "Rig.h" +#include "PrimitiveMode.h" // Use dual quaternion skinning! // Must match define in Skinning.slh @@ -162,8 +163,8 @@ public: bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isHFMModelLoaded(); } bool isAddedToScene() const { return _addedToScene; } - void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } - bool isWireframe() const { return _isWireframe; } + void setPrimitiveMode(PrimitiveMode primitiveMode); + PrimitiveMode getPrimitiveMode() const { return _primitiveMode; } void reset(); @@ -451,7 +452,7 @@ protected: virtual void createRenderItemSet(); - bool _isWireframe; + PrimitiveMode _primitiveMode { PrimitiveMode::SOLID }; bool _useDualQuaternionSkinning { false }; // debug rendering support diff --git a/libraries/shared/src/PrimitiveMode.cpp b/libraries/shared/src/PrimitiveMode.cpp new file mode 100644 index 0000000000..c426f896b9 --- /dev/null +++ b/libraries/shared/src/PrimitiveMode.cpp @@ -0,0 +1,24 @@ +// +// Created by Sam Gondelman on 1/7/19 +// Copyright 2019 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 "PrimitiveMode.h" + +const char* primitiveModeNames[] = { + "solid", + "lines" +}; + +static const size_t PRIMITIVE_MODE_NAMES = (sizeof(primitiveModeNames) / sizeof(primitiveModeNames[0])); + +QString PrimitiveModeHelpers::getNameForPrimitiveMode(PrimitiveMode mode) { + if (((int)mode <= 0) || ((int)mode >= (int)PRIMITIVE_MODE_NAMES)) { + mode = (PrimitiveMode)0; + } + + return primitiveModeNames[(int)mode]; +} \ No newline at end of file diff --git a/libraries/shared/src/PrimitiveMode.h b/libraries/shared/src/PrimitiveMode.h new file mode 100644 index 0000000000..6072f24fb9 --- /dev/null +++ b/libraries/shared/src/PrimitiveMode.h @@ -0,0 +1,39 @@ +// +// Created by Sam Gondelman on 1/7/19. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_PrimitiveMode_h +#define hifi_PrimitiveMode_h + +#include "QString" + +/**jsdoc + *

How the geometry of the entity is rendered.

+ * + * + * + * + * + * + * + * + *
ValueDescription
solidThe entity will be drawn as a solid shape.
linesThe entity will be drawn as wireframe.
+ * @typedef {string} PrimitiveMode + */ + +enum class PrimitiveMode { + SOLID = 0, + LINES +}; + +class PrimitiveModeHelpers { +public: + static QString getNameForPrimitiveMode(PrimitiveMode mode); +}; + +#endif // hifi_PrimitiveMode_h + From 5dd59dd9e9cd672a454be5ce91b3d5e748ebb682 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 8 Jan 2019 14:02:57 -0800 Subject: [PATCH 04/46] correct lighting of layered shapes --- .../src/RenderableShapeEntityItem.cpp | 7 ++- libraries/render-utils/src/GeometryCache.cpp | 53 +++++++++++++------ libraries/render-utils/src/GeometryCache.h | 12 ++++- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 978341bb39..c47904213b 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -249,7 +249,12 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { } else if (!useMaterialPipeline()) { // FIXME, support instanced multi-shape rendering using multidraw indirect outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; - auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); + render::ShapePipelinePointer pipeline; + if (_renderLayer == RenderLayer::WORLD) { + pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); + } else { + pipeline = outColor.a < 1.0f ? geometryCache->getForwardTransparentShapePipeline() : geometryCache->getForwardOpaqueShapePipeline(); + } if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) { geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline); } else { diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index d6d6f4903e..02f51e558a 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -721,11 +721,16 @@ QHash GeometryCache::_simplePrograms; gpu::ShaderPointer GeometryCache::_simpleShader; gpu::ShaderPointer GeometryCache::_transparentShader; gpu::ShaderPointer GeometryCache::_unlitShader; +gpu::ShaderPointer GeometryCache::_forwardSimpleShader; +gpu::ShaderPointer GeometryCache::_forwardTransparentShader; +gpu::ShaderPointer GeometryCache::_forwardUnlitShader; gpu::ShaderPointer GeometryCache::_simpleFadeShader; gpu::ShaderPointer GeometryCache::_unlitFadeShader; render::ShapePipelinePointer GeometryCache::_simpleOpaquePipeline; render::ShapePipelinePointer GeometryCache::_simpleTransparentPipeline; +render::ShapePipelinePointer GeometryCache::_forwardSimpleOpaquePipeline; +render::ShapePipelinePointer GeometryCache::_forwardSimpleTransparentPipeline; render::ShapePipelinePointer GeometryCache::_simpleOpaqueFadePipeline; render::ShapePipelinePointer GeometryCache::_simpleTransparentFadePipeline; render::ShapePipelinePointer GeometryCache::_simpleWirePipeline; @@ -805,6 +810,8 @@ void GeometryCache::initializeShapePipelines() { if (!_simpleOpaquePipeline) { _simpleOpaquePipeline = getShapePipeline(false, false, true, false); _simpleTransparentPipeline = getShapePipeline(false, true, true, false); + _forwardSimpleOpaquePipeline = getShapePipeline(false, false, true, false, false, true); + _forwardSimpleTransparentPipeline = getShapePipeline(false, true, true, false, false, true); _simpleOpaqueFadePipeline = getFadingShapePipeline(false, false, false, false, false); _simpleTransparentFadePipeline = getFadingShapePipeline(false, true, false, false, false); _simpleWirePipeline = getShapePipeline(false, false, true, true); @@ -812,9 +819,9 @@ void GeometryCache::initializeShapePipelines() { } render::ShapePipelinePointer GeometryCache::getShapePipeline(bool textured, bool transparent, bool culled, - bool unlit, bool depthBias) { + bool unlit, bool depthBias, bool forward) { - return std::make_shared(getSimplePipeline(textured, transparent, culled, unlit, depthBias, false, true), nullptr, + return std::make_shared(getSimplePipeline(textured, transparent, culled, unlit, depthBias, false, true, forward), nullptr, [](const render::ShapePipeline& pipeline, gpu::Batch& batch, render::Args* args) { batch.setResourceTexture(gr::Texture::MaterialAlbedo, DependencyManager::get()->getWhiteTexture()); DependencyManager::get()->setupKeyLightBatch(args, batch); @@ -2165,6 +2172,7 @@ public: HAS_DEPTH_BIAS_FLAG, IS_FADING_FLAG, IS_ANTIALIASED_FLAG, + IS_FORWARD_FLAG, NUM_FLAGS, }; @@ -2177,6 +2185,7 @@ public: HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG), IS_FADING = (1 << IS_FADING_FLAG), IS_ANTIALIASED = (1 << IS_ANTIALIASED_FLAG), + IS_FORWARD = (1 << IS_FORWARD_FLAG), }; typedef unsigned short Flags; @@ -2189,6 +2198,7 @@ public: bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); } bool isFading() const { return isFlag(IS_FADING); } bool isAntiAliased() const { return isFlag(IS_ANTIALIASED); } + bool isForward() const { return isFlag(IS_FORWARD); } Flags _flags = 0; #if defined(__clang__) @@ -2200,9 +2210,9 @@ public: SimpleProgramKey(bool textured = false, bool transparent = false, bool culled = true, - bool unlit = false, bool depthBias = false, bool fading = false, bool isAntiAliased = true) { + bool unlit = false, bool depthBias = false, bool fading = false, bool isAntiAliased = true, bool forward = false) { _flags = (textured ? IS_TEXTURED : 0) | (transparent ? IS_TRANSPARENT : 0) | (culled ? IS_CULLED : 0) | - (unlit ? IS_UNLIT : 0) | (depthBias ? HAS_DEPTH_BIAS : 0) | (fading ? IS_FADING : 0) | (isAntiAliased ? IS_ANTIALIASED : 0); + (unlit ? IS_UNLIT : 0) | (depthBias ? HAS_DEPTH_BIAS : 0) | (fading ? IS_FADING : 0) | (isAntiAliased ? IS_ANTIALIASED : 0) | (forward ? IS_FORWARD : 0); } SimpleProgramKey(int bitmask) : _flags(bitmask) {} @@ -2255,8 +2265,8 @@ void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool tra } } -gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transparent, bool culled, bool unlit, bool depthBiased, bool fading, bool isAntiAliased) { - SimpleProgramKey config { textured, transparent, culled, unlit, depthBiased, fading, isAntiAliased }; +gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transparent, bool culled, bool unlit, bool depthBiased, bool fading, bool isAntiAliased, bool forward) { + SimpleProgramKey config { textured, transparent, culled, unlit, depthBiased, fading, isAntiAliased, forward }; // If the pipeline already exists, return it auto it = _simplePrograms.find(config); @@ -2269,13 +2279,20 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp static std::once_flag once; std::call_once(once, [&]() { using namespace shader::render_utils::program; - auto PS = DISABLE_DEFERRED ? forward_simple_textured : simple_textured; - // Use the forward pipeline for both here, otherwise transparents will be unlit - auto PSTransparent = DISABLE_DEFERRED ? forward_simple_textured_transparent : forward_simple_textured_transparent; - auto PSUnlit = DISABLE_DEFERRED ? forward_simple_textured_unlit : simple_textured_unlit; - _simpleShader = gpu::Shader::createProgram(PS); - _transparentShader = gpu::Shader::createProgram(PSTransparent); - _unlitShader = gpu::Shader::createProgram(PSUnlit); + + _forwardSimpleShader = gpu::Shader::createProgram(forward_simple_textured); + _forwardTransparentShader = gpu::Shader::createProgram(forward_simple_textured_transparent); + _forwardUnlitShader = gpu::Shader::createProgram(forward_simple_textured_unlit); + if (DISABLE_DEFERRED) { + _simpleShader = _forwardSimpleShader; + _transparentShader = _forwardTransparentShader; + _unlitShader = _forwardUnlitShader; + } else { + _simpleShader = gpu::Shader::createProgram(simple_textured); + // Use the forward pipeline for both here, otherwise transparents will be unlit + _transparentShader = gpu::Shader::createProgram(forward_simple_textured_transparent); + _unlitShader = gpu::Shader::createProgram(simple_textured_unlit); + } }); } else { static std::once_flag once; @@ -2308,8 +2325,14 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp PrepareStencil::testMaskDrawShapeNoAA(*state); } - gpu::ShaderPointer program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _unlitShader) : - (config.isFading() ? _simpleFadeShader : (config.isTransparent() ? _transparentShader : _simpleShader)); + gpu::ShaderPointer program; + if (config.isForward()) { + program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _forwardUnlitShader) : + (config.isFading() ? _simpleFadeShader : (config.isTransparent() ? _forwardTransparentShader : _forwardSimpleShader)); + } else { + program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _unlitShader) : + (config.isFading() ? _simpleFadeShader : (config.isTransparent() ? _transparentShader : _simpleShader)); + } gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); _simplePrograms.insert(config, pipeline); return pipeline; diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 589be4dcc1..e46bb4a899 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -174,7 +174,7 @@ public: bool unlit = false, bool depthBias = false, bool isAntiAliased = true); // Get the pipeline to render static geometry static gpu::PipelinePointer getSimplePipeline(bool textured = false, bool transparent = false, bool culled = true, - bool unlit = false, bool depthBias = false, bool fading = false, bool isAntiAliased = true); + bool unlit = false, bool depthBias = false, bool fading = false, bool isAntiAliased = true, bool forward = false); void bindWebBrowserProgram(gpu::Batch& batch, bool transparent = false); gpu::PipelinePointer getWebBrowserProgram(bool transparent); @@ -183,6 +183,8 @@ public: render::ShapePipelinePointer getOpaqueShapePipeline() { assert(_simpleOpaquePipeline != nullptr); return _simpleOpaquePipeline; } render::ShapePipelinePointer getTransparentShapePipeline() { assert(_simpleTransparentPipeline != nullptr); return _simpleTransparentPipeline; } + render::ShapePipelinePointer getForwardOpaqueShapePipeline() { assert(_forwardSimpleOpaquePipeline != nullptr); return _forwardSimpleOpaquePipeline; } + render::ShapePipelinePointer getForwardTransparentShapePipeline() { assert(_forwardSimpleTransparentPipeline != nullptr); return _forwardSimpleTransparentPipeline; } render::ShapePipelinePointer getOpaqueFadeShapePipeline() { assert(_simpleOpaqueFadePipeline != nullptr); return _simpleOpaqueFadePipeline; } render::ShapePipelinePointer getTransparentFadeShapePipeline() { assert(_simpleTransparentFadePipeline != nullptr); return _simpleTransparentFadePipeline; } render::ShapePipelinePointer getOpaqueShapePipeline(bool isFading); @@ -465,13 +467,19 @@ private: QHash _lastRegisteredGridBuffer; QHash _registeredGridBuffers; + // FIXME: clean these up static gpu::ShaderPointer _simpleShader; static gpu::ShaderPointer _transparentShader; static gpu::ShaderPointer _unlitShader; + static gpu::ShaderPointer _forwardSimpleShader; + static gpu::ShaderPointer _forwardTransparentShader; + static gpu::ShaderPointer _forwardUnlitShader; static gpu::ShaderPointer _simpleFadeShader; static gpu::ShaderPointer _unlitFadeShader; static render::ShapePipelinePointer _simpleOpaquePipeline; static render::ShapePipelinePointer _simpleTransparentPipeline; + static render::ShapePipelinePointer _forwardSimpleOpaquePipeline; + static render::ShapePipelinePointer _forwardSimpleTransparentPipeline; static render::ShapePipelinePointer _simpleOpaqueFadePipeline; static render::ShapePipelinePointer _simpleTransparentFadePipeline; static render::ShapePipelinePointer _simpleWirePipeline; @@ -485,7 +493,7 @@ private: gpu::PipelinePointer _simpleTransparentWebBrowserPipeline; static render::ShapePipelinePointer getShapePipeline(bool textured = false, bool transparent = false, bool culled = true, - bool unlit = false, bool depthBias = false); + bool unlit = false, bool depthBias = false, bool forward = false); static render::ShapePipelinePointer getFadingShapePipeline(bool textured = false, bool transparent = false, bool culled = true, bool unlit = false, bool depthBias = false); }; From 292071febb552e9d6e5fcae2f52d594214712eab Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 8 Jan 2019 14:34:19 -0800 Subject: [PATCH 05/46] fix model groupCulled --- .../src/RenderableModelEntityItem.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 216e5204e9..7e01af04dd 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1074,10 +1074,16 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare } void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) { + auto builder = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); + + if (_model && _model->isGroupCulled()) { + builder.withMetaCullGroup(); + } + if (didVisualGeometryRequestSucceed) { - _itemKey = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); + _itemKey = builder.build(); } else { - _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); + _itemKey = builder.withTypeShape().build(); } } @@ -1447,6 +1453,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce bool groupCulled = entity->getGroupCulled(); if (model->isGroupCulled() != groupCulled) { model->setGroupCulled(groupCulled); + setKey(_didLastVisualGeometryRequestSucceed); } } From 6d12f5704ee1c0d9ec2e4dc9f6759c0cbc92596a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 10 Jan 2019 15:47:19 -0800 Subject: [PATCH 06/46] fix multi-frustum view updating --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 134c375b56..e23960427f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6269,7 +6269,7 @@ void Application::update(float deltaTime) { // TODO: Fix this by modeling the way the secondary camera works on how the main camera works // ie. Use a camera object stored in the game logic and informs the Engine on where the secondary // camera should be. - // updateSecondaryCameraViewFrustum(); + updateSecondaryCameraViewFrustum(); } quint64 now = usecTimestampNow(); From 6bd6c45b60da16ff745adbf4b1f71cee43118d6d Mon Sep 17 00:00:00 2001 From: Clement Date: Fri, 7 Dec 2018 12:03:42 -0800 Subject: [PATCH 07/46] Remove dead IdentityRequest code --- assignment-client/src/avatars/AvatarMixer.cpp | 31 ------------------- assignment-client/src/avatars/AvatarMixer.h | 1 - interface/src/Application.cpp | 1 - interface/src/avatar/AvatarManager.cpp | 19 ------------ interface/src/avatar/AvatarManager.h | 3 -- .../networking/src/udt/PacketHeaders.cpp | 2 -- libraries/networking/src/udt/PacketHeaders.h | 2 +- 7 files changed, 1 insertion(+), 58 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 6b90a8fbbd..500772c1b5 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -54,7 +54,6 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket"); packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); - packetReceiver.registerListener(PacketType::AvatarIdentityRequest, this, "handleAvatarIdentityRequestPacket"); packetReceiver.registerListener(PacketType::SetAvatarTraits, this, "queueIncomingPacket"); packetReceiver.registerListener(PacketType::BulkAvatarTraitsAck, this, "queueIncomingPacket"); @@ -582,36 +581,6 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes _handleAvatarIdentityPacketElapsedTime += (end - start); } -void AvatarMixer::handleAvatarIdentityRequestPacket(QSharedPointer message, SharedNodePointer senderNode) { - if (message->getSize() < NUM_BYTES_RFC4122_UUID) { - qCDebug(avatars) << "Malformed AvatarIdentityRequest received from" << message->getSenderSockAddr().toString(); - return; - } - - QUuid avatarID(QUuid::fromRfc4122(message->getMessage()) ); - if (!avatarID.isNull()) { - auto nodeList = DependencyManager::get(); - auto requestedNode = nodeList->nodeWithUUID(avatarID); - - if (requestedNode) { - AvatarMixerClientData* avatarClientData = static_cast(requestedNode->getLinkedData()); - if (avatarClientData) { - const AvatarData& avatarData = avatarClientData->getAvatar(); - QByteArray serializedAvatar = avatarData.identityByteArray(); - auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); - identityPackets->write(serializedAvatar); - nodeList->sendPacketList(std::move(identityPackets), *senderNode); - ++_sumIdentityPackets; - } - - AvatarMixerClientData* senderData = static_cast(senderNode->getLinkedData()); - if (senderData) { - senderData->resetSentTraitData(requestedNode->getLocalID()); - } - } - } -} - void AvatarMixer::handleKillAvatarPacket(QSharedPointer message, SharedNodePointer node) { auto start = usecTimestampNow(); handleAvatarKilled(node); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 8ae7fc9931..764656a2d5 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -54,7 +54,6 @@ private slots: void handleRequestsDomainListDataPacket(QSharedPointer message, SharedNodePointer senderNode); void handleReplicatedPacket(QSharedPointer message); void handleReplicatedBulkAvatarPacket(QSharedPointer message); - void handleAvatarIdentityRequestPacket(QSharedPointer message, SharedNodePointer senderNode); void domainSettingsRequestComplete(); void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID); void start(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e70375e47..799842bd87 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2201,7 +2201,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo || ((rightHandPose.valid || lastRightHandPose.valid) && (rightHandPose != lastRightHandPose)); lastLeftHandPose = leftHandPose; lastRightHandPose = rightHandPose; - properties["avatar_identity_requests_sent"] = DependencyManager::get()->getIdentityRequestsSent(); UserActivityLogger::getInstance().logAction("stats", properties); }); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 53c16c8a61..02b10b3f58 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -347,25 +347,6 @@ void AvatarManager::postUpdate(float deltaTime, const render::ScenePointer& scen } } -void AvatarManager::sendIdentityRequest(const QUuid& avatarID) const { - auto nodeList = DependencyManager::get(); - QWeakPointer nodeListWeak = nodeList; - nodeList->eachMatchingNode( - [](const SharedNodePointer& node)->bool { - return node->getType() == NodeType::AvatarMixer && node->getActiveSocket(); - }, - [this, avatarID, nodeListWeak](const SharedNodePointer& node) { - auto nodeList = nodeListWeak.lock(); - if (nodeList) { - auto packet = NLPacket::create(PacketType::AvatarIdentityRequest, NUM_BYTES_RFC4122_UUID, true); - packet->write(avatarID.toRfc4122()); - nodeList->sendPacket(std::move(packet), *node); - ++_identityRequestsSent; - } - } - ); -} - void AvatarManager::simulateAvatarFades(float deltaTime) { if (_avatarsToFadeOut.empty()) { return; diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 359af8e361..9ad7bd1b78 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -92,7 +92,6 @@ public: void updateMyAvatar(float deltaTime); void updateOtherAvatars(float deltaTime); - void sendIdentityRequest(const QUuid& avatarID) const; void setMyAvatarDataPacketsPaused(bool puase); @@ -191,7 +190,6 @@ public: Q_INVOKABLE QVariantMap getPalData(const QStringList& specificAvatarIdentifiers = QStringList()); float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); } - int getIdentityRequestsSent() const { return _identityRequestsSent; } void queuePhysicsChange(const OtherAvatarPointer& avatar); void buildPhysicsTransaction(PhysicsEngine::Transaction& transaction); @@ -241,7 +239,6 @@ private: float _avatarSimulationTime { 0.0f }; bool _shouldRender { true }; bool _myAvatarDataPacketsPaused { false }; - mutable int _identityRequestsSent { 0 }; mutable std::mutex _spaceLock; workload::SpacePointer _space; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 642914cd56..ee9f784b8c 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -93,8 +93,6 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(PingVersion::IncludeConnectionID); case PacketType::AvatarQuery: return static_cast(AvatarQueryVersion::ConicalFrustums); - case PacketType::AvatarIdentityRequest: - return 22; case PacketType::EntityQueryInitialResultsComplete: return static_cast(EntityVersion::ParticleSpin); case PacketType::BulkAvatarTraitsAck: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index f53a287d71..37b8a3b1c7 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -57,7 +57,7 @@ public: ICEServerQuery, OctreeStats, SetAvatarTraits, - AvatarIdentityRequest, + UNUSED_PACKET_TYPE, AssignmentClientStatus, NoisyMute, AvatarIdentity, From 184c11ca44db2d1de369f62d8daddcde31f2b818 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 16 Jan 2019 08:54:29 +1300 Subject: [PATCH 08/46] Fix tablet sometimes not working after domain change --- interface/src/Application.cpp | 4 ++++ interface/src/ui/overlays/Web3DOverlay.cpp | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e70375e47..128a1a0392 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1200,6 +1200,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this]() { + auto tabletScriptingInterface = DependencyManager::get(); + if (tabletScriptingInterface) { + tabletScriptingInterface->setQmlTabletRoot(SYSTEM_TABLET, nullptr); + } getOverlays().deleteOverlay(getTabletScreenID()); getOverlays().deleteOverlay(getTabletHomeButtonID()); getOverlays().deleteOverlay(getTabletFrameID()); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index ec6b62e237..4fe3708ba9 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -134,13 +134,6 @@ void Web3DOverlay::destroyWebSurface() { QQuickItem* rootItem = _webSurface->getRootItem(); - if (rootItem && rootItem->objectName() == "tabletRoot") { - auto tabletScriptingInterface = DependencyManager::get(); - if (tabletScriptingInterface) { - tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", nullptr); - } - } - // Fix for crash in QtWebEngineCore when rapidly switching domains // Call stop on the QWebEngineView before destroying OffscreenQMLSurface. if (rootItem) { From 174c79d66d828de3e3aab2f2bc5deec973406d92 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Jan 2019 11:51:23 -0800 Subject: [PATCH 09/46] use new-style far-grabbing code for mouse grabs --- libraries/entities/src/EntityItem.cpp | 3 +- scripts/system/controllers/grab.js | 188 +++++--------------------- 2 files changed, 33 insertions(+), 158 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 498f0ff066..7b5f6e4066 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3368,7 +3368,8 @@ void EntityItem::addGrab(GrabPointer grab) { EntityDynamicType dynamicType; QVariantMap arguments; int grabParentJointIndex =grab->getParentJointIndex(); - if (grabParentJointIndex == FARGRAB_RIGHTHAND_INDEX || grabParentJointIndex == FARGRAB_LEFTHAND_INDEX) { + if (grabParentJointIndex == FARGRAB_RIGHTHAND_INDEX || grabParentJointIndex == FARGRAB_LEFTHAND_INDEX || + grabParentJointIndex == FARGRAB_MOUSE_INDEX) { // add a far-grab action dynamicType = DYNAMIC_TYPE_FAR_GRAB; arguments["otherID"] = grab->getOwnerID(); diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index a78a2971e9..4ef2dca32f 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -14,79 +14,25 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global MyAvatar, Entities, Script, HMD, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller, +/* global MyAvatar, Entities, Script, HMD, Camera, Vec3, Reticle, Overlays, Messages, Quat, Controller, isInEditMode, entityIsGrabbable, Picks, PickType, Pointers, unhighlightTargetEntity, DISPATCHER_PROPERTIES, - entityIsGrabbable, entityIsEquipped, getMainTabletIDs + entityIsGrabbable, getMainTabletIDs */ /* jslint bitwise: true */ (function() { // BEGIN LOCAL_SCOPE - Script.include("/~/system/libraries/utils.js"); - Script.include("/~/system/libraries/controllerDispatcherUtils.js"); +Script.include("/~/system/libraries/utils.js"); +Script.include("/~/system/libraries/controllerDispatcherUtils.js"); + +var FAR_GRAB_JOINT = 65526; // FARGRAB_MOUSE_INDEX + var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed var DELAY_FOR_30HZ = 33; // milliseconds -var ZERO_VEC3 = { - x: 0, - y: 0, - z: 0 -}; -var IDENTITY_QUAT = { - x: 0, - y: 0, - z: 0, - w: 0 -}; - -var DEFAULT_GRABBABLE_DATA = { - grabbable: true, - invertSolidWhileHeld: false -}; - - -var ACTION_TTL = 10; // seconds - -function getTag() { - return "grab-" + MyAvatar.sessionUUID; -} - -var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position -var DISTANCE_HOLDING_UNITY_MASS = 1200; // The mass at which the distance holding action timeframe is unmodified -var DISTANCE_HOLDING_UNITY_DISTANCE = 6; // The distance at which the distance holding action timeframe is unmodified - -function distanceGrabTimescale(mass, distance) { - var timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME * mass / - DISTANCE_HOLDING_UNITY_MASS * distance / - DISTANCE_HOLDING_UNITY_DISTANCE; - if (timeScale < DISTANCE_HOLDING_ACTION_TIMEFRAME) { - timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME; - } - return timeScale; -} -function getMass(dimensions, density) { - return (dimensions.x * dimensions.y * dimensions.z) * density; -} - -function entityIsGrabbedByOther(entityID) { - // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. - var actionIDs = Entities.getActionIDs(entityID); - for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { - var actionID = actionIDs[actionIndex]; - var actionArguments = Entities.getActionArguments(entityID, actionID); - var tag = actionArguments.tag; - if (tag == getTag()) { - // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. - continue; - } - if (tag.slice(0, 5) == "grab-") { - // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. - return true; - } - } - return false; -} +var ZERO_VEC3 = { x: 0, y: 0, z: 0 }; +var IDENTITY_QUAT = { x: 0, y: 0, z: 0, w: 1 }; // helper function function mouseIntersectionWithPlane(pointOnPlane, planeNormal, event, maxDistance) { @@ -227,7 +173,6 @@ var beacon = { function Grabber() { this.isGrabbing = false; this.entityID = null; - this.actionID = null; this.startPosition = ZERO_VEC3; this.lastRotation = IDENTITY_QUAT; this.currentPosition = ZERO_VEC3; @@ -253,9 +198,6 @@ function Grabber() { z: 0 }; - this.targetPosition = null; - this.targetRotation = null; - this.liftKey = false; // SHIFT this.rotateKey = false; // CONTROL @@ -305,7 +247,7 @@ Grabber.prototype.computeNewGrabPlane = function() { } } - this.pointOnPlane = Vec3.sum(this.currentPosition, this.offset); + this.pointOnPlane = Vec3.subtract(this.currentPosition, this.offset); var xzOffset = Vec3.subtract(this.pointOnPlane, Camera.getPosition()); xzOffset.y = 0; this.xzDistanceToGrab = Vec3.length(xzOffset); @@ -341,16 +283,11 @@ Grabber.prototype.pressEvent = function(event) { } var props = Entities.getEntityProperties(pickResults.objectID, DISPATCHER_PROPERTIES); - var isDynamic = props.dynamic; if (!entityIsGrabbable(props)) { // only grab grabbable objects return; } - if (!props.grab.grabbable) { - return; - } - Pointers.setRenderState(this.mouseRayEntities, "grabbed"); Pointers.setLockEndUUID(this.mouseRayEntities, pickResults.objectID, false); unhighlightTargetEntity(pickResults.objectID); @@ -361,7 +298,6 @@ Grabber.prototype.pressEvent = function(event) { var entityProperties = Entities.getEntityProperties(clickedEntity, DISPATCHER_PROPERTIES); this.startPosition = entityProperties.position; this.lastRotation = entityProperties.rotation; - this.madeDynamic = false; var cameraPosition = Camera.getPosition(); var objectBoundingDiameter = Vec3.length(entityProperties.dimensions); @@ -373,21 +309,10 @@ Grabber.prototype.pressEvent = function(event) { return; } - if (entityIsGrabbable(props) && !isDynamic) { - entityProperties.dynamic = true; - Entities.editEntity(clickedEntity, entityProperties); - this.madeDynamic = true; - } - // this.activateEntity(clickedEntity, entityProperties); this.isGrabbing = true; this.entityID = clickedEntity; this.currentPosition = entityProperties.position; - this.targetPosition = { - x: this.startPosition.x, - y: this.startPosition.y, - z: this.startPosition.z - }; // compute the grab point var pickRay = Camera.computePickRay(event.x, event.y); @@ -396,14 +321,13 @@ Grabber.prototype.pressEvent = function(event) { nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction); this.pointOnPlane = Vec3.sum(cameraPosition, nearestPoint); - // compute the grab offset (points from object center to point of grab) - this.offset = Vec3.subtract(this.pointOnPlane, this.startPosition); + MyAvatar.setJointTranslation(FAR_GRAB_JOINT, MyAvatar.worldToJointPoint(this.startPosition)); + MyAvatar.setJointRotation(FAR_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation)); + + this.offset = Vec3.subtract(this.startPosition, this.pointOnPlane); // offset in world-space this.computeNewGrabPlane(); - - if (!entityIsGrabbedByOther(this.entityID)) { - this.moveEvent(event); - } + this.moveEvent(event); var args = "mouse"; Entities.callEntityMethod(this.entityID, "startDistanceGrab", args); @@ -413,6 +337,8 @@ Grabber.prototype.pressEvent = function(event) { grabbedEntity: this.entityID })); + this.grabID = MyAvatar.grab(this.entityID, FAR_GRAB_JOINT, ZERO_VEC3, IDENTITY_QUAT); + // TODO: play sounds again when we aren't leaking AudioInjector threads //Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME }); }; @@ -428,20 +354,7 @@ Grabber.prototype.releaseEvent = function(event) { } if (this.isGrabbing) { - // this.deactivateEntity(this.entityID); this.isGrabbing = false; - if (this.actionID) { - Entities.deleteAction(this.entityID, this.actionID); - } - - if (this.madeDynamic) { - var entityProps = {}; - entityProps.dynamic = false; - entityProps.localVelocity = {x: 0, y: 0, z: 0}; - Entities.editEntity(this.entityID, entityProps); - } - - this.actionID = null; Pointers.setRenderState(this.mouseRayEntities, ""); Pointers.setLockEndUUID(this.mouseRayEntities, null, false); @@ -455,6 +368,13 @@ Grabber.prototype.releaseEvent = function(event) { joint: "mouse" })); + if (this.grabID) { + MyAvatar.releaseGrab(this.grabID); + this.grabID = null; + } + + MyAvatar.clearJointData(FAR_GRAB_JOINT); + // TODO: play sounds again when we aren't leaking AudioInjector threads //Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME }); } @@ -482,23 +402,12 @@ Grabber.prototype.moveEvent = function(event) { Grabber.prototype.moveEventProcess = function() { this.moveEventTimer = null; - // see if something added/restored gravity var entityProperties = Entities.getEntityProperties(this.entityID, DISPATCHER_PROPERTIES); - if (!entityProperties || !entityProperties.gravity || HMD.active) { + if (!entityProperties || HMD.active) { return; } - if (Vec3.length(entityProperties.gravity) !== 0.0) { - this.originalGravity = entityProperties.gravity; - } this.currentPosition = entityProperties.position; - this.mass = getMass(entityProperties.dimensions, entityProperties.density); - var cameraPosition = Camera.getPosition(); - - var actionArgs = { - tag: getTag(), - ttl: ACTION_TTL - }; if (this.mode === "rotate") { var drag = mouse.getDrag(); @@ -510,19 +419,9 @@ Grabber.prototype.moveEventProcess = function() { var ROTATE_STRENGTH = 0.4; // magic number tuned by hand var angle = ROTATE_STRENGTH * Math.sqrt((drag.x * drag.x) + (drag.y * drag.y)); var deltaQ = Quat.angleAxis(angle, axis); - // var qZero = entityProperties.rotation; - //var qZero = this.lastRotation; + this.lastRotation = Quat.multiply(deltaQ, this.lastRotation); - - var distanceToCameraR = Vec3.length(Vec3.subtract(this.currentPosition, cameraPosition)); - var angularTimeScale = distanceGrabTimescale(this.mass, distanceToCameraR); - - actionArgs = { - targetRotation: this.lastRotation, - angularTimeScale: angularTimeScale, - tag: getTag(), - ttl: ACTION_TTL - }; + MyAvatar.setJointRotation(FAR_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation)); } else { var newPointOnPlane; @@ -534,17 +433,10 @@ Grabber.prototype.moveEventProcess = function() { planeNormal = Vec3.normalize(planeNormal); var pointOnCylinder = Vec3.multiply(planeNormal, this.xzDistanceToGrab); pointOnCylinder = Vec3.sum(Camera.getPosition(), pointOnCylinder); - this.pointOnPlane = mouseIntersectionWithPlane(pointOnCylinder, planeNormal, mouse.current, this.maxDistance); - newPointOnPlane = { - x: this.pointOnPlane.x, - y: this.pointOnPlane.y, - z: this.pointOnPlane.z - }; - + newPointOnPlane = mouseIntersectionWithPlane(pointOnCylinder, planeNormal, mouse.current, this.maxDistance); } else { - - newPointOnPlane = mouseIntersectionWithPlane( - this.pointOnPlane, this.planeNormal, mouse.current, this.maxDistance); + var cameraPosition = Camera.getPosition(); + newPointOnPlane = mouseIntersectionWithPlane(this.pointOnPlane, this.planeNormal, mouse.current, this.maxDistance); var relativePosition = Vec3.subtract(newPointOnPlane, cameraPosition); var distance = Vec3.length(relativePosition); if (distance > this.maxDistance) { @@ -553,26 +445,8 @@ Grabber.prototype.moveEventProcess = function() { newPointOnPlane = Vec3.sum(relativePosition, cameraPosition); } } - this.targetPosition = Vec3.subtract(newPointOnPlane, this.offset); - var distanceToCameraL = Vec3.length(Vec3.subtract(this.targetPosition, cameraPosition)); - var linearTimeScale = distanceGrabTimescale(this.mass, distanceToCameraL); - - actionArgs = { - targetPosition: this.targetPosition, - linearTimeScale: linearTimeScale, - tag: getTag(), - ttl: ACTION_TTL - }; - - } - - if (!this.actionID) { - if (!entityIsGrabbedByOther(this.entityID) && !entityIsEquipped(this.entityID)) { - this.actionID = Entities.addAction("far-grab", this.entityID, actionArgs); - } - } else { - Entities.updateAction(this.entityID, this.actionID, actionArgs); + MyAvatar.setJointTranslation(FAR_GRAB_JOINT, MyAvatar.worldToJointPoint(Vec3.sum(newPointOnPlane, this.offset))); } this.scheduleMouseMoveProcessor(); From 2515c7f73e49eff031f6fed7d4f6b22f2c22fb89 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Jan 2019 13:40:16 -0800 Subject: [PATCH 10/46] remove old-style grabbing scripts --- .../farActionGrabEntityDynOnly.js | 572 --------------- .../controllerModules/farParentGrabEntity.js | 664 ------------------ .../controllerModules/nearActionGrabEntity.js | 250 ------- .../controllerModules/nearParentGrabEntity.js | 359 ---------- .../system/controllers/controllerScripts.js | 15 +- scripts/system/controllers/grab.js | 20 +- 6 files changed, 15 insertions(+), 1865 deletions(-) delete mode 100644 scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js delete mode 100644 scripts/system/controllers/controllerModules/farParentGrabEntity.js delete mode 100644 scripts/system/controllers/controllerModules/nearActionGrabEntity.js delete mode 100644 scripts/system/controllers/controllerModules/nearParentGrabEntity.js diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js b/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js deleted file mode 100644 index 0ba3dd6e6b..0000000000 --- a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js +++ /dev/null @@ -1,572 +0,0 @@ -"use strict"; - -// farActionGrabEntity.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* jslint bitwise: true */ - -/* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Camera, Quat, getEnabledModuleByName, - makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, - makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, - TRIGGER_ON_VALUE, ZERO_VEC, getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, - Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, - Uuid, worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { - - var MARGIN = 25; - - function TargetObject(entityID, entityProps) { - this.entityID = entityID; - this.entityProps = entityProps; - this.targetEntityID = null; - this.targetEntityProps = null; - - this.getTargetEntity = function() { - var parentPropsLength = this.parentProps.length; - if (parentPropsLength !== 0) { - var targetEntity = { - id: this.parentProps[parentPropsLength - 1].id, - props: this.parentProps[parentPropsLength - 1]}; - this.targetEntityID = targetEntity.id; - this.targetEntityProps = targetEntity.props; - return targetEntity; - } - this.targetEntityID = this.entityID; - this.targetEntityProps = this.entityProps; - return { - id: this.entityID, - props: this.entityProps}; - }; - } - - function FarActionGrabEntity(hand) { - this.hand = hand; - this.grabbing = false; - this.grabbedThingID = null; - this.targetObject = null; - this.actionID = null; // action this script created... - this.entityToLockOnto = null; - this.potentialEntityWithContextOverlay = false; - this.entityWithContextOverlay = false; - this.contextOverlayTimer = false; - this.locked = false; - this.highlightedEntity = null; - this.reticleMinX = MARGIN; - this.reticleMaxX = 0; - this.reticleMinY = MARGIN; - this.reticleMaxY = 0; - - var ACTION_TTL = 15; // seconds - - var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object - var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position - var DISTANCE_HOLDING_UNITY_MASS = 1200; // The mass at which the distance holding action timeframe is unmodified - var DISTANCE_HOLDING_UNITY_DISTANCE = 6; // The distance at which the distance holding action timeframe is unmodified - - this.parameters = makeDispatcherModuleParameters( - 550, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100, - makeLaserParams(this.hand, false)); - - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.distanceGrabTimescale = function(mass, distance) { - var timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME * mass / - DISTANCE_HOLDING_UNITY_MASS * distance / - DISTANCE_HOLDING_UNITY_DISTANCE; - if (timeScale < DISTANCE_HOLDING_ACTION_TIMEFRAME) { - timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME; - } - return timeScale; - }; - - this.getMass = function(dimensions, density) { - return (dimensions.x * dimensions.y * dimensions.z) * density; - }; - - this.startFarGrabAction = function (controllerData, grabbedProperties) { - var controllerLocation = controllerData.controllerLocations[this.hand]; - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - - // transform the position into room space - var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); - var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - - var now = Date.now(); - - // add the action and initialize some variables - this.currentObjectPosition = grabbedProperties.position; - this.currentObjectRotation = grabbedProperties.rotation; - this.currentObjectTime = now; - this.currentCameraOrientation = Camera.orientation; - - this.grabRadius = this.grabbedDistance; - this.grabRadialVelocity = 0.0; - - // offset between controller vector at the grab radius and the entity position - var targetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - targetPosition = Vec3.sum(targetPosition, worldControllerPosition); - this.offsetPosition = Vec3.subtract(this.currentObjectPosition, targetPosition); - - // compute a constant based on the initial conditions which we use below to exaggerate hand motion - // onto the held object - this.radiusScalar = Math.log(this.grabRadius + 1.0); - if (this.radiusScalar < 1.0) { - this.radiusScalar = 1.0; - } - - // compute the mass for the purpose of energy and how quickly to move object - this.mass = this.getMass(grabbedProperties.dimensions, grabbedProperties.density); - var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, grabbedProperties.position)); - var timeScale = this.distanceGrabTimescale(this.mass, distanceToObject); - this.linearTimeScale = timeScale; - this.actionID = Entities.addAction("far-grab", this.grabbedThingID, { - targetPosition: this.currentObjectPosition, - linearTimeScale: timeScale, - targetRotation: this.currentObjectRotation, - angularTimeScale: timeScale, - tag: "far-grab-" + MyAvatar.sessionUUID, - ttl: ACTION_TTL - }); - if (this.actionID === Uuid.NULL) { - this.actionID = null; - } - - if (this.actionID !== null) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.grabbedThingID, "startDistanceGrab", args); - } - - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.previousRoomControllerPosition = roomControllerPosition; - this.grabbing = true; - }; - - this.continueDistanceHolding = function(controllerData) { - var controllerLocation = controllerData.controllerLocations[this.hand]; - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - - // also transform the position into room space - var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); - var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES); - var now = Date.now(); - var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds - this.currentObjectTime = now; - - // the action was set up when this.distanceHolding was called. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, worldControllerPosition) * - this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; - if (radius < 1.0) { - radius = 1.0; - } - - var roomHandDelta = Vec3.subtract(roomControllerPosition, this.previousRoomControllerPosition); - var worldHandDelta = Mat4.transformVector(MyAvatar.getSensorToWorldMatrix(), roomHandDelta); - var handMoved = Vec3.multiply(worldHandDelta, radius); - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, handMoved); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.grabbedThingID, "continueDistanceGrab", args); - - // Update radialVelocity - var lastVelocity = Vec3.multiply(worldHandDelta, 1.0 / deltaObjectTime); - var delta = Vec3.normalize(Vec3.subtract(grabbedProperties.position, worldControllerPosition)); - var newRadialVelocity = Vec3.dot(lastVelocity, delta); - - var VELOCITY_AVERAGING_TIME = 0.016; - var blendFactor = deltaObjectTime / VELOCITY_AVERAGING_TIME; - if (blendFactor < 0.0) { - blendFactor = 0.0; - } else if (blendFactor > 1.0) { - blendFactor = 1.0; - } - this.grabRadialVelocity = blendFactor * newRadialVelocity + (1.0 - blendFactor) * this.grabRadialVelocity; - - var RADIAL_GRAB_AMPLIFIER = 10.0; - if (Math.abs(this.grabRadialVelocity) > 0.0) { - this.grabRadius = this.grabRadius + (this.grabRadialVelocity * deltaObjectTime * - this.grabRadius * RADIAL_GRAB_AMPLIFIER); - } - - // don't let grabRadius go all the way to zero, because it can't come back from that - var MINIMUM_GRAB_RADIUS = 0.1; - if (this.grabRadius < MINIMUM_GRAB_RADIUS) { - this.grabRadius = MINIMUM_GRAB_RADIUS; - } - var newTargetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - newTargetPosition = Vec3.sum(newTargetPosition, worldControllerPosition); - newTargetPosition = Vec3.sum(newTargetPosition, this.offsetPosition); - - // XXX - // this.maybeScale(grabbedProperties); - - var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition)); - - this.linearTimeScale = (this.linearTimeScale / 2); - if (this.linearTimeScale <= DISTANCE_HOLDING_ACTION_TIMEFRAME) { - this.linearTimeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME; - } - var success = Entities.updateAction(this.grabbedThingID, this.actionID, { - targetPosition: newTargetPosition, - linearTimeScale: this.linearTimeScale, - targetRotation: this.currentObjectRotation, - angularTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject), - ttl: ACTION_TTL - }); - if (!success) { - print("farActionGrabEntity continueDistanceHolding -- updateAction failed: " + this.actionID); - this.actionID = null; - } - - this.previousRoomControllerPosition = roomControllerPosition; - }; - - this.endFarGrabAction = function () { - this.distanceHolding = false; - this.distanceRotating = false; - Entities.deleteAction(this.grabbedThingID, this.actionID); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.grabbedThingID, "releaseGrab", args); - this.actionID = null; - this.grabbedThingID = null; - this.targetObject = null; - this.potentialEntityWithContextOverlay = false; - this.grabbing = false; - }; - - this.updateRecommendedArea = function() { - var dims = Controller.getViewportDimensions(); - this.reticleMaxX = dims.x - MARGIN; - this.reticleMaxY = dims.y - MARGIN; - }; - - this.calculateNewReticlePosition = function(intersection) { - this.updateRecommendedArea(); - var point2d = HMD.overlayFromWorldPoint(intersection); - point2d.x = Math.max(this.reticleMinX, Math.min(point2d.x, this.reticleMaxX)); - point2d.y = Math.max(this.reticleMinY, Math.min(point2d.y, this.reticleMaxY)); - return point2d; - }; - - this.notPointingAtEntity = function(controllerData) { - var intersection = controllerData.rayPicks[this.hand]; - var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); - var entityType = entityProperty.type; - var hudRayPick = controllerData.hudRayPicks[this.hand]; - var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); - if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web") || - intersection.type === Picks.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) { - return true; - } - return false; - }; - - this.distanceRotate = function(otherFarGrabModule) { - this.distanceRotating = true; - this.distanceHolding = false; - - var worldControllerRotation = getControllerWorldLocation(this.handToController(), true).orientation; - var controllerRotationDelta = - Quat.multiply(worldControllerRotation, Quat.inverse(this.previousWorldControllerRotation)); - // Rotate entity by twice the delta rotation. - controllerRotationDelta = Quat.multiply(controllerRotationDelta, controllerRotationDelta); - - // Perform the rotation in the translation controller's action update. - otherFarGrabModule.currentObjectRotation = Quat.multiply(controllerRotationDelta, - otherFarGrabModule.currentObjectRotation); - - this.previousWorldControllerRotation = worldControllerRotation; - }; - - this.prepareDistanceRotatingData = function(controllerData) { - var intersection = controllerData.rayPicks[this.hand]; - - var controllerLocation = getControllerWorldLocation(this.handToController(), true); - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - - var grabbedProperties = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); - this.currentObjectPosition = grabbedProperties.position; - this.grabRadius = intersection.distance; - - // Offset between controller vector at the grab radius and the entity position. - var targetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - targetPosition = Vec3.sum(targetPosition, worldControllerPosition); - this.offsetPosition = Vec3.subtract(this.currentObjectPosition, targetPosition); - - // Initial controller rotation. - this.previousWorldControllerRotation = worldControllerRotation; - }; - - this.destroyContextOverlay = function(controllerData) { - if (this.entityWithContextOverlay) { - ContextOverlay.destroyContextOverlay(this.entityWithContextOverlay); - this.entityWithContextOverlay = false; - this.potentialEntityWithContextOverlay = false; - } - }; - - this.targetIsNull = function() { - var properties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES); - if (Object.keys(properties).length === 0 && this.distanceHolding) { - return true; - } - return false; - }; - - this.getTargetProps = function (controllerData) { - var targetEntityID = controllerData.rayPicks[this.hand].objectID; - if (targetEntityID) { - return Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); - } - return null; - }; - - this.isReady = function (controllerData) { - if (HMD.active) { - if (this.notPointingAtEntity(controllerData)) { - return makeRunningValues(false, [], []); - } - - this.distanceHolding = false; - this.distanceRotating = false; - - if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { - this.prepareDistanceRotatingData(controllerData); - return makeRunningValues(true, [], []); - } else { - this.destroyContextOverlay(); - return makeRunningValues(false, [], []); - } - } - return makeRunningValues(false, [], []); - }; - - this.run = function (controllerData) { - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.targetIsNull()) { - this.endFarGrabAction(); - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", - this.highlightedEntity); - this.highlightedEntity = null; - return makeRunningValues(false, [], []); - } - this.intersectionDistance = controllerData.rayPicks[this.hand].distance; - - var otherModuleName = this.hand === RIGHT_HAND ? "LeftFarActionGrabEntity" : "RightFarActionGrabEntity"; - var otherFarGrabModule = getEnabledModuleByName(otherModuleName); - - // gather up the readiness of the near-grab modules - var nearGrabNames = [ - this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar", - this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", - this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity" - ]; - if (!this.grabbing) { - nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"); - nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); - } - - var nearGrabReadiness = []; - for (var i = 0; i < nearGrabNames.length; i++) { - var nearGrabModule = getEnabledModuleByName(nearGrabNames[i]); - var ready = nearGrabModule ? nearGrabModule.isReady(controllerData) : makeRunningValues(false, [], []); - nearGrabReadiness.push(ready); - } - - if (this.actionID) { - // if we are doing a distance grab and the object or tablet gets close enough to the controller, - // stop the far-grab so the near-grab or equip can take over. - for (var k = 0; k < nearGrabReadiness.length; k++) { - if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.grabbedThingID || - HMD.tabletID && nearGrabReadiness[k].targets[0] === HMD.tabletID)) { - this.endFarGrabAction(); - return makeRunningValues(false, [], []); - } - } - - this.continueDistanceHolding(controllerData); - } else { - // if we are doing a distance search and this controller moves into a position - // where it could near-grab something, stop searching. - for (var j = 0; j < nearGrabReadiness.length; j++) { - if (nearGrabReadiness[j].active) { - this.endFarGrabAction(); - return makeRunningValues(false, [], []); - } - } - - var rayPickInfo = controllerData.rayPicks[this.hand]; - if (rayPickInfo.type === Picks.INTERSECTED_ENTITY) { - if (controllerData.triggerClicks[this.hand]) { - var entityID = rayPickInfo.objectID; - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", - this.highlightedEntity); - this.highlightedEntity = null; - var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); - if (targetProps.href !== "") { - AddressManager.handleLookupString(targetProps.href); - return makeRunningValues(false, [], []); - } - - this.targetObject = new TargetObject(entityID, targetProps); - this.targetObject.parentProps = getEntityParents(targetProps); - - if (this.contextOverlayTimer) { - Script.clearTimeout(this.contextOverlayTimer); - } - this.contextOverlayTimer = false; - if (entityID === this.entityWithContextOverlay) { - this.destroyContextOverlay(); - } else { - Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); - } - - var targetEntity = this.targetObject.getTargetEntity(); - entityID = targetEntity.id; - targetProps = targetEntity.props; - - if (!targetProps.dynamic && !this.targetObject.entityProps.dynamic) { - // let farParentGrabEntity handle it - return makeRunningValues(false, [], []); - } - - if (entityIsGrabbable(targetProps) || entityIsGrabbable(this.targetObject.entityProps)) { - if (!this.distanceRotating) { - this.grabbedThingID = entityID; - this.grabbedDistance = rayPickInfo.distance; - } - - if (otherFarGrabModule.grabbedThingID === this.grabbedThingID && - otherFarGrabModule.distanceHolding) { - this.prepareDistanceRotatingData(controllerData); - this.distanceRotate(otherFarGrabModule); - } else { - this.distanceHolding = true; - this.distanceRotating = false; - this.startFarGrabAction(controllerData, targetProps); - } - } - } else { - var targetEntityID = rayPickInfo.objectID; - if (this.highlightedEntity !== targetEntityID) { - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", - this.highlightedEntity); - var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); - - var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps); - selectionTargetObject.parentProps = getEntityParents(selectionTargetProps); - var selectionTargetEntity = selectionTargetObject.getTargetEntity(); - - if (entityIsGrabbable(selectionTargetEntity.props) || - entityIsGrabbable(selectionTargetObject.entityProps)) { - - Selection.addToSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", rayPickInfo.objectID); - } - this.highlightedEntity = rayPickInfo.objectID; - } - - if (!this.entityWithContextOverlay) { - var _this = this; - - if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) { - if (_this.contextOverlayTimer) { - Script.clearTimeout(_this.contextOverlayTimer); - } - _this.contextOverlayTimer = false; - _this.potentialEntityWithContextOverlay = rayPickInfo.objectID; - } - - if (!_this.contextOverlayTimer) { - _this.contextOverlayTimer = Script.setTimeout(function () { - if (!_this.entityWithContextOverlay && - _this.contextOverlayTimer && - _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var pEvProps = Entities.getEntityProperties(rayPickInfo.objectID, - DISPATCHER_PROPERTIES); - var pointerEvent = { - type: "Move", - id: _this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, - rayPickInfo.intersection, pEvProps), - pos3D: rayPickInfo.intersection, - normal: rayPickInfo.surfaceNormal, - direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), - button: "Secondary" - }; - if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) { - _this.entityWithContextOverlay = rayPickInfo.objectID; - } - } - _this.contextOverlayTimer = false; - }, 500); - } - } - } - } else if (this.distanceRotating) { - this.distanceRotate(otherFarGrabModule); - } else if (this.highlightedEntity) { - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - this.highlightedEntity = null; - } - } - return this.exitIfDisabled(controllerData); - }; - - this.exitIfDisabled = function(controllerData) { - var moduleName = this.hand === RIGHT_HAND ? "RightDisableModules" : "LeftDisableModules"; - var disableModule = getEnabledModuleByName(moduleName); - if (disableModule) { - if (disableModule.disableModules) { - this.endFarGrabAction(); - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", - this.highlightedEntity); - this.highlightedEntity = null; - return makeRunningValues(false, [], []); - } - } - var grabbedThing = (this.distanceHolding || this.distanceRotating) ? this.targetObject.entityID : null; - var offset = this.calculateOffset(controllerData); - var laserLockInfo = makeLaserLockInfo(grabbedThing, false, this.hand, offset); - return makeRunningValues(true, [], [], laserLockInfo); - }; - - this.calculateOffset = function(controllerData) { - if (this.distanceHolding || this.distanceRotating) { - var targetProps = Entities.getEntityProperties(this.targetObject.entityID, - [ "position", "rotation", "registrationPoint", "dimensions" ]); - return worldPositionToRegistrationFrameMatrix(targetProps, controllerData.rayPicks[this.hand].intersection); - } - return undefined; - }; - } - - var leftFarActionGrabEntity = new FarActionGrabEntity(LEFT_HAND); - var rightFarActionGrabEntity = new FarActionGrabEntity(RIGHT_HAND); - - enableDispatcherModule("LeftFarActionGrabEntity", leftFarActionGrabEntity); - enableDispatcherModule("RightFarActionGrabEntity", rightFarActionGrabEntity); - - function cleanup() { - disableDispatcherModule("LeftFarActionGrabEntity"); - disableDispatcherModule("RightFarActionGrabEntity"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/system/controllers/controllerModules/farParentGrabEntity.js b/scripts/system/controllers/controllerModules/farParentGrabEntity.js deleted file mode 100644 index 9960b08292..0000000000 --- a/scripts/system/controllers/controllerModules/farParentGrabEntity.js +++ /dev/null @@ -1,664 +0,0 @@ -"use strict"; - -// farParentGrabEntity.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* jslint bitwise: true */ - -/* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Quat, getEnabledModuleByName, makeRunningValues, - Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC, - HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, getControllerWorldLocation, - projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager, - getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, Uuid, findGroupParent, - worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, findFarGrabJointChildEntities -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { - var MARGIN = 25; - - function TargetObject(entityID, entityProps) { - this.entityID = entityID; - this.entityProps = entityProps; - this.targetEntityID = null; - this.targetEntityProps = null; - - this.getTargetEntity = function() { - var parentPropsLength = this.parentProps.length; - if (parentPropsLength !== 0) { - var targetEntity = { - id: this.parentProps[parentPropsLength - 1].id, - props: this.parentProps[parentPropsLength - 1]}; - this.targetEntityID = targetEntity.id; - this.targetEntityProps = targetEntity.props; - return targetEntity; - } - this.targetEntityID = this.entityID; - this.targetEntityProps = this.entityProps; - return { - id: this.entityID, - props: this.entityProps}; - }; - } - - function FarParentGrabEntity(hand) { - this.hand = hand; - this.grabbing = false; - this.targetEntityID = null; - this.targetObject = null; - this.previouslyUnhooked = {}; - this.previousParentID = {}; - this.previousParentJointIndex = {}; - this.potentialEntityWithContextOverlay = false; - this.entityWithContextOverlay = false; - this.contextOverlayTimer = false; - this.highlightedEntity = null; - this.reticleMinX = MARGIN; - this.reticleMaxX = 0; - this.reticleMinY = MARGIN; - this.reticleMaxY = 0; - this.lastUnexpectedChildrenCheckTime = 0; - this.endedGrab = 0; - this.MIN_HAPTIC_PULSE_INTERVAL = 500; // ms - - var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX - - var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object - var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position - var DISTANCE_HOLDING_UNITY_MASS = 1200; // The mass at which the distance holding action timeframe is unmodified - var DISTANCE_HOLDING_UNITY_DISTANCE = 6; // The distance at which the distance holding action timeframe is unmodified - - this.parameters = makeDispatcherModuleParameters( - 540, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100, - makeLaserParams(this.hand, false)); - - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.distanceGrabTimescale = function(mass, distance) { - var timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME * mass / - DISTANCE_HOLDING_UNITY_MASS * distance / - DISTANCE_HOLDING_UNITY_DISTANCE; - if (timeScale < DISTANCE_HOLDING_ACTION_TIMEFRAME) { - timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME; - } - return timeScale; - }; - - this.getMass = function(dimensions, density) { - return (dimensions.x * dimensions.y * dimensions.z) * density; - }; - - this.thisFarGrabJointIsParent = function(isParentProps) { - if (!isParentProps) { - return false; - } - - if (isParentProps.parentID !== MyAvatar.sessionUUID && isParentProps.parentID !== MyAvatar.SELF_ID) { - return false; - } - - if (isParentProps.parentJointIndex === FAR_GRAB_JOINTS[this.hand]) { - return true; - } - - return false; - }; - - this.startFarParentGrab = function (controllerData, grabbedProperties) { - var controllerLocation = controllerData.controllerLocations[this.hand]; - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - // transform the position into room space - var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); - var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - - var now = Date.now(); - - // add the action and initialize some variables - this.currentObjectPosition = grabbedProperties.position; - this.currentObjectRotation = grabbedProperties.rotation; - this.currentObjectTime = now; - - this.grabRadius = this.grabbedDistance; - this.grabRadialVelocity = 0.0; - - // offset between controller vector at the grab radius and the entity position - var targetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - targetPosition = Vec3.sum(targetPosition, worldControllerPosition); - this.offsetPosition = Vec3.subtract(this.currentObjectPosition, targetPosition); - - // compute a constant based on the initial conditions which we use below to exaggerate hand motion - // onto the held object - this.radiusScalar = Math.log(this.grabRadius + 1.0); - if (this.radiusScalar < 1.0) { - this.radiusScalar = 1.0; - } - - // compute the mass for the purpose of energy and how quickly to move object - this.mass = this.getMass(grabbedProperties.dimensions, grabbedProperties.density); - - // Debounce haptic pules. Can occur as near grab controller module vacillates between being ready or not due to - // changing positions and floating point rounding. - if (Date.now() - this.endedGrab > this.MIN_HAPTIC_PULSE_INTERVAL) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - } - - unhighlightTargetEntity(this.targetEntityID); - var message = { - hand: this.hand, - entityID: this.targetEntityID - }; - - Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message)); - - var newTargetPosLocal = MyAvatar.worldToJointPoint(grabbedProperties.position); - MyAvatar.setJointTranslation(FAR_GRAB_JOINTS[this.hand], newTargetPosLocal); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(grabbedProperties.id, "startNearGrab", args); - - var reparentProps = { - parentID: MyAvatar.SELF_ID, - parentJointIndex: FAR_GRAB_JOINTS[this.hand], - localVelocity: {x: 0, y: 0, z: 0}, - localAngularVelocity: {x: 0, y: 0, z: 0} - }; - - if (this.thisFarGrabJointIsParent(grabbedProperties)) { - // this should never happen, but if it does, don't set previous parent to be this hand. - this.previousParentID[grabbedProperties.id] = null; - this.previousParentJointIndex[grabbedProperties.id] = -1; - } else { - this.previousParentID[grabbedProperties.id] = grabbedProperties.parentID; - this.previousParentJointIndex[grabbedProperties.id] = grabbedProperties.parentJointIndex; - } - - this.targetEntityID = grabbedProperties.id; - Entities.editEntity(grabbedProperties.id, reparentProps); - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'grab', - grabbedEntity: grabbedProperties.id, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - this.grabbing = true; - - this.previousRoomControllerPosition = roomControllerPosition; - }; - - this.continueDistanceHolding = function(controllerData) { - var controllerLocation = controllerData.controllerLocations[this.hand]; - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - - // also transform the position into room space - var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); - var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - - var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); - var now = Date.now(); - var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds - this.currentObjectTime = now; - - // the action was set up when this.distanceHolding was called. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, worldControllerPosition) * - this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; - if (radius < 1.0) { - radius = 1.0; - } - - var roomHandDelta = Vec3.subtract(roomControllerPosition, this.previousRoomControllerPosition); - var worldHandDelta = Mat4.transformVector(MyAvatar.getSensorToWorldMatrix(), roomHandDelta); - var handMoved = Vec3.multiply(worldHandDelta, radius); - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, handMoved); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "continueDistanceGrab", args); - - // Update radialVelocity - var lastVelocity = Vec3.multiply(worldHandDelta, 1.0 / deltaObjectTime); - var delta = Vec3.normalize(Vec3.subtract(grabbedProperties.position, worldControllerPosition)); - var newRadialVelocity = Vec3.dot(lastVelocity, delta); - - var VELOCITY_AVERAGING_TIME = 0.016; - var blendFactor = deltaObjectTime / VELOCITY_AVERAGING_TIME; - if (blendFactor < 0.0) { - blendFactor = 0.0; - } else if (blendFactor > 1.0) { - blendFactor = 1.0; - } - this.grabRadialVelocity = blendFactor * newRadialVelocity + (1.0 - blendFactor) * this.grabRadialVelocity; - - var RADIAL_GRAB_AMPLIFIER = 10.0; - if (Math.abs(this.grabRadialVelocity) > 0.0) { - this.grabRadius = this.grabRadius + (this.grabRadialVelocity * deltaObjectTime * - this.grabRadius * RADIAL_GRAB_AMPLIFIER); - } - - // don't let grabRadius go all the way to zero, because it can't come back from that - var MINIMUM_GRAB_RADIUS = 0.1; - if (this.grabRadius < MINIMUM_GRAB_RADIUS) { - this.grabRadius = MINIMUM_GRAB_RADIUS; - } - var newTargetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - newTargetPosition = Vec3.sum(newTargetPosition, worldControllerPosition); - newTargetPosition = Vec3.sum(newTargetPosition, this.offsetPosition); - - // MyAvatar.setJointTranslation(FAR_GRAB_JOINTS[this.hand], MyAvatar.worldToJointPoint(newTargetPosition)); - - // var newTargetPosLocal = Mat4.transformPoint(MyAvatar.getSensorToWorldMatrix(), newTargetPosition); - var newTargetPosLocal = MyAvatar.worldToJointPoint(newTargetPosition); - MyAvatar.setJointTranslation(FAR_GRAB_JOINTS[this.hand], newTargetPosLocal); - - this.previousRoomControllerPosition = roomControllerPosition; - }; - - this.endFarParentGrab = function (controllerData) { - this.endedGrab = Date.now(); - // var endProps = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; - var endProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); - if (this.thisFarGrabJointIsParent(endProps)) { - Entities.editEntity(this.targetEntityID, { - parentID: this.previousParentID[this.targetEntityID], - parentJointIndex: this.previousParentJointIndex[this.targetEntityID], - localVelocity: {x: 0, y: 0, z: 0}, - localAngularVelocity: {x: 0, y: 0, z: 0} - }); - } - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "releaseGrab", args); - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'release', - grabbedEntity: this.targetEntityID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - unhighlightTargetEntity(this.targetEntityID); - this.grabbing = false; - this.targetEntityID = null; - this.potentialEntityWithContextOverlay = false; - MyAvatar.clearJointData(FAR_GRAB_JOINTS[this.hand]); - }; - - this.updateRecommendedArea = function() { - var dims = Controller.getViewportDimensions(); - this.reticleMaxX = dims.x - MARGIN; - this.reticleMaxY = dims.y - MARGIN; - }; - - this.calculateNewReticlePosition = function(intersection) { - this.updateRecommendedArea(); - var point2d = HMD.overlayFromWorldPoint(intersection); - point2d.x = Math.max(this.reticleMinX, Math.min(point2d.x, this.reticleMaxX)); - point2d.y = Math.max(this.reticleMinY, Math.min(point2d.y, this.reticleMaxY)); - return point2d; - }; - - this.notPointingAtEntity = function(controllerData) { - var intersection = controllerData.rayPicks[this.hand]; - var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); - var entityType = entityProperty.type; - var hudRayPick = controllerData.hudRayPicks[this.hand]; - var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); - if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web") || - intersection.type === Picks.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) { - return true; - } - return false; - }; - - this.distanceRotate = function(otherFarGrabModule) { - this.distanceRotating = true; - this.distanceHolding = false; - - var worldControllerRotation = getControllerWorldLocation(this.handToController(), true).orientation; - var controllerRotationDelta = - Quat.multiply(worldControllerRotation, Quat.inverse(this.previousWorldControllerRotation)); - // Rotate entity by twice the delta rotation. - controllerRotationDelta = Quat.multiply(controllerRotationDelta, controllerRotationDelta); - - // Perform the rotation in the translation controller's action update. - otherFarGrabModule.currentObjectRotation = Quat.multiply(controllerRotationDelta, - otherFarGrabModule.currentObjectRotation); - - this.previousWorldControllerRotation = worldControllerRotation; - }; - - this.prepareDistanceRotatingData = function(controllerData) { - var intersection = controllerData.rayPicks[this.hand]; - - var controllerLocation = getControllerWorldLocation(this.handToController(), true); - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - - var grabbedProperties = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); - this.currentObjectPosition = grabbedProperties.position; - this.grabRadius = intersection.distance; - - // Offset between controller vector at the grab radius and the entity position. - var targetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - targetPosition = Vec3.sum(targetPosition, worldControllerPosition); - this.offsetPosition = Vec3.subtract(this.currentObjectPosition, targetPosition); - - // Initial controller rotation. - this.previousWorldControllerRotation = worldControllerRotation; - }; - - this.destroyContextOverlay = function(controllerData) { - if (this.entityWithContextOverlay) { - ContextOverlay.destroyContextOverlay(this.entityWithContextOverlay); - this.entityWithContextOverlay = false; - this.potentialEntityWithContextOverlay = false; - } - }; - - this.checkForUnexpectedChildren = function (controllerData) { - // sometimes things can get parented to a hand and this script is unaware. Search for such entities and - // unhook them. - - var now = Date.now(); - var UNEXPECTED_CHILDREN_CHECK_TIME = 0.1; // seconds - if (now - this.lastUnexpectedChildrenCheckTime > MSECS_PER_SEC * UNEXPECTED_CHILDREN_CHECK_TIME) { - this.lastUnexpectedChildrenCheckTime = now; - - var children = findFarGrabJointChildEntities(this.hand); - var _this = this; - - children.forEach(function(childID) { - // we appear to be holding something and this script isn't in a state that would be holding something. - // unhook it. if we previously took note of this entity's parent, put it back where it was. This - // works around some problems that happen when more than one hand or avatar is passing something around. - if (_this.previousParentID[childID]) { - var previousParentID = _this.previousParentID[childID]; - var previousParentJointIndex = _this.previousParentJointIndex[childID]; - - // The main flaw with keeping track of previous parentage in individual scripts is: - // (1) A grabs something (2) B takes it from A (3) A takes it from B (4) A releases it - // now A and B will take turns passing it back to the other. Detect this and stop the loop here... - var UNHOOK_LOOP_DETECT_MS = 200; - if (_this.previouslyUnhooked[childID]) { - if (now - _this.previouslyUnhooked[childID] < UNHOOK_LOOP_DETECT_MS) { - previousParentID = Uuid.NULL; - previousParentJointIndex = -1; - } - } - _this.previouslyUnhooked[childID] = now; - - Entities.editEntity(childID, { - parentID: previousParentID, - parentJointIndex: previousParentJointIndex - }); - } else { - Entities.editEntity(childID, { parentID: Uuid.NULL }); - } - }); - } - }; - - this.targetIsNull = function() { - var properties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); - if (Object.keys(properties).length === 0 && this.distanceHolding) { - return true; - } - return false; - }; - - this.getTargetProps = function (controllerData) { - var targetEntity = controllerData.rayPicks[this.hand].objectID; - if (targetEntity) { - var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); - if (entityIsGrabbable(gtProps)) { - // if we've attempted to grab a child, roll up to the root of the tree - var groupRootProps = findGroupParent(controllerData, gtProps); - if (entityIsGrabbable(groupRootProps)) { - return groupRootProps; - } - return gtProps; - } - } - return null; - }; - - this.isReady = function (controllerData) { - if (HMD.active) { - if (this.notPointingAtEntity(controllerData)) { - return makeRunningValues(false, [], []); - } - - this.distanceHolding = false; - this.distanceRotating = false; - - if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { - var targetProps = this.getTargetProps(controllerData); - if (targetProps && (targetProps.dynamic && targetProps.parentID === Uuid.NULL)) { - return makeRunningValues(false, [], []); // let farActionGrabEntity handle it - } else { - this.prepareDistanceRotatingData(controllerData); - return makeRunningValues(true, [], []); - } - } else { - this.checkForUnexpectedChildren(controllerData); - this.destroyContextOverlay(); - return makeRunningValues(false, [], []); - } - } - return makeRunningValues(false, [], []); - }; - - this.run = function (controllerData) { - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.targetIsNull()) { - this.endFarParentGrab(controllerData); - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - this.highlightedEntity = null; - return makeRunningValues(false, [], []); - } - this.intersectionDistance = controllerData.rayPicks[this.hand].distance; - - var otherModuleName = this.hand === RIGHT_HAND ? "LeftFarParentGrabEntity" : "RightFarParentGrabEntity"; - var otherFarGrabModule = getEnabledModuleByName(otherModuleName); - - // gather up the readiness of the near-grab modules - var nearGrabNames = [ - this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar", - this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", - this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity" - ]; - if (!this.grabbing) { - nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"); - nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); - } - - var nearGrabReadiness = []; - for (var i = 0; i < nearGrabNames.length; i++) { - var nearGrabModule = getEnabledModuleByName(nearGrabNames[i]); - var ready = nearGrabModule ? nearGrabModule.isReady(controllerData) : makeRunningValues(false, [], []); - nearGrabReadiness.push(ready); - } - - if (this.targetEntityID) { - // if we are doing a distance grab and the object gets close enough to the controller, - // stop the far-grab so the near-grab or equip can take over. - for (var k = 0; k < nearGrabReadiness.length; k++) { - if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.targetEntityID)) { - this.endFarParentGrab(controllerData); - return makeRunningValues(false, [], []); - } - } - - this.continueDistanceHolding(controllerData); - } else { - // if we are doing a distance search and this controller moves into a position - // where it could near-grab something, stop searching. - for (var j = 0; j < nearGrabReadiness.length; j++) { - if (nearGrabReadiness[j].active) { - this.endFarParentGrab(controllerData); - return makeRunningValues(false, [], []); - } - } - - var rayPickInfo = controllerData.rayPicks[this.hand]; - if (rayPickInfo.type === Picks.INTERSECTED_ENTITY) { - if (controllerData.triggerClicks[this.hand]) { - var entityID = rayPickInfo.objectID; - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - this.highlightedEntity = null; - var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); - if (targetProps.href !== "") { - AddressManager.handleLookupString(targetProps.href); - return makeRunningValues(false, [], []); - } - - this.targetObject = new TargetObject(entityID, targetProps); - this.targetObject.parentProps = getEntityParents(targetProps); - - if (this.contextOverlayTimer) { - Script.clearTimeout(this.contextOverlayTimer); - } - this.contextOverlayTimer = false; - if (entityID === this.entityWithContextOverlay) { - this.destroyContextOverlay(); - } else { - Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); - } - - var targetEntity = this.targetObject.getTargetEntity(); - entityID = targetEntity.id; - targetProps = targetEntity.props; - - if (targetProps.dynamic || this.targetObject.entityProps.dynamic) { - // let farActionGrabEntity handle it - return makeRunningValues(false, [], []); - } - - if (entityIsGrabbable(targetProps) || entityIsGrabbable(this.targetObject.entityProps)) { - - if (!this.distanceRotating) { - this.targetEntityID = entityID; - this.grabbedDistance = rayPickInfo.distance; - } - - if (otherFarGrabModule.targetEntityID === this.targetEntityID && - otherFarGrabModule.distanceHolding) { - this.prepareDistanceRotatingData(controllerData); - this.distanceRotate(otherFarGrabModule); - } else { - this.distanceHolding = true; - this.distanceRotating = false; - this.startFarParentGrab(controllerData, targetProps); - } - } - } else { - var targetEntityID = rayPickInfo.objectID; - if (this.highlightedEntity !== targetEntityID) { - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); - - var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps); - selectionTargetObject.parentProps = getEntityParents(selectionTargetProps); - var selectionTargetEntity = selectionTargetObject.getTargetEntity(); - - if (entityIsGrabbable(selectionTargetEntity.props) || - entityIsGrabbable(selectionTargetObject.entityProps)) { - - Selection.addToSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", rayPickInfo.objectID); - } - this.highlightedEntity = rayPickInfo.objectID; - } - - if (!this.entityWithContextOverlay) { - var _this = this; - - if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) { - if (_this.contextOverlayTimer) { - Script.clearTimeout(_this.contextOverlayTimer); - } - _this.contextOverlayTimer = false; - _this.potentialEntityWithContextOverlay = rayPickInfo.objectID; - } - - if (!_this.contextOverlayTimer) { - _this.contextOverlayTimer = Script.setTimeout(function () { - if (!_this.entityWithContextOverlay && - _this.contextOverlayTimer && - _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var cotProps = Entities.getEntityProperties(rayPickInfo.objectID, - DISPATCHER_PROPERTIES); - var pointerEvent = { - type: "Move", - id: _this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, - rayPickInfo.intersection, cotProps), - pos3D: rayPickInfo.intersection, - normal: rayPickInfo.surfaceNormal, - direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), - button: "Secondary" - }; - if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) { - _this.entityWithContextOverlay = rayPickInfo.objectID; - } - } - _this.contextOverlayTimer = false; - }, 500); - } - } - } - } else if (this.distanceRotating) { - this.distanceRotate(otherFarGrabModule); - } else if (this.highlightedEntity) { - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - this.highlightedEntity = null; - } - } - return this.exitIfDisabled(controllerData); - }; - - this.exitIfDisabled = function(controllerData) { - var moduleName = this.hand === RIGHT_HAND ? "RightDisableModules" : "LeftDisableModules"; - var disableModule = getEnabledModuleByName(moduleName); - if (disableModule) { - if (disableModule.disableModules) { - this.endFarParentGrab(controllerData); - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - this.highlightedEntity = null; - return makeRunningValues(false, [], []); - } - } - var grabbedThing = (this.distanceHolding || this.distanceRotating) ? this.targetObject.entityID : null; - var offset = this.calculateOffset(controllerData); - var laserLockInfo = makeLaserLockInfo(grabbedThing, false, this.hand, offset); - return makeRunningValues(true, [], [], laserLockInfo); - }; - - this.calculateOffset = function(controllerData) { - if (this.distanceHolding || this.distanceRotating) { - var targetProps = Entities.getEntityProperties(this.targetObject.entityID, - [ "position", "rotation", "registrationPoint", "dimensions" ]); - return worldPositionToRegistrationFrameMatrix(targetProps, controllerData.rayPicks[this.hand].intersection); - } - return undefined; - }; - } - - var leftFarParentGrabEntity = new FarParentGrabEntity(LEFT_HAND); - var rightFarParentGrabEntity = new FarParentGrabEntity(RIGHT_HAND); - - enableDispatcherModule("LeftFarParentGrabEntity", leftFarParentGrabEntity); - enableDispatcherModule("RightFarParentGrabEntity", rightFarParentGrabEntity); - - function cleanup() { - disableDispatcherModule("LeftFarParentGrabEntity"); - disableDispatcherModule("RightFarParentGrabEntity"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js deleted file mode 100644 index ddff35b9e7..0000000000 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ /dev/null @@ -1,250 +0,0 @@ -"use strict"; - -// nearActionGrabEntity.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, - getControllerJointIndex, getGrabbableData, enableDispatcherModule, disableDispatcherModule, - propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable, - MSECS_PER_SEC, makeDispatcherModuleParameters, makeRunningValues, - TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity, - HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity, Uuid, - DISPATCHER_PROPERTIES, HMD -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); -Script.include("/~/system/libraries/cloneEntityUtils.js"); - -(function() { - - function NearActionGrabEntity(hand) { - this.hand = hand; - this.targetEntityID = null; - this.actionID = null; // action this script created... - - this.parameters = makeDispatcherModuleParameters( - 500, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100); - - var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position - var ACTION_TTL = 15; // seconds - var ACTION_TTL_REFRESH = 5; - - // XXX does handJointIndex change if the avatar changes? - this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - this.controllerJointIndex = getControllerJointIndex(this.hand); - - - // handPosition is where the avatar's hand appears to be, in-world. - this.getHandPosition = function () { - if (this.hand === RIGHT_HAND) { - return MyAvatar.getRightPalmPosition(); - } else { - return MyAvatar.getLeftPalmPosition(); - } - }; - - this.getHandRotation = function () { - if (this.hand === RIGHT_HAND) { - return MyAvatar.getRightPalmRotation(); - } else { - return MyAvatar.getLeftPalmRotation(); - } - }; - - - this.startNearGrabAction = function (controllerData, targetProps) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - - var grabbableData = getGrabbableData(targetProps); - this.grabFollowsController = grabbableData.grabFollowsController; - this.kinematicGrab = grabbableData.grabKinematic; - - var handJointIndex; - if (HMD.mounted && HMD.isHandControllerAvailable() && grabbableData.grabFollowsController) { - handJointIndex = getControllerJointIndex(this.hand); - } else { - handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - } - this.offsetPosition = Entities.worldToLocalPosition(targetProps.position, MyAvatar.SELF_ID, handJointIndex); - this.offsetRotation = Entities.worldToLocalRotation(targetProps.rotation, MyAvatar.SELF_ID, handJointIndex); - - var now = Date.now(); - this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); - - if (this.actionID) { - Entities.deleteAction(this.targetEntityID, this.actionID); - } - this.actionID = Entities.addAction("hold", this.targetEntityID, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: this.kinematicGrab, - kinematicSetVelocity: true, - ignoreIK: this.grabFollowsController - }); - if (this.actionID === Uuid.NULL) { - this.actionID = null; - return; - } - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'grab', - grabbedEntity: this.targetEntityID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "startNearGrab", args); - }; - - // this is for when the action is going to time-out - this.refreshNearGrabAction = function (controllerData) { - var now = Date.now(); - if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSECS_PER_SEC) { - // if less than a 5 seconds left, refresh the actions ttl - var success = Entities.updateAction(this.targetEntityID, this.actionID, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: this.kinematicGrab, - kinematicSetVelocity: true, - ignoreIK: this.grabFollowsController - }); - if (success) { - this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); - } - } - }; - - this.endNearGrabAction = function () { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "releaseGrab", args); - - Entities.deleteAction(this.targetEntityID, this.actionID); - this.actionID = null; - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'release', - grabbedEntity: this.targetEntityID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - - this.targetEntityID = null; - }; - - this.getTargetProps = function (controllerData) { - // nearbyEntityProperties is already sorted by distance from controller - var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - for (var i = 0; i < nearbyEntityProperties.length; i++) { - var props = nearbyEntityProperties[i]; - if (props.distance > NEAR_GRAB_RADIUS * sensorScaleFactor) { - break; - } - if (entityIsGrabbable(props) || entityIsCloneable(props)) { - if (!entityIsCloneable(props)) { - // if we've attempted to grab a non-cloneable child, roll up to the root of the tree - var groupRootProps = findGroupParent(controllerData, props); - if (entityIsGrabbable(groupRootProps)) { - return groupRootProps; - } - } - return props; - } - } - return null; - }; - - this.isReady = function (controllerData) { - this.targetEntityID = null; - - var targetProps = this.getTargetProps(controllerData); - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE && - controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { - return makeRunningValues(false, [], []); - } - - if (targetProps) { - if ((!propsArePhysical(targetProps) && !propsAreCloneDynamic(targetProps)) || - targetProps.parentID !== Uuid.NULL) { - return makeRunningValues(false, [], []); // let nearParentGrabEntity handle it - } else { - this.targetEntityID = targetProps.id; - return makeRunningValues(true, [this.targetEntityID], []); - } - } else { - return makeRunningValues(false, [], []); - } - }; - - this.run = function (controllerData) { - if (this.actionID) { - if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE && - controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { - this.endNearGrabAction(); - return makeRunningValues(false, [], []); - } - - this.refreshNearGrabAction(controllerData); - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "continueNearGrab", args); - } else { - - // still searching / highlighting - var readiness = this.isReady (controllerData); - if (!readiness.active) { - return readiness; - } - - var targetProps = this.getTargetProps(controllerData); - if (targetProps) { - if (controllerData.triggerClicks[this.hand] || - controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) { - // switch to grabbing - var targetCloneable = entityIsCloneable(targetProps); - if (targetCloneable) { - var cloneID = cloneEntity(targetProps); - var cloneProps = Entities.getEntityProperties(cloneID, DISPATCHER_PROPERTIES); - this.targetEntityID = cloneID; - this.startNearGrabAction(controllerData, cloneProps); - } else { - this.startNearGrabAction(controllerData, targetProps); - } - } - } - } - - return makeRunningValues(true, [this.targetEntityID], []); - }; - - this.cleanup = function () { - if (this.targetEntityID) { - this.endNearGrabAction(); - } - }; - } - - var leftNearActionGrabEntity = new NearActionGrabEntity(LEFT_HAND); - var rightNearActionGrabEntity = new NearActionGrabEntity(RIGHT_HAND); - - enableDispatcherModule("LeftNearActionGrabEntity", leftNearActionGrabEntity); - enableDispatcherModule("RightNearActionGrabEntity", rightNearActionGrabEntity); - - function cleanup() { - leftNearActionGrabEntity.cleanup(); - rightNearActionGrabEntity.cleanup(); - disableDispatcherModule("LeftNearActionGrabEntity"); - disableDispatcherModule("RightNearActionGrabEntity"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js deleted file mode 100644 index 13557bdb7e..0000000000 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ /dev/null @@ -1,359 +0,0 @@ -"use strict"; - -// nearParentGrabEntity.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - - -/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, - enableDispatcherModule, disableDispatcherModule, propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, - TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, - findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH, - HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME, - TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, NEAR_GRAB_DISTANCE, - distanceBetweenEntityLocalPositionAndBoundingBox, getGrabbableData, getGrabPointSphereOffset, DISPATCHER_PROPERTIES -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/cloneEntityUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { - - // XXX this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; - // XXX this.kinematicGrab = (grabbableData.kinematic !== undefined) ? grabbableData.kinematic : NEAR_GRABBING_KINEMATIC; - - function NearParentingGrabEntity(hand) { - this.hand = hand; - this.targetEntityID = null; - this.grabbing = false; - this.previousParentID = {}; - this.previousParentJointIndex = {}; - this.previouslyUnhooked = {}; - this.lastUnequipCheckTime = 0; - this.autoUnequipCounter = 0; - this.lastUnexpectedChildrenCheckTime = 0; - this.robbed = false; - this.cloneAllowed = true; - - this.parameters = makeDispatcherModuleParameters( - 500, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100); - - this.thisHandIsParent = function(props) { - if (!props) { - return false; - } - - if (props.parentID !== MyAvatar.sessionUUID && props.parentID !== MyAvatar.SELF_ID) { - return false; - } - - var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - if (props.parentJointIndex === handJointIndex) { - return true; - } - - if (props.parentJointIndex === getControllerJointIndex(this.hand)) { - return true; - } - - var controllerCRJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? - "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : - "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"); - - if (props.parentJointIndex === controllerCRJointIndex) { - return true; - } - - return false; - }; - - this.getOtherModule = function() { - return this.hand === RIGHT_HAND ? leftNearParentingGrabEntity : rightNearParentingGrabEntity; - }; - - this.otherHandIsParent = function(props) { - var otherModule = this.getOtherModule(); - return (otherModule.thisHandIsParent(props) && otherModule.grabbing); - }; - - this.startNearParentingGrabEntity = function (controllerData, targetProps) { - var grabData = getGrabbableData(targetProps); - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - - var handJointIndex; - if (grabData.grabFollowsController) { - handJointIndex = getControllerJointIndex(this.hand); - } else { - handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - } - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(targetProps.id, "startNearGrab", args); - - var reparentProps = { - parentID: MyAvatar.SELF_ID, - parentJointIndex: handJointIndex, - localVelocity: {x: 0, y: 0, z: 0}, - localAngularVelocity: {x: 0, y: 0, z: 0} - }; - - if (this.thisHandIsParent(targetProps)) { - // this should never happen, but if it does, don't set previous parent to be this hand. - this.previousParentID[targetProps.id] = null; - this.previousParentJointIndex[targetProps.id] = -1; - } else if (this.otherHandIsParent(targetProps)) { - var otherModule = this.getOtherModule(); - this.previousParentID[this.grabbedThingID] = otherModule.previousParentID[this.grabbedThingID]; - this.previousParentJointIndex[this.grabbedThingID] = otherModule.previousParentJointIndex[this.grabbedThingID]; - otherModule.robbed = true; - } else { - this.previousParentID[targetProps.id] = targetProps.parentID; - this.previousParentJointIndex[targetProps.id] = targetProps.parentJointIndex; - } - - this.targetEntityID = targetProps.id; - Entities.editEntity(targetProps.id, reparentProps); - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'grab', - grabbedEntity: targetProps.id, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - this.grabbing = true; - }; - - this.endNearParentingGrabEntity = function (controllerData) { - var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; - if (this.thisHandIsParent(props) && !this.robbed) { - Entities.editEntity(this.targetEntityID, { - parentID: this.previousParentID[this.targetEntityID], - parentJointIndex: this.previousParentJointIndex[this.targetEntityID], - localVelocity: {x: 0, y: 0, z: 0}, - localAngularVelocity: {x: 0, y: 0, z: 0} - }); - } - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "releaseGrab", args); - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'release', - grabbedEntity: this.targetEntityID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - - this.grabbing = false; - this.targetEntityID = null; - this.robbed = false; - }; - - this.checkForChildTooFarAway = function (controllerData) { - var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; - var now = Date.now(); - if (now - this.lastUnequipCheckTime > MSECS_PER_SEC * TEAR_AWAY_CHECK_TIME) { - this.lastUnequipCheckTime = now; - if (props.parentID === MyAvatar.SELF_ID) { - var tearAwayDistance = TEAR_AWAY_DISTANCE * MyAvatar.sensorToWorldScale; - var controllerIndex = - this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand; - var controllerGrabOffset = getGrabPointSphereOffset(controllerIndex, true); - controllerGrabOffset = Vec3.multiply(-MyAvatar.sensorToWorldScale, controllerGrabOffset); - var distance = distanceBetweenEntityLocalPositionAndBoundingBox(props, controllerGrabOffset); - if (distance > tearAwayDistance) { - this.autoUnequipCounter++; - } else { - this.autoUnequipCounter = 0; - } - if (this.autoUnequipCounter >= TEAR_AWAY_COUNT) { - return true; - } - } - } - return false; - }; - - - this.checkForUnexpectedChildren = function (controllerData) { - // sometimes things can get parented to a hand and this script is unaware. Search for such entities and - // unhook them. - - var now = Date.now(); - var UNEXPECTED_CHILDREN_CHECK_TIME = 0.1; // seconds - if (now - this.lastUnexpectedChildrenCheckTime > MSECS_PER_SEC * UNEXPECTED_CHILDREN_CHECK_TIME) { - this.lastUnexpectedChildrenCheckTime = now; - - var children = findHandChildEntities(this.hand); - var _this = this; - - children.forEach(function(childID) { - // we appear to be holding something and this script isn't in a state that would be holding something. - // unhook it. if we previously took note of this entity's parent, put it back where it was. This - // works around some problems that happen when more than one hand or avatar is passing something around. - if (_this.previousParentID[childID]) { - var previousParentID = _this.previousParentID[childID]; - var previousParentJointIndex = _this.previousParentJointIndex[childID]; - - // The main flaw with keeping track of previous parentage in individual scripts is: - // (1) A grabs something (2) B takes it from A (3) A takes it from B (4) A releases it - // now A and B will take turns passing it back to the other. Detect this and stop the loop here... - var UNHOOK_LOOP_DETECT_MS = 200; - if (_this.previouslyUnhooked[childID]) { - if (now - _this.previouslyUnhooked[childID] < UNHOOK_LOOP_DETECT_MS) { - previousParentID = Uuid.NULL; - previousParentJointIndex = -1; - } - } - _this.previouslyUnhooked[childID] = now; - - Entities.editEntity(childID, { - parentID: previousParentID, - parentJointIndex: previousParentJointIndex - }); - } else { - Entities.editEntity(childID, { parentID: Uuid.NULL }); - } - }); - } - }; - - this.getTargetProps = function (controllerData) { - // nearbyEntityProperties is already sorted by length from controller - var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - var nearGrabDistance = NEAR_GRAB_DISTANCE * sensorScaleFactor; - var nearGrabRadius = NEAR_GRAB_RADIUS * sensorScaleFactor; - for (var i = 0; i < nearbyEntityProperties.length; i++) { - var props = nearbyEntityProperties[i]; - var grabPosition = controllerData.controllerLocations[this.hand].position; // Is offset from hand position. - var dist = distanceBetweenPointAndEntityBoundingBox(grabPosition, props); - var distance = Vec3.distance(grabPosition, props.position); - if ((dist > nearGrabDistance) || - (distance > nearGrabRadius)) { // Only smallish entities can be near grabbed. - continue; - } - if (entityIsGrabbable(props) || entityIsCloneable(props)) { - if (!entityIsCloneable(props)) { - // if we've attempted to grab a non-cloneable child, roll up to the root of the tree - var groupRootProps = findGroupParent(controllerData, props); - if (entityIsGrabbable(groupRootProps)) { - return groupRootProps; - } - } - return props; - } - } - return null; - }; - - this.isReady = function (controllerData, deltaTime) { - this.targetEntityID = null; - this.grabbing = false; - - var targetProps = this.getTargetProps(controllerData); - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE && - controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { - this.checkForUnexpectedChildren(controllerData); - this.robbed = false; - this.cloneAllowed = true; - return makeRunningValues(false, [], []); - } - - if (targetProps) { - if ((propsArePhysical(targetProps) || propsAreCloneDynamic(targetProps)) && - targetProps.parentID === Uuid.NULL) { - this.robbed = false; - return makeRunningValues(false, [], []); // let nearActionGrabEntity handle it - } else { - this.targetEntityID = targetProps.id; - return makeRunningValues(true, [this.targetEntityID], []); - } - } else { - this.robbed = false; - return makeRunningValues(false, [], []); - } - }; - - this.run = function (controllerData, deltaTime) { - if (this.grabbing) { - if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE && - controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { - this.endNearParentingGrabEntity(controllerData); - return makeRunningValues(false, [], []); - } - - var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; - if (!props) { - // entity was deleted - this.grabbing = false; - this.targetEntityID = null; - this.robbed = false; - return makeRunningValues(false, [], []); - } - - if (this.checkForChildTooFarAway(controllerData)) { - // if the held entity moves too far from the hand, release it - print("nearParentGrabEntity -- autoreleasing held item because it is far from hand"); - this.endNearParentingGrabEntity(controllerData); - return makeRunningValues(false, [], []); - } - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "continueNearGrab", args); - } else { - // still searching - var readiness = this.isReady(controllerData); - if (!readiness.active) { - this.robbed = false; - return readiness; - } - if (controllerData.triggerClicks[this.hand] || controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) { - // switch to grab - var targetProps = this.getTargetProps(controllerData); - var targetCloneable = entityIsCloneable(targetProps); - - if (targetCloneable) { - if (this.cloneAllowed) { - var cloneID = cloneEntity(targetProps); - if (cloneID !== null) { - var cloneProps = Entities.getEntityProperties(cloneID, DISPATCHER_PROPERTIES); - this.grabbing = true; - this.targetEntityID = cloneID; - this.startNearParentingGrabEntity(controllerData, cloneProps); - this.cloneAllowed = false; // prevent another clone call until inputs released - } - } - } else if (targetProps) { - this.grabbing = true; - this.startNearParentingGrabEntity(controllerData, targetProps); - } - } - } - - return makeRunningValues(true, [this.targetEntityID], []); - }; - - this.cleanup = function () { - if (this.targetEntityID) { - this.endNearParentingGrabEntity(); - } - }; - } - - var leftNearParentingGrabEntity = new NearParentingGrabEntity(LEFT_HAND); - var rightNearParentingGrabEntity = new NearParentingGrabEntity(RIGHT_HAND); - - enableDispatcherModule("LeftNearParentingGrabEntity", leftNearParentingGrabEntity); - enableDispatcherModule("RightNearParentingGrabEntity", rightNearParentingGrabEntity); - - function cleanup() { - leftNearParentingGrabEntity.cleanup(); - rightNearParentingGrabEntity.cleanup(); - disableDispatcherModule("LeftNearParentingGrabEntity"); - disableDispatcherModule("RightNearParentingGrabEntity"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index 2114f2c0b2..86ff7701c3 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -32,22 +32,13 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/mouseHMD.js", "controllerModules/scaleEntity.js", "controllerModules/nearGrabHyperLinkEntity.js", - "controllerModules/nearTabletHighlight.js" + "controllerModules/nearTabletHighlight.js", + "controllerModules/nearGrabEntity.js", + "controllerModules/farGrabEntity.js" ]; -if (Settings.getValue("useTraitsGrab", true)) { - CONTOLLER_SCRIPTS.push("controllerModules/nearGrabEntity.js"); - CONTOLLER_SCRIPTS.push("controllerModules/farGrabEntity.js"); -} else { - CONTOLLER_SCRIPTS.push("controllerModules/nearParentGrabEntity.js"); - CONTOLLER_SCRIPTS.push("controllerModules/nearActionGrabEntity.js"); - CONTOLLER_SCRIPTS.push("controllerModules/farActionGrabEntityDynOnly.js"); - CONTOLLER_SCRIPTS.push("controllerModules/farParentGrabEntity.js"); -} - var DEBUG_MENU_ITEM = "Debug defaultScripts.js"; - function runDefaultsTogether() { for (var j in CONTOLLER_SCRIPTS) { if (CONTOLLER_SCRIPTS.hasOwnProperty(j)) { diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 4ef2dca32f..ca3b43bd37 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -25,7 +25,7 @@ Script.include("/~/system/libraries/utils.js"); Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -var FAR_GRAB_JOINT = 65526; // FARGRAB_MOUSE_INDEX +var MOUSE_GRAB_JOINT = 65526; // FARGRAB_MOUSE_INDEX var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed @@ -321,10 +321,10 @@ Grabber.prototype.pressEvent = function(event) { nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction); this.pointOnPlane = Vec3.sum(cameraPosition, nearestPoint); - MyAvatar.setJointTranslation(FAR_GRAB_JOINT, MyAvatar.worldToJointPoint(this.startPosition)); - MyAvatar.setJointRotation(FAR_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation)); - + // compute the grab offset (points from point of grab to object center) this.offset = Vec3.subtract(this.startPosition, this.pointOnPlane); // offset in world-space + MyAvatar.setJointTranslation(MOUSE_GRAB_JOINT, MyAvatar.worldToJointPoint(this.startPosition)); + MyAvatar.setJointRotation(MOUSE_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation)); this.computeNewGrabPlane(); this.moveEvent(event); @@ -337,7 +337,11 @@ Grabber.prototype.pressEvent = function(event) { grabbedEntity: this.entityID })); - this.grabID = MyAvatar.grab(this.entityID, FAR_GRAB_JOINT, ZERO_VEC3, IDENTITY_QUAT); + if (this.grabID) { + MyAvatar.releaseGrab(this.grabID); + this.grabID = null; + } + this.grabID = MyAvatar.grab(this.entityID, MOUSE_GRAB_JOINT, ZERO_VEC3, IDENTITY_QUAT); // TODO: play sounds again when we aren't leaking AudioInjector threads //Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME }); @@ -373,7 +377,7 @@ Grabber.prototype.releaseEvent = function(event) { this.grabID = null; } - MyAvatar.clearJointData(FAR_GRAB_JOINT); + MyAvatar.clearJointData(MOUSE_GRAB_JOINT); // TODO: play sounds again when we aren't leaking AudioInjector threads //Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME }); @@ -421,7 +425,7 @@ Grabber.prototype.moveEventProcess = function() { var deltaQ = Quat.angleAxis(angle, axis); this.lastRotation = Quat.multiply(deltaQ, this.lastRotation); - MyAvatar.setJointRotation(FAR_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation)); + MyAvatar.setJointRotation(MOUSE_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation)); } else { var newPointOnPlane; @@ -446,7 +450,7 @@ Grabber.prototype.moveEventProcess = function() { } } - MyAvatar.setJointTranslation(FAR_GRAB_JOINT, MyAvatar.worldToJointPoint(Vec3.sum(newPointOnPlane, this.offset))); + MyAvatar.setJointTranslation(MOUSE_GRAB_JOINT, MyAvatar.worldToJointPoint(Vec3.sum(newPointOnPlane, this.offset))); } this.scheduleMouseMoveProcessor(); From e8676f63c673a15670f2685c6538639aed48d87a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Jan 2019 13:50:56 -0800 Subject: [PATCH 11/46] release grab if scripts are reloaded before grab is released --- scripts/system/controllers/grab.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index ca3b43bd37..3481639cc5 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -479,6 +479,10 @@ Grabber.prototype.keyPressEvent = function(event) { Grabber.prototype.cleanup = function() { Pointers.removePointer(this.mouseRayEntities); Picks.removePick(this.mouseRayOverlays); + if (this.grabID) { + MyAvatar.releaseGrab(this.grabID); + this.grabID = null; + } }; var grabber = new Grabber(); From b5326936d814ed1d3842ac458272015e73f8b69c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 15 Jan 2019 14:17:51 -0800 Subject: [PATCH 12/46] grab.js will now ignore click-to-equip entities --- .../controllerModules/equipEntity.js | 12 +++--- scripts/system/controllers/grab.js | 7 ++-- .../libraries/controllerDispatcherUtils.js | 39 ++++++------------- 3 files changed, 21 insertions(+), 37 deletions(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index c61e46c8eb..b1c1bc7765 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -6,11 +6,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera, print, - getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, entityIsFarGrabbedByOther, - Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions, - Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable, - cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode, getGrabbableData +/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera, print, getControllerJointIndex, + enableDispatcherModule, disableDispatcherModule, entityIsFarGrabbedByOther, Messages, makeDispatcherModuleParameters, + makeRunningValues, Settings, entityHasActions, Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, + entityIsCloneable, cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode, getGrabbableData, + entityIsEquippable */ Script.include("/~/system/libraries/Xform.js"); @@ -767,7 +767,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var entityProperties = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); entityProperties.id = entityID; var hasEquipData = getWearableData(entityProperties); - if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID && !entityIsFarGrabbedByOther(entityID)) { + if (hasEquipData && entityIsEquippable(entityProperties)) { entityProperties.id = entityID; var rightHandPosition = MyAvatar.getJointPosition("RightHand"); var leftHandPosition = MyAvatar.getJointPosition("LeftHand"); diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 3481639cc5..1fb82d3843 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -257,15 +257,12 @@ Grabber.prototype.pressEvent = function(event) { if (isInEditMode() || HMD.active) { return; } - if (event.button !== "LEFT") { return; } - if (event.isAlt || event.isMeta) { return; } - if (Overlays.getOverlayAtPoint(Reticle.position) > 0) { // the mouse is pointing at an overlay; don't look for entities underneath the overlay. return; @@ -287,6 +284,10 @@ Grabber.prototype.pressEvent = function(event) { // only grab grabbable objects return; } + if (props.grab.equippable) { + // don't mouse-grab click-to-equip entities (let equipEntity.js handle these) + return; + } Pointers.setRenderState(this.mouseRayEntities, "grabbed"); Pointers.setLockEndUUID(this.mouseRayEntities, pickResults.objectID, false); diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 221af07474..faf4b4ed5d 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -58,7 +58,6 @@ NEAR_GRAB_DISTANCE: true, distanceBetweenPointAndEntityBoundingBox:true, entityIsEquipped:true, - entityIsFarGrabbedByOther:true, highlightTargetEntity:true, clearHighlightedEntities:true, unhighlightTargetEntity:true, @@ -323,16 +322,20 @@ isAnothersChildEntity = function (iaceProps) { return false; }; -entityIsGrabbable = function (eigProps) { - var grabbable = getGrabbableData(eigProps).grabbable; + +entityIsEquippable = function (eieProps) { + var grabbable = getGrabbableData(eieProps).grabbable; if (!grabbable || - eigProps.locked || - isAnothersAvatarEntity(eigProps) || - isAnothersChildEntity(eigProps) || - FORBIDDEN_GRAB_TYPES.indexOf(eigProps.type) >= 0) { + isAnothersAvatarEntity(eieProps) || + isAnothersChildEntity(eieProps) || + FORBIDDEN_GRAB_TYPES.indexOf(eieProps.type) >= 0) { return false; } return true; +} + +entityIsGrabbable = function (eigProps) { + return entityIsEquippable(eigProps) && !eigProps.locked; }; clearHighlightedEntities = function() { @@ -561,27 +564,6 @@ entityIsEquipped = function(entityID) { return equippedInRightHand || equippedInLeftHand; }; -entityIsFarGrabbedByOther = function(entityID) { - // by convention, a far grab sets the tag of its action to be far-grab-*owner-session-id*. - var actionIDs = Entities.getActionIDs(entityID); - var myFarGrabTag = "far-grab-" + MyAvatar.sessionUUID; - for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { - var actionID = actionIDs[actionIndex]; - var actionArguments = Entities.getActionArguments(entityID, actionID); - var tag = actionArguments.tag; - if (tag == myFarGrabTag) { - // we see a far-grab-*uuid* shaped tag, but it's our tag, so that's okay. - continue; - } - if (tag.slice(0, 9) == "far-grab-") { - // we see a far-grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. - return true; - } - } - return false; -}; - - worldPositionToRegistrationFrameMatrix = function(wptrProps, pos) { // get world matrix for intersection point var intersectionMat = new Xform({ x: 0, y: 0, z:0, w: 1 }, pos); @@ -620,6 +602,7 @@ if (typeof module !== 'undefined') { BUMPER_ON_VALUE: BUMPER_ON_VALUE, TEAR_AWAY_DISTANCE: TEAR_AWAY_DISTANCE, propsArePhysical: propsArePhysical, + entityIsEquippable: entityIsEquippable, entityIsGrabbable: entityIsGrabbable, NEAR_GRAB_RADIUS: NEAR_GRAB_RADIUS, projectOntoOverlayXYPlane: projectOntoOverlayXYPlane, From 84806247973cd7544da7032ce623f7cde3a86e6f Mon Sep 17 00:00:00 2001 From: Clement Date: Fri, 14 Dec 2018 17:19:46 -0800 Subject: [PATCH 13/46] Limit upstream data to avatar mixer --- assignment-client/src/Agent.cpp | 72 +------------------ assignment-client/src/Agent.h | 3 - .../src/avatars/ScriptableAvatar.cpp | 41 ++++++++++- .../src/avatars/ScriptableAvatar.h | 10 +++ interface/src/avatar/AvatarManager.cpp | 2 - interface/src/avatar/MyAvatar.cpp | 39 ++++++++-- interface/src/avatar/MyAvatar.h | 6 ++ libraries/avatars/src/AvatarData.cpp | 13 ++-- libraries/avatars/src/AvatarData.h | 4 +- libraries/avatars/src/AvatarHashMap.h | 3 + libraries/avatars/src/ClientTraitsHandler.cpp | 13 ++-- libraries/avatars/src/ClientTraitsHandler.h | 2 +- 12 files changed, 113 insertions(+), 95 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index cc2973f61d..8c9a40c854 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -505,16 +505,6 @@ void Agent::executeScript() { DependencyManager::set(_entityViewer.getTree()); - // Agents should run at 45hz - static const int AVATAR_DATA_HZ = 45; - static const int AVATAR_DATA_IN_MSECS = MSECS_PER_SECOND / AVATAR_DATA_HZ; - QTimer* avatarDataTimer = new QTimer(this); - connect(avatarDataTimer, &QTimer::timeout, this, &Agent::processAgentAvatar); - avatarDataTimer->setSingleShot(false); - avatarDataTimer->setInterval(AVATAR_DATA_IN_MSECS); - avatarDataTimer->setTimerType(Qt::PreciseTimer); - avatarDataTimer->start(); - _scriptEngine->run(); Frame::clearFrameHandler(AUDIO_FRAME_TYPE); @@ -528,8 +518,6 @@ void Agent::executeScript() { recordingInterface->stopRecording(); } - avatarDataTimer->stop(); - setIsAvatar(false); // will stop timers for sending identity packets } @@ -584,20 +572,16 @@ void Agent::setIsAvatar(bool isAvatar) { auto scriptableAvatar = DependencyManager::get(); if (_isAvatar) { - if (!_avatarIdentityTimer) { + if (!_avatarQueryTimer) { // set up the avatar timers - _avatarIdentityTimer = new QTimer(this); _avatarQueryTimer = new QTimer(this); // connect our slot - connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket); connect(_avatarQueryTimer, &QTimer::timeout, this, &Agent::queryAvatars); - static const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000; static const int AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS = 1000; - // start the timers - _avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); // FIXME - we shouldn't really need to constantly send identity packets + // start the timer _avatarQueryTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS); connect(_scriptEngine.data(), &ScriptEngine::update, @@ -609,11 +593,7 @@ void Agent::setIsAvatar(bool isAvatar) { _entityEditSender.setMyAvatar(scriptableAvatar.data()); } else { - if (_avatarIdentityTimer) { - _avatarIdentityTimer->stop(); - delete _avatarIdentityTimer; - _avatarIdentityTimer = nullptr; - + if (_avatarQueryTimer) { _avatarQueryTimer->stop(); delete _avatarQueryTimer; _avatarQueryTimer = nullptr; @@ -646,14 +626,6 @@ void Agent::setIsAvatar(bool isAvatar) { } } -void Agent::sendAvatarIdentityPacket() { - if (_isAvatar) { - auto scriptedAvatar = DependencyManager::get(); - scriptedAvatar->markIdentityDataChanged(); - scriptedAvatar->sendIdentityPacket(); - } -} - void Agent::queryAvatars() { auto scriptedAvatar = DependencyManager::get(); @@ -681,44 +653,6 @@ void Agent::queryAvatars() { { NodeType::AvatarMixer }); } -void Agent::processAgentAvatar() { - if (!_scriptEngine->isFinished() && _isAvatar) { - auto scriptedAvatar = DependencyManager::get(); - - AvatarData::AvatarDataDetail dataDetail = (randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO) ? AvatarData::SendAllData : AvatarData::CullSmallData; - QByteArray avatarByteArray = scriptedAvatar->toByteArrayStateful(dataDetail); - - int maximumByteArraySize = NLPacket::maxPayloadSize(PacketType::AvatarData) - sizeof(AvatarDataSequenceNumber); - - if (avatarByteArray.size() > maximumByteArraySize) { - qWarning() << " scriptedAvatar->toByteArrayStateful() resulted in very large buffer:" << avatarByteArray.size() << "... attempt to drop facial data"; - avatarByteArray = scriptedAvatar->toByteArrayStateful(dataDetail, true); - - if (avatarByteArray.size() > maximumByteArraySize) { - qWarning() << " scriptedAvatar->toByteArrayStateful() without facial data resulted in very large buffer:" << avatarByteArray.size() << "... reduce to MinimumData"; - avatarByteArray = scriptedAvatar->toByteArrayStateful(AvatarData::MinimumData, true); - - if (avatarByteArray.size() > maximumByteArraySize) { - qWarning() << " scriptedAvatar->toByteArrayStateful() MinimumData resulted in very large buffer:" << avatarByteArray.size() << "... FAIL!!"; - return; - } - } - } - - scriptedAvatar->doneEncoding(true); - - static AvatarDataSequenceNumber sequenceNumber = 0; - auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size() + sizeof(sequenceNumber)); - avatarPacket->writePrimitive(sequenceNumber++); - - avatarPacket->write(avatarByteArray); - - auto nodeList = DependencyManager::get(); - - nodeList->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); - } -} - void Agent::encodeFrameOfZeros(QByteArray& encodedZeros) { _flushEncoder = false; static const QByteArray zeros(AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL, 0); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 244f72e624..b8e7652cca 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -81,7 +81,6 @@ private slots: void nodeActivated(SharedNodePointer activatedNode); void nodeKilled(SharedNodePointer killedNode); - void processAgentAvatar(); void processAgentAvatarAudio(); private: @@ -99,7 +98,6 @@ private: void setAvatarSound(SharedSoundPointer avatarSound) { _avatarSound = avatarSound; } - void sendAvatarIdentityPacket(); void queryAvatars(); QString _scriptContents; @@ -110,7 +108,6 @@ private: bool _shouldMuteRecordingAudio { false }; int _numAvatarSoundSentBytes = 0; bool _isAvatar = false; - QTimer* _avatarIdentityTimer = nullptr; QTimer* _avatarQueryTimer = nullptr; QHash _outgoingScriptAudioSequenceNumbers; diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index c61e41fbbe..044ab86942 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -91,6 +91,39 @@ void ScriptableAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { updateJointMappings(); } +int ScriptableAvatar::sendAvatarDataPacket(bool sendAll) { + using namespace std::chrono; + auto now = Clock::now(); + + int MAX_DATA_RATE_MBPS = 3; + int maxDataRateBytesPerSeconds = MAX_DATA_RATE_MBPS * BYTES_PER_KILOBYTE * KILO_PER_MEGA / BITS_IN_BYTE; + int maxDataRateBytesPerMilliseconds = maxDataRateBytesPerSeconds / MSECS_PER_SECOND; + + auto bytesSent = 0; + + if (now > _nextTraitsSendWindow) { + if (getIdentityDataChanged()) { + bytesSent += sendIdentityPacket(); + } + + bytesSent += _clientTraitsHandler->sendChangedTraitsToMixer(); + + // Compute the next send window based on how much data we sent and what + // data rate we're trying to max at. + milliseconds timeUntilNextSend { bytesSent / maxDataRateBytesPerMilliseconds }; + _nextTraitsSendWindow += timeUntilNextSend; + + // Don't let the next send window lag behind if we're not sending a lot of data. + if (_nextTraitsSendWindow < now) { + _nextTraitsSendWindow = now; + } + } + + bytesSent += AvatarData::sendAvatarDataPacket(sendAll); + + return bytesSent; +} + static AnimPose composeAnimPose(const HFMJoint& joint, const glm::quat rotation, const glm::vec3 translation) { glm::mat4 translationMat = glm::translate(translation); glm::mat4 rotationMat = glm::mat4_cast(joint.preRotation * rotation * joint.postRotation); @@ -161,7 +194,13 @@ void ScriptableAvatar::update(float deltatime) { } } - _clientTraitsHandler->sendChangedTraitsToMixer(); + quint64 now = usecTimestampNow(); + quint64 dt = now - _lastSendAvatarDataTime; + + if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS) { + sendAvatarDataPacket(); + _lastSendAvatarDataTime = now; + } } void ScriptableAvatar::updateJointMappings() { diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index df949f8bff..e93be897d5 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -123,6 +123,10 @@ class ScriptableAvatar : public AvatarData, public Dependency { Q_OBJECT + + using Clock = std::chrono::system_clock; + using TimePoint = Clock::time_point; + public: ScriptableAvatar(); @@ -177,6 +181,8 @@ public: virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; + int sendAvatarDataPacket(bool sendAll = false) override; + virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking = false) override; void setHasProceduralBlinkFaceMovement(bool hasProceduralBlinkFaceMovement); @@ -228,6 +234,10 @@ private: /// Loads the joint indices, names from the FST file (if any) void updateJointMappings(); + + quint64 _lastSendAvatarDataTime { 0 }; + + TimePoint _nextTraitsSendWindow; }; #endif // hifi_ScriptableAvatar_h diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 02b10b3f58..e2b548cfbf 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -48,8 +48,6 @@ // 50 times per second - target is 45hz, but this helps account for any small deviations // in the update loop - this also results in ~30hz when in desktop mode which is essentially // what we want -const int CLIENT_TO_AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 50; -static const quint64 MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS = USECS_PER_SECOND / CLIENT_TO_AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND; // We add _myAvatar into the hash with all the other AvatarData, and we use the default NULL QUid as the key. const QUuid MY_AVATAR_KEY; // NULL key diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 91ea8f0291..2fb62de9b7 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -668,12 +668,6 @@ void MyAvatar::update(float deltaTime) { Q_ARG(glm::vec3, (getWorldPosition() - halfBoundingBoxDimensions)), Q_ARG(glm::vec3, (halfBoundingBoxDimensions*2.0f))); - if (getIdentityDataChanged()) { - sendIdentityPacket(); - } - - _clientTraitsHandler->sendChangedTraitsToMixer(); - simulate(deltaTime, true); currentEnergy += energyChargeRate; @@ -3106,6 +3100,39 @@ void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) { _prevShouldDrawHead = shouldDrawHead; } +int MyAvatar::sendAvatarDataPacket(bool sendAll) { + using namespace std::chrono; + auto now = Clock::now(); + + int MAX_DATA_RATE_MBPS = 3; + int maxDataRateBytesPerSeconds = MAX_DATA_RATE_MBPS * BYTES_PER_KILOBYTE * KILO_PER_MEGA / BITS_IN_BYTE; + int maxDataRateBytesPerMilliseconds = maxDataRateBytesPerSeconds / MSECS_PER_SECOND; + + auto bytesSent = 0; + + if (now > _nextTraitsSendWindow) { + if (getIdentityDataChanged()) { + bytesSent += sendIdentityPacket(); + } + + bytesSent += _clientTraitsHandler->sendChangedTraitsToMixer(); + + // Compute the next send window based on how much data we sent and what + // data rate we're trying to max at. + milliseconds timeUntilNextSend { bytesSent / maxDataRateBytesPerMilliseconds }; + _nextTraitsSendWindow += timeUntilNextSend; + + // Don't let the next send window lag behind if we're not sending a lot of data. + if (_nextTraitsSendWindow < now) { + _nextTraitsSendWindow = now; + } + } + + bytesSent += Avatar::sendAvatarDataPacket(sendAll); + + return bytesSent; +} + const float RENDER_HEAD_CUTOFF_DISTANCE = 0.47f; bool MyAvatar::cameraInsideHead(const glm::vec3& cameraPosition) const { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 67a449b274..c7f5462cd1 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -253,6 +253,9 @@ class MyAvatar : public Avatar { const QString DOMINANT_LEFT_HAND = "left"; const QString DOMINANT_RIGHT_HAND = "right"; + using Clock = std::chrono::system_clock; + using TimePoint = Clock::time_point; + public: enum DriveKeys { TRANSLATE_X = 0, @@ -1211,6 +1214,7 @@ public: void setAvatarEntityData(const AvatarEntityMap& avatarEntityData) override; void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) override; void avatarEntityDataToJson(QJsonObject& root) const override; + int sendAvatarDataPacket(bool sendAll = false) override; public slots: @@ -1935,6 +1939,8 @@ private: bool _skeletonModelLoaded { false }; bool _reloadAvatarEntityDataFromSettings { true }; + TimePoint _nextTraitsSendWindow; + Setting::Handle _dominantHandSetting; Setting::Handle _headPitchSetting; Setting::Handle _scaleSetting; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 21e0a6aba2..1699a5d382 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2157,7 +2157,7 @@ void AvatarData::detachAll(const QString& modelURL, const QString& jointName) { setAttachmentData(attachmentData); } -void AvatarData::sendAvatarDataPacket(bool sendAll) { +int AvatarData::sendAvatarDataPacket(bool sendAll) { auto nodeList = DependencyManager::get(); // about 2% of the time, we send a full update (meaning, we transmit all the joint data), even if nothing has changed. @@ -2170,16 +2170,14 @@ void AvatarData::sendAvatarDataPacket(bool sendAll) { int maximumByteArraySize = NLPacket::maxPayloadSize(PacketType::AvatarData) - sizeof(AvatarDataSequenceNumber); if (avatarByteArray.size() > maximumByteArraySize) { - qCWarning(avatars) << "toByteArrayStateful() resulted in very large buffer:" << avatarByteArray.size() << "... attempt to drop facial data"; avatarByteArray = toByteArrayStateful(dataDetail, true); if (avatarByteArray.size() > maximumByteArraySize) { - qCWarning(avatars) << "toByteArrayStateful() without facial data resulted in very large buffer:" << avatarByteArray.size() << "... reduce to MinimumData"; avatarByteArray = toByteArrayStateful(MinimumData, true); if (avatarByteArray.size() > maximumByteArraySize) { qCWarning(avatars) << "toByteArrayStateful() MinimumData resulted in very large buffer:" << avatarByteArray.size() << "... FAIL!!"; - return; + return 0; } } } @@ -2191,18 +2189,20 @@ void AvatarData::sendAvatarDataPacket(bool sendAll) { auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size() + sizeof(sequenceNumber)); avatarPacket->writePrimitive(sequenceNumber++); avatarPacket->write(avatarByteArray); + auto packetSize = avatarPacket->getWireSize(); nodeList->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); + + return packetSize; } -void AvatarData::sendIdentityPacket() { +int AvatarData::sendIdentityPacket() { auto nodeList = DependencyManager::get(); if (_identityDataChanged) { // if the identity data has changed, push the sequence number forwards ++_identitySequenceNumber; } - QByteArray identityData = identityByteArray(); auto packetList = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); @@ -2216,6 +2216,7 @@ void AvatarData::sendIdentityPacket() { }); _identityDataChanged = false; + return identityData.size(); } static const QString JSON_ATTACHMENT_URL = QStringLiteral("modelUrl"); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index ec5ea4a5d0..c2b2a1d031 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1273,12 +1273,12 @@ public slots: * @function MyAvatar.sendAvatarDataPacket * @param {boolean} [sendAll=false] */ - void sendAvatarDataPacket(bool sendAll = false); + virtual int sendAvatarDataPacket(bool sendAll = false); /**jsdoc * @function MyAvatar.sendIdentityPacket */ - void sendIdentityPacket(); + int sendIdentityPacket(); /**jsdoc * @function MyAvatar.setSessionUUID diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index 3bb38dd081..84f9e212f2 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -32,6 +32,9 @@ #include "AvatarData.h" #include "AssociatedTraitValues.h" +const int CLIENT_TO_AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 50; +const quint64 MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS = USECS_PER_SECOND / CLIENT_TO_AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND; + /**jsdoc * Note: An AvatarList API is also provided for Interface and client entity scripts: it is a * synonym for the {@link AvatarManager} API. diff --git a/libraries/avatars/src/ClientTraitsHandler.cpp b/libraries/avatars/src/ClientTraitsHandler.cpp index 3e24c1f9ad..bcbe5308c7 100644 --- a/libraries/avatars/src/ClientTraitsHandler.cpp +++ b/libraries/avatars/src/ClientTraitsHandler.cpp @@ -65,8 +65,9 @@ void ClientTraitsHandler::resetForNewMixer() { _owningAvatar->prepareResetTraitInstances(); } -void ClientTraitsHandler::sendChangedTraitsToMixer() { +int ClientTraitsHandler::sendChangedTraitsToMixer() { std::unique_lock lock(_traitLock); + int bytesWritten = 0; if (hasChangedTraits() || _shouldPerformInitialSend) { // we have at least one changed trait to send @@ -75,7 +76,7 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { auto avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer); if (!avatarMixer || !avatarMixer->getActiveSocket()) { // we don't have an avatar mixer with an active socket, we can't send changed traits at this time - return; + return 0; } // we have a mixer to send to, setup our set traits packet @@ -106,7 +107,7 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { if (initialSend || *simpleIt == Updated) { if (traitType == AvatarTraits::SkeletonModelURL) { - _owningAvatar->packTrait(traitType, *traitsPacketList); + bytesWritten += _owningAvatar->packTrait(traitType, *traitsPacketList); // keep track of our skeleton version in case we get an override back _currentSkeletonVersion = _currentTraitVersion; @@ -123,10 +124,10 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { || instanceIDValuePair.value == Updated) { // this is a changed trait we need to send or we haven't send out trait information yet // ask the owning avatar to pack it - _owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList); + bytesWritten += _owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList); } else if (!initialSend && instanceIDValuePair.value == Deleted) { // pack delete for this trait instance - AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id, + bytesWritten += AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList); } } @@ -136,6 +137,8 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { nodeList->sendPacketList(std::move(traitsPacketList), *avatarMixer); } + + return bytesWritten; } void ClientTraitsHandler::processTraitOverride(QSharedPointer message, SharedNodePointer sendingNode) { diff --git a/libraries/avatars/src/ClientTraitsHandler.h b/libraries/avatars/src/ClientTraitsHandler.h index 3900268101..35499fd2cf 100644 --- a/libraries/avatars/src/ClientTraitsHandler.h +++ b/libraries/avatars/src/ClientTraitsHandler.h @@ -24,7 +24,7 @@ class ClientTraitsHandler : public QObject { public: ClientTraitsHandler(AvatarData* owningAvatar); - void sendChangedTraitsToMixer(); + int sendChangedTraitsToMixer(); bool hasChangedTraits() const { return _hasChangedTraits; } From b11afa48f8b72f924cad6ded76e6149520f6370d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 31 Dec 2018 13:05:53 -0800 Subject: [PATCH 14/46] Move files to new location --- android/{app => apps/interface}/CMakeLists.txt | 0 android/{app => apps/interface}/build.gradle | 0 android/{app => apps/interface}/proguard-rules.pro | 0 .../interface}/src/main/AndroidManifest.xml | 0 .../interface}/src/main/assets/privacy_policy.html | 0 .../{app => apps/interface}/src/main/cpp/native.cpp | 0 .../gvrinterface/InterfaceActivity.java | 0 .../hifiinterface/BreakpadUploaderService.java | 0 .../io/highfidelity/hifiinterface/HifiUtils.java | 0 .../hifiinterface/InterfaceActivity.java | 0 .../hifiinterface/LoginMenuActivity.java | 0 .../io/highfidelity/hifiinterface/MainActivity.java | 0 .../hifiinterface/PermissionChecker.java | 0 .../highfidelity/hifiinterface/SplashActivity.java | 0 .../highfidelity/hifiinterface/WebViewActivity.java | 0 .../hifiinterface/fragment/FriendsFragment.java | 0 .../hifiinterface/fragment/HomeFragment.java | 0 .../hifiinterface/fragment/LoginFragment.java | 0 .../fragment/OnBackPressedListener.java | 0 .../hifiinterface/fragment/PolicyFragment.java | 0 .../hifiinterface/fragment/SettingsFragment.java | 0 .../hifiinterface/fragment/SignupFragment.java | 0 .../hifiinterface/fragment/StartMenuFragment.java | 0 .../hifiinterface/fragment/WebViewFragment.java | 0 .../hifiinterface/provider/Callback.java | 0 .../hifiinterface/provider/DomainProvider.java | 0 .../provider/EndpointUsersProvider.java | 0 .../provider/UserStoryDomainProvider.java | 0 .../hifiinterface/provider/UsersProvider.java | 0 .../receiver/HeadsetStateReceiver.java | 0 .../task/DownloadProfileImageTask.java | 0 .../hifiinterface/view/DomainAdapter.java | 0 .../hifiinterface/view/UserListAdapter.java | 0 .../qtproject/qt5/android/bindings/QtActivity.java | 0 .../qt5/android/bindings/QtActivityLoader.java | 0 .../qt5/android/bindings/QtApplication.java | 0 .../main/res/drawable/default_profile_avatar.xml | 0 .../src/main/res/drawable/domain_placeholder.png | Bin .../res/drawable/encourage_login_background.jpg | Bin .../src/main/res/drawable/hifi_header.xml | 0 .../src/main/res/drawable/hifi_logo_header.xml | 0 .../src/main/res/drawable/hifi_logo_splash.xml | 0 .../src/main/res/drawable/ic_bookmark.xml | 0 .../interface}/src/main/res/drawable/ic_clear.xml | 0 .../interface}/src/main/res/drawable/ic_close.xml | 0 .../src/main/res/drawable/ic_close_black_24dp.xml | 0 .../src/main/res/drawable/ic_delete_black_24dp.xml | 0 .../interface}/src/main/res/drawable/ic_expand.xml | 0 .../src/main/res/drawable/ic_eye_noshow.xml | 0 .../src/main/res/drawable/ic_eye_show.xml | 0 .../src/main/res/drawable/ic_launcher.xml | 0 .../interface}/src/main/res/drawable/ic_menu.xml | 0 .../interface}/src/main/res/drawable/ic_person.xml | 0 .../src/main/res/drawable/ic_right_arrow.xml | 0 .../interface}/src/main/res/drawable/ic_search.xml | 0 .../interface}/src/main/res/drawable/ic_share.xml | 0 .../interface}/src/main/res/drawable/ic_star.xml | 0 .../interface}/src/main/res/drawable/ic_steam.xml | 0 .../src/main/res/drawable/ic_teleporticon.xml | 0 .../src/main/res/drawable/launch_screen.xml | 0 .../src/main/res/drawable/rounded_button_color1.xml | 0 .../src/main/res/drawable/rounded_button_color3.xml | 0 .../src/main/res/drawable/rounded_button_color4.xml | 0 .../main/res/drawable/rounded_secondary_button.xml | 0 .../interface}/src/main/res/drawable/search_bg.xml | 0 .../main/res/drawable/selector_show_password.xml | 0 .../interface}/src/main/res/font/raleway.ttf | Bin .../interface}/src/main/res/font/raleway_bold.xml | 0 .../interface}/src/main/res/font/raleway_italic.xml | 0 .../src/main/res/font/raleway_light_italic.xml | 0 .../interface}/src/main/res/font/raleway_medium.xml | 0 .../src/main/res/font/raleway_semibold.xml | 0 .../main/res/layout/activity_encourage_login.xml | 0 .../src/main/res/layout/activity_main.xml | 0 .../src/main/res/layout/activity_splash.xml | 0 .../src/main/res/layout/activity_web_view.xml | 0 .../interface}/src/main/res/layout/domain_view.xml | 0 .../src/main/res/layout/fragment_friends.xml | 0 .../src/main/res/layout/fragment_home.xml | 0 .../src/main/res/layout/fragment_login.xml | 0 .../src/main/res/layout/fragment_login_menu.xml | 0 .../src/main/res/layout/fragment_policy.xml | 0 .../src/main/res/layout/fragment_signup.xml | 0 .../src/main/res/layout/fragment_web_view.xml | 0 .../src/main/res/layout/navigation_header.xml | 0 .../interface}/src/main/res/layout/user_item.xml | 0 .../interface}/src/main/res/layout/web_drawer.xml | 0 .../src/main/res/menu/menu_navigation.xml | 0 .../interface}/src/main/res/menu/web_view_menu.xml | 0 .../src/main/res/values-w385dp/dimens.xml | 0 .../interface}/src/main/res/values/colors.xml | 0 .../interface}/src/main/res/values/dimens.xml | 0 .../interface}/src/main/res/values/font_certs.xml | 0 .../src/main/res/values/preloaded_fonts.xml | 0 .../interface}/src/main/res/values/strings.xml | 0 .../interface}/src/main/res/values/styles.xml | 0 .../interface}/src/main/res/xml/settings.xml | 0 97 files changed, 0 insertions(+), 0 deletions(-) rename android/{app => apps/interface}/CMakeLists.txt (100%) rename android/{app => apps/interface}/build.gradle (100%) rename android/{app => apps/interface}/proguard-rules.pro (100%) rename android/{app => apps/interface}/src/main/AndroidManifest.xml (100%) rename android/{app => apps/interface}/src/main/assets/privacy_policy.html (100%) rename android/{app => apps/interface}/src/main/cpp/native.cpp (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/gvrinterface/InterfaceActivity.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/BreakpadUploaderService.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/MainActivity.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/fragment/HomeFragment.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/fragment/PolicyFragment.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/provider/Callback.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/provider/DomainProvider.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/provider/EndpointUsersProvider.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/provider/UserStoryDomainProvider.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/provider/UsersProvider.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/receiver/HeadsetStateReceiver.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/task/DownloadProfileImageTask.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java (100%) rename android/{app => apps/interface}/src/main/java/io/highfidelity/hifiinterface/view/UserListAdapter.java (100%) rename android/{app => apps/interface}/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java (100%) rename android/{app => apps/interface}/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java (100%) rename android/{app => apps/interface}/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java (100%) rename android/{app => apps/interface}/src/main/res/drawable/default_profile_avatar.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/domain_placeholder.png (100%) rename android/{app => apps/interface}/src/main/res/drawable/encourage_login_background.jpg (100%) rename android/{app => apps/interface}/src/main/res/drawable/hifi_header.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/hifi_logo_header.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/hifi_logo_splash.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_bookmark.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_clear.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_close.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_close_black_24dp.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_delete_black_24dp.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_expand.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_eye_noshow.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_eye_show.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_launcher.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_menu.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_person.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_right_arrow.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_search.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_share.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_star.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_steam.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/ic_teleporticon.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/launch_screen.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/rounded_button_color1.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/rounded_button_color3.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/rounded_button_color4.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/rounded_secondary_button.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/search_bg.xml (100%) rename android/{app => apps/interface}/src/main/res/drawable/selector_show_password.xml (100%) rename android/{app => apps/interface}/src/main/res/font/raleway.ttf (100%) rename android/{app => apps/interface}/src/main/res/font/raleway_bold.xml (100%) rename android/{app => apps/interface}/src/main/res/font/raleway_italic.xml (100%) rename android/{app => apps/interface}/src/main/res/font/raleway_light_italic.xml (100%) rename android/{app => apps/interface}/src/main/res/font/raleway_medium.xml (100%) rename android/{app => apps/interface}/src/main/res/font/raleway_semibold.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/activity_encourage_login.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/activity_main.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/activity_splash.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/activity_web_view.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/domain_view.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/fragment_friends.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/fragment_home.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/fragment_login.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/fragment_login_menu.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/fragment_policy.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/fragment_signup.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/fragment_web_view.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/navigation_header.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/user_item.xml (100%) rename android/{app => apps/interface}/src/main/res/layout/web_drawer.xml (100%) rename android/{app => apps/interface}/src/main/res/menu/menu_navigation.xml (100%) rename android/{app => apps/interface}/src/main/res/menu/web_view_menu.xml (100%) rename android/{app => apps/interface}/src/main/res/values-w385dp/dimens.xml (100%) rename android/{app => apps/interface}/src/main/res/values/colors.xml (100%) rename android/{app => apps/interface}/src/main/res/values/dimens.xml (100%) rename android/{app => apps/interface}/src/main/res/values/font_certs.xml (100%) rename android/{app => apps/interface}/src/main/res/values/preloaded_fonts.xml (100%) rename android/{app => apps/interface}/src/main/res/values/strings.xml (100%) rename android/{app => apps/interface}/src/main/res/values/styles.xml (100%) rename android/{app => apps/interface}/src/main/res/xml/settings.xml (100%) diff --git a/android/app/CMakeLists.txt b/android/apps/interface/CMakeLists.txt similarity index 100% rename from android/app/CMakeLists.txt rename to android/apps/interface/CMakeLists.txt diff --git a/android/app/build.gradle b/android/apps/interface/build.gradle similarity index 100% rename from android/app/build.gradle rename to android/apps/interface/build.gradle diff --git a/android/app/proguard-rules.pro b/android/apps/interface/proguard-rules.pro similarity index 100% rename from android/app/proguard-rules.pro rename to android/apps/interface/proguard-rules.pro diff --git a/android/app/src/main/AndroidManifest.xml b/android/apps/interface/src/main/AndroidManifest.xml similarity index 100% rename from android/app/src/main/AndroidManifest.xml rename to android/apps/interface/src/main/AndroidManifest.xml diff --git a/android/app/src/main/assets/privacy_policy.html b/android/apps/interface/src/main/assets/privacy_policy.html similarity index 100% rename from android/app/src/main/assets/privacy_policy.html rename to android/apps/interface/src/main/assets/privacy_policy.html diff --git a/android/app/src/main/cpp/native.cpp b/android/apps/interface/src/main/cpp/native.cpp similarity index 100% rename from android/app/src/main/cpp/native.cpp rename to android/apps/interface/src/main/cpp/native.cpp diff --git a/android/app/src/main/java/io/highfidelity/gvrinterface/InterfaceActivity.java b/android/apps/interface/src/main/java/io/highfidelity/gvrinterface/InterfaceActivity.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/gvrinterface/InterfaceActivity.java rename to android/apps/interface/src/main/java/io/highfidelity/gvrinterface/InterfaceActivity.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/BreakpadUploaderService.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/BreakpadUploaderService.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/BreakpadUploaderService.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/BreakpadUploaderService.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/MainActivity.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/MainActivity.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/HomeFragment.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/HomeFragment.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/fragment/HomeFragment.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/HomeFragment.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/PolicyFragment.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/PolicyFragment.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/fragment/PolicyFragment.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/PolicyFragment.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/provider/Callback.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/Callback.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/provider/Callback.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/Callback.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/provider/DomainProvider.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/DomainProvider.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/provider/DomainProvider.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/DomainProvider.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/provider/EndpointUsersProvider.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/EndpointUsersProvider.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/provider/EndpointUsersProvider.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/EndpointUsersProvider.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/provider/UserStoryDomainProvider.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/UserStoryDomainProvider.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/provider/UserStoryDomainProvider.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/UserStoryDomainProvider.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/provider/UsersProvider.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/UsersProvider.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/provider/UsersProvider.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/provider/UsersProvider.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/receiver/HeadsetStateReceiver.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/receiver/HeadsetStateReceiver.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/receiver/HeadsetStateReceiver.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/receiver/HeadsetStateReceiver.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/task/DownloadProfileImageTask.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/task/DownloadProfileImageTask.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/task/DownloadProfileImageTask.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/task/DownloadProfileImageTask.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/view/UserListAdapter.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/view/UserListAdapter.java similarity index 100% rename from android/app/src/main/java/io/highfidelity/hifiinterface/view/UserListAdapter.java rename to android/apps/interface/src/main/java/io/highfidelity/hifiinterface/view/UserListAdapter.java diff --git a/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java b/android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java similarity index 100% rename from android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java rename to android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java diff --git a/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java b/android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java similarity index 100% rename from android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java rename to android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java diff --git a/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java b/android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java similarity index 100% rename from android/app/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java rename to android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java diff --git a/android/app/src/main/res/drawable/default_profile_avatar.xml b/android/apps/interface/src/main/res/drawable/default_profile_avatar.xml similarity index 100% rename from android/app/src/main/res/drawable/default_profile_avatar.xml rename to android/apps/interface/src/main/res/drawable/default_profile_avatar.xml diff --git a/android/app/src/main/res/drawable/domain_placeholder.png b/android/apps/interface/src/main/res/drawable/domain_placeholder.png similarity index 100% rename from android/app/src/main/res/drawable/domain_placeholder.png rename to android/apps/interface/src/main/res/drawable/domain_placeholder.png diff --git a/android/app/src/main/res/drawable/encourage_login_background.jpg b/android/apps/interface/src/main/res/drawable/encourage_login_background.jpg similarity index 100% rename from android/app/src/main/res/drawable/encourage_login_background.jpg rename to android/apps/interface/src/main/res/drawable/encourage_login_background.jpg diff --git a/android/app/src/main/res/drawable/hifi_header.xml b/android/apps/interface/src/main/res/drawable/hifi_header.xml similarity index 100% rename from android/app/src/main/res/drawable/hifi_header.xml rename to android/apps/interface/src/main/res/drawable/hifi_header.xml diff --git a/android/app/src/main/res/drawable/hifi_logo_header.xml b/android/apps/interface/src/main/res/drawable/hifi_logo_header.xml similarity index 100% rename from android/app/src/main/res/drawable/hifi_logo_header.xml rename to android/apps/interface/src/main/res/drawable/hifi_logo_header.xml diff --git a/android/app/src/main/res/drawable/hifi_logo_splash.xml b/android/apps/interface/src/main/res/drawable/hifi_logo_splash.xml similarity index 100% rename from android/app/src/main/res/drawable/hifi_logo_splash.xml rename to android/apps/interface/src/main/res/drawable/hifi_logo_splash.xml diff --git a/android/app/src/main/res/drawable/ic_bookmark.xml b/android/apps/interface/src/main/res/drawable/ic_bookmark.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_bookmark.xml rename to android/apps/interface/src/main/res/drawable/ic_bookmark.xml diff --git a/android/app/src/main/res/drawable/ic_clear.xml b/android/apps/interface/src/main/res/drawable/ic_clear.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_clear.xml rename to android/apps/interface/src/main/res/drawable/ic_clear.xml diff --git a/android/app/src/main/res/drawable/ic_close.xml b/android/apps/interface/src/main/res/drawable/ic_close.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_close.xml rename to android/apps/interface/src/main/res/drawable/ic_close.xml diff --git a/android/app/src/main/res/drawable/ic_close_black_24dp.xml b/android/apps/interface/src/main/res/drawable/ic_close_black_24dp.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_close_black_24dp.xml rename to android/apps/interface/src/main/res/drawable/ic_close_black_24dp.xml diff --git a/android/app/src/main/res/drawable/ic_delete_black_24dp.xml b/android/apps/interface/src/main/res/drawable/ic_delete_black_24dp.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_delete_black_24dp.xml rename to android/apps/interface/src/main/res/drawable/ic_delete_black_24dp.xml diff --git a/android/app/src/main/res/drawable/ic_expand.xml b/android/apps/interface/src/main/res/drawable/ic_expand.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_expand.xml rename to android/apps/interface/src/main/res/drawable/ic_expand.xml diff --git a/android/app/src/main/res/drawable/ic_eye_noshow.xml b/android/apps/interface/src/main/res/drawable/ic_eye_noshow.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_eye_noshow.xml rename to android/apps/interface/src/main/res/drawable/ic_eye_noshow.xml diff --git a/android/app/src/main/res/drawable/ic_eye_show.xml b/android/apps/interface/src/main/res/drawable/ic_eye_show.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_eye_show.xml rename to android/apps/interface/src/main/res/drawable/ic_eye_show.xml diff --git a/android/app/src/main/res/drawable/ic_launcher.xml b/android/apps/interface/src/main/res/drawable/ic_launcher.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_launcher.xml rename to android/apps/interface/src/main/res/drawable/ic_launcher.xml diff --git a/android/app/src/main/res/drawable/ic_menu.xml b/android/apps/interface/src/main/res/drawable/ic_menu.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_menu.xml rename to android/apps/interface/src/main/res/drawable/ic_menu.xml diff --git a/android/app/src/main/res/drawable/ic_person.xml b/android/apps/interface/src/main/res/drawable/ic_person.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_person.xml rename to android/apps/interface/src/main/res/drawable/ic_person.xml diff --git a/android/app/src/main/res/drawable/ic_right_arrow.xml b/android/apps/interface/src/main/res/drawable/ic_right_arrow.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_right_arrow.xml rename to android/apps/interface/src/main/res/drawable/ic_right_arrow.xml diff --git a/android/app/src/main/res/drawable/ic_search.xml b/android/apps/interface/src/main/res/drawable/ic_search.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_search.xml rename to android/apps/interface/src/main/res/drawable/ic_search.xml diff --git a/android/app/src/main/res/drawable/ic_share.xml b/android/apps/interface/src/main/res/drawable/ic_share.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_share.xml rename to android/apps/interface/src/main/res/drawable/ic_share.xml diff --git a/android/app/src/main/res/drawable/ic_star.xml b/android/apps/interface/src/main/res/drawable/ic_star.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_star.xml rename to android/apps/interface/src/main/res/drawable/ic_star.xml diff --git a/android/app/src/main/res/drawable/ic_steam.xml b/android/apps/interface/src/main/res/drawable/ic_steam.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_steam.xml rename to android/apps/interface/src/main/res/drawable/ic_steam.xml diff --git a/android/app/src/main/res/drawable/ic_teleporticon.xml b/android/apps/interface/src/main/res/drawable/ic_teleporticon.xml similarity index 100% rename from android/app/src/main/res/drawable/ic_teleporticon.xml rename to android/apps/interface/src/main/res/drawable/ic_teleporticon.xml diff --git a/android/app/src/main/res/drawable/launch_screen.xml b/android/apps/interface/src/main/res/drawable/launch_screen.xml similarity index 100% rename from android/app/src/main/res/drawable/launch_screen.xml rename to android/apps/interface/src/main/res/drawable/launch_screen.xml diff --git a/android/app/src/main/res/drawable/rounded_button_color1.xml b/android/apps/interface/src/main/res/drawable/rounded_button_color1.xml similarity index 100% rename from android/app/src/main/res/drawable/rounded_button_color1.xml rename to android/apps/interface/src/main/res/drawable/rounded_button_color1.xml diff --git a/android/app/src/main/res/drawable/rounded_button_color3.xml b/android/apps/interface/src/main/res/drawable/rounded_button_color3.xml similarity index 100% rename from android/app/src/main/res/drawable/rounded_button_color3.xml rename to android/apps/interface/src/main/res/drawable/rounded_button_color3.xml diff --git a/android/app/src/main/res/drawable/rounded_button_color4.xml b/android/apps/interface/src/main/res/drawable/rounded_button_color4.xml similarity index 100% rename from android/app/src/main/res/drawable/rounded_button_color4.xml rename to android/apps/interface/src/main/res/drawable/rounded_button_color4.xml diff --git a/android/app/src/main/res/drawable/rounded_secondary_button.xml b/android/apps/interface/src/main/res/drawable/rounded_secondary_button.xml similarity index 100% rename from android/app/src/main/res/drawable/rounded_secondary_button.xml rename to android/apps/interface/src/main/res/drawable/rounded_secondary_button.xml diff --git a/android/app/src/main/res/drawable/search_bg.xml b/android/apps/interface/src/main/res/drawable/search_bg.xml similarity index 100% rename from android/app/src/main/res/drawable/search_bg.xml rename to android/apps/interface/src/main/res/drawable/search_bg.xml diff --git a/android/app/src/main/res/drawable/selector_show_password.xml b/android/apps/interface/src/main/res/drawable/selector_show_password.xml similarity index 100% rename from android/app/src/main/res/drawable/selector_show_password.xml rename to android/apps/interface/src/main/res/drawable/selector_show_password.xml diff --git a/android/app/src/main/res/font/raleway.ttf b/android/apps/interface/src/main/res/font/raleway.ttf similarity index 100% rename from android/app/src/main/res/font/raleway.ttf rename to android/apps/interface/src/main/res/font/raleway.ttf diff --git a/android/app/src/main/res/font/raleway_bold.xml b/android/apps/interface/src/main/res/font/raleway_bold.xml similarity index 100% rename from android/app/src/main/res/font/raleway_bold.xml rename to android/apps/interface/src/main/res/font/raleway_bold.xml diff --git a/android/app/src/main/res/font/raleway_italic.xml b/android/apps/interface/src/main/res/font/raleway_italic.xml similarity index 100% rename from android/app/src/main/res/font/raleway_italic.xml rename to android/apps/interface/src/main/res/font/raleway_italic.xml diff --git a/android/app/src/main/res/font/raleway_light_italic.xml b/android/apps/interface/src/main/res/font/raleway_light_italic.xml similarity index 100% rename from android/app/src/main/res/font/raleway_light_italic.xml rename to android/apps/interface/src/main/res/font/raleway_light_italic.xml diff --git a/android/app/src/main/res/font/raleway_medium.xml b/android/apps/interface/src/main/res/font/raleway_medium.xml similarity index 100% rename from android/app/src/main/res/font/raleway_medium.xml rename to android/apps/interface/src/main/res/font/raleway_medium.xml diff --git a/android/app/src/main/res/font/raleway_semibold.xml b/android/apps/interface/src/main/res/font/raleway_semibold.xml similarity index 100% rename from android/app/src/main/res/font/raleway_semibold.xml rename to android/apps/interface/src/main/res/font/raleway_semibold.xml diff --git a/android/app/src/main/res/layout/activity_encourage_login.xml b/android/apps/interface/src/main/res/layout/activity_encourage_login.xml similarity index 100% rename from android/app/src/main/res/layout/activity_encourage_login.xml rename to android/apps/interface/src/main/res/layout/activity_encourage_login.xml diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/apps/interface/src/main/res/layout/activity_main.xml similarity index 100% rename from android/app/src/main/res/layout/activity_main.xml rename to android/apps/interface/src/main/res/layout/activity_main.xml diff --git a/android/app/src/main/res/layout/activity_splash.xml b/android/apps/interface/src/main/res/layout/activity_splash.xml similarity index 100% rename from android/app/src/main/res/layout/activity_splash.xml rename to android/apps/interface/src/main/res/layout/activity_splash.xml diff --git a/android/app/src/main/res/layout/activity_web_view.xml b/android/apps/interface/src/main/res/layout/activity_web_view.xml similarity index 100% rename from android/app/src/main/res/layout/activity_web_view.xml rename to android/apps/interface/src/main/res/layout/activity_web_view.xml diff --git a/android/app/src/main/res/layout/domain_view.xml b/android/apps/interface/src/main/res/layout/domain_view.xml similarity index 100% rename from android/app/src/main/res/layout/domain_view.xml rename to android/apps/interface/src/main/res/layout/domain_view.xml diff --git a/android/app/src/main/res/layout/fragment_friends.xml b/android/apps/interface/src/main/res/layout/fragment_friends.xml similarity index 100% rename from android/app/src/main/res/layout/fragment_friends.xml rename to android/apps/interface/src/main/res/layout/fragment_friends.xml diff --git a/android/app/src/main/res/layout/fragment_home.xml b/android/apps/interface/src/main/res/layout/fragment_home.xml similarity index 100% rename from android/app/src/main/res/layout/fragment_home.xml rename to android/apps/interface/src/main/res/layout/fragment_home.xml diff --git a/android/app/src/main/res/layout/fragment_login.xml b/android/apps/interface/src/main/res/layout/fragment_login.xml similarity index 100% rename from android/app/src/main/res/layout/fragment_login.xml rename to android/apps/interface/src/main/res/layout/fragment_login.xml diff --git a/android/app/src/main/res/layout/fragment_login_menu.xml b/android/apps/interface/src/main/res/layout/fragment_login_menu.xml similarity index 100% rename from android/app/src/main/res/layout/fragment_login_menu.xml rename to android/apps/interface/src/main/res/layout/fragment_login_menu.xml diff --git a/android/app/src/main/res/layout/fragment_policy.xml b/android/apps/interface/src/main/res/layout/fragment_policy.xml similarity index 100% rename from android/app/src/main/res/layout/fragment_policy.xml rename to android/apps/interface/src/main/res/layout/fragment_policy.xml diff --git a/android/app/src/main/res/layout/fragment_signup.xml b/android/apps/interface/src/main/res/layout/fragment_signup.xml similarity index 100% rename from android/app/src/main/res/layout/fragment_signup.xml rename to android/apps/interface/src/main/res/layout/fragment_signup.xml diff --git a/android/app/src/main/res/layout/fragment_web_view.xml b/android/apps/interface/src/main/res/layout/fragment_web_view.xml similarity index 100% rename from android/app/src/main/res/layout/fragment_web_view.xml rename to android/apps/interface/src/main/res/layout/fragment_web_view.xml diff --git a/android/app/src/main/res/layout/navigation_header.xml b/android/apps/interface/src/main/res/layout/navigation_header.xml similarity index 100% rename from android/app/src/main/res/layout/navigation_header.xml rename to android/apps/interface/src/main/res/layout/navigation_header.xml diff --git a/android/app/src/main/res/layout/user_item.xml b/android/apps/interface/src/main/res/layout/user_item.xml similarity index 100% rename from android/app/src/main/res/layout/user_item.xml rename to android/apps/interface/src/main/res/layout/user_item.xml diff --git a/android/app/src/main/res/layout/web_drawer.xml b/android/apps/interface/src/main/res/layout/web_drawer.xml similarity index 100% rename from android/app/src/main/res/layout/web_drawer.xml rename to android/apps/interface/src/main/res/layout/web_drawer.xml diff --git a/android/app/src/main/res/menu/menu_navigation.xml b/android/apps/interface/src/main/res/menu/menu_navigation.xml similarity index 100% rename from android/app/src/main/res/menu/menu_navigation.xml rename to android/apps/interface/src/main/res/menu/menu_navigation.xml diff --git a/android/app/src/main/res/menu/web_view_menu.xml b/android/apps/interface/src/main/res/menu/web_view_menu.xml similarity index 100% rename from android/app/src/main/res/menu/web_view_menu.xml rename to android/apps/interface/src/main/res/menu/web_view_menu.xml diff --git a/android/app/src/main/res/values-w385dp/dimens.xml b/android/apps/interface/src/main/res/values-w385dp/dimens.xml similarity index 100% rename from android/app/src/main/res/values-w385dp/dimens.xml rename to android/apps/interface/src/main/res/values-w385dp/dimens.xml diff --git a/android/app/src/main/res/values/colors.xml b/android/apps/interface/src/main/res/values/colors.xml similarity index 100% rename from android/app/src/main/res/values/colors.xml rename to android/apps/interface/src/main/res/values/colors.xml diff --git a/android/app/src/main/res/values/dimens.xml b/android/apps/interface/src/main/res/values/dimens.xml similarity index 100% rename from android/app/src/main/res/values/dimens.xml rename to android/apps/interface/src/main/res/values/dimens.xml diff --git a/android/app/src/main/res/values/font_certs.xml b/android/apps/interface/src/main/res/values/font_certs.xml similarity index 100% rename from android/app/src/main/res/values/font_certs.xml rename to android/apps/interface/src/main/res/values/font_certs.xml diff --git a/android/app/src/main/res/values/preloaded_fonts.xml b/android/apps/interface/src/main/res/values/preloaded_fonts.xml similarity index 100% rename from android/app/src/main/res/values/preloaded_fonts.xml rename to android/apps/interface/src/main/res/values/preloaded_fonts.xml diff --git a/android/app/src/main/res/values/strings.xml b/android/apps/interface/src/main/res/values/strings.xml similarity index 100% rename from android/app/src/main/res/values/strings.xml rename to android/apps/interface/src/main/res/values/strings.xml diff --git a/android/app/src/main/res/values/styles.xml b/android/apps/interface/src/main/res/values/styles.xml similarity index 100% rename from android/app/src/main/res/values/styles.xml rename to android/apps/interface/src/main/res/values/styles.xml diff --git a/android/app/src/main/res/xml/settings.xml b/android/apps/interface/src/main/res/xml/settings.xml similarity index 100% rename from android/app/src/main/res/xml/settings.xml rename to android/apps/interface/src/main/res/xml/settings.xml From 61ea0de74280aaafeb9fb3e9fd20e22a13e92a6e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 31 Dec 2018 13:28:53 -0800 Subject: [PATCH 15/46] Update build files based on move --- .gitignore | 3 + CMakeLists.txt | 4 +- android/apps/interface/CMakeLists.txt | 17 +- android/apps/interface/build.gradle | 56 ++- android/build.gradle | 375 +----------------- android/build_android.sh | 11 +- android/containerized_build.sh | 11 +- android/docker/update.txt | 13 + android/libraries/qt/build.gradle | 22 + .../libraries/qt/src/main/AndroidManifest.xml | 2 + .../java/io/highfidelity/utils/HifiUtils.java | 69 ++++ .../qt5/android/bindings/QtActivity.java | 0 .../android/bindings/QtActivityLoader.java | 0 .../qt5/android/bindings/QtApplication.java | 0 android/settings.gradle | 6 +- hifi_android.py | 62 ++- hifi_utils.py | 4 - hifi_vcpkg.py | 18 + prebuild.py | 14 +- 19 files changed, 274 insertions(+), 413 deletions(-) create mode 100644 android/docker/update.txt create mode 100644 android/libraries/qt/build.gradle create mode 100644 android/libraries/qt/src/main/AndroidManifest.xml create mode 100644 android/libraries/qt/src/main/java/io/highfidelity/utils/HifiUtils.java rename android/{apps/interface => libraries/qt}/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java (100%) rename android/{apps/interface => libraries/qt}/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java (100%) rename android/{apps/interface => libraries/qt}/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java (100%) diff --git a/.gitignore b/.gitignore index f5605d7090..3f58e46b69 100644 --- a/.gitignore +++ b/.gitignore @@ -14,11 +14,13 @@ Makefile # Android Studio *.iml +*.class local.properties android/gradle* android/.gradle android/**/src/main/jniLibs android/**/libs +android/**/bin android/**/src/main/res/values/libs.xml android/**/src/main/assets android/**/gradle* @@ -102,3 +104,4 @@ tools/unity-avatar-exporter/Logs tools/unity-avatar-exporter/Packages tools/unity-avatar-exporter/ProjectSettings tools/unity-avatar-exporter/Temp + diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e5dbe935a..d0a2e57dd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ target_python() if (HIFI_ANDROID ) execute_process( - COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_CURRENT_SOURCE_DIR}/prebuild.py --android --build-root ${CMAKE_BINARY_DIR} + COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_CURRENT_SOURCE_DIR}/prebuild.py --android ${HIFI_ANDROID_APP} --build-root ${CMAKE_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) else() @@ -174,7 +174,7 @@ set_packaging_parameters() # FIXME hack to work on the proper Android toolchain if (ANDROID) - add_subdirectory(android/app) + add_subdirectory(android/apps/${HIFI_ANDROID_APP}) return() endif() diff --git a/android/apps/interface/CMakeLists.txt b/android/apps/interface/CMakeLists.txt index 19dce330c1..500d555915 100644 --- a/android/apps/interface/CMakeLists.txt +++ b/android/apps/interface/CMakeLists.txt @@ -4,10 +4,10 @@ link_hifi_libraries(shared task networking gl gpu qml image fbx hfm render-utils target_opengl() target_bullet() -set(INTERFACE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../interface") +set(INTERFACE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../interface") add_subdirectory("${INTERFACE_DIR}" "libraries/interface") include_directories("${INTERFACE_DIR}/src") -set(HIFI_CODEC_PLUGIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../plugins/hifiCodec") +set(HIFI_CODEC_PLUGIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/hifiCodec") add_subdirectory("${HIFI_CODEC_PLUGIN_DIR}" "libraries/hifiCodecPlugin") target_link_libraries(native-lib android log m interface) @@ -15,16 +15,3 @@ target_link_libraries(native-lib android log m interface) set(GVR_ROOT "${HIFI_ANDROID_PRECOMPILED}/gvr/gvr-android-sdk-1.101.0/") target_include_directories(native-lib PRIVATE "${GVR_ROOT}/libraries/headers" "libraries/ui/src") target_link_libraries(native-lib "${GVR_ROOT}/libraries/libgvr.so" ui) - -# finished libraries -# core -> qt -# networking -> openssl, tbb -# fbx -> draco -# physics -> bullet -# entities-renderer -> polyvox - -# unfinished libraries -# image -> nvtt (doesn't look good, but can be made optional) -# script-engine -> quazip (probably not required for the android client) - - diff --git a/android/apps/interface/build.gradle b/android/apps/interface/build.gradle index e3c6989baf..0c23496faa 100644 --- a/android/apps/interface/build.gradle +++ b/android/apps/interface/build.gradle @@ -1,9 +1,41 @@ import org.apache.tools.ant.taskdefs.condition.Os +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.2.1' + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +task renameHifiACTaskDebug() { + doLast { + def sourceFile = new File("${appDir}/build/intermediates/cmake/debug/obj/arm64-v8a/","libhifiCodec.so") + def destinationFile = new File("${appDir}/src/main/jniLibs/arm64-v8a", "libplugins_libhifiCodec.so") + copy { from sourceFile; into destinationFile.parent; rename(sourceFile.name, destinationFile.name) } + } +} +task renameHifiACTaskRelease(type: Copy) { + doLast { + def sourceFile = new File("${appDir}/build/intermediates/cmake/release/obj/arm64-v8a/","libhifiCodec.so") + def destinationFile = new File("${appDir}/src/main/jniLibs/arm64-v8a", "libplugins_libhifiCodec.so") + copy { from sourceFile; into destinationFile.parent; rename(sourceFile.name, destinationFile.name) } + } +} + apply plugin: 'com.android.application' android { - compileSdkVersion 26 + compileSdkVersion 28 //buildToolsVersion '27.0.3' def appVersionCode = Integer.valueOf(VERSION_CODE ?: 1) @@ -12,24 +44,24 @@ android { defaultConfig { applicationId "io.highfidelity.hifiinterface" minSdkVersion 24 - targetSdkVersion 26 + targetSdkVersion 28 versionCode appVersionCode versionName appVersionName ndk { abiFilters 'arm64-v8a' } externalNativeBuild { cmake { arguments '-DHIFI_ANDROID=1', + '-DHIFI_ANDROID_APP=interface', '-DANDROID_PLATFORM=android-24', '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_shared', - '-DQT_CMAKE_PREFIX_PATH=' + HIFI_ANDROID_PRECOMPILED + '/qt/lib/cmake', - '-DHIFI_ANDROID_PRECOMPILED=' + HIFI_ANDROID_PRECOMPILED, '-DRELEASE_NUMBER=' + RELEASE_NUMBER, '-DRELEASE_TYPE=' + RELEASE_TYPE, '-DSTABLE_BUILD=' + STABLE_BUILD, '-DDISABLE_QML=OFF', '-DDISABLE_KTX_CACHE=OFF', '-DUSE_BREAKPAD=' + (System.getenv("CMAKE_BACKTRACE_URL") && System.getenv("CMAKE_BACKTRACE_TOKEN") ? 'ON' : 'OFF'); + targets = ['native-lib'] } } signingConfigs { @@ -72,7 +104,7 @@ android { externalNativeBuild { cmake { - path '../../CMakeLists.txt' + path '../../../CMakeLists.txt' } } @@ -82,6 +114,7 @@ android { variant.externalNativeBuildTasks.each { task -> variant.mergeResources.dependsOn(task) if (Os.isFamily(Os.FAMILY_UNIX)) { + // FIXME def uploadDumpSymsTask = rootProject.getTasksByName("uploadBreakpadDumpSyms${variant.name.capitalize()}", false).first() def runDumpSymsTask = rootProject.getTasksByName("runBreakpadDumpSyms${variant.name.capitalize()}", false).first() def renameHifiACTask = rootProject.getTasksByName("renameHifiACTask${variant.name.capitalize()}", false).first() @@ -97,7 +130,7 @@ android { // Copy the compiled resources generated by the external native build copy { - from new File(projectDir, "../../interface/compiledResources") + from new File(projectDir, "../../../interface/compiledResources") into outputDir duplicatesStrategy DuplicatesStrategy.INCLUDE eachFile { details -> @@ -108,7 +141,7 @@ android { // Copy the scripts directory copy { - from new File(projectDir, "../../scripts") + from new File(projectDir, "../../../scripts") into new File(outputDir, "scripts") duplicatesStrategy DuplicatesStrategy.INCLUDE eachFile { details-> @@ -123,12 +156,6 @@ android { assetList.each { file -> out.println(file) } } } - - variant.outputs.all { - if (RELEASE_NUMBER != '0') { - outputFileName = "app_" + RELEASE_NUMBER + "_" + RELEASE_TYPE + ".apk" - } - } } } @@ -157,5 +184,6 @@ dependencies { api 'com.sothree.slidinguppanel:library:3.4.0' - implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation fileTree(include: ['*.jar'], dir: '../../libraries/qt/libs') + implementation project(':qt') } diff --git a/android/build.gradle b/android/build.gradle index 8d03b9f6b3..11c702130c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -42,378 +42,13 @@ ext { RELEASE_TYPE = project.hasProperty('RELEASE_TYPE') ? project.getProperty('RELEASE_TYPE') : 'DEV' STABLE_BUILD = project.hasProperty('STABLE_BUILD') ? project.getProperty('STABLE_BUILD') : '0' EXEC_SUFFIX = Os.isFamily(Os.FAMILY_WINDOWS) ? '.exe' : '' - QT5_DEPS = [ - 'Qt5Concurrent', - 'Qt5Core', - 'Qt5Gui', - 'Qt5Multimedia', - 'Qt5Network', - 'Qt5OpenGL', - 'Qt5Qml', - 'Qt5Quick', - 'Qt5QuickControls2', - 'Qt5QuickTemplates2', - 'Qt5Script', - 'Qt5ScriptTools', - 'Qt5Svg', - 'Qt5WebChannel', - 'Qt5WebSockets', - 'Qt5Widgets', - 'Qt5XmlPatterns', - // Android specific - 'Qt5AndroidExtras', - 'Qt5WebView', - ] } -def baseFolder = new File(HIFI_ANDROID_PRECOMPILED) -def appDir = new File(projectDir, 'app') +def appDir = new File(projectDir, 'apps/interface') def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a') def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/' def breakpadDumpSymsDir = new File("${appDir}/build/tmp/breakpadDumpSyms") -def qtFile='qt-5.11.1_linux_armv8-libcpp_openssl_patched.tgz' -def qtChecksum='aa449d4bfa963f3bc9a9dfe558ba29df' -def qtVersionId='3S97HBM5G5Xw9EfE52sikmgdN3t6C2MN' -if (Os.isFamily(Os.FAMILY_MAC)) { - qtFile = 'qt-5.11.1_osx_armv8-libcpp_openssl_patched.tgz' - qtChecksum='c83cc477c08a892e00c71764dca051a0' - qtVersionId='OxBD7iKINv1HbyOXmAmDrBb8AF3N.Kup' -} else if (Os.isFamily(Os.FAMILY_WINDOWS)) { - qtFile = 'qt-5.11.1_win_armv8-libcpp_openssl_patched.tgz' - qtChecksum='0582191cc55431aa4f660848a542883e' - qtVersionId='JfWM0P_Mz5Qp0LwpzhrsRwN3fqlLSFeT' -} - -def packages = [ - qt: [ - file: qtFile, - versionId: qtVersionId, - checksum: qtChecksum, - ], - bullet: [ - file: 'bullet-2.88_armv8-libcpp.tgz', - versionId: 'S8YaoED0Cl8sSb8fSV7Q2G1lQJSNDxqg', - checksum: '81642779ccb110f8c7338e8739ac38a0', - ], - draco: [ - file: 'draco_armv8-libcpp.tgz', - versionId: '3.B.uBj31kWlgND3_R2xwQzT_TP6Dz_8', - checksum: '617a80d213a5ec69fbfa21a1f2f738cd', - ], - glad: [ - file: 'glad_armv8-libcpp.zip', - versionId: 'r5Zran.JSCtvrrB6Q4KaqfIoALPw3lYY', - checksum: 'a8ee8584cf1ccd34766c7ddd9d5e5449', - ], - gvr: [ - file: 'gvrsdk_v1.101.0.tgz', - versionId: 'nqBV_j81Uc31rC7bKIrlya_Hah4v3y5r', - checksum: '57fd02baa069176ba18597a29b6b4fc7', - ], - nvtt: [ - file: 'nvtt_armv8-libcpp.zip', - versionId: 'lmkBVR5t4UF1UUwMwEirnk9H_8Nt90IO', - checksum: 'eb46d0b683e66987190ed124aabf8910', - sharedLibFolder: 'lib', - includeLibs: ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so'], - ], - openssl: [ - file: 'openssl-1.1.0g_armv8.tgz', - versionId: 'AiiPjmgUZTgNj7YV1EEx2lL47aDvvvAW', - checksum: 'cabb681fbccd79594f65fcc266e02f32', - ], - polyvox: [ - file: 'polyvox_armv8-libcpp.tgz', - versionId: 'A2kbKiNhpIenGq23bKRRzg7IMAI5BI92', - checksum: 'dba88b3a098747af4bb169e9eb9af57e', - sharedLibFolder: 'lib', - includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'], - ], - tbb: [ - file: 'tbb-2018_U1_armv8_libcpp.tgz', - versionId: 'mrRbWnv4O4evcM1quRH43RJqimlRtaKB', - checksum: '20768f298f53b195e71b414b0ae240c4', - sharedLibFolder: 'lib/release', - includeLibs: ['libtbb.so', 'libtbbmalloc.so'], - ], - hifiAC: [ - baseUrl: 'http://s3.amazonaws.com/hifi-public/dependencies/', - file: 'codecSDK-android_armv8-2.0.zip', - checksum: '1cbef929675818fc64c4101b72f84a6a' - ], - etc2comp: [ - file: 'etc2comp-patched-armv8-libcpp.tgz', - versionId: 'bHhGECRAQR1vkpshBcK6ByNc1BQIM8gU', - checksum: '14b02795d774457a33bbc60e00a786bc' - ], - breakpad: [ - file: 'breakpad.tgz', - versionId: '8VrYXz7oyc.QBxNia0BVJOUBvrFO61jI', - checksum: 'ddcb23df336b08017042ba4786db1d9e', - sharedLibFolder: 'lib', - includeLibs: ['libbreakpad_client.a'] - ] -] - -def options = [ - files: new TreeSet(), - features: new HashSet(), - permissions: new HashSet() -] - -def qmlRoot = new File(HIFI_ANDROID_PRECOMPILED, 'qt') - -def captureOutput = { String command, List commandArgs -> - def result - new ByteArrayOutputStream().withStream { os -> - def execResult = exec { - executable = command - args = commandArgs - standardOutput = os - errorOutput = new ByteArrayOutputStream() - } - result = os.toString() - } - return result; -} - -def relativize = { File root, File absolute -> - def relativeURI = root.toURI().relativize(absolute.toURI()) - return new File(relativeURI.toString()) -} - -def scanQmlImports = { File qmlRootPath -> - def qmlImportCommandFile = new File(qmlRoot, 'bin/qmlimportscanner' + EXEC_SUFFIX) - if (!qmlImportCommandFile.exists()) { - throw new GradleException('Unable to find required qmlimportscanner executable at ' + qmlImportCommandFile.parent.toString()) - } - - def command = qmlImportCommandFile.absolutePath - def args = [ - '-rootPath', qmlRootPath.absolutePath, - '-importPath', "${qmlRoot.absolutePath}/qml" - ] - - def commandResult = captureOutput(command, args) - new JsonSlurper().parseText(commandResult).each { - if (!it.containsKey('path')) { - println "Warning: QML import could not be resolved in any of the import paths: ${it.name}" - return - } - def file = new File(it.path) - // Ignore non-existent files - if (!file.exists()) { - return - } - // Ignore files in the import path - if (file.canonicalPath.startsWith(qmlRootPath.canonicalPath)) { - return - } - if (file.isFile()) { - options.files.add(file) - } else { - file.eachFileRecurse(FileType.FILES, { - options.files.add(it) - }) - } - } -} - -def parseQtDependencies = { List qtLibs -> - qtLibs.each({ - def libFile = new File(qmlRoot, "lib/lib${it}.so") - options.files.add(libFile) - - def androidDeps = new File(qmlRoot, "lib/${it}-android-dependencies.xml") - if (!libFile.exists()) return - if (!androidDeps.exists()) return - - new XmlSlurper().parse(androidDeps).dependencies.lib.depends.'*'.each{ node -> - switch (node.name()) { - case 'lib': - case 'bundled': - def relativeFilename = node.@file.toString() - - // Special case, since this is handled by qmlimportscanner instead - if (relativeFilename.startsWith('qml')) - return - - def file = new File(qmlRoot, relativeFilename) - - if (!file.exists()) - return - - if (file.isFile()) { - options.files.add(file) - } else { - file.eachFileRecurse(FileType.FILES, { options.files.add(it) }) - } - break - - - case 'jar': - if (node.@bundling == "1") { - def jar = new File(qmlRoot, node.@file.toString()) - if (!jar.exists()) { - throw new GradleException('Unable to find required JAR ' + jar.path) - } - options.files.add(jar) - } - break - - case 'permission': - options.permissions.add(node.@name) - break - - case 'feature': - options.features.add(node.@name) - break - - default: - throw new GradleException('Unhandled Android Dependency node ' + node.name()) - } - } - }) -} - -def generateLibsXml = { - def libDestinationDirectory = jniFolder - def jarDestinationDirectory = new File(appDir, 'libs') - def assetDestinationDirectory = new File(appDir, 'src/main/assets/--Added-by-androiddeployqt--'); - def libsXmlFile = new File(appDir, 'src/main/res/values/libs.xml') - def libPrefix = 'lib' + File.separator - def jarPrefix = 'jar' + File.separator - - def xmlParser = new XmlParser() - def libsXmlRoot = xmlParser.parseText('') - def qtLibsNode = xmlParser.createNode(libsXmlRoot, 'array', [name: 'qt_libs']) - def bundledLibsNode = xmlParser.createNode(libsXmlRoot, 'array', [name: 'bundled_in_lib']) - def bundledAssetsNode = xmlParser.createNode(libsXmlRoot, 'array', [name: 'bundled_in_assets']) - - options.files.each { - def sourceFile = it - if (!sourceFile.exists()) { - throw new GradleException("Unable to find dependency file " + sourceFile.toString()) - } - - def relativePath = relativize( qmlRoot, sourceFile ).toString() - def destinationFile - if (relativePath.endsWith('.so')) { - def garbledFileName - if (relativePath.startsWith(libPrefix)) { - garbledFileName = relativePath.substring(libPrefix.size()) - Pattern p = ~/lib(Qt5.*).so/ - Matcher m = p.matcher(garbledFileName) - assert m.matches() - def libName = m.group(1) - xmlParser.createNode(qtLibsNode, 'item', [:]).setValue(libName) - } else { - garbledFileName = 'lib' + relativePath.replace(File.separator, '_'[0]) - xmlParser.createNode(bundledLibsNode, 'item', [:]).setValue("${garbledFileName}:${relativePath}".replace(File.separator, '/')) - } - destinationFile = new File(libDestinationDirectory, garbledFileName) - } else if (relativePath.startsWith('jar')) { - destinationFile = new File(jarDestinationDirectory, relativePath.substring(jarPrefix.size())) - } else { - xmlParser.createNode(bundledAssetsNode, 'item', [:]).setValue("--Added-by-androiddeployqt--/${relativePath}:${relativePath}".replace(File.separator, '/')) - destinationFile = new File(assetDestinationDirectory, relativePath) - } - - copy { from sourceFile; into destinationFile.parent; rename(sourceFile.name, destinationFile.name) } - assert destinationFile.exists() && destinationFile.isFile() - } - def xml = XmlUtil.serialize(libsXmlRoot) - new FileWriter(libsXmlFile).withPrintWriter { writer -> - writer.write(xml) - } -} - -task downloadDependencies { - doLast { - packages.each { entry -> - def filename = entry.value['file']; - def dependencyBaseUrl = entry.value['baseUrl'] - def url = (dependencyBaseUrl?.trim() ? dependencyBaseUrl : baseUrl) + filename; - if (entry.value.containsKey('versionId')) { - url = url + '?versionId=' + entry.value['versionId'] - } - download { - src url - dest new File(baseFolder, filename) - onlyIfNewer true - } - } - } -} - -task verifyQt(type: Verify) { def p = packages['qt']; src new File(baseFolder, p['file']); checksum p['checksum']; } -task verifyBullet(type: Verify) { def p = packages['bullet']; src new File(baseFolder, p['file']); checksum p['checksum'] } -task verifyDraco(type: Verify) { def p = packages['draco']; src new File(baseFolder, p['file']); checksum p['checksum'] } -task verifyGvr(type: Verify) { def p = packages['gvr']; src new File(baseFolder, p['file']); checksum p['checksum'] } -task verifyOpenSSL(type: Verify) { def p = packages['openssl']; src new File(baseFolder, p['file']); checksum p['checksum'] } -task verifyPolyvox(type: Verify) { def p = packages['polyvox']; src new File(baseFolder, p['file']); checksum p['checksum'] } -task verifyTBB(type: Verify) { def p = packages['tbb']; src new File(baseFolder, p['file']); checksum p['checksum'] } -task verifyHifiAC(type: Verify) { def p = packages['hifiAC']; src new File(baseFolder, p['file']); checksum p['checksum'] } -task verifyEtc2Comp(type: Verify) { def p = packages['etc2comp']; src new File(baseFolder, p['file']); checksum p['checksum'] } -task verifyBreakpad(type: Verify) { def p = packages['breakpad']; src new File(baseFolder, p['file']); checksum p['checksum'] } - -task verifyDependencyDownloads(dependsOn: downloadDependencies) { } -verifyDependencyDownloads.dependsOn verifyQt -verifyDependencyDownloads.dependsOn verifyBullet -verifyDependencyDownloads.dependsOn verifyDraco -verifyDependencyDownloads.dependsOn verifyGvr -verifyDependencyDownloads.dependsOn verifyOpenSSL -verifyDependencyDownloads.dependsOn verifyPolyvox -verifyDependencyDownloads.dependsOn verifyTBB -verifyDependencyDownloads.dependsOn verifyHifiAC -verifyDependencyDownloads.dependsOn verifyEtc2Comp -verifyDependencyDownloads.dependsOn verifyBreakpad - -task extractDependencies(dependsOn: verifyDependencyDownloads) { - doLast { - packages.each { entry -> - def folder = entry.key - def filename = entry.value['file'] - def localFile = new File(HIFI_ANDROID_PRECOMPILED, filename) - def localFolder = new File(HIFI_ANDROID_PRECOMPILED, folder) - def fileTree; - if (filename.endsWith('zip')) { - fileTree = zipTree(localFile) - } else { - fileTree = tarTree(resources.gzip(localFile)) - } - copy { - from fileTree - into localFolder - } - } - } -} - -// Copies the non Qt dependencies. Qt dependencies (primary libraries and plugins) are handled by the qtBundle task -task copyDependencies() { - doLast { - packages.each { entry -> - def packageName = entry.key - def currentPackage = entry.value; - if (currentPackage.containsKey('sharedLibFolder')) { - def localFolder = new File(baseFolder, packageName + '/' + currentPackage['sharedLibFolder']) - def tree = fileTree(localFolder); - if (currentPackage.containsKey('includeLibs')) { - currentPackage['includeLibs'].each { includeSpec -> tree.include includeSpec } - } - tree.visit { element -> - if (!element.file.isDirectory()) { - println "Copying " + element.file + " to " + jniFolder - copy { from element.file; into jniFolder } - } - } - } - } - } -} - task extractGvrBinaries() { doLast { def gvrLibFolder = new File(HIFI_ANDROID_PRECOMPILED, 'gvr/gvr-android-sdk-1.101.0/libraries'); @@ -500,13 +135,11 @@ task qtBundle { } } -task setupDependencies(dependsOn: [copyDependencies, extractGvrBinaries, qtBundle]) { } +task setupDependencies() { + // migrated to python +} task cleanDependencies(type: Delete) { - delete HIFI_ANDROID_PRECOMPILED - delete 'app/src/main/jniLibs/arm64-v8a' - delete 'app/src/main/assets/--Added-by-androiddeployqt--' - delete 'app/src/main/res/values/libs.xml' } def runBreakpadDumpSyms = { buildType -> diff --git a/android/build_android.sh b/android/build_android.sh index 189e6099a8..9c68b8969b 100755 --- a/android/build_android.sh +++ b/android/build_android.sh @@ -1,4 +1,11 @@ #!/usr/bin/env bash set -xeuo pipefail -./gradlew -PHIFI_ANDROID_PRECOMPILED=${HIFI_ANDROID_PRECOMPILED} -PVERSION_CODE=${VERSION_CODE} -PRELEASE_NUMBER=${RELEASE_NUMBER} -PRELEASE_TYPE=${RELEASE_TYPE} setupDependencies -./gradlew -PHIFI_ANDROID_PRECOMPILED=${HIFI_ANDROID_PRECOMPILED} -PVERSION_CODE=${VERSION_CODE} -PRELEASE_NUMBER=${RELEASE_NUMBER} -PRELEASE_TYPE=${RELEASE_TYPE} app:${ANDROID_BUILD_TARGET} \ No newline at end of file +./gradlew -PHIFI_ANDROID_PRECOMPILED=${HIFI_ANDROID_PRECOMPILED} -PVERSION_CODE=${VERSION_CODE} -PRELEASE_NUMBER=${RELEASE_NUMBER} -PRELEASE_TYPE=${RELEASE_TYPE} ${ANDROID_APP}:${ANDROID_BUILD_TARGET} + +# This is the actual output from gradle, which no longer attempts to muck with the naming of the APK +OUTPUT_APK=./apps/${ANDROID_APP}/build/outputs/apk/${ANDROID_BUILD_DIR}/${ANDROID_APP}-${ANDROID_BUILD_DIR}.apk +# This is the APK name requested by Jenkins +TARGET_APK=./${ANDROID_APK_NAME} +# Make sure this matches up with the new ARTIFACT_EXPRESSION for jenkins builds, which should be "android/*.apk" +cp ${OUTPUT_APK} ${TARGET_APK} + diff --git a/android/containerized_build.sh b/android/containerized_build.sh index e5ec895146..42118a8e38 100755 --- a/android/containerized_build.sh +++ b/android/containerized_build.sh @@ -5,12 +5,21 @@ DOCKER_IMAGE_NAME="hifi_androidbuild" docker build --build-arg BUILD_UID=`id -u` -t "${DOCKER_IMAGE_NAME}" -f docker/Dockerfile docker +# The Jenkins PR builds use VERSION_CODE, but the release builds use VERSION +# So make sure we use VERSION_CODE consistently +if [-z "$VERSION_CODE"]; then + export VERSION_CODE=$VERSION +fi + docker run \ --rm \ - --security-opt seccomp:unconfined \ + --security-opt seccomp:unconfined \ -v "${WORKSPACE}":/home/jenkins/hifi \ + -v /home/jenkins/.gradle:/home/jenkins/.gradle \ -e RELEASE_NUMBER \ -e RELEASE_TYPE \ + -e ANDROID_APP \ + -e ANDROID_APK_NAME \ -e ANDROID_BUILD_TARGET \ -e ANDROID_BUILD_DIR \ -e CMAKE_BACKTRACE_URL \ diff --git a/android/docker/update.txt b/android/docker/update.txt new file mode 100644 index 0000000000..a12c215a06 --- /dev/null +++ b/android/docker/update.txt @@ -0,0 +1,13 @@ +git fetch +git checkout feature/quest_move_interface +export VERSION_CODE=1 +export RELEASE_NUMBER=1 +export RELEASE_TYPE=DEV +export ANDROID_APP=interface +touch ~/.gradle/gradle.properties +echo HIFI_ANDROID_KEYSTORE=/home/jenkins/keystore.jks > ~/.gradle/gradle.properties +echo HIFI_ANDROID_KEYSTORE_PASSWORD=password >> ~/.gradle/gradle.properties +echo HIFI_ANDROID_KEY_ALIAS=key0 >> ~/.gradle/gradle.properties +echo HIFI_ANDROID_KEY_PASSWORD=password >> ~/.gradle/gradle.properties +./build_android.sh +cp ./apps/${ANDROID_APP}/build/outputs/apk/release/${ANDROID_APP}-release.apk ${ANDROID_APP}.apk \ No newline at end of file diff --git a/android/libraries/qt/build.gradle b/android/libraries/qt/build.gradle new file mode 100644 index 0000000000..e6141f4cdf --- /dev/null +++ b/android/libraries/qt/build.gradle @@ -0,0 +1,22 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 24 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + api 'com.google.guava:guava:23.0' +} diff --git a/android/libraries/qt/src/main/AndroidManifest.xml b/android/libraries/qt/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..c6638c09e8 --- /dev/null +++ b/android/libraries/qt/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/android/libraries/qt/src/main/java/io/highfidelity/utils/HifiUtils.java b/android/libraries/qt/src/main/java/io/highfidelity/utils/HifiUtils.java new file mode 100644 index 0000000000..e8e9f04d9f --- /dev/null +++ b/android/libraries/qt/src/main/java/io/highfidelity/utils/HifiUtils.java @@ -0,0 +1,69 @@ + +package io.highfidelity.utils; + +import android.content.res.AssetManager; + +import com.google.common.io.ByteStreams; +import com.google.common.io.Files; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.LinkedList; + +public class HifiUtils { + + private static LinkedList readAssetLines(AssetManager assetManager, String asset) throws IOException { + LinkedList assets = new LinkedList<>(); + InputStream is = assetManager.open(asset); + BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8")); + String line; + while ((line=in.readLine()) != null) { + assets.add(line); + } + in.close(); + return assets; + } + + private static void copyAsset(AssetManager assetManager, String asset, String destFileName) throws IOException { + try (InputStream is = assetManager.open(asset)) { + try (OutputStream os = Files.asByteSink(new File(destFileName)).openStream()) { + ByteStreams.copy(is, os); + } + } + } + + public static void upackAssets(AssetManager assetManager, String destDir) { + try { + if (!destDir.endsWith("/")) + destDir = destDir + "/"; + LinkedList assets = readAssetLines(assetManager, "cache_assets.txt"); + String dateStamp = assets.poll(); + String dateStampFilename = destDir + dateStamp; + File dateStampFile = new File(dateStampFilename); + if (dateStampFile.exists()) { + return; + } + for (String fileToCopy : assets) { + String destFileName = destDir + fileToCopy; + { + File destFile = new File(destFileName); + File destFolder = destFile.getParentFile(); + if (!destFolder.exists()) { + destFolder.mkdirs(); + } + if (destFile.exists()) { + destFile.delete(); + } + } + copyAsset(assetManager, fileToCopy, destFileName); + } + Files.write("touch".getBytes(), dateStampFile); + } catch (IOException e){ + throw new RuntimeException(e); + } + } +} diff --git a/android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java b/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java similarity index 100% rename from android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java rename to android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java diff --git a/android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java b/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java similarity index 100% rename from android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java rename to android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivityLoader.java diff --git a/android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java b/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java similarity index 100% rename from android/apps/interface/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java rename to android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtApplication.java diff --git a/android/settings.gradle b/android/settings.gradle index e7b4def49c..40b5eb44bf 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1 +1,5 @@ -include ':app' +include ':qt' +project(':qt').projectDir = new File(settingsDir, 'libraries/qt') + +include ':interface' +project(':interface').projectDir = new File(settingsDir, 'apps/interface') diff --git a/hifi_android.py b/hifi_android.py index e3944cda9a..308ad2a151 100644 --- a/hifi_android.py +++ b/hifi_android.py @@ -6,6 +6,7 @@ import re import shutil import xml.etree.ElementTree as ET import functools +import zipfile print = functools.partial(print, flush=True) @@ -163,6 +164,31 @@ def copyAndroidLibs(packagePath, appPath): print("Copying {}".format(lib)) shutil.copy(sourceFile, destFile) + gvrLibFolder = os.path.join(packagePath, 'gvr/gvr-android-sdk-1.101.0/libraries') + audioSoOut = os.path.join(gvrLibFolder, 'libgvr_audio.so') + if not os.path.isfile(audioSoOut): + audioAar = os.path.join(gvrLibFolder, 'sdk-audio-1.101.0.aar') + with zipfile.ZipFile(audioAar) as z: + with z.open('jni/arm64-v8a/libgvr_audio.so') as f: + with open(audioSoOut, 'wb') as of: + shutil.copyfileobj(f, of) + + audioSoOut2 = os.path.join(jniPath, 'libgvr_audio.so') + if not os.path.isfile(audioSoOut2): + shutil.copy(audioSoOut, audioSoOut2) + + baseSoOut = os.path.join(gvrLibFolder, 'libgvr.so') + if not os.path.isfile(baseSoOut): + baseAar = os.path.join(gvrLibFolder, 'sdk-base-1.101.0.aar') + with zipfile.ZipFile(baseAar) as z: + with z.open('jni/arm64-v8a/libgvr.so') as f: + with open(baseSoOut, 'wb') as of: + shutil.copyfileobj(f, of) + + baseSoOut2 = os.path.join(jniPath, 'libgvr.so') + if not os.path.isfile(baseSoOut2): + shutil.copy(baseSoOut, baseSoOut2) + class QtPackager: def __init__(self, appPath, qtRootPath): self.appPath = appPath @@ -170,6 +196,7 @@ class QtPackager: self.jniPath = os.path.join(self.appPath, 'src/main/jniLibs/arm64-v8a') self.assetPath = os.path.join(self.appPath, 'src/main/assets') self.qtAssetPath = os.path.join(self.assetPath, '--Added-by-androiddeployqt--') + self.qtAssetCacheList = os.path.join(self.qtAssetPath, 'qt_cache_pregenerated_file_list') # Jars go into the qt library self.jarPath = os.path.realpath(os.path.join(self.appPath, '../../libraries/qt/libs')) self.xmlFile = os.path.join(self.appPath, 'src/main/res/values/libs.xml') @@ -277,10 +304,43 @@ class QtPackager: tree = ET.ElementTree(libsXmlRoot) tree.write(self.xmlFile, 'UTF-8', True) + def generateAssetsFileList(self): + print("Implement asset file list") + # outputFilename = os.path.join(self.qtAssetPath, "qt_cache_pregenerated_file_list") + # fileList = hifi_utils.recursiveFileList(self.qtAssetPath) + # fileMap = {} + # for fileName in fileList: + # relativeFileName = os.path.relpath(fileName, self.assetPath) + # dirName, localFileName = os.path.split(relativeFileName) + # if not dirName in fileMap: + # fileMap[dirName] = [] + # fileMap[dirName].append(localFileName) + + # for dirName in fileMap: + # for localFileName in fileMap[dirName]: + # ???? + + # + # Gradle version + # + # DataOutputStream fos = new DataOutputStream(new FileOutputStream(outputFile)); + # for (Map.Entry> e: directoryContents.entrySet()) { + # def entryList = e.getValue() + # fos.writeInt(e.key.length()*2); // 2 bytes per char + # fos.writeChars(e.key); + # fos.writeInt(entryList.size()); + # for (String entry: entryList) { + # fos.writeInt(entry.length()*2); + # fos.writeChars(entry); + # } + # } + def bundle(self): - if not os.path.isfile(self.xmlFile) or True: + if not os.path.isfile(self.xmlFile): self.copyQtDeps() self.scanQmlImports() self.processFiles() + # if not os.path.isfile(self.qtAssetCacheList): + # self.generateAssetsFileList() diff --git a/hifi_utils.py b/hifi_utils.py index f53258d4f6..c1a52ed842 100644 --- a/hifi_utils.py +++ b/hifi_utils.py @@ -97,16 +97,12 @@ def downloadFile(url, hash=None, hasher=hashlib.sha512(), retries=3): else: tempFileName, headers = urllib.request.urlretrieve(url) - # for some reason the hash we get back from the downloaded file is sometimes wrong if we check it right away - # but if we examine the file later, it is correct. - time.sleep(3) downloadHash = hashFile(tempFileName, hasher) # Verify the hash if hash is not None and hash != downloadHash: print("Try {}: Downloaded file {} hash {} does not match expected hash {} for url {}".format(i + 1, tempFileName, downloadHash, hash, url)) os.remove(tempFileName) continue - return tempFileName raise RuntimeError("Downloaded file hash {} does not match expected hash {} for\n{}".format(downloadHash, hash, url)) diff --git a/hifi_vcpkg.py b/hifi_vcpkg.py index 5492109864..6d241c595f 100644 --- a/hifi_vcpkg.py +++ b/hifi_vcpkg.py @@ -189,6 +189,18 @@ endif() #hifi_utils.downloadAndExtract(url, dest, hash) hifi_utils.downloadAndExtract(url, dest) + print("Installing additional android archives") + androidPackages = hifi_android.getPlatformPackages() + for packageName in androidPackages: + package = androidPackages[packageName] + dest = os.path.join(self.androidPackagePath, packageName) + if os.path.isdir(dest): + continue + url = hifi_android.getPackageUrl(package) + zipFile = package['file'].endswith('.zip') + print("Android archive {}".format(package['file'])) + hifi_utils.downloadAndExtract(url, dest, isZip=zipFile, hash=package['checksum'], hasher=hashlib.md5()) + def writeTag(self): print("Writing tag {} to {}".format(self.tagContents, self.tagFile)) with open(self.tagFile, 'w') as f: @@ -203,6 +215,12 @@ endif() cmakeTemplate = VcpkgRepo.CMAKE_TEMPLATE if not self.args.android: cmakeTemplate += VcpkgRepo.CMAKE_TEMPLATE_NON_ANDROID + else: + precompiled = os.path.realpath(os.path.join(self.path, 'android')) + qtCmakePrefix = os.path.realpath(os.path.join(precompiled, 'qt/lib/cmake')) + cmakeTemplate += 'set(HIFI_ANDROID_PRECOMPILED "{}")\n'.format(precompiled) + cmakeTemplate += 'set(QT_CMAKE_PREFIX_PATH "{}")\n'.format(qtCmakePrefix) + cmakeConfig = cmakeTemplate.format(cmakeScript, cmakeScript, installPath, toolsPath).replace('\\', '/') with open(self.configFilePath, 'w') as f: f.write(cmakeConfig) diff --git a/prebuild.py b/prebuild.py index a758dcbea2..fb54b8d6fe 100644 --- a/prebuild.py +++ b/prebuild.py @@ -43,8 +43,7 @@ def parse_args(): defaultPortsPath = hifi_utils.scriptRelative('cmake', 'ports') from argparse import ArgumentParser parser = ArgumentParser(description='Prepare build dependencies.') - parser.add_argument('--android', action='store_true') - #parser.add_argument('--android', type=str) + parser.add_argument('--android', type=str) parser.add_argument('--debug', action='store_true') parser.add_argument('--force-bootstrap', action='store_true') parser.add_argument('--force-build', action='store_true') @@ -87,6 +86,17 @@ def main(): # here shouldn't invalidte the vcpkg install) pm.cleanBuilds() + # If we're running in android mode, we also need to grab a bunch of additional binaries + # (this logic is all migrated from the old setupDependencies tasks in gradle) + if args.android: + # Find the target location + appPath = hifi_utils.scriptRelative('android/apps/' + args.android) + # Copy the non-Qt libraries specified in the config in hifi_android.py + hifi_android.copyAndroidLibs(pm.androidPackagePath, appPath) + # Determine the Qt package path + qtPath = os.path.join(pm.androidPackagePath, 'qt') + hifi_android.QtPackager(appPath, qtPath).bundle() + # Write the vcpkg config to the build directory last pm.writeConfig() From b1c34eb9ec13cacbc51fff9e17fe09df51caa29e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 15 Jan 2019 15:07:05 -0800 Subject: [PATCH 16/46] update queryAACube during grab rather than only when grab is released --- interface/src/avatar/GrabManager.cpp | 4 ++++ libraries/entities/src/EntityItem.cpp | 3 ++- libraries/entities/src/EntityTree.cpp | 1 + .../system/libraries/controllerDispatcherUtils.js | 13 +++++++++++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/GrabManager.cpp b/interface/src/avatar/GrabManager.cpp index c41435d67e..db1337b64d 100644 --- a/interface/src/avatar/GrabManager.cpp +++ b/interface/src/avatar/GrabManager.cpp @@ -18,6 +18,8 @@ void GrabManager::simulateGrabs() { // Update grabbed objects auto entityTreeRenderer = DependencyManager::get(); auto entityTree = entityTreeRenderer->getTree(); + auto sessionID = DependencyManager::get()->getSessionUUID(); + EntityEditPacketSender* packetSender = entityTreeRenderer ? entityTreeRenderer->getPacketSender() : nullptr; entityTree->withReadLock([&] { PROFILE_RANGE(simulation, "Grabs"); @@ -33,6 +35,8 @@ void GrabManager::simulateGrabs() { glm::vec3 finalPosition = acc.finalizePosition(); glm::quat finalOrientation = acc.finalizeOrientation(); grabbedThing->setTransform(createMatFromQuatAndPos(finalOrientation, finalPosition)); + bool iShouldTellServer = grabbedThing->getEditSenderID() == sessionID; + entityTree->updateEntityQueryAACube(grabbedThing, packetSender, false, iShouldTellServer); } } }); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7b5f6e4066..436da476bf 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3349,7 +3349,8 @@ void EntityItem::prepareForSimulationOwnershipBid(EntityItemProperties& properti } bool EntityItem::isWearable() const { - return isVisible() && (getParentID() == DependencyManager::get()->getSessionUUID() || getParentID() == AVATAR_SELF_ID); + return isVisible() && + (getParentID() == DependencyManager::get()->getSessionUUID() || getParentID() == AVATAR_SELF_ID); } void EntityItem::addGrab(GrabPointer grab) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index fb1a11d43f..26a5a14039 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2982,6 +2982,7 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, properties.setLastEdited(now); packetSender->queueEditEntityMessage(PacketType::EntityEdit, getThisPointer(), entity->getID(), properties); + entity->setLastEdited(now); // so we ignore the echo from the server entity->setLastBroadcast(now); // for debug/physics status icons } diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index faf4b4ed5d..78c50a2318 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -33,6 +33,7 @@ getGrabbableData:true, isAnothersAvatarEntity:true, isAnothersChildEntity:true, + entityIsEquippable:true, entityIsGrabbable:true, entityIsDistanceGrabbable:true, getControllerJointIndexCacheTime:true, @@ -332,10 +333,18 @@ entityIsEquippable = function (eieProps) { return false; } return true; -} +}; entityIsGrabbable = function (eigProps) { - return entityIsEquippable(eigProps) && !eigProps.locked; + var grabbable = getGrabbableData(eigProps).grabbable; + if (!grabbable || + eigProps.locked || + isAnothersAvatarEntity(eigProps) || + isAnothersChildEntity(eigProps) || + FORBIDDEN_GRAB_TYPES.indexOf(eigProps.type) >= 0) { + return false; + } + return true; }; clearHighlightedEntities = function() { From c4fc884bce1d5043dc181da9ff9dfc062594049c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 15 Jan 2019 16:35:20 -0800 Subject: [PATCH 17/46] ignore position edits from server when grabs are in effect --- libraries/entities/src/EntityItem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 436da476bf..8b6595d8c0 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -770,7 +770,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto lastEdited = lastEditedFromBufferAdjusted; bool otherOverwrites = overwriteLocalData && !weOwnSimulation; - auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) { + auto shouldUpdate = [this, lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) { + if (stillHasGrabActions()) { + return false; + } bool simulationChanged = lastEdited > updatedTimestamp; return otherOverwrites && simulationChanged && (valueChanged || filterRejection); }; From 104084d811b373285c8357f659cfb58e331e5380 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Tue, 15 Jan 2019 18:56:09 -0800 Subject: [PATCH 18/46] Avatar Mixer Protocol: Normalize translation before compression --- libraries/avatars/src/AvatarData.cpp | 36 +++++++++++++++++++++------- libraries/avatars/src/AvatarData.h | 3 ++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 21e0a6aba2..abd89525fa 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -677,7 +677,6 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent validityPosition = destinationBuffer; #ifdef WANT_DEBUG - int translationSentCount = 0; unsigned char* beforeTranslations = destinationBuffer; #endif @@ -686,7 +685,13 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent float minTranslation = (distanceAdjust && cullSmallChanges) ? getDistanceBasedMinTranslationDistance(viewerPosition) : AVATAR_MIN_TRANSLATION; - float maxTranslationDimension = 0.0; + float maxTranslationDimension = 0.0f; + const int MAX_NUM_JOINTS = 256; + + assert(numJoints < MAX_NUM_JOINTS); + glm::vec3 translationsSentArray[MAX_NUM_JOINTS]; // 3060 bytes allocated on the stack for performance. + int translationsSent = 0; + i = sendStatus.translationsSent; for (; i < numJoints; ++i) { const JointData& data = joints[i]; @@ -697,15 +702,11 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent if (sendAll || last.translationIsDefaultPose || (!cullSmallChanges && last.translation != data.translation) || (cullSmallChanges && glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation)) { validityPosition[i / BITS_IN_BYTE] |= 1 << (i % BITS_IN_BYTE); -#ifdef WANT_DEBUG - translationSentCount++; -#endif maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension); maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension); maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension); - destinationBuffer += - packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); + translationsSentArray[translationsSent++] = data.translation; if (sentJoints) { sentJoints[i].translation = data.translation; @@ -721,6 +722,16 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent } } + + // AJT: TODO make sure size computation is properly up to date! + // Write maxTranslationDimension into packet + memcpy(destinationBuffer, &maxTranslationDimension, sizeof(float)); + destinationBuffer += sizeof(float); + + // Write normalized and compressed translations into packet + for (i = 0; i < translationsSent; ++i) { + destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, translationsSentArray[i] / maxTranslationDimension, TRANSLATION_COMPRESSION_RADIX); + } sendStatus.translationsSent = i; // faux joints @@ -766,7 +777,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent #ifdef WANT_DEBUG if (sendAll) { qCDebug(avatars) << "AvatarData::toByteArray" << cullSmallChanges << sendAll - << "rotations:" << rotationSentCount << "translations:" << translationSentCount + << "rotations:" << rotationSentCount << "translations:" << translationsSentCount << "largest:" << maxTranslationDimension << "size:" << (beforeRotations - startPosition) << "+" @@ -1280,6 +1291,13 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } } // 1 + bytesOfValidity bytes + + // AJT: read maxTranslationDimension + float maxTranslationDimension; + PACKET_READ_CHECK(MaxTranslationDimension, sizeof(float)); + memcpy(&maxTranslationDimension, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + // each joint translation component is stored in 6 bytes. const int COMPRESSED_TRANSLATION_SIZE = 6; PACKET_READ_CHECK(JointTranslation, numValidJointTranslations * COMPRESSED_TRANSLATION_SIZE); @@ -1288,6 +1306,8 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { JointData& data = _jointData[i]; if (validTranslations[i]) { sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); + // un-normalize translation + data.translation *= maxTranslationDimension; _hasNewJointData = true; data.translationIsDefaultPose = false; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index ec5ea4a5d0..8a3014d043 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -277,7 +277,8 @@ namespace AvatarDataPacket { uint8_t rotationValidityBits[ceil(numJoints / 8)]; // one bit per joint, if true then a compressed rotation follows. SixByteQuat rotation[numValidRotations]; // encodeded and compressed by packOrientationQuatToSixBytes() uint8_t translationValidityBits[ceil(numJoints / 8)]; // one bit per joint, if true then a compressed translation follows. - SixByteTrans translation[numValidTranslations]; // encodeded and compressed by packFloatVec3ToSignedTwoByteFixed() + float maxTranslationDimension; // used to normalize fixed point translation values. + SixByteTrans translation[numValidTranslations]; // normalized and compressed by packFloatVec3ToSignedTwoByteFixed() SixByteQuat leftHandControllerRotation; SixByteTrans leftHandControllerTranslation; From 0bd6f9e26b1fcf8b7978b0e5469389393209a291 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 16 Jan 2019 12:03:56 -0800 Subject: [PATCH 19/46] Fix JNI signature --- android/apps/interface/src/main/cpp/native.cpp | 2 +- .../java/io/highfidelity/hifiinterface/InterfaceActivity.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/apps/interface/src/main/cpp/native.cpp b/android/apps/interface/src/main/cpp/native.cpp index f9c7751a3e..2bb851bb85 100644 --- a/android/apps/interface/src/main/cpp/native.cpp +++ b/android/apps/interface/src/main/cpp/native.cpp @@ -149,7 +149,7 @@ void unpackAndroidAssets() { extern "C" { -JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCreate(JNIEnv* env, jobject obj, jobject instance, jobject asset_mgr) { +JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCreate(JNIEnv* env, jobject instance, jobject asset_mgr) { g_assetManager = AAssetManager_fromJava(env, asset_mgr); qRegisterMetaType("QAndroidJniObject"); __interfaceActivity = QAndroidJniObject(instance); diff --git a/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java index 50aea59663..b7d2157737 100644 --- a/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java +++ b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java @@ -61,7 +61,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW private HeadsetStateReceiver headsetStateReceiver; //public static native void handleHifiURL(String hifiURLString); - private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager); + private native void nativeOnCreate(AssetManager assetManager); private native void nativeOnDestroy(); private native void nativeGotoUrl(String url); private native void nativeGoToUser(String username); @@ -114,7 +114,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW assetManager = getResources().getAssets(); //nativeGvrApi = - nativeOnCreate(this, assetManager /*, gvrApi.getNativeGvrContext()*/); + nativeOnCreate(assetManager /*, gvrApi.getNativeGvrContext()*/); final View rootView = getWindow().getDecorView().findViewById(android.R.id.content); From 1879cd3b3cdb2e068db2ea1c9099f572cc692153 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 17 Jan 2019 11:10:19 -0800 Subject: [PATCH 20/46] Fixing repository order --- android/apps/interface/build.gradle | 4 ++-- android/build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/apps/interface/build.gradle b/android/apps/interface/build.gradle index 0c23496faa..46d1574b18 100644 --- a/android/apps/interface/build.gradle +++ b/android/apps/interface/build.gradle @@ -2,8 +2,8 @@ import org.apache.tools.ant.taskdefs.condition.Os buildscript { repositories { - google() jcenter() + google() } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' @@ -12,8 +12,8 @@ buildscript { allprojects { repositories { - google() jcenter() + google() } } diff --git a/android/build.gradle b/android/build.gradle index 11c702130c..ed2ca1c47e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -10,8 +10,8 @@ import java.util.regex.Pattern buildscript { repositories { - jcenter() google() + jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' @@ -26,8 +26,8 @@ plugins { allprojects { repositories { - jcenter() google() + jcenter() mavenCentral() } } From 59fafa1f5cb7079f62e63e1d82505ba30da7b25e Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 17 Jan 2019 11:47:12 -0800 Subject: [PATCH 21/46] only do entitlements check once --- plugins/oculus/src/OculusHelpers.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 29691e73a5..548afb97ab 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -82,15 +82,18 @@ private: } #ifdef OCULUS_APP_ID - if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { - if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { - qCWarning(oculusLog) << "Unable to initialize the platform for entitlement check - fail the check" << ovr::getError(); - return; - } else { - qCDebug(oculusLog) << "Performing Oculus Platform entitlement check"; - ovr_Entitlement_GetIsViewerEntitled(); + static std::once_flag once; + std::call_once(once, []() { + if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { + if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { + qCWarning(oculusLog) << "Unable to initialize the platform for entitlement check - fail the check" << ovr::getError(); + return; + } else { + qCDebug(oculusLog) << "Performing Oculus Platform entitlement check"; + ovr_Entitlement_GetIsViewerEntitled(); + } } - } + }); #endif ovrGraphicsLuid luid; From 2bf7ac27451d0fd953d829cd13871d2041ea62ab Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 15 Jan 2019 11:36:08 -0800 Subject: [PATCH 22/46] fix bug that was introducing a local velocity to an entity when it was parented to a moving avatar --- libraries/entities/src/EntityItemProperties.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 1fdff19e38..affd061af1 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -3833,22 +3833,22 @@ void EntityItemProperties::copySimulationRestrictedProperties(const EntityItemPo setParentJointIndex(entity->getParentJointIndex()); } if (!_localPositionChanged && !_positionChanged) { - setPosition(entity->getWorldPosition()); + setLocalPosition(entity->getLocalPosition()); } if (!_localRotationChanged && !_rotationChanged) { - setRotation(entity->getWorldOrientation()); + setLocalRotation(entity->getLocalOrientation()); } if (!_localVelocityChanged && !_velocityChanged) { - setVelocity(entity->getWorldVelocity()); + setLocalVelocity(entity->getLocalVelocity()); } if (!_localAngularVelocityChanged && !_angularVelocityChanged) { - setAngularVelocity(entity->getWorldAngularVelocity()); + setLocalAngularVelocity(entity->getLocalAngularVelocity()); } if (!_accelerationChanged) { setAcceleration(entity->getAcceleration()); } if (!_localDimensionsChanged && !_dimensionsChanged) { - setDimensions(entity->getScaledDimensions()); + setLocalDimensions(entity->getUnscaledDimensions()); } } From c8e9bff03a18b24ce7168f023509a45aadac94a3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 16 Jan 2019 15:31:04 -0800 Subject: [PATCH 23/46] fix releaseGrab call on grabbed entity when a nearGrab ends --- .../controllerModules/farGrabEntity.js | 4 ++-- .../controllerModules/nearGrabEntity.js | 15 ++++++++------- .../system/libraries/controllerDispatcherUtils.js | 9 ++++++--- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/scripts/system/controllers/controllerModules/farGrabEntity.js b/scripts/system/controllers/controllerModules/farGrabEntity.js index dab1aa97af..197a809e91 100644 --- a/scripts/system/controllers/controllerModules/farGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farGrabEntity.js @@ -11,7 +11,7 @@ Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager, - getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, findGroupParent, + getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, findGrabbableGroupParent, worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES */ @@ -308,7 +308,7 @@ Script.include("/~/system/libraries/controllers.js"); var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); if (entityIsGrabbable(gtProps)) { // if we've attempted to grab a child, roll up to the root of the tree - var groupRootProps = findGroupParent(controllerData, gtProps); + var groupRootProps = findGrabbableGroupParent(controllerData, gtProps); if (entityIsGrabbable(groupRootProps)) { return groupRootProps; } diff --git a/scripts/system/controllers/controllerModules/nearGrabEntity.js b/scripts/system/controllers/controllerModules/nearGrabEntity.js index 60a5781ca4..0f8071677c 100644 --- a/scripts/system/controllers/controllerModules/nearGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearGrabEntity.js @@ -8,9 +8,10 @@ /* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, - makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, findGroupParent, Vec3, cloneEntity, - entityIsCloneable, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, distanceBetweenPointAndEntityBoundingBox, - getGrabbableData, getEnabledModuleByName, DISPATCHER_PROPERTIES, HMD, NEAR_GRAB_DISTANCE + makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, findGrabbableGroupParent, Vec3, + cloneEntity, entityIsCloneable, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, + distanceBetweenPointAndEntityBoundingBox, getGrabbableData, getEnabledModuleByName, DISPATCHER_PROPERTIES, HMD, + NEAR_GRAB_DISTANCE */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -80,9 +81,6 @@ Script.include("/~/system/libraries/controllers.js"); this.endNearGrabEntity = function () { this.endGrab(); - this.grabbing = false; - this.targetEntityID = null; - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "releaseGrab", args); Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ @@ -90,6 +88,9 @@ Script.include("/~/system/libraries/controllers.js"); grabbedEntity: this.targetEntityID, joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" })); + + this.grabbing = false; + this.targetEntityID = null; }; this.getTargetProps = function (controllerData) { @@ -110,7 +111,7 @@ Script.include("/~/system/libraries/controllers.js"); if (entityIsGrabbable(props) || entityIsCloneable(props)) { if (!entityIsCloneable(props)) { // if we've attempted to grab a non-cloneable child, roll up to the root of the tree - var groupRootProps = findGroupParent(controllerData, props); + var groupRootProps = findGrabbableGroupParent(controllerData, props); if (entityIsGrabbable(groupRootProps)) { return groupRootProps; } diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 221af07474..43dac435ac 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -46,7 +46,7 @@ makeLaserLockInfo:true, entityHasActions:true, ensureDynamic:true, - findGroupParent:true, + findGrabbableGroupParent:true, BUMPER_ON_VALUE:true, getEntityParents:true, findHandChildEntities:true, @@ -439,7 +439,7 @@ ensureDynamic = function (entityID) { } }; -findGroupParent = function (controllerData, targetProps) { +findGrabbableGroupParent = function (controllerData, targetProps) { while (targetProps.grab.grabDelegateToParent && targetProps.parentID && targetProps.parentID !== Uuid.NULL && @@ -448,6 +448,9 @@ findGroupParent = function (controllerData, targetProps) { if (!parentProps) { break; } + if (!entityIsGrabbable(parentProps)) { + break; + } parentProps.id = targetProps.parentID; targetProps = parentProps; controllerData.nearbyEntityPropertiesByID[targetProps.id] = targetProps; @@ -614,7 +617,7 @@ if (typeof module !== 'undefined') { unhighlightTargetEntity: unhighlightTargetEntity, clearHighlightedEntities: clearHighlightedEntities, makeRunningValues: makeRunningValues, - findGroupParent: findGroupParent, + findGrabbableGroupParent: findGrabbableGroupParent, LEFT_HAND: LEFT_HAND, RIGHT_HAND: RIGHT_HAND, BUMPER_ON_VALUE: BUMPER_ON_VALUE, From 4fbc257be0eb3a1578bc6273c05b148dc89f1a4b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 16 Jan 2019 16:26:40 -0800 Subject: [PATCH 24/46] don't cauterize head-children when they are grabbed --- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/avatar/MyAvatar.h | 2 -- libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp | 2 ++ libraries/avatars-renderer/src/avatars-renderer/Avatar.h | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index cc7742c517..54064e8523 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -773,7 +773,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) { auto headBoneSet = _skeletonModel->getCauterizeBoneSet(); forEachChild([&](SpatiallyNestablePointer object) { bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end(); - if (isChildOfHead) { + if (isChildOfHead && !object->hasGrabs()) { // Cauterize or display children of head per head drawing state. updateChildCauterization(object, !_prevShouldDrawHead); object->forEachDescendant([&](SpatiallyNestablePointer descendant) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 58880acb08..23eb746226 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1869,8 +1869,6 @@ private: bool _enableDebugDrawIKChains { false }; bool _enableDebugDrawDetailedCollision { false }; - mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state? - AudioListenerMode _audioListenerMode; glm::vec3 _customListenPosition; glm::quat _customListenOrientation; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index a6185d7e79..e35a47b821 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -385,6 +385,7 @@ void Avatar::updateGrabs() { entityTree->updateEntityQueryAACube(target, packetSender, force, iShouldTellServer); }); } + _cauterizationNeedsUpdate = true; } _avatarGrabs.remove(grabID); _changedAvatarGrabs.remove(grabID); @@ -402,6 +403,7 @@ void Avatar::updateGrabs() { target->addGrab(grab); // only clear this entry from the _changedAvatarGrabs if we found the entity. changeItr.remove(); + _cauterizationNeedsUpdate = true; } } }); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 4ff3e9cc13..e9359ec8c5 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -536,6 +536,8 @@ protected: glm::vec3 _worldUpDirection { Vectors::UP }; bool _moving { false }; ///< set when position is changing + mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state? + // protected methods... bool isLookingAtMe(AvatarSharedPointer avatar) const; void updateGrabs(); From e22024b0dd3086386a5fcf82ddb3490f7ad64c36 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 17 Jan 2019 13:31:11 -0800 Subject: [PATCH 25/46] revert attempted fix for non-zero velocity for hats --- libraries/entities/src/EntityItemProperties.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index affd061af1..1fdff19e38 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -3833,22 +3833,22 @@ void EntityItemProperties::copySimulationRestrictedProperties(const EntityItemPo setParentJointIndex(entity->getParentJointIndex()); } if (!_localPositionChanged && !_positionChanged) { - setLocalPosition(entity->getLocalPosition()); + setPosition(entity->getWorldPosition()); } if (!_localRotationChanged && !_rotationChanged) { - setLocalRotation(entity->getLocalOrientation()); + setRotation(entity->getWorldOrientation()); } if (!_localVelocityChanged && !_velocityChanged) { - setLocalVelocity(entity->getLocalVelocity()); + setVelocity(entity->getWorldVelocity()); } if (!_localAngularVelocityChanged && !_angularVelocityChanged) { - setLocalAngularVelocity(entity->getLocalAngularVelocity()); + setAngularVelocity(entity->getWorldAngularVelocity()); } if (!_accelerationChanged) { setAcceleration(entity->getAcceleration()); } if (!_localDimensionsChanged && !_dimensionsChanged) { - setLocalDimensions(entity->getUnscaledDimensions()); + setDimensions(entity->getScaledDimensions()); } } From 74f9a415d364d039d5f5d57635aa412b24bf3959 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 17 Jan 2019 13:58:34 -0800 Subject: [PATCH 26/46] move _cauterizationNeedsUpdate back to MyAvatar --- interface/src/avatar/MyAvatar.cpp | 4 +++- interface/src/avatar/MyAvatar.h | 2 ++ .../avatars-renderer/src/avatars-renderer/Avatar.cpp | 9 +++++---- libraries/avatars-renderer/src/avatars-renderer/Avatar.h | 4 +--- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 54064e8523..48acf09abb 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -823,7 +823,9 @@ void MyAvatar::simulate(float deltaTime, bool inView) { // and all of its joints, now update our attachements. Avatar::simulateAttachments(deltaTime); relayJointDataToChildren(); - updateGrabs(); + if (updateGrabs()) { + _cauterizationNeedsUpdate = true; + } if (!_skeletonModel->hasSkeleton()) { // All the simulation that can be done has been done diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 23eb746226..58880acb08 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1869,6 +1869,8 @@ private: bool _enableDebugDrawIKChains { false }; bool _enableDebugDrawDetailedCollision { false }; + mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state? + AudioListenerMode _audioListenerMode; glm::vec3 _customListenPosition; glm::quat _customListenOrientation; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index e35a47b821..5933e9adee 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -324,8 +324,8 @@ void Avatar::removeAvatarEntitiesFromTree() { } } -void Avatar::updateGrabs() { - +bool Avatar::updateGrabs() { + bool grabAddedOrRemoved = false; // update the Grabs according to any changes in _avatarGrabData _avatarGrabsLock.withWriteLock([&] { if (_avatarGrabDataChanged) { @@ -385,7 +385,7 @@ void Avatar::updateGrabs() { entityTree->updateEntityQueryAACube(target, packetSender, force, iShouldTellServer); }); } - _cauterizationNeedsUpdate = true; + grabAddedOrRemoved = true; } _avatarGrabs.remove(grabID); _changedAvatarGrabs.remove(grabID); @@ -403,10 +403,11 @@ void Avatar::updateGrabs() { target->addGrab(grab); // only clear this entry from the _changedAvatarGrabs if we found the entity. changeItr.remove(); - _cauterizationNeedsUpdate = true; + grabAddedOrRemoved = true; } } }); + return grabAddedOrRemoved; } void Avatar::accumulateGrabPositions(std::map& grabAccumulators) { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index e9359ec8c5..d5431ad2d2 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -536,11 +536,9 @@ protected: glm::vec3 _worldUpDirection { Vectors::UP }; bool _moving { false }; ///< set when position is changing - mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state? - // protected methods... bool isLookingAtMe(AvatarSharedPointer avatar) const; - void updateGrabs(); + bool updateGrabs(); void relayJointDataToChildren(); void fade(render::Transaction& transaction, render::Transition::Type type); From 286f23d512b0770975050acaff1ccdb298bef5d1 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Thu, 17 Jan 2019 15:19:54 -0800 Subject: [PATCH 27/46] Updated protocol version and fixed bugs --- libraries/animation/src/Rig.cpp | 9 ++- libraries/avatars/src/AvatarData.cpp | 56 +++++++++---------- libraries/avatars/src/AvatarData.h | 1 - .../networking/src/udt/PacketHeaders.cpp | 4 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/shared/src/JointData.h | 2 +- tools/dissectors/3-hf-avatar.lua | 3 + 7 files changed, 39 insertions(+), 39 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 44fdd8797f..c7a342b0eb 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1985,11 +1985,10 @@ void Rig::copyJointsIntoJointData(QVector& jointDataVec) const { data.rotation = !_sendNetworkNode ? _internalPoseSet._absolutePoses[i].rot() : _networkPoseSet._absolutePoses[i].rot(); data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot); - // translations are in relative frame but scaled so that they are in meters, - // instead of model units. + // translations are in relative frame. glm::vec3 defaultRelTrans = _animSkeleton->getRelativeDefaultPose(i).trans(); glm::vec3 currentRelTrans = _sendNetworkNode ? _networkPoseSet._relativePoses[i].trans() : _internalPoseSet._relativePoses[i].trans(); - data.translation = geometryToRigScale * currentRelTrans; + data.translation = currentRelTrans; data.translationIsDefaultPose = isEqual(currentRelTrans, defaultRelTrans); } else { data.translationIsDefaultPose = true; @@ -2042,8 +2041,8 @@ void Rig::copyJointsFromJointData(const QVector& jointDataVec) { if (data.translationIsDefaultPose) { _internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans(); } else { - // JointData translations are in scaled relative-frame so we scale back to regular relative-frame - _internalPoseSet._relativePoses[i].trans() = rigToGeometryScale * data.translation; + // JointData translations are in relative-frame + _internalPoseSet._relativePoses[i].trans() = data.translation; } } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index abd89525fa..b649bd2994 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -73,6 +73,7 @@ size_t AvatarDataPacket::maxJointDataSize(size_t numJoints, bool hasGrabJoints) totalSize += validityBitsSize; // Orientations mask totalSize += numJoints * sizeof(SixByteQuat); // Orientations totalSize += validityBitsSize; // Translations mask + totalSize += sizeof(float); // maxTranslationDimension totalSize += numJoints * sizeof(SixByteTrans); // Translations size_t NUM_FAUX_JOINT = 2; @@ -612,12 +613,23 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent const int jointBitVectorSize = calcBitVectorSize(numJoints); // Start joints if room for at least the faux joints. - IF_AVATAR_SPACE(PACKET_HAS_JOINT_DATA, 1 + 2 * jointBitVectorSize + AvatarDataPacket::FAUX_JOINTS_SIZE) { + IF_AVATAR_SPACE(PACKET_HAS_JOINT_DATA, 1 + 4 + 2 * jointBitVectorSize + AvatarDataPacket::FAUX_JOINTS_SIZE) { // Allow for faux joints + translation bit-vector: const ptrdiff_t minSizeForJoint = sizeof(AvatarDataPacket::SixByteQuat) + jointBitVectorSize + AvatarDataPacket::FAUX_JOINTS_SIZE; auto startSection = destinationBuffer; + // compute maxTranslationDimension before we send any joint data. + float maxTranslationDimension = 0.001f; + for (int i = 0; i < numJoints; ++i) { + const JointData& data = jointData[i]; + if (!data.translationIsDefaultPose) { + maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension); + maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension); + maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension); + } + } + // joint rotation data *destinationBuffer++ = (uint8_t)numJoints; @@ -677,21 +689,19 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent validityPosition = destinationBuffer; #ifdef WANT_DEBUG + int translationSentCount = 0; unsigned char* beforeTranslations = destinationBuffer; #endif memset(destinationBuffer, 0, jointBitVectorSize); destinationBuffer += jointBitVectorSize; // Move pointer past the validity bytes + // write maxTranslationDimension + memcpy(destinationBuffer, &maxTranslationDimension, sizeof(float)); + destinationBuffer += sizeof(float); + float minTranslation = (distanceAdjust && cullSmallChanges) ? getDistanceBasedMinTranslationDistance(viewerPosition) : AVATAR_MIN_TRANSLATION; - float maxTranslationDimension = 0.0f; - const int MAX_NUM_JOINTS = 256; - - assert(numJoints < MAX_NUM_JOINTS); - glm::vec3 translationsSentArray[MAX_NUM_JOINTS]; // 3060 bytes allocated on the stack for performance. - int translationsSent = 0; - i = sendStatus.translationsSent; for (; i < numJoints; ++i) { const JointData& data = joints[i]; @@ -702,11 +712,11 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent if (sendAll || last.translationIsDefaultPose || (!cullSmallChanges && last.translation != data.translation) || (cullSmallChanges && glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation)) { validityPosition[i / BITS_IN_BYTE] |= 1 << (i % BITS_IN_BYTE); - maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension); - maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension); - maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension); - - translationsSentArray[translationsSent++] = data.translation; +#ifdef WANT_DEBUG + translationSentCount++; +#endif + destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation / maxTranslationDimension, + TRANSLATION_COMPRESSION_RADIX); if (sentJoints) { sentJoints[i].translation = data.translation; @@ -722,16 +732,6 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent } } - - // AJT: TODO make sure size computation is properly up to date! - // Write maxTranslationDimension into packet - memcpy(destinationBuffer, &maxTranslationDimension, sizeof(float)); - destinationBuffer += sizeof(float); - - // Write normalized and compressed translations into packet - for (i = 0; i < translationsSent; ++i) { - destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, translationsSentArray[i] / maxTranslationDimension, TRANSLATION_COMPRESSION_RADIX); - } sendStatus.translationsSent = i; // faux joints @@ -777,7 +777,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent #ifdef WANT_DEBUG if (sendAll) { qCDebug(avatars) << "AvatarData::toByteArray" << cullSmallChanges << sendAll - << "rotations:" << rotationSentCount << "translations:" << translationsSentCount + << "rotations:" << rotationSentCount << "translations:" << translationSentCount << "largest:" << maxTranslationDimension << "size:" << (beforeRotations - startPosition) << "+" @@ -796,7 +796,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent outboundDataRateOut->jointDataRate.increment(numBytes); } } - + IF_AVATAR_SPACE(PACKET_HAS_JOINT_DEFAULT_POSE_FLAGS, 1 + 2 * jointBitVectorSize) { auto startSection = destinationBuffer; @@ -1291,10 +1291,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } } // 1 + bytesOfValidity bytes - - // AJT: read maxTranslationDimension + // read maxTranslationDimension float maxTranslationDimension; - PACKET_READ_CHECK(MaxTranslationDimension, sizeof(float)); + PACKET_READ_CHECK(JointMaxTranslationDimension, sizeof(float)); memcpy(&maxTranslationDimension, sourceBuffer, sizeof(float)); sourceBuffer += sizeof(float); @@ -1306,7 +1305,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { JointData& data = _jointData[i]; if (validTranslations[i]) { sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); - // un-normalize translation data.translation *= maxTranslationDimension; _hasNewJointData = true; data.translationIsDefaultPose = false; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8a3014d043..5bca76b513 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -279,7 +279,6 @@ namespace AvatarDataPacket { uint8_t translationValidityBits[ceil(numJoints / 8)]; // one bit per joint, if true then a compressed translation follows. float maxTranslationDimension; // used to normalize fixed point translation values. SixByteTrans translation[numValidTranslations]; // normalized and compressed by packFloatVec3ToSignedTwoByteFixed() - SixByteQuat leftHandControllerRotation; SixByteTrans leftHandControllerTranslation; SixByteQuat rightHandControllerRotation; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 642914cd56..5634edca05 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,10 +38,10 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: case PacketType::AvatarData: - return static_cast(AvatarMixerPacketVersion::CollisionFlag); + return static_cast(AvatarMixerPacketVersion::SendMaxTranslationDimension); case PacketType::BulkAvatarData: case PacketType::KillAvatar: - return static_cast(AvatarMixerPacketVersion::FasterAvatarEntities); + return static_cast(AvatarMixerPacketVersion::SendMaxTranslationDimension); case PacketType::MessagesData: return static_cast(MessageDataVersion::TextOrBinaryData); // ICE packets diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index f53a287d71..c01b3a47d7 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -312,7 +312,8 @@ enum class AvatarMixerPacketVersion : PacketVersion { GrabTraits, CollisionFlag, AvatarTraitsAck, - FasterAvatarEntities + FasterAvatarEntities, + SendMaxTranslationDimension }; enum class DomainConnectRequestVersion : PacketVersion { diff --git a/libraries/shared/src/JointData.h b/libraries/shared/src/JointData.h index f4c8b89e7a..7a2420262a 100644 --- a/libraries/shared/src/JointData.h +++ b/libraries/shared/src/JointData.h @@ -14,7 +14,7 @@ public: }; // Used by the avatar mixer to describe a single joint -// Translations relative to their parent and are in meters. +// Translations relative to their parent joint // Rotations are absolute (i.e. not relative to parent) and are in rig space. class JointData { public: diff --git a/tools/dissectors/3-hf-avatar.lua b/tools/dissectors/3-hf-avatar.lua index 0fa551c6f8..4fc5f44e66 100644 --- a/tools/dissectors/3-hf-avatar.lua +++ b/tools/dissectors/3-hf-avatar.lua @@ -282,6 +282,9 @@ function decode_avatar_data_packet(buf) i = i + num_validity_bytes result["valid_translations"] = "Valid Translations: " .. string.format("(%d/%d) {", #indices, num_joints) .. table.concat(indices, ", ") .. "}" + -- TODO: skip maxTranslationDimension + i = i + 4 + -- TODO: skip translations for now i = i + #indices * 6 From 74b83d9961a51cf04faefb49cbc6657dafae9111 Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 17 Jan 2019 15:23:40 -0800 Subject: [PATCH 28/46] Add ESS to the Agent's node interest set --- assignment-client/src/Agent.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index cc2973f61d..3446379c8b 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -196,7 +196,8 @@ void Agent::run() { connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &Agent::nodeKilled); nodeList->addSetOfNodeTypesToNodeInterestSet({ - NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer + NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, + NodeType::MessagesMixer, NodeType::AssetServer, NodeType::EntityScriptServer }); } From f552f8d78a37d59212be209e7b9bee023e8a8213 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 17 Jan 2019 14:20:40 -0800 Subject: [PATCH 29/46] Working on fixing build problems --- android/docker/Dockerfile | 14 ++++++++------ hifi_android.py | 10 +++++----- hifi_utils.py | 5 ++++- hifi_vcpkg.py | 4 ++-- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile index 2a6943cbc2..96cc28c99a 100644 --- a/android/docker/Dockerfile +++ b/android/docker/Dockerfile @@ -52,11 +52,14 @@ ENV PATH ${PATH}:${ANDROID_NDK_HOME} RUN apt-get -y install \ g++ \ gcc \ + sudo \ + emacs-nox \ - # --- Gradle ARG BUILD_UID=1001 RUN useradd -ms /bin/bash -u $BUILD_UID jenkins +RUN echo "jenkins ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers USER jenkins WORKDIR /home/jenkins @@ -71,22 +74,21 @@ RUN mkdir "$HIFI_BASE" && \ RUN git clone https://github.com/jherico/hifi.git && \ cd ~/hifi && \ - git checkout feature/build/gradle-wrapper - + git checkout feature/quest_move_interface WORKDIR /home/jenkins/hifi -RUN touch .test4 && \ - git fetch && git reset origin/feature/build/gradle-wrapper --hard +RUN touch .test6 && \ + git fetch && git reset origin/feature/quest_move_interface --hard RUN mkdir build # Pre-cache the vcpkg managed dependencies WORKDIR /home/jenkins/hifi/build -RUN python3 ../prebuild.py --build-root `pwd` --android +RUN python3 ../prebuild.py --build-root `pwd` --android interface # Pre-cache the gradle dependencies WORKDIR /home/jenkins/hifi/android RUN ./gradlew -m tasks -PHIFI_ANDROID_PRECOMPILED=$HIFI_ANDROID_PRECOMPILED -RUN ./gradlew extractDependencies -PHIFI_ANDROID_PRECOMPILED=$HIFI_ANDROID_PRECOMPILED +#RUN ./gradlew extractDependencies -PHIFI_ANDROID_PRECOMPILED=$HIFI_ANDROID_PRECOMPILED diff --git a/hifi_android.py b/hifi_android.py index 308ad2a151..13c9cdccf2 100644 --- a/hifi_android.py +++ b/hifi_android.py @@ -222,7 +222,7 @@ class QtPackager: if (relativeFilename.startswith('qml')): continue filename = os.path.join(self.qtRootPath, relativeFilename) - self.files.extend(hifi_utils.recursiveFileList(filename)) + self.files.extend(hifi_utils.recursiveFileList(filename, excludeNamePattern=r"^\.")) elif item.tag == 'jar' and 'bundling' in item.attrib and item.attrib['bundling'] == "1": self.files.append(os.path.join(self.qtRootPath, item.attrib['file'])) elif item.tag == 'permission': @@ -247,7 +247,6 @@ class QtPackager: qmlImportResults = json.loads(commandResult) for item in qmlImportResults: if 'path' not in item: - print("Warning: QML import could not be resolved in any of the import paths: {}".format(item['name'])) continue path = os.path.realpath(item['path']) if not os.path.exists(path): @@ -258,7 +257,7 @@ class QtPackager: basePath = os.path.normcase(basePath) if basePath.startswith(qmlRootPath): continue - self.files.extend(hifi_utils.recursiveFileList(path)) + self.files.extend(hifi_utils.recursiveFileList(path, excludeNamePattern=r"^\.")) def processFiles(self): self.files = list(set(self.files)) @@ -271,7 +270,7 @@ class QtPackager: for sourceFile in self.files: if not os.path.isfile(sourceFile): raise RuntimeError("Unable to find dependency file " + sourceFile) - relativePath = os.path.relpath(sourceFile, self.qtRootPath) + relativePath = os.path.relpath(sourceFile, self.qtRootPath).replace('\\', '/') destinationFile = None if relativePath.endswith('.so'): garbledFileName = None @@ -284,7 +283,7 @@ class QtPackager: libName = m.group(1) ET.SubElement(qtLibsNode, 'item').text = libName else: - garbledFileName = 'lib' + relativePath.replace('\\', '_'[0]) + garbledFileName = 'lib' + relativePath.replace('/', '_'[0]) value = "{}:{}".format(garbledFileName, relativePath).replace('\\', '/') ET.SubElement(bundledLibsNode, 'item').text = value destinationFile = os.path.join(self.jniPath, garbledFileName) @@ -337,6 +336,7 @@ class QtPackager: def bundle(self): if not os.path.isfile(self.xmlFile): + print("Bundling Qt info into {}".format(self.xmlFile)) self.copyQtDeps() self.scanQmlImports() self.processFiles() diff --git a/hifi_utils.py b/hifi_utils.py index c1a52ed842..24e43dc83c 100644 --- a/hifi_utils.py +++ b/hifi_utils.py @@ -6,6 +6,7 @@ import ssl import subprocess import sys import tarfile +import re import urllib import urllib.request import zipfile @@ -23,13 +24,15 @@ def scriptRelative(*paths): return result -def recursiveFileList(startPath): +def recursiveFileList(startPath, excludeNamePattern=None ): result = [] if os.path.isfile(startPath): result.append(startPath) elif os.path.isdir(startPath): for dirName, subdirList, fileList in os.walk(startPath): for fname in fileList: + if excludeNamePattern and re.match(excludeNamePattern, fname): + continue result.append(os.path.realpath(os.path.join(startPath, dirName, fname))) result.sort() return result diff --git a/hifi_vcpkg.py b/hifi_vcpkg.py index 6d241c595f..e062b40d86 100644 --- a/hifi_vcpkg.py +++ b/hifi_vcpkg.py @@ -85,7 +85,7 @@ endif() if self.args.android: self.triplet = 'arm64-android' - self.androidPackagePath = os.path.join(self.path, 'android') + self.androidPackagePath = os.getenv('HIFI_ANDROID_PRECOMPILED', os.path.join(self.path, 'android')) else: self.triplet = self.hostTriplet @@ -216,7 +216,7 @@ endif() if not self.args.android: cmakeTemplate += VcpkgRepo.CMAKE_TEMPLATE_NON_ANDROID else: - precompiled = os.path.realpath(os.path.join(self.path, 'android')) + precompiled = os.path.realpath(self.androidPackagePath) qtCmakePrefix = os.path.realpath(os.path.join(precompiled, 'qt/lib/cmake')) cmakeTemplate += 'set(HIFI_ANDROID_PRECOMPILED "{}")\n'.format(precompiled) cmakeTemplate += 'set(QT_CMAKE_PREFIX_PATH "{}")\n'.format(qtCmakePrefix) From e68a8794cecd84744bd959fc3c4a42bfb24605ea Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Thu, 17 Jan 2019 16:18:43 -0800 Subject: [PATCH 30/46] Remove unused variable --- libraries/animation/src/Rig.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index c7a342b0eb..7b505f5668 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -2015,7 +2015,6 @@ void Rig::copyJointsFromJointData(const QVector& jointDataVec) { std::vector rotations; rotations.reserve(numJoints); const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform)); - const glm::vec3 rigToGeometryScale(extractScale(_rigToGeometryTransform)); for (int i = 0; i < numJoints; i++) { const JointData& data = jointDataVec.at(i); From a3e9ad9bc2a957703a28e468fd8b00e5b6eb7815 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 18 Jan 2019 10:30:02 -0800 Subject: [PATCH 31/46] Revert target SDK to 26 due to splash screen bug: https://tinyurl.com/yb9ll4cd --- android/apps/interface/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/apps/interface/build.gradle b/android/apps/interface/build.gradle index 46d1574b18..4163df03b7 100644 --- a/android/apps/interface/build.gradle +++ b/android/apps/interface/build.gradle @@ -35,7 +35,7 @@ task renameHifiACTaskRelease(type: Copy) { apply plugin: 'com.android.application' android { - compileSdkVersion 28 + compileSdkVersion 26 //buildToolsVersion '27.0.3' def appVersionCode = Integer.valueOf(VERSION_CODE ?: 1) @@ -44,7 +44,7 @@ android { defaultConfig { applicationId "io.highfidelity.hifiinterface" minSdkVersion 24 - targetSdkVersion 28 + targetSdkVersion 26 versionCode appVersionCode versionName appVersionName ndk { abiFilters 'arm64-v8a' } From d6f0fbd17b443aa5e3427fb3aaa8cab3fa861f24 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 18 Jan 2019 10:48:20 -0800 Subject: [PATCH 32/46] fix snap app issue --- interface/resources/qml/hifi/tablet/TabletRoot.qml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index a01d978b2f..b19dcbb919 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -134,8 +134,7 @@ Item { if (isWebPage) { var webUrl = tabletApps.get(currentApp).appWebUrl; var scriptUrl = tabletApps.get(currentApp).scriptUrl; - loadSource("hifi/tablet/TabletWebView.qml"); - loadWebUrl(webUrl, scriptUrl); + loadWebBase(webUrl, scriptUrl); } else { loader.load(tabletApps.get(currentApp).appUrl); } @@ -150,16 +149,6 @@ Item { tabletRoot.openBrowser = newWindow; } - function loadWebUrl(url, injectedJavaScriptUrl) { - tabletApps.clear(); - loader.item.url = url; - loader.item.scriptURL = injectedJavaScriptUrl; - tabletApps.append({"appUrl": "TabletWebView.qml", "isWebUrl": true, "scriptUrl": injectedJavaScriptUrl, "appWebUrl": url}); - if (loader.item.hasOwnProperty("closeButtonVisible")) { - loader.item.closeButtonVisible = false; - } - } - // used to send a message from qml to interface script. signal sendToScript(var message); From 17ac4138b68f118ddab5b9dff3eb7641ef886d3f Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Fri, 18 Jan 2019 13:43:56 -0800 Subject: [PATCH 33/46] typos --- libraries/entities/src/EntityItemProperties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 72c90092f0..51e1db063c 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -781,10 +781,10 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * 0. * @property {string} parentMaterialName="0" - Selects the mesh part or parts within the parent to which to apply the material. * If in the format "mat::string", all mesh parts with material name "string" are replaced. - * Otherwise the property value is parsed as an unsigned integer, specifying the mesh parth index to modify. If "all", + * Otherwise the property value is parsed as an unsigned integer, specifying the mesh part index to modify. If "all", * all mesh parts will be replaced. If an array (starts with "[" and ends with "]"), the string will be * split at each "," and each element will be parsed as either a number or a string if it starts with - * "mat::". In other words, "[0,1,mat::string,mat::string2]" will replace mesh parts 1 and 2, and any + * "mat::". In other words, "[0,1,mat::string,mat::string2]" will replace mesh parts 0 and 1, and any * mesh parts with material "string" or "string2". Do not put spaces around the commas. Invalid values * are parsed to 0. * @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either "uv" or From 9a854291af18811d630a2467f92d998e5bf400aa Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 18 Jan 2019 15:36:38 -0800 Subject: [PATCH 34/46] supress spurious not important AvatarEntity updates --- interface/src/avatar/MyAvatar.cpp | 8 ++++++-- libraries/entities/src/EntityTree.cpp | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e4da94c699..91987e721f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -873,9 +873,13 @@ void MyAvatar::simulate(float deltaTime, bool inView) { collisionlessAllowed = zone->getGhostingAllowed(); } EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender(); - bool force = false; - bool iShouldTellServer = true; forEachDescendant([&](SpatiallyNestablePointer object) { + // we need to update attached queryAACubes in our own local tree so point-select always works + // however we don't want to flood the update pipeline with AvatarEntity updates, so we assume + // others have all info required to properly update queryAACube of AvatarEntities on their end + EntityItemPointer entity = std::dynamic_pointer_cast(object); + bool iShouldTellServer = !(entity && entity->isAvatarEntity()); + const bool force = false; entityTree->updateEntityQueryAACube(object, packetSender, force, iShouldTellServer); }); }); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b251579b81..4c64a38e26 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -3008,8 +3008,8 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, // if the queryBox has changed, tell the entity-server EntityItemPointer entity = std::dynamic_pointer_cast(object); if (entity) { - bool tellServerThis = tellServer && (entity->getEntityHostType() != entity::HostType::AVATAR); - if ((entity->updateQueryAACube() || force)) { + // NOTE: we rely on side-effects of the entity->updateQueryAACube() call in the following if() conditional: + if (entity->updateQueryAACube() || force) { bool success; AACube newCube = entity->getQueryAACube(success); if (success) { @@ -3017,7 +3017,7 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, } // send an edit packet to update the entity-server about the queryAABox. We do this for domain-hosted // entities as well as for avatar-entities; the packet-sender will route the update accordingly - if (tellServerThis && packetSender && (entity->isDomainEntity() || entity->isAvatarEntity())) { + if (tellServer && packetSender && (entity->isDomainEntity() || entity->isAvatarEntity())) { quint64 now = usecTimestampNow(); EntityItemProperties properties = entity->getProperties(); properties.setQueryAACubeDirty(); From 5dbd62cc6711bbfacee6ce3988fc05dfed9524d1 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 18 Jan 2019 17:52:53 -0800 Subject: [PATCH 35/46] code review feedback --- libraries/avatars/src/AvatarData.cpp | 35 +++++++++++++++++++++------- libraries/avatars/src/AvatarData.h | 1 + 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b649bd2994..dcee1a9618 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -54,7 +54,8 @@ using namespace std; const QString AvatarData::FRAME_NAME = "com.highfidelity.recording.AvatarData"; -static const int TRANSLATION_COMPRESSION_RADIX = 12; +static const int TRANSLATION_COMPRESSION_RADIX = 14; +static const int FAUX_JOINT_COMPRESSION_RADIX = 12; static const int SENSOR_TO_WORLD_SCALE_RADIX = 10; static const float AUDIO_LOUDNESS_SCALE = 1024.0f; static const float DEFAULT_AVATAR_DENSITY = 1000.0f; // density of water @@ -86,6 +87,23 @@ size_t AvatarDataPacket::maxJointDataSize(size_t numJoints, bool hasGrabJoints) return totalSize; } +size_t AvatarDataPacket::minJointDataSize(size_t numJoints) { + const size_t validityBitsSize = calcBitVectorSize((int)numJoints); + + size_t totalSize = sizeof(uint8_t); // numJoints + + totalSize += validityBitsSize; // Orientations mask + // assume no valid rotations + totalSize += validityBitsSize; // Translations mask + totalSize += sizeof(float); // maxTranslationDimension + // assume no valid translations + + size_t NUM_FAUX_JOINT = 2; + totalSize += NUM_FAUX_JOINT * (sizeof(SixByteQuat) + sizeof(SixByteTrans)); // faux joints + + return totalSize; +} + size_t AvatarDataPacket::maxJointDefaultPoseFlagsSize(size_t numJoints) { const size_t bitVectorSize = calcBitVectorSize((int)numJoints); size_t totalSize = sizeof(uint8_t); // numJoints @@ -612,8 +630,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent assert(numJoints <= 255); const int jointBitVectorSize = calcBitVectorSize(numJoints); - // Start joints if room for at least the faux joints. - IF_AVATAR_SPACE(PACKET_HAS_JOINT_DATA, 1 + 4 + 2 * jointBitVectorSize + AvatarDataPacket::FAUX_JOINTS_SIZE) { + // 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; @@ -621,7 +639,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent // compute maxTranslationDimension before we send any joint data. float maxTranslationDimension = 0.001f; - for (int i = 0; i < numJoints; ++i) { + for (int i = sendStatus.rotationsSent; i < numJoints; ++i) { const JointData& data = jointData[i]; if (!data.translationIsDefaultPose) { maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension); @@ -697,8 +715,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent destinationBuffer += jointBitVectorSize; // Move pointer past the validity bytes // write maxTranslationDimension - memcpy(destinationBuffer, &maxTranslationDimension, sizeof(float)); - destinationBuffer += sizeof(float); + AVATAR_MEMCPY(maxTranslationDimension); float minTranslation = (distanceAdjust && cullSmallChanges) ? getDistanceBasedMinTranslationDistance(viewerPosition) : AVATAR_MIN_TRANSLATION; @@ -738,12 +755,12 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix()); destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerLeftHandTransform.getRotation()); destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerLeftHandTransform.getTranslation(), - TRANSLATION_COMPRESSION_RADIX); + FAUX_JOINT_COMPRESSION_RADIX); Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix()); destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerRightHandTransform.getRotation()); destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerRightHandTransform.getTranslation(), - TRANSLATION_COMPRESSION_RADIX); + FAUX_JOINT_COMPRESSION_RADIX); IF_AVATAR_SPACE(PACKET_HAS_GRAB_JOINTS, sizeof (AvatarDataPacket::FarGrabJoints)) { // the far-grab joints may range further than 3 meters, so we can't use packFloatVec3ToSignedTwoByteFixed etc @@ -882,7 +899,7 @@ const unsigned char* unpackFauxJoint(const unsigned char* sourceBuffer, ThreadSa glm::vec3 position; Transform transform; sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, orientation); - sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, position, TRANSLATION_COMPRESSION_RADIX); + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, position, FAUX_JOINT_COMPRESSION_RADIX); transform.setTranslation(position); transform.setRotation(orientation); matrixCache.set(transform.getMatrix()); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 5bca76b513..52ab5ba688 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -286,6 +286,7 @@ namespace AvatarDataPacket { }; */ size_t maxJointDataSize(size_t numJoints, bool hasGrabJoints); + size_t minJointDataSize(size_t numJoints); /* struct JointDefaultPoseFlags { From c3a8c71f60d015677b8a18469d58f3c9dd54dc04 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 21 Jan 2019 12:27:14 -0800 Subject: [PATCH 36/46] Add TabletMenu to list of pages that trigger the QmlCommerce bridge --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7b79215cd2..bb2f129385 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2911,6 +2911,7 @@ void Application::initializeUi() { QUrl{ "hifi/dialogs/security/SecurityImageChange.qml" }, QUrl{ "hifi/dialogs/security/SecurityImageModel.qml" }, QUrl{ "hifi/dialogs/security/SecurityImageSelection.qml" }, + QUrl{ "hifi/tablet/TabletMenu.qml" }, }, commerceCallback); QmlContextCallback ttsCallback = [](QQmlContext* context) { context->setContextProperty("TextToSpeech", DependencyManager::get().data()); From 5b1ea24d206ec1fb3b03af0df7d289f14a65f2b2 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 21 Jan 2019 12:35:48 -0800 Subject: [PATCH 37/46] glsl initializer lists are 4.2 --- libraries/render-utils/src/simple_transparent.slf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/simple_transparent.slf b/libraries/render-utils/src/simple_transparent.slf index ea444d6113..f14de6b0ae 100644 --- a/libraries/render-utils/src/simple_transparent.slf +++ b/libraries/render-utils/src/simple_transparent.slf @@ -92,10 +92,10 @@ void main(void) { emissive = vec3(clamp(emissiveAmount, 0.0, 1.0)); #elif defined(PROCEDURAL_V3) || defined(PROCEDURAL_V4) #if defined(PROCEDURAL_V3) - ProceduralFragment proceduralData = { + ProceduralFragment proceduralData = ProceduralFragment( #else vec4 position = cam._viewInverse * _positionES; - ProceduralFragmentWithPosition proceduralData = { + ProceduralFragmentWithPosition proceduralData = ProceduralFragmentWithPosition( position.xyz, #endif normal, @@ -107,7 +107,7 @@ void main(void) { DEFAULT_METALLIC, DEFAULT_OCCLUSION, DEFAULT_SCATTERING - }; + ); #if defined(PROCEDURAL_V3) emissiveAmount = getProceduralFragment(proceduralData); From fb09856c119fae93ba8d8447298e47d97cc749c4 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 21 Jan 2019 12:56:13 -0800 Subject: [PATCH 38/46] Gabriel Calero's fix. --- android/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile index 96cc28c99a..9332659ae9 100644 --- a/android/docker/Dockerfile +++ b/android/docker/Dockerfile @@ -27,7 +27,7 @@ RUN mkdir -p "$ANDROID_HOME" "$ANDROID_SDK_HOME" && \ unzip sdk.zip && \ rm sdk.zip && \ yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses - +RUN yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses && yes | $ANDROID_HOME/tools/bin/sdkmanager --update # Install Android Build Tool and Libraries RUN $ANDROID_HOME/tools/bin/sdkmanager --update RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \ From a693e0b6f9cad3a58341ffad62f8df0deaa35584 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 21 Jan 2019 13:08:37 -0800 Subject: [PATCH 39/46] Gabriel Calero's fix. --- android/docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile index 9332659ae9..10d6df4b4a 100644 --- a/android/docker/Dockerfile +++ b/android/docker/Dockerfile @@ -26,8 +26,8 @@ RUN mkdir -p "$ANDROID_HOME" "$ANDROID_SDK_HOME" && \ curl -s -S -o sdk.zip -L "${SDK_URL}" && \ unzip sdk.zip && \ rm sdk.zip && \ - yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses -RUN yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses && yes | $ANDROID_HOME/tools/bin/sdkmanager --update + yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses && yes | $ANDROID_HOME/tools/bin/sdkmanager --update + # Install Android Build Tool and Libraries RUN $ANDROID_HOME/tools/bin/sdkmanager --update RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \ From 084d55a414d8d57ac9310227f4c0b6d3a8e43257 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 21 Jan 2019 13:26:44 -0800 Subject: [PATCH 40/46] Gabriel Calero's fix. --- android/docker/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile index 10d6df4b4a..619eb562a4 100644 --- a/android/docker/Dockerfile +++ b/android/docker/Dockerfile @@ -29,7 +29,6 @@ RUN mkdir -p "$ANDROID_HOME" "$ANDROID_SDK_HOME" && \ yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses && yes | $ANDROID_HOME/tools/bin/sdkmanager --update # Install Android Build Tool and Libraries -RUN $ANDROID_HOME/tools/bin/sdkmanager --update RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \ "platforms;android-${ANDROID_VERSION}" \ "platform-tools" From 4edd072b3b020b8846daf699ea05849e8b474ea1 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 21 Jan 2019 16:49:54 -0800 Subject: [PATCH 41/46] Removed whitespace --- android/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile index 619eb562a4..c37f73cb2a 100644 --- a/android/docker/Dockerfile +++ b/android/docker/Dockerfile @@ -27,7 +27,7 @@ RUN mkdir -p "$ANDROID_HOME" "$ANDROID_SDK_HOME" && \ unzip sdk.zip && \ rm sdk.zip && \ yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses && yes | $ANDROID_HOME/tools/bin/sdkmanager --update - + # Install Android Build Tool and Libraries RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \ "platforms;android-${ANDROID_VERSION}" \ From 49947d9f6d053809bb0e3abdeffd6d19c3cbec42 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 21 Jan 2019 16:51:08 -0800 Subject: [PATCH 42/46] better default values --- libraries/render-utils/src/simple.slf | 12 ++++++------ libraries/render-utils/src/simple_transparent.slf | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index 582549ade1..469c0976aa 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -91,14 +91,14 @@ void main(void) { position.xyz, #endif normal, - vec3(0.0), + diffuse, DEFAULT_SPECULAR, - DEFAULT_EMISSIVE, + emissive, 1.0, - DEFAULT_ROUGHNESS, - DEFAULT_METALLIC, - DEFAULT_OCCLUSION, - DEFAULT_SCATTERING + roughness, + metallic, + occlusion, + scattering ); #if defined(PROCEDURAL_V3) diff --git a/libraries/render-utils/src/simple_transparent.slf b/libraries/render-utils/src/simple_transparent.slf index f14de6b0ae..6d8348f50c 100644 --- a/libraries/render-utils/src/simple_transparent.slf +++ b/libraries/render-utils/src/simple_transparent.slf @@ -99,13 +99,13 @@ void main(void) { position.xyz, #endif normal, - vec3(0.0), - DEFAULT_SPECULAR, - DEFAULT_EMISSIVE, - 1.0, - DEFAULT_ROUGHNESS, - DEFAULT_METALLIC, - DEFAULT_OCCLUSION, + diffuse, + fresnel, + emissive, + alpha, + roughness, + metallic, + occlusion, DEFAULT_SCATTERING ); From 3a5d550fa5ff9a89b97cd922a95fb8a8f69407e3 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 22 Jan 2019 17:13:36 -0800 Subject: [PATCH 43/46] Treat QmlCommerce as a singleton class --- interface/src/Application.cpp | 7 ++++--- interface/src/commerce/QmlCommerce.h | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7b79215cd2..b6a47d6c9d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -919,6 +919,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -2598,6 +2599,7 @@ void Application::cleanupBeforeQuit() { DependencyManager::destroy(); // Must be destroyed before TabletScriptingInterface // stop QML + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); @@ -2886,7 +2888,7 @@ void Application::initializeUi() { Tooltip::registerType(); UpdateDialog::registerType(); QmlContextCallback commerceCallback = [](QQmlContext* context) { - context->setContextProperty("Commerce", new QmlCommerce()); + context->setContextProperty("Commerce", DependencyManager::get().data()); }; OffscreenQmlSurface::addWhitelistContextHandler({ QUrl{ "hifi/commerce/checkout/Checkout.qml" }, @@ -8014,8 +8016,7 @@ void Application::openUrl(const QUrl& url) const { if (url.scheme() == URL_SCHEME_HIFI) { DependencyManager::get()->handleLookupString(url.toString()); } else if (url.scheme() == URL_SCHEME_HIFIAPP) { - QmlCommerce commerce; - commerce.openSystemApp(url.path()); + DependencyManager::get()->openSystemApp(url.path()); } else { // address manager did not handle - ask QDesktopServices to handle QDesktopServices::openUrl(url); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index ad21899ebf..3a376e748c 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -19,7 +19,9 @@ #include -class QmlCommerce : public QObject { +#include + +class QmlCommerce : public QObject, public Dependency { Q_OBJECT public: From 77293150b738f4373c7cb89c031998c2a43b207e Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 22 Jan 2019 18:05:47 -0800 Subject: [PATCH 44/46] Const declarations to enforce singleton capability --- interface/src/commerce/QmlCommerce.cpp | 12 +++++------- interface/src/commerce/QmlCommerce.h | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 00acd40e70..5236c5a7fb 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -22,7 +22,9 @@ #include #include "scripting/HMDScriptingInterface.h" -QmlCommerce::QmlCommerce() { +QmlCommerce::QmlCommerce() : + _appsPath(PathUtils::getAppDataPath() + "Apps/") +{ auto ledger = DependencyManager::get(); auto wallet = DependencyManager::get(); connect(ledger.data(), &Ledger::buyResult, this, &QmlCommerce::buyResult); @@ -44,22 +46,18 @@ QmlCommerce::QmlCommerce() { auto accountManager = DependencyManager::get(); connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() { setPassphrase(""); }); - - _appsPath = PathUtils::getAppDataPath() + "Apps/"; } - - void QmlCommerce::openSystemApp(const QString& appName) { - static QMap systemApps { + static const QMap systemApps { {"GOTO", "hifi/tablet/TabletAddressDialog.qml"}, {"PEOPLE", "hifi/Pal.qml"}, {"WALLET", "hifi/commerce/wallet/Wallet.qml"}, {"MARKET", "/marketplace.html"} }; - static QMap systemInject{ + static const QMap systemInject{ {"MARKET", "/scripts/system/html/js/marketplacesInject.js"} }; diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 3a376e748c..3217b8a1f9 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -100,7 +100,7 @@ protected: Q_INVOKABLE void updateItem(const QString& certificateId); private: - QString _appsPath; + const QString _appsPath; }; #endif // hifi_QmlCommerce_h From ea5705907bfe5b6d6221ec1dab42e156c08113c8 Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 18 Jan 2019 17:03:52 -0800 Subject: [PATCH 45/46] fix shape type and compound shape URL properties/tooltips --- .../entities/src/EntityItemProperties.cpp | 4 +-- .../system/assets/data/createAppTooltips.json | 12 +++++-- scripts/system/html/js/entityProperties.js | 34 ++++++++----------- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 1fdff19e38..721b32821d 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -900,7 +900,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * parse the JSON string into a JavaScript object of name, URL pairs. Read-only. * * @property {ShapeType} shapeType="none" - The shape of the collision hull used if collisions are enabled. - * @property {string} compoundShapeURL="" - The OBJ file to use for the compound shape if shapeType is + * @property {string} compoundShapeURL="" - The model file to use for the compound shape if shapeType is * "compound". * * @property {Entities.AnimationProperties} animation - An animation to play on the model. @@ -1238,7 +1238,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {ShapeType} shapeType="box" - The shape of the volume in which the zone's lighting effects and avatar * permissions have effect. Reverts to the default value if set to "none", or set to "compound" * and compoundShapeURL is "". - * @property {string} compoundShapeURL="" - The OBJ file to use for the compound shape if shapeType is + * @property {string} compoundShapeURL="" - The model file to use for the compound shape if shapeType is * "compound". * * @property {string} keyLightMode="inherit" - Configures the key light in the zone. Possible values:
diff --git a/scripts/system/assets/data/createAppTooltips.json b/scripts/system/assets/data/createAppTooltips.json index cb194c9d66..5c47577fab 100644 --- a/scripts/system/assets/data/createAppTooltips.json +++ b/scripts/system/assets/data/createAppTooltips.json @@ -39,6 +39,14 @@ "leftMargin": { "tooltip": "The left margin, in meters." }, + "zoneShapeType": { + "tooltip": "The shape of the volume in which the zone's lighting effects and avatar permissions have effect.", + "jsPropertyName": "shapeType" + }, + "zoneCompoundShapeURL": { + "tooltip": "The model file to use for the compound shape if Shape Type is \"Use Compound Shape URL\".", + "jsPropertyName": "compoundShapeURL" + }, "flyingAllowed": { "tooltip": "If enabled, users can fly in the zone." }, @@ -133,7 +141,7 @@ "tooltip": "The shape of the collision hull used if collisions are enabled. This affects how an entity collides." }, "compoundShapeURL": { - "tooltip": "The OBJ file to use for the compound shape if Collision Shape is \"compound\"." + "tooltip": "The model file to use for the compound shape if Collision Shape is \"Compound\"." }, "animation.url": { "tooltip": "An animation to play on the model." @@ -580,4 +588,4 @@ "tooltip": "Import a local or hosted file that can be used across domains.", "skipJSProperty": true } -} +} \ No newline at end of file diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 8b7264eeb1..15a5a32a34 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -184,6 +184,20 @@ const GROUPS = [ id: "zone", addToGroup: "base", properties: [ + { + label: "Shape Type", + type: "dropdown", + options: { "box": "Box", "sphere": "Sphere", "ellipsoid": "Ellipsoid", + "cylinder-y": "Cylinder", "compound": "Use Compound Shape URL" }, + propertyID: "zoneShapeType", + propertyName: "shapeType", // actual entity property name + }, + { + label: "Compound Shape URL", + type: "string", + propertyID: "zoneCompoundShapeURL", + propertyName: "compoundShapeURL", // actual entity property name + }, { label: "Flying Allowed", type: "bool", @@ -1345,24 +1359,6 @@ const GROUPS = [ }, ] }, - { - id: "zone_shape", - label: "ZONE SHAPE", - properties: [ - { - label: "Shape Type", - type: "dropdown", - options: { "box": "Box", "sphere": "Sphere", "ellipsoid": "Ellipsoid", - "cylinder-y": "Cylinder", "compound": "Use Compound Shape URL" }, - propertyID: "shapeType", - }, - { - label: "Compound Shape URL", - type: "string", - propertyID: "compoundShapeURL", - }, - ] - }, { id: "physics", label: "PHYSICS", @@ -1454,7 +1450,7 @@ const GROUPS_PER_TYPE = { None: [ 'base', 'spatial', 'behavior', 'collision', 'physics' ], Shape: [ 'base', 'shape', 'spatial', 'behavior', 'collision', 'physics' ], Text: [ 'base', 'text', 'spatial', 'behavior', 'collision', 'physics' ], - Zone: [ 'base', 'zone', 'spatial', 'behavior', 'zone_shape', 'physics' ], + Zone: [ 'base', 'zone', 'spatial', 'behavior', 'physics' ], Model: [ 'base', 'model', 'spatial', 'behavior', 'collision', 'physics' ], Image: [ 'base', 'image', 'spatial', 'behavior', 'collision', 'physics' ], Web: [ 'base', 'web', 'spatial', 'behavior', 'collision', 'physics' ], From 89032698ebaa911fb5625714542a1f4b2f53a664 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 22 Jan 2019 18:24:09 -0800 Subject: [PATCH 46/46] newline --- scripts/system/assets/data/createAppTooltips.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/assets/data/createAppTooltips.json b/scripts/system/assets/data/createAppTooltips.json index 5c47577fab..bf3ff3f324 100644 --- a/scripts/system/assets/data/createAppTooltips.json +++ b/scripts/system/assets/data/createAppTooltips.json @@ -588,4 +588,4 @@ "tooltip": "Import a local or hosted file that can be used across domains.", "skipJSProperty": true } -} \ No newline at end of file +}