From 241849139ffe1c0a28181c7cd32a0d65857379dd Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 15 Jan 2018 10:21:16 -0800 Subject: [PATCH 01/12] wip --- libraries/entities/CMakeLists.txt | 6 +- .../entities/src/EntityItemProperties.cpp | 43 +++++++ libraries/entities/src/EntityItemProperties.h | 37 ++++-- .../entities/src/EntityItemPropertiesMacros.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 7 + libraries/entities/src/EntityTypes.cpp | 2 + libraries/entities/src/EntityTypes.h | 3 +- libraries/entities/src/MaterialEntityItem.cpp | 120 ++++++++++++++++++ libraries/entities/src/MaterialEntityItem.h | 79 ++++++++++++ libraries/shared/src/MaterialMode.h | 18 +++ 10 files changed, 301 insertions(+), 15 deletions(-) create mode 100644 libraries/entities/src/MaterialEntityItem.cpp create mode 100644 libraries/entities/src/MaterialEntityItem.h create mode 100644 libraries/shared/src/MaterialMode.h diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index c23740654e..191e43ebbe 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,4 +1,8 @@ set(TARGET_NAME entities) setup_hifi_library(Network Script) include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") -link_hifi_libraries(shared networking octree avatars model) +include_hifi_library_headers(fbx) +include_hifi_library_headers(gpu) +include_hifi_library_headers(image) +include_hifi_library_headers(ktx) +link_hifi_libraries(shared networking octree avatars model model-networking) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8bfce7e2d2..0edec88edf 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -330,6 +330,13 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart); CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_URL, materialURL); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_TYPE, materialMode); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); + CHECK_PROPERTY_CHANGE(PROP_PARENT_SHAPE_ID, shapeID); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BOUNDS, materialBounds); + // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); CHECK_PROPERTY_CHANGE(PROP_ITEM_DESCRIPTION, itemDescription); @@ -623,6 +630,16 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch); } + // Materials + if (_type == EntityTypes::Material) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_URL, materialURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_TYPE, materialMode); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BOUNDS, materialBounds); + } + if (!skipDefaults && !strictSemantics) { AABox aaBox = getAABox(); QScriptValue boundingBox = engine->newObject(); @@ -755,6 +772,12 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMode, MaterialMode, setMaterialMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor); + COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, int, setPriority); + COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, int, setShapeID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialBounds, glmVec4, setMaterialBounds); // Certifiable Properties COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); @@ -1490,6 +1513,16 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape()); } + // Materials + if (properties.getType() == EntityTypes::Material) { + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, properties.getMaterialURL()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)properties.getMaterialMode()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, properties.getBlendFactor()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, properties.getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, properties.getMaterialBounds()); + } + APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData()); @@ -1845,6 +1878,16 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE, QString, setShape); } + // Materials + if (properties.getType() == EntityTypes::Material) { + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_URL, QString, setMaterialURL); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BOUNDS, glmVec4, setMaterialBounds); + } + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index c3d04dc7ad..3190d66b63 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -44,6 +44,8 @@ #include "TextEntityItem.h" #include "ZoneEntityItem.h" +#include "MaterialMode.h" + const quint64 UNKNOWN_CREATED_TIME = 0; using ComponentPair = std::pair; @@ -58,19 +60,21 @@ const std::array COMPONENT_MODES = { { /// set of entity item properties via JavaScript hashes/QScriptValues /// all units for SI units (meter, second, radian, etc) class EntityItemProperties { - friend class EntityItem; // TODO: consider removing this friend relationship and use public methods - friend class ModelEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class BoxEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class SphereEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class TextEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class ParticleEffectEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class ZoneEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class WebEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class LineEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class PolyVoxEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class PolyLineEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class ShapeEntityItem; // TODO: consider removing this friend relationship and use public methods + // TODO: consider removing these friend relationship and use public methods + friend class EntityItem; + friend class ModelEntityItem; + friend class BoxEntityItem; + friend class SphereEntityItem; + friend class LightEntityItem; + friend class TextEntityItem; + friend class ParticleEffectEntityItem; + friend class ZoneEntityItem; + friend class WebEntityItem; + friend class LineEntityItem; + friend class PolyVoxEntityItem; + friend class PolyLineEntityItem; + friend class ShapeEntityItem; + friend class MaterialEntityItem; public: EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()); virtual ~EntityItemProperties() = default; @@ -218,6 +222,13 @@ public: DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube()); DEFINE_PROPERTY_REF(PROP_SHAPE, Shape, shape, QString, "Sphere"); + DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, ""); + DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode, UV); + DEFINE_PROPERTY_REF(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float, 1.0f); + DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t, 0); + DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t, 0); + DEFINE_PROPERTY_REF(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4, glm::vec4(0, 0, 1, 1)); + // Certifiable Properties - related to Proof of Purchase certificates DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 278d945ab0..c8c8a658ce 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -184,6 +184,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu } typedef glm::vec3 glmVec3; +typedef glm::vec4 glmVec4; typedef glm::quat glmQuat; typedef QVector qVectorVec3; typedef QVector qVectorQuat; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 7fd72bf0ee..fc9b5cd709 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -226,6 +226,13 @@ enum EntityPropertyList { PROP_LOCAL_DIMENSIONS, // only used to convert values to and from scripts + PROP_MATERIAL_URL, + PROP_MATERIAL_TYPE, + PROP_MATERIAL_BLEND_FACTOR, + PROP_MATERIAL_PRIORITY, + PROP_PARENT_SHAPE_ID, + PROP_MATERIAL_BOUNDS, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index cb17c28fd7..307371c649 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -29,6 +29,7 @@ #include "PolyVoxEntityItem.h" #include "PolyLineEntityItem.h" #include "ShapeEntityItem.h" +#include "MaterialEntityItem.h" QMap EntityTypes::_typeToNameMap; QMap EntityTypes::_nameToTypeMap; @@ -50,6 +51,7 @@ REGISTER_ENTITY_TYPE(PolyLine) REGISTER_ENTITY_TYPE(Shape) REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, ShapeEntityItem::boxFactory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, ShapeEntityItem::sphereFactory) +REGISTER_ENTITY_TYPE(Material) const QString& EntityTypes::getEntityTypeName(EntityType entityType) { QMap::iterator matchedTypeName = _typeToNameMap.find(entityType); diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 316bf2b813..62011c6e26 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -49,7 +49,8 @@ public: PolyVox, PolyLine, Shape, - LAST = Shape + Material, + LAST = Material } EntityType; static const QString& getEntityTypeName(EntityType entityType); diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp new file mode 100644 index 0000000000..19daa11490 --- /dev/null +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -0,0 +1,120 @@ +// +// Created by Sam Gondelman on 1/12/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MaterialEntityItem.h" + +#include "EntityItemProperties.h" + +EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Material; +} + +EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMode, getMaterialMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendFactor, getBlendFactor); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeID, getShapeID); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialBounds, getMaterialBounds); + return properties; +} + +bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMode, setMaterialMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeID, setShapeID); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialBounds, setMaterialBounds); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "MaterialEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties.getLastEdited()); + } + return somethingChanged; +} + +int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL); + READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); + READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); + READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, int, setPriority); + READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, int, setShapeID); + READ_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, glm::vec4, setMaterialBounds); + + return bytesRead; +} + + +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time +EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + requestedProperties += PROP_MATERIAL_URL; + requestedProperties += PROP_MATERIAL_TYPE; + requestedProperties += PROP_MATERIAL_BLEND_FACTOR; + requestedProperties += PROP_MATERIAL_PRIORITY; + requestedProperties += PROP_PARENT_SHAPE_ID; + requestedProperties += PROP_MATERIAL_BOUNDS; + return requestedProperties; +} + +void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, getMaterialMode()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, getMaterialBounds()); +} + +void MaterialEntityItem::debugDump() const { + quint64 now = usecTimestampNow(); + qCDebug(entities) << "MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " url:" << _materialURL; + qCDebug(entities) << " material type:" << _materialMode; + qCDebug(entities) << " blend factor:" << _blendFactor; + qCDebug(entities) << " priority:" << _priority; + qCDebug(entities) << " parent shape ID:" << _shapeID; + qCDebug(entities) << " material bounds:" << _materialBounds; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; +} diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h new file mode 100644 index 0000000000..094c94f24c --- /dev/null +++ b/libraries/entities/src/MaterialEntityItem.h @@ -0,0 +1,79 @@ +// +// Created by Sam Gondelman on 1/12/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_MaterialEntityItem_h +#define hifi_MaterialEntityItem_h + +#include "EntityItem.h" + +#include "MaterialMode.h" +#include + +class MaterialEntityItem : public EntityItem { + using Pointer = std::shared_ptr; +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + MaterialEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + + // methods for getting/setting all properties of an entity + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; + virtual bool setProperties(const EntityItemProperties& properties) override; + + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + void debugDump() const override; + + const QString& getMaterialURL() { return _materialURL; } + void setMaterialURL(const QString& materialURL) { _materialURL = materialURL; } + + MaterialMode getMaterialType() { return _materialMode; } + void setMaterialMode(MaterialMode mode); + + float getBlendFactor() { return _blendFactor; } + void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } + + int getPriority() { return _priority; } + void setPriority(int priority) { _priority = priority; } + + int getShapeID() { return _shapeID; } + void setShapeID(int shapeID) { _shapeID = shapeID; } + + const glm::vec4& getMaterialBounds() { return _materialBounds; } + void setMaterialBounds(const glm::vec4& materialBounds) { _materialBounds = materialBounds; } + +protected: + QString _materialURL; + MaterialMode _materialMode { UV }; + float _blendFactor { 1.0f }; + int _priority { 0 }; + int _shapeID { 0 }; + glm::vec4 _materialBounds { 0, 0, 1, 1 }; + + //NetworkMaterial _material; + +}; + +#endif // hifi_MaterialEntityItem_h diff --git a/libraries/shared/src/MaterialMode.h b/libraries/shared/src/MaterialMode.h new file mode 100644 index 0000000000..05c6d295a5 --- /dev/null +++ b/libraries/shared/src/MaterialMode.h @@ -0,0 +1,18 @@ +// +// Created by Sam Gondelman on 1/12/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_MaterialMode_h +#define hifi_MaterialMode_h + +enum MaterialMode { + UV = 0, + PROJECTED +}; + +#endif // hifi_MaterialMode_h + From d7f4b033e8f6d5249e43001dac5f1453093a4e06 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 17 Jan 2018 15:56:18 -0800 Subject: [PATCH 02/12] wip finish adding material entity --- .../resources/qml/hifi/tablet/EditTabView.qml | 11 + .../qml/hifi/tablet/NewMaterialDialog.qml | 174 +++++++++++++ .../src/RenderableEntityItem.cpp | 7 +- .../src/RenderableEntityItem.h | 1 - .../src/RenderableMaterialEntityItem.cpp | 238 ++++++++++++++++++ .../src/RenderableMaterialEntityItem.h | 54 ++++ .../entities/src/EntityItemProperties.cpp | 63 ++++- .../entities/src/EntityItemPropertiesMacros.h | 23 ++ libraries/entities/src/MaterialEntityItem.cpp | 229 +++++++++++++++-- libraries/entities/src/MaterialEntityItem.h | 34 ++- libraries/graphics/src/graphics/Material.cpp | 2 +- .../src/model-networking/ModelCache.cpp | 91 ++++++- .../src/model-networking/ModelCache.h | 20 +- .../src/model-networking/TextureCache.cpp | 2 + .../src/model-networking/TextureCache.h | 1 - libraries/networking/src/ResourceCache.cpp | 9 +- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/octree/src/OctreePacketData.h | 4 + .../src/CauterizedMeshPartPayload.cpp | 4 +- .../src/CauterizedMeshPartPayload.h | 2 +- libraries/render-utils/src/GeometryCache.cpp | 1 - .../render-utils/src/MeshPartPayload.cpp | 152 +---------- libraries/render-utils/src/MeshPartPayload.h | 8 +- libraries/render/CMakeLists.txt | 6 +- libraries/render/src/render/ShapePipeline.cpp | 121 +++++++++ libraries/render/src/render/ShapePipeline.h | 4 + libraries/shared/src/MaterialMode.cpp | 24 ++ libraries/shared/src/MaterialMode.h | 7 + scripts/developer/tests/toolbarTest.js | 12 +- scripts/system/edit.js | 45 +++- scripts/system/html/css/edit-style.css | 49 +++- scripts/system/html/entityProperties.html | 45 ++++ scripts/system/html/js/entityProperties.js | 52 +++- scripts/system/libraries/entityList.js | 10 +- 35 files changed, 1291 insertions(+), 219 deletions(-) create mode 100644 interface/resources/qml/hifi/tablet/NewMaterialDialog.qml create mode 100644 libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp create mode 100644 libraries/entities-renderer/src/RenderableMaterialEntityItem.h create mode 100644 libraries/shared/src/MaterialMode.cpp diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index e94325f399..65dd871fb2 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -133,6 +133,17 @@ TabView { editTabView.currentIndex = 4 } } + + NewEntityButton { + icon: "icons/create-icons/94-model-01.svg" + text: "MATERIAL" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newMaterialButton" } + }); + editTabView.currentIndex = 2 + } + } } HifiControls.Button { diff --git a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml new file mode 100644 index 0000000000..6d3477187b --- /dev/null +++ b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml @@ -0,0 +1,174 @@ +// +// NewMaterialDialog.qml +// qml/hifi +// +// Created by Sam Gondelman on 1/17/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs + +import "../../styles-uit" +import "../../controls-uit" +import "../dialogs" + +Rectangle { + id: newMaterialDialog + // width: parent.width + // height: parent.height + HifiConstants { id: hifi } + color: hifi.colors.baseGray; + signal sendToScript(var message); + property bool keyboardEnabled: false + property bool punctuationMode: false + property bool keyboardRasied: false + + function errorMessageBox(message) { + return desktop.messageBox({ + icon: hifi.icons.warning, + defaultButton: OriginalDialogs.StandardButton.Ok, + title: "Error", + text: message + }); + } + + Item { + id: column1 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + anchors.bottomMargin: 10 + anchors.topMargin: 10 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: keyboard.top + + Text { + id: text1 + text: qsTr("Material URL") + color: "#ffffff" + font.pixelSize: 12 + } + + TextInput { + id: materialURL + height: 20 + text: qsTr("") + color: "white" + anchors.top: text1.bottom + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + font.pixelSize: 12 + + onAccepted: { + newMaterialDialog.keyboardEnabled = false; + } + + MouseArea { + anchors.fill: parent + onClicked: { + newMaterialDialog.keyboardEnabled = HMD.active + parent.focus = true; + parent.forceActiveFocus(); + materialURL.cursorPosition = materialURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters); + } + } + } + + Rectangle { + id: textInputBox + color: "white" + anchors.fill: materialURL + opacity: 0.1 + } + + Row { + id: row1 + height: 400 + spacing: 30 + anchors.top: materialURL.bottom + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + Column { + id: column3 + height: 400 + spacing: 10 + + Text { + id: text3 + text: qsTr("Material Mode") + color: "#ffffff" + font.pixelSize: 12 + } + + ComboBox { + id: materialMode + property var materialArray: ["UV space material", + "3D projected material"] + + width: 200 + z: 100 + transformOrigin: Item.Center + model: materialArray + } + + Row { + id: row3 + width: 200 + height: 400 + spacing: 5 + + anchors.horizontalCenter: column3.horizontalCenter + anchors.horizontalCenterOffset: -20 + + Button { + id: button1 + text: qsTr("Add") + z: -1 + onClicked: { + newMaterialDialog.sendToScript({ + method: "newMaterialDialogAdd", + params: { + textInput: materialURL.text, + comboBox: materialMode.currentIndex + } + }); + } + } + + Button { + id: button2 + z: -1 + text: qsTr("Cancel") + onClicked: { + newMaterialDialog.sendToScript({method: "newMaterialDialogCancel"}) + } + } + } + } + } + } + + Keyboard { + id: keyboard + raised: parent.keyboardEnabled + numeric: parent.punctuationMode + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + } +} diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index fb9aba636b..cbd2df86ad 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -25,6 +25,7 @@ #include "RenderableTextEntityItem.h" #include "RenderableWebEntityItem.h" #include "RenderableZoneEntityItem.h" +#include "RenderableMaterialEntityItem.h" using namespace render; @@ -247,6 +248,10 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, result = make_renderer(entity); break; + case Type::Material: + result = make_renderer(entity); + break; + default: break; } @@ -388,4 +393,4 @@ void EntityRenderer::onAddToScene(const EntityItemPointer& entity) { void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) { entity->deregisterChangeHandler(_changeHandlerId); QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr); -} +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 8eb82e2c6e..e54ae2f6b4 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -59,7 +59,6 @@ protected: virtual void onAddToScene(const EntityItemPointer& entity); virtual void onRemoveFromScene(const EntityItemPointer& entity); -protected: EntityRenderer(const EntityItemPointer& entity); ~EntityRenderer(); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp new file mode 100644 index 0000000000..83754c1c16 --- /dev/null +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -0,0 +1,238 @@ +// +// Created by Sam Gondelman on 1/18/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "RenderableMaterialEntityItem.h" + +using namespace render; +using namespace render::entities; + +bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { + if (entity->getMaterial() != _drawMaterial) { + return true; + } + return false; +} + +void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { + withWriteLock([&] { + _drawMaterial = entity->getMaterial(); + _renderTransform = getModelTransform(); + const float MATERIAL_ENTITY_SCALE = 0.5f; + _renderTransform.postScale(MATERIAL_ENTITY_SCALE); + _renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); + }); +} + +ItemKey MaterialEntityRenderer::getKey() { + ItemKey::Builder builder; + builder.withTypeShape(); + + if (!_visible) { + builder.withInvisible(); + } + + if (_drawMaterial) { + auto matKey = _drawMaterial->getKey(); + if (matKey.isTranslucent()) { + builder.withTransparent(); + } + } + + return builder.build(); +} + +ShapeKey MaterialEntityRenderer::getShapeKey() { + graphics::MaterialKey drawMaterialKey; + if (_drawMaterial) { + drawMaterialKey = _drawMaterial->getKey(); + } + + bool isTranslucent = drawMaterialKey.isTranslucent(); + bool hasTangents = drawMaterialKey.isNormalMap(); + bool hasSpecular = drawMaterialKey.isMetallicMap(); + bool hasLightmap = drawMaterialKey.isLightmapMap(); + bool isUnlit = drawMaterialKey.isUnlit(); + + ShapeKey::Builder builder; + builder.withMaterial(); + + if (isTranslucent) { + builder.withTranslucent(); + } + if (hasTangents) { + builder.withTangents(); + } + if (hasSpecular) { + builder.withSpecular(); + } + if (hasLightmap) { + builder.withLightmap(); + } + if (isUnlit) { + builder.withUnlit(); + } + + return builder.build(); +} + +glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) { + return glm::vec3(glm::sin(theta) * glm::cos(phi), glm::cos(theta), glm::sin(theta) * glm::sin(phi)); +} + +glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) { + return glm::vec3(-glm::cos(theta) * glm::cos(phi), 0, -glm::cos(theta) * glm::sin(phi)); +} + +void MaterialEntityRenderer::addVertex(std::vector& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) { + buffer.push_back(pos.x); buffer.push_back(pos.y); buffer.push_back(pos.z); + buffer.push_back(tan.x); buffer.push_back(tan.y); buffer.push_back(tan.z); + buffer.push_back(uv.x); buffer.push_back(uv.y); +} + +void MaterialEntityRenderer::addTriangleFan(std::vector& buffer, int stack, int step) { + float v1 = ((float)stack) / STACKS; + float theta1 = v1 * M_PI; + glm::vec3 tip = getVertexPos(0, theta1); + float v2 = ((float)(stack + step)) / STACKS; + float theta2 = v2 * M_PI; + for (int i = 0; i < SLICES; i++) { + float u1 = ((float)i) / SLICES; + float u2 = ((float)(i + step)) / SLICES; + float phi1 = u1 * M_PI_TIMES_2; + float phi2 = u2 * M_PI_TIMES_2; + /* (flipped for negative step) + p1 + / \ + / \ + / \ + p3 ------ p2 + */ + + glm::vec3 pos2 = getVertexPos(phi2, theta2); + glm::vec3 pos3 = getVertexPos(phi1, theta2); + + glm::vec3 tan1 = getTangent(0, theta1); + glm::vec3 tan2 = getTangent(phi2, theta2); + glm::vec3 tan3 = getTangent(phi1, theta2); + + glm::vec2 uv1 = glm::vec2((u1 + u2) / 2.0f, v1); + glm::vec2 uv2 = glm::vec2(u2, v2); + glm::vec2 uv3 = glm::vec2(u1, v2); + + addVertex(buffer, tip, tan1, uv1); + addVertex(buffer, pos2, tan2, uv2); + addVertex(buffer, pos3, tan3, uv3); + + _numVertices += 3; + } +} + +int MaterialEntityRenderer::_numVertices = 0; +std::shared_ptr MaterialEntityRenderer::_streamFormat = nullptr; +std::shared_ptr MaterialEntityRenderer::_stream = nullptr; +std::shared_ptr MaterialEntityRenderer::_verticesBuffer = nullptr; + +void MaterialEntityRenderer::generateMesh() { + _streamFormat = std::make_shared(); + _stream = std::make_shared(); + _verticesBuffer = std::make_shared(); + + const int NUM_POS_COORDS = 3; + const int NUM_TANGENT_COORDS = 3; + const int VERTEX_TANGENT_OFFSET = NUM_POS_COORDS * sizeof(float); + const int VERTEX_TEXCOORD_OFFSET = VERTEX_TANGENT_OFFSET + NUM_TANGENT_COORDS * sizeof(float); + + _streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + _streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + _streamFormat->setAttribute(gpu::Stream::TANGENT, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_TANGENT_OFFSET); + _streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET); + + _stream->addBuffer(_verticesBuffer, 0, _streamFormat->getChannels().at(0)._stride); + + std::vector vertexBuffer; + + // Top + addTriangleFan(vertexBuffer, 0, 1); + + // Middle section + for (int j = 1; j < STACKS - 1; j++) { + float v1 = ((float)j) / STACKS; + float v2 = ((float)(j + 1)) / STACKS; + float theta1 = v1 * M_PI; + float theta2 = v2 * M_PI; + for (int i = 0; i < SLICES; i++) { + float u1 = ((float)i) / SLICES; + float u2 = ((float)(i + 1)) / SLICES; + float phi1 = u1 * M_PI_TIMES_2; + float phi2 = u2 * M_PI_TIMES_2; + + /* + p2 ---- p3 + | / | + | / | + | / | + p1 ---- p4 + */ + + glm::vec3 pos1 = getVertexPos(phi1, theta2); + glm::vec3 pos2 = getVertexPos(phi1, theta1); + glm::vec3 pos3 = getVertexPos(phi2, theta1); + glm::vec3 pos4 = getVertexPos(phi2, theta2); + + glm::vec3 tan1 = getTangent(phi1, theta2); + glm::vec3 tan2 = getTangent(phi1, theta1); + glm::vec3 tan3 = getTangent(phi2, theta1); + glm::vec3 tan4 = getTangent(phi2, theta2); + + glm::vec2 uv1 = glm::vec2(u1, v2); + glm::vec2 uv2 = glm::vec2(u1, v1); + glm::vec2 uv3 = glm::vec2(u2, v1); + glm::vec2 uv4 = glm::vec2(u2, v2); + + addVertex(vertexBuffer, pos1, tan1, uv1); + addVertex(vertexBuffer, pos2, tan2, uv2); + addVertex(vertexBuffer, pos3, tan3, uv3); + + addVertex(vertexBuffer, pos3, tan3, uv3); + addVertex(vertexBuffer, pos4, tan4, uv4); + addVertex(vertexBuffer, pos1, tan1, uv1); + + _numVertices += 6; + } + } + + // Bottom + addTriangleFan(vertexBuffer, STACKS, -1); + + _verticesBuffer->append(vertexBuffer.size() * sizeof(float), (gpu::Byte*) vertexBuffer.data()); +} + +void MaterialEntityRenderer::doRender(RenderArgs* args) { + PerformanceTimer perfTimer("RenderableMaterialEntityItem::render"); + Q_ASSERT(args->_batch); + + gpu::Batch& batch = *args->_batch; + + batch.setModelTransform(_renderTransform); + + // bind the material + args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_details._materialSwitches++; + + // Draw! + if (_numVertices == 0) { + generateMesh(); + } + + batch.setInputFormat(_streamFormat); + batch.setInputStream(0, *_stream); + batch.draw(gpu::TRIANGLES, _numVertices, 0); + + const int NUM_VERTICES_PER_TRIANGLE = 3; + args->_details._trianglesRendered += _numVertices / NUM_VERTICES_PER_TRIANGLE; +} diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h new file mode 100644 index 0000000000..166ad762cc --- /dev/null +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -0,0 +1,54 @@ +// +// Created by Sam Gondelman on 1/18/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_RenderableMaterialEntityItem_h +#define hifi_RenderableMaterialEntityItem_h + +#include "RenderableEntityItem.h" + +#include + +class NetworkMaterial; + +namespace render { namespace entities { + +class MaterialEntityRenderer : public TypedEntityRenderer { + using Parent = TypedEntityRenderer; + using Pointer = std::shared_ptr; +public: + MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {} + +private: + virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; + virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doRender(RenderArgs* args) override; + + ItemKey getKey() override; + ShapeKey getShapeKey() override; + + Transform _renderTransform; + + std::shared_ptr _drawMaterial; + + static int _numVertices; + static std::shared_ptr _streamFormat; + static std::shared_ptr _stream; + static std::shared_ptr _verticesBuffer; + + void generateMesh(); + void addTriangleFan(std::vector& buffer, int stack, int step); + static glm::vec3 getVertexPos(float phi, float theta); + static glm::vec3 getTangent(float phi, float theta); + static void addVertex(std::vector& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv); + const int SLICES = 15; + const int STACKS = 9; + const float M_PI_TIMES_2 = 2.0f * M_PI; +}; + +} } +#endif // hifi_RenderableMaterialEntityItem_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f8f8859d73..77300be399 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -115,6 +115,17 @@ void buildStringToShapeTypeLookup() { addShapeType(SHAPE_TYPE_STATIC_MESH); } +QHash stringToMaterialModeLookup; + +void addMaterialMode(MaterialMode mode) { + stringToMaterialModeLookup[MaterialModeHelpers::getNameForMaterialMode(mode)] = mode; +} + +void buildStringToMaterialModeLookup() { + addMaterialMode(UV); + addMaterialMode(PROJECTED); +} + QString getCollisionGroupAsString(uint8_t group) { switch (group) { case USER_COLLISION_GROUP_DYNAMIC: @@ -259,6 +270,21 @@ void EntityItemProperties::setSkyboxModeFromString(const QString& skyboxMode) { } } +QString EntityItemProperties::getMaterialModeAsString() const { + return MaterialModeHelpers::getNameForMaterialMode(_materialMode); +} + +void EntityItemProperties::setMaterialModeFromString(const QString& materialMode) { + if (stringToMaterialModeLookup.empty()) { + buildStringToMaterialModeLookup(); + } + auto materialModeItr = stringToMaterialModeLookup.find(materialMode.toLower()); + if (materialModeItr != stringToMaterialModeLookup.end()) { + _materialMode = materialModeItr.value(); + _materialModeChanged = true; + } +} + EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; @@ -329,7 +355,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread); CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart); CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_URL, materialURL); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_TYPE, materialMode); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); @@ -635,7 +660,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool // Materials if (_type == EntityTypes::Material) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_URL, materialURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_TYPE, materialMode); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MATERIAL_TYPE, materialMode, getMaterialModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); @@ -776,7 +801,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMode, MaterialMode, setMaterialMode); + COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(materialMode, MaterialMode, setMaterialMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor); COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, int, setPriority); COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, int, setShapeID); @@ -1135,6 +1160,13 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float); ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t); + ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4); + // Certifiable Properties ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString); @@ -2067,6 +2099,13 @@ void EntityItemProperties::markAllChanged() { //_alphaStartChanged = true; //_alphaFinishChanged = true; + _materialURLChanged = true; + _materialModeChanged = true; + _blendFactorChanged = true; + _priorityChanged = true; + _shapeIDChanged = true; + _materialBoundsChanged = true; + // Certifiable Properties _itemNameChanged = true; _itemDescriptionChanged = true; @@ -2390,6 +2429,24 @@ QList EntityItemProperties::listChangedProperties() { if (radiusFinishChanged()) { out += "radiusFinish"; } + if (materialURLChanged()) { + out += "materialURL"; + } + if (materialModeChanged()) { + out += "materialMode"; + } + if (blendFactorChanged()) { + out += "blendFactor"; + } + if (priorityChanged()) { + out += "priority"; + } + if (shapeIDChanged()) { + out += "shapeID"; + } + if (materialBoundsChanged()) { + out += "materialBounds"; + } // Certifiable Properties if (itemNameChanged()) { diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index c8c8a658ce..557a8476fa 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -242,6 +242,29 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal return glm::vec3(0); } +inline glmVec4 glmVec4_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = false; /// assume it can't be converted + QScriptValue x = v.property("x"); + QScriptValue y = v.property("y"); + QScriptValue z = v.property("z"); + QScriptValue w = v.property("w"); + if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { + glm::vec4 newValue(0); + newValue.x = x.toVariant().toFloat(); + newValue.y = y.toVariant().toFloat(); + newValue.z = z.toVariant().toFloat(); + newValue.w = w.toVariant().toFloat(); + isValid = !glm::isnan(newValue.x) && + !glm::isnan(newValue.y) && + !glm::isnan(newValue.z) && + !glm::isnan(newValue.w); + if (isValid) { + return newValue; + } + } + return glm::vec4(0); +} + inline AACube AACube_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; AACube result; diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 19daa11490..bbcc691879 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -10,6 +10,9 @@ #include "EntityItemProperties.h" +#include "QJsonDocument" +#include "QJsonArray" + EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); @@ -34,7 +37,7 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMode, setMaterialMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); @@ -55,6 +58,139 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { return somethingChanged; } +bool MaterialEntityItem::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) { + if (array.isArray()) { + QJsonArray colorArray = array.toArray(); + if (colorArray.size() >= 3 && colorArray[0].isDouble() && colorArray[1].isDouble() && colorArray[2].isDouble()) { + isSRGB = true; + if (colorArray.size() >= 4) { + if (colorArray[3].isBool()) { + isSRGB = colorArray[3].toBool(); + } + } + color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble()); + return true; + } + } + return false; +} + +void MaterialEntityItem::parseJSONMaterial(const QJsonObject& materialJSON) { + QString name = ""; + std::shared_ptr material = std::make_shared(); + for (auto& key : materialJSON.keys()) { + if (key == "name") { + auto nameJSON = materialJSON.value(key); + if (nameJSON.isString()) { + name = nameJSON.toString(); + } + } else if (key == "emissive") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setEmissive(color, isSRGB); + } + } else if (key == "opacity") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setOpacity(value.toDouble()); + } + } else if (key == "albedo") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setAlbedo(color, isSRGB); + } + } else if (key == "roughness") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setRoughness(value.toDouble()); + } + } else if (key == "fresnel") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setFresnel(color, isSRGB); + } + } else if (key == "metallic") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setMetallic(value.toDouble()); + } + } else if (key == "scattering") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setScattering(value.toDouble()); + } + } else if (key == "emissiveMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setEmissiveMap(value.toString()); + } + } else if (key == "albedoMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + bool useAlphaChannel = false; + auto opacityMap = materialJSON.find("opacityMap"); + if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) { + useAlphaChannel = true; + } + material->setAlbedoMap(value.toString(), useAlphaChannel); + } + } else if (key == "roughnessMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setRoughnessMap(value.toString(), false); + } + } else if (key == "glossMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setRoughnessMap(value.toString(), true); + } + } else if (key == "metallicMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setMetallicMap(value.toString(), false); + } + } else if (key == "specularMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setMetallicMap(value.toString(), true); + } + } else if (key == "normalMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setNormalMap(value.toString(), false); + } + } else if (key == "bumpMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setNormalMap(value.toString(), true); + } + } else if (key == "occlusionMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setOcclusionMap(value.toString()); + } + } else if (key == "scatteringMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setScatteringMap(value.toString()); + } + } else if (key == "lightMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setLightmapMap(value.toString()); + } + } + } + _materials[name] = material; + _materialNames.push_back(name); +} + int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -66,8 +202,8 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); - READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, int, setPriority); - READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, int, setShapeID); + READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); + READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); READ_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, glm::vec4, setMaterialBounds); return bytesRead; @@ -96,25 +232,82 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode bool successPropertyFits = true; APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, getMaterialMode()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, (uint32_t)getPriority()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, (uint32_t)getShapeID()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, getMaterialBounds()); } void MaterialEntityItem::debugDump() const { quint64 now = usecTimestampNow(); - qCDebug(entities) << "MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " name:" << _name; - qCDebug(entities) << " url:" << _materialURL; - qCDebug(entities) << " material type:" << _materialMode; - qCDebug(entities) << " blend factor:" << _blendFactor; - qCDebug(entities) << " priority:" << _priority; - qCDebug(entities) << " parent shape ID:" << _shapeID; - qCDebug(entities) << " material bounds:" << _materialBounds; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); - qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; + qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " material json:" << _materialURL; + qCDebug(entities) << " current material name:" << _currentMaterialName; + qCDebug(entities) << " material type:" << _materialMode; + qCDebug(entities) << " blend factor:" << _blendFactor; + qCDebug(entities) << " priority:" << _priority; + qCDebug(entities) << " parent shape ID:" << _shapeID; + qCDebug(entities) << " material bounds:" << _materialBounds; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << "MATERIAL EntityItem Ptr:" << this; } + +void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) { + EntityItem::setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS); +} + +std::shared_ptr MaterialEntityItem::getMaterial() const { + auto material = _materials.find(_currentMaterialName); + if (material != _materials.end()) { + return material.value(); + } else { + return nullptr; + } +} + +void MaterialEntityItem::setMaterialURL(const QString& materialURLString) { + if (materialURLString.startsWith("userData")) { + QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); + _materials.clear(); + _materialNames.clear(); + if (!materialJSON.isNull()) { + if (materialJSON.isArray()) { + QJsonArray materials = materialJSON.array(); + for (auto& material : materials) { + if (!material.isNull() && material.isObject()) { + parseJSONMaterial(material.toObject()); + } + } + } else if (materialJSON.isObject()) { + parseJSONMaterial(materialJSON.object()); + } + } + } + _materialURL = materialURLString; + + // TODO: if URL ends with ?string, set _currentMaterialName = string + + // Since our JSON changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(_currentMaterialName); +} + +void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialName) { + auto material = _materials.find(currentMaterialName); + if (material != _materials.end()) { + _currentMaterialName = currentMaterialName; + } else if (_materialNames.size() > 0) { + setCurrentMaterialName(_materialNames[0]); + } +} + +void MaterialEntityItem::setUserData(const QString& userData) { + EntityItem::setUserData(userData); + if (_materialURL.startsWith("userData")) { + // Trigger material update when user data changes + setMaterialURL(_materialURL); + } +} \ No newline at end of file diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index 094c94f24c..80fe226b68 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -46,25 +46,34 @@ public: void debugDump() const override; - const QString& getMaterialURL() { return _materialURL; } - void setMaterialURL(const QString& materialURL) { _materialURL = materialURL; } + virtual void setUnscaledDimensions(const glm::vec3& value) override; - MaterialMode getMaterialType() { return _materialMode; } - void setMaterialMode(MaterialMode mode); + QString getMaterialURL() const { return _materialURL; } + void setMaterialURL(const QString& materialURLString); - float getBlendFactor() { return _blendFactor; } + QString getCurrentMaterialName() const { return _currentMaterialName; } + void setCurrentMaterialName(const QString& currentMaterialName); + + MaterialMode getMaterialMode() const { return _materialMode; } + void setMaterialMode(MaterialMode mode) { _materialMode = mode; } + + float getBlendFactor() const { return _blendFactor; } void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } - int getPriority() { return _priority; } + int getPriority() const { return _priority; } void setPriority(int priority) { _priority = priority; } - int getShapeID() { return _shapeID; } + int getShapeID() const { return _shapeID; } void setShapeID(int shapeID) { _shapeID = shapeID; } - const glm::vec4& getMaterialBounds() { return _materialBounds; } + glm::vec4 getMaterialBounds() const { return _materialBounds; } void setMaterialBounds(const glm::vec4& materialBounds) { _materialBounds = materialBounds; } -protected: + std::shared_ptr getMaterial() const; + + void setUserData(const QString& userData) override; + +private: QString _materialURL; MaterialMode _materialMode { UV }; float _blendFactor { 1.0f }; @@ -72,7 +81,12 @@ protected: int _shapeID { 0 }; glm::vec4 _materialBounds { 0, 0, 1, 1 }; - //NetworkMaterial _material; + QHash> _materials; + std::vector _materialNames; + QString _currentMaterialName; + + void parseJSONMaterial(const QJsonObject& materialJSON); + static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); }; diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index ea5bd331c9..6cc6b8472f 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -221,4 +221,4 @@ bool Material::calculateMaterialInfo() const { _hasCalculatedTextureInfo = allTextures; } return _hasCalculatedTextureInfo; -} +} \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 07f7283bfa..1fe3648838 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -425,7 +425,7 @@ bool Geometry::areTexturesLoaded() const { return true; } -const std::shared_ptr Geometry::getShapeMaterial(int partID) const { +const std::shared_ptr Geometry::getShapeMaterial(int partID) const { if ((partID >= 0) && (partID < (int)_meshParts->size())) { int materialID = _meshParts->at(partID)->materialID; if ((materialID >= 0) && (materialID < (int)_materials.size())) { @@ -491,6 +491,15 @@ void GeometryResourceWatcher::resourceRefreshed() { // _instance.reset(); } +NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) : + Material(m), + _textures(m._textures), + _albedoTransform(m._albedoTransform), + _lightmapParams(m._lightmapParams), + _lightmapTransform(m._lightmapTransform), + _isOriginal(m._isOriginal) +{} + const QString NetworkMaterial::NO_TEXTURE = QString(); const QString& NetworkMaterial::getTextureName(MapChannel channel) { @@ -532,19 +541,85 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl } graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel) { - const auto texture = DependencyManager::get()->getTexture(url, type); - _textures[channel].texture = texture; + auto textureCache = DependencyManager::get(); + if (textureCache) { + auto texture = textureCache->getTexture(url, type); + _textures[channel].texture = texture; - auto map = std::make_shared(); - map->setTextureSource(texture->_textureSource); + auto map = std::make_shared(); + if (texture) { + map->setTextureSource(texture->_textureSource); + emit textureFinished(); + } - return map; + return map; + } + return nullptr; +} + +void NetworkMaterial::setAlbedoMap(const QString& url, bool useAlphaChannel) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); + if (map) { + map->setUseAlphaChannel(useAlphaChannel); + setTextureMap(MapChannel::ALBEDO_MAP, map); + } +} + +void NetworkMaterial::setNormalMap(const QString& url, bool isBumpmap) { + auto map = fetchTextureMap(QUrl(url), isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP); + if (map) { + setTextureMap(MapChannel::NORMAL_MAP, map); + } +} + +void NetworkMaterial::setRoughnessMap(const QString& url, bool isGloss) { + auto map = fetchTextureMap(QUrl(url), isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); + if (map) { + setTextureMap(MapChannel::ROUGHNESS_MAP, map); + } +} + +void NetworkMaterial::setMetallicMap(const QString& url, bool isSpecular) { + auto map = fetchTextureMap(QUrl(url), isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); + if (map) { + setTextureMap(MapChannel::METALLIC_MAP, map); + } +} + +void NetworkMaterial::setOcclusionMap(const QString& url) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); + if (map) { + setTextureMap(MapChannel::OCCLUSION_MAP, map); + } +} + +void NetworkMaterial::setEmissiveMap(const QString& url) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); + if (map) { + setTextureMap(MapChannel::EMISSIVE_MAP, map); + } +} + +void NetworkMaterial::setScatteringMap(const QString& url) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); + if (map) { + setTextureMap(MapChannel::SCATTERING_MAP, map); + } +} + +void NetworkMaterial::setLightmapMap(const QString& url) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); + if (map) { + //map->setTextureTransform(_lightmapTransform); + //map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); + setTextureMap(MapChannel::LIGHTMAP_MAP, map); + } } NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) : - graphics::Material(*material._material) + graphics::Material(*material._material), + _textures(MapChannel::NUM_MAP_CHANNELS) { - _textures = Textures(MapChannel::NUM_MAP_CHANNELS); if (!material.albedoTexture.filename.isEmpty()) { auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); _albedoTransform = material.albedoTexture.transform; diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index f650b3f2eb..575f94f9bf 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -48,7 +48,7 @@ public: const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; } const GeometryMeshes& getMeshes() const { return *_meshes; } - const std::shared_ptr getShapeMaterial(int shapeID) const; + const std::shared_ptr getShapeMaterial(int shapeID) const; const QVariantMap getTextures() const; void setTextures(const QVariantMap& textureMap); @@ -131,7 +131,6 @@ private: Geometry::Pointer& _geometryRef; }; - /// Stores cached model geometries. class ModelCache : public ResourceCache, public Dependency { Q_OBJECT @@ -157,11 +156,26 @@ private: virtual ~ModelCache() = default; }; -class NetworkMaterial : public graphics::Material { +class NetworkMaterial : public QObject, public graphics::Material { + Q_OBJECT public: using MapChannel = graphics::Material::MapChannel; + NetworkMaterial() : _textures(MapChannel::NUM_MAP_CHANNELS) {} NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl); + NetworkMaterial(const NetworkMaterial& material); + + void setAlbedoMap(const QString& url, bool useAlphaChannel); + void setNormalMap(const QString& url, bool isBumpmap); + void setRoughnessMap(const QString& url, bool isGloss); + void setMetallicMap(const QString& url, bool isSpecular); + void setOcclusionMap(const QString& url); + void setEmissiveMap(const QString& url); + void setScatteringMap(const QString& url); + void setLightmapMap(const QString& url); + +signals: + void textureFinished(); protected: friend class Geometry; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 8153dba3a5..3402758ef1 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -275,6 +275,8 @@ QSharedPointer TextureCache::createResource(const QUrl& url, const QSh return QSharedPointer(texture, &Resource::deleter); } +int networkTexturePointerMetaTypeId = qRegisterMetaType>(); + NetworkTexture::NetworkTexture(const QUrl& url) : Resource(url), _type(), diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 742d003d02..6a88eb641a 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -163,7 +163,6 @@ public: NetworkTexturePointer getTexture(const QUrl& url, image::TextureUsage::Type type = image::TextureUsage::DEFAULT_TEXTURE, const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); - gpu::TexturePointer getTextureByHash(const std::string& hash); gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index a3ac995bcf..7ba7cca96d 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -340,14 +340,6 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& return resource; } - if (QThread::currentThread() != thread()) { - qCDebug(networking) << "Fetching asynchronously:" << url; - QMetaObject::invokeMethod(this, "getResource", - Q_ARG(QUrl, url), Q_ARG(QUrl, fallback)); - // Cannot use extra parameter as it might be freed before the invocation - return QSharedPointer(); - } - if (!url.isValid() && !url.isEmpty() && fallback.isValid()) { return getResource(fallback, QUrl()); } @@ -358,6 +350,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& extra); resource->setSelf(resource); resource->setCache(this); + resource->moveToThread(qApp->thread()); connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); { QWriteLocker locker(&_resourcesLock); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 711aeb2cc2..98ad1ab323 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::SoftEntities); + return static_cast(EntityVersion::MaterialEntities); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::RemovedJurisdictions); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 458666571c..e13809810c 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -206,7 +206,8 @@ enum class EntityVersion : PacketVersion { OwnershipChallengeFix, ZoneLightInheritModes = 82, ZoneStageRemoved, - SoftEntities + SoftEntities, + MaterialEntities }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index ef4e98798f..7f8eb49101 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -33,6 +33,8 @@ #include #include +#include "MaterialMode.h" + #include "OctreeConstants.h" #include "OctreeElement.h" @@ -249,6 +251,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec4& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } @@ -257,6 +260,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, rgbColor& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; } static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, MaterialMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, QString& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result); static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result); diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index 3d213840dd..41a5bf5faf 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -38,7 +38,7 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform _cauterizedTransform = renderTransform; } -void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { +void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const { bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { @@ -46,7 +46,7 @@ void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::S } batch.setModelTransform(_cauterizedTransform); } else { - ModelMeshPartPayload::bindTransform(batch, locations, renderMode); + ModelMeshPartPayload::bindTransform(batch, renderMode); } } diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 2337632047..3c0f90fcb5 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -25,7 +25,7 @@ public: void updateTransformForCauterizedMesh(const Transform& renderTransform); - void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; + void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override; void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 1fd6ca2980..0d76b2c093 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1318,7 +1318,6 @@ void GeometryCache::renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, in renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color, id); } - void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner, const glm::vec4& color, int id) { diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index c506887fc4..dd5809093e 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -125,126 +125,7 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } -void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool enableTextures) const { - if (!_drawMaterial) { - return; - } - - auto textureCache = DependencyManager::get(); - - batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, _drawMaterial->getSchemaBuffer()); - batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, _drawMaterial->getTexMapArrayBuffer()); - - const auto& materialKey = _drawMaterial->getKey(); - const auto& textureMaps = _drawMaterial->getTextureMaps(); - - int numUnlit = 0; - if (materialKey.isUnlit()) { - numUnlit++; - } - - if (!enableTextures) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - return; - } - - // Albedo - if (materialKey.isAlbedoMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture()); - } - } - - // Roughness map - if (materialKey.isRoughnessMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); - } - } - - // Normal map - if (materialKey.isNormalMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); - } - } - - // Metallic map - if (materialKey.isMetallicMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); - } - } - - // Occlusion map - if (materialKey.isOcclusionMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); - } - } - - // Scattering map - if (materialKey.isScatteringMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); - } - } - - // Emissive / Lightmap - if (materialKey.isLightmapMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); - - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); - } - } else if (materialKey.isEmissiveMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); - - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - } - } -} - -void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { +void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const { batch.setModelTransform(_drawTransform); } @@ -252,23 +133,21 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::Loca void MeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("MeshPartPayload::render"); + if (!args) { + return; + } + gpu::Batch& batch = *(args->_batch); - auto locations = args->_shapePipeline->locations; - assert(locations); - // Bind the model transform and the skinCLusterMatrices if needed - bindTransform(batch, locations, args->_renderMode); + bindTransform(batch, args->_renderMode); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); // apply material properties - bindMaterial(batch, locations, args->_enableTexturing); - - if (args) { - args->_details._materialSwitches++; - } + args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_details._materialSwitches++; // Draw! { @@ -276,10 +155,8 @@ void MeshPartPayload::render(RenderArgs* args) { drawCall(batch); } - if (args) { - const int INDICES_PER_TRIANGLE = 3; - args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; - } + const int INDICES_PER_TRIANGLE = 3; + args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; } namespace render { @@ -500,7 +377,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { } } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const { if (_clusterBuffer) { batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer); } @@ -515,17 +392,14 @@ void ModelMeshPartPayload::render(RenderArgs* args) { } gpu::Batch& batch = *(args->_batch); - auto locations = args->_shapePipeline->locations; - assert(locations); - bindTransform(batch, locations, args->_renderMode); + bindTransform(batch, args->_renderMode); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); // apply material properties - bindMaterial(batch, locations, args->_enableTexturing); - + args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 8160b9f009..7ec02ae7f0 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -17,7 +17,6 @@ #include #include -#include #include @@ -49,8 +48,7 @@ public: // ModelMeshPartPayload functions to perform render void drawCall(gpu::Batch& batch) const; virtual void bindMesh(gpu::Batch& batch); - virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool enableTextures) const; - virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const; + virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const; // Payload resource cached values Transform _drawTransform; @@ -63,7 +61,7 @@ public: mutable graphics::Box _worldBound; std::shared_ptr _drawMesh; - std::shared_ptr _drawMaterial; + std::shared_ptr _drawMaterial; graphics::Mesh::Part _drawPart; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } @@ -109,7 +107,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; - void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; + void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override; void computeAdjustedLocalBound(const std::vector& clusterTransforms); diff --git a/libraries/render/CMakeLists.txt b/libraries/render/CMakeLists.txt index 1d88c3e5f5..4f8673cde6 100644 --- a/libraries/render/CMakeLists.txt +++ b/libraries/render/CMakeLists.txt @@ -2,7 +2,9 @@ set(TARGET_NAME render) AUTOSCRIBE_SHADER_LIB(gpu graphics) setup_hifi_library() -# render needs octree only for getAccuracyAngle(float, int) -link_hifi_libraries(shared ktx gpu graphics octree) +# render needs octree only for getAccuracyAngle(float, int), and model-networking for TextureCache +link_hifi_libraries(shared ktx gpu graphics octree model-networking) +include_hifi_library_headers(networking) +include_hifi_library_headers(image) target_nsight() diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 4254280fa1..db4ff604ca 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -15,6 +15,8 @@ #include +#include + using namespace render; ShapePipeline::CustomFactoryMap ShapePipeline::_globalCustomFactoryMap; @@ -157,3 +159,122 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke return shapePipeline; } + +void ShapePipeline::bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) const { + if (!material) { + return; + } + + auto textureCache = DependencyManager::get(); + + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, material->getSchemaBuffer()); + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, material->getTexMapArrayBuffer()); + + const auto& materialKey = material->getKey(); + const auto& textureMaps = material->getTextureMaps(); + + int numUnlit = 0; + if (materialKey.isUnlit()) { + numUnlit++; + } + + if (!enableTextures) { + batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + return; + } + + // Albedo + if (materialKey.isAlbedoMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); + } else { + batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture()); + } + } + + // Roughness map + if (materialKey.isRoughnessMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); + } + } + + // Normal map + if (materialKey.isNormalMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); + } + } + + // Metallic map + if (materialKey.isMetallicMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); + } + } + + // Occlusion map + if (materialKey.isOcclusionMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); + } + } + + // Scattering map + if (materialKey.isScatteringMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); + } + } + + // Emissive / Lightmap + if (materialKey.isLightmapMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); + + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); + } + } else if (materialKey.isEmissiveMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); + + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + } + } +} diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index be77e2f95e..3e358e9ac2 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -18,6 +18,8 @@ #include "Args.h" +#include + namespace render { class Item; class ShapePlumber; @@ -294,6 +296,8 @@ public: void prepareShapeItem(Args* args, const ShapeKey& key, const Item& shape); + void bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) const; + protected: friend class ShapePlumber; diff --git a/libraries/shared/src/MaterialMode.cpp b/libraries/shared/src/MaterialMode.cpp new file mode 100644 index 0000000000..cb656a7bf7 --- /dev/null +++ b/libraries/shared/src/MaterialMode.cpp @@ -0,0 +1,24 @@ +// +// Created by Sam Gondelman on 1/17/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MaterialMode.h" + +const char* materialModeNames[] = { + "uv", + "projected" +}; + +static const size_t MATERIAL_MODE_NAMES = (sizeof(materialModeNames) / sizeof((materialModeNames)[0])); + +QString MaterialModeHelpers::getNameForMaterialMode(MaterialMode mode) { + if (((int)mode <= 0) || ((int)mode >= (int)MATERIAL_MODE_NAMES)) { + mode = (MaterialMode)0; + } + + return materialModeNames[(int)mode]; +} \ No newline at end of file diff --git a/libraries/shared/src/MaterialMode.h b/libraries/shared/src/MaterialMode.h index 05c6d295a5..a933693f75 100644 --- a/libraries/shared/src/MaterialMode.h +++ b/libraries/shared/src/MaterialMode.h @@ -9,10 +9,17 @@ #ifndef hifi_MaterialMode_h #define hifi_MaterialMode_h +#include "QString" + enum MaterialMode { UV = 0, PROJECTED }; +class MaterialModeHelpers { +public: + static QString getNameForMaterialMode(MaterialMode mode); +}; + #endif // hifi_MaterialMode_h diff --git a/scripts/developer/tests/toolbarTest.js b/scripts/developer/tests/toolbarTest.js index e21fbd8e19..dfc97ebe39 100644 --- a/scripts/developer/tests/toolbarTest.js +++ b/scripts/developer/tests/toolbarTest.js @@ -11,7 +11,8 @@ var toolBar = (function() { newTextButton, newWebButton, newZoneButton, - newParticleButton + newParticleButton, + newMaterialButton var toolIconUrl = Script.resolvePath("../../system/assets/images/tools/"); @@ -89,6 +90,13 @@ var toolBar = (function() { visible: false }); + newMaterialButton = toolBar.addButton({ + objectName: "newMaterialButton", + imageURL: toolIconUrl + "model-01.svg", + alpha: 0.9, + visible: false + }); + that.setActive(false); newModelButton.clicked(); } @@ -109,8 +117,8 @@ var toolBar = (function() { newTextButton.writeProperty('visible', doShow); newWebButton.writeProperty('visible', doShow); newZoneButton.writeProperty('visible', doShow); - newModelButton.writeProperty('visible', doShow); newParticleButton.writeProperty('visible', doShow); + newMaterialButton.writeProperty('visible', doShow); }; initialize(); diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 87cd3e0faf..928d8ba1fa 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -251,7 +251,7 @@ var toolBar = (function () { // Align entity with Avatar orientation. properties.rotation = MyAvatar.orientation; - var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web"]; + var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web", "Material"]; if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) { // Adjust position of entity per bounding box prior to creating it. @@ -354,6 +354,9 @@ var toolBar = (function () { var SHAPE_TYPE_SPHERE = 5; var DYNAMIC_DEFAULT = false; + var MATERIAL_MODE_UV = 0; + var MATERIAL_MODE_PROJECTED = 1; + function handleNewModelDialogResult(result) { if (result) { var url = result.textInput; @@ -394,6 +397,28 @@ var toolBar = (function () { } } + function handleNewMaterialDialogResult(result) { + if (result) { + var json = result.textInput; + var materialMode; + switch (result.comboBox) { + case MATERIAL_MODE_PROJECTED: + materialMode = "projected"; + break; + default: + shapeType = "uv"; + } + + if (json) { + createNewEntity({ + type: "Material", + materialURL: json, + materialMode: materialMode + }); + } + } + } + function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.popFromStack(); @@ -404,6 +429,9 @@ var toolBar = (function () { case "newEntityButtonClicked": buttonHandlers[message.params.buttonName](); break; + case "newMaterialDialogAdd": + handleNewMaterialDialogResult(message.params); + break; } } @@ -614,6 +642,17 @@ var toolBar = (function () { }); }); + addButton("newMaterialButton", "model-01.svg", function () { + var MATERIAL_MODES = []; + MATERIAL_MODES[MATERIAL_MODE_UV] = "UV space material"; + MATERIAL_MODES[MATERIAL_MODE_PROJECTED] = "3D projected material"; + var MATERIAL_MODE_DEFAULT = MATERIAL_MODE_UV; + + // tablet version of new material dialog + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet.pushOntoStack("NewMaterialDialog.qml"); + }); + that.setActive(false); } @@ -1983,7 +2022,7 @@ var PropertiesTool = function (opts) { ); } Entities.editEntity(selectionManager.selections[0], data.properties); - if (data.properties.name !== undefined || data.properties.modelURL !== undefined || + if (data.properties.name !== undefined || data.properties.modelURL !== undefined || data.properties.materialURL !== undefined || data.properties.visible !== undefined || data.properties.locked !== undefined) { entityListTool.sendUpdate(); } @@ -1994,7 +2033,7 @@ var PropertiesTool = function (opts) { parentSelectedEntities(); } else if (data.type === 'unparent') { unparentSelectedEntities(); - } else if (data.type === 'saveUserData'){ + } else if (data.type === 'saveUserData') { //the event bridge and json parsing handle our avatar id string differently. var actualID = data.id.split('"')[1]; Entities.editEntity(actualID, data.properties); diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 736d42d593..96084f355f 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -448,7 +448,7 @@ input[type=checkbox]:checked + label:hover { border: 1.5pt solid black; } -.shape-section, .light-section, .model-section, .web-section, .hyperlink-section, .text-section, .zone-section { +.shape-section, .light-section, .model-section, .web-section, .hyperlink-section, .text-section, .zone-section, .material-section { display: table; } @@ -570,6 +570,7 @@ hr { .physical-group[collapsed="true"] ~ .physical-group, .behavior-group[collapsed="true"] ~ .behavior-group, .model-group[collapsed="true"] ~ .model-group, +.material-group[collapsed="true"] ~ .material-group, .light-group[collapsed="true"] ~ .light-group { display: none !important; } @@ -1386,7 +1387,7 @@ input#reset-to-natural-dimensions { } -#static-userdata{ +#static-userdata { display: none; z-index: 99; position: absolute; @@ -1397,7 +1398,7 @@ input#reset-to-natural-dimensions { background-color: #2e2e2e; } -#userdata-saved{ +#userdata-saved { margin-top:5px; font-size:16px; display:none; @@ -1454,6 +1455,9 @@ input#reset-to-natural-dimensions { order: 6; } +#properties-list.ShapeMenu #material, +#properties-list.BoxMenu #material, +#properties-list.SphereMenu #material, #properties-list.ShapeMenu #light, #properties-list.BoxMenu #light, #properties-list.SphereMenu #light, @@ -1490,6 +1494,7 @@ input#reset-to-natural-dimensions { } /* items to hide */ +#properties-list.ParticleEffectMenu #material, #properties-list.ParticleEffectMenu #base-color-section, #properties-list.ParticleEffectMenu #hyperlink, #properties-list.ParticleEffectMenu #light, @@ -1524,6 +1529,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.LightMenu #material, #properties-list.LightMenu #model, #properties-list.LightMenu #zone, #properties-list.LightMenu #text, @@ -1560,6 +1566,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.ModelMenu #material, #properties-list.ModelMenu #light, #properties-list.ModelMenu #zone, #properties-list.ModelMenu #text, @@ -1596,6 +1603,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.ZoneMenu #material, #properties-list.ZoneMenu #light, #properties-list.ZoneMenu #model, #properties-list.ZoneMenu #text, @@ -1632,6 +1640,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.WebMenu #material, #properties-list.WebMenu #light, #properties-list.WebMenu #model, #properties-list.WebMenu #zone, @@ -1669,6 +1678,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.TextMenu #material, #properties-list.TextMenu #light, #properties-list.TextMenu #model, #properties-list.TextMenu #zone, @@ -1681,6 +1691,39 @@ input#reset-to-natural-dimensions { display: none } +/* ----- Order of Menu items for Material ----- */ +#properties-list.MaterialMenu #general { + order: 1; +} +#properties-list.MaterialMenu #material { + order: 2; +} +#properties-list.MaterialMenu #spatial { + order: 3; +} +#properties-list.MaterialMenu #hyperlink { + order: 4; +} +#properties-list.MaterialMenu #behavior { + order: 5; +} + +/* sections to hide */ +#properties-list.MaterialMenu #physical, +#properties-list.MaterialMenu #collision-info, +#properties-list.MaterialMenu #model, +#properties-list.MaterialMenu #light, +#properties-list.MaterialMenu #zone, +#properties-list.MaterialMenu #text, +#properties-list.MaterialMenu #web { + display: none; +} +/* items to hide */ +#properties-list.MaterialMenu #shape-list, +#properties-list.MaterialMenu #base-color-section { + display: none +} + /* Currently always hidden */ #properties-list #polyvox { diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index b93974ee77..93d22180c9 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -761,6 +761,51 @@ +
+ + MaterialM + +
+
+ + +
+
+
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+
+ +
+
+ diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 72092b66ca..af9d106149 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -24,7 +24,8 @@ var ICON_FOR_TYPE = { Zone: "o", PolyVox: "", Multiple: "", - PolyLine: "" + PolyLine: "", + Material: "" }; var EDITOR_TIMEOUT_DURATION = 1500; @@ -77,7 +78,6 @@ function disableProperties() { if ($('#userdata-editor').css('display') === "block" && elLocked.checked === true) { showStaticUserData(); } - } function showElements(els, show) { @@ -192,6 +192,19 @@ function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, el }; } +function createEmitVec4PropertyUpdateFunction(property, elX, elY, elZ, elW) { + return function () { + var properties = {}; + properties[property] = { + x: elX.value, + y: elY.value, + z: elZ.value, + w: elW.value + }; + updateProperties(properties); + }; +} + function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) { return function() { var properties = {}; @@ -473,7 +486,6 @@ function bindAllNonJSONEditorElements() { } else { if ($('#userdata-editor').css('height') !== "0px") { saveJSONUserData(true); - } } }); @@ -621,6 +633,16 @@ function loaded() { var elModelTextures = document.getElementById("property-model-textures"); var elModelOriginalTextures = document.getElementById("property-model-original-textures"); + var elMaterialURL = document.getElementById("property-material-url"); + var elMaterialMode = document.getElementById("property-material-mode"); + var elBlendFactor = document.getElementById("property-blend-factor"); + var elPriority = document.getElementById("property-priority"); + var elShapeID = document.getElementById("property-shape-id"); + var elMaterialBoundsX = document.getElementById("property-material-bounds-x"); + var elMaterialBoundsY = document.getElementById("property-material-bounds-y"); + var elMaterialBoundsZ = document.getElementById("property-material-bounds-z"); + var elMaterialBoundsW = document.getElementById("property-material-bounds-w"); + var elWebSourceURL = document.getElementById("property-web-source-url"); var elWebDPI = document.getElementById("property-web-dpi"); @@ -1105,6 +1127,17 @@ function loaded() { elXTextureURL.value = properties.xTextureURL; elYTextureURL.value = properties.yTextureURL; elZTextureURL.value = properties.zTextureURL; + } else if (properties.type === "Material") { + elMaterialURL.value = properties.materialURL; + elMaterialMode.value = properties.materialMode; + setDropdownText(elMaterialMode); + elBlendFactor.value = properties.blendFactor.toFixed(2); + elPriority.value = properties.priority; + elShapeID.value = properties.shapeID; + elMaterialBoundsX.value = properties.materialBounds.x.toFixed(2); + elMaterialBoundsY.value = properties.materialBounds.y.toFixed(2); + elMaterialBoundsZ.value = properties.materialBounds.z.toFixed(2); + //elMaterialBoundsW.value = properties.materialBounds.w.toFixed(2); } if (properties.locked) { @@ -1375,6 +1408,19 @@ function loaded() { elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures')); + elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL')); + elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode')); + elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2)); + elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority')); + elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID')); + + var materialBoundsChangeFunction = createEmitVec4PropertyUpdateFunction('materialBounds', + elMaterialBoundsX, elMaterialBoundsY, elMaterialBoundsZ, elMaterialBoundsW); + elMaterialBoundsX.addEventListener('change', materialBoundsChangeFunction); + elMaterialBoundsY.addEventListener('change', materialBoundsChangeFunction); + elMaterialBoundsZ.addEventListener('change', materialBoundsChangeFunction); + elMaterialBoundsW.addEventListener('change', materialBoundsChangeFunction); + elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text')); elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera')); elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight')); diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index 9d9689000e..d53766ab4e 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -77,18 +77,24 @@ EntityListTool = function(opts) { var properties = Entities.getEntityProperties(id); if (!filterInView || Vec3.distance(properties.position, cameraPosition) <= searchRadius) { + var url = ""; + if (properties.type == "Model") { + url = properties.modelURL; + } else if (properties.type == "Material") { + url = properties.materialURL; + } entities.push({ id: id, name: properties.name, type: properties.type, - url: properties.type == "Model" ? properties.modelURL : "", + url: url, locked: properties.locked, visible: properties.visible, verticesCount: valueIfDefined(properties.renderInfo.verticesCount), texturesCount: valueIfDefined(properties.renderInfo.texturesCount), texturesSize: valueIfDefined(properties.renderInfo.texturesSize), hasTransparent: valueIfDefined(properties.renderInfo.hasTransparent), - isBaked: properties.type == "Model" ? properties.modelURL.toLowerCase().endsWith(".baked.fbx") : false, + isBaked: properties.type == "Model" ? url.toLowerCase().endsWith(".baked.fbx") : false, drawCalls: valueIfDefined(properties.renderInfo.drawCalls), hasScript: properties.script !== "" }); From 84cd0e15299d7bfd2d9132b6c6c1c17373ca7faa Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 5 Feb 2018 18:08:36 -0800 Subject: [PATCH 03/12] wip live material swapping on model entities, model overlays, avatars, and albedo swap on shape entities --- domain-server/CMakeLists.txt | 2 + .../icons/create-icons/126-material-01.svg | 9 + .../resources/qml/hifi/tablet/EditTabView.qml | 2 +- interface/src/Application.cpp | 36 +++ interface/src/ui/overlays/ModelOverlay.cpp | 26 ++ interface/src/ui/overlays/ModelOverlay.h | 5 + interface/src/ui/overlays/Overlay.cpp | 10 + interface/src/ui/overlays/Overlay.h | 6 + .../src/avatars-renderer/Avatar.cpp | 30 +++ .../src/avatars-renderer/Avatar.h | 8 + libraries/avatars/CMakeLists.txt | 3 +- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 5 + .../src/RenderableEntityItem.cpp | 13 + .../src/RenderableEntityItem.h | 6 + .../src/RenderableMaterialEntityItem.cpp | 26 +- .../src/RenderableMaterialEntityItem.h | 5 +- .../src/RenderableModelEntityItem.cpp | 26 ++ .../src/RenderableModelEntityItem.h | 7 + .../src/RenderableShapeEntityItem.cpp | 29 +- .../src/RenderableShapeEntityItem.h | 2 +- .../entities/src/DeleteEntityOperator.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 39 ++- libraries/entities/src/EntityItem.h | 22 +- .../entities/src/EntityItemProperties.cpp | 52 ++-- libraries/entities/src/EntityItemProperties.h | 8 +- .../entities/src/EntityItemPropertiesMacros.h | 43 ++- libraries/entities/src/EntityPropertyFlags.h | 4 +- libraries/entities/src/EntityTree.cpp | 48 +++- libraries/entities/src/EntityTree.h | 15 ++ libraries/entities/src/EntityTreeElement.cpp | 26 +- libraries/entities/src/EntityTreeElement.h | 3 +- libraries/entities/src/MaterialEntityItem.cpp | 253 +++++++++++++++--- libraries/entities/src/MaterialEntityItem.h | 43 ++- libraries/entities/src/ModelEntityItem.cpp | 2 +- libraries/entities/src/ShapeEntityItem.cpp | 7 + libraries/entities/src/ShapeEntityItem.h | 6 +- libraries/graphics/src/graphics/Material.cpp | 15 ++ libraries/graphics/src/graphics/Material.h | 36 +++ .../src/model-networking/ModelCache.cpp | 2 +- .../src/model-networking/ModelCache.h | 6 +- libraries/octree/src/OctreePacketData.cpp | 11 + libraries/octree/src/OctreePacketData.h | 5 +- .../render-utils/src/MeshPartPayload.cpp | 32 ++- libraries/render-utils/src/MeshPartPayload.h | 13 +- libraries/render-utils/src/Model.cpp | 44 +++ libraries/render-utils/src/Model.h | 3 + scripts/system/edit.js | 51 ++-- scripts/system/html/css/edit-style.css | 12 +- scripts/system/html/entityProperties.html | 29 +- scripts/system/html/js/entityProperties.js | 61 ++--- tools/jsdoc/package-lock.json | 138 ++++++++++ 52 files changed, 1038 insertions(+), 251 deletions(-) create mode 100644 interface/resources/icons/create-icons/126-material-01.svg create mode 100644 tools/jsdoc/package-lock.json diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index c1e275e4d3..f67be55b92 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -22,6 +22,8 @@ setup_memory_debugger() symlink_or_copy_directory_beside_target(${_SHOULD_SYMLINK_RESOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/resources" "resources") # link the shared hifi libraries +include_hifi_library_headers(gpu) +include_hifi_library_headers(graphics) link_hifi_libraries(embedded-webserver networking shared avatars) # find OpenSSL diff --git a/interface/resources/icons/create-icons/126-material-01.svg b/interface/resources/icons/create-icons/126-material-01.svg new file mode 100644 index 0000000000..9b6d92505f --- /dev/null +++ b/interface/resources/icons/create-icons/126-material-01.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index 65dd871fb2..6f97664e06 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -135,7 +135,7 @@ TabView { } NewEntityButton { - icon: "icons/create-icons/94-model-01.svg" + icon: "icons/create-icons/126-material-01.svg" text: "MATERIAL" onClicked: { editRoot.sendToScript({ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1a54c94d53..1cf8f0587f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1580,6 +1580,42 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); + EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->addMaterial(material, shapeID); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->removeMaterial(material, shapeID); + return true; + } + return false; + }); + + EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->addMaterial(material, shapeID); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->removeMaterial(material, shapeID); + return true; + } + return false; + }); + // Keyboard focus handling for Web overlays. auto overlays = &(qApp->getOverlays()); connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) { diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 4847650163..9e4835a76e 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -632,3 +632,29 @@ uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const { } return 0; } + +void ModelOverlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::addMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->addMaterial(material, shapeID); + } +} + +void ModelOverlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::removeMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->removeMaterial(material, shapeID); + } +} + +void ModelOverlay::processMaterials() { + assert(_model); + std::lock_guard lock(_materialsLock); + for (auto& shapeMaterialPair : _materials) { + auto material = shapeMaterialPair.second; + while (!material.empty()) { + _model->addMaterial(material.top(), shapeMaterialPair.first); + material.pop(); + } + } +} \ No newline at end of file diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 08c776c426..827f7f2d5b 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -59,6 +59,9 @@ public: void setDrawInFront(bool drawInFront) override; void setDrawHUDLayer(bool drawHUDLayer) override; + void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + protected: Transform evalRenderTransform() override; @@ -110,6 +113,8 @@ private: bool _drawInFrontDirty { false }; bool _drawInHUDDirty { false }; + void processMaterials(); + }; #endif // hifi_ModelOverlay_h diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 3c952b8338..368ed04062 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -235,3 +235,13 @@ QVector qVectorOverlayIDFromScriptValue(const QScriptValue& array) { } return newVector; } + +void Overlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); +} + +void Overlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); +} \ No newline at end of file diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index e9271f3c3f..4cb3f7c84d 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -91,6 +91,9 @@ public: unsigned int getStackOrder() const { return _stackOrder; } void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; } + virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + protected: float updatePulse(); @@ -117,6 +120,9 @@ protected: static const xColor DEFAULT_OVERLAY_COLOR; static const float DEFAULT_ALPHA; + std::unordered_map _materials; + std::mutex _materialsLock; + private: OverlayID _overlayID; // only used for non-3d overlays }; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 86635cd3bf..4cd9bbedd7 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -570,6 +570,7 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc } transaction.resetItem(_renderItemID, avatarPayloadPointer); _skeletonModel->addToScene(scene, transaction); + processMaterials(); for (auto& attachmentModel : _attachmentModels) { attachmentModel->addToScene(scene, transaction); } @@ -761,6 +762,7 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) { _skeletonModel->removeFromScene(scene, transaction); _skeletonModel->addToScene(scene, transaction); + processMaterials(); canTryFade = true; _isAnimatingScale = true; } @@ -1760,3 +1762,31 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const { return DEFAULT_AVATAR_EYE_HEIGHT; } } + +void Avatar::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); + if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { + _skeletonModel->addMaterial(material, shapeID); + } +} + +void Avatar::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); + if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { + _skeletonModel->removeMaterial(material, shapeID); + } +} + +void Avatar::processMaterials() { + assert(_skeletonModel); + std::lock_guard lock(_materialsLock); + for (auto& shapeMaterialPair : _materials) { + auto material = shapeMaterialPair.second; + while (!material.empty()) { + _skeletonModel->addMaterial(material.top(), shapeMaterialPair.first); + material.pop(); + } + } +} \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index c2b404a925..9c355159d8 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -272,6 +272,9 @@ public: virtual void setAvatarEntityDataChanged(bool value) override; + void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + public slots: // FIXME - these should be migrated to use Pose data instead @@ -397,6 +400,11 @@ protected: float _displayNameAlpha { 1.0f }; ThreadSafeValueCache _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT }; + + std::unordered_map _materials; + std::mutex _materialsLock; + + void processMaterials(); }; #endif // hifi_Avatar_h diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index fc6d15cced..13fda28f40 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -1,3 +1,4 @@ set(TARGET_NAME avatars) setup_hifi_library(Network Script) -link_hifi_libraries(shared networking) +include_hifi_library_headers(gpu) +link_hifi_libraries(shared networking graphics) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 74888283df..1bbc8cc1a5 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2558,4 +2558,4 @@ void AvatarEntityMapFromScriptValue(const QScriptValue& object, AvatarEntityMap& value[EntityID] = binaryEntityProperties; } -} +} \ No newline at end of file diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a363fb6d15..b7d594f1dc 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -54,6 +54,8 @@ #include "HeadData.h" #include "PathUtils.h" +#include + using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; using AvatarHash = QHash; @@ -694,6 +696,9 @@ public: bool getIsReplicated() const { return _isReplicated; } + virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID) {} + virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) {} + signals: void displayNameChanged(); void sessionDisplayNameChanged(); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 49ddf111c3..2f92790d18 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -146,6 +146,9 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _entity(entity _needsRenderUpdate = true; emit requestRenderUpdate(); }); + _materials = entity->getMaterials(); + connect(entity.get(), &EntityItem::addMaterialToRenderItem, this, &EntityRenderer::addMaterial); + connect(entity.get(), &EntityItem::removeMaterialFromRenderItem, this, &EntityRenderer::removeMaterial); } EntityRenderer::~EntityRenderer() { } @@ -399,4 +402,14 @@ void EntityRenderer::onAddToScene(const EntityItemPointer& entity) { void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) { entity->deregisterChangeHandler(_changeHandlerId); QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr); +} + +void EntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); +} + +void EntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); } \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index ce5bfb30a4..f58b540aef 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -101,6 +101,10 @@ protected: return result; } +public slots: + virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + signals: void requestRenderUpdate(); @@ -129,6 +133,8 @@ protected: // Only touched on the rendering thread bool _renderUpdateQueued{ false }; + std::unordered_map _materials; + std::mutex _materialsLock; private: // The base class relies on comparing the model transform to the entity transform in order diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 83754c1c16..d541d99c4c 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -15,12 +15,18 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP if (entity->getMaterial() != _drawMaterial) { return true; } + if (entity->getParentID() != _parentID || entity->getClientOnly() != _clientOnly || entity->getOwningAvatarID() != _owningAvatarID) { + return true; + } return false; } void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { withWriteLock([&] { _drawMaterial = entity->getMaterial(); + _parentID = entity->getParentID(); + _clientOnly = entity->getClientOnly(); + _owningAvatarID = entity->getOwningAvatarID(); _renderTransform = getModelTransform(); const float MATERIAL_ENTITY_SCALE = 0.5f; _renderTransform.postScale(MATERIAL_ENTITY_SCALE); @@ -30,7 +36,7 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& ItemKey MaterialEntityRenderer::getKey() { ItemKey::Builder builder; - builder.withTypeShape(); + builder.withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); if (!_visible) { builder.withInvisible(); @@ -215,13 +221,25 @@ void MaterialEntityRenderer::generateMesh() { void MaterialEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderableMaterialEntityItem::render"); Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - batch.setModelTransform(_renderTransform); + // Don't render if our parent is set or our material is null + QUuid parentID; + Transform renderTransform; + graphics::MaterialPointer drawMaterial; + withReadLock([&] { + parentID = _clientOnly ? _owningAvatarID : _parentID; + renderTransform = _renderTransform; + drawMaterial = _drawMaterial; + }); + if (!parentID.isNull() || !drawMaterial) { + return; + } + + batch.setModelTransform(renderTransform); // bind the material - args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_shapePipeline->bindMaterial(drawMaterial, batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index 166ad762cc..af8cef9351 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -31,6 +31,9 @@ private: ItemKey getKey() override; ShapeKey getShapeKey() override; + QUuid _parentID; + bool _clientOnly; + QUuid _owningAvatarID; Transform _renderTransform; std::shared_ptr _drawMaterial; @@ -47,7 +50,7 @@ private: static void addVertex(std::vector& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv); const int SLICES = 15; const int STACKS = 9; - const float M_PI_TIMES_2 = 2.0f * M_PI; + const float M_PI_TIMES_2 = 2.0f * (float)M_PI; }; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 137203f475..739ccd9738 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1380,6 +1380,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce auto entityRenderer = static_cast(&data); entityRenderer->setSubRenderItemIDs(newRenderItemIDs); }); + processMaterials(); } } @@ -1466,3 +1467,28 @@ void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStr } } +void ModelEntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::addMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->addMaterial(material, shapeID); + } +} + +void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::removeMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->removeMaterial(material, shapeID); + } +} + +void ModelEntityRenderer::processMaterials() { + assert(_model); + std::lock_guard lock(_materialsLock); + for (auto& shapeMaterialPair : _materials) { + auto material = shapeMaterialPair.second; + while (!material.empty()) { + _model->addMaterial(material.top(), shapeMaterialPair.first); + material.pop(); + } + } +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 33fc9910a0..75c6639902 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -138,10 +138,15 @@ namespace render { namespace entities { class ModelEntityRenderer : public TypedEntityRenderer { using Parent = TypedEntityRenderer; friend class EntityRenderer; + Q_OBJECT public: ModelEntityRenderer(const EntityItemPointer& entity); +public slots: + void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + protected: virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override; virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override; @@ -194,6 +199,8 @@ private: uint64_t _lastAnimated { 0 }; render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() }; + + void processMaterials(); }; } } // namespace diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index cdee2c5ec9..8163b14608 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -54,8 +54,7 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin if (_lastUserData != entity->getUserData()) { return true; } - glm::vec4 newColor(toGlm(entity->getXColor()), entity->getLocalRenderAlpha()); - if (newColor != _color) { + if (_material != entity->getMaterial()) { return true; } @@ -78,7 +77,9 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _procedural.setProceduralData(ProceduralData::parse(_lastUserData)); } - _color = vec4(toGlm(entity->getXColor()), entity->getLocalRenderAlpha()); + removeMaterial(_material, 0); + _material = entity->getMaterial(); + addMaterial(_material, 0); _shape = entity->getShape(); _position = entity->getWorldPosition(); @@ -112,14 +113,13 @@ bool ShapeEntityRenderer::isTransparent() const { return Parent::isTransparent(); } - - void ShapeEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderableShapeEntityItem::render"); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; + std::shared_ptr mat; auto geometryCache = DependencyManager::get(); GeometryCache::Shape geometryShape; bool proceduralRender = false; @@ -127,15 +127,22 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { withReadLock([&] { geometryShape = geometryCache->getShapeForEntityShape(_shape); batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation - outColor = _color; - if (_procedural.isReady()) { - _procedural.prepare(batch, _position, _dimensions, _orientation); - outColor = _procedural.getColor(_color); - outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; - proceduralRender = true; + mat = _materials[0].top(); + if (mat) { + outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity()); + if (_procedural.isReady()) { + _procedural.prepare(batch, _position, _dimensions, _orientation); + outColor = _procedural.getColor(outColor); + outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; + proceduralRender = true; + } } }); + if (!mat) { + return; + } + if (proceduralRender) { if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { geometryCache->renderWireShape(batch, geometryShape, outColor); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index 433cb41ad2..c913544255 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -34,7 +34,7 @@ private: QString _lastUserData; Transform _renderTransform; entity::Shape _shape { entity::Sphere }; - glm::vec4 _color; + std::shared_ptr _material; glm::vec3 _position; glm::vec3 _dimensions; glm::quat _orientation; diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index cbd0ad7839..347d40ea49 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -93,7 +93,7 @@ bool DeleteEntityOperator::preRecursion(const OctreeElementPointer& element) { // and we can stop searching. if (entityTreeElement == details.containingElement) { EntityItemPointer theEntity = details.entity; - bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element + bool entityDeleted = entityTreeElement->removeEntityItem(theEntity, true); // remove it from the element assert(entityDeleted); (void)entityDeleted; // quite warning _tree->clearEntityMapEntry(details.entity->getEntityItemID()); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ed13a46414..43510864ba 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -60,14 +60,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : } EntityItem::~EntityItem() { - // clear out any left-over actions - EntityTreeElementPointer element = _element; // use local copy of _element for logic below - EntityTreePointer entityTree = element ? element->getTree() : nullptr; - EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr; - if (simulation) { - clearActions(simulation); - } - // these pointers MUST be correct at delete, else we probably have a dangling backpointer // to this EntityItem in the corresponding data structure. assert(!_simulated); @@ -2937,3 +2929,34 @@ void EntityItem::retrieveMarketplacePublicKey() { networkReply->deleteLater(); }); } + +void EntityItem::preDelete() { + // clear out any left-over actions + EntityTreeElementPointer element = _element; // use local copy of _element for logic below + EntityTreePointer entityTree = element ? element->getTree() : nullptr; + EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr; + if (simulation) { + clearActions(simulation); + } +} + +void EntityItem::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); + emit addMaterialToRenderItem(material, shapeID); +} + +void EntityItem::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); + emit removeMaterialFromRenderItem(material, shapeID); +} + +std::unordered_map EntityItem::getMaterials() { + std::unordered_map toReturn; + { + std::lock_guard lock(_materialsLock); + toReturn = _materials; + } + return toReturn; +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5f84bcc311..b2804a2e86 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -36,6 +36,8 @@ #include "SimulationFlags.h" #include "EntityDynamicInterface.h" +#include "graphics/Material.h" + class EntitySimulation; class EntityTreeElement; class EntityTreeElementExtraEncodeData; @@ -49,7 +51,6 @@ typedef std::shared_ptr EntityTreeElementPointer; using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr; - #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() override { }; @@ -443,10 +444,10 @@ public: void scriptHasUnloaded() { _loadedScript = ""; _loadedScriptTimestamp = 0; } bool getClientOnly() const { return _clientOnly; } - void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; } + virtual void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; } // if this entity is client-only, which avatar is it associated with? QUuid getOwningAvatarID() const { return _owningAvatarID; } - void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; } + virtual void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; } virtual bool wantsHandControllerPointerEvents() const { return false; } virtual bool wantsKeyboardFocus() const { return false; } @@ -477,8 +478,18 @@ public: void setCauterized(bool value) { _cauterized = value; } bool getCauterized() const { return _cauterized; } + virtual void postAdd() {} + virtual void preDelete(); + virtual void postParentFixup() {} + + void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + std::unordered_map getMaterials(); + signals: void requestRenderUpdate(); + void addMaterialToRenderItem(graphics::MaterialPointer material, quint16 shapeID); + void removeMaterialFromRenderItem(graphics::MaterialPointer material, quint16 shapeID); protected: QHash _changeHandlers; @@ -631,6 +642,11 @@ protected: quint64 _lastUpdatedQueryAACubeTimestamp { 0 }; bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera + +private: + std::unordered_map _materials; + std::mutex _materialsLock; + }; #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 965252abf4..19aa6990db 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -360,7 +360,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); CHECK_PROPERTY_CHANGE(PROP_PARENT_SHAPE_ID, shapeID); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BOUNDS, materialBounds); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_POS, materialPos); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_SCALE, materialScale); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_ROT, materialRot); // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); @@ -664,7 +666,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BOUNDS, materialBounds); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_POS, materialPos); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_SCALE, materialScale); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_ROT, materialRot); } if (!skipDefaults && !strictSemantics) { @@ -801,11 +805,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); - COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(materialMode, MaterialMode, setMaterialMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(materialMode, MaterialMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor); - COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, int, setPriority); - COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, int, setShapeID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialBounds, glmVec4, setMaterialBounds); + COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority); + COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, quint16, setShapeID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialPos, glmVec2, setMaterialPos); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialScale, glmVec2, setMaterialScale); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialRot, float, setMaterialRot); // Certifiable Properties COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); @@ -1163,9 +1169,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, quint16); + ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_ROT, MaterialRot, materialRot, float); // Certifiable Properties ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); @@ -1557,7 +1565,9 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, properties.getBlendFactor()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, properties.getShapeID()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, properties.getMaterialBounds()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, properties.getMaterialPos()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, properties.getMaterialScale()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, properties.getMaterialRot()); } APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); @@ -1921,9 +1931,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BOUNDS, glmVec4, setMaterialBounds); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_POS, glmVec2, setMaterialPos); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_SCALE, glmVec2, setMaterialScale); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_ROT, float, setMaterialRot); } READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); @@ -2104,7 +2116,9 @@ void EntityItemProperties::markAllChanged() { _blendFactorChanged = true; _priorityChanged = true; _shapeIDChanged = true; - _materialBoundsChanged = true; + _materialPosChanged = true; + _materialScaleChanged = true; + _materialRotChanged = true; // Certifiable Properties _itemNameChanged = true; @@ -2444,8 +2458,14 @@ QList EntityItemProperties::listChangedProperties() { if (shapeIDChanged()) { out += "shapeID"; } - if (materialBoundsChanged()) { - out += "materialBounds"; + if (materialPosChanged()) { + out += "materialPos"; + } + if (materialScaleChanged()) { + out += "materialScale"; + } + if (materialRotChanged()) { + out += "materialRot"; } // Certifiable Properties diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 9bedff41df..a8a79b6303 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -225,9 +225,11 @@ public: DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, ""); DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode, UV); DEFINE_PROPERTY_REF(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float, 1.0f); - DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t, 0); - DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t, 0); - DEFINE_PROPERTY_REF(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4, glm::vec4(0, 0, 1, 1)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, quint16, 0); + DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16, 0); + DEFINE_PROPERTY_REF(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2, glm::vec2(0, 0)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2, glm::vec2(1, 1)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_ROT, MaterialRot, materialRot, float, 0); // Certifiable Properties - related to Proof of Purchase certificates DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 2609fe237d..51a23b6867 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -101,6 +101,7 @@ changedProperties += P; \ } +inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec2& v) { return vec2toScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3toScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); } @@ -183,8 +184,8 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu properties.setProperty(#P, V); \ } +typedef glm::vec2 glmVec2; typedef glm::vec3 glmVec3; -typedef glm::vec4 glmVec4; typedef glm::quat glmQuat; typedef QVector qVectorVec3; typedef QVector qVectorQuat; @@ -222,6 +223,23 @@ inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& return QByteArray::fromBase64(b64.toUtf8()); } +inline glmVec2 glmVec2_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = false; /// assume it can't be converted + QScriptValue x = v.property("x"); + QScriptValue y = v.property("y"); + if (x.isValid() && y.isValid()) { + glm::vec4 newValue(0); + newValue.x = x.toVariant().toFloat(); + newValue.y = y.toVariant().toFloat(); + isValid = !glm::isnan(newValue.x) && + !glm::isnan(newValue.y); + if (isValid) { + return newValue; + } + } + return glm::vec2(0); +} + inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = false; /// assume it can't be converted QScriptValue x = v.property("x"); @@ -242,29 +260,6 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal return glm::vec3(0); } -inline glmVec4 glmVec4_convertFromScriptValue(const QScriptValue& v, bool& isValid) { - isValid = false; /// assume it can't be converted - QScriptValue x = v.property("x"); - QScriptValue y = v.property("y"); - QScriptValue z = v.property("z"); - QScriptValue w = v.property("w"); - if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { - glm::vec4 newValue(0); - newValue.x = x.toVariant().toFloat(); - newValue.y = y.toVariant().toFloat(); - newValue.z = z.toVariant().toFloat(); - newValue.w = w.toVariant().toFloat(); - isValid = !glm::isnan(newValue.x) && - !glm::isnan(newValue.y) && - !glm::isnan(newValue.z) && - !glm::isnan(newValue.w); - if (isValid) { - return newValue; - } - } - return glm::vec4(0); -} - inline AACube AACube_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; AACube result; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index bd573423a3..17ebddbe9d 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -232,7 +232,9 @@ enum EntityPropertyList { PROP_MATERIAL_BLEND_FACTOR, PROP_MATERIAL_PRIORITY, PROP_PARENT_SHAPE_ID, - PROP_MATERIAL_BOUNDS, + PROP_MATERIAL_POS, + PROP_MATERIAL_SCALE, + PROP_MATERIAL_ROT, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bf29f3bec9..775b3bd2f7 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1732,15 +1732,19 @@ void EntityTree::fixupNeedsParentFixups() { } }); entity->locationChanged(true); - } else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) { - // this is a child of an avatar, which the entity server will never have - // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. - if (!_childrenOfAvatars.contains(entity->getParentID())) { - _childrenOfAvatars[entity->getParentID()] = QSet(); + entity->postParentFixup(); + } else if (_avatarIDs.contains(entity->getParentID())) { + if (getIsServer()) { + // this is a child of an avatar, which the entity server will never have + // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. + if (!_childrenOfAvatars.contains(entity->getParentID())) { + _childrenOfAvatars[entity->getParentID()] = QSet(); + } + _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); } - _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); doMove = true; iter.remove(); // and pull it out of the list + entity->postParentFixup(); } if (queryAACubeSuccess && doMove) { @@ -2378,3 +2382,35 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const { return entity->getJointNames(); } +std::function EntityTree::_addMaterialToAvatarOperator = nullptr; +std::function EntityTree::_removeMaterialFromAvatarOperator = nullptr; +std::function EntityTree::_addMaterialToOverlayOperator = nullptr; +std::function EntityTree::_removeMaterialFromOverlayOperator = nullptr; + +bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + if (_addMaterialToAvatarOperator) { + return _addMaterialToAvatarOperator(avatarID, material, shapeID); + } + return false; +} + +bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + if (_removeMaterialFromAvatarOperator) { + return _removeMaterialFromAvatarOperator(avatarID, material, shapeID); + } + return false; +} + +bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + if (_addMaterialToOverlayOperator) { + return _addMaterialToOverlayOperator(overlayID, material, shapeID); + } + return false; +} + +bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + if (_removeMaterialFromOverlayOperator) { + return _removeMaterialFromOverlayOperator(overlayID, material, shapeID); + } + return false; +} \ No newline at end of file diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8cb89d6493..a02ce900ff 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -280,6 +280,16 @@ public: void setMyAvatar(std::shared_ptr myAvatar) { _myAvatar = myAvatar; } + static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } + static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } + static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); + static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); + + static void setAddMaterialToOverlayOperator(std::function addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; } + static void setRemoveMaterialFromOverlayOperator(std::function removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; } + static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); + static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); + signals: void deletingEntity(const EntityItemID& entityID); void deletingEntityPointer(EntityItem* entityID); @@ -387,6 +397,11 @@ private: void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation); std::shared_ptr _myAvatar{ nullptr }; + + static std::function _addMaterialToAvatarOperator; + static std::function _removeMaterialFromAvatarOperator; + static std::function _addMaterialToOverlayOperator; + static std::function _removeMaterialFromOverlayOperator; }; #endif // hifi_EntityTree_h diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index c9e1ecc3f1..980ed1c104 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -896,6 +896,7 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI void EntityTreeElement::cleanupEntities() { withWriteLock([&] { foreach(EntityItemPointer entity, _entityItems) { + entity->preDelete(); // NOTE: only EntityTreeElement should ever be changing the value of entity->_element // NOTE: We explicitly don't delete the EntityItem here because since we only // access it by smart pointers, when we remove it from the _entityItems @@ -907,26 +908,10 @@ void EntityTreeElement::cleanupEntities() { bumpChangedContent(); } -bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { - bool foundEntity = false; - withWriteLock([&] { - uint16_t numberOfEntities = _entityItems.size(); - for (uint16_t i = 0; i < numberOfEntities; i++) { - EntityItemPointer& entity = _entityItems[i]; - if (entity->getEntityItemID() == id) { - foundEntity = true; - // NOTE: only EntityTreeElement should ever be changing the value of entity->_element - entity->_element = NULL; - _entityItems.removeAt(i); - bumpChangedContent(); - break; - } - } - }); - return foundEntity; -} - -bool EntityTreeElement::removeEntityItem(EntityItemPointer entity) { +bool EntityTreeElement::removeEntityItem(EntityItemPointer entity, bool deletion) { + if (deletion) { + entity->preDelete(); + } int numEntries = 0; withWriteLock([&] { numEntries = _entityItems.removeAll(entity); @@ -955,6 +940,7 @@ void EntityTreeElement::addEntityItem(EntityItemPointer entity) { }); bumpChangedContent(); entity->_element = getThisPointer(); + entity->postAdd(); } // will average a "common reduced LOD view" from the the child elements... diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index a524904c71..2313bde0c4 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -210,8 +210,7 @@ public: void getEntitiesInside(const AACube& box, QVector& foundEntities); void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities - bool removeEntityWithEntityItemID(const EntityItemID& id); - bool removeEntityItem(EntityItemPointer entity); + bool removeEntityItem(EntityItemPointer entity, bool deletion = false); bool containsEntityBounds(EntityItemPointer entity) const; bool bestFitEntityBounds(EntityItemPointer entity) const; diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index bbcc691879..7026da117c 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -16,6 +16,9 @@ EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); + // When you reload content, setProperties doesn't have any of the propertiesChanged flags set, so it won't trigger a material add + entity->removeMaterial(); + entity->applyMaterial(); return entity; } @@ -31,7 +34,9 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendFactor, getBlendFactor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeID, getShapeID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialBounds, getMaterialBounds); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialPos, getMaterialPos); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialScale, getMaterialScale); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialRot, getMaterialRot); return properties; } @@ -43,7 +48,9 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeID, setShapeID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialBounds, setMaterialBounds); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialPos, setMaterialPos); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialScale, setMaterialScale); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialRot, setMaterialRot); if (somethingChanged) { bool wantDebug = false; @@ -202,9 +209,11 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); - READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); - READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); - READ_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, glm::vec4, setMaterialBounds); + READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, quint16, setPriority); + READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY(PROP_MATERIAL_POS, glm::vec2, setMaterialPos); + READ_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, glm::vec2, setMaterialScale); + READ_ENTITY_PROPERTY(PROP_MATERIAL_ROT, float, setMaterialRot); return bytesRead; } @@ -218,7 +227,9 @@ EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParam requestedProperties += PROP_MATERIAL_BLEND_FACTOR; requestedProperties += PROP_MATERIAL_PRIORITY; requestedProperties += PROP_PARENT_SHAPE_ID; - requestedProperties += PROP_MATERIAL_BOUNDS; + requestedProperties += PROP_MATERIAL_POS; + requestedProperties += PROP_MATERIAL_SCALE; + requestedProperties += PROP_MATERIAL_ROT; return requestedProperties; } @@ -234,9 +245,11 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, (uint32_t)getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, (uint32_t)getShapeID()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, getMaterialBounds()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, getMaterialPos()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, getMaterialScale()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, getMaterialRot()); } void MaterialEntityItem::debugDump() const { @@ -249,7 +262,9 @@ void MaterialEntityItem::debugDump() const { qCDebug(entities) << " blend factor:" << _blendFactor; qCDebug(entities) << " priority:" << _priority; qCDebug(entities) << " parent shape ID:" << _shapeID; - qCDebug(entities) << " material bounds:" << _materialBounds; + qCDebug(entities) << " material pos:" << _materialPos; + qCDebug(entities) << " material scale:" << _materialRot; + qCDebug(entities) << " material rot:" << _materialScale; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); @@ -269,30 +284,38 @@ std::shared_ptr MaterialEntityItem::getMaterial() const { } } -void MaterialEntityItem::setMaterialURL(const QString& materialURLString) { - if (materialURLString.startsWith("userData")) { - QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); - _materials.clear(); - _materialNames.clear(); - if (!materialJSON.isNull()) { - if (materialJSON.isArray()) { - QJsonArray materials = materialJSON.array(); - for (auto& material : materials) { - if (!material.isNull() && material.isObject()) { - parseJSONMaterial(material.toObject()); +void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool userDataChanged) { + bool usingUserData = materialURLString.startsWith("userData"); + if (_materialURL != materialURLString || (usingUserData && userDataChanged)) { + removeMaterial(); + _materialURL = materialURLString; + + if (usingUserData) { + QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); + _materials.clear(); + _materialNames.clear(); + if (!materialJSON.isNull()) { + if (materialJSON.isArray()) { + QJsonArray materials = materialJSON.array(); + for (auto material : materials) { + if (!material.isNull() && material.isObject()) { + parseJSONMaterial(material.toObject()); + } } + } else if (materialJSON.isObject()) { + parseJSONMaterial(materialJSON.object()); } - } else if (materialJSON.isObject()) { - parseJSONMaterial(materialJSON.object()); } + } else { + // get material via network request } + + // TODO: if URL ends with ?string, try to set _currentMaterialName = string + + // Since our JSON changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(_currentMaterialName); + applyMaterial(); } - _materialURL = materialURLString; - - // TODO: if URL ends with ?string, set _currentMaterialName = string - - // Since our JSON changed, the current name might not be valid anymore, so we need to update - setCurrentMaterialName(_currentMaterialName); } void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialName) { @@ -300,14 +323,176 @@ void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialNa if (material != _materials.end()) { _currentMaterialName = currentMaterialName; } else if (_materialNames.size() > 0) { - setCurrentMaterialName(_materialNames[0]); + _currentMaterialName = _materialNames[0]; } } void MaterialEntityItem::setUserData(const QString& userData) { - EntityItem::setUserData(userData); - if (_materialURL.startsWith("userData")) { - // Trigger material update when user data changes - setMaterialURL(_materialURL); + if (_userData != userData) { + EntityItem::setUserData(userData); + if (_materialURL.startsWith("userData")) { + // Trigger material update when user data changes + setMaterialURL(_materialURL, true); + } } +} + +void MaterialEntityItem::setMaterialPos(const glm::vec2& materialPos) { + if (_materialPos != materialPos) { + removeMaterial(); + _materialPos = materialPos; + applyMaterial(); + } +} + +void MaterialEntityItem::setMaterialScale(const glm::vec2& materialScale) { + if (_materialScale != materialScale) { + removeMaterial(); + _materialScale = materialScale; + applyMaterial(); + } +} + +void MaterialEntityItem::setMaterialRot(const float& materialRot) { + if (_materialRot != materialRot) { + removeMaterial(); + _materialRot = materialRot; + applyMaterial(); + } +} + +void MaterialEntityItem::setBlendFactor(float blendFactor) { + if (_blendFactor != blendFactor) { + removeMaterial(); + _blendFactor = blendFactor; + applyMaterial(); + } +} + +void MaterialEntityItem::setPriority(quint16 priority) { + if (_priority != priority) { + removeMaterial(); + _priority = priority; + applyMaterial(); + } +} + +void MaterialEntityItem::setShapeID(quint16 shapeID) { + if (_shapeID != shapeID) { + removeMaterial(); + _shapeID = shapeID; + applyMaterial(); + } +} + +void MaterialEntityItem::setParentID(const QUuid& parentID) { + if (getParentID() != parentID) { + removeMaterial(); + EntityItem::setParentID(parentID); + applyMaterial(); + } +} + +void MaterialEntityItem::setClientOnly(bool clientOnly) { + if (getClientOnly() != clientOnly) { + removeMaterial(); + EntityItem::setClientOnly(clientOnly); + applyMaterial(); + } +} + +void MaterialEntityItem::setOwningAvatarID(const QUuid& owningAvatarID) { + if (getOwningAvatarID() != owningAvatarID) { + removeMaterial(); + EntityItem::setOwningAvatarID(owningAvatarID); + applyMaterial(); + } +} + +void MaterialEntityItem::removeMaterial() { + graphics::MaterialPointer material = getMaterial(); + QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID(); + if (!material || parentID.isNull()) { + return; + } + + // Our parent could be an entity, an avatar, or an overlay + EntityTreePointer tree = getTree(); + if (tree) { + EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); + if (entity) { + entity->removeMaterial(material, getShapeID()); + return; + } + } + + if (EntityTree::removeMaterialFromAvatar(parentID, material, getShapeID())) { + return; + } + + if (EntityTree::removeMaterialFromOverlay(parentID, material, getShapeID())) { + return; + } + + // if a remove fails, our parent is gone, so we don't need to retry +} + +void MaterialEntityItem::applyMaterial() { + _retryApply = false; + graphics::MaterialPointer material = getMaterial(); + QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID(); + if (!material || parentID.isNull()) { + return; + } + Transform textureTransform; + textureTransform.setTranslation(glm::vec3(_materialPos, 0)); + textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialRot))); + textureTransform.setScale(glm::vec3(_materialScale, 1)); + material->setTextureTransforms(textureTransform); + material->setBlendFactor(getBlendFactor()); + material->setPriority(getPriority()); + + // Our parent could be an entity, an avatar, or an overlay + EntityTreePointer tree = getTree(); + if (tree) { + EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); + if (entity) { + entity->addMaterial(material, getShapeID()); + return; + } + } + + if (EntityTree::addMaterialToAvatar(parentID, material, getShapeID())) { + return; + } + + if (EntityTree::addMaterialToOverlay(parentID, material, getShapeID())) { + return; + } + + // if we've reached this point, we couldn't find our parent, so we need to try again later + _retryApply = true; +} + +void MaterialEntityItem::postAdd() { + removeMaterial(); + applyMaterial(); +} + +void MaterialEntityItem::preDelete() { + EntityItem::preDelete(); + removeMaterial(); +} + +void MaterialEntityItem::postParentFixup() { + removeMaterial(); + applyMaterial(); +} + +void MaterialEntityItem::update(const quint64& now) { + if (_retryApply) { + applyMaterial(); + } + + EntityItem::update(now); } \ No newline at end of file diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index 80fe226b68..40137acf22 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -23,6 +23,9 @@ public: ALLOW_INSTANTIATION // This class can be instantiated + void update(const quint64& now) override; + bool needsToCallUpdate() const override { return true; } + // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; @@ -49,7 +52,7 @@ public: virtual void setUnscaledDimensions(const glm::vec3& value) override; QString getMaterialURL() const { return _materialURL; } - void setMaterialURL(const QString& materialURLString); + void setMaterialURL(const QString& materialURLString, bool userDataChanged = false); QString getCurrentMaterialName() const { return _currentMaterialName; } void setCurrentMaterialName(const QString& currentMaterialName); @@ -58,33 +61,51 @@ public: void setMaterialMode(MaterialMode mode) { _materialMode = mode; } float getBlendFactor() const { return _blendFactor; } - void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } + void setBlendFactor(float blendFactor); - int getPriority() const { return _priority; } - void setPriority(int priority) { _priority = priority; } + quint16 getPriority() const { return _priority; } + void setPriority(quint16 priority); - int getShapeID() const { return _shapeID; } - void setShapeID(int shapeID) { _shapeID = shapeID; } + quint16 getShapeID() const { return _shapeID; } + void setShapeID(quint16 shapeID); - glm::vec4 getMaterialBounds() const { return _materialBounds; } - void setMaterialBounds(const glm::vec4& materialBounds) { _materialBounds = materialBounds; } + glm::vec2 getMaterialPos() const { return _materialPos; } + void setMaterialPos(const glm::vec2& materialPos); + glm::vec2 getMaterialScale() const { return _materialScale; } + void setMaterialScale(const glm::vec2& materialScale); + float getMaterialRot() const { return _materialRot; } + void setMaterialRot(const float& materialRot); std::shared_ptr getMaterial() const; void setUserData(const QString& userData) override; + void setParentID(const QUuid& parentID) override; + void setClientOnly(bool clientOnly) override; + void setOwningAvatarID(const QUuid& owningAvatarID) override; + + void applyMaterial(); + void removeMaterial(); + + void postAdd() override; + void preDelete() override; + void postParentFixup() override; private: QString _materialURL; MaterialMode _materialMode { UV }; float _blendFactor { 1.0f }; - int _priority { 0 }; - int _shapeID { 0 }; - glm::vec4 _materialBounds { 0, 0, 1, 1 }; + quint16 _priority { 0 }; + quint16 _shapeID { 0 }; + glm::vec2 _materialPos { 0, 0 }; + glm::vec2 _materialScale { 1, 1 }; + float _materialRot { 0 }; QHash> _materials; std::vector _materialNames; QString _currentMaterialName; + bool _retryApply { false }; + void parseJSONMaterial(const QJsonObject& materialJSON); static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 5d33e4c047..bec7bc1906 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -721,4 +721,4 @@ bool ModelEntityItem::isAnimatingSomething() const { _animationProperties.getRunning() && (_animationProperties.getFPS() != 0.0f); }); -} +} \ No newline at end of file diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index cbcfcaaa1d..2425208a87 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -85,6 +85,7 @@ EntityItemPointer ShapeEntityItem::sphereFactory(const EntityItemID& entityID, c ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Shape; _volumeMultiplier *= PI / 6.0f; + _material = std::make_shared(); } EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { @@ -184,6 +185,7 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit void ShapeEntityItem::setColor(const rgbColor& value) { memcpy(_color, value, sizeof(rgbColor)); + _material->setAlbedo(glm::vec3(_color[0], _color[1], _color[2]) / 255.0f); } xColor ShapeEntityItem::getXColor() const { @@ -204,6 +206,11 @@ void ShapeEntityItem::setColor(const QColor& value) { setAlpha(value.alpha()); } +void ShapeEntityItem::setAlpha(float alpha) { + _alpha = alpha; + _material->setOpacity(alpha); +} + void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { const float MAX_FLAT_DIMENSION = 0.0001f; if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) { diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 84ce1ce57e..7ad1b3c1c2 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -75,7 +75,7 @@ public: void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); } float getAlpha() const { return _alpha; }; - void setAlpha(float alpha) { _alpha = alpha; } + void setAlpha(float alpha); const rgbColor& getColor() const { return _color; } void setColor(const rgbColor& value); @@ -101,6 +101,8 @@ public: virtual void computeShapeInfo(ShapeInfo& info) override; virtual ShapeType getShapeType() const override; + std::shared_ptr getMaterial() { return _material; } + protected: float _alpha { 1 }; @@ -111,6 +113,8 @@ protected: //! prior functionality where new or unsupported shapes are treated as //! ellipsoids. ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID }; + + std::shared_ptr _material; }; #endif // hifi_ShapeEntityItem_h diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index 6cc6b8472f..7c66c8ab07 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -12,9 +12,13 @@ #include "TextureMap.h" +#include + using namespace graphics; using namespace gpu; +int materialPointerMetaID = qRegisterMetaType("graphics::MaterialPointer"); + Material::Material() : _key(0), _schemaBuffer(), @@ -221,4 +225,15 @@ bool Material::calculateMaterialInfo() const { _hasCalculatedTextureInfo = allTextures; } return _hasCalculatedTextureInfo; +} + +void Material::setTextureTransforms(const Transform& transform) { + for (auto &textureMapItem : _textureMaps) { + if (textureMapItem.second) { + textureMapItem.second->setTextureTransform(transform); + } + } + for (int i = 0; i < NUM_TEXCOORD_TRANSFORMS; i++) { + _texMapArrayBuffer.edit()._texcoordTransforms[i] = transform.getMatrix(); + } } \ No newline at end of file diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index cfbfaa61ea..b9eb881ed8 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -15,11 +15,14 @@ #include #include +#include #include #include +class Transform; + namespace graphics { class TextureMap; @@ -351,6 +354,14 @@ public: size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } + void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } + float getBlendFactor() { return _blendFactor; } + + void setPriority(quint16 priority) { _priority = priority; } + quint16 getPriority() { return _priority; } + + void setTextureTransforms(const Transform& transform); + private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; @@ -364,10 +375,35 @@ private: mutable bool _hasCalculatedTextureInfo { false }; bool calculateMaterialInfo() const; + float _blendFactor { 1.0f }; + quint16 _priority { 0 }; }; typedef std::shared_ptr< Material > MaterialPointer; +Q_DECLARE_METATYPE(MaterialPointer) + +class MaterialCompare { +public: + bool operator() (MaterialPointer left, MaterialPointer right) { + return left->getPriority() < right->getPriority(); + } +}; + +class MultiMaterial : public std::priority_queue, MaterialCompare> { +public: + bool remove(const MaterialPointer& value) { + auto it = std::find(c.begin(), c.end(), value); + if (it != c.end()) { + c.erase(it); + std::make_heap(c.begin(), c.end(), comp); + return true; + } else { + return false; + } + } +}; + }; #endif diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 1fe3648838..32deba3687 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -549,7 +549,6 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, im auto map = std::make_shared(); if (texture) { map->setTextureSource(texture->_textureSource); - emit textureFinished(); } return map; @@ -728,6 +727,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { if (!occlusionName.isEmpty()) { auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl(); + // FIXME: we need to handle the occlusion map transform here auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); setTextureMap(MapChannel::OCCLUSION_MAP, map); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 575f94f9bf..bbb00d72eb 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -156,8 +156,7 @@ private: virtual ~ModelCache() = default; }; -class NetworkMaterial : public QObject, public graphics::Material { - Q_OBJECT +class NetworkMaterial : public graphics::Material { public: using MapChannel = graphics::Material::MapChannel; @@ -174,9 +173,6 @@ public: void setScatteringMap(const QString& url); void setLightmapMap(const QString& url); -signals: - void textureFinished(); - protected: friend class Geometry; diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index a2aad33058..7108f9a4e4 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -381,6 +381,17 @@ bool OctreePacketData::appendValue(float value) { return success; } +bool OctreePacketData::appendValue(const glm::vec2& value) { + const unsigned char* data = (const unsigned char*)&value; + int length = sizeof(value); + bool success = append(data, length); + if (success) { + _bytesOfValues += length; + _totalBytesOfValues += length; + } + return success; +} + bool OctreePacketData::appendValue(const glm::vec3& value) { const unsigned char* data = (const unsigned char*)&value; int length = sizeof(value); diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 7f8eb49101..85100ec177 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -164,6 +164,9 @@ public: /// appends a float value to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(float value); + /// appends a vec2 to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const glm::vec2& value); + /// appends a non-position vector to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const glm::vec3& value); @@ -250,8 +253,8 @@ public: static quint64 getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color static int unpackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } - static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec4& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index b80327cf14..d24843c87d 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -47,7 +47,7 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, graphics::MaterialPointer material) { updateMeshPart(mesh, partIndex); - updateMaterial(material); + addMaterial(material); } void MeshPartPayload::updateMeshPart(const std::shared_ptr& drawMesh, int partIndex) { @@ -67,8 +67,12 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor _worldBound.transform(_drawTransform); } -void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) { - _drawMaterial = drawMaterial; +void MeshPartPayload::addMaterial(graphics::MaterialPointer material) { + _drawMaterials.push(material); +} + +void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) { + _drawMaterials.remove(material); } void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) { @@ -85,8 +89,8 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) builder.withLayered(); } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + auto matKey = _drawMaterials.top()->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); } @@ -105,8 +109,8 @@ Item::Bound MeshPartPayload::getBound() const { ShapeKey MeshPartPayload::getShapeKey() const { graphics::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + drawMaterialKey = _drawMaterials.top()->getKey(); } ShapeKey::Builder builder; @@ -160,7 +164,7 @@ void MeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_shapePipeline->bindMaterial(_drawMaterials.top(), batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! @@ -252,7 +256,7 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) { auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID); if (networkMaterial) { - _drawMaterial = networkMaterial; + addMaterial(networkMaterial); } } @@ -298,8 +302,8 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag builder.withDeformed(); } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + auto matKey = _drawMaterials.top()->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); } @@ -329,8 +333,8 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe } graphics::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + drawMaterialKey = _drawMaterials.top()->getKey(); } bool isTranslucent = drawMaterialKey.isTranslucent(); @@ -411,7 +415,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_shapePipeline->bindMaterial(_drawMaterials.top(), batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index b9ae47fb6a..e6893f1ea7 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -39,8 +39,6 @@ public: virtual void notifyLocationChanged() {} void updateTransform(const Transform& transform, const Transform& offsetTransform); - virtual void updateMaterial(graphics::MaterialPointer drawMaterial); - // Render Item interface virtual render::ItemKey getKey() const; virtual render::Item::Bound getBound() const; @@ -63,13 +61,16 @@ public: mutable graphics::Box _worldBound; std::shared_ptr _drawMesh; - std::shared_ptr _drawMaterial; + graphics::MultiMaterial _drawMaterials; graphics::Mesh::Part _drawPart; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } - size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; } - int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; } - bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; } + size_t getMaterialTextureSize() { return _drawMaterials.top() ? _drawMaterials.top()->getTextureSize() : 0; } + int getMaterialTextureCount() { return _drawMaterials.top() ? _drawMaterials.top()->getTextureCount() : 0; } + bool hasTextureInfo() const { return _drawMaterials.top() ? _drawMaterials.top()->hasTextureInfo() : false; } + + void addMaterial(graphics::MaterialPointer material); + void removeMaterial(graphics::MaterialPointer material); protected: render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b9ccc28c01..805995edfb 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1524,6 +1524,50 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } +void Model::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + render::Transaction transaction; + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.addMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); + } +} + +void Model::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + render::Transaction transaction; + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.removeMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); + } +} + class CollisionRenderGeometry : public Geometry { public: CollisionRenderGeometry(graphics::MeshPointer mesh) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index ca0904f334..80067aff2a 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -318,6 +318,9 @@ public: void scaleToFit(); + void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + public slots: void loadURLFinished(bool success); diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 1763713831..6196a4c5d4 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -342,7 +342,7 @@ var toolBar = (function () { var buttonHandlers = {}; // only used to tablet mode - function addButton(name, image, handler) { + function addButton(name, handler) { buttonHandlers[name] = handler; } @@ -399,7 +399,7 @@ var toolBar = (function () { function handleNewMaterialDialogResult(result) { if (result) { - var json = result.textInput; + var materialURL = result.textInput; var materialMode; switch (result.comboBox) { case MATERIAL_MODE_PROJECTED: @@ -409,11 +409,13 @@ var toolBar = (function () { shapeType = "uv"; } - if (json) { + var DEFAULT_LAYERED_MATERIAL_PRIORITY = 1; + if (materialURL) { createNewEntity({ type: "Material", - materialURL: json, - materialMode: materialMode + materialURL: materialURL, + materialMode: materialMode, + priority: DEFAULT_LAYERED_MATERIAL_PRIORITY }); } } @@ -475,32 +477,22 @@ var toolBar = (function () { that.toggle(); }); - addButton("importEntitiesButton", "assets-01.svg", function() { + addButton("importEntitiesButton", function() { Window.browseChanged.connect(onFileOpenChanged); Window.browseAsync("Select Model to Import", "", "*.json"); }); - addButton("openAssetBrowserButton", "assets-01.svg", function() { + addButton("openAssetBrowserButton", function() { Window.showAssetServer(); }); - addButton("newModelButton", "model-01.svg", function () { - - var SHAPE_TYPES = []; - SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision"; - SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model"; - SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes"; - SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons"; - SHAPE_TYPES[SHAPE_TYPE_BOX] = "Box"; - SHAPE_TYPES[SHAPE_TYPE_SPHERE] = "Sphere"; - var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH; - + addButton("newModelButton", function () { // tablet version of new-model dialog var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml"); }); - addButton("newCubeButton", "cube-01.svg", function () { + addButton("newCubeButton", function () { createNewEntity({ type: "Box", dimensions: DEFAULT_DIMENSIONS, @@ -512,7 +504,7 @@ var toolBar = (function () { }); }); - addButton("newSphereButton", "sphere-01.svg", function () { + addButton("newSphereButton", function () { createNewEntity({ type: "Sphere", dimensions: DEFAULT_DIMENSIONS, @@ -524,7 +516,7 @@ var toolBar = (function () { }); }); - addButton("newLightButton", "light-01.svg", function () { + addButton("newLightButton", function () { createNewEntity({ type: "Light", dimensions: DEFAULT_LIGHT_DIMENSIONS, @@ -543,7 +535,7 @@ var toolBar = (function () { }); }); - addButton("newTextButton", "text-01.svg", function () { + addButton("newTextButton", function () { createNewEntity({ type: "Text", dimensions: { @@ -566,7 +558,7 @@ var toolBar = (function () { }); }); - addButton("newWebButton", "web-01.svg", function () { + addButton("newWebButton", function () { createNewEntity({ type: "Web", dimensions: { @@ -578,7 +570,7 @@ var toolBar = (function () { }); }); - addButton("newZoneButton", "zone-01.svg", function () { + addButton("newZoneButton", function () { createNewEntity({ type: "Zone", dimensions: { @@ -589,7 +581,7 @@ var toolBar = (function () { }); }); - addButton("newParticleButton", "particle-01.svg", function () { + addButton("newParticleButton", function () { createNewEntity({ type: "ParticleEffect", isEmitting: true, @@ -642,15 +634,10 @@ var toolBar = (function () { }); }); - addButton("newMaterialButton", "model-01.svg", function () { - var MATERIAL_MODES = []; - MATERIAL_MODES[MATERIAL_MODE_UV] = "UV space material"; - MATERIAL_MODES[MATERIAL_MODE_PROJECTED] = "3D projected material"; - var MATERIAL_MODE_DEFAULT = MATERIAL_MODE_UV; - + addButton("newMaterialButton", function () { // tablet version of new material dialog var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - tablet.pushOntoStack("NewMaterialDialog.qml"); + tablet.pushOntoStack("hifi/tablet/NewMaterialDialog.qml"); }); that.setActive(false); diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 96084f355f..dd266311ea 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -645,14 +645,14 @@ hr { margin-left: 10px; } -.text label, .url label, .number label, .textarea label, .rgb label, .xyz label, .pyr label, .dropdown label, .gen label { +.text label, .url label, .number label, .textarea label, .xy label, .wh label, .rgb label, .xyz label,.pyr label, .dropdown label, .gen label { float: left; margin-left: 1px; margin-bottom: 3px; margin-top: -2px; } -.text legend, .url legend, .number legend, .textarea legend, .rgb legend, .xyz legend, .pyr legend, .dropdown legend, .gen legend { +.text legend, .url legend, .number legend, .textarea legend, .xy legend, .wh legend, .rgb legend, .xyz legend, .pyr legend, .dropdown legend, .gen legend { float: left; margin-left: 1px; margin-bottom: 3px; @@ -667,7 +667,7 @@ hr { clear: both; float: left; } -.xyz > div, .pyr > div, .gen > div { +.xy > div, .wh > div, .xyz > div, .pyr > div, .gen > div { clear: both; } @@ -841,6 +841,12 @@ div.refresh input[type="button"] { margin-right: -6px; } +.xy .tuple input { + padding-left: 25px; +} +.wh .tuple input { + padding-left: 45px; +} .rgb .tuple input { padding-left: 65px; } diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 93d22180c9..348d93d589 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -787,7 +787,7 @@
- +
@@ -795,13 +795,26 @@
-
- -
-
-
-
-
+
+
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 64f706ce1f..3558a36c04 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -25,7 +25,7 @@ var ICON_FOR_TYPE = { PolyVox: "", Multiple: "", PolyLine: "", - Material: "" + Material: "" }; var EDITOR_TIMEOUT_DURATION = 1500; @@ -167,6 +167,17 @@ function createEmitGroupTextPropertyUpdateFunction(group, propertyName) { }; } +function createEmitVec2PropertyUpdateFunction(property, elX, elY) { + return function () { + var properties = {}; + properties[property] = { + x: elX.value, + y: elY.value + }; + updateProperties(properties); + }; +} + function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) { return function() { var properties = {}; @@ -192,19 +203,6 @@ function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, el }; } -function createEmitVec4PropertyUpdateFunction(property, elX, elY, elZ, elW) { - return function () { - var properties = {}; - properties[property] = { - x: elX.value, - y: elY.value, - z: elZ.value, - w: elW.value - }; - updateProperties(properties); - }; -} - function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) { return function() { var properties = {}; @@ -638,10 +636,11 @@ function loaded() { var elBlendFactor = document.getElementById("property-blend-factor"); var elPriority = document.getElementById("property-priority"); var elShapeID = document.getElementById("property-shape-id"); - var elMaterialBoundsX = document.getElementById("property-material-bounds-x"); - var elMaterialBoundsY = document.getElementById("property-material-bounds-y"); - var elMaterialBoundsZ = document.getElementById("property-material-bounds-z"); - var elMaterialBoundsW = document.getElementById("property-material-bounds-w"); + var elMaterialPosX = document.getElementById("property-material-pos-x"); + var elMaterialPosY = document.getElementById("property-material-pos-y"); + var elMaterialScaleX = document.getElementById("property-material-scale-x"); + var elMaterialScaleY = document.getElementById("property-material-scale-y"); + var elMaterialRot = document.getElementById("property-material-rot"); var elWebSourceURL = document.getElementById("property-web-source-url"); var elWebDPI = document.getElementById("property-web-dpi"); @@ -1134,10 +1133,11 @@ function loaded() { elBlendFactor.value = properties.blendFactor.toFixed(2); elPriority.value = properties.priority; elShapeID.value = properties.shapeID; - elMaterialBoundsX.value = properties.materialBounds.x.toFixed(2); - elMaterialBoundsY.value = properties.materialBounds.y.toFixed(2); - elMaterialBoundsZ.value = properties.materialBounds.z.toFixed(2); - //elMaterialBoundsW.value = properties.materialBounds.w.toFixed(2); + elMaterialPosX.value = properties.materialPos.x.toFixed(4); + elMaterialPosY.value = properties.materialPos.y.toFixed(4); + elMaterialScaleX.value = properties.materialScale.x.toFixed(4); + elMaterialScaleY.value = properties.materialScale.y.toFixed(4); + elMaterialRot.value = properties.materialRot.toFixed(2); } if (properties.locked) { @@ -1411,15 +1411,16 @@ function loaded() { elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL')); elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode')); elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2)); - elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority')); - elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID')); + elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority', 0)); + elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID', 0)); - var materialBoundsChangeFunction = createEmitVec4PropertyUpdateFunction('materialBounds', - elMaterialBoundsX, elMaterialBoundsY, elMaterialBoundsZ, elMaterialBoundsW); - elMaterialBoundsX.addEventListener('change', materialBoundsChangeFunction); - elMaterialBoundsY.addEventListener('change', materialBoundsChangeFunction); - elMaterialBoundsZ.addEventListener('change', materialBoundsChangeFunction); - elMaterialBoundsW.addEventListener('change', materialBoundsChangeFunction); + var materialPosChangeFunction = createEmitVec2PropertyUpdateFunction('materialPos', elMaterialPosX, elMaterialPosY); + elMaterialPosX.addEventListener('change', materialPosChangeFunction); + elMaterialPosY.addEventListener('change', materialPosChangeFunction); + var materialScaleChangeFunction = createEmitVec2PropertyUpdateFunction('materialScale', elMaterialScaleX, elMaterialScaleY); + elMaterialScaleX.addEventListener('change', materialScaleChangeFunction); + elMaterialScaleY.addEventListener('change', materialScaleChangeFunction); + elMaterialRot.addEventListener('change', createEmitNumberPropertyUpdateFunction('materialRot', 2)); elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text')); elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera')); diff --git a/tools/jsdoc/package-lock.json b/tools/jsdoc/package-lock.json new file mode 100644 index 0000000000..073bbf60f6 --- /dev/null +++ b/tools/jsdoc/package-lock.json @@ -0,0 +1,138 @@ +{ + "name": "hifiJSDoc", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "babylon": { + "version": "7.0.0-beta.19", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", + "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==" + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "catharsis": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", + "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", + "requires": { + "underscore-contrib": "0.3.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", + "requires": { + "xmlcreate": "1.0.2" + } + }, + "jsdoc": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", + "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", + "requires": { + "babylon": "7.0.0-beta.19", + "bluebird": "3.5.1", + "catharsis": "0.8.9", + "escape-string-regexp": "1.0.5", + "js2xmlparser": "3.0.0", + "klaw": "2.0.0", + "marked": "0.3.12", + "mkdirp": "0.5.1", + "requizzle": "0.2.1", + "strip-json-comments": "2.0.1", + "taffydb": "2.6.2", + "underscore": "1.8.3" + } + }, + "klaw": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", + "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "marked": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.12.tgz", + "integrity": "sha512-k4NaW+vS7ytQn6MgJn3fYpQt20/mOgYM5Ft9BYMfQJDz2QT6yEeS9XJ8k2Nw8JTeWK/znPPW2n3UJGzyYEiMoA==" + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "requizzle": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", + "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + } + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=" + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "underscore-contrib": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", + "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + } + } + }, + "xmlcreate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", + "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=" + } + } +} From 9e8aa1898cc3c6ffe0b797b9d711effa72337aa0 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 9 Feb 2018 15:24:07 -0800 Subject: [PATCH 04/12] warnings, load material from URL, shapeID -> parentMaterialID --- assignment-client/src/assets/AssetServer.h | 7 +- interface/src/Application.cpp | 16 +- interface/src/ui/overlays/ModelOverlay.cpp | 12 +- interface/src/ui/overlays/ModelOverlay.h | 4 +- interface/src/ui/overlays/Overlay.cpp | 8 +- interface/src/ui/overlays/Overlay.h | 6 +- .../src/avatars-renderer/Avatar.cpp | 12 +- .../src/avatars-renderer/Avatar.h | 6 +- libraries/avatars/src/AvatarData.h | 4 +- .../src/RenderableEntityItem.cpp | 8 +- .../src/RenderableEntityItem.h | 6 +- .../src/RenderableMaterialEntityItem.cpp | 8 +- .../src/RenderableModelEntityItem.cpp | 12 +- .../src/RenderableModelEntityItem.h | 4 +- .../src/RenderableShapeEntityItem.cpp | 6 +- libraries/entities/src/EntityItem.cpp | 16 +- libraries/entities/src/EntityItem.h | 12 +- .../entities/src/EntityItemProperties.cpp | 28 +-- libraries/entities/src/EntityItemProperties.h | 3 +- libraries/entities/src/EntityPropertyFlags.h | 3 +- libraries/entities/src/EntityTree.cpp | 24 +- libraries/entities/src/EntityTree.h | 24 +- libraries/entities/src/MaterialEntityItem.cpp | 215 ++++-------------- libraries/entities/src/MaterialEntityItem.h | 15 +- libraries/graphics/src/graphics/Material.h | 4 - .../src/model-networking/MaterialCache.cpp | 175 ++++++++++++++ .../src/model-networking/MaterialCache.h | 46 ++++ .../src/model-networking/ModelCache.cpp | 2 +- libraries/networking/src/ResourceRequest.cpp | 2 +- libraries/render-utils/src/Model.cpp | 92 ++++---- libraries/render-utils/src/Model.h | 6 +- libraries/shared/src/RegisteredMetaTypes.h | 7 + scripts/system/html/entityProperties.html | 11 +- scripts/system/html/js/entityProperties.js | 9 +- 34 files changed, 447 insertions(+), 366 deletions(-) create mode 100644 libraries/model-networking/src/model-networking/MaterialCache.cpp create mode 100644 libraries/model-networking/src/model-networking/MaterialCache.h diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 5e7a3c1700..1470249bf3 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -21,12 +21,7 @@ #include "AssetUtils.h" #include "ReceivedMessage.h" -namespace std { - template <> - struct hash { - size_t operator()(const QString& v) const { return qHash(v); } - }; -} +#include "RegisteredMetaTypes.h" struct AssetMeta { AssetMeta() { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f8fa8f9b17..ce4027945d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1587,37 +1587,37 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { - avatar->addMaterial(material, shapeID); + avatar->addMaterial(material, parentMaterialID); return true; } return false; }); - EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { - avatar->removeMaterial(material, shapeID); + avatar->removeMaterial(material, parentMaterialID); return true; } return false; }); - EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { auto overlay = _overlays.getOverlay(overlayID); if (overlay) { - overlay->addMaterial(material, shapeID); + overlay->addMaterial(material, parentMaterialID); return true; } return false; }); - EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { auto overlay = _overlays.getOverlay(overlayID); if (overlay) { - overlay->removeMaterial(material, shapeID); + overlay->removeMaterial(material, parentMaterialID); return true; } return false; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index bf95494d19..ab7f55d6e7 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -633,17 +633,17 @@ uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const { return 0; } -void ModelOverlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { - Overlay::addMaterial(material, shapeID); +void ModelOverlay::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + Overlay::addMaterial(material, parentMaterialID); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->addMaterial(material, shapeID); + _model->addMaterial(material, parentMaterialID); } } -void ModelOverlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { - Overlay::removeMaterial(material, shapeID); +void ModelOverlay::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + Overlay::removeMaterial(material, parentMaterialID); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->removeMaterial(material, shapeID); + _model->removeMaterial(material, parentMaterialID); } } diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 827f7f2d5b..6761b1508c 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -59,8 +59,8 @@ public: void setDrawInFront(bool drawInFront) override; void setDrawHUDLayer(bool drawHUDLayer) override; - void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; protected: Transform evalRenderTransform() override; diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 368ed04062..04d6c2fe4d 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -236,12 +236,12 @@ QVector qVectorOverlayIDFromScriptValue(const QScriptValue& array) { return newVector; } -void Overlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void Overlay::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].push(material); + _materials[parentMaterialID].push(material); } -void Overlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void Overlay::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].remove(material); + _materials[parentMaterialID].remove(material); } \ No newline at end of file diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 4cb3f7c84d..bd9f7942fd 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -91,8 +91,8 @@ public: unsigned int getStackOrder() const { return _stackOrder; } void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; } - virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); - virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); protected: float updatePulse(); @@ -120,7 +120,7 @@ protected: static const xColor DEFAULT_OVERLAY_COLOR; static const float DEFAULT_ALPHA; - std::unordered_map _materials; + std::unordered_map _materials; std::mutex _materialsLock; private: diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 4cd9bbedd7..3276a8fe89 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1763,19 +1763,19 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const { } } -void Avatar::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void Avatar::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].push(material); + _materials[parentMaterialID].push(material); if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { - _skeletonModel->addMaterial(material, shapeID); + _skeletonModel->addMaterial(material, parentMaterialID); } } -void Avatar::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void Avatar::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].remove(material); + _materials[parentMaterialID].remove(material); if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { - _skeletonModel->removeMaterial(material, shapeID); + _skeletonModel->removeMaterial(material, parentMaterialID); } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 9c355159d8..49aa664a9f 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -272,8 +272,8 @@ public: virtual void setAvatarEntityDataChanged(bool value) override; - void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; public slots: @@ -401,7 +401,7 @@ protected: ThreadSafeValueCache _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT }; - std::unordered_map _materials; + std::unordered_map _materials; std::mutex _materialsLock; void processMaterials(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index fbd586f153..832585a483 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -696,8 +696,8 @@ public: bool getIsReplicated() const { return _isReplicated; } - virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID) {} - virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) {} + virtual void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) {} + virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) {} signals: void displayNameChanged(); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 2f92790d18..81d7dceb0d 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -404,12 +404,12 @@ void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) { QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr); } -void EntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void EntityRenderer::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].push(material); + _materials[parentMaterialID].push(material); } -void EntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].remove(material); + _materials[parentMaterialID].remove(material); } \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index f58b540aef..6247a97c21 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -102,8 +102,8 @@ protected: } public slots: - virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); - virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); signals: void requestRenderUpdate(); @@ -133,7 +133,7 @@ protected: // Only touched on the rendering thread bool _renderUpdateQueued{ false }; - std::unordered_map _materials; + std::unordered_map _materials; std::mutex _materialsLock; private: diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index d541d99c4c..ad17202d8e 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -102,10 +102,10 @@ void MaterialEntityRenderer::addVertex(std::vector& buffer, const glm::ve void MaterialEntityRenderer::addTriangleFan(std::vector& buffer, int stack, int step) { float v1 = ((float)stack) / STACKS; - float theta1 = v1 * M_PI; + float theta1 = v1 * (float)M_PI; glm::vec3 tip = getVertexPos(0, theta1); float v2 = ((float)(stack + step)) / STACKS; - float theta2 = v2 * M_PI; + float theta2 = v2 * (float)M_PI; for (int i = 0; i < SLICES; i++) { float u1 = ((float)i) / SLICES; float u2 = ((float)(i + step)) / SLICES; @@ -169,8 +169,8 @@ void MaterialEntityRenderer::generateMesh() { for (int j = 1; j < STACKS - 1; j++) { float v1 = ((float)j) / STACKS; float v2 = ((float)(j + 1)) / STACKS; - float theta1 = v1 * M_PI; - float theta2 = v2 * M_PI; + float theta1 = v1 * (float)M_PI; + float theta2 = v2 * (float)M_PI; for (int i = 0; i < SLICES; i++) { float u1 = ((float)i) / SLICES; float u2 = ((float)(i + 1)) / SLICES; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 739ccd9738..e28ba797d5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1467,17 +1467,17 @@ void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStr } } -void ModelEntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { - Parent::addMaterial(material, shapeID); +void ModelEntityRenderer::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + Parent::addMaterial(material, parentMaterialID); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->addMaterial(material, shapeID); + _model->addMaterial(material, parentMaterialID); } } -void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { - Parent::removeMaterial(material, shapeID); +void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + Parent::removeMaterial(material, parentMaterialID); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->removeMaterial(material, shapeID); + _model->removeMaterial(material, parentMaterialID); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 75c6639902..3951deaa2d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -144,8 +144,8 @@ public: ModelEntityRenderer(const EntityItemPointer& entity); public slots: - void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; protected: virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override; diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 8bed9c70ee..5c5df38350 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -77,9 +77,9 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _procedural.setProceduralData(ProceduralData::parse(_lastUserData)); } - removeMaterial(_material, 0); + removeMaterial(_material, "0"); _material = entity->getMaterial(); - addMaterial(_material, 0); + addMaterial(_material, "0"); _shape = entity->getShape(); _position = entity->getWorldPosition(); @@ -127,7 +127,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { withReadLock([&] { geometryShape = geometryCache->getShapeForEntityShape(_shape); batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation - mat = _materials[0].top(); + mat = _materials["0"].top(); if (mat) { outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity()); if (_procedural.isReady()) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 43510864ba..3ea81e5a36 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2940,20 +2940,20 @@ void EntityItem::preDelete() { } } -void EntityItem::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void EntityItem::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].push(material); - emit addMaterialToRenderItem(material, shapeID); + _materials[parentMaterialID].push(material); + emit addMaterialToRenderItem(material, parentMaterialID); } -void EntityItem::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void EntityItem::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].remove(material); - emit removeMaterialFromRenderItem(material, shapeID); + _materials[parentMaterialID].remove(material); + emit removeMaterialFromRenderItem(material, parentMaterialID); } -std::unordered_map EntityItem::getMaterials() { - std::unordered_map toReturn; +std::unordered_map EntityItem::getMaterials() { + std::unordered_map toReturn; { std::lock_guard lock(_materialsLock); toReturn = _materials; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index b2804a2e86..97d2f32a04 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -482,14 +482,14 @@ public: virtual void preDelete(); virtual void postParentFixup() {} - void addMaterial(graphics::MaterialPointer material, quint16 shapeID); - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); - std::unordered_map getMaterials(); + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + std::unordered_map getMaterials(); signals: void requestRenderUpdate(); - void addMaterialToRenderItem(graphics::MaterialPointer material, quint16 shapeID); - void removeMaterialFromRenderItem(graphics::MaterialPointer material, quint16 shapeID); + void addMaterialToRenderItem(graphics::MaterialPointer material, const QString& parentMaterialID); + void removeMaterialFromRenderItem(graphics::MaterialPointer material, const QString& parentMaterialID); protected: QHash _changeHandlers; @@ -644,7 +644,7 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera private: - std::unordered_map _materials; + std::unordered_map _materials; std::mutex _materialsLock; }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 19aa6990db..450d0727f9 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -357,9 +357,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_URL, materialURL); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_TYPE, materialMode); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); - CHECK_PROPERTY_CHANGE(PROP_PARENT_SHAPE_ID, shapeID); + CHECK_PROPERTY_CHANGE(PROP_PARENT_MATERIAL_ID, parentMaterialID); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_POS, materialPos); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_SCALE, materialScale); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_ROT, materialRot); @@ -663,9 +662,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool if (_type == EntityTypes::Material) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_URL, materialURL); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MATERIAL_TYPE, materialMode, getMaterialModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_MATERIAL_ID, parentMaterialID); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_POS, materialPos); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_SCALE, materialScale); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_ROT, materialRot); @@ -806,9 +804,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(materialMode, MaterialMode); - COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor); COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority); - COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, quint16, setShapeID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(parentMaterialID, QString, setParentMaterialID); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialPos, glmVec2, setMaterialPos); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialScale, glmVec2, setMaterialScale); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialRot, float, setMaterialRot); @@ -1168,9 +1165,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, quint16); - ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16); + ADD_PROPERTY_TO_MAP(PROP_PARENT_MATERIAL_ID, ParentMaterialID, parentMaterialID, QString); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_ROT, MaterialRot, materialRot, float); @@ -1562,9 +1558,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy if (properties.getType() == EntityTypes::Material) { APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, properties.getMaterialURL()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)properties.getMaterialMode()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, properties.getBlendFactor()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, properties.getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_ID, properties.getParentMaterialID()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, properties.getMaterialPos()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, properties.getMaterialScale()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, properties.getMaterialRot()); @@ -1930,9 +1925,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int if (properties.getType() == EntityTypes::Material) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_MATERIAL_ID, QString, setParentMaterialID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_POS, glmVec2, setMaterialPos); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_SCALE, glmVec2, setMaterialScale); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_ROT, float, setMaterialRot); @@ -2113,9 +2107,8 @@ void EntityItemProperties::markAllChanged() { _materialURLChanged = true; _materialModeChanged = true; - _blendFactorChanged = true; _priorityChanged = true; - _shapeIDChanged = true; + _parentMaterialIDChanged = true; _materialPosChanged = true; _materialScaleChanged = true; _materialRotChanged = true; @@ -2449,14 +2442,11 @@ QList EntityItemProperties::listChangedProperties() { if (materialModeChanged()) { out += "materialMode"; } - if (blendFactorChanged()) { - out += "blendFactor"; - } if (priorityChanged()) { out += "priority"; } - if (shapeIDChanged()) { - out += "shapeID"; + if (parentMaterialIDChanged()) { + out += "parentMaterialID"; } if (materialPosChanged()) { out += "materialPos"; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index a8a79b6303..daa2272e36 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -224,9 +224,8 @@ public: DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, ""); DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode, UV); - DEFINE_PROPERTY_REF(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float, 1.0f); DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, quint16, 0); - DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16, 0); + DEFINE_PROPERTY_REF(PROP_PARENT_MATERIAL_ID, ParentMaterialID, parentMaterialID, QString, "0"); DEFINE_PROPERTY_REF(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2, glm::vec2(0, 0)); DEFINE_PROPERTY_REF(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2, glm::vec2(1, 1)); DEFINE_PROPERTY_REF(PROP_MATERIAL_ROT, MaterialRot, materialRot, float, 0); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 17ebddbe9d..6ed2186760 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -229,9 +229,8 @@ enum EntityPropertyList { PROP_MATERIAL_URL, PROP_MATERIAL_TYPE, - PROP_MATERIAL_BLEND_FACTOR, PROP_MATERIAL_PRIORITY, - PROP_PARENT_SHAPE_ID, + PROP_PARENT_MATERIAL_ID, PROP_MATERIAL_POS, PROP_MATERIAL_SCALE, PROP_MATERIAL_ROT, diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 775b3bd2f7..9935718568 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2382,35 +2382,35 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const { return entity->getJointNames(); } -std::function EntityTree::_addMaterialToAvatarOperator = nullptr; -std::function EntityTree::_removeMaterialFromAvatarOperator = nullptr; -std::function EntityTree::_addMaterialToOverlayOperator = nullptr; -std::function EntityTree::_removeMaterialFromOverlayOperator = nullptr; +std::function EntityTree::_addMaterialToAvatarOperator = nullptr; +std::function EntityTree::_removeMaterialFromAvatarOperator = nullptr; +std::function EntityTree::_addMaterialToOverlayOperator = nullptr; +std::function EntityTree::_removeMaterialFromOverlayOperator = nullptr; -bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { +bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { if (_addMaterialToAvatarOperator) { - return _addMaterialToAvatarOperator(avatarID, material, shapeID); + return _addMaterialToAvatarOperator(avatarID, material, parentMaterialID); } return false; } -bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { +bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { if (_removeMaterialFromAvatarOperator) { - return _removeMaterialFromAvatarOperator(avatarID, material, shapeID); + return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialID); } return false; } -bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { +bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { if (_addMaterialToOverlayOperator) { - return _addMaterialToOverlayOperator(overlayID, material, shapeID); + return _addMaterialToOverlayOperator(overlayID, material, parentMaterialID); } return false; } -bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { +bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { if (_removeMaterialFromOverlayOperator) { - return _removeMaterialFromOverlayOperator(overlayID, material, shapeID); + return _removeMaterialFromOverlayOperator(overlayID, material, parentMaterialID); } return false; } \ No newline at end of file diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index a02ce900ff..a532f64fc9 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -280,15 +280,15 @@ public: void setMyAvatar(std::shared_ptr myAvatar) { _myAvatar = myAvatar; } - static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } - static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } - static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); - static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); + static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } + static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } + static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID); + static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID); - static void setAddMaterialToOverlayOperator(std::function addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; } - static void setRemoveMaterialFromOverlayOperator(std::function removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; } - static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); - static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); + static void setAddMaterialToOverlayOperator(std::function addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; } + static void setRemoveMaterialFromOverlayOperator(std::function removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; } + static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID); + static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID); signals: void deletingEntity(const EntityItemID& entityID); @@ -398,10 +398,10 @@ private: std::shared_ptr _myAvatar{ nullptr }; - static std::function _addMaterialToAvatarOperator; - static std::function _removeMaterialFromAvatarOperator; - static std::function _addMaterialToOverlayOperator; - static std::function _removeMaterialFromOverlayOperator; + static std::function _addMaterialToAvatarOperator; + static std::function _removeMaterialFromAvatarOperator; + static std::function _addMaterialToOverlayOperator; + static std::function _removeMaterialFromOverlayOperator; }; #endif // hifi_EntityTree_h diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 7026da117c..1ebaa4f21a 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -31,9 +31,8 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMode, getMaterialMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendFactor, getBlendFactor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeID, getShapeID); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentMaterialID, getParentMaterialID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialPos, getMaterialPos); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialScale, getMaterialScale); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialRot, getMaterialRot); @@ -45,9 +44,8 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMode, setMaterialMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeID, setShapeID); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentMaterialID, setParentMaterialID); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialPos, setMaterialPos); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialScale, setMaterialScale); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialRot, setMaterialRot); @@ -65,139 +63,6 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { return somethingChanged; } -bool MaterialEntityItem::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) { - if (array.isArray()) { - QJsonArray colorArray = array.toArray(); - if (colorArray.size() >= 3 && colorArray[0].isDouble() && colorArray[1].isDouble() && colorArray[2].isDouble()) { - isSRGB = true; - if (colorArray.size() >= 4) { - if (colorArray[3].isBool()) { - isSRGB = colorArray[3].toBool(); - } - } - color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble()); - return true; - } - } - return false; -} - -void MaterialEntityItem::parseJSONMaterial(const QJsonObject& materialJSON) { - QString name = ""; - std::shared_ptr material = std::make_shared(); - for (auto& key : materialJSON.keys()) { - if (key == "name") { - auto nameJSON = materialJSON.value(key); - if (nameJSON.isString()) { - name = nameJSON.toString(); - } - } else if (key == "emissive") { - glm::vec3 color; - bool isSRGB; - bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); - if (valid) { - material->setEmissive(color, isSRGB); - } - } else if (key == "opacity") { - auto value = materialJSON.value(key); - if (value.isDouble()) { - material->setOpacity(value.toDouble()); - } - } else if (key == "albedo") { - glm::vec3 color; - bool isSRGB; - bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); - if (valid) { - material->setAlbedo(color, isSRGB); - } - } else if (key == "roughness") { - auto value = materialJSON.value(key); - if (value.isDouble()) { - material->setRoughness(value.toDouble()); - } - } else if (key == "fresnel") { - glm::vec3 color; - bool isSRGB; - bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); - if (valid) { - material->setFresnel(color, isSRGB); - } - } else if (key == "metallic") { - auto value = materialJSON.value(key); - if (value.isDouble()) { - material->setMetallic(value.toDouble()); - } - } else if (key == "scattering") { - auto value = materialJSON.value(key); - if (value.isDouble()) { - material->setScattering(value.toDouble()); - } - } else if (key == "emissiveMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setEmissiveMap(value.toString()); - } - } else if (key == "albedoMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - bool useAlphaChannel = false; - auto opacityMap = materialJSON.find("opacityMap"); - if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) { - useAlphaChannel = true; - } - material->setAlbedoMap(value.toString(), useAlphaChannel); - } - } else if (key == "roughnessMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setRoughnessMap(value.toString(), false); - } - } else if (key == "glossMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setRoughnessMap(value.toString(), true); - } - } else if (key == "metallicMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setMetallicMap(value.toString(), false); - } - } else if (key == "specularMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setMetallicMap(value.toString(), true); - } - } else if (key == "normalMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setNormalMap(value.toString(), false); - } - } else if (key == "bumpMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setNormalMap(value.toString(), true); - } - } else if (key == "occlusionMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setOcclusionMap(value.toString()); - } - } else if (key == "scatteringMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setScatteringMap(value.toString()); - } - } else if (key == "lightMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setLightmapMap(value.toString()); - } - } - } - _materials[name] = material; - _materialNames.push_back(name); -} - int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -208,9 +73,8 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); - READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, quint16, setPriority); - READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_ID, QString, setParentMaterialID); READ_ENTITY_PROPERTY(PROP_MATERIAL_POS, glm::vec2, setMaterialPos); READ_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, glm::vec2, setMaterialScale); READ_ENTITY_PROPERTY(PROP_MATERIAL_ROT, float, setMaterialRot); @@ -224,9 +88,8 @@ EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParam EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_MATERIAL_URL; requestedProperties += PROP_MATERIAL_TYPE; - requestedProperties += PROP_MATERIAL_BLEND_FACTOR; requestedProperties += PROP_MATERIAL_PRIORITY; - requestedProperties += PROP_PARENT_SHAPE_ID; + requestedProperties += PROP_PARENT_MATERIAL_ID; requestedProperties += PROP_MATERIAL_POS; requestedProperties += PROP_MATERIAL_SCALE; requestedProperties += PROP_MATERIAL_ROT; @@ -244,9 +107,8 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode bool successPropertyFits = true; APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_ID, getParentMaterialID()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, getMaterialPos()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, getMaterialScale()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, getMaterialRot()); @@ -259,9 +121,8 @@ void MaterialEntityItem::debugDump() const { qCDebug(entities) << " material json:" << _materialURL; qCDebug(entities) << " current material name:" << _currentMaterialName; qCDebug(entities) << " material type:" << _materialMode; - qCDebug(entities) << " blend factor:" << _blendFactor; qCDebug(entities) << " priority:" << _priority; - qCDebug(entities) << " parent shape ID:" << _shapeID; + qCDebug(entities) << " parent material ID:" << _parentMaterialID; qCDebug(entities) << " material pos:" << _materialPos; qCDebug(entities) << " material scale:" << _materialRot; qCDebug(entities) << " material rot:" << _materialScale; @@ -290,6 +151,8 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u removeMaterial(); _materialURL = materialURLString; + // TODO: if URL ends with ?string, try to set _currentMaterialName = string + if (usingUserData) { QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); _materials.clear(); @@ -299,22 +162,39 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u QJsonArray materials = materialJSON.array(); for (auto material : materials) { if (!material.isNull() && material.isObject()) { - parseJSONMaterial(material.toObject()); + auto networkMaterial = NetworkMaterialResource::parseJSONMaterial(material.toObject()); + _materials[networkMaterial.first] = networkMaterial.second; + _materialNames.push_back(networkMaterial.first); } } } else if (materialJSON.isObject()) { - parseJSONMaterial(materialJSON.object()); + auto networkMaterial = NetworkMaterialResource::parseJSONMaterial(materialJSON.object()); + _materials[networkMaterial.first] = networkMaterial.second; + _materialNames.push_back(networkMaterial.first); } } + // Since our material changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(_currentMaterialName); + applyMaterial(); } else { - // get material via network request + _networkMaterial = MaterialCache::instance().getMaterial(materialURLString); + auto onMaterialRequestFinished = [&](bool success) { + if (success) { + _materials[_networkMaterial->name] = _networkMaterial->networkMaterial; + _materialNames.push_back(_networkMaterial->name); + + setCurrentMaterialName(_currentMaterialName); + applyMaterial(); + } + }; + if (_networkMaterial) { + if (_networkMaterial->isLoaded()) { + onMaterialRequestFinished(!_networkMaterial->isFailed()); + } else { + connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished); + } + } } - - // TODO: if URL ends with ?string, try to set _currentMaterialName = string - - // Since our JSON changed, the current name might not be valid anymore, so we need to update - setCurrentMaterialName(_currentMaterialName); - applyMaterial(); } } @@ -361,14 +241,6 @@ void MaterialEntityItem::setMaterialRot(const float& materialRot) { } } -void MaterialEntityItem::setBlendFactor(float blendFactor) { - if (_blendFactor != blendFactor) { - removeMaterial(); - _blendFactor = blendFactor; - applyMaterial(); - } -} - void MaterialEntityItem::setPriority(quint16 priority) { if (_priority != priority) { removeMaterial(); @@ -377,10 +249,10 @@ void MaterialEntityItem::setPriority(quint16 priority) { } } -void MaterialEntityItem::setShapeID(quint16 shapeID) { - if (_shapeID != shapeID) { +void MaterialEntityItem::setParentMaterialID(const QString& parentMaterialID) { + if (_parentMaterialID != parentMaterialID) { removeMaterial(); - _shapeID = shapeID; + _parentMaterialID = parentMaterialID; applyMaterial(); } } @@ -421,16 +293,16 @@ void MaterialEntityItem::removeMaterial() { if (tree) { EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); if (entity) { - entity->removeMaterial(material, getShapeID()); + entity->removeMaterial(material, getParentMaterialID()); return; } } - if (EntityTree::removeMaterialFromAvatar(parentID, material, getShapeID())) { + if (EntityTree::removeMaterialFromAvatar(parentID, material, getParentMaterialID())) { return; } - if (EntityTree::removeMaterialFromOverlay(parentID, material, getShapeID())) { + if (EntityTree::removeMaterialFromOverlay(parentID, material, getParentMaterialID())) { return; } @@ -449,7 +321,6 @@ void MaterialEntityItem::applyMaterial() { textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialRot))); textureTransform.setScale(glm::vec3(_materialScale, 1)); material->setTextureTransforms(textureTransform); - material->setBlendFactor(getBlendFactor()); material->setPriority(getPriority()); // Our parent could be an entity, an avatar, or an overlay @@ -457,16 +328,16 @@ void MaterialEntityItem::applyMaterial() { if (tree) { EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); if (entity) { - entity->addMaterial(material, getShapeID()); + entity->addMaterial(material, getParentMaterialID()); return; } } - if (EntityTree::addMaterialToAvatar(parentID, material, getShapeID())) { + if (EntityTree::addMaterialToAvatar(parentID, material, getParentMaterialID())) { return; } - if (EntityTree::addMaterialToOverlay(parentID, material, getShapeID())) { + if (EntityTree::addMaterialToOverlay(parentID, material, getParentMaterialID())) { return; } diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index 40137acf22..dde9b60da9 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -13,6 +13,7 @@ #include "MaterialMode.h" #include +#include class MaterialEntityItem : public EntityItem { using Pointer = std::shared_ptr; @@ -60,14 +61,11 @@ public: MaterialMode getMaterialMode() const { return _materialMode; } void setMaterialMode(MaterialMode mode) { _materialMode = mode; } - float getBlendFactor() const { return _blendFactor; } - void setBlendFactor(float blendFactor); - quint16 getPriority() const { return _priority; } void setPriority(quint16 priority); - quint16 getShapeID() const { return _shapeID; } - void setShapeID(quint16 shapeID); + QString getParentMaterialID() const { return _parentMaterialID; } + void setParentMaterialID(const QString& parentMaterialID); glm::vec2 getMaterialPos() const { return _materialPos; } void setMaterialPos(const glm::vec2& materialPos); @@ -93,22 +91,19 @@ public: private: QString _materialURL; MaterialMode _materialMode { UV }; - float _blendFactor { 1.0f }; quint16 _priority { 0 }; - quint16 _shapeID { 0 }; + QString _parentMaterialID { "0" }; glm::vec2 _materialPos { 0, 0 }; glm::vec2 _materialScale { 1, 1 }; float _materialRot { 0 }; + NetworkMaterialResourcePointer _networkMaterial; QHash> _materials; std::vector _materialNames; QString _currentMaterialName; bool _retryApply { false }; - void parseJSONMaterial(const QJsonObject& materialJSON); - static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); - }; #endif // hifi_MaterialEntityItem_h diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 6731d544b8..5b3396dfc5 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -354,9 +354,6 @@ public: size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } - void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } - float getBlendFactor() { return _blendFactor; } - void setPriority(quint16 priority) { _priority = priority; } quint16 getPriority() { return _priority; } @@ -375,7 +372,6 @@ private: mutable bool _hasCalculatedTextureInfo { false }; bool calculateMaterialInfo() const; - float _blendFactor { 1.0f }; quint16 _priority { 0 }; }; diff --git a/libraries/model-networking/src/model-networking/MaterialCache.cpp b/libraries/model-networking/src/model-networking/MaterialCache.cpp new file mode 100644 index 0000000000..723448f65a --- /dev/null +++ b/libraries/model-networking/src/model-networking/MaterialCache.cpp @@ -0,0 +1,175 @@ +// +// Created by Sam Gondelman on 2/9/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "MaterialCache.h" + +#include "QJsonObject" +#include "QJsonDocument" +#include "QJsonArray" + +NetworkMaterialResource::NetworkMaterialResource(const QUrl& url) : + Resource(url) {} + +void NetworkMaterialResource::downloadFinished(const QByteArray& data) { + if (_url.toString().endsWith(".json")) { + QJsonDocument materialJSON = QJsonDocument::fromJson(data); + if (!materialJSON.isNull() && materialJSON.isObject()) { + auto parsedMaterial = parseJSONMaterial(materialJSON.object()); + name = parsedMaterial.first; + networkMaterial = parsedMaterial.second; + } + } + + // TODO: parse other material types + + finishedLoading(true); +} + +bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) { + if (array.isArray()) { + QJsonArray colorArray = array.toArray(); + if (colorArray.size() >= 3 && colorArray[0].isDouble() && colorArray[1].isDouble() && colorArray[2].isDouble()) { + isSRGB = true; + if (colorArray.size() >= 4) { + if (colorArray[3].isBool()) { + isSRGB = colorArray[3].toBool(); + } + } + color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble()); + return true; + } + } + return false; +} + +std::pair> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON) { + QString name = ""; + std::shared_ptr material = std::make_shared(); + for (auto& key : materialJSON.keys()) { + if (key == "name") { + auto nameJSON = materialJSON.value(key); + if (nameJSON.isString()) { + name = nameJSON.toString(); + } + } else if (key == "emissive") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setEmissive(color, isSRGB); + } + } else if (key == "opacity") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setOpacity(value.toDouble()); + } + } else if (key == "albedo") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setAlbedo(color, isSRGB); + } + } else if (key == "roughness") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setRoughness(value.toDouble()); + } + } else if (key == "fresnel") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setFresnel(color, isSRGB); + } + } else if (key == "metallic") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setMetallic(value.toDouble()); + } + } else if (key == "scattering") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setScattering(value.toDouble()); + } + } else if (key == "emissiveMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setEmissiveMap(value.toString()); + } + } else if (key == "albedoMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + bool useAlphaChannel = false; + auto opacityMap = materialJSON.find("opacityMap"); + if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) { + useAlphaChannel = true; + } + material->setAlbedoMap(value.toString(), useAlphaChannel); + } + } else if (key == "roughnessMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setRoughnessMap(value.toString(), false); + } + } else if (key == "glossMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setRoughnessMap(value.toString(), true); + } + } else if (key == "metallicMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setMetallicMap(value.toString(), false); + } + } else if (key == "specularMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setMetallicMap(value.toString(), true); + } + } else if (key == "normalMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setNormalMap(value.toString(), false); + } + } else if (key == "bumpMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setNormalMap(value.toString(), true); + } + } else if (key == "occlusionMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setOcclusionMap(value.toString()); + } + } else if (key == "scatteringMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setScatteringMap(value.toString()); + } + } else if (key == "lightMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setLightmapMap(value.toString()); + } + } + } + return std::pair>(name, material); +} + +MaterialCache& MaterialCache::instance() { + static MaterialCache _instance; + return _instance; +} + +NetworkMaterialResourcePointer MaterialCache::getMaterial(const QUrl& url) { + return ResourceCache::getResource(url, QUrl(), nullptr).staticCast(); +} + +QSharedPointer MaterialCache::createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) { + return QSharedPointer(new NetworkMaterialResource(url), &Resource::deleter); +} \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/MaterialCache.h b/libraries/model-networking/src/model-networking/MaterialCache.h new file mode 100644 index 0000000000..1b0f1c577c --- /dev/null +++ b/libraries/model-networking/src/model-networking/MaterialCache.h @@ -0,0 +1,46 @@ +// +// Created by Sam Gondelman on 2/9/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_MaterialCache_h +#define hifi_MaterialCache_h + +#include + +#include "glm/glm.hpp" + +#include "ModelCache.h" + +class NetworkMaterialResource : public Resource { +public: + NetworkMaterialResource(const QUrl& url); + + QString getType() const override { return "NetworkMaterial"; } + + virtual void downloadFinished(const QByteArray& data) override; + + QString name { "" }; + std::shared_ptr networkMaterial { nullptr }; + + static std::pair> parseJSONMaterial(const QJsonObject& materialJSON); + +private: + static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); +}; + +using NetworkMaterialResourcePointer = QSharedPointer; + +class MaterialCache : public ResourceCache { +public: + static MaterialCache& instance(); + + NetworkMaterialResourcePointer getMaterial(const QUrl& url); + +protected: + virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; +}; + +#endif diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 32deba3687..739f401ee7 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -495,8 +495,8 @@ NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) : Material(m), _textures(m._textures), _albedoTransform(m._albedoTransform), - _lightmapParams(m._lightmapParams), _lightmapTransform(m._lightmapTransform), + _lightmapParams(m._lightmapParams), _isOriginal(m._isOriginal) {} diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index 5d39583c9e..115e665b77 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -23,7 +23,7 @@ void ResourceRequest::send() { QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection); return; } - + Q_ASSERT(_state == NotStarted); _state = InProgress; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 805995edfb..3a9ea45d77 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1524,48 +1524,62 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } -void Model::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { - if (shapeID < _modelMeshRenderItemIDs.size()) { - render::Transaction transaction; - auto itemID = _modelMeshRenderItemIDs[shapeID]; - bool visible = isVisible(); - uint8_t viewTagBits = getViewTagBits(); - bool layeredInFront = isLayeredInFront(); - bool layeredInHUD = isLayeredInHUD(); - bool wireframe = isWireframe(); - auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; - bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, - invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { - data.addMaterial(material); - // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); - data.setShapeKey(invalidatePayloadShapeKey, wireframe); - }); - AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); - } +std::vector Model::getMeshIDsFromMaterialID(const QString& parentMaterialID) { + std::vector toReturn; + // TODO: first, try to find all meshes with materials that match parentMaterialID as a string + // if none, return parentMaterialID as a uint + toReturn.push_back(parentMaterialID.toUInt()); + return toReturn; } -void Model::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { - if (shapeID < _modelMeshRenderItemIDs.size()) { - render::Transaction transaction; - auto itemID = _modelMeshRenderItemIDs[shapeID]; - bool visible = isVisible(); - uint8_t viewTagBits = getViewTagBits(); - bool layeredInFront = isLayeredInFront(); - bool layeredInHUD = isLayeredInHUD(); - bool wireframe = isWireframe(); - auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; - bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, - invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { - data.removeMaterial(material); - // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); - data.setShapeKey(invalidatePayloadShapeKey, wireframe); - }); - AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); +void Model::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + std::vector shapeIDs = getMeshIDsFromMaterialID(parentMaterialID); + render::Transaction transaction; + for (auto shapeID : shapeIDs) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.addMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + } } + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); +} + +void Model::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + std::vector shapeIDs = getMeshIDsFromMaterialID(parentMaterialID); + render::Transaction transaction; + for (auto shapeID : shapeIDs) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.removeMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + } + } + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); } class CollisionRenderGeometry : public Geometry { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 80067aff2a..b4152324bc 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -318,8 +318,8 @@ public: void scaleToFit(); - void addMaterial(graphics::MaterialPointer material, quint16 shapeID); - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); public slots: void loadURLFinished(bool success); @@ -471,6 +471,8 @@ private: float _loadingPriority { 0.0f }; void calculateTextureInfo(); + + std::vector getMeshIDsFromMaterialID(const QString& parentMaterialID); }; Q_DECLARE_METATYPE(ModelPointer) diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 25b2cec331..4dbbd190ff 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -256,6 +256,13 @@ namespace std { return result; } }; + + template <> + struct hash { + size_t operator()(const QString& a) const { + return qHash(a); + } + }; } enum ContactEventType { diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 348d93d589..5eedd1c7e4 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -780,19 +780,14 @@ -
- - -
-
-
- - +
+ +
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 3558a36c04..01ec4ae283 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -633,9 +633,8 @@ function loaded() { var elMaterialURL = document.getElementById("property-material-url"); var elMaterialMode = document.getElementById("property-material-mode"); - var elBlendFactor = document.getElementById("property-blend-factor"); var elPriority = document.getElementById("property-priority"); - var elShapeID = document.getElementById("property-shape-id"); + var elParentMaterialID = document.getElementById("property-parent-material-id"); var elMaterialPosX = document.getElementById("property-material-pos-x"); var elMaterialPosY = document.getElementById("property-material-pos-y"); var elMaterialScaleX = document.getElementById("property-material-scale-x"); @@ -1130,9 +1129,8 @@ function loaded() { elMaterialURL.value = properties.materialURL; elMaterialMode.value = properties.materialMode; setDropdownText(elMaterialMode); - elBlendFactor.value = properties.blendFactor.toFixed(2); elPriority.value = properties.priority; - elShapeID.value = properties.shapeID; + elParentMaterialID.value = properties.parentMaterialID; elMaterialPosX.value = properties.materialPos.x.toFixed(4); elMaterialPosY.value = properties.materialPos.y.toFixed(4); elMaterialScaleX.value = properties.materialScale.x.toFixed(4); @@ -1410,9 +1408,8 @@ function loaded() { elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL')); elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode')); - elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2)); elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority', 0)); - elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID', 0)); + elParentMaterialID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentMaterialID')); var materialPosChangeFunction = createEmitVec2PropertyUpdateFunction('materialPos', elMaterialPosX, elMaterialPosY); elMaterialPosX.addEventListener('change', materialPosChangeFunction); From ad409618640071ca84824765c656b7467a53ac19 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 12 Feb 2018 13:46:27 -0800 Subject: [PATCH 05/12] fix tangents (I think), update material rendering when transform changes --- .../src/RenderableMaterialEntityItem.cpp | 13 ++++++++++++- .../src/RenderableMaterialEntityItem.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index ad17202d8e..529aa03124 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -18,6 +18,9 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP if (entity->getParentID() != _parentID || entity->getClientOnly() != _clientOnly || entity->getOwningAvatarID() != _owningAvatarID) { return true; } + if (entity->getMaterialPos() != _materialPos || entity->getMaterialScale() != _materialScale || entity->getMaterialRot() != _materialRot) { + return true; + } return false; } @@ -27,6 +30,9 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& _parentID = entity->getParentID(); _clientOnly = entity->getClientOnly(); _owningAvatarID = entity->getOwningAvatarID(); + _materialPos = entity->getMaterialPos(); + _materialScale = entity->getMaterialScale(); + _materialRot = entity->getMaterialRot(); _renderTransform = getModelTransform(); const float MATERIAL_ENTITY_SCALE = 0.5f; _renderTransform.postScale(MATERIAL_ENTITY_SCALE); @@ -91,7 +97,7 @@ glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) { } glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) { - return glm::vec3(-glm::cos(theta) * glm::cos(phi), 0, -glm::cos(theta) * glm::sin(phi)); + return glm::vec3(-glm::cos(theta) * glm::cos(phi), glm::sin(theta), -glm::cos(theta) * glm::sin(phi)); } void MaterialEntityRenderer::addVertex(std::vector& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) { @@ -227,16 +233,21 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { QUuid parentID; Transform renderTransform; graphics::MaterialPointer drawMaterial; + Transform textureTransform; withReadLock([&] { parentID = _clientOnly ? _owningAvatarID : _parentID; renderTransform = _renderTransform; drawMaterial = _drawMaterial; + textureTransform.setTranslation(glm::vec3(_materialPos, 0)); + textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialRot))); + textureTransform.setScale(glm::vec3(_materialScale, 1)); }); if (!parentID.isNull() || !drawMaterial) { return; } batch.setModelTransform(renderTransform); + drawMaterial->setTextureTransforms(textureTransform); // bind the material args->_shapePipeline->bindMaterial(drawMaterial, batch, args->_enableTexturing); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index af8cef9351..4af21d84f6 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -34,6 +34,9 @@ private: QUuid _parentID; bool _clientOnly; QUuid _owningAvatarID; + glm::vec2 _materialPos; + glm::vec2 _materialScale; + float _materialRot; Transform _renderTransform; std::shared_ptr _drawMaterial; From 38290064c1c6510f2d3dd6b2333c03ef7dd2b6a8 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 13 Feb 2018 13:24:08 -0800 Subject: [PATCH 06/12] replace materials by name, hide material mode for now --- libraries/entities/src/MaterialEntityItem.cpp | 8 ++- libraries/entities/src/MaterialEntityItem.h | 29 +++++++++-- libraries/graphics/src/graphics/Material.cpp | 3 ++ libraries/graphics/src/graphics/Material.h | 5 ++ .../src/model-networking/ModelCache.cpp | 1 + libraries/render-utils/src/Model.cpp | 24 +++++++-- libraries/render-utils/src/Model.h | 3 +- scripts/system/html/entityProperties.html | 34 ++++++++----- scripts/system/html/js/entityProperties.js | 49 ++++++++++++++++--- 9 files changed, 126 insertions(+), 30 deletions(-) diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 1ebaa4f21a..fcca2d9803 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -346,8 +346,12 @@ void MaterialEntityItem::applyMaterial() { } void MaterialEntityItem::postAdd() { - removeMaterial(); - applyMaterial(); + // postAdd is called every time we are added to a new octree cell, but we only need to update the material the first time + if (!_hasBeenAddedToOctree) { + removeMaterial(); + applyMaterial(); + _hasBeenAddedToOctree = true; + } } void MaterialEntityItem::preDelete() { diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index dde9b60da9..d015bae681 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -19,7 +19,7 @@ class MaterialEntityItem : public EntityItem { using Pointer = std::shared_ptr; public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - + MaterialEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated @@ -44,9 +44,9 @@ public: virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) override; + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; void debugDump() const override; @@ -89,20 +89,39 @@ public: void postParentFixup() override; private: + // URL for this material. Currently, only JSON format is supported. Set to "userData" to use the user data to live edit a material. + // The following fields are supported in the JSON: + // strings: + // name (NOT YET USED) + // floats: + // opacity, roughness, metallic, scattering + // colors (arrays of 3 floats 0-1. Optional fourth value in array can be a boolean isSRGB): + // emissive, albedo, fresnel + // urls to textures: + // emissiveMap, albedoMap, metallicMap, roughnessMap, normalMap, occlusionMap, lightmapMap, scatteringMap QString _materialURL; + // Type of material. "uv" or "projected". NOT YET IMPLEMENTED, only UV is used MaterialMode _materialMode { UV }; + // Priority for this material when applying it to its parent. Only the highest priority material will be used. Materials with the same priority are (essentially) randomly sorted. + // Base materials that come with models always have priority 0. quint16 _priority { 0 }; + // An identifier for choosing a submesh or submeshes within a parent. If in the format "mat::", all submeshes with material name "" will be replaced. Otherwise, + // parentMaterialID will be parsed as an unsigned int (strings not starting with "mat::" will parse to 0), representing the mesh index to modify. QString _parentMaterialID { "0" }; + // Offset position in UV-space of top left of material, (0, 0) to (1, 1) glm::vec2 _materialPos { 0, 0 }; + // How much to scale this material within its parent's UV-space glm::vec2 _materialScale { 1, 1 }; + // How much to rotate this material within its parent's UV-space (degrees) float _materialRot { 0 }; - + NetworkMaterialResourcePointer _networkMaterial; QHash> _materials; std::vector _materialNames; QString _currentMaterialName; bool _retryApply { false }; + bool _hasBeenAddedToOctree { false }; }; diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index 7c66c8ab07..2bf58bc6fb 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -34,6 +34,7 @@ Material::Material() : } Material::Material(const Material& material) : + _name(material._name), _key(material._key), _textureMaps(material._textureMaps) { @@ -50,6 +51,8 @@ Material::Material(const Material& material) : Material& Material::operator= (const Material& material) { QMutexLocker locker(&_textureMapsMutex); + _name = material._name; + _key = (material._key); _textureMaps = (material._textureMaps); _hasCalculatedTextureInfo = false; diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 5b3396dfc5..5abc090be3 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -359,6 +359,11 @@ public: void setTextureTransforms(const Transform& transform); + const QString& getName() { return _name; } + +protected: + QString _name { "" }; + private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 739f401ee7..19ee05d1e2 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -619,6 +619,7 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur graphics::Material(*material._material), _textures(MapChannel::NUM_MAP_CHANNELS) { + _name = material.name; if (!material.albedoTexture.filename.isEmpty()) { auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); _albedoTransform = material.albedoTexture.transform; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3a9ea45d77..84687a46d0 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -828,6 +828,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti _modelMeshRenderItemIDs.clear(); _modelMeshRenderItemsMap.clear(); _modelMeshRenderItems.clear(); + _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); foreach(auto item, _collisionRenderItemsMap.keys()) { @@ -1456,6 +1457,7 @@ void Model::createVisibleRenderItemSet() { Q_ASSERT(_modelMeshRenderItems.isEmpty()); _modelMeshRenderItems.clear(); + _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); Transform transform; @@ -1479,6 +1481,7 @@ void Model::createVisibleRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); + _modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName()); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; } @@ -1524,11 +1527,24 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } -std::vector Model::getMeshIDsFromMaterialID(const QString& parentMaterialID) { - std::vector toReturn; - // TODO: first, try to find all meshes with materials that match parentMaterialID as a string +std::vector Model::getMeshIDsFromMaterialID(QString parentMaterialID) { + // try to find all meshes with materials that match parentMaterialID as a string // if none, return parentMaterialID as a uint - toReturn.push_back(parentMaterialID.toUInt()); + std::vector toReturn; + const QString MATERIAL_NAME_PREFIX = "mat::"; + if (parentMaterialID.startsWith(MATERIAL_NAME_PREFIX)) { + parentMaterialID.replace(0, MATERIAL_NAME_PREFIX.size(), QString("")); + for (int i = 0; i < _modelMeshMaterialNames.size(); i++) { + if (_modelMeshMaterialNames[i] == parentMaterialID) { + toReturn.push_back(i); + } + } + } + + if (toReturn.empty()) { + toReturn.push_back(parentMaterialID.toUInt()); + } + return toReturn; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index b4152324bc..67bc646473 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -438,6 +438,7 @@ protected: render::ItemIDs _modelMeshRenderItemIDs; using ShapeInfo = struct { int meshIndex; }; std::vector _modelMeshRenderItemShapes; + std::vector _modelMeshMaterialNames; bool _addedToScene { false }; // has been added to scene bool _needsFixupInScene { true }; // needs to be removed/re-added to scene @@ -472,7 +473,7 @@ private: void calculateTextureInfo(); - std::vector getMeshIDsFromMaterialID(const QString& parentMaterialID); + std::vector getMeshIDsFromMaterialID(QString parentMaterialID); }; Q_DECLARE_METATYPE(ModelPointer) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 5eedd1c7e4..a70e42a7e1 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -772,12 +772,19 @@
-