From 84cd0e15299d7bfd2d9132b6c6c1c17373ca7faa Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 5 Feb 2018 18:08:36 -0800 Subject: [PATCH] wip live material swapping on model entities, model overlays, avatars, and albedo swap on shape entities --- domain-server/CMakeLists.txt | 2 + .../icons/create-icons/126-material-01.svg | 9 + .../resources/qml/hifi/tablet/EditTabView.qml | 2 +- interface/src/Application.cpp | 36 +++ interface/src/ui/overlays/ModelOverlay.cpp | 26 ++ interface/src/ui/overlays/ModelOverlay.h | 5 + interface/src/ui/overlays/Overlay.cpp | 10 + interface/src/ui/overlays/Overlay.h | 6 + .../src/avatars-renderer/Avatar.cpp | 30 +++ .../src/avatars-renderer/Avatar.h | 8 + libraries/avatars/CMakeLists.txt | 3 +- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 5 + .../src/RenderableEntityItem.cpp | 13 + .../src/RenderableEntityItem.h | 6 + .../src/RenderableMaterialEntityItem.cpp | 26 +- .../src/RenderableMaterialEntityItem.h | 5 +- .../src/RenderableModelEntityItem.cpp | 26 ++ .../src/RenderableModelEntityItem.h | 7 + .../src/RenderableShapeEntityItem.cpp | 29 +- .../src/RenderableShapeEntityItem.h | 2 +- .../entities/src/DeleteEntityOperator.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 39 ++- libraries/entities/src/EntityItem.h | 22 +- .../entities/src/EntityItemProperties.cpp | 52 ++-- libraries/entities/src/EntityItemProperties.h | 8 +- .../entities/src/EntityItemPropertiesMacros.h | 43 ++- libraries/entities/src/EntityPropertyFlags.h | 4 +- libraries/entities/src/EntityTree.cpp | 48 +++- libraries/entities/src/EntityTree.h | 15 ++ libraries/entities/src/EntityTreeElement.cpp | 26 +- libraries/entities/src/EntityTreeElement.h | 3 +- libraries/entities/src/MaterialEntityItem.cpp | 253 +++++++++++++++--- libraries/entities/src/MaterialEntityItem.h | 43 ++- libraries/entities/src/ModelEntityItem.cpp | 2 +- libraries/entities/src/ShapeEntityItem.cpp | 7 + libraries/entities/src/ShapeEntityItem.h | 6 +- libraries/graphics/src/graphics/Material.cpp | 15 ++ libraries/graphics/src/graphics/Material.h | 36 +++ .../src/model-networking/ModelCache.cpp | 2 +- .../src/model-networking/ModelCache.h | 6 +- libraries/octree/src/OctreePacketData.cpp | 11 + libraries/octree/src/OctreePacketData.h | 5 +- .../render-utils/src/MeshPartPayload.cpp | 32 ++- libraries/render-utils/src/MeshPartPayload.h | 13 +- libraries/render-utils/src/Model.cpp | 44 +++ libraries/render-utils/src/Model.h | 3 + scripts/system/edit.js | 51 ++-- scripts/system/html/css/edit-style.css | 12 +- scripts/system/html/entityProperties.html | 29 +- scripts/system/html/js/entityProperties.js | 61 ++--- tools/jsdoc/package-lock.json | 138 ++++++++++ 52 files changed, 1038 insertions(+), 251 deletions(-) create mode 100644 interface/resources/icons/create-icons/126-material-01.svg create mode 100644 tools/jsdoc/package-lock.json diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index c1e275e4d3..f67be55b92 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -22,6 +22,8 @@ setup_memory_debugger() symlink_or_copy_directory_beside_target(${_SHOULD_SYMLINK_RESOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/resources" "resources") # link the shared hifi libraries +include_hifi_library_headers(gpu) +include_hifi_library_headers(graphics) link_hifi_libraries(embedded-webserver networking shared avatars) # find OpenSSL diff --git a/interface/resources/icons/create-icons/126-material-01.svg b/interface/resources/icons/create-icons/126-material-01.svg new file mode 100644 index 0000000000..9b6d92505f --- /dev/null +++ b/interface/resources/icons/create-icons/126-material-01.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index 65dd871fb2..6f97664e06 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -135,7 +135,7 @@ TabView { } NewEntityButton { - icon: "icons/create-icons/94-model-01.svg" + icon: "icons/create-icons/126-material-01.svg" text: "MATERIAL" onClicked: { editRoot.sendToScript({ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1a54c94d53..1cf8f0587f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1580,6 +1580,42 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); + EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->addMaterial(material, shapeID); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->removeMaterial(material, shapeID); + return true; + } + return false; + }); + + EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->addMaterial(material, shapeID); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->removeMaterial(material, shapeID); + return true; + } + return false; + }); + // Keyboard focus handling for Web overlays. auto overlays = &(qApp->getOverlays()); connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) { diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 4847650163..9e4835a76e 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -632,3 +632,29 @@ uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const { } return 0; } + +void ModelOverlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::addMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->addMaterial(material, shapeID); + } +} + +void ModelOverlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::removeMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->removeMaterial(material, shapeID); + } +} + +void ModelOverlay::processMaterials() { + assert(_model); + std::lock_guard lock(_materialsLock); + for (auto& shapeMaterialPair : _materials) { + auto material = shapeMaterialPair.second; + while (!material.empty()) { + _model->addMaterial(material.top(), shapeMaterialPair.first); + material.pop(); + } + } +} \ No newline at end of file diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 08c776c426..827f7f2d5b 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -59,6 +59,9 @@ public: void setDrawInFront(bool drawInFront) override; void setDrawHUDLayer(bool drawHUDLayer) override; + void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + protected: Transform evalRenderTransform() override; @@ -110,6 +113,8 @@ private: bool _drawInFrontDirty { false }; bool _drawInHUDDirty { false }; + void processMaterials(); + }; #endif // hifi_ModelOverlay_h diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 3c952b8338..368ed04062 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -235,3 +235,13 @@ QVector qVectorOverlayIDFromScriptValue(const QScriptValue& array) { } return newVector; } + +void Overlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); +} + +void Overlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); +} \ No newline at end of file diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index e9271f3c3f..4cb3f7c84d 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -91,6 +91,9 @@ public: unsigned int getStackOrder() const { return _stackOrder; } void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; } + virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + protected: float updatePulse(); @@ -117,6 +120,9 @@ protected: static const xColor DEFAULT_OVERLAY_COLOR; static const float DEFAULT_ALPHA; + std::unordered_map _materials; + std::mutex _materialsLock; + private: OverlayID _overlayID; // only used for non-3d overlays }; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 86635cd3bf..4cd9bbedd7 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -570,6 +570,7 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc } transaction.resetItem(_renderItemID, avatarPayloadPointer); _skeletonModel->addToScene(scene, transaction); + processMaterials(); for (auto& attachmentModel : _attachmentModels) { attachmentModel->addToScene(scene, transaction); } @@ -761,6 +762,7 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) { _skeletonModel->removeFromScene(scene, transaction); _skeletonModel->addToScene(scene, transaction); + processMaterials(); canTryFade = true; _isAnimatingScale = true; } @@ -1760,3 +1762,31 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const { return DEFAULT_AVATAR_EYE_HEIGHT; } } + +void Avatar::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); + if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { + _skeletonModel->addMaterial(material, shapeID); + } +} + +void Avatar::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); + if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { + _skeletonModel->removeMaterial(material, shapeID); + } +} + +void Avatar::processMaterials() { + assert(_skeletonModel); + std::lock_guard lock(_materialsLock); + for (auto& shapeMaterialPair : _materials) { + auto material = shapeMaterialPair.second; + while (!material.empty()) { + _skeletonModel->addMaterial(material.top(), shapeMaterialPair.first); + material.pop(); + } + } +} \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index c2b404a925..9c355159d8 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -272,6 +272,9 @@ public: virtual void setAvatarEntityDataChanged(bool value) override; + void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + public slots: // FIXME - these should be migrated to use Pose data instead @@ -397,6 +400,11 @@ protected: float _displayNameAlpha { 1.0f }; ThreadSafeValueCache _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT }; + + std::unordered_map _materials; + std::mutex _materialsLock; + + void processMaterials(); }; #endif // hifi_Avatar_h diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index fc6d15cced..13fda28f40 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -1,3 +1,4 @@ set(TARGET_NAME avatars) setup_hifi_library(Network Script) -link_hifi_libraries(shared networking) +include_hifi_library_headers(gpu) +link_hifi_libraries(shared networking graphics) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 74888283df..1bbc8cc1a5 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2558,4 +2558,4 @@ void AvatarEntityMapFromScriptValue(const QScriptValue& object, AvatarEntityMap& value[EntityID] = binaryEntityProperties; } -} +} \ No newline at end of file diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a363fb6d15..b7d594f1dc 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -54,6 +54,8 @@ #include "HeadData.h" #include "PathUtils.h" +#include + using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; using AvatarHash = QHash; @@ -694,6 +696,9 @@ public: bool getIsReplicated() const { return _isReplicated; } + virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID) {} + virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) {} + signals: void displayNameChanged(); void sessionDisplayNameChanged(); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 49ddf111c3..2f92790d18 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -146,6 +146,9 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _entity(entity _needsRenderUpdate = true; emit requestRenderUpdate(); }); + _materials = entity->getMaterials(); + connect(entity.get(), &EntityItem::addMaterialToRenderItem, this, &EntityRenderer::addMaterial); + connect(entity.get(), &EntityItem::removeMaterialFromRenderItem, this, &EntityRenderer::removeMaterial); } EntityRenderer::~EntityRenderer() { } @@ -399,4 +402,14 @@ void EntityRenderer::onAddToScene(const EntityItemPointer& entity) { void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) { entity->deregisterChangeHandler(_changeHandlerId); QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr); +} + +void EntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); +} + +void EntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); } \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index ce5bfb30a4..f58b540aef 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -101,6 +101,10 @@ protected: return result; } +public slots: + virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + signals: void requestRenderUpdate(); @@ -129,6 +133,8 @@ protected: // Only touched on the rendering thread bool _renderUpdateQueued{ false }; + std::unordered_map _materials; + std::mutex _materialsLock; private: // The base class relies on comparing the model transform to the entity transform in order diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 83754c1c16..d541d99c4c 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -15,12 +15,18 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP if (entity->getMaterial() != _drawMaterial) { return true; } + if (entity->getParentID() != _parentID || entity->getClientOnly() != _clientOnly || entity->getOwningAvatarID() != _owningAvatarID) { + return true; + } return false; } void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { withWriteLock([&] { _drawMaterial = entity->getMaterial(); + _parentID = entity->getParentID(); + _clientOnly = entity->getClientOnly(); + _owningAvatarID = entity->getOwningAvatarID(); _renderTransform = getModelTransform(); const float MATERIAL_ENTITY_SCALE = 0.5f; _renderTransform.postScale(MATERIAL_ENTITY_SCALE); @@ -30,7 +36,7 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& ItemKey MaterialEntityRenderer::getKey() { ItemKey::Builder builder; - builder.withTypeShape(); + builder.withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); if (!_visible) { builder.withInvisible(); @@ -215,13 +221,25 @@ void MaterialEntityRenderer::generateMesh() { void MaterialEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderableMaterialEntityItem::render"); Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - batch.setModelTransform(_renderTransform); + // Don't render if our parent is set or our material is null + QUuid parentID; + Transform renderTransform; + graphics::MaterialPointer drawMaterial; + withReadLock([&] { + parentID = _clientOnly ? _owningAvatarID : _parentID; + renderTransform = _renderTransform; + drawMaterial = _drawMaterial; + }); + if (!parentID.isNull() || !drawMaterial) { + return; + } + + batch.setModelTransform(renderTransform); // bind the material - args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_shapePipeline->bindMaterial(drawMaterial, batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index 166ad762cc..af8cef9351 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -31,6 +31,9 @@ private: ItemKey getKey() override; ShapeKey getShapeKey() override; + QUuid _parentID; + bool _clientOnly; + QUuid _owningAvatarID; Transform _renderTransform; std::shared_ptr _drawMaterial; @@ -47,7 +50,7 @@ private: static void addVertex(std::vector& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv); const int SLICES = 15; const int STACKS = 9; - const float M_PI_TIMES_2 = 2.0f * M_PI; + const float M_PI_TIMES_2 = 2.0f * (float)M_PI; }; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 137203f475..739ccd9738 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1380,6 +1380,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce auto entityRenderer = static_cast(&data); entityRenderer->setSubRenderItemIDs(newRenderItemIDs); }); + processMaterials(); } } @@ -1466,3 +1467,28 @@ void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStr } } +void ModelEntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::addMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->addMaterial(material, shapeID); + } +} + +void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::removeMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->removeMaterial(material, shapeID); + } +} + +void ModelEntityRenderer::processMaterials() { + assert(_model); + std::lock_guard lock(_materialsLock); + for (auto& shapeMaterialPair : _materials) { + auto material = shapeMaterialPair.second; + while (!material.empty()) { + _model->addMaterial(material.top(), shapeMaterialPair.first); + material.pop(); + } + } +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 33fc9910a0..75c6639902 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -138,10 +138,15 @@ namespace render { namespace entities { class ModelEntityRenderer : public TypedEntityRenderer { using Parent = TypedEntityRenderer; friend class EntityRenderer; + Q_OBJECT public: ModelEntityRenderer(const EntityItemPointer& entity); +public slots: + void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + protected: virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override; virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override; @@ -194,6 +199,8 @@ private: uint64_t _lastAnimated { 0 }; render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() }; + + void processMaterials(); }; } } // namespace diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index cdee2c5ec9..8163b14608 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -54,8 +54,7 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin if (_lastUserData != entity->getUserData()) { return true; } - glm::vec4 newColor(toGlm(entity->getXColor()), entity->getLocalRenderAlpha()); - if (newColor != _color) { + if (_material != entity->getMaterial()) { return true; } @@ -78,7 +77,9 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _procedural.setProceduralData(ProceduralData::parse(_lastUserData)); } - _color = vec4(toGlm(entity->getXColor()), entity->getLocalRenderAlpha()); + removeMaterial(_material, 0); + _material = entity->getMaterial(); + addMaterial(_material, 0); _shape = entity->getShape(); _position = entity->getWorldPosition(); @@ -112,14 +113,13 @@ bool ShapeEntityRenderer::isTransparent() const { return Parent::isTransparent(); } - - void ShapeEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderableShapeEntityItem::render"); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; + std::shared_ptr mat; auto geometryCache = DependencyManager::get(); GeometryCache::Shape geometryShape; bool proceduralRender = false; @@ -127,15 +127,22 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { withReadLock([&] { geometryShape = geometryCache->getShapeForEntityShape(_shape); batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation - outColor = _color; - if (_procedural.isReady()) { - _procedural.prepare(batch, _position, _dimensions, _orientation); - outColor = _procedural.getColor(_color); - outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; - proceduralRender = true; + mat = _materials[0].top(); + if (mat) { + outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity()); + if (_procedural.isReady()) { + _procedural.prepare(batch, _position, _dimensions, _orientation); + outColor = _procedural.getColor(outColor); + outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; + proceduralRender = true; + } } }); + if (!mat) { + return; + } + if (proceduralRender) { if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { geometryCache->renderWireShape(batch, geometryShape, outColor); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index 433cb41ad2..c913544255 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -34,7 +34,7 @@ private: QString _lastUserData; Transform _renderTransform; entity::Shape _shape { entity::Sphere }; - glm::vec4 _color; + std::shared_ptr _material; glm::vec3 _position; glm::vec3 _dimensions; glm::quat _orientation; diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index cbd0ad7839..347d40ea49 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -93,7 +93,7 @@ bool DeleteEntityOperator::preRecursion(const OctreeElementPointer& element) { // and we can stop searching. if (entityTreeElement == details.containingElement) { EntityItemPointer theEntity = details.entity; - bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element + bool entityDeleted = entityTreeElement->removeEntityItem(theEntity, true); // remove it from the element assert(entityDeleted); (void)entityDeleted; // quite warning _tree->clearEntityMapEntry(details.entity->getEntityItemID()); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ed13a46414..43510864ba 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -60,14 +60,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : } EntityItem::~EntityItem() { - // clear out any left-over actions - EntityTreeElementPointer element = _element; // use local copy of _element for logic below - EntityTreePointer entityTree = element ? element->getTree() : nullptr; - EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr; - if (simulation) { - clearActions(simulation); - } - // these pointers MUST be correct at delete, else we probably have a dangling backpointer // to this EntityItem in the corresponding data structure. assert(!_simulated); @@ -2937,3 +2929,34 @@ void EntityItem::retrieveMarketplacePublicKey() { networkReply->deleteLater(); }); } + +void EntityItem::preDelete() { + // clear out any left-over actions + EntityTreeElementPointer element = _element; // use local copy of _element for logic below + EntityTreePointer entityTree = element ? element->getTree() : nullptr; + EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr; + if (simulation) { + clearActions(simulation); + } +} + +void EntityItem::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); + emit addMaterialToRenderItem(material, shapeID); +} + +void EntityItem::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); + emit removeMaterialFromRenderItem(material, shapeID); +} + +std::unordered_map EntityItem::getMaterials() { + std::unordered_map toReturn; + { + std::lock_guard lock(_materialsLock); + toReturn = _materials; + } + return toReturn; +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5f84bcc311..b2804a2e86 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -36,6 +36,8 @@ #include "SimulationFlags.h" #include "EntityDynamicInterface.h" +#include "graphics/Material.h" + class EntitySimulation; class EntityTreeElement; class EntityTreeElementExtraEncodeData; @@ -49,7 +51,6 @@ typedef std::shared_ptr EntityTreeElementPointer; using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr; - #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() override { }; @@ -443,10 +444,10 @@ public: void scriptHasUnloaded() { _loadedScript = ""; _loadedScriptTimestamp = 0; } bool getClientOnly() const { return _clientOnly; } - void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; } + virtual void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; } // if this entity is client-only, which avatar is it associated with? QUuid getOwningAvatarID() const { return _owningAvatarID; } - void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; } + virtual void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; } virtual bool wantsHandControllerPointerEvents() const { return false; } virtual bool wantsKeyboardFocus() const { return false; } @@ -477,8 +478,18 @@ public: void setCauterized(bool value) { _cauterized = value; } bool getCauterized() const { return _cauterized; } + virtual void postAdd() {} + virtual void preDelete(); + virtual void postParentFixup() {} + + void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + std::unordered_map getMaterials(); + signals: void requestRenderUpdate(); + void addMaterialToRenderItem(graphics::MaterialPointer material, quint16 shapeID); + void removeMaterialFromRenderItem(graphics::MaterialPointer material, quint16 shapeID); protected: QHash _changeHandlers; @@ -631,6 +642,11 @@ protected: quint64 _lastUpdatedQueryAACubeTimestamp { 0 }; bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera + +private: + std::unordered_map _materials; + std::mutex _materialsLock; + }; #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 965252abf4..19aa6990db 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -360,7 +360,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); CHECK_PROPERTY_CHANGE(PROP_PARENT_SHAPE_ID, shapeID); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BOUNDS, materialBounds); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_POS, materialPos); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_SCALE, materialScale); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_ROT, materialRot); // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); @@ -664,7 +666,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BOUNDS, materialBounds); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_POS, materialPos); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_SCALE, materialScale); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_ROT, materialRot); } if (!skipDefaults && !strictSemantics) { @@ -801,11 +805,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); - COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(materialMode, MaterialMode, setMaterialMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(materialMode, MaterialMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor); - COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, int, setPriority); - COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, int, setShapeID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialBounds, glmVec4, setMaterialBounds); + COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority); + COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, quint16, setShapeID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialPos, glmVec2, setMaterialPos); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialScale, glmVec2, setMaterialScale); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialRot, float, setMaterialRot); // Certifiable Properties COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); @@ -1163,9 +1169,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, quint16); + ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_ROT, MaterialRot, materialRot, float); // Certifiable Properties ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); @@ -1557,7 +1565,9 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, properties.getBlendFactor()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, properties.getShapeID()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, properties.getMaterialBounds()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, properties.getMaterialPos()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, properties.getMaterialScale()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, properties.getMaterialRot()); } APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); @@ -1921,9 +1931,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BOUNDS, glmVec4, setMaterialBounds); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_POS, glmVec2, setMaterialPos); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_SCALE, glmVec2, setMaterialScale); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_ROT, float, setMaterialRot); } READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); @@ -2104,7 +2116,9 @@ void EntityItemProperties::markAllChanged() { _blendFactorChanged = true; _priorityChanged = true; _shapeIDChanged = true; - _materialBoundsChanged = true; + _materialPosChanged = true; + _materialScaleChanged = true; + _materialRotChanged = true; // Certifiable Properties _itemNameChanged = true; @@ -2444,8 +2458,14 @@ QList EntityItemProperties::listChangedProperties() { if (shapeIDChanged()) { out += "shapeID"; } - if (materialBoundsChanged()) { - out += "materialBounds"; + if (materialPosChanged()) { + out += "materialPos"; + } + if (materialScaleChanged()) { + out += "materialScale"; + } + if (materialRotChanged()) { + out += "materialRot"; } // Certifiable Properties diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 9bedff41df..a8a79b6303 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -225,9 +225,11 @@ public: DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, ""); DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode, UV); DEFINE_PROPERTY_REF(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float, 1.0f); - DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t, 0); - DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t, 0); - DEFINE_PROPERTY_REF(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4, glm::vec4(0, 0, 1, 1)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, quint16, 0); + DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16, 0); + DEFINE_PROPERTY_REF(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2, glm::vec2(0, 0)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2, glm::vec2(1, 1)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_ROT, MaterialRot, materialRot, float, 0); // Certifiable Properties - related to Proof of Purchase certificates DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 2609fe237d..51a23b6867 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -101,6 +101,7 @@ changedProperties += P; \ } +inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec2& v) { return vec2toScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3toScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); } @@ -183,8 +184,8 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu properties.setProperty(#P, V); \ } +typedef glm::vec2 glmVec2; typedef glm::vec3 glmVec3; -typedef glm::vec4 glmVec4; typedef glm::quat glmQuat; typedef QVector qVectorVec3; typedef QVector qVectorQuat; @@ -222,6 +223,23 @@ inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& return QByteArray::fromBase64(b64.toUtf8()); } +inline glmVec2 glmVec2_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = false; /// assume it can't be converted + QScriptValue x = v.property("x"); + QScriptValue y = v.property("y"); + if (x.isValid() && y.isValid()) { + glm::vec4 newValue(0); + newValue.x = x.toVariant().toFloat(); + newValue.y = y.toVariant().toFloat(); + isValid = !glm::isnan(newValue.x) && + !glm::isnan(newValue.y); + if (isValid) { + return newValue; + } + } + return glm::vec2(0); +} + inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = false; /// assume it can't be converted QScriptValue x = v.property("x"); @@ -242,29 +260,6 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal return glm::vec3(0); } -inline glmVec4 glmVec4_convertFromScriptValue(const QScriptValue& v, bool& isValid) { - isValid = false; /// assume it can't be converted - QScriptValue x = v.property("x"); - QScriptValue y = v.property("y"); - QScriptValue z = v.property("z"); - QScriptValue w = v.property("w"); - if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { - glm::vec4 newValue(0); - newValue.x = x.toVariant().toFloat(); - newValue.y = y.toVariant().toFloat(); - newValue.z = z.toVariant().toFloat(); - newValue.w = w.toVariant().toFloat(); - isValid = !glm::isnan(newValue.x) && - !glm::isnan(newValue.y) && - !glm::isnan(newValue.z) && - !glm::isnan(newValue.w); - if (isValid) { - return newValue; - } - } - return glm::vec4(0); -} - inline AACube AACube_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; AACube result; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index bd573423a3..17ebddbe9d 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -232,7 +232,9 @@ enum EntityPropertyList { PROP_MATERIAL_BLEND_FACTOR, PROP_MATERIAL_PRIORITY, PROP_PARENT_SHAPE_ID, - PROP_MATERIAL_BOUNDS, + PROP_MATERIAL_POS, + PROP_MATERIAL_SCALE, + PROP_MATERIAL_ROT, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bf29f3bec9..775b3bd2f7 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1732,15 +1732,19 @@ void EntityTree::fixupNeedsParentFixups() { } }); entity->locationChanged(true); - } else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) { - // this is a child of an avatar, which the entity server will never have - // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. - if (!_childrenOfAvatars.contains(entity->getParentID())) { - _childrenOfAvatars[entity->getParentID()] = QSet(); + entity->postParentFixup(); + } else if (_avatarIDs.contains(entity->getParentID())) { + if (getIsServer()) { + // this is a child of an avatar, which the entity server will never have + // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. + if (!_childrenOfAvatars.contains(entity->getParentID())) { + _childrenOfAvatars[entity->getParentID()] = QSet(); + } + _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); } - _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); doMove = true; iter.remove(); // and pull it out of the list + entity->postParentFixup(); } if (queryAACubeSuccess && doMove) { @@ -2378,3 +2382,35 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const { return entity->getJointNames(); } +std::function EntityTree::_addMaterialToAvatarOperator = nullptr; +std::function EntityTree::_removeMaterialFromAvatarOperator = nullptr; +std::function EntityTree::_addMaterialToOverlayOperator = nullptr; +std::function EntityTree::_removeMaterialFromOverlayOperator = nullptr; + +bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + if (_addMaterialToAvatarOperator) { + return _addMaterialToAvatarOperator(avatarID, material, shapeID); + } + return false; +} + +bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + if (_removeMaterialFromAvatarOperator) { + return _removeMaterialFromAvatarOperator(avatarID, material, shapeID); + } + return false; +} + +bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + if (_addMaterialToOverlayOperator) { + return _addMaterialToOverlayOperator(overlayID, material, shapeID); + } + return false; +} + +bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + if (_removeMaterialFromOverlayOperator) { + return _removeMaterialFromOverlayOperator(overlayID, material, shapeID); + } + return false; +} \ No newline at end of file diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8cb89d6493..a02ce900ff 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -280,6 +280,16 @@ public: void setMyAvatar(std::shared_ptr myAvatar) { _myAvatar = myAvatar; } + static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } + static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } + static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); + static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); + + static void setAddMaterialToOverlayOperator(std::function addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; } + static void setRemoveMaterialFromOverlayOperator(std::function removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; } + static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); + static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); + signals: void deletingEntity(const EntityItemID& entityID); void deletingEntityPointer(EntityItem* entityID); @@ -387,6 +397,11 @@ private: void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation); std::shared_ptr _myAvatar{ nullptr }; + + static std::function _addMaterialToAvatarOperator; + static std::function _removeMaterialFromAvatarOperator; + static std::function _addMaterialToOverlayOperator; + static std::function _removeMaterialFromOverlayOperator; }; #endif // hifi_EntityTree_h diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index c9e1ecc3f1..980ed1c104 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -896,6 +896,7 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI void EntityTreeElement::cleanupEntities() { withWriteLock([&] { foreach(EntityItemPointer entity, _entityItems) { + entity->preDelete(); // NOTE: only EntityTreeElement should ever be changing the value of entity->_element // NOTE: We explicitly don't delete the EntityItem here because since we only // access it by smart pointers, when we remove it from the _entityItems @@ -907,26 +908,10 @@ void EntityTreeElement::cleanupEntities() { bumpChangedContent(); } -bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { - bool foundEntity = false; - withWriteLock([&] { - uint16_t numberOfEntities = _entityItems.size(); - for (uint16_t i = 0; i < numberOfEntities; i++) { - EntityItemPointer& entity = _entityItems[i]; - if (entity->getEntityItemID() == id) { - foundEntity = true; - // NOTE: only EntityTreeElement should ever be changing the value of entity->_element - entity->_element = NULL; - _entityItems.removeAt(i); - bumpChangedContent(); - break; - } - } - }); - return foundEntity; -} - -bool EntityTreeElement::removeEntityItem(EntityItemPointer entity) { +bool EntityTreeElement::removeEntityItem(EntityItemPointer entity, bool deletion) { + if (deletion) { + entity->preDelete(); + } int numEntries = 0; withWriteLock([&] { numEntries = _entityItems.removeAll(entity); @@ -955,6 +940,7 @@ void EntityTreeElement::addEntityItem(EntityItemPointer entity) { }); bumpChangedContent(); entity->_element = getThisPointer(); + entity->postAdd(); } // will average a "common reduced LOD view" from the the child elements... diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index a524904c71..2313bde0c4 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -210,8 +210,7 @@ public: void getEntitiesInside(const AACube& box, QVector& foundEntities); void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities - bool removeEntityWithEntityItemID(const EntityItemID& id); - bool removeEntityItem(EntityItemPointer entity); + bool removeEntityItem(EntityItemPointer entity, bool deletion = false); bool containsEntityBounds(EntityItemPointer entity) const; bool bestFitEntityBounds(EntityItemPointer entity) const; diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index bbcc691879..7026da117c 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -16,6 +16,9 @@ EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); + // When you reload content, setProperties doesn't have any of the propertiesChanged flags set, so it won't trigger a material add + entity->removeMaterial(); + entity->applyMaterial(); return entity; } @@ -31,7 +34,9 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendFactor, getBlendFactor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeID, getShapeID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialBounds, getMaterialBounds); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialPos, getMaterialPos); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialScale, getMaterialScale); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialRot, getMaterialRot); return properties; } @@ -43,7 +48,9 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeID, setShapeID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialBounds, setMaterialBounds); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialPos, setMaterialPos); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialScale, setMaterialScale); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialRot, setMaterialRot); if (somethingChanged) { bool wantDebug = false; @@ -202,9 +209,11 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); - READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); - READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); - READ_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, glm::vec4, setMaterialBounds); + READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, quint16, setPriority); + READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY(PROP_MATERIAL_POS, glm::vec2, setMaterialPos); + READ_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, glm::vec2, setMaterialScale); + READ_ENTITY_PROPERTY(PROP_MATERIAL_ROT, float, setMaterialRot); return bytesRead; } @@ -218,7 +227,9 @@ EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParam requestedProperties += PROP_MATERIAL_BLEND_FACTOR; requestedProperties += PROP_MATERIAL_PRIORITY; requestedProperties += PROP_PARENT_SHAPE_ID; - requestedProperties += PROP_MATERIAL_BOUNDS; + requestedProperties += PROP_MATERIAL_POS; + requestedProperties += PROP_MATERIAL_SCALE; + requestedProperties += PROP_MATERIAL_ROT; return requestedProperties; } @@ -234,9 +245,11 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, (uint32_t)getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, (uint32_t)getShapeID()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, getMaterialBounds()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, getMaterialPos()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, getMaterialScale()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, getMaterialRot()); } void MaterialEntityItem::debugDump() const { @@ -249,7 +262,9 @@ void MaterialEntityItem::debugDump() const { qCDebug(entities) << " blend factor:" << _blendFactor; qCDebug(entities) << " priority:" << _priority; qCDebug(entities) << " parent shape ID:" << _shapeID; - qCDebug(entities) << " material bounds:" << _materialBounds; + qCDebug(entities) << " material pos:" << _materialPos; + qCDebug(entities) << " material scale:" << _materialRot; + qCDebug(entities) << " material rot:" << _materialScale; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); @@ -269,30 +284,38 @@ std::shared_ptr MaterialEntityItem::getMaterial() const { } } -void MaterialEntityItem::setMaterialURL(const QString& materialURLString) { - if (materialURLString.startsWith("userData")) { - QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); - _materials.clear(); - _materialNames.clear(); - if (!materialJSON.isNull()) { - if (materialJSON.isArray()) { - QJsonArray materials = materialJSON.array(); - for (auto& material : materials) { - if (!material.isNull() && material.isObject()) { - parseJSONMaterial(material.toObject()); +void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool userDataChanged) { + bool usingUserData = materialURLString.startsWith("userData"); + if (_materialURL != materialURLString || (usingUserData && userDataChanged)) { + removeMaterial(); + _materialURL = materialURLString; + + if (usingUserData) { + QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); + _materials.clear(); + _materialNames.clear(); + if (!materialJSON.isNull()) { + if (materialJSON.isArray()) { + QJsonArray materials = materialJSON.array(); + for (auto material : materials) { + if (!material.isNull() && material.isObject()) { + parseJSONMaterial(material.toObject()); + } } + } else if (materialJSON.isObject()) { + parseJSONMaterial(materialJSON.object()); } - } else if (materialJSON.isObject()) { - parseJSONMaterial(materialJSON.object()); } + } else { + // get material via network request } + + // TODO: if URL ends with ?string, try to set _currentMaterialName = string + + // Since our JSON changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(_currentMaterialName); + applyMaterial(); } - _materialURL = materialURLString; - - // TODO: if URL ends with ?string, set _currentMaterialName = string - - // Since our JSON changed, the current name might not be valid anymore, so we need to update - setCurrentMaterialName(_currentMaterialName); } void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialName) { @@ -300,14 +323,176 @@ void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialNa if (material != _materials.end()) { _currentMaterialName = currentMaterialName; } else if (_materialNames.size() > 0) { - setCurrentMaterialName(_materialNames[0]); + _currentMaterialName = _materialNames[0]; } } void MaterialEntityItem::setUserData(const QString& userData) { - EntityItem::setUserData(userData); - if (_materialURL.startsWith("userData")) { - // Trigger material update when user data changes - setMaterialURL(_materialURL); + if (_userData != userData) { + EntityItem::setUserData(userData); + if (_materialURL.startsWith("userData")) { + // Trigger material update when user data changes + setMaterialURL(_materialURL, true); + } } +} + +void MaterialEntityItem::setMaterialPos(const glm::vec2& materialPos) { + if (_materialPos != materialPos) { + removeMaterial(); + _materialPos = materialPos; + applyMaterial(); + } +} + +void MaterialEntityItem::setMaterialScale(const glm::vec2& materialScale) { + if (_materialScale != materialScale) { + removeMaterial(); + _materialScale = materialScale; + applyMaterial(); + } +} + +void MaterialEntityItem::setMaterialRot(const float& materialRot) { + if (_materialRot != materialRot) { + removeMaterial(); + _materialRot = materialRot; + applyMaterial(); + } +} + +void MaterialEntityItem::setBlendFactor(float blendFactor) { + if (_blendFactor != blendFactor) { + removeMaterial(); + _blendFactor = blendFactor; + applyMaterial(); + } +} + +void MaterialEntityItem::setPriority(quint16 priority) { + if (_priority != priority) { + removeMaterial(); + _priority = priority; + applyMaterial(); + } +} + +void MaterialEntityItem::setShapeID(quint16 shapeID) { + if (_shapeID != shapeID) { + removeMaterial(); + _shapeID = shapeID; + applyMaterial(); + } +} + +void MaterialEntityItem::setParentID(const QUuid& parentID) { + if (getParentID() != parentID) { + removeMaterial(); + EntityItem::setParentID(parentID); + applyMaterial(); + } +} + +void MaterialEntityItem::setClientOnly(bool clientOnly) { + if (getClientOnly() != clientOnly) { + removeMaterial(); + EntityItem::setClientOnly(clientOnly); + applyMaterial(); + } +} + +void MaterialEntityItem::setOwningAvatarID(const QUuid& owningAvatarID) { + if (getOwningAvatarID() != owningAvatarID) { + removeMaterial(); + EntityItem::setOwningAvatarID(owningAvatarID); + applyMaterial(); + } +} + +void MaterialEntityItem::removeMaterial() { + graphics::MaterialPointer material = getMaterial(); + QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID(); + if (!material || parentID.isNull()) { + return; + } + + // Our parent could be an entity, an avatar, or an overlay + EntityTreePointer tree = getTree(); + if (tree) { + EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); + if (entity) { + entity->removeMaterial(material, getShapeID()); + return; + } + } + + if (EntityTree::removeMaterialFromAvatar(parentID, material, getShapeID())) { + return; + } + + if (EntityTree::removeMaterialFromOverlay(parentID, material, getShapeID())) { + return; + } + + // if a remove fails, our parent is gone, so we don't need to retry +} + +void MaterialEntityItem::applyMaterial() { + _retryApply = false; + graphics::MaterialPointer material = getMaterial(); + QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID(); + if (!material || parentID.isNull()) { + return; + } + Transform textureTransform; + textureTransform.setTranslation(glm::vec3(_materialPos, 0)); + textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialRot))); + textureTransform.setScale(glm::vec3(_materialScale, 1)); + material->setTextureTransforms(textureTransform); + material->setBlendFactor(getBlendFactor()); + material->setPriority(getPriority()); + + // Our parent could be an entity, an avatar, or an overlay + EntityTreePointer tree = getTree(); + if (tree) { + EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); + if (entity) { + entity->addMaterial(material, getShapeID()); + return; + } + } + + if (EntityTree::addMaterialToAvatar(parentID, material, getShapeID())) { + return; + } + + if (EntityTree::addMaterialToOverlay(parentID, material, getShapeID())) { + return; + } + + // if we've reached this point, we couldn't find our parent, so we need to try again later + _retryApply = true; +} + +void MaterialEntityItem::postAdd() { + removeMaterial(); + applyMaterial(); +} + +void MaterialEntityItem::preDelete() { + EntityItem::preDelete(); + removeMaterial(); +} + +void MaterialEntityItem::postParentFixup() { + removeMaterial(); + applyMaterial(); +} + +void MaterialEntityItem::update(const quint64& now) { + if (_retryApply) { + applyMaterial(); + } + + EntityItem::update(now); } \ No newline at end of file diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index 80fe226b68..40137acf22 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -23,6 +23,9 @@ public: ALLOW_INSTANTIATION // This class can be instantiated + void update(const quint64& now) override; + bool needsToCallUpdate() const override { return true; } + // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; @@ -49,7 +52,7 @@ public: virtual void setUnscaledDimensions(const glm::vec3& value) override; QString getMaterialURL() const { return _materialURL; } - void setMaterialURL(const QString& materialURLString); + void setMaterialURL(const QString& materialURLString, bool userDataChanged = false); QString getCurrentMaterialName() const { return _currentMaterialName; } void setCurrentMaterialName(const QString& currentMaterialName); @@ -58,33 +61,51 @@ public: void setMaterialMode(MaterialMode mode) { _materialMode = mode; } float getBlendFactor() const { return _blendFactor; } - void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } + void setBlendFactor(float blendFactor); - int getPriority() const { return _priority; } - void setPriority(int priority) { _priority = priority; } + quint16 getPriority() const { return _priority; } + void setPriority(quint16 priority); - int getShapeID() const { return _shapeID; } - void setShapeID(int shapeID) { _shapeID = shapeID; } + quint16 getShapeID() const { return _shapeID; } + void setShapeID(quint16 shapeID); - glm::vec4 getMaterialBounds() const { return _materialBounds; } - void setMaterialBounds(const glm::vec4& materialBounds) { _materialBounds = materialBounds; } + glm::vec2 getMaterialPos() const { return _materialPos; } + void setMaterialPos(const glm::vec2& materialPos); + glm::vec2 getMaterialScale() const { return _materialScale; } + void setMaterialScale(const glm::vec2& materialScale); + float getMaterialRot() const { return _materialRot; } + void setMaterialRot(const float& materialRot); std::shared_ptr getMaterial() const; void setUserData(const QString& userData) override; + void setParentID(const QUuid& parentID) override; + void setClientOnly(bool clientOnly) override; + void setOwningAvatarID(const QUuid& owningAvatarID) override; + + void applyMaterial(); + void removeMaterial(); + + void postAdd() override; + void preDelete() override; + void postParentFixup() override; private: QString _materialURL; MaterialMode _materialMode { UV }; float _blendFactor { 1.0f }; - int _priority { 0 }; - int _shapeID { 0 }; - glm::vec4 _materialBounds { 0, 0, 1, 1 }; + quint16 _priority { 0 }; + quint16 _shapeID { 0 }; + glm::vec2 _materialPos { 0, 0 }; + glm::vec2 _materialScale { 1, 1 }; + float _materialRot { 0 }; QHash> _materials; std::vector _materialNames; QString _currentMaterialName; + bool _retryApply { false }; + void parseJSONMaterial(const QJsonObject& materialJSON); static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 5d33e4c047..bec7bc1906 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -721,4 +721,4 @@ bool ModelEntityItem::isAnimatingSomething() const { _animationProperties.getRunning() && (_animationProperties.getFPS() != 0.0f); }); -} +} \ No newline at end of file diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index cbcfcaaa1d..2425208a87 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -85,6 +85,7 @@ EntityItemPointer ShapeEntityItem::sphereFactory(const EntityItemID& entityID, c ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Shape; _volumeMultiplier *= PI / 6.0f; + _material = std::make_shared(); } EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { @@ -184,6 +185,7 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit void ShapeEntityItem::setColor(const rgbColor& value) { memcpy(_color, value, sizeof(rgbColor)); + _material->setAlbedo(glm::vec3(_color[0], _color[1], _color[2]) / 255.0f); } xColor ShapeEntityItem::getXColor() const { @@ -204,6 +206,11 @@ void ShapeEntityItem::setColor(const QColor& value) { setAlpha(value.alpha()); } +void ShapeEntityItem::setAlpha(float alpha) { + _alpha = alpha; + _material->setOpacity(alpha); +} + void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { const float MAX_FLAT_DIMENSION = 0.0001f; if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) { diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 84ce1ce57e..7ad1b3c1c2 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -75,7 +75,7 @@ public: void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); } float getAlpha() const { return _alpha; }; - void setAlpha(float alpha) { _alpha = alpha; } + void setAlpha(float alpha); const rgbColor& getColor() const { return _color; } void setColor(const rgbColor& value); @@ -101,6 +101,8 @@ public: virtual void computeShapeInfo(ShapeInfo& info) override; virtual ShapeType getShapeType() const override; + std::shared_ptr getMaterial() { return _material; } + protected: float _alpha { 1 }; @@ -111,6 +113,8 @@ protected: //! prior functionality where new or unsupported shapes are treated as //! ellipsoids. ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID }; + + std::shared_ptr _material; }; #endif // hifi_ShapeEntityItem_h diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index 6cc6b8472f..7c66c8ab07 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -12,9 +12,13 @@ #include "TextureMap.h" +#include + using namespace graphics; using namespace gpu; +int materialPointerMetaID = qRegisterMetaType("graphics::MaterialPointer"); + Material::Material() : _key(0), _schemaBuffer(), @@ -221,4 +225,15 @@ bool Material::calculateMaterialInfo() const { _hasCalculatedTextureInfo = allTextures; } return _hasCalculatedTextureInfo; +} + +void Material::setTextureTransforms(const Transform& transform) { + for (auto &textureMapItem : _textureMaps) { + if (textureMapItem.second) { + textureMapItem.second->setTextureTransform(transform); + } + } + for (int i = 0; i < NUM_TEXCOORD_TRANSFORMS; i++) { + _texMapArrayBuffer.edit()._texcoordTransforms[i] = transform.getMatrix(); + } } \ No newline at end of file diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index cfbfaa61ea..b9eb881ed8 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -15,11 +15,14 @@ #include #include +#include #include #include +class Transform; + namespace graphics { class TextureMap; @@ -351,6 +354,14 @@ public: size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } + void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } + float getBlendFactor() { return _blendFactor; } + + void setPriority(quint16 priority) { _priority = priority; } + quint16 getPriority() { return _priority; } + + void setTextureTransforms(const Transform& transform); + private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; @@ -364,10 +375,35 @@ private: mutable bool _hasCalculatedTextureInfo { false }; bool calculateMaterialInfo() const; + float _blendFactor { 1.0f }; + quint16 _priority { 0 }; }; typedef std::shared_ptr< Material > MaterialPointer; +Q_DECLARE_METATYPE(MaterialPointer) + +class MaterialCompare { +public: + bool operator() (MaterialPointer left, MaterialPointer right) { + return left->getPriority() < right->getPriority(); + } +}; + +class MultiMaterial : public std::priority_queue, MaterialCompare> { +public: + bool remove(const MaterialPointer& value) { + auto it = std::find(c.begin(), c.end(), value); + if (it != c.end()) { + c.erase(it); + std::make_heap(c.begin(), c.end(), comp); + return true; + } else { + return false; + } + } +}; + }; #endif diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 1fe3648838..32deba3687 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -549,7 +549,6 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, im auto map = std::make_shared(); if (texture) { map->setTextureSource(texture->_textureSource); - emit textureFinished(); } return map; @@ -728,6 +727,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { if (!occlusionName.isEmpty()) { auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl(); + // FIXME: we need to handle the occlusion map transform here auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); setTextureMap(MapChannel::OCCLUSION_MAP, map); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 575f94f9bf..bbb00d72eb 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -156,8 +156,7 @@ private: virtual ~ModelCache() = default; }; -class NetworkMaterial : public QObject, public graphics::Material { - Q_OBJECT +class NetworkMaterial : public graphics::Material { public: using MapChannel = graphics::Material::MapChannel; @@ -174,9 +173,6 @@ public: void setScatteringMap(const QString& url); void setLightmapMap(const QString& url); -signals: - void textureFinished(); - protected: friend class Geometry; diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index a2aad33058..7108f9a4e4 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -381,6 +381,17 @@ bool OctreePacketData::appendValue(float value) { return success; } +bool OctreePacketData::appendValue(const glm::vec2& value) { + const unsigned char* data = (const unsigned char*)&value; + int length = sizeof(value); + bool success = append(data, length); + if (success) { + _bytesOfValues += length; + _totalBytesOfValues += length; + } + return success; +} + bool OctreePacketData::appendValue(const glm::vec3& value) { const unsigned char* data = (const unsigned char*)&value; int length = sizeof(value); diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 7f8eb49101..85100ec177 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -164,6 +164,9 @@ public: /// appends a float value to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(float value); + /// appends a vec2 to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const glm::vec2& value); + /// appends a non-position vector to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const glm::vec3& value); @@ -250,8 +253,8 @@ public: static quint64 getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color static int unpackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } - static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec4& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index b80327cf14..d24843c87d 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -47,7 +47,7 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, graphics::MaterialPointer material) { updateMeshPart(mesh, partIndex); - updateMaterial(material); + addMaterial(material); } void MeshPartPayload::updateMeshPart(const std::shared_ptr& drawMesh, int partIndex) { @@ -67,8 +67,12 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor _worldBound.transform(_drawTransform); } -void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) { - _drawMaterial = drawMaterial; +void MeshPartPayload::addMaterial(graphics::MaterialPointer material) { + _drawMaterials.push(material); +} + +void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) { + _drawMaterials.remove(material); } void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) { @@ -85,8 +89,8 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) builder.withLayered(); } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + auto matKey = _drawMaterials.top()->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); } @@ -105,8 +109,8 @@ Item::Bound MeshPartPayload::getBound() const { ShapeKey MeshPartPayload::getShapeKey() const { graphics::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + drawMaterialKey = _drawMaterials.top()->getKey(); } ShapeKey::Builder builder; @@ -160,7 +164,7 @@ void MeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_shapePipeline->bindMaterial(_drawMaterials.top(), batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! @@ -252,7 +256,7 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) { auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID); if (networkMaterial) { - _drawMaterial = networkMaterial; + addMaterial(networkMaterial); } } @@ -298,8 +302,8 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag builder.withDeformed(); } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + auto matKey = _drawMaterials.top()->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); } @@ -329,8 +333,8 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe } graphics::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + drawMaterialKey = _drawMaterials.top()->getKey(); } bool isTranslucent = drawMaterialKey.isTranslucent(); @@ -411,7 +415,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_shapePipeline->bindMaterial(_drawMaterials.top(), batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index b9ae47fb6a..e6893f1ea7 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -39,8 +39,6 @@ public: virtual void notifyLocationChanged() {} void updateTransform(const Transform& transform, const Transform& offsetTransform); - virtual void updateMaterial(graphics::MaterialPointer drawMaterial); - // Render Item interface virtual render::ItemKey getKey() const; virtual render::Item::Bound getBound() const; @@ -63,13 +61,16 @@ public: mutable graphics::Box _worldBound; std::shared_ptr _drawMesh; - std::shared_ptr _drawMaterial; + graphics::MultiMaterial _drawMaterials; graphics::Mesh::Part _drawPart; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } - size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; } - int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; } - bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; } + size_t getMaterialTextureSize() { return _drawMaterials.top() ? _drawMaterials.top()->getTextureSize() : 0; } + int getMaterialTextureCount() { return _drawMaterials.top() ? _drawMaterials.top()->getTextureCount() : 0; } + bool hasTextureInfo() const { return _drawMaterials.top() ? _drawMaterials.top()->hasTextureInfo() : false; } + + void addMaterial(graphics::MaterialPointer material); + void removeMaterial(graphics::MaterialPointer material); protected: render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b9ccc28c01..805995edfb 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1524,6 +1524,50 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } +void Model::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + render::Transaction transaction; + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.addMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); + } +} + +void Model::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + render::Transaction transaction; + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.removeMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); + } +} + class CollisionRenderGeometry : public Geometry { public: CollisionRenderGeometry(graphics::MeshPointer mesh) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index ca0904f334..80067aff2a 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -318,6 +318,9 @@ public: void scaleToFit(); + void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + public slots: void loadURLFinished(bool success); diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 1763713831..6196a4c5d4 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -342,7 +342,7 @@ var toolBar = (function () { var buttonHandlers = {}; // only used to tablet mode - function addButton(name, image, handler) { + function addButton(name, handler) { buttonHandlers[name] = handler; } @@ -399,7 +399,7 @@ var toolBar = (function () { function handleNewMaterialDialogResult(result) { if (result) { - var json = result.textInput; + var materialURL = result.textInput; var materialMode; switch (result.comboBox) { case MATERIAL_MODE_PROJECTED: @@ -409,11 +409,13 @@ var toolBar = (function () { shapeType = "uv"; } - if (json) { + var DEFAULT_LAYERED_MATERIAL_PRIORITY = 1; + if (materialURL) { createNewEntity({ type: "Material", - materialURL: json, - materialMode: materialMode + materialURL: materialURL, + materialMode: materialMode, + priority: DEFAULT_LAYERED_MATERIAL_PRIORITY }); } } @@ -475,32 +477,22 @@ var toolBar = (function () { that.toggle(); }); - addButton("importEntitiesButton", "assets-01.svg", function() { + addButton("importEntitiesButton", function() { Window.browseChanged.connect(onFileOpenChanged); Window.browseAsync("Select Model to Import", "", "*.json"); }); - addButton("openAssetBrowserButton", "assets-01.svg", function() { + addButton("openAssetBrowserButton", function() { Window.showAssetServer(); }); - addButton("newModelButton", "model-01.svg", function () { - - var SHAPE_TYPES = []; - SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision"; - SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model"; - SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes"; - SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons"; - SHAPE_TYPES[SHAPE_TYPE_BOX] = "Box"; - SHAPE_TYPES[SHAPE_TYPE_SPHERE] = "Sphere"; - var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH; - + addButton("newModelButton", function () { // tablet version of new-model dialog var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml"); }); - addButton("newCubeButton", "cube-01.svg", function () { + addButton("newCubeButton", function () { createNewEntity({ type: "Box", dimensions: DEFAULT_DIMENSIONS, @@ -512,7 +504,7 @@ var toolBar = (function () { }); }); - addButton("newSphereButton", "sphere-01.svg", function () { + addButton("newSphereButton", function () { createNewEntity({ type: "Sphere", dimensions: DEFAULT_DIMENSIONS, @@ -524,7 +516,7 @@ var toolBar = (function () { }); }); - addButton("newLightButton", "light-01.svg", function () { + addButton("newLightButton", function () { createNewEntity({ type: "Light", dimensions: DEFAULT_LIGHT_DIMENSIONS, @@ -543,7 +535,7 @@ var toolBar = (function () { }); }); - addButton("newTextButton", "text-01.svg", function () { + addButton("newTextButton", function () { createNewEntity({ type: "Text", dimensions: { @@ -566,7 +558,7 @@ var toolBar = (function () { }); }); - addButton("newWebButton", "web-01.svg", function () { + addButton("newWebButton", function () { createNewEntity({ type: "Web", dimensions: { @@ -578,7 +570,7 @@ var toolBar = (function () { }); }); - addButton("newZoneButton", "zone-01.svg", function () { + addButton("newZoneButton", function () { createNewEntity({ type: "Zone", dimensions: { @@ -589,7 +581,7 @@ var toolBar = (function () { }); }); - addButton("newParticleButton", "particle-01.svg", function () { + addButton("newParticleButton", function () { createNewEntity({ type: "ParticleEffect", isEmitting: true, @@ -642,15 +634,10 @@ var toolBar = (function () { }); }); - addButton("newMaterialButton", "model-01.svg", function () { - var MATERIAL_MODES = []; - MATERIAL_MODES[MATERIAL_MODE_UV] = "UV space material"; - MATERIAL_MODES[MATERIAL_MODE_PROJECTED] = "3D projected material"; - var MATERIAL_MODE_DEFAULT = MATERIAL_MODE_UV; - + addButton("newMaterialButton", function () { // tablet version of new material dialog var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - tablet.pushOntoStack("NewMaterialDialog.qml"); + tablet.pushOntoStack("hifi/tablet/NewMaterialDialog.qml"); }); that.setActive(false); diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 96084f355f..dd266311ea 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -645,14 +645,14 @@ hr { margin-left: 10px; } -.text label, .url label, .number label, .textarea label, .rgb label, .xyz label, .pyr label, .dropdown label, .gen label { +.text label, .url label, .number label, .textarea label, .xy label, .wh label, .rgb label, .xyz label,.pyr label, .dropdown label, .gen label { float: left; margin-left: 1px; margin-bottom: 3px; margin-top: -2px; } -.text legend, .url legend, .number legend, .textarea legend, .rgb legend, .xyz legend, .pyr legend, .dropdown legend, .gen legend { +.text legend, .url legend, .number legend, .textarea legend, .xy legend, .wh legend, .rgb legend, .xyz legend, .pyr legend, .dropdown legend, .gen legend { float: left; margin-left: 1px; margin-bottom: 3px; @@ -667,7 +667,7 @@ hr { clear: both; float: left; } -.xyz > div, .pyr > div, .gen > div { +.xy > div, .wh > div, .xyz > div, .pyr > div, .gen > div { clear: both; } @@ -841,6 +841,12 @@ div.refresh input[type="button"] { margin-right: -6px; } +.xy .tuple input { + padding-left: 25px; +} +.wh .tuple input { + padding-left: 45px; +} .rgb .tuple input { padding-left: 65px; } diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 93d22180c9..348d93d589 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -787,7 +787,7 @@
- +
@@ -795,13 +795,26 @@
-
- -
-
-
-
-
+
+
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 64f706ce1f..3558a36c04 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -25,7 +25,7 @@ var ICON_FOR_TYPE = { PolyVox: "", Multiple: "", PolyLine: "", - Material: "" + Material: "" }; var EDITOR_TIMEOUT_DURATION = 1500; @@ -167,6 +167,17 @@ function createEmitGroupTextPropertyUpdateFunction(group, propertyName) { }; } +function createEmitVec2PropertyUpdateFunction(property, elX, elY) { + return function () { + var properties = {}; + properties[property] = { + x: elX.value, + y: elY.value + }; + updateProperties(properties); + }; +} + function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) { return function() { var properties = {}; @@ -192,19 +203,6 @@ function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, el }; } -function createEmitVec4PropertyUpdateFunction(property, elX, elY, elZ, elW) { - return function () { - var properties = {}; - properties[property] = { - x: elX.value, - y: elY.value, - z: elZ.value, - w: elW.value - }; - updateProperties(properties); - }; -} - function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) { return function() { var properties = {}; @@ -638,10 +636,11 @@ function loaded() { var elBlendFactor = document.getElementById("property-blend-factor"); var elPriority = document.getElementById("property-priority"); var elShapeID = document.getElementById("property-shape-id"); - var elMaterialBoundsX = document.getElementById("property-material-bounds-x"); - var elMaterialBoundsY = document.getElementById("property-material-bounds-y"); - var elMaterialBoundsZ = document.getElementById("property-material-bounds-z"); - var elMaterialBoundsW = document.getElementById("property-material-bounds-w"); + var elMaterialPosX = document.getElementById("property-material-pos-x"); + var elMaterialPosY = document.getElementById("property-material-pos-y"); + var elMaterialScaleX = document.getElementById("property-material-scale-x"); + var elMaterialScaleY = document.getElementById("property-material-scale-y"); + var elMaterialRot = document.getElementById("property-material-rot"); var elWebSourceURL = document.getElementById("property-web-source-url"); var elWebDPI = document.getElementById("property-web-dpi"); @@ -1134,10 +1133,11 @@ function loaded() { elBlendFactor.value = properties.blendFactor.toFixed(2); elPriority.value = properties.priority; elShapeID.value = properties.shapeID; - elMaterialBoundsX.value = properties.materialBounds.x.toFixed(2); - elMaterialBoundsY.value = properties.materialBounds.y.toFixed(2); - elMaterialBoundsZ.value = properties.materialBounds.z.toFixed(2); - //elMaterialBoundsW.value = properties.materialBounds.w.toFixed(2); + elMaterialPosX.value = properties.materialPos.x.toFixed(4); + elMaterialPosY.value = properties.materialPos.y.toFixed(4); + elMaterialScaleX.value = properties.materialScale.x.toFixed(4); + elMaterialScaleY.value = properties.materialScale.y.toFixed(4); + elMaterialRot.value = properties.materialRot.toFixed(2); } if (properties.locked) { @@ -1411,15 +1411,16 @@ function loaded() { elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL')); elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode')); elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2)); - elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority')); - elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID')); + elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority', 0)); + elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID', 0)); - var materialBoundsChangeFunction = createEmitVec4PropertyUpdateFunction('materialBounds', - elMaterialBoundsX, elMaterialBoundsY, elMaterialBoundsZ, elMaterialBoundsW); - elMaterialBoundsX.addEventListener('change', materialBoundsChangeFunction); - elMaterialBoundsY.addEventListener('change', materialBoundsChangeFunction); - elMaterialBoundsZ.addEventListener('change', materialBoundsChangeFunction); - elMaterialBoundsW.addEventListener('change', materialBoundsChangeFunction); + var materialPosChangeFunction = createEmitVec2PropertyUpdateFunction('materialPos', elMaterialPosX, elMaterialPosY); + elMaterialPosX.addEventListener('change', materialPosChangeFunction); + elMaterialPosY.addEventListener('change', materialPosChangeFunction); + var materialScaleChangeFunction = createEmitVec2PropertyUpdateFunction('materialScale', elMaterialScaleX, elMaterialScaleY); + elMaterialScaleX.addEventListener('change', materialScaleChangeFunction); + elMaterialScaleY.addEventListener('change', materialScaleChangeFunction); + elMaterialRot.addEventListener('change', createEmitNumberPropertyUpdateFunction('materialRot', 2)); elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text')); elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera')); diff --git a/tools/jsdoc/package-lock.json b/tools/jsdoc/package-lock.json new file mode 100644 index 0000000000..073bbf60f6 --- /dev/null +++ b/tools/jsdoc/package-lock.json @@ -0,0 +1,138 @@ +{ + "name": "hifiJSDoc", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "babylon": { + "version": "7.0.0-beta.19", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", + "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==" + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "catharsis": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", + "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", + "requires": { + "underscore-contrib": "0.3.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", + "requires": { + "xmlcreate": "1.0.2" + } + }, + "jsdoc": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", + "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", + "requires": { + "babylon": "7.0.0-beta.19", + "bluebird": "3.5.1", + "catharsis": "0.8.9", + "escape-string-regexp": "1.0.5", + "js2xmlparser": "3.0.0", + "klaw": "2.0.0", + "marked": "0.3.12", + "mkdirp": "0.5.1", + "requizzle": "0.2.1", + "strip-json-comments": "2.0.1", + "taffydb": "2.6.2", + "underscore": "1.8.3" + } + }, + "klaw": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", + "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "marked": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.12.tgz", + "integrity": "sha512-k4NaW+vS7ytQn6MgJn3fYpQt20/mOgYM5Ft9BYMfQJDz2QT6yEeS9XJ8k2Nw8JTeWK/znPPW2n3UJGzyYEiMoA==" + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "requizzle": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", + "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + } + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=" + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "underscore-contrib": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", + "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + } + } + }, + "xmlcreate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", + "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=" + } + } +}