wip live material swapping on model entities, model overlays, avatars,

and albedo swap on shape entities
This commit is contained in:
SamGondelman 2018-02-05 18:08:36 -08:00
parent 4d4294dd6a
commit 84cd0e1529
52 changed files with 1038 additions and 251 deletions

View file

@ -22,6 +22,8 @@ setup_memory_debugger()
symlink_or_copy_directory_beside_target(${_SHOULD_SYMLINK_RESOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/resources" "resources") symlink_or_copy_directory_beside_target(${_SHOULD_SYMLINK_RESOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/resources" "resources")
# link the shared hifi libraries # link the shared hifi libraries
include_hifi_library_headers(gpu)
include_hifi_library_headers(graphics)
link_hifi_libraries(embedded-webserver networking shared avatars) link_hifi_libraries(embedded-webserver networking shared avatars)
# find OpenSSL # find OpenSSL

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path d="M348.5,162.5c1.7,0,3,1.4,3,3v181.4c0,1.7-1.3,3-3,3H167.2c-1.6,0-3-1.3-3-3V165.5c0-1.6,1.4-3,3-3H348.5 M348.5,145.5
H167.2c-11,0-20,9-20,20v181.4c0,11,9,20,20,20h181.4c11,0,20-9,20-20V165.5C368.5,154.5,359.6,145.5,348.5,145.5L348.5,145.5z"/>
<rect x="161.6" y="253.6" width="96.3" height="96.3"/>
<rect x="256.1" y="159.8" width="95.4" height="95.4"/>
</svg>

After

Width:  |  Height:  |  Size: 717 B

View file

@ -135,7 +135,7 @@ TabView {
} }
NewEntityButton { NewEntityButton {
icon: "icons/create-icons/94-model-01.svg" icon: "icons/create-icons/126-material-01.svg"
text: "MATERIAL" text: "MATERIAL"
onClicked: { onClicked: {
editRoot.sendToScript({ editRoot.sendToScript({

View file

@ -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<AvatarManager>();
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<AvatarManager>();
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. // Keyboard focus handling for Web overlays.
auto overlays = &(qApp->getOverlays()); auto overlays = &(qApp->getOverlays());
connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) { connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) {

View file

@ -632,3 +632,29 @@ uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const {
} }
return 0; 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<std::mutex> lock(_materialsLock);
for (auto& shapeMaterialPair : _materials) {
auto material = shapeMaterialPair.second;
while (!material.empty()) {
_model->addMaterial(material.top(), shapeMaterialPair.first);
material.pop();
}
}
}

View file

@ -59,6 +59,9 @@ public:
void setDrawInFront(bool drawInFront) override; void setDrawInFront(bool drawInFront) override;
void setDrawHUDLayer(bool drawHUDLayer) override; void setDrawHUDLayer(bool drawHUDLayer) override;
void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override;
void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override;
protected: protected:
Transform evalRenderTransform() override; Transform evalRenderTransform() override;
@ -110,6 +113,8 @@ private:
bool _drawInFrontDirty { false }; bool _drawInFrontDirty { false };
bool _drawInHUDDirty { false }; bool _drawInHUDDirty { false };
void processMaterials();
}; };
#endif // hifi_ModelOverlay_h #endif // hifi_ModelOverlay_h

View file

@ -235,3 +235,13 @@ QVector<OverlayID> qVectorOverlayIDFromScriptValue(const QScriptValue& array) {
} }
return newVector; return newVector;
} }
void Overlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) {
std::lock_guard<std::mutex> lock(_materialsLock);
_materials[shapeID].push(material);
}
void Overlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) {
std::lock_guard<std::mutex> lock(_materialsLock);
_materials[shapeID].remove(material);
}

View file

@ -91,6 +91,9 @@ public:
unsigned int getStackOrder() const { return _stackOrder; } unsigned int getStackOrder() const { return _stackOrder; }
void setStackOrder(unsigned int stackOrder) { _stackOrder = 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: protected:
float updatePulse(); float updatePulse();
@ -117,6 +120,9 @@ protected:
static const xColor DEFAULT_OVERLAY_COLOR; static const xColor DEFAULT_OVERLAY_COLOR;
static const float DEFAULT_ALPHA; static const float DEFAULT_ALPHA;
std::unordered_map<quint16, graphics::MultiMaterial> _materials;
std::mutex _materialsLock;
private: private:
OverlayID _overlayID; // only used for non-3d overlays OverlayID _overlayID; // only used for non-3d overlays
}; };

View file

@ -570,6 +570,7 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc
} }
transaction.resetItem(_renderItemID, avatarPayloadPointer); transaction.resetItem(_renderItemID, avatarPayloadPointer);
_skeletonModel->addToScene(scene, transaction); _skeletonModel->addToScene(scene, transaction);
processMaterials();
for (auto& attachmentModel : _attachmentModels) { for (auto& attachmentModel : _attachmentModels) {
attachmentModel->addToScene(scene, transaction); attachmentModel->addToScene(scene, transaction);
} }
@ -761,6 +762,7 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) { if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
_skeletonModel->removeFromScene(scene, transaction); _skeletonModel->removeFromScene(scene, transaction);
_skeletonModel->addToScene(scene, transaction); _skeletonModel->addToScene(scene, transaction);
processMaterials();
canTryFade = true; canTryFade = true;
_isAnimatingScale = true; _isAnimatingScale = true;
} }
@ -1760,3 +1762,31 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const {
return DEFAULT_AVATAR_EYE_HEIGHT; return DEFAULT_AVATAR_EYE_HEIGHT;
} }
} }
void Avatar::addMaterial(graphics::MaterialPointer material, quint16 shapeID) {
std::lock_guard<std::mutex> 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<std::mutex> lock(_materialsLock);
_materials[shapeID].remove(material);
if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) {
_skeletonModel->removeMaterial(material, shapeID);
}
}
void Avatar::processMaterials() {
assert(_skeletonModel);
std::lock_guard<std::mutex> lock(_materialsLock);
for (auto& shapeMaterialPair : _materials) {
auto material = shapeMaterialPair.second;
while (!material.empty()) {
_skeletonModel->addMaterial(material.top(), shapeMaterialPair.first);
material.pop();
}
}
}

View file

@ -272,6 +272,9 @@ public:
virtual void setAvatarEntityDataChanged(bool value) override; virtual void setAvatarEntityDataChanged(bool value) override;
void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override;
void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override;
public slots: public slots:
// FIXME - these should be migrated to use Pose data instead // FIXME - these should be migrated to use Pose data instead
@ -397,6 +400,11 @@ protected:
float _displayNameAlpha { 1.0f }; float _displayNameAlpha { 1.0f };
ThreadSafeValueCache<float> _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT }; ThreadSafeValueCache<float> _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT };
std::unordered_map<quint16, graphics::MultiMaterial> _materials;
std::mutex _materialsLock;
void processMaterials();
}; };
#endif // hifi_Avatar_h #endif // hifi_Avatar_h

View file

@ -1,3 +1,4 @@
set(TARGET_NAME avatars) set(TARGET_NAME avatars)
setup_hifi_library(Network Script) setup_hifi_library(Network Script)
link_hifi_libraries(shared networking) include_hifi_library_headers(gpu)
link_hifi_libraries(shared networking graphics)

View file

@ -2558,4 +2558,4 @@ void AvatarEntityMapFromScriptValue(const QScriptValue& object, AvatarEntityMap&
value[EntityID] = binaryEntityProperties; value[EntityID] = binaryEntityProperties;
} }
} }

View file

@ -54,6 +54,8 @@
#include "HeadData.h" #include "HeadData.h"
#include "PathUtils.h" #include "PathUtils.h"
#include <graphics/Material.h>
using AvatarSharedPointer = std::shared_ptr<AvatarData>; using AvatarSharedPointer = std::shared_ptr<AvatarData>;
using AvatarWeakPointer = std::weak_ptr<AvatarData>; using AvatarWeakPointer = std::weak_ptr<AvatarData>;
using AvatarHash = QHash<QUuid, AvatarSharedPointer>; using AvatarHash = QHash<QUuid, AvatarSharedPointer>;
@ -694,6 +696,9 @@ public:
bool getIsReplicated() const { return _isReplicated; } bool getIsReplicated() const { return _isReplicated; }
virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID) {}
virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) {}
signals: signals:
void displayNameChanged(); void displayNameChanged();
void sessionDisplayNameChanged(); void sessionDisplayNameChanged();

View file

@ -146,6 +146,9 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _entity(entity
_needsRenderUpdate = true; _needsRenderUpdate = true;
emit requestRenderUpdate(); emit requestRenderUpdate();
}); });
_materials = entity->getMaterials();
connect(entity.get(), &EntityItem::addMaterialToRenderItem, this, &EntityRenderer::addMaterial);
connect(entity.get(), &EntityItem::removeMaterialFromRenderItem, this, &EntityRenderer::removeMaterial);
} }
EntityRenderer::~EntityRenderer() { } EntityRenderer::~EntityRenderer() { }
@ -399,4 +402,14 @@ void EntityRenderer::onAddToScene(const EntityItemPointer& entity) {
void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) { void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) {
entity->deregisterChangeHandler(_changeHandlerId); entity->deregisterChangeHandler(_changeHandlerId);
QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr); QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr);
}
void EntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) {
std::lock_guard<std::mutex> lock(_materialsLock);
_materials[shapeID].push(material);
}
void EntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) {
std::lock_guard<std::mutex> lock(_materialsLock);
_materials[shapeID].remove(material);
} }

View file

@ -101,6 +101,10 @@ protected:
return result; return result;
} }
public slots:
virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID);
virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID);
signals: signals:
void requestRenderUpdate(); void requestRenderUpdate();
@ -129,6 +133,8 @@ protected:
// Only touched on the rendering thread // Only touched on the rendering thread
bool _renderUpdateQueued{ false }; bool _renderUpdateQueued{ false };
std::unordered_map<quint16, graphics::MultiMaterial> _materials;
std::mutex _materialsLock;
private: private:
// The base class relies on comparing the model transform to the entity transform in order // The base class relies on comparing the model transform to the entity transform in order

View file

@ -15,12 +15,18 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP
if (entity->getMaterial() != _drawMaterial) { if (entity->getMaterial() != _drawMaterial) {
return true; return true;
} }
if (entity->getParentID() != _parentID || entity->getClientOnly() != _clientOnly || entity->getOwningAvatarID() != _owningAvatarID) {
return true;
}
return false; return false;
} }
void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] { withWriteLock([&] {
_drawMaterial = entity->getMaterial(); _drawMaterial = entity->getMaterial();
_parentID = entity->getParentID();
_clientOnly = entity->getClientOnly();
_owningAvatarID = entity->getOwningAvatarID();
_renderTransform = getModelTransform(); _renderTransform = getModelTransform();
const float MATERIAL_ENTITY_SCALE = 0.5f; const float MATERIAL_ENTITY_SCALE = 0.5f;
_renderTransform.postScale(MATERIAL_ENTITY_SCALE); _renderTransform.postScale(MATERIAL_ENTITY_SCALE);
@ -30,7 +36,7 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
ItemKey MaterialEntityRenderer::getKey() { ItemKey MaterialEntityRenderer::getKey() {
ItemKey::Builder builder; ItemKey::Builder builder;
builder.withTypeShape(); builder.withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
if (!_visible) { if (!_visible) {
builder.withInvisible(); builder.withInvisible();
@ -215,13 +221,25 @@ void MaterialEntityRenderer::generateMesh() {
void MaterialEntityRenderer::doRender(RenderArgs* args) { void MaterialEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render"); PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);
gpu::Batch& batch = *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 // bind the material
args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); args->_shapePipeline->bindMaterial(drawMaterial, batch, args->_enableTexturing);
args->_details._materialSwitches++; args->_details._materialSwitches++;
// Draw! // Draw!

View file

@ -31,6 +31,9 @@ private:
ItemKey getKey() override; ItemKey getKey() override;
ShapeKey getShapeKey() override; ShapeKey getShapeKey() override;
QUuid _parentID;
bool _clientOnly;
QUuid _owningAvatarID;
Transform _renderTransform; Transform _renderTransform;
std::shared_ptr<NetworkMaterial> _drawMaterial; std::shared_ptr<NetworkMaterial> _drawMaterial;
@ -47,7 +50,7 @@ private:
static void addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv); static void addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv);
const int SLICES = 15; const int SLICES = 15;
const int STACKS = 9; 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;
}; };
} } } }

View file

@ -1380,6 +1380,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
auto entityRenderer = static_cast<EntityRenderer*>(&data); auto entityRenderer = static_cast<EntityRenderer*>(&data);
entityRenderer->setSubRenderItemIDs(newRenderItemIDs); 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<std::mutex> lock(_materialsLock);
for (auto& shapeMaterialPair : _materials) {
auto material = shapeMaterialPair.second;
while (!material.empty()) {
_model->addMaterial(material.top(), shapeMaterialPair.first);
material.pop();
}
}
}

View file

@ -138,10 +138,15 @@ namespace render { namespace entities {
class ModelEntityRenderer : public TypedEntityRenderer<RenderableModelEntityItem> { class ModelEntityRenderer : public TypedEntityRenderer<RenderableModelEntityItem> {
using Parent = TypedEntityRenderer<RenderableModelEntityItem>; using Parent = TypedEntityRenderer<RenderableModelEntityItem>;
friend class EntityRenderer; friend class EntityRenderer;
Q_OBJECT
public: public:
ModelEntityRenderer(const EntityItemPointer& entity); ModelEntityRenderer(const EntityItemPointer& entity);
public slots:
void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override;
void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override;
protected: protected:
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override; virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override; virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
@ -194,6 +199,8 @@ private:
uint64_t _lastAnimated { 0 }; uint64_t _lastAnimated { 0 };
render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() }; render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
void processMaterials();
}; };
} } // namespace } } // namespace

View file

@ -54,8 +54,7 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
if (_lastUserData != entity->getUserData()) { if (_lastUserData != entity->getUserData()) {
return true; return true;
} }
glm::vec4 newColor(toGlm(entity->getXColor()), entity->getLocalRenderAlpha()); if (_material != entity->getMaterial()) {
if (newColor != _color) {
return true; return true;
} }
@ -78,7 +77,9 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
_procedural.setProceduralData(ProceduralData::parse(_lastUserData)); _procedural.setProceduralData(ProceduralData::parse(_lastUserData));
} }
_color = vec4(toGlm(entity->getXColor()), entity->getLocalRenderAlpha()); removeMaterial(_material, 0);
_material = entity->getMaterial();
addMaterial(_material, 0);
_shape = entity->getShape(); _shape = entity->getShape();
_position = entity->getWorldPosition(); _position = entity->getWorldPosition();
@ -112,14 +113,13 @@ bool ShapeEntityRenderer::isTransparent() const {
return Parent::isTransparent(); return Parent::isTransparent();
} }
void ShapeEntityRenderer::doRender(RenderArgs* args) { void ShapeEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableShapeEntityItem::render"); PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
std::shared_ptr<graphics::Material> mat;
auto geometryCache = DependencyManager::get<GeometryCache>(); auto geometryCache = DependencyManager::get<GeometryCache>();
GeometryCache::Shape geometryShape; GeometryCache::Shape geometryShape;
bool proceduralRender = false; bool proceduralRender = false;
@ -127,15 +127,22 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
withReadLock([&] { withReadLock([&] {
geometryShape = geometryCache->getShapeForEntityShape(_shape); geometryShape = geometryCache->getShapeForEntityShape(_shape);
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
outColor = _color; mat = _materials[0].top();
if (_procedural.isReady()) { if (mat) {
_procedural.prepare(batch, _position, _dimensions, _orientation); outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity());
outColor = _procedural.getColor(_color); if (_procedural.isReady()) {
outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; _procedural.prepare(batch, _position, _dimensions, _orientation);
proceduralRender = true; outColor = _procedural.getColor(outColor);
outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f;
proceduralRender = true;
}
} }
}); });
if (!mat) {
return;
}
if (proceduralRender) { if (proceduralRender) {
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
geometryCache->renderWireShape(batch, geometryShape, outColor); geometryCache->renderWireShape(batch, geometryShape, outColor);

View file

@ -34,7 +34,7 @@ private:
QString _lastUserData; QString _lastUserData;
Transform _renderTransform; Transform _renderTransform;
entity::Shape _shape { entity::Sphere }; entity::Shape _shape { entity::Sphere };
glm::vec4 _color; std::shared_ptr<graphics::Material> _material;
glm::vec3 _position; glm::vec3 _position;
glm::vec3 _dimensions; glm::vec3 _dimensions;
glm::quat _orientation; glm::quat _orientation;

View file

@ -93,7 +93,7 @@ bool DeleteEntityOperator::preRecursion(const OctreeElementPointer& element) {
// and we can stop searching. // and we can stop searching.
if (entityTreeElement == details.containingElement) { if (entityTreeElement == details.containingElement) {
EntityItemPointer theEntity = details.entity; 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); assert(entityDeleted);
(void)entityDeleted; // quite warning (void)entityDeleted; // quite warning
_tree->clearEntityMapEntry(details.entity->getEntityItemID()); _tree->clearEntityMapEntry(details.entity->getEntityItemID());

View file

@ -60,14 +60,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
} }
EntityItem::~EntityItem() { 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 // these pointers MUST be correct at delete, else we probably have a dangling backpointer
// to this EntityItem in the corresponding data structure. // to this EntityItem in the corresponding data structure.
assert(!_simulated); assert(!_simulated);
@ -2937,3 +2929,34 @@ void EntityItem::retrieveMarketplacePublicKey() {
networkReply->deleteLater(); 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<std::mutex> lock(_materialsLock);
_materials[shapeID].push(material);
emit addMaterialToRenderItem(material, shapeID);
}
void EntityItem::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) {
std::lock_guard<std::mutex> lock(_materialsLock);
_materials[shapeID].remove(material);
emit removeMaterialFromRenderItem(material, shapeID);
}
std::unordered_map<quint16, graphics::MultiMaterial> EntityItem::getMaterials() {
std::unordered_map<quint16, graphics::MultiMaterial> toReturn;
{
std::lock_guard<std::mutex> lock(_materialsLock);
toReturn = _materials;
}
return toReturn;
}

View file

@ -36,6 +36,8 @@
#include "SimulationFlags.h" #include "SimulationFlags.h"
#include "EntityDynamicInterface.h" #include "EntityDynamicInterface.h"
#include "graphics/Material.h"
class EntitySimulation; class EntitySimulation;
class EntityTreeElement; class EntityTreeElement;
class EntityTreeElementExtraEncodeData; class EntityTreeElementExtraEncodeData;
@ -49,7 +51,6 @@ typedef std::shared_ptr<EntityTreeElement> EntityTreeElementPointer;
using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr<EntityTreeElementExtraEncodeData>; using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr<EntityTreeElementExtraEncodeData>;
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() override { }; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() override { };
@ -443,10 +444,10 @@ public:
void scriptHasUnloaded() { _loadedScript = ""; _loadedScriptTimestamp = 0; } void scriptHasUnloaded() { _loadedScript = ""; _loadedScriptTimestamp = 0; }
bool getClientOnly() const { return _clientOnly; } 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? // if this entity is client-only, which avatar is it associated with?
QUuid getOwningAvatarID() const { return _owningAvatarID; } 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 wantsHandControllerPointerEvents() const { return false; }
virtual bool wantsKeyboardFocus() const { return false; } virtual bool wantsKeyboardFocus() const { return false; }
@ -477,8 +478,18 @@ public:
void setCauterized(bool value) { _cauterized = value; } void setCauterized(bool value) { _cauterized = value; }
bool getCauterized() const { return _cauterized; } 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<quint16, graphics::MultiMaterial> getMaterials();
signals: signals:
void requestRenderUpdate(); void requestRenderUpdate();
void addMaterialToRenderItem(graphics::MaterialPointer material, quint16 shapeID);
void removeMaterialFromRenderItem(graphics::MaterialPointer material, quint16 shapeID);
protected: protected:
QHash<ChangeHandlerId, ChangeHandlerCallback> _changeHandlers; QHash<ChangeHandlerId, ChangeHandlerCallback> _changeHandlers;
@ -631,6 +642,11 @@ protected:
quint64 _lastUpdatedQueryAACubeTimestamp { 0 }; quint64 _lastUpdatedQueryAACubeTimestamp { 0 };
bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera
private:
std::unordered_map<quint16, graphics::MultiMaterial> _materials;
std::mutex _materialsLock;
}; };
#endif // hifi_EntityItem_h #endif // hifi_EntityItem_h

View file

@ -360,7 +360,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor);
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority);
CHECK_PROPERTY_CHANGE(PROP_PARENT_SHAPE_ID, shapeID); 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 // Certifiable Properties
CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); 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_BLEND_FACTOR, blendFactor);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); 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) { 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(radiusFinish, float, setRadiusFinish);
COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints);
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); 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(blendFactor, float, setBlendFactor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, int, setPriority); COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority);
COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, int, setShapeID); COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, quint16, setShapeID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialBounds, glmVec4, setMaterialBounds); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialPos, glmVec2, setMaterialPos);
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialScale, glmVec2, setMaterialScale);
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialRot, float, setMaterialRot);
// Certifiable Properties // Certifiable Properties
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); 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_URL, MaterialURL, materialURL, QString);
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode); 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_BLEND_FACTOR, BlendFactor, blendFactor, float);
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, quint16);
ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t); ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16);
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4); 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 // Certifiable Properties
ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); 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_BLEND_FACTOR, properties.getBlendFactor());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority());
APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, properties.getShapeID()); 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()); 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_URL, QString, setMaterialURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); 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_BLEND_FACTOR, float, setBlendFactor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, quint16, setShapeID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BOUNDS, glmVec4, setMaterialBounds); 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); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
@ -2104,7 +2116,9 @@ void EntityItemProperties::markAllChanged() {
_blendFactorChanged = true; _blendFactorChanged = true;
_priorityChanged = true; _priorityChanged = true;
_shapeIDChanged = true; _shapeIDChanged = true;
_materialBoundsChanged = true; _materialPosChanged = true;
_materialScaleChanged = true;
_materialRotChanged = true;
// Certifiable Properties // Certifiable Properties
_itemNameChanged = true; _itemNameChanged = true;
@ -2444,8 +2458,14 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (shapeIDChanged()) { if (shapeIDChanged()) {
out += "shapeID"; out += "shapeID";
} }
if (materialBoundsChanged()) { if (materialPosChanged()) {
out += "materialBounds"; out += "materialPos";
}
if (materialScaleChanged()) {
out += "materialScale";
}
if (materialRotChanged()) {
out += "materialRot";
} }
// Certifiable Properties // Certifiable Properties

View file

@ -225,9 +225,11 @@ public:
DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, ""); DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, "");
DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode, UV); DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode, UV);
DEFINE_PROPERTY_REF(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float, 1.0f); 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_MATERIAL_PRIORITY, Priority, priority, quint16, 0);
DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t, 0); DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16, 0);
DEFINE_PROPERTY_REF(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4, glm::vec4(0, 0, 1, 1)); 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 // 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_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME);

View file

@ -101,6 +101,7 @@
changedProperties += P; \ 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, const glm::vec3& v) { return vec3toScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, int 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); \ properties.setProperty(#P, V); \
} }
typedef glm::vec2 glmVec2;
typedef glm::vec3 glmVec3; typedef glm::vec3 glmVec3;
typedef glm::vec4 glmVec4;
typedef glm::quat glmQuat; typedef glm::quat glmQuat;
typedef QVector<glm::vec3> qVectorVec3; typedef QVector<glm::vec3> qVectorVec3;
typedef QVector<glm::quat> qVectorQuat; typedef QVector<glm::quat> qVectorQuat;
@ -222,6 +223,23 @@ inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool&
return QByteArray::fromBase64(b64.toUtf8()); 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) { inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x"); QScriptValue x = v.property("x");
@ -242,29 +260,6 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal
return glm::vec3(0); 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) { inline AACube AACube_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true; isValid = true;
AACube result; AACube result;

View file

@ -232,7 +232,9 @@ enum EntityPropertyList {
PROP_MATERIAL_BLEND_FACTOR, PROP_MATERIAL_BLEND_FACTOR,
PROP_MATERIAL_PRIORITY, PROP_MATERIAL_PRIORITY,
PROP_PARENT_SHAPE_ID, 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 // ATTENTION: add new properties to end of list just ABOVE this line

View file

@ -1732,15 +1732,19 @@ void EntityTree::fixupNeedsParentFixups() {
} }
}); });
entity->locationChanged(true); entity->locationChanged(true);
} else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) { entity->postParentFixup();
// this is a child of an avatar, which the entity server will never have } else if (_avatarIDs.contains(entity->getParentID())) {
// a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. if (getIsServer()) {
if (!_childrenOfAvatars.contains(entity->getParentID())) { // this is a child of an avatar, which the entity server will never have
_childrenOfAvatars[entity->getParentID()] = QSet<EntityItemID>(); // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves.
if (!_childrenOfAvatars.contains(entity->getParentID())) {
_childrenOfAvatars[entity->getParentID()] = QSet<EntityItemID>();
}
_childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID();
} }
_childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID();
doMove = true; doMove = true;
iter.remove(); // and pull it out of the list iter.remove(); // and pull it out of the list
entity->postParentFixup();
} }
if (queryAACubeSuccess && doMove) { if (queryAACubeSuccess && doMove) {
@ -2378,3 +2382,35 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const {
return entity->getJointNames(); return entity->getJointNames();
} }
std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> EntityTree::_addMaterialToAvatarOperator = nullptr;
std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> EntityTree::_removeMaterialFromAvatarOperator = nullptr;
std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> EntityTree::_addMaterialToOverlayOperator = nullptr;
std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> 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;
}

View file

@ -280,6 +280,16 @@ public:
void setMyAvatar(std::shared_ptr<AvatarData> myAvatar) { _myAvatar = myAvatar; } void setMyAvatar(std::shared_ptr<AvatarData> myAvatar) { _myAvatar = myAvatar; }
static void setAddMaterialToAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; }
static void setRemoveMaterialFromAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> 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<bool(const QUuid&, graphics::MaterialPointer, quint16)> addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; }
static void setRemoveMaterialFromOverlayOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> 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: signals:
void deletingEntity(const EntityItemID& entityID); void deletingEntity(const EntityItemID& entityID);
void deletingEntityPointer(EntityItem* entityID); void deletingEntityPointer(EntityItem* entityID);
@ -387,6 +397,11 @@ private:
void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation); void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation);
std::shared_ptr<AvatarData> _myAvatar{ nullptr }; std::shared_ptr<AvatarData> _myAvatar{ nullptr };
static std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> _addMaterialToAvatarOperator;
static std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> _removeMaterialFromAvatarOperator;
static std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> _addMaterialToOverlayOperator;
static std::function<bool(const QUuid&, graphics::MaterialPointer, quint16)> _removeMaterialFromOverlayOperator;
}; };
#endif // hifi_EntityTree_h #endif // hifi_EntityTree_h

View file

@ -896,6 +896,7 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI
void EntityTreeElement::cleanupEntities() { void EntityTreeElement::cleanupEntities() {
withWriteLock([&] { withWriteLock([&] {
foreach(EntityItemPointer entity, _entityItems) { foreach(EntityItemPointer entity, _entityItems) {
entity->preDelete();
// NOTE: only EntityTreeElement should ever be changing the value of entity->_element // 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 // 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 // access it by smart pointers, when we remove it from the _entityItems
@ -907,26 +908,10 @@ void EntityTreeElement::cleanupEntities() {
bumpChangedContent(); bumpChangedContent();
} }
bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { bool EntityTreeElement::removeEntityItem(EntityItemPointer entity, bool deletion) {
bool foundEntity = false; if (deletion) {
withWriteLock([&] { entity->preDelete();
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) {
int numEntries = 0; int numEntries = 0;
withWriteLock([&] { withWriteLock([&] {
numEntries = _entityItems.removeAll(entity); numEntries = _entityItems.removeAll(entity);
@ -955,6 +940,7 @@ void EntityTreeElement::addEntityItem(EntityItemPointer entity) {
}); });
bumpChangedContent(); bumpChangedContent();
entity->_element = getThisPointer(); entity->_element = getThisPointer();
entity->postAdd();
} }
// will average a "common reduced LOD view" from the the child elements... // will average a "common reduced LOD view" from the the child elements...

View file

@ -210,8 +210,7 @@ public:
void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities); void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities);
void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities
bool removeEntityWithEntityItemID(const EntityItemID& id); bool removeEntityItem(EntityItemPointer entity, bool deletion = false);
bool removeEntityItem(EntityItemPointer entity);
bool containsEntityBounds(EntityItemPointer entity) const; bool containsEntityBounds(EntityItemPointer entity) const;
bool bestFitEntityBounds(EntityItemPointer entity) const; bool bestFitEntityBounds(EntityItemPointer entity) const;

View file

@ -16,6 +16,9 @@
EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
entity->setProperties(properties); 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; return entity;
} }
@ -31,7 +34,9 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir
COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendFactor, getBlendFactor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendFactor, getBlendFactor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeID, getShapeID); 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; return properties;
} }
@ -43,7 +48,9 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeID, setShapeID); 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) { if (somethingChanged) {
bool wantDebug = false; 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_URL, QString, setMaterialURL);
READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode);
READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor);
READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, quint16, setPriority);
READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, quint16, setShapeID);
READ_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, glm::vec4, setMaterialBounds); 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; return bytesRead;
} }
@ -218,7 +227,9 @@ EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParam
requestedProperties += PROP_MATERIAL_BLEND_FACTOR; requestedProperties += PROP_MATERIAL_BLEND_FACTOR;
requestedProperties += PROP_MATERIAL_PRIORITY; requestedProperties += PROP_MATERIAL_PRIORITY;
requestedProperties += PROP_PARENT_SHAPE_ID; requestedProperties += PROP_PARENT_SHAPE_ID;
requestedProperties += PROP_MATERIAL_BOUNDS; requestedProperties += PROP_MATERIAL_POS;
requestedProperties += PROP_MATERIAL_SCALE;
requestedProperties += PROP_MATERIAL_ROT;
return requestedProperties; return requestedProperties;
} }
@ -234,9 +245,11 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, (uint32_t)getPriority()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority());
APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, (uint32_t)getShapeID()); APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, getMaterialBounds()); 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 { void MaterialEntityItem::debugDump() const {
@ -249,7 +262,9 @@ void MaterialEntityItem::debugDump() const {
qCDebug(entities) << " blend factor:" << _blendFactor; qCDebug(entities) << " blend factor:" << _blendFactor;
qCDebug(entities) << " priority:" << _priority; qCDebug(entities) << " priority:" << _priority;
qCDebug(entities) << " parent shape ID:" << _shapeID; 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) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
@ -269,30 +284,38 @@ std::shared_ptr<NetworkMaterial> MaterialEntityItem::getMaterial() const {
} }
} }
void MaterialEntityItem::setMaterialURL(const QString& materialURLString) { void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool userDataChanged) {
if (materialURLString.startsWith("userData")) { bool usingUserData = materialURLString.startsWith("userData");
QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); if (_materialURL != materialURLString || (usingUserData && userDataChanged)) {
_materials.clear(); removeMaterial();
_materialNames.clear(); _materialURL = materialURLString;
if (!materialJSON.isNull()) {
if (materialJSON.isArray()) { if (usingUserData) {
QJsonArray materials = materialJSON.array(); QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8());
for (auto& material : materials) { _materials.clear();
if (!material.isNull() && material.isObject()) { _materialNames.clear();
parseJSONMaterial(material.toObject()); 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) { void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialName) {
@ -300,14 +323,176 @@ void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialNa
if (material != _materials.end()) { if (material != _materials.end()) {
_currentMaterialName = currentMaterialName; _currentMaterialName = currentMaterialName;
} else if (_materialNames.size() > 0) { } else if (_materialNames.size() > 0) {
setCurrentMaterialName(_materialNames[0]); _currentMaterialName = _materialNames[0];
} }
} }
void MaterialEntityItem::setUserData(const QString& userData) { void MaterialEntityItem::setUserData(const QString& userData) {
EntityItem::setUserData(userData); if (_userData != userData) {
if (_materialURL.startsWith("userData")) { EntityItem::setUserData(userData);
// Trigger material update when user data changes if (_materialURL.startsWith("userData")) {
setMaterialURL(_materialURL); // 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);
} }

View file

@ -23,6 +23,9 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated 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 // methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
virtual bool setProperties(const EntityItemProperties& properties) override; virtual bool setProperties(const EntityItemProperties& properties) override;
@ -49,7 +52,7 @@ public:
virtual void setUnscaledDimensions(const glm::vec3& value) override; virtual void setUnscaledDimensions(const glm::vec3& value) override;
QString getMaterialURL() const { return _materialURL; } QString getMaterialURL() const { return _materialURL; }
void setMaterialURL(const QString& materialURLString); void setMaterialURL(const QString& materialURLString, bool userDataChanged = false);
QString getCurrentMaterialName() const { return _currentMaterialName; } QString getCurrentMaterialName() const { return _currentMaterialName; }
void setCurrentMaterialName(const QString& currentMaterialName); void setCurrentMaterialName(const QString& currentMaterialName);
@ -58,33 +61,51 @@ public:
void setMaterialMode(MaterialMode mode) { _materialMode = mode; } void setMaterialMode(MaterialMode mode) { _materialMode = mode; }
float getBlendFactor() const { return _blendFactor; } float getBlendFactor() const { return _blendFactor; }
void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } void setBlendFactor(float blendFactor);
int getPriority() const { return _priority; } quint16 getPriority() const { return _priority; }
void setPriority(int priority) { _priority = priority; } void setPriority(quint16 priority);
int getShapeID() const { return _shapeID; } quint16 getShapeID() const { return _shapeID; }
void setShapeID(int shapeID) { _shapeID = shapeID; } void setShapeID(quint16 shapeID);
glm::vec4 getMaterialBounds() const { return _materialBounds; } glm::vec2 getMaterialPos() const { return _materialPos; }
void setMaterialBounds(const glm::vec4& materialBounds) { _materialBounds = materialBounds; } 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<NetworkMaterial> getMaterial() const; std::shared_ptr<NetworkMaterial> getMaterial() const;
void setUserData(const QString& userData) override; 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: private:
QString _materialURL; QString _materialURL;
MaterialMode _materialMode { UV }; MaterialMode _materialMode { UV };
float _blendFactor { 1.0f }; float _blendFactor { 1.0f };
int _priority { 0 }; quint16 _priority { 0 };
int _shapeID { 0 }; quint16 _shapeID { 0 };
glm::vec4 _materialBounds { 0, 0, 1, 1 }; glm::vec2 _materialPos { 0, 0 };
glm::vec2 _materialScale { 1, 1 };
float _materialRot { 0 };
QHash<QString, std::shared_ptr<NetworkMaterial>> _materials; QHash<QString, std::shared_ptr<NetworkMaterial>> _materials;
std::vector<QString> _materialNames; std::vector<QString> _materialNames;
QString _currentMaterialName; QString _currentMaterialName;
bool _retryApply { false };
void parseJSONMaterial(const QJsonObject& materialJSON); void parseJSONMaterial(const QJsonObject& materialJSON);
static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB);

View file

@ -721,4 +721,4 @@ bool ModelEntityItem::isAnimatingSomething() const {
_animationProperties.getRunning() && _animationProperties.getRunning() &&
(_animationProperties.getFPS() != 0.0f); (_animationProperties.getFPS() != 0.0f);
}); });
} }

View file

@ -85,6 +85,7 @@ EntityItemPointer ShapeEntityItem::sphereFactory(const EntityItemID& entityID, c
ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
_type = EntityTypes::Shape; _type = EntityTypes::Shape;
_volumeMultiplier *= PI / 6.0f; _volumeMultiplier *= PI / 6.0f;
_material = std::make_shared<graphics::Material>();
} }
EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
@ -184,6 +185,7 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
void ShapeEntityItem::setColor(const rgbColor& value) { void ShapeEntityItem::setColor(const rgbColor& value) {
memcpy(_color, value, sizeof(rgbColor)); memcpy(_color, value, sizeof(rgbColor));
_material->setAlbedo(glm::vec3(_color[0], _color[1], _color[2]) / 255.0f);
} }
xColor ShapeEntityItem::getXColor() const { xColor ShapeEntityItem::getXColor() const {
@ -204,6 +206,11 @@ void ShapeEntityItem::setColor(const QColor& value) {
setAlpha(value.alpha()); setAlpha(value.alpha());
} }
void ShapeEntityItem::setAlpha(float alpha) {
_alpha = alpha;
_material->setOpacity(alpha);
}
void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
const float MAX_FLAT_DIMENSION = 0.0001f; const float MAX_FLAT_DIMENSION = 0.0001f;
if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) { if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {

View file

@ -75,7 +75,7 @@ public:
void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); } void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); }
float getAlpha() const { return _alpha; }; float getAlpha() const { return _alpha; };
void setAlpha(float alpha) { _alpha = alpha; } void setAlpha(float alpha);
const rgbColor& getColor() const { return _color; } const rgbColor& getColor() const { return _color; }
void setColor(const rgbColor& value); void setColor(const rgbColor& value);
@ -101,6 +101,8 @@ public:
virtual void computeShapeInfo(ShapeInfo& info) override; virtual void computeShapeInfo(ShapeInfo& info) override;
virtual ShapeType getShapeType() const override; virtual ShapeType getShapeType() const override;
std::shared_ptr<graphics::Material> getMaterial() { return _material; }
protected: protected:
float _alpha { 1 }; float _alpha { 1 };
@ -111,6 +113,8 @@ protected:
//! prior functionality where new or unsupported shapes are treated as //! prior functionality where new or unsupported shapes are treated as
//! ellipsoids. //! ellipsoids.
ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID }; ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID };
std::shared_ptr<graphics::Material> _material;
}; };
#endif // hifi_ShapeEntityItem_h #endif // hifi_ShapeEntityItem_h

View file

@ -12,9 +12,13 @@
#include "TextureMap.h" #include "TextureMap.h"
#include <Transform.h>
using namespace graphics; using namespace graphics;
using namespace gpu; using namespace gpu;
int materialPointerMetaID = qRegisterMetaType<MaterialPointer>("graphics::MaterialPointer");
Material::Material() : Material::Material() :
_key(0), _key(0),
_schemaBuffer(), _schemaBuffer(),
@ -221,4 +225,15 @@ bool Material::calculateMaterialInfo() const {
_hasCalculatedTextureInfo = allTextures; _hasCalculatedTextureInfo = allTextures;
} }
return _hasCalculatedTextureInfo; 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<TexMapArraySchema>()._texcoordTransforms[i] = transform.getMatrix();
}
} }

View file

@ -15,11 +15,14 @@
#include <bitset> #include <bitset>
#include <map> #include <map>
#include <queue>
#include <ColorUtils.h> #include <ColorUtils.h>
#include <gpu/Resource.h> #include <gpu/Resource.h>
class Transform;
namespace graphics { namespace graphics {
class TextureMap; class TextureMap;
@ -351,6 +354,14 @@ public:
size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; }
bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } 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: private:
mutable MaterialKey _key; mutable MaterialKey _key;
mutable UniformBufferView _schemaBuffer; mutable UniformBufferView _schemaBuffer;
@ -364,10 +375,35 @@ private:
mutable bool _hasCalculatedTextureInfo { false }; mutable bool _hasCalculatedTextureInfo { false };
bool calculateMaterialInfo() const; bool calculateMaterialInfo() const;
float _blendFactor { 1.0f };
quint16 _priority { 0 };
}; };
typedef std::shared_ptr< Material > MaterialPointer; 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<MaterialPointer, std::vector<MaterialPointer>, 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 #endif

View file

@ -549,7 +549,6 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, im
auto map = std::make_shared<graphics::TextureMap>(); auto map = std::make_shared<graphics::TextureMap>();
if (texture) { if (texture) {
map->setTextureSource(texture->_textureSource); map->setTextureSource(texture->_textureSource);
emit textureFinished();
} }
return map; return map;
@ -728,6 +727,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) {
if (!occlusionName.isEmpty()) { if (!occlusionName.isEmpty()) {
auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl(); 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); auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
setTextureMap(MapChannel::OCCLUSION_MAP, map); setTextureMap(MapChannel::OCCLUSION_MAP, map);
} }

View file

@ -156,8 +156,7 @@ private:
virtual ~ModelCache() = default; virtual ~ModelCache() = default;
}; };
class NetworkMaterial : public QObject, public graphics::Material { class NetworkMaterial : public graphics::Material {
Q_OBJECT
public: public:
using MapChannel = graphics::Material::MapChannel; using MapChannel = graphics::Material::MapChannel;
@ -174,9 +173,6 @@ public:
void setScatteringMap(const QString& url); void setScatteringMap(const QString& url);
void setLightmapMap(const QString& url); void setLightmapMap(const QString& url);
signals:
void textureFinished();
protected: protected:
friend class Geometry; friend class Geometry;

View file

@ -381,6 +381,17 @@ bool OctreePacketData::appendValue(float value) {
return success; 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) { bool OctreePacketData::appendValue(const glm::vec3& value) {
const unsigned char* data = (const unsigned char*)&value; const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value); int length = sizeof(value);

View file

@ -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 /// 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); 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 /// 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); bool appendValue(const glm::vec3& value);
@ -250,8 +253,8 @@ public:
static quint64 getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color 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, 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::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, 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, 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); } static int unpackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }

View file

@ -47,7 +47,7 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material) { MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material) {
updateMeshPart(mesh, partIndex); updateMeshPart(mesh, partIndex);
updateMaterial(material); addMaterial(material);
} }
void MeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex) { void MeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex) {
@ -67,8 +67,12 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor
_worldBound.transform(_drawTransform); _worldBound.transform(_drawTransform);
} }
void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) { void MeshPartPayload::addMaterial(graphics::MaterialPointer material) {
_drawMaterial = drawMaterial; _drawMaterials.push(material);
}
void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) {
_drawMaterials.remove(material);
} }
void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) { 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(); builder.withLayered();
} }
if (_drawMaterial) { if (_drawMaterials.top()) {
auto matKey = _drawMaterial->getKey(); auto matKey = _drawMaterials.top()->getKey();
if (matKey.isTranslucent()) { if (matKey.isTranslucent()) {
builder.withTransparent(); builder.withTransparent();
} }
@ -105,8 +109,8 @@ Item::Bound MeshPartPayload::getBound() const {
ShapeKey MeshPartPayload::getShapeKey() const { ShapeKey MeshPartPayload::getShapeKey() const {
graphics::MaterialKey drawMaterialKey; graphics::MaterialKey drawMaterialKey;
if (_drawMaterial) { if (_drawMaterials.top()) {
drawMaterialKey = _drawMaterial->getKey(); drawMaterialKey = _drawMaterials.top()->getKey();
} }
ShapeKey::Builder builder; ShapeKey::Builder builder;
@ -160,7 +164,7 @@ void MeshPartPayload::render(RenderArgs* args) {
bindMesh(batch); bindMesh(batch);
// apply material properties // apply material properties
args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); args->_shapePipeline->bindMaterial(_drawMaterials.top(), batch, args->_enableTexturing);
args->_details._materialSwitches++; args->_details._materialSwitches++;
// Draw! // Draw!
@ -252,7 +256,7 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) {
auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID); auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID);
if (networkMaterial) { if (networkMaterial) {
_drawMaterial = networkMaterial; addMaterial(networkMaterial);
} }
} }
@ -298,8 +302,8 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag
builder.withDeformed(); builder.withDeformed();
} }
if (_drawMaterial) { if (_drawMaterials.top()) {
auto matKey = _drawMaterial->getKey(); auto matKey = _drawMaterials.top()->getKey();
if (matKey.isTranslucent()) { if (matKey.isTranslucent()) {
builder.withTransparent(); builder.withTransparent();
} }
@ -329,8 +333,8 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe
} }
graphics::MaterialKey drawMaterialKey; graphics::MaterialKey drawMaterialKey;
if (_drawMaterial) { if (_drawMaterials.top()) {
drawMaterialKey = _drawMaterial->getKey(); drawMaterialKey = _drawMaterials.top()->getKey();
} }
bool isTranslucent = drawMaterialKey.isTranslucent(); bool isTranslucent = drawMaterialKey.isTranslucent();
@ -411,7 +415,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
bindMesh(batch); bindMesh(batch);
// apply material properties // apply material properties
args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); args->_shapePipeline->bindMaterial(_drawMaterials.top(), batch, args->_enableTexturing);
args->_details._materialSwitches++; args->_details._materialSwitches++;
// Draw! // Draw!

View file

@ -39,8 +39,6 @@ public:
virtual void notifyLocationChanged() {} virtual void notifyLocationChanged() {}
void updateTransform(const Transform& transform, const Transform& offsetTransform); void updateTransform(const Transform& transform, const Transform& offsetTransform);
virtual void updateMaterial(graphics::MaterialPointer drawMaterial);
// Render Item interface // Render Item interface
virtual render::ItemKey getKey() const; virtual render::ItemKey getKey() const;
virtual render::Item::Bound getBound() const; virtual render::Item::Bound getBound() const;
@ -63,13 +61,16 @@ public:
mutable graphics::Box _worldBound; mutable graphics::Box _worldBound;
std::shared_ptr<const graphics::Mesh> _drawMesh; std::shared_ptr<const graphics::Mesh> _drawMesh;
std::shared_ptr<graphics::Material> _drawMaterial; graphics::MultiMaterial _drawMaterials;
graphics::Mesh::Part _drawPart; graphics::Mesh::Part _drawPart;
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; } size_t getMaterialTextureSize() { return _drawMaterials.top() ? _drawMaterials.top()->getTextureSize() : 0; }
int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; } int getMaterialTextureCount() { return _drawMaterials.top() ? _drawMaterials.top()->getTextureCount() : 0; }
bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; } bool hasTextureInfo() const { return _drawMaterials.top() ? _drawMaterials.top()->hasTextureInfo() : false; }
void addMaterial(graphics::MaterialPointer material);
void removeMaterial(graphics::MaterialPointer material);
protected: protected:
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() }; render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };

View file

@ -1524,6 +1524,50 @@ bool Model::isRenderable() const {
return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); 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<ModelMeshPartPayload>(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<ModelMeshPartPayload>(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 { class CollisionRenderGeometry : public Geometry {
public: public:
CollisionRenderGeometry(graphics::MeshPointer mesh) { CollisionRenderGeometry(graphics::MeshPointer mesh) {

View file

@ -318,6 +318,9 @@ public:
void scaleToFit(); void scaleToFit();
void addMaterial(graphics::MaterialPointer material, quint16 shapeID);
void removeMaterial(graphics::MaterialPointer material, quint16 shapeID);
public slots: public slots:
void loadURLFinished(bool success); void loadURLFinished(bool success);

View file

@ -342,7 +342,7 @@ var toolBar = (function () {
var buttonHandlers = {}; // only used to tablet mode var buttonHandlers = {}; // only used to tablet mode
function addButton(name, image, handler) { function addButton(name, handler) {
buttonHandlers[name] = handler; buttonHandlers[name] = handler;
} }
@ -399,7 +399,7 @@ var toolBar = (function () {
function handleNewMaterialDialogResult(result) { function handleNewMaterialDialogResult(result) {
if (result) { if (result) {
var json = result.textInput; var materialURL = result.textInput;
var materialMode; var materialMode;
switch (result.comboBox) { switch (result.comboBox) {
case MATERIAL_MODE_PROJECTED: case MATERIAL_MODE_PROJECTED:
@ -409,11 +409,13 @@ var toolBar = (function () {
shapeType = "uv"; shapeType = "uv";
} }
if (json) { var DEFAULT_LAYERED_MATERIAL_PRIORITY = 1;
if (materialURL) {
createNewEntity({ createNewEntity({
type: "Material", type: "Material",
materialURL: json, materialURL: materialURL,
materialMode: materialMode materialMode: materialMode,
priority: DEFAULT_LAYERED_MATERIAL_PRIORITY
}); });
} }
} }
@ -475,32 +477,22 @@ var toolBar = (function () {
that.toggle(); that.toggle();
}); });
addButton("importEntitiesButton", "assets-01.svg", function() { addButton("importEntitiesButton", function() {
Window.browseChanged.connect(onFileOpenChanged); Window.browseChanged.connect(onFileOpenChanged);
Window.browseAsync("Select Model to Import", "", "*.json"); Window.browseAsync("Select Model to Import", "", "*.json");
}); });
addButton("openAssetBrowserButton", "assets-01.svg", function() { addButton("openAssetBrowserButton", function() {
Window.showAssetServer(); Window.showAssetServer();
}); });
addButton("newModelButton", "model-01.svg", function () { addButton("newModelButton", 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;
// tablet version of new-model dialog // tablet version of new-model dialog
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml"); tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml");
}); });
addButton("newCubeButton", "cube-01.svg", function () { addButton("newCubeButton", function () {
createNewEntity({ createNewEntity({
type: "Box", type: "Box",
dimensions: DEFAULT_DIMENSIONS, dimensions: DEFAULT_DIMENSIONS,
@ -512,7 +504,7 @@ var toolBar = (function () {
}); });
}); });
addButton("newSphereButton", "sphere-01.svg", function () { addButton("newSphereButton", function () {
createNewEntity({ createNewEntity({
type: "Sphere", type: "Sphere",
dimensions: DEFAULT_DIMENSIONS, dimensions: DEFAULT_DIMENSIONS,
@ -524,7 +516,7 @@ var toolBar = (function () {
}); });
}); });
addButton("newLightButton", "light-01.svg", function () { addButton("newLightButton", function () {
createNewEntity({ createNewEntity({
type: "Light", type: "Light",
dimensions: DEFAULT_LIGHT_DIMENSIONS, dimensions: DEFAULT_LIGHT_DIMENSIONS,
@ -543,7 +535,7 @@ var toolBar = (function () {
}); });
}); });
addButton("newTextButton", "text-01.svg", function () { addButton("newTextButton", function () {
createNewEntity({ createNewEntity({
type: "Text", type: "Text",
dimensions: { dimensions: {
@ -566,7 +558,7 @@ var toolBar = (function () {
}); });
}); });
addButton("newWebButton", "web-01.svg", function () { addButton("newWebButton", function () {
createNewEntity({ createNewEntity({
type: "Web", type: "Web",
dimensions: { dimensions: {
@ -578,7 +570,7 @@ var toolBar = (function () {
}); });
}); });
addButton("newZoneButton", "zone-01.svg", function () { addButton("newZoneButton", function () {
createNewEntity({ createNewEntity({
type: "Zone", type: "Zone",
dimensions: { dimensions: {
@ -589,7 +581,7 @@ var toolBar = (function () {
}); });
}); });
addButton("newParticleButton", "particle-01.svg", function () { addButton("newParticleButton", function () {
createNewEntity({ createNewEntity({
type: "ParticleEffect", type: "ParticleEffect",
isEmitting: true, isEmitting: true,
@ -642,15 +634,10 @@ var toolBar = (function () {
}); });
}); });
addButton("newMaterialButton", "model-01.svg", function () { addButton("newMaterialButton", 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 // tablet version of new material dialog
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.pushOntoStack("NewMaterialDialog.qml"); tablet.pushOntoStack("hifi/tablet/NewMaterialDialog.qml");
}); });
that.setActive(false); that.setActive(false);

View file

@ -645,14 +645,14 @@ hr {
margin-left: 10px; 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; float: left;
margin-left: 1px; margin-left: 1px;
margin-bottom: 3px; margin-bottom: 3px;
margin-top: -2px; 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; float: left;
margin-left: 1px; margin-left: 1px;
margin-bottom: 3px; margin-bottom: 3px;
@ -667,7 +667,7 @@ hr {
clear: both; clear: both;
float: left; float: left;
} }
.xyz > div, .pyr > div, .gen > div { .xy > div, .wh > div, .xyz > div, .pyr > div, .gen > div {
clear: both; clear: both;
} }
@ -841,6 +841,12 @@ div.refresh input[type="button"] {
margin-right: -6px; margin-right: -6px;
} }
.xy .tuple input {
padding-left: 25px;
}
.wh .tuple input {
padding-left: 45px;
}
.rgb .tuple input { .rgb .tuple input {
padding-left: 65px; padding-left: 65px;
} }

View file

@ -787,7 +787,7 @@
<div class="material-group material-section property number"> <div class="material-group material-section property number">
<label>Priority </label> <label>Priority </label>
<input type="number" id="property-priority"> <input type="number" id="property-priority" min="0">
</div> </div>
<div class="material-group material-section property number"> <div class="material-group material-section property number">
@ -795,13 +795,26 @@
<input type="number" id="property-shape-id" min="0"> <input type="number" id="property-shape-id" min="0">
</div> </div>
<div class="material-group material-section property tuple"> <fieldset>
<label>Material Bounds </label> <div class="material-group material-section property xy fstuple">
<div><input type="number" class="x" id="property-material-bounds-x" min="0" max="1" step="0.1"><label for="property-material-bounds-x">Left:</label></div> <label>Material Position </label>
<div><input type="number" class="y" id="property-material-bounds-y" min="0" max="1" step="0.1"><label for="property-material-bounds-y">Top:</label></div> <div class="tuple">
<div><input type="number" class="z" id="property-material-bounds-z" min="0" max="1" step="0.1"><label for="property-material-bounds-z">Right:</label></div> <div><input type="number" class="x" id="property-material-pos-x" min="0" max="1" step="0.1"><label for="property-material-pos-x">X:</label></div>
<div><input type="number" class="w" id="property-material-bounds-w" min="0" max="1" step="0.1"><label for="property-material-bounds-w">Bottom:</label></div> <div><input type="number" class="y" id="property-material-pos-y" min="0" max="1" step="0.1"><label for="property-material-pos-y">Y:</label></div>
</div> </div>
<div class="material-group material-section property wh fstuple">
<label>Material Scale </label>
<div class="tuple">
<div><input type="number" class="x" id="property-material-scale-x" min="0" step="0.1"><label for="property-material-scale-x">Width:</label></div>
<div><input type="number" class="y" id="property-material-scale-y" min="0" step="0.1"><label for="property-material-scale-y">Height:</label></div>
</div>
<div class="material-group material-section property number">
<label>Material Rotation <span class="unit">deg</span></label>
<input type="number" id="property-material-rot" step="0.1">
</div>
</fieldset>
</fieldset> </fieldset>
</fieldset> </fieldset>

View file

@ -25,7 +25,7 @@ var ICON_FOR_TYPE = {
PolyVox: "&#xe005;", PolyVox: "&#xe005;",
Multiple: "&#xe000;", Multiple: "&#xe000;",
PolyLine: "&#xe01b;", PolyLine: "&#xe01b;",
Material: "&#xe008;" Material: "&#xe00b;"
}; };
var EDITOR_TIMEOUT_DURATION = 1500; 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) { function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) {
return function() { return function() {
var properties = {}; 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) { function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) {
return function() { return function() {
var properties = {}; var properties = {};
@ -638,10 +636,11 @@ function loaded() {
var elBlendFactor = document.getElementById("property-blend-factor"); var elBlendFactor = document.getElementById("property-blend-factor");
var elPriority = document.getElementById("property-priority"); var elPriority = document.getElementById("property-priority");
var elShapeID = document.getElementById("property-shape-id"); var elShapeID = document.getElementById("property-shape-id");
var elMaterialBoundsX = document.getElementById("property-material-bounds-x"); var elMaterialPosX = document.getElementById("property-material-pos-x");
var elMaterialBoundsY = document.getElementById("property-material-bounds-y"); var elMaterialPosY = document.getElementById("property-material-pos-y");
var elMaterialBoundsZ = document.getElementById("property-material-bounds-z"); var elMaterialScaleX = document.getElementById("property-material-scale-x");
var elMaterialBoundsW = document.getElementById("property-material-bounds-w"); var elMaterialScaleY = document.getElementById("property-material-scale-y");
var elMaterialRot = document.getElementById("property-material-rot");
var elWebSourceURL = document.getElementById("property-web-source-url"); var elWebSourceURL = document.getElementById("property-web-source-url");
var elWebDPI = document.getElementById("property-web-dpi"); var elWebDPI = document.getElementById("property-web-dpi");
@ -1134,10 +1133,11 @@ function loaded() {
elBlendFactor.value = properties.blendFactor.toFixed(2); elBlendFactor.value = properties.blendFactor.toFixed(2);
elPriority.value = properties.priority; elPriority.value = properties.priority;
elShapeID.value = properties.shapeID; elShapeID.value = properties.shapeID;
elMaterialBoundsX.value = properties.materialBounds.x.toFixed(2); elMaterialPosX.value = properties.materialPos.x.toFixed(4);
elMaterialBoundsY.value = properties.materialBounds.y.toFixed(2); elMaterialPosY.value = properties.materialPos.y.toFixed(4);
elMaterialBoundsZ.value = properties.materialBounds.z.toFixed(2); elMaterialScaleX.value = properties.materialScale.x.toFixed(4);
//elMaterialBoundsW.value = properties.materialBounds.w.toFixed(2); elMaterialScaleY.value = properties.materialScale.y.toFixed(4);
elMaterialRot.value = properties.materialRot.toFixed(2);
} }
if (properties.locked) { if (properties.locked) {
@ -1411,15 +1411,16 @@ function loaded() {
elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL')); elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL'));
elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode')); elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode'));
elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2)); elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2));
elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority')); elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority', 0));
elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID')); elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID', 0));
var materialBoundsChangeFunction = createEmitVec4PropertyUpdateFunction('materialBounds', var materialPosChangeFunction = createEmitVec2PropertyUpdateFunction('materialPos', elMaterialPosX, elMaterialPosY);
elMaterialBoundsX, elMaterialBoundsY, elMaterialBoundsZ, elMaterialBoundsW); elMaterialPosX.addEventListener('change', materialPosChangeFunction);
elMaterialBoundsX.addEventListener('change', materialBoundsChangeFunction); elMaterialPosY.addEventListener('change', materialPosChangeFunction);
elMaterialBoundsY.addEventListener('change', materialBoundsChangeFunction); var materialScaleChangeFunction = createEmitVec2PropertyUpdateFunction('materialScale', elMaterialScaleX, elMaterialScaleY);
elMaterialBoundsZ.addEventListener('change', materialBoundsChangeFunction); elMaterialScaleX.addEventListener('change', materialScaleChangeFunction);
elMaterialBoundsW.addEventListener('change', materialBoundsChangeFunction); elMaterialScaleY.addEventListener('change', materialScaleChangeFunction);
elMaterialRot.addEventListener('change', createEmitNumberPropertyUpdateFunction('materialRot', 2));
elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text')); elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text'));
elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera')); elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera'));

138
tools/jsdoc/package-lock.json generated Normal file
View file

@ -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="
}
}
}