From 0dd8d2d3d4d3ca5555b5beb03392e19f89580e13 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 7 Aug 2018 18:18:58 -0700 Subject: [PATCH 01/23] working on enabling bloom --- .../src/RenderableZoneEntityItem.cpp | 49 ++++++ .../src/RenderableZoneEntityItem.h | 31 ++-- libraries/entities/src/BloomPropertyGroup.cpp | 159 +++++++++++++++++ libraries/entities/src/BloomPropertyGroup.h | 94 ++++++++++ .../entities/src/EntityItemProperties.cpp | 51 +++++- libraries/entities/src/EntityItemProperties.h | 4 + libraries/entities/src/EntityPropertyFlags.h | 5 + libraries/entities/src/ZoneEntityItem.cpp | 165 ++++++++++-------- libraries/entities/src/ZoneEntityItem.h | 14 +- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- .../render-utils/src/UpdateSceneTask.cpp | 2 + 12 files changed, 483 insertions(+), 96 deletions(-) create mode 100644 libraries/entities/src/BloomPropertyGroup.cpp create mode 100644 libraries/entities/src/BloomPropertyGroup.h diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index c5035431f6..f23e8096f1 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -64,6 +64,13 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity _hazeIndex = INVALID_INDEX; } } + + if (_bloomStage) { + if (!BloomStage::isIndexInvalid(_bloomIndex)) { + _bloomStage->removeBloom(_bloomIndex); + _bloomIndex = INVALID_INDEX; + } + } } void ZoneEntityRenderer::doRender(RenderArgs* args) { @@ -112,6 +119,11 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { assert(_hazeStage); } + if (!_bloomStage) { + _bloomStage = args->_scene->getStage(); + assert(_bloomStage); + } + { // Sun // Need an update ? if (_needSunUpdate) { @@ -161,6 +173,15 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { } } + { + if (_needBloomUpdate) { + if (BloomStage::isIndexInvalid(_bloomIndex)) { + _bloomIndex = _bloomStage->addBloom(_bloom); + } + _needBloomUpdate = false; + } + } + if (_visible) { // Finally, push the lights visible in the frame // @@ -190,6 +211,11 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { if (_hazeMode != COMPONENT_MODE_INHERIT) { _hazeStage->_currentFrame.pushHaze(_hazeIndex); } + + // Bloom only if the mode is not inherit, as the model deals with on/off + if (_bloomMode != COMPONENT_MODE_INHERIT) { + _bloomStage->_currentFrame.pushBloom(_bloomIndex); + } } } @@ -211,6 +237,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen bool ambientLightChanged = entity->ambientLightPropertiesChanged(); bool skyboxChanged = entity->skyboxPropertiesChanged(); bool hazeChanged = entity->hazePropertiesChanged(); + bool bloomChanged = entity->bloomPropertiesChanged(); entity->resetRenderingPropertiesChanged(); _lastPosition = entity->getWorldPosition(); @@ -221,6 +248,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen _ambientLightProperties = entity->getAmbientLightProperties(); _skyboxProperties = entity->getSkyboxProperties(); _hazeProperties = entity->getHazeProperties(); + _bloomProperties = entity->getBloomProperties(); #if 0 if (_lastShapeURL != _typedEntity->getCompoundShapeURL()) { @@ -258,6 +286,10 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen if (hazeChanged) { updateHazeFromEntity(entity); } + + if (bloomChanged) { + updateBloomFromEntity(entity); + } } void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { @@ -276,6 +308,7 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint if (entity->keyLightPropertiesChanged() || entity->ambientLightPropertiesChanged() || entity->hazePropertiesChanged() || + entity->bloomPropertiesChanged() || entity->skyboxPropertiesChanged()) { return true; @@ -388,6 +421,18 @@ void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity) haze->setTransform(entity->getTransform().getMatrix()); } +void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity) { + setBloomMode((ComponentMode)entity->getBloomMode()); + + const auto& bloom = editBloom(); + + const uint32_t bloomMode = entity->getBloomMode(); + bloom->setBloomActive(bloomMode == COMPONENT_MODE_ENABLED); + bloom->setBloomIntensity(_bloomProperties.getBloomIntensity()); + bloom->setBloomThreshold(_bloomProperties.getBloomThreshold()); + bloom->setBloomSize(_bloomProperties.getBloomSize()); +} + void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) { setSkyboxMode((ComponentMode)entity->getSkyboxMode()); @@ -510,6 +555,10 @@ void ZoneEntityRenderer::setSkyboxMode(ComponentMode mode) { _skyboxMode = mode; } +void ZoneEntityRenderer::setBloomMode(ComponentMode mode) { + _bloomMode = mode; +} + void ZoneEntityRenderer::setSkyboxColor(const glm::vec3& color) { editSkybox()->setColor(color); } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index c48679e5d4..3e2690e1bd 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -1,7 +1,6 @@ // // RenderableZoneEntityItem.h // -// // Created by Clement on 4/22/15. // Copyright 2015 High Fidelity, Inc. // @@ -15,10 +14,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include "RenderableEntityItem.h" #include @@ -50,6 +51,7 @@ private: void updateAmbientLightFromEntity(const TypedEntityPointer& entity); void updateHazeFromEntity(const TypedEntityPointer& entity); void updateKeyBackgroundFromEntity(const TypedEntityPointer& entity); + void updateBloomFromEntity(const TypedEntityPointer& entity); void updateAmbientMap(); void updateSkyboxMap(); void setAmbientURL(const QString& ambientUrl); @@ -59,6 +61,7 @@ private: void setKeyLightMode(ComponentMode mode); void setAmbientLightMode(ComponentMode mode); void setSkyboxMode(ComponentMode mode); + void setBloomMode(ComponentMode mode); void setSkyboxColor(const glm::vec3& color); void setProceduralUserData(const QString& userData); @@ -68,6 +71,7 @@ private: graphics::SunSkyStagePointer editBackground() { _needBackgroundUpdate = true; return _background; } graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); } graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; } + graphics::BloomPointer editBloom() { _needBloomUpdate = true; return _bloom; } glm::vec3 _lastPosition; glm::vec3 _lastDimensions; @@ -82,36 +86,43 @@ private: #endif LightStagePointer _stage; - const graphics::LightPointer _sunLight{ std::make_shared() }; - const graphics::LightPointer _ambientLight{ std::make_shared() }; - const graphics::SunSkyStagePointer _background{ std::make_shared() }; - const graphics::HazePointer _haze{ std::make_shared() }; + const graphics::LightPointer _sunLight { std::make_shared() }; + const graphics::LightPointer _ambientLight { std::make_shared() }; + const graphics::SunSkyStagePointer _background { std::make_shared() }; + const graphics::HazePointer _haze { std::make_shared() }; + const graphics::BloomPointer _bloom { std::make_shared() }; ComponentMode _keyLightMode { COMPONENT_MODE_INHERIT }; ComponentMode _ambientLightMode { COMPONENT_MODE_INHERIT }; ComponentMode _skyboxMode { COMPONENT_MODE_INHERIT }; ComponentMode _hazeMode { COMPONENT_MODE_INHERIT }; + ComponentMode _bloomMode { COMPONENT_MODE_INHERIT }; - indexed_container::Index _sunIndex{ LightStage::INVALID_INDEX }; - indexed_container::Index _shadowIndex{ LightStage::INVALID_INDEX }; - indexed_container::Index _ambientIndex{ LightStage::INVALID_INDEX }; + indexed_container::Index _sunIndex { LightStage::INVALID_INDEX }; + indexed_container::Index _shadowIndex { LightStage::INVALID_INDEX }; + indexed_container::Index _ambientIndex { LightStage::INVALID_INDEX }; BackgroundStagePointer _backgroundStage; - BackgroundStage::Index _backgroundIndex{ BackgroundStage::INVALID_INDEX }; + BackgroundStage::Index _backgroundIndex { BackgroundStage::INVALID_INDEX }; HazeStagePointer _hazeStage; - HazeStage::Index _hazeIndex{ HazeStage::INVALID_INDEX }; + HazeStage::Index _hazeIndex { HazeStage::INVALID_INDEX }; + + BloomStagePointer _bloomStage; + BloomStage::Index _bloomIndex { BloomStage::INVALID_INDEX }; bool _needUpdate{ true }; bool _needSunUpdate{ true }; bool _needAmbientUpdate{ true }; bool _needBackgroundUpdate{ true }; bool _needHazeUpdate{ true }; + bool _needBloomUpdate { true }; KeyLightPropertyGroup _keyLightProperties; AmbientLightPropertyGroup _ambientLightProperties; HazePropertyGroup _hazeProperties; SkyboxPropertyGroup _skyboxProperties; + BloomPropertyGroup _bloomProperties; // More attributes used for rendering: QString _ambientTextureURL; diff --git a/libraries/entities/src/BloomPropertyGroup.cpp b/libraries/entities/src/BloomPropertyGroup.cpp new file mode 100644 index 0000000000..2c4d46ab35 --- /dev/null +++ b/libraries/entities/src/BloomPropertyGroup.cpp @@ -0,0 +1,159 @@ +// +// BloomPropertyGroup.cpp +// libraries/entities/src +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BloomPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" +#include "EntityItemPropertiesMacros.h" + +void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize); +} + +void BloomPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomIntensity, float, setBloomIntensity); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomThreshold, float, setBloomThreshold); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomSize, float, setBloomSize); +} + +void BloomPropertyGroup::merge(const BloomPropertyGroup& other) { + COPY_PROPERTY_IF_CHANGED(bloomIntensity); + COPY_PROPERTY_IF_CHANGED(bloomThreshold); + COPY_PROPERTY_IF_CHANGED(bloomSize); +} + +void BloomPropertyGroup::debugDump() const { + qCDebug(entities) << " BloomPropertyGroup: ---------------------------------------------"; + qCDebug(entities) << " _bloomIntensity:" << _bloomIntensity; + qCDebug(entities) << " _bloomThreshold:" << _bloomThreshold; + qCDebug(entities) << " _bloomSize:" << _bloomSize; +} + +void BloomPropertyGroup::listChangedProperties(QList& out) { + if (bloomIntensityChanged()) { + out << "bloom-bloomIntensity"; + } + if (bloomThresholdChanged()) { + out << "bloom-bloomThreshold"; + } + if (bloomSizeChanged()) { + out << "bloom-bloomSize"; + } +} + +bool BloomPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize()); + + return true; +} + +bool BloomPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + + READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity); + READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold); + READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize); + + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_INTENSITY, BloomIntensity); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_THRESHOLD, BloomThreshold); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_SIZE, BloomSize); + + processedBytes += bytesRead; + + Q_UNUSED(somethingChanged); + + return true; +} + +void BloomPropertyGroup::markAllChanged() { + _bloomIntensityChanged = true; + _bloomThresholdChanged = true; + _bloomSizeChanged = true; +} + +EntityPropertyFlags BloomPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + + CHECK_PROPERTY_CHANGE(PROP_BLOOM_INTENSITY, bloomIntensity); + CHECK_PROPERTY_CHANGE(PROP_BLOOM_THRESHOLD, bloomThreshold); + CHECK_PROPERTY_CHANGE(PROP_BLOOM_SIZE, bloomSize); + + return changedProperties; +} + +void BloomPropertyGroup::getProperties(EntityItemProperties& properties) const { + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomIntensity, getBloomIntensity); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomThreshold, getBloomThreshold); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomSize, getBloomSize); +} + +bool BloomPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomIntensity, bloomIntensity, setBloomIntensity); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomThreshold, bloomThreshold, setBloomThreshold); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomSize, bloomSize, setBloomSize); + + return somethingChanged; +} + +EntityPropertyFlags BloomPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + + requestedProperties += PROP_BLOOM_INTENSITY; + requestedProperties += PROP_BLOOM_THRESHOLD; + requestedProperties += PROP_BLOOM_SIZE; + + return requestedProperties; +} + +void BloomPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize()); +} + +int BloomPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity); + READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold); + READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize); + + return bytesRead; +} diff --git a/libraries/entities/src/BloomPropertyGroup.h b/libraries/entities/src/BloomPropertyGroup.h new file mode 100644 index 0000000000..a1f9b6d748 --- /dev/null +++ b/libraries/entities/src/BloomPropertyGroup.h @@ -0,0 +1,94 @@ +// +// BloomPropertyGroup.h +// libraries/entities/src +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_BloomPropertyGroup_h +#define hifi_BloomPropertyGroup_h + +#include +#include + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; + +static const float INITIAL_BLOOM_INTENSITY { 0.25f }; +static const float INITIAL_BLOOM_THRESHOLD { 0.7f }; +static const float INITIAL_BLOOM_SIZE { 0.9f }; + +/**jsdoc + * Bloom is defined by the following properties. + * @typedef {object} Entities.Bloom + * + * @property {number} bloomIntensity=0.25 - The intensity of the bloom effect. + * @property {number} bloomThreshold=0.7 - The threshold for the bloom effect. + * @property {number} bloomSize=0.9 - The size of the bloom effect. + */ +class BloomPropertyGroup : public PropertyGroup { +public: + // EntityItemProperty related helpers + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, + QScriptEngine* engine, bool skipDefaults, + EntityItemProperties& defaultEntityProperties) const override; + virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + + void merge(const BloomPropertyGroup& other); + + virtual void debugDump() const override; + virtual void listChangedProperties(QList& out) override; + + virtual bool appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags, + const unsigned char*& dataAt, int& processedBytes) override; + virtual void markAllChanged() override; + virtual EntityPropertyFlags getChangedProperties() const override; + + // EntityItem related helpers + // methods for getting/setting all properties of an entity + virtual void getProperties(EntityItemProperties& propertiesOut) const override; + + /// returns true if something changed + virtual bool setProperties(const EntityItemProperties& properties) override; + + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + DEFINE_PROPERTY(PROP_BLOOM_INTENSITY, BloomIntensity, bloomIntensity, float, INITIAL_BLOOM_INTENSITY); + DEFINE_PROPERTY(PROP_BLOOM_THRESHOLD, BloomThreshold, bloomThreshold, float, INITIAL_BLOOM_THRESHOLD); + DEFINE_PROPERTY(PROP_BLOOM_SIZE, BloomSize, bloomSize, float, INITIAL_BLOOM_SIZE); + +}; + +#endif // hifi_BloomPropertyGroup_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 1f9bf2eb18..68d0e6aed4 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -37,6 +37,7 @@ AnimationPropertyGroup EntityItemProperties::_staticAnimation; SkyboxPropertyGroup EntityItemProperties::_staticSkybox; HazePropertyGroup EntityItemProperties::_staticHaze; +BloomPropertyGroup EntityItemProperties::_staticBloom; KeyLightPropertyGroup EntityItemProperties::_staticKeyLight; AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight; @@ -84,6 +85,7 @@ void EntityItemProperties::debugDump() const { getHaze().debugDump(); getKeyLight().debugDump(); getAmbientLight().debugDump(); + getBloom().debugDump(); qCDebug(entities) << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); @@ -211,6 +213,10 @@ QString EntityItemProperties::getHazeModeAsString() const { return getComponentModeAsString(_hazeMode); } +QString EntityItemProperties::getBloomModeAsString() const { + return getComponentModeAsString(_bloomMode); +} + QString EntityItemProperties::getComponentModeString(uint32_t mode) { // return "inherit" if mode is not valid if (mode < COMPONENT_MODE_ITEM_COUNT) { @@ -235,6 +241,15 @@ void EntityItemProperties::setHazeModeFromString(const QString& hazeMode) { } } +void EntityItemProperties::setBloomModeFromString(const QString& bloomMode) { + auto result = findComponent(bloomMode); + + if (result != COMPONENT_MODES.end()) { + _bloomMode = result->first; + _bloomModeChanged = true; + } +} + QString EntityItemProperties::getKeyLightModeAsString() const { return getComponentModeAsString(_keyLightMode); } @@ -394,6 +409,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_KEY_LIGHT_MODE, keyLightMode); CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode); CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode); + CHECK_PROPERTY_CHANGE(PROP_BLOOM_MODE, bloomMode); CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); @@ -454,6 +470,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { changedProperties += _ambientLight.getChangedProperties(); changedProperties += _skybox.getChangedProperties(); changedProperties += _haze.getChangedProperties(); + changedProperties += _bloom.getChangedProperties(); return changedProperties; } @@ -1164,6 +1181,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * "enabled": The haze properties of this zone are enabled, overriding the haze from any enclosing zone. * @property {Entities.Haze} haze - The haze properties of the zone. * + * @property {string} bloomMode="inherit" - Configures the bloom in the zone. Possible values:
+ * "inherit": The bloom from any enclosing zone continues into this zone.
+ * "disabled": The bloom from any enclosing zone and the bloom of this zone are disabled in this zone.
+ * "enabled": The bloom properties of this zone are enabled, overriding the bloom from any enclosing zone. + * @property {Entities.Bloom} bloom - The bloom properties of the zone. + * * @property {boolean} flyingAllowed=true - If true then visitors can fly in the zone; otherwise they cannot. * @property {boolean} ghostingAllowed=true - If true then visitors with avatar collisions turned off will not * collide with content in the zone; otherwise visitors will always collide with content in the zone. @@ -1382,6 +1405,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString()); _haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString()); + _bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString()); @@ -1630,6 +1656,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(keyLightMode, KeyLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(bloomMode, BloomMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize); @@ -1662,6 +1689,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool _ambientLight.copyFromScriptValue(object, _defaultSettings); _skybox.copyFromScriptValue(object, _defaultSettings); _haze.copyFromScriptValue(object, _defaultSettings); + _bloom.copyFromScriptValue(object, _defaultSettings); COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL); @@ -1803,6 +1831,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(keyLightMode); COPY_PROPERTY_IF_CHANGED(ambientLightMode); COPY_PROPERTY_IF_CHANGED(skyboxMode); + COPY_PROPERTY_IF_CHANGED(bloomMode); COPY_PROPERTY_IF_CHANGED(sourceUrl); COPY_PROPERTY_IF_CHANGED(voxelVolumeSize); @@ -1825,6 +1854,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { _ambientLight.merge(other._ambientLight); _skybox.merge(other._skybox); _haze.merge(other._haze); + _bloom.merge(other._bloom); COPY_PROPERTY_IF_CHANGED(xTextureURL); COPY_PROPERTY_IF_CHANGED(yTextureURL); @@ -2096,6 +2126,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_RANGE, Haze, haze, HazeKeyLightRange, hazeKeyLightRange); ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_ALTITUDE, Haze, haze, HazeKeyLightAltitude, hazeKeyLightAltitude); + ADD_PROPERTY_TO_MAP(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t); + ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity); + ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold); + ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize); + ADD_PROPERTY_TO_MAP(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t); @@ -2357,6 +2392,10 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy _staticHaze.setProperties(properties); _staticHaze.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode()); + _staticBloom.setProperties(properties); + _staticBloom.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)properties.getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)properties.getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)properties.getSkyboxMode()); @@ -2731,6 +2770,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode); properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode); + properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); @@ -3044,10 +3086,12 @@ void EntityItemProperties::markAllChanged() { _skyboxModeChanged = true; _ambientLightModeChanged = true; _hazeModeChanged = true; + _bloomModeChanged = true; _animation.markAllChanged(); _skybox.markAllChanged(); _haze.markAllChanged(); + _bloom.markAllChanged(); _sourceUrlChanged = true; _voxelVolumeSizeChanged = true; @@ -3442,15 +3486,15 @@ QList EntityItemProperties::listChangedProperties() { if (hazeModeChanged()) { out += "hazeMode"; } - + if (bloomModeChanged()) { + out += "bloomMode"; + } if (keyLightModeChanged()) { out += "keyLightMode"; } - if (ambientLightModeChanged()) { out += "ambientLightMode"; } - if (skyboxModeChanged()) { out += "skyboxMode"; } @@ -3581,6 +3625,7 @@ QList EntityItemProperties::listChangedProperties() { getAmbientLight().listChangedProperties(out); getSkybox().listChangedProperties(out); getHaze().listChangedProperties(out); + getBloom().listChangedProperties(out); return out; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 04e54c54a5..50305345de 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -42,6 +42,7 @@ #include "SimulationOwner.h" #include "SkyboxPropertyGroup.h" #include "HazePropertyGroup.h" +#include "BloomPropertyGroup.h" #include "TextEntityItem.h" #include "ZoneEntityItem.h" @@ -195,9 +196,11 @@ public: DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); + DEFINE_PROPERTY_REF_ENUM(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup); DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup); + DEFINE_PROPERTY_GROUP(Bloom, bloom, BloomPropertyGroup); DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup); DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, ""); DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float, LineEntityItem::DEFAULT_LINE_WIDTH); @@ -533,6 +536,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, KeyLightMode, keyLightMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AmbientLightMode, ambientLightMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, SkyboxMode, skyboxMode, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, BloomMode, bloomMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Cloneable, cloneable, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneLifetime, cloneLifetime, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 156c5d9dd4..3932730661 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -257,6 +257,11 @@ enum EntityPropertyList { PROP_SPIN_SPREAD, PROP_PARTICLE_ROTATE_WITH_ENTITY, + PROP_BLOOM_MODE, + PROP_BLOOM_INTENSITY, + PROP_BLOOM_THRESHOLD, + PROP_BLOOM_SIZE, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index f2550e5d3c..a7dfa1a41e 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -47,33 +47,27 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(en EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class - // Contains a QString property, must be synchronized + // Contain QString properties, must be synchronized withReadLock([&] { _keyLightProperties.getProperties(properties); - }); - - withReadLock([&] { _ambientLightProperties.getProperties(properties); + _skyboxProperties.getProperties(properties); }); + _hazeProperties.getProperties(properties); + _bloomProperties.getProperties(properties); COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL); - // Contains a QString property, must be synchronized - withReadLock([&] { - _skyboxProperties.getProperties(properties); - }); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed); COPY_ENTITY_PROPERTY_TO_PROPERTIES(filterURL, getFilterURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode); - _hazeProperties.getProperties(properties); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightMode, getKeyLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientLightMode, getAmbientLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(skyboxMode, getSkyboxMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(bloomMode, getBloomMode); return properties; } @@ -102,32 +96,27 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie // Contains a QString property, must be synchronized withWriteLock([&] { _keyLightPropertiesChanged = _keyLightProperties.setProperties(properties); - }); - withWriteLock([&] { _ambientLightPropertiesChanged = _ambientLightProperties.setProperties(properties); + _skyboxPropertiesChanged = _skyboxProperties.setProperties(properties); }); + _hazePropertiesChanged = _hazeProperties.setProperties(properties); + _bloomPropertiesChanged = _bloomProperties.setProperties(properties); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); - // Contains a QString property, must be synchronized - withWriteLock([&] { - _skyboxPropertiesChanged = _skyboxProperties.setProperties(properties); - }); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode); - _hazePropertiesChanged = _hazeProperties.setProperties(properties); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightMode, setKeyLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(skyboxMode, setSkyboxMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode); somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged || - _stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged; + _stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged; return somethingChanged; } @@ -139,54 +128,67 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - int bytesFromKeylight; - withWriteLock([&] { - bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _keyLightPropertiesChanged); - }); + { + int bytesFromKeylight; + withWriteLock([&] { + bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _keyLightPropertiesChanged); + }); + somethingChanged = somethingChanged || _keyLightPropertiesChanged; + bytesRead += bytesFromKeylight; + dataAt += bytesFromKeylight; + } - somethingChanged = somethingChanged || _keyLightPropertiesChanged; - bytesRead += bytesFromKeylight; - dataAt += bytesFromKeylight; + { + int bytesFromAmbientlight; + withWriteLock([&] { + bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged); + }); + somethingChanged = somethingChanged || _ambientLightPropertiesChanged; + bytesRead += bytesFromAmbientlight; + dataAt += bytesFromAmbientlight; + } - int bytesFromAmbientlight; - withWriteLock([&] { - bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged); - }); + { + int bytesFromSkybox; + withWriteLock([&] { + bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _skyboxPropertiesChanged); + }); + somethingChanged = somethingChanged || _skyboxPropertiesChanged; + bytesRead += bytesFromSkybox; + dataAt += bytesFromSkybox; + } - somethingChanged = somethingChanged || _ambientLightPropertiesChanged; - bytesRead += bytesFromAmbientlight; - dataAt += bytesFromAmbientlight; + { + int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _hazePropertiesChanged); + somethingChanged = somethingChanged || _hazePropertiesChanged; + bytesRead += bytesFromHaze; + dataAt += bytesFromHaze; + } + + { + int bytesFromBloom = _bloomProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _bloomPropertiesChanged); + somethingChanged = somethingChanged || _bloomPropertiesChanged; + bytesRead += bytesFromBloom; + dataAt += bytesFromBloom; + } READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - int bytesFromSkybox; - withWriteLock([&] { - bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _skyboxPropertiesChanged); - }); - somethingChanged = somethingChanged || _skyboxPropertiesChanged; - bytesRead += bytesFromSkybox; - dataAt += bytesFromSkybox; - READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed); READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed); READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL); READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode); - - int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _hazePropertiesChanged); - - somethingChanged = somethingChanged || _hazePropertiesChanged; - bytesRead += bytesFromHaze; - dataAt += bytesFromHaze; - READ_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); + READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode); return bytesRead; } @@ -196,29 +198,24 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p withReadLock([&] { requestedProperties += _keyLightProperties.getEntityProperties(params); - }); - - withReadLock([&] { requestedProperties += _ambientLightProperties.getEntityProperties(params); + requestedProperties += _skyboxProperties.getEntityProperties(params); }); + requestedProperties += _hazeProperties.getEntityProperties(params); + requestedProperties += _bloomProperties.getEntityProperties(params); requestedProperties += PROP_SHAPE_TYPE; requestedProperties += PROP_COMPOUND_SHAPE_URL; - withReadLock([&] { - requestedProperties += _skyboxProperties.getEntityProperties(params); - }); - requestedProperties += PROP_FLYING_ALLOWED; requestedProperties += PROP_GHOSTING_ALLOWED; requestedProperties += PROP_FILTER_URL; requestedProperties += PROP_HAZE_MODE; - requestedProperties += _hazeProperties.getEntityProperties(params); - requestedProperties += PROP_KEY_LIGHT_MODE; requestedProperties += PROP_AMBIENT_LIGHT_MODE; requestedProperties += PROP_SKYBOX_MODE; + requestedProperties += PROP_BLOOM_MODE; return requestedProperties; } @@ -235,44 +232,46 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits _keyLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - _ambientLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + _hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + _bloomProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL()); - _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed()); APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed()); APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL()); APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode()); - _hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)getSkyboxMode()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode()); } void ZoneEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); - qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeString(_hazeMode); - qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode); - qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode); - qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode); + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeString(_hazeMode); + qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode); + qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode); + qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode); + qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeString(_bloomMode); _keyLightProperties.debugDump(); _ambientLightProperties.debugDump(); _skyboxProperties.debugDump(); _hazeProperties.debugDump(); + _bloomProperties.debugDump(); } ShapeType ZoneEntityItem::getShapeType() const { @@ -344,6 +343,7 @@ void ZoneEntityItem::resetRenderingPropertiesChanged() { _ambientLightPropertiesChanged = false; _skyboxPropertiesChanged = false; _hazePropertiesChanged = false; + _bloomPropertiesChanged = false; _stagePropertiesChanged = false; }); } @@ -359,6 +359,17 @@ uint32_t ZoneEntityItem::getHazeMode() const { return _hazeMode; } +void ZoneEntityItem::setBloomMode(const uint32_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _bloomMode) { + _bloomMode = value; + _bloomPropertiesChanged = true; + } +} + +uint32_t ZoneEntityItem::getBloomMode() const { + return _bloomMode; +} + void ZoneEntityItem::setKeyLightMode(const uint32_t value) { if (value < COMPONENT_MODE_ITEM_COUNT && value != _keyLightMode) { _keyLightMode = value; diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 0aaa32a57a..e2ebf16f11 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -18,6 +18,7 @@ #include "EntityTree.h" #include "SkyboxPropertyGroup.h" #include "HazePropertyGroup.h" +#include "BloomPropertyGroup.h" #include class ZoneEntityItem : public EntityItem { @@ -79,9 +80,13 @@ public: void setSkyboxMode(uint32_t value); uint32_t getSkyboxMode() const; + void setBloomMode(const uint32_t value); + uint32_t getBloomMode() const; + SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock([&] { return _skyboxProperties; }); } const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; } + const BloomPropertyGroup& getBloomProperties() const { return _bloomProperties; } bool getFlyingAllowed() const { return _flyingAllowed; } void setFlyingAllowed(bool value) { _flyingAllowed = value; } @@ -93,10 +98,8 @@ public: bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; } bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; } bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; } - - bool hazePropertiesChanged() const { - return _hazePropertiesChanged; - } + bool hazePropertiesChanged() const { return _hazePropertiesChanged; } + bool bloomPropertiesChanged() const { return _bloomPropertiesChanged; } bool stagePropertiesChanged() const { return _stagePropertiesChanged; } @@ -133,9 +136,11 @@ protected: uint32_t _ambientLightMode { COMPONENT_MODE_INHERIT }; uint32_t _hazeMode { COMPONENT_MODE_INHERIT }; + uint32_t _bloomMode { COMPONENT_MODE_INHERIT }; SkyboxPropertyGroup _skyboxProperties; HazePropertyGroup _hazeProperties; + BloomPropertyGroup _bloomProperties; bool _flyingAllowed { DEFAULT_FLYING_ALLOWED }; bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED }; @@ -146,6 +151,7 @@ protected: bool _ambientLightPropertiesChanged { false }; bool _skyboxPropertiesChanged { false }; bool _hazePropertiesChanged{ false }; + bool _bloomPropertiesChanged { false }; bool _stagePropertiesChanged { false }; static bool _drawZoneBoundaries; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 82e9820509..ae165af5d1 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::ParticleSpin); + return static_cast(EntityVersion::BloomEffect); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 64c5bfe534..bfc92b9bde 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -240,7 +240,8 @@ enum class EntityVersion : PacketVersion { CollisionMask16Bytes, YieldSimulationOwnership, ParticleEntityFix, - ParticleSpin + ParticleSpin, + BloomEffect }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/render-utils/src/UpdateSceneTask.cpp b/libraries/render-utils/src/UpdateSceneTask.cpp index e05f28ef0d..be61953073 100644 --- a/libraries/render-utils/src/UpdateSceneTask.cpp +++ b/libraries/render-utils/src/UpdateSceneTask.cpp @@ -14,6 +14,7 @@ #include "LightStage.h" #include "BackgroundStage.h" #include "HazeStage.h" +#include "BloomStage.h" #include #include #include "DeferredLightingEffect.h" @@ -22,6 +23,7 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render task.addJob("LightStageSetup"); task.addJob("BackgroundStageSetup"); task.addJob("HazeStageSetup"); + task.addJob("BloomStageSetup"); task.addJob("TransitionStageSetup"); task.addJob("HighlightStageSetup"); From 2959a406d767eaed3717211aa68330b14f093c54 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 7 Aug 2018 18:18:58 -0700 Subject: [PATCH 02/23] working on enabling bloom --- .../src/RenderableZoneEntityItem.cpp | 49 ++++++ .../src/RenderableZoneEntityItem.h | 31 ++-- libraries/entities/src/BloomPropertyGroup.cpp | 159 +++++++++++++++++ libraries/entities/src/BloomPropertyGroup.h | 94 ++++++++++ .../entities/src/EntityItemProperties.cpp | 51 +++++- libraries/entities/src/EntityItemProperties.h | 4 + libraries/entities/src/EntityPropertyFlags.h | 5 + libraries/entities/src/ZoneEntityItem.cpp | 165 ++++++++++-------- libraries/entities/src/ZoneEntityItem.h | 14 +- libraries/graphics/src/graphics/Bloom.cpp | 18 ++ libraries/graphics/src/graphics/Bloom.h | 44 +++++ .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/render-utils/src/BloomEffect.cpp | 93 +++++----- libraries/render-utils/src/BloomEffect.h | 49 +----- libraries/render-utils/src/BloomStage.cpp | 80 +++++++++ libraries/render-utils/src/BloomStage.h | 122 +++++++++++++ libraries/render-utils/src/HazeStage.h | 1 - .../render-utils/src/RenderDeferredTask.cpp | 8 +- .../render-utils/src/UpdateSceneTask.cpp | 2 + libraries/render-utils/src/ZoneRenderer.cpp | 10 +- scripts/system/html/entityProperties.html | 46 +++++ scripts/system/html/js/entityProperties.js | 88 +++++++--- 23 files changed, 917 insertions(+), 221 deletions(-) create mode 100644 libraries/entities/src/BloomPropertyGroup.cpp create mode 100644 libraries/entities/src/BloomPropertyGroup.h create mode 100644 libraries/graphics/src/graphics/Bloom.cpp create mode 100644 libraries/graphics/src/graphics/Bloom.h create mode 100644 libraries/render-utils/src/BloomStage.cpp create mode 100644 libraries/render-utils/src/BloomStage.h diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index c5035431f6..f23e8096f1 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -64,6 +64,13 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity _hazeIndex = INVALID_INDEX; } } + + if (_bloomStage) { + if (!BloomStage::isIndexInvalid(_bloomIndex)) { + _bloomStage->removeBloom(_bloomIndex); + _bloomIndex = INVALID_INDEX; + } + } } void ZoneEntityRenderer::doRender(RenderArgs* args) { @@ -112,6 +119,11 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { assert(_hazeStage); } + if (!_bloomStage) { + _bloomStage = args->_scene->getStage(); + assert(_bloomStage); + } + { // Sun // Need an update ? if (_needSunUpdate) { @@ -161,6 +173,15 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { } } + { + if (_needBloomUpdate) { + if (BloomStage::isIndexInvalid(_bloomIndex)) { + _bloomIndex = _bloomStage->addBloom(_bloom); + } + _needBloomUpdate = false; + } + } + if (_visible) { // Finally, push the lights visible in the frame // @@ -190,6 +211,11 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { if (_hazeMode != COMPONENT_MODE_INHERIT) { _hazeStage->_currentFrame.pushHaze(_hazeIndex); } + + // Bloom only if the mode is not inherit, as the model deals with on/off + if (_bloomMode != COMPONENT_MODE_INHERIT) { + _bloomStage->_currentFrame.pushBloom(_bloomIndex); + } } } @@ -211,6 +237,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen bool ambientLightChanged = entity->ambientLightPropertiesChanged(); bool skyboxChanged = entity->skyboxPropertiesChanged(); bool hazeChanged = entity->hazePropertiesChanged(); + bool bloomChanged = entity->bloomPropertiesChanged(); entity->resetRenderingPropertiesChanged(); _lastPosition = entity->getWorldPosition(); @@ -221,6 +248,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen _ambientLightProperties = entity->getAmbientLightProperties(); _skyboxProperties = entity->getSkyboxProperties(); _hazeProperties = entity->getHazeProperties(); + _bloomProperties = entity->getBloomProperties(); #if 0 if (_lastShapeURL != _typedEntity->getCompoundShapeURL()) { @@ -258,6 +286,10 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen if (hazeChanged) { updateHazeFromEntity(entity); } + + if (bloomChanged) { + updateBloomFromEntity(entity); + } } void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { @@ -276,6 +308,7 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint if (entity->keyLightPropertiesChanged() || entity->ambientLightPropertiesChanged() || entity->hazePropertiesChanged() || + entity->bloomPropertiesChanged() || entity->skyboxPropertiesChanged()) { return true; @@ -388,6 +421,18 @@ void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity) haze->setTransform(entity->getTransform().getMatrix()); } +void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity) { + setBloomMode((ComponentMode)entity->getBloomMode()); + + const auto& bloom = editBloom(); + + const uint32_t bloomMode = entity->getBloomMode(); + bloom->setBloomActive(bloomMode == COMPONENT_MODE_ENABLED); + bloom->setBloomIntensity(_bloomProperties.getBloomIntensity()); + bloom->setBloomThreshold(_bloomProperties.getBloomThreshold()); + bloom->setBloomSize(_bloomProperties.getBloomSize()); +} + void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) { setSkyboxMode((ComponentMode)entity->getSkyboxMode()); @@ -510,6 +555,10 @@ void ZoneEntityRenderer::setSkyboxMode(ComponentMode mode) { _skyboxMode = mode; } +void ZoneEntityRenderer::setBloomMode(ComponentMode mode) { + _bloomMode = mode; +} + void ZoneEntityRenderer::setSkyboxColor(const glm::vec3& color) { editSkybox()->setColor(color); } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index c48679e5d4..3e2690e1bd 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -1,7 +1,6 @@ // // RenderableZoneEntityItem.h // -// // Created by Clement on 4/22/15. // Copyright 2015 High Fidelity, Inc. // @@ -15,10 +14,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include "RenderableEntityItem.h" #include @@ -50,6 +51,7 @@ private: void updateAmbientLightFromEntity(const TypedEntityPointer& entity); void updateHazeFromEntity(const TypedEntityPointer& entity); void updateKeyBackgroundFromEntity(const TypedEntityPointer& entity); + void updateBloomFromEntity(const TypedEntityPointer& entity); void updateAmbientMap(); void updateSkyboxMap(); void setAmbientURL(const QString& ambientUrl); @@ -59,6 +61,7 @@ private: void setKeyLightMode(ComponentMode mode); void setAmbientLightMode(ComponentMode mode); void setSkyboxMode(ComponentMode mode); + void setBloomMode(ComponentMode mode); void setSkyboxColor(const glm::vec3& color); void setProceduralUserData(const QString& userData); @@ -68,6 +71,7 @@ private: graphics::SunSkyStagePointer editBackground() { _needBackgroundUpdate = true; return _background; } graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); } graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; } + graphics::BloomPointer editBloom() { _needBloomUpdate = true; return _bloom; } glm::vec3 _lastPosition; glm::vec3 _lastDimensions; @@ -82,36 +86,43 @@ private: #endif LightStagePointer _stage; - const graphics::LightPointer _sunLight{ std::make_shared() }; - const graphics::LightPointer _ambientLight{ std::make_shared() }; - const graphics::SunSkyStagePointer _background{ std::make_shared() }; - const graphics::HazePointer _haze{ std::make_shared() }; + const graphics::LightPointer _sunLight { std::make_shared() }; + const graphics::LightPointer _ambientLight { std::make_shared() }; + const graphics::SunSkyStagePointer _background { std::make_shared() }; + const graphics::HazePointer _haze { std::make_shared() }; + const graphics::BloomPointer _bloom { std::make_shared() }; ComponentMode _keyLightMode { COMPONENT_MODE_INHERIT }; ComponentMode _ambientLightMode { COMPONENT_MODE_INHERIT }; ComponentMode _skyboxMode { COMPONENT_MODE_INHERIT }; ComponentMode _hazeMode { COMPONENT_MODE_INHERIT }; + ComponentMode _bloomMode { COMPONENT_MODE_INHERIT }; - indexed_container::Index _sunIndex{ LightStage::INVALID_INDEX }; - indexed_container::Index _shadowIndex{ LightStage::INVALID_INDEX }; - indexed_container::Index _ambientIndex{ LightStage::INVALID_INDEX }; + indexed_container::Index _sunIndex { LightStage::INVALID_INDEX }; + indexed_container::Index _shadowIndex { LightStage::INVALID_INDEX }; + indexed_container::Index _ambientIndex { LightStage::INVALID_INDEX }; BackgroundStagePointer _backgroundStage; - BackgroundStage::Index _backgroundIndex{ BackgroundStage::INVALID_INDEX }; + BackgroundStage::Index _backgroundIndex { BackgroundStage::INVALID_INDEX }; HazeStagePointer _hazeStage; - HazeStage::Index _hazeIndex{ HazeStage::INVALID_INDEX }; + HazeStage::Index _hazeIndex { HazeStage::INVALID_INDEX }; + + BloomStagePointer _bloomStage; + BloomStage::Index _bloomIndex { BloomStage::INVALID_INDEX }; bool _needUpdate{ true }; bool _needSunUpdate{ true }; bool _needAmbientUpdate{ true }; bool _needBackgroundUpdate{ true }; bool _needHazeUpdate{ true }; + bool _needBloomUpdate { true }; KeyLightPropertyGroup _keyLightProperties; AmbientLightPropertyGroup _ambientLightProperties; HazePropertyGroup _hazeProperties; SkyboxPropertyGroup _skyboxProperties; + BloomPropertyGroup _bloomProperties; // More attributes used for rendering: QString _ambientTextureURL; diff --git a/libraries/entities/src/BloomPropertyGroup.cpp b/libraries/entities/src/BloomPropertyGroup.cpp new file mode 100644 index 0000000000..2c4d46ab35 --- /dev/null +++ b/libraries/entities/src/BloomPropertyGroup.cpp @@ -0,0 +1,159 @@ +// +// BloomPropertyGroup.cpp +// libraries/entities/src +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BloomPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" +#include "EntityItemPropertiesMacros.h" + +void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize); +} + +void BloomPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomIntensity, float, setBloomIntensity); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomThreshold, float, setBloomThreshold); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomSize, float, setBloomSize); +} + +void BloomPropertyGroup::merge(const BloomPropertyGroup& other) { + COPY_PROPERTY_IF_CHANGED(bloomIntensity); + COPY_PROPERTY_IF_CHANGED(bloomThreshold); + COPY_PROPERTY_IF_CHANGED(bloomSize); +} + +void BloomPropertyGroup::debugDump() const { + qCDebug(entities) << " BloomPropertyGroup: ---------------------------------------------"; + qCDebug(entities) << " _bloomIntensity:" << _bloomIntensity; + qCDebug(entities) << " _bloomThreshold:" << _bloomThreshold; + qCDebug(entities) << " _bloomSize:" << _bloomSize; +} + +void BloomPropertyGroup::listChangedProperties(QList& out) { + if (bloomIntensityChanged()) { + out << "bloom-bloomIntensity"; + } + if (bloomThresholdChanged()) { + out << "bloom-bloomThreshold"; + } + if (bloomSizeChanged()) { + out << "bloom-bloomSize"; + } +} + +bool BloomPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize()); + + return true; +} + +bool BloomPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + + READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity); + READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold); + READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize); + + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_INTENSITY, BloomIntensity); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_THRESHOLD, BloomThreshold); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_SIZE, BloomSize); + + processedBytes += bytesRead; + + Q_UNUSED(somethingChanged); + + return true; +} + +void BloomPropertyGroup::markAllChanged() { + _bloomIntensityChanged = true; + _bloomThresholdChanged = true; + _bloomSizeChanged = true; +} + +EntityPropertyFlags BloomPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + + CHECK_PROPERTY_CHANGE(PROP_BLOOM_INTENSITY, bloomIntensity); + CHECK_PROPERTY_CHANGE(PROP_BLOOM_THRESHOLD, bloomThreshold); + CHECK_PROPERTY_CHANGE(PROP_BLOOM_SIZE, bloomSize); + + return changedProperties; +} + +void BloomPropertyGroup::getProperties(EntityItemProperties& properties) const { + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomIntensity, getBloomIntensity); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomThreshold, getBloomThreshold); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomSize, getBloomSize); +} + +bool BloomPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomIntensity, bloomIntensity, setBloomIntensity); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomThreshold, bloomThreshold, setBloomThreshold); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomSize, bloomSize, setBloomSize); + + return somethingChanged; +} + +EntityPropertyFlags BloomPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + + requestedProperties += PROP_BLOOM_INTENSITY; + requestedProperties += PROP_BLOOM_THRESHOLD; + requestedProperties += PROP_BLOOM_SIZE; + + return requestedProperties; +} + +void BloomPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize()); +} + +int BloomPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity); + READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold); + READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize); + + return bytesRead; +} diff --git a/libraries/entities/src/BloomPropertyGroup.h b/libraries/entities/src/BloomPropertyGroup.h new file mode 100644 index 0000000000..a1f9b6d748 --- /dev/null +++ b/libraries/entities/src/BloomPropertyGroup.h @@ -0,0 +1,94 @@ +// +// BloomPropertyGroup.h +// libraries/entities/src +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_BloomPropertyGroup_h +#define hifi_BloomPropertyGroup_h + +#include +#include + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; + +static const float INITIAL_BLOOM_INTENSITY { 0.25f }; +static const float INITIAL_BLOOM_THRESHOLD { 0.7f }; +static const float INITIAL_BLOOM_SIZE { 0.9f }; + +/**jsdoc + * Bloom is defined by the following properties. + * @typedef {object} Entities.Bloom + * + * @property {number} bloomIntensity=0.25 - The intensity of the bloom effect. + * @property {number} bloomThreshold=0.7 - The threshold for the bloom effect. + * @property {number} bloomSize=0.9 - The size of the bloom effect. + */ +class BloomPropertyGroup : public PropertyGroup { +public: + // EntityItemProperty related helpers + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, + QScriptEngine* engine, bool skipDefaults, + EntityItemProperties& defaultEntityProperties) const override; + virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + + void merge(const BloomPropertyGroup& other); + + virtual void debugDump() const override; + virtual void listChangedProperties(QList& out) override; + + virtual bool appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags, + const unsigned char*& dataAt, int& processedBytes) override; + virtual void markAllChanged() override; + virtual EntityPropertyFlags getChangedProperties() const override; + + // EntityItem related helpers + // methods for getting/setting all properties of an entity + virtual void getProperties(EntityItemProperties& propertiesOut) const override; + + /// returns true if something changed + virtual bool setProperties(const EntityItemProperties& properties) override; + + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + DEFINE_PROPERTY(PROP_BLOOM_INTENSITY, BloomIntensity, bloomIntensity, float, INITIAL_BLOOM_INTENSITY); + DEFINE_PROPERTY(PROP_BLOOM_THRESHOLD, BloomThreshold, bloomThreshold, float, INITIAL_BLOOM_THRESHOLD); + DEFINE_PROPERTY(PROP_BLOOM_SIZE, BloomSize, bloomSize, float, INITIAL_BLOOM_SIZE); + +}; + +#endif // hifi_BloomPropertyGroup_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 1f9bf2eb18..68d0e6aed4 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -37,6 +37,7 @@ AnimationPropertyGroup EntityItemProperties::_staticAnimation; SkyboxPropertyGroup EntityItemProperties::_staticSkybox; HazePropertyGroup EntityItemProperties::_staticHaze; +BloomPropertyGroup EntityItemProperties::_staticBloom; KeyLightPropertyGroup EntityItemProperties::_staticKeyLight; AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight; @@ -84,6 +85,7 @@ void EntityItemProperties::debugDump() const { getHaze().debugDump(); getKeyLight().debugDump(); getAmbientLight().debugDump(); + getBloom().debugDump(); qCDebug(entities) << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); @@ -211,6 +213,10 @@ QString EntityItemProperties::getHazeModeAsString() const { return getComponentModeAsString(_hazeMode); } +QString EntityItemProperties::getBloomModeAsString() const { + return getComponentModeAsString(_bloomMode); +} + QString EntityItemProperties::getComponentModeString(uint32_t mode) { // return "inherit" if mode is not valid if (mode < COMPONENT_MODE_ITEM_COUNT) { @@ -235,6 +241,15 @@ void EntityItemProperties::setHazeModeFromString(const QString& hazeMode) { } } +void EntityItemProperties::setBloomModeFromString(const QString& bloomMode) { + auto result = findComponent(bloomMode); + + if (result != COMPONENT_MODES.end()) { + _bloomMode = result->first; + _bloomModeChanged = true; + } +} + QString EntityItemProperties::getKeyLightModeAsString() const { return getComponentModeAsString(_keyLightMode); } @@ -394,6 +409,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_KEY_LIGHT_MODE, keyLightMode); CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode); CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode); + CHECK_PROPERTY_CHANGE(PROP_BLOOM_MODE, bloomMode); CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); @@ -454,6 +470,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { changedProperties += _ambientLight.getChangedProperties(); changedProperties += _skybox.getChangedProperties(); changedProperties += _haze.getChangedProperties(); + changedProperties += _bloom.getChangedProperties(); return changedProperties; } @@ -1164,6 +1181,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * "enabled": The haze properties of this zone are enabled, overriding the haze from any enclosing zone. * @property {Entities.Haze} haze - The haze properties of the zone. * + * @property {string} bloomMode="inherit" - Configures the bloom in the zone. Possible values:
+ * "inherit": The bloom from any enclosing zone continues into this zone.
+ * "disabled": The bloom from any enclosing zone and the bloom of this zone are disabled in this zone.
+ * "enabled": The bloom properties of this zone are enabled, overriding the bloom from any enclosing zone. + * @property {Entities.Bloom} bloom - The bloom properties of the zone. + * * @property {boolean} flyingAllowed=true - If true then visitors can fly in the zone; otherwise they cannot. * @property {boolean} ghostingAllowed=true - If true then visitors with avatar collisions turned off will not * collide with content in the zone; otherwise visitors will always collide with content in the zone. @@ -1382,6 +1405,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString()); _haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString()); + _bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString()); @@ -1630,6 +1656,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(keyLightMode, KeyLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(bloomMode, BloomMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize); @@ -1662,6 +1689,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool _ambientLight.copyFromScriptValue(object, _defaultSettings); _skybox.copyFromScriptValue(object, _defaultSettings); _haze.copyFromScriptValue(object, _defaultSettings); + _bloom.copyFromScriptValue(object, _defaultSettings); COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL); @@ -1803,6 +1831,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(keyLightMode); COPY_PROPERTY_IF_CHANGED(ambientLightMode); COPY_PROPERTY_IF_CHANGED(skyboxMode); + COPY_PROPERTY_IF_CHANGED(bloomMode); COPY_PROPERTY_IF_CHANGED(sourceUrl); COPY_PROPERTY_IF_CHANGED(voxelVolumeSize); @@ -1825,6 +1854,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { _ambientLight.merge(other._ambientLight); _skybox.merge(other._skybox); _haze.merge(other._haze); + _bloom.merge(other._bloom); COPY_PROPERTY_IF_CHANGED(xTextureURL); COPY_PROPERTY_IF_CHANGED(yTextureURL); @@ -2096,6 +2126,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_RANGE, Haze, haze, HazeKeyLightRange, hazeKeyLightRange); ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_ALTITUDE, Haze, haze, HazeKeyLightAltitude, hazeKeyLightAltitude); + ADD_PROPERTY_TO_MAP(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t); + ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity); + ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold); + ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize); + ADD_PROPERTY_TO_MAP(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t); @@ -2357,6 +2392,10 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy _staticHaze.setProperties(properties); _staticHaze.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode()); + _staticBloom.setProperties(properties); + _staticBloom.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)properties.getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)properties.getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)properties.getSkyboxMode()); @@ -2731,6 +2770,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode); properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode); + properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); @@ -3044,10 +3086,12 @@ void EntityItemProperties::markAllChanged() { _skyboxModeChanged = true; _ambientLightModeChanged = true; _hazeModeChanged = true; + _bloomModeChanged = true; _animation.markAllChanged(); _skybox.markAllChanged(); _haze.markAllChanged(); + _bloom.markAllChanged(); _sourceUrlChanged = true; _voxelVolumeSizeChanged = true; @@ -3442,15 +3486,15 @@ QList EntityItemProperties::listChangedProperties() { if (hazeModeChanged()) { out += "hazeMode"; } - + if (bloomModeChanged()) { + out += "bloomMode"; + } if (keyLightModeChanged()) { out += "keyLightMode"; } - if (ambientLightModeChanged()) { out += "ambientLightMode"; } - if (skyboxModeChanged()) { out += "skyboxMode"; } @@ -3581,6 +3625,7 @@ QList EntityItemProperties::listChangedProperties() { getAmbientLight().listChangedProperties(out); getSkybox().listChangedProperties(out); getHaze().listChangedProperties(out); + getBloom().listChangedProperties(out); return out; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 04e54c54a5..50305345de 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -42,6 +42,7 @@ #include "SimulationOwner.h" #include "SkyboxPropertyGroup.h" #include "HazePropertyGroup.h" +#include "BloomPropertyGroup.h" #include "TextEntityItem.h" #include "ZoneEntityItem.h" @@ -195,9 +196,11 @@ public: DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); + DEFINE_PROPERTY_REF_ENUM(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup); DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup); + DEFINE_PROPERTY_GROUP(Bloom, bloom, BloomPropertyGroup); DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup); DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, ""); DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float, LineEntityItem::DEFAULT_LINE_WIDTH); @@ -533,6 +536,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, KeyLightMode, keyLightMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AmbientLightMode, ambientLightMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, SkyboxMode, skyboxMode, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, BloomMode, bloomMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Cloneable, cloneable, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneLifetime, cloneLifetime, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 156c5d9dd4..3932730661 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -257,6 +257,11 @@ enum EntityPropertyList { PROP_SPIN_SPREAD, PROP_PARTICLE_ROTATE_WITH_ENTITY, + PROP_BLOOM_MODE, + PROP_BLOOM_INTENSITY, + PROP_BLOOM_THRESHOLD, + PROP_BLOOM_SIZE, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index f2550e5d3c..a7dfa1a41e 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -47,33 +47,27 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(en EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class - // Contains a QString property, must be synchronized + // Contain QString properties, must be synchronized withReadLock([&] { _keyLightProperties.getProperties(properties); - }); - - withReadLock([&] { _ambientLightProperties.getProperties(properties); + _skyboxProperties.getProperties(properties); }); + _hazeProperties.getProperties(properties); + _bloomProperties.getProperties(properties); COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL); - // Contains a QString property, must be synchronized - withReadLock([&] { - _skyboxProperties.getProperties(properties); - }); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed); COPY_ENTITY_PROPERTY_TO_PROPERTIES(filterURL, getFilterURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode); - _hazeProperties.getProperties(properties); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightMode, getKeyLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientLightMode, getAmbientLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(skyboxMode, getSkyboxMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(bloomMode, getBloomMode); return properties; } @@ -102,32 +96,27 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie // Contains a QString property, must be synchronized withWriteLock([&] { _keyLightPropertiesChanged = _keyLightProperties.setProperties(properties); - }); - withWriteLock([&] { _ambientLightPropertiesChanged = _ambientLightProperties.setProperties(properties); + _skyboxPropertiesChanged = _skyboxProperties.setProperties(properties); }); + _hazePropertiesChanged = _hazeProperties.setProperties(properties); + _bloomPropertiesChanged = _bloomProperties.setProperties(properties); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); - // Contains a QString property, must be synchronized - withWriteLock([&] { - _skyboxPropertiesChanged = _skyboxProperties.setProperties(properties); - }); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode); - _hazePropertiesChanged = _hazeProperties.setProperties(properties); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightMode, setKeyLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(skyboxMode, setSkyboxMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode); somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged || - _stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged; + _stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged; return somethingChanged; } @@ -139,54 +128,67 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - int bytesFromKeylight; - withWriteLock([&] { - bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _keyLightPropertiesChanged); - }); + { + int bytesFromKeylight; + withWriteLock([&] { + bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _keyLightPropertiesChanged); + }); + somethingChanged = somethingChanged || _keyLightPropertiesChanged; + bytesRead += bytesFromKeylight; + dataAt += bytesFromKeylight; + } - somethingChanged = somethingChanged || _keyLightPropertiesChanged; - bytesRead += bytesFromKeylight; - dataAt += bytesFromKeylight; + { + int bytesFromAmbientlight; + withWriteLock([&] { + bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged); + }); + somethingChanged = somethingChanged || _ambientLightPropertiesChanged; + bytesRead += bytesFromAmbientlight; + dataAt += bytesFromAmbientlight; + } - int bytesFromAmbientlight; - withWriteLock([&] { - bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged); - }); + { + int bytesFromSkybox; + withWriteLock([&] { + bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _skyboxPropertiesChanged); + }); + somethingChanged = somethingChanged || _skyboxPropertiesChanged; + bytesRead += bytesFromSkybox; + dataAt += bytesFromSkybox; + } - somethingChanged = somethingChanged || _ambientLightPropertiesChanged; - bytesRead += bytesFromAmbientlight; - dataAt += bytesFromAmbientlight; + { + int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _hazePropertiesChanged); + somethingChanged = somethingChanged || _hazePropertiesChanged; + bytesRead += bytesFromHaze; + dataAt += bytesFromHaze; + } + + { + int bytesFromBloom = _bloomProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _bloomPropertiesChanged); + somethingChanged = somethingChanged || _bloomPropertiesChanged; + bytesRead += bytesFromBloom; + dataAt += bytesFromBloom; + } READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - int bytesFromSkybox; - withWriteLock([&] { - bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _skyboxPropertiesChanged); - }); - somethingChanged = somethingChanged || _skyboxPropertiesChanged; - bytesRead += bytesFromSkybox; - dataAt += bytesFromSkybox; - READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed); READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed); READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL); READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode); - - int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _hazePropertiesChanged); - - somethingChanged = somethingChanged || _hazePropertiesChanged; - bytesRead += bytesFromHaze; - dataAt += bytesFromHaze; - READ_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); + READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode); return bytesRead; } @@ -196,29 +198,24 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p withReadLock([&] { requestedProperties += _keyLightProperties.getEntityProperties(params); - }); - - withReadLock([&] { requestedProperties += _ambientLightProperties.getEntityProperties(params); + requestedProperties += _skyboxProperties.getEntityProperties(params); }); + requestedProperties += _hazeProperties.getEntityProperties(params); + requestedProperties += _bloomProperties.getEntityProperties(params); requestedProperties += PROP_SHAPE_TYPE; requestedProperties += PROP_COMPOUND_SHAPE_URL; - withReadLock([&] { - requestedProperties += _skyboxProperties.getEntityProperties(params); - }); - requestedProperties += PROP_FLYING_ALLOWED; requestedProperties += PROP_GHOSTING_ALLOWED; requestedProperties += PROP_FILTER_URL; requestedProperties += PROP_HAZE_MODE; - requestedProperties += _hazeProperties.getEntityProperties(params); - requestedProperties += PROP_KEY_LIGHT_MODE; requestedProperties += PROP_AMBIENT_LIGHT_MODE; requestedProperties += PROP_SKYBOX_MODE; + requestedProperties += PROP_BLOOM_MODE; return requestedProperties; } @@ -235,44 +232,46 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits _keyLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - _ambientLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + _hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + _bloomProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL()); - _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed()); APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed()); APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL()); APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode()); - _hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)getSkyboxMode()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode()); } void ZoneEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); - qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeString(_hazeMode); - qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode); - qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode); - qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode); + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeString(_hazeMode); + qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode); + qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode); + qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode); + qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeString(_bloomMode); _keyLightProperties.debugDump(); _ambientLightProperties.debugDump(); _skyboxProperties.debugDump(); _hazeProperties.debugDump(); + _bloomProperties.debugDump(); } ShapeType ZoneEntityItem::getShapeType() const { @@ -344,6 +343,7 @@ void ZoneEntityItem::resetRenderingPropertiesChanged() { _ambientLightPropertiesChanged = false; _skyboxPropertiesChanged = false; _hazePropertiesChanged = false; + _bloomPropertiesChanged = false; _stagePropertiesChanged = false; }); } @@ -359,6 +359,17 @@ uint32_t ZoneEntityItem::getHazeMode() const { return _hazeMode; } +void ZoneEntityItem::setBloomMode(const uint32_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _bloomMode) { + _bloomMode = value; + _bloomPropertiesChanged = true; + } +} + +uint32_t ZoneEntityItem::getBloomMode() const { + return _bloomMode; +} + void ZoneEntityItem::setKeyLightMode(const uint32_t value) { if (value < COMPONENT_MODE_ITEM_COUNT && value != _keyLightMode) { _keyLightMode = value; diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 0aaa32a57a..e2ebf16f11 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -18,6 +18,7 @@ #include "EntityTree.h" #include "SkyboxPropertyGroup.h" #include "HazePropertyGroup.h" +#include "BloomPropertyGroup.h" #include class ZoneEntityItem : public EntityItem { @@ -79,9 +80,13 @@ public: void setSkyboxMode(uint32_t value); uint32_t getSkyboxMode() const; + void setBloomMode(const uint32_t value); + uint32_t getBloomMode() const; + SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock([&] { return _skyboxProperties; }); } const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; } + const BloomPropertyGroup& getBloomProperties() const { return _bloomProperties; } bool getFlyingAllowed() const { return _flyingAllowed; } void setFlyingAllowed(bool value) { _flyingAllowed = value; } @@ -93,10 +98,8 @@ public: bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; } bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; } bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; } - - bool hazePropertiesChanged() const { - return _hazePropertiesChanged; - } + bool hazePropertiesChanged() const { return _hazePropertiesChanged; } + bool bloomPropertiesChanged() const { return _bloomPropertiesChanged; } bool stagePropertiesChanged() const { return _stagePropertiesChanged; } @@ -133,9 +136,11 @@ protected: uint32_t _ambientLightMode { COMPONENT_MODE_INHERIT }; uint32_t _hazeMode { COMPONENT_MODE_INHERIT }; + uint32_t _bloomMode { COMPONENT_MODE_INHERIT }; SkyboxPropertyGroup _skyboxProperties; HazePropertyGroup _hazeProperties; + BloomPropertyGroup _bloomProperties; bool _flyingAllowed { DEFAULT_FLYING_ALLOWED }; bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED }; @@ -146,6 +151,7 @@ protected: bool _ambientLightPropertiesChanged { false }; bool _skyboxPropertiesChanged { false }; bool _hazePropertiesChanged{ false }; + bool _bloomPropertiesChanged { false }; bool _stagePropertiesChanged { false }; static bool _drawZoneBoundaries; diff --git a/libraries/graphics/src/graphics/Bloom.cpp b/libraries/graphics/src/graphics/Bloom.cpp new file mode 100644 index 0000000000..f8dcda3292 --- /dev/null +++ b/libraries/graphics/src/graphics/Bloom.cpp @@ -0,0 +1,18 @@ +// +// Bloom.cpp +// libraries/graphics/src/graphics +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Bloom.h" + +using namespace graphics; + +const float Bloom::INITIAL_BLOOM_INTENSITY { 0.25f }; +const float Bloom::INITIAL_BLOOM_THRESHOLD { 0.7f }; +const float Bloom::INITIAL_BLOOM_SIZE { 0.9f }; \ No newline at end of file diff --git a/libraries/graphics/src/graphics/Bloom.h b/libraries/graphics/src/graphics/Bloom.h new file mode 100644 index 0000000000..02362ce25d --- /dev/null +++ b/libraries/graphics/src/graphics/Bloom.h @@ -0,0 +1,44 @@ +// +// Bloom.h +// libraries/graphics/src/graphics +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_model_Bloom_h +#define hifi_model_Bloom_h + +#include + +namespace graphics { + class Bloom { + public: + // Initial values + static const float INITIAL_BLOOM_INTENSITY; + static const float INITIAL_BLOOM_THRESHOLD; + static const float INITIAL_BLOOM_SIZE; + + Bloom() {} + + void setBloomIntensity(const float bloomIntensity) { _bloomIntensity = bloomIntensity; } + void setBloomThreshold(const float bloomThreshold) { _bloomThreshold = bloomThreshold; } + void setBloomSize(const float bloomSize) { _bloomSize = bloomSize; } + void setBloomActive(const bool isBloomActive) { _isBloomActive = isBloomActive; } + + float getBloomIntensity() { return _bloomIntensity; } + float getBloomThreshold() { return _bloomThreshold; } + float getBloomSize() { return _bloomSize; } + bool getBloomActive() { return _isBloomActive; } + + private: + bool _isBloomActive { false }; + float _bloomIntensity { INITIAL_BLOOM_INTENSITY }; + float _bloomThreshold {INITIAL_BLOOM_THRESHOLD }; + float _bloomSize { INITIAL_BLOOM_SIZE }; + }; + using BloomPointer = std::shared_ptr; +} +#endif // hifi_model_Bloom_h diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 82e9820509..ae165af5d1 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::ParticleSpin); + return static_cast(EntityVersion::BloomEffect); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 64c5bfe534..bfc92b9bde 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -240,7 +240,8 @@ enum class EntityVersion : PacketVersion { CollisionMask16Bytes, YieldSimulationOwnership, ParticleEntityFix, - ParticleSpin + ParticleSpin, + BloomEffect }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 2a9a9b3850..91ba95f3af 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -25,11 +25,7 @@ BloomThreshold::BloomThreshold(unsigned int downsamplingFactor) { _parameters.edit()._sampleCount = downsamplingFactor; } -void BloomThreshold::configure(const Config& config) { - if (_parameters.get()._threshold != config.threshold) { - _parameters.edit()._threshold = config.threshold; - } -} +void BloomThreshold::configure(const Config& config) {} void BloomThreshold::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); @@ -39,6 +35,7 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons const auto frameTransform = inputs.get0(); const auto inputFrameBuffer = inputs.get1(); + const auto bloom = inputs.get2(); assert(inputFrameBuffer->hasColor()); @@ -68,6 +65,28 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y }; + if (!bloom || !bloom->getBloomActive()) { + outputs = _outputBuffer; + return; + } + + _parameters.edit()._threshold = bloom->getBloomThreshold(); + + //{ + // std::string blurName { "BloomBlurN" }; + // auto sigma = 0.5f + bloom->getBloomSize() * 3.5f; + // auto task = static_cast(this); + + // for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { + // blurName.back() = '0' + i; + // auto blurJobIt = task->editJob(blurName); + // assert(blurJobIt != task->_jobs.end()); + // auto& gaussianBlur = blurJobIt->edit(); + // auto gaussianBlurParams = gaussianBlur.getParameters(); + // gaussianBlurParams->setFilterGaussianTaps(9, sigma); + // } + //} + gpu::doInBatch("BloomThreshold::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); @@ -90,16 +109,7 @@ BloomApply::BloomApply() { } -void BloomApply::configure(const Config& config) { - const auto newIntensity = config.intensity / 3.0f; - - if (_parameters.get()._intensities.x != newIntensity) { - auto& parameters = _parameters.edit(); - parameters._intensities.x = newIntensity; - parameters._intensities.y = newIntensity; - parameters._intensities.z = newIntensity; - } -} +void BloomApply::configure(const Config& config) {} void BloomApply::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { assert(renderContext->args); @@ -123,8 +133,19 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In const auto blur0FB = inputs.get1(); const auto blur1FB = inputs.get2(); const auto blur2FB = inputs.get3(); + const auto bloom = inputs.get4(); const glm::ivec4 viewport{ 0, 0, framebufferSize.x, framebufferSize.y }; + if (!bloom || !bloom->getBloomActive()) { + return; + } + + const auto newIntensity = bloom->getBloomIntensity() / 3.0f; + auto& parameters = _parameters.edit(); + parameters._intensities.x = newIntensity; + parameters._intensities.y = newIntensity; + parameters._intensities.z = newIntensity; + gpu::doInBatch("BloomApply::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); @@ -266,43 +287,9 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In }); } -void BloomConfig::setIntensity(float value) { - auto task = static_cast(_task); - auto blurJobIt = task->editJob("BloomApply"); - assert(blurJobIt != task->_jobs.end()); - blurJobIt->getConfiguration()->setProperty("intensity", value); -} +BloomEffect::BloomEffect() {} -float BloomConfig::getIntensity() const { - auto task = static_cast(_task); - auto blurJobIt = task->getJob("BloomApply"); - assert(blurJobIt != task->_jobs.end()); - return blurJobIt->getConfiguration()->property("intensity").toFloat(); -} - -void BloomConfig::setSize(float value) { - std::string blurName{ "BloomBlurN" }; - auto sigma = 0.5f+value*3.5f; - auto task = static_cast(_task); - - for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { - blurName.back() = '0' + i; - auto blurJobIt = task->editJob(blurName); - assert(blurJobIt != task->_jobs.end()); - auto& gaussianBlur = blurJobIt->edit(); - auto gaussianBlurParams = gaussianBlur.getParameters(); - gaussianBlurParams->setFilterGaussianTaps(9, sigma); - } - auto blurJobIt = task->getJob("BloomApply"); - assert(blurJobIt != task->_jobs.end()); - blurJobIt->getConfiguration()->setProperty("sigma", sigma); -} - -Bloom::Bloom() { - -} - -void Bloom::configure(const Config& config) { +void BloomEffect::configure(const Config& config) { std::string blurName{ "BloomBlurN" }; for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { @@ -312,7 +299,7 @@ void Bloom::configure(const Config& config) { } } -void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { +void BloomEffect::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { // Start by computing threshold of color buffer input at quarter resolution const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs, 4U); @@ -325,7 +312,7 @@ void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying const auto& frameBuffer = input[1]; // Mix all blur levels at quarter resolution - const auto applyInput = BloomApply::Inputs(bloomInputBuffer, blurFB0, blurFB1, blurFB2).asVarying(); + const auto applyInput = BloomApply::Inputs(bloomInputBuffer, blurFB0, blurFB1, blurFB2, input.get2()).asVarying(); task.addJob("BloomApply", applyInput); // And then blend result in additive manner on top of final color buffer const auto drawInput = BloomDraw::Inputs(frameBuffer, bloomInputBuffer).asVarying(); diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index 04cb4a9474..150a134dac 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -14,42 +14,21 @@ #include +#include "graphics/Bloom.h" + #include "DeferredFrameTransform.h" class BloomConfig : public render::Task::Config { Q_OBJECT - Q_PROPERTY(float intensity READ getIntensity WRITE setIntensity NOTIFY dirty) - Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty) - -public: - - BloomConfig() : render::Task::Config(false) {} - - float size{ 0.7f }; - - void setIntensity(float value); - float getIntensity() const; - void setSize(float value); - -signals: - void dirty(); }; class BloomThresholdConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty) - -public: - - float threshold{ 0.9f }; - -signals: - void dirty(); }; class BloomThreshold { public: - using Inputs = render::VaryingSet2; + using Inputs = render::VaryingSet3; using Outputs = gpu::FramebufferPointer; using Config = BloomThresholdConfig; using JobModel = render::Job::ModelIO; @@ -71,21 +50,11 @@ private: class BloomApplyConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(float intensity MEMBER intensity NOTIFY dirty) - Q_PROPERTY(float sigma MEMBER sigma NOTIFY dirty) - -public: - - float intensity{ 0.25f }; - float sigma{ 1.0f }; - -signals: - void dirty(); }; class BloomApply { public: - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet5; using Config = BloomApplyConfig; using JobModel = render::Job::ModelI; @@ -118,7 +87,7 @@ private: class DebugBloomConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(int mode MEMBER mode NOTIFY dirty) + Q_PROPERTY(int mode MEMBER mode NOTIFY dirty) public: @@ -155,13 +124,13 @@ private: DebugBloomConfig::Mode _mode; }; -class Bloom { +class BloomEffect { public: - using Inputs = render::VaryingSet2; + using Inputs = render::VaryingSet3; using Config = BloomConfig; - using JobModel = render::Task::ModelI; + using JobModel = render::Task::ModelI; - Bloom(); + BloomEffect(); void configure(const Config& config); void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); diff --git a/libraries/render-utils/src/BloomStage.cpp b/libraries/render-utils/src/BloomStage.cpp new file mode 100644 index 0000000000..9a1c8ee183 --- /dev/null +++ b/libraries/render-utils/src/BloomStage.cpp @@ -0,0 +1,80 @@ +// +// BloomStage.cpp +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "BloomStage.h" + +#include "DeferredLightingEffect.h" + +#include + +std::string BloomStage::_stageName { "BLOOM_STAGE"}; +const BloomStage::Index BloomStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; + +FetchBloomStage::FetchBloomStage() { + _bloom = std::make_shared(); +} + +void FetchBloomStage::configure(const Config& config) { + _bloom->setBloomIntensity(config.bloomIntensity); + _bloom->setBloomThreshold(config.bloomThreshold); + _bloom->setBloomSize(config.bloomSize); + _bloom->setBloomActive(config.isBloomActive); +} + +BloomStage::Index BloomStage::findBloom(const BloomPointer& bloom) const { + auto found = _bloomMap.find(bloom); + if (found != _bloomMap.end()) { + return INVALID_INDEX; + } else { + return (*found).second; + } +} + +BloomStage::Index BloomStage::addBloom(const BloomPointer& bloom) { + auto found = _bloomMap.find(bloom); + if (found == _bloomMap.end()) { + auto bloomId = _blooms.newElement(bloom); + // Avoid failing to allocate a bloom, just pass + if (bloomId != INVALID_INDEX) { + // Insert the bloom and its index in the reverse map + _bloomMap.insert(BloomMap::value_type(bloom, bloomId)); + } + return bloomId; + } else { + return (*found).second; + } +} + +BloomStage::BloomPointer BloomStage::removeBloom(Index index) { + BloomPointer removed = _blooms.freeElement(index); + if (removed) { + _bloomMap.erase(removed); + } + return removed; +} + +BloomStageSetup::BloomStageSetup() {} + +void BloomStageSetup::run(const render::RenderContextPointer& renderContext) { + auto stage = renderContext->_scene->getStage(BloomStage::getName()); + if (!stage) { + renderContext->_scene->resetStage(BloomStage::getName(), std::make_shared()); + } +} + +void FetchBloomStage::run(const render::RenderContextPointer& renderContext, graphics::BloomPointer& bloom) { + auto bloomStage = renderContext->_scene->getStage(); + assert(bloomStage); + + bloom = nullptr; + if (bloomStage->_currentFrame._blooms.size() != 0) { + auto bloomId = bloomStage->_currentFrame._blooms.front(); + bloom = bloomStage->getBloom(bloomId); + } +} diff --git a/libraries/render-utils/src/BloomStage.h b/libraries/render-utils/src/BloomStage.h new file mode 100644 index 0000000000..76829a19a6 --- /dev/null +++ b/libraries/render-utils/src/BloomStage.h @@ -0,0 +1,122 @@ +// +// BloomStage.h + +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_render_utils_BloomStage_h +#define hifi_render_utils_BloomStage_h + +#include +#include +#include +#include +#include + +#include +#include +#include + +// Bloom stage to set up bloom-related rendering tasks +class BloomStage : public render::Stage { +public: + static std::string _stageName; + static const std::string& getName() { return _stageName; } + + using Index = render::indexed_container::Index; + static const Index INVALID_INDEX; + static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } + + using BloomPointer = graphics::BloomPointer; + using Blooms = render::indexed_container::IndexedPointerVector; + using BloomMap = std::unordered_map; + + using BloomIndices = std::vector; + + Index findBloom(const BloomPointer& bloom) const; + Index addBloom(const BloomPointer& bloom); + + BloomPointer removeBloom(Index index); + + bool checkBloomId(Index index) const { return _blooms.checkIndex(index); } + + Index getNumBlooms() const { return _blooms.getNumElements(); } + Index getNumFreeBlooms() const { return _blooms.getNumFreeIndices(); } + Index getNumAllocatedBlooms() const { return _blooms.getNumAllocatedIndices(); } + + BloomPointer getBloom(Index bloomId) const { + return _blooms.get(bloomId); + } + + Blooms _blooms; + BloomMap _bloomMap; + + class Frame { + public: + Frame() {} + + void clear() { _blooms.clear(); } + + void pushBloom(BloomStage::Index index) { _blooms.emplace_back(index); } + + BloomStage::BloomIndices _blooms; + }; + + Frame _currentFrame; +}; +using BloomStagePointer = std::shared_ptr; + +class BloomStageSetup { +public: + using JobModel = render::Job::Model; + + BloomStageSetup(); + void run(const render::RenderContextPointer& renderContext); + +protected: +}; + +class FetchBloomConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(float bloomIntensity MEMBER bloomIntensity WRITE setBloomIntensity NOTIFY dirty); + Q_PROPERTY(float bloomThreshold MEMBER bloomThreshold WRITE setBloomThreshold NOTIFY dirty); + Q_PROPERTY(float bloomSize MEMBER bloomSize WRITE setBloomSize NOTIFY dirty); + Q_PROPERTY(bool isBloomActive MEMBER isBloomActive WRITE setBloomActive NOTIFY dirty); + +public: + FetchBloomConfig() : render::Job::Config() {} + + float bloomIntensity { graphics::Bloom::INITIAL_BLOOM_INTENSITY }; + float bloomThreshold { graphics::Bloom::INITIAL_BLOOM_THRESHOLD }; + float bloomSize { graphics::Bloom::INITIAL_BLOOM_SIZE }; + + bool isBloomActive { false }; + +public slots: + void setBloomIntensity(const float value) { bloomIntensity = value; emit dirty(); } + void setBloomThreshold(const float value) { bloomThreshold = value; emit dirty(); } + void setBloomSize(const float value) { bloomSize = value; emit dirty(); } + void setBloomActive(const bool active) { isBloomActive = active; emit dirty(); } + +signals: + void dirty(); +}; + +class FetchBloomStage { +public: + using Config = FetchBloomConfig; + using JobModel = render::Job::ModelO; + + FetchBloomStage(); + + void configure(const Config& config); + void run(const render::RenderContextPointer& renderContext, graphics::BloomPointer& bloom); + +private: + graphics::BloomPointer _bloom; +}; +#endif diff --git a/libraries/render-utils/src/HazeStage.h b/libraries/render-utils/src/HazeStage.h index 8f137cb280..b48168e376 100644 --- a/libraries/render-utils/src/HazeStage.h +++ b/libraries/render-utils/src/HazeStage.h @@ -163,6 +163,5 @@ public: private: graphics::HazePointer _haze; - gpu::PipelinePointer _hazePipeline; }; #endif diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 59c86acd19..b71d712a6e 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -45,6 +45,7 @@ #include "TextureCache.h" #include "ZoneRenderer.h" #include "FadeEffect.h" +#include "BloomStage.h" #include "RenderUtilsLogging.h" #include "AmbientOcclusionEffect.h" @@ -171,7 +172,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto velocityBufferOutputs = task.addJob("VelocityBuffer", velocityBufferInputs); const auto velocityBuffer = velocityBufferOutputs.getN(0); - // Clear Light, Haze and Skybox Stages and render zones from the general metas bucket + // Clear Light, Haze, Bloom, and Skybox Stages and render zones from the general metas bucket const auto zones = task.addJob("ZoneRenderer", metas); // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. @@ -240,8 +241,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("Antialiasing", antialiasingInputs); // Add bloom - const auto bloomInputs = Bloom::Inputs(deferredFrameTransform, lightingFramebuffer).asVarying(); - task.addJob("Bloom", bloomInputs); + const auto bloomModel = task.addJob("BloomModel"); + const auto bloomInputs = BloomEffect::Inputs(deferredFrameTransform, lightingFramebuffer, bloomModel).asVarying(); + task.addJob("Bloom", bloomInputs); // Lighting Buffer ready for tone mapping const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, scaledPrimaryFramebuffer).asVarying(); diff --git a/libraries/render-utils/src/UpdateSceneTask.cpp b/libraries/render-utils/src/UpdateSceneTask.cpp index e05f28ef0d..be61953073 100644 --- a/libraries/render-utils/src/UpdateSceneTask.cpp +++ b/libraries/render-utils/src/UpdateSceneTask.cpp @@ -14,6 +14,7 @@ #include "LightStage.h" #include "BackgroundStage.h" #include "HazeStage.h" +#include "BloomStage.h" #include #include #include "DeferredLightingEffect.h" @@ -22,6 +23,7 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render task.addJob("LightStageSetup"); task.addJob("BackgroundStageSetup"); task.addJob("HazeStageSetup"); + task.addJob("BloomStageSetup"); task.addJob("TransitionStageSetup"); task.addJob("HighlightStageSetup"); diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index 3299b0c41c..d85818a21a 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -21,11 +21,12 @@ #include "StencilMaskPass.h" #include "DeferredLightingEffect.h" - #include "render-utils/ShaderConstants.h" #include "StencilMaskPass.h" #include "DeferredLightingEffect.h" +#include "BloomStage.h" + namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; @@ -63,7 +64,7 @@ void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& oupu } void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) { - // Grab light, background and haze stages and clear them + // Grab light, background, haze, and bloom stages and clear them auto lightStage = context->_scene->getStage(); assert(lightStage); lightStage->_currentFrame.clear(); @@ -76,6 +77,10 @@ void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) assert(hazeStage); hazeStage->_currentFrame.clear(); + auto bloomStage = context->_scene->getStage(); + assert(bloomStage); + bloomStage->_currentFrame.clear(); + // call render over the zones to grab their components in the correct order first... render::renderItems(context, inputs); @@ -84,6 +89,7 @@ void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) lightStage->_currentFrame.pushAmbientLight(lightStage->getDefaultLight()); backgroundStage->_currentFrame.pushBackground(0); hazeStage->_currentFrame.pushHaze(0); + bloomStage->_currentFrame.pushBloom(0); } const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() { diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 9614f8b8fe..744150253d 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -678,6 +678,52 @@ +
+ + Bloom + +
+ Inherit + Off + On +
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index d2cea2d394..43ea6bf22f 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -839,7 +839,7 @@ function loaded() { var elZoneHazeModeInherit = document.getElementById("property-zone-haze-mode-inherit"); var elZoneHazeModeDisabled = document.getElementById("property-zone-haze-mode-disabled"); var elZoneHazeModeEnabled = document.getElementById("property-zone-haze-mode-enabled"); - + var elZoneHazeRange = document.getElementById("property-zone-haze-range"); var elZoneHazeColor = document.getElementById("property-zone-haze-color"); var elZoneHazeColorRed = document.getElementById("property-zone-haze-color-red"); @@ -858,6 +858,15 @@ function loaded() { var elZoneHazeBackgroundBlend = document.getElementById("property-zone-haze-background-blend"); + // Bloom + var elZoneBloomModeInherit = document.getElementById("property-zone-bloom-mode-inherit"); + var elZoneBloomModeDisabled = document.getElementById("property-zone-bloom-mode-disabled"); + var elZoneBloomModeEnabled = document.getElementById("property-zone-bloom-mode-enabled"); + + var elZoneBloomIntensity = document.getElementById("property-zone-bloom-intensity"); + var elZoneBloomThreshold = document.getElementById("property-zone-bloom-threshold"); + var elZoneBloomSize = document.getElementById("property-zone-bloom-size"); + var elZoneSkyboxColor = document.getElementById("property-zone-skybox-color"); var elZoneSkyboxColorRed = document.getElementById("property-zone-skybox-color-red"); var elZoneSkyboxColorGreen = document.getElementById("property-zone-skybox-color-green"); @@ -914,19 +923,19 @@ function loaded() { deleteJSONMaterialEditor(); } } - + elTypeIcon.style.display = "none"; elType.innerHTML = "No selection"; elPropertiesList.className = ''; - + elID.value = ""; elName.value = ""; elLocked.checked = false; elVisible.checked = false; - + elParentID.value = ""; elParentJointIndex.value = ""; - + elColorRed.value = ""; elColorGreen.value = ""; elColorBlue.value = ""; @@ -935,15 +944,15 @@ function loaded() { elPositionX.value = ""; elPositionY.value = ""; elPositionZ.value = ""; - + elRotationX.value = ""; elRotationY.value = ""; elRotationZ.value = ""; - + elDimensionsX.value = ""; elDimensionsY.value = ""; elDimensionsZ.value = ""; - + elRegistrationX.value = ""; elRegistrationY.value = ""; elRegistrationZ.value = ""; @@ -965,14 +974,14 @@ function loaded() { elAccelerationX.value = ""; elAccelerationY.value = ""; elAccelerationZ.value = ""; - + elRestitution.value = ""; elFriction.value = ""; elDensity.value = ""; - + elCollisionless.checked = false; elDynamic.checked = false; - + elCollideStatic.checked = false; elCollideKinematic.checked = false; elCollideDynamic.checked = false; @@ -989,27 +998,27 @@ function loaded() { elCloneableGroup.style.display = "none"; elCloneableLimit.value = ""; elCloneableLifetime.value = ""; - - showElements(document.getElementsByClassName('can-cast-shadow-section'), true); + + showElements(document.getElementsByClassName('can-cast-shadow-section'), true); elCanCastShadow.checked = false; - + elCollisionSoundURL.value = ""; elLifetime.value = ""; elScriptURL.value = ""; elServerScripts.value = ""; elHyperlinkHref.value = ""; elDescription.value = ""; - + deleteJSONEditor(); elUserData.value = ""; showUserDataTextArea(); showSaveUserDataButton(); showNewJSONEditorButton(); - + // Shape Properties elShape.value = "Cube"; setDropdownText(elShape); - + // Light Properties elLightSpotLight.checked = false; elLightColor.style.backgroundColor = "rgb(" + 0 + "," + 0 + "," + 0 + ")"; @@ -1020,7 +1029,7 @@ function loaded() { elLightFalloffRadius.value = ""; elLightExponent.value = ""; elLightCutoff.value = ""; - + // Model Properties elModelURL.value = ""; elCompoundShapeURL.value = ""; @@ -1037,7 +1046,7 @@ function loaded() { elModelAnimationAllowTranslation.checked = false; elModelTextures.value = ""; elModelOriginalTextures.value = ""; - + // Zone Properties elZoneFlyingAllowed.checked = false; elZoneGhostingAllowed.checked = false; @@ -1067,6 +1076,9 @@ function loaded() { elZoneHazeAltitudeEffect.checked = false; elZoneHazeBaseRef.value = ""; elZoneHazeCeiling.value = ""; + elZoneBloomIntensity.value = ""; + elZoneBloomThreshold.value = ""; + elZoneBloomSize.value = ""; elZoneSkyboxColor.style.backgroundColor = "rgb(" + 0 + "," + 0 + "," + 0 + ")"; elZoneSkyboxColorRed.value = ""; elZoneSkyboxColorGreen.value = ""; @@ -1076,7 +1088,8 @@ function loaded() { showElements(document.getElementsByClassName('skybox-section'), true); showElements(document.getElementsByClassName('ambient-section'), true); showElements(document.getElementsByClassName('haze-section'), true); - + showElements(document.getElementsByClassName('bloom-section'), true); + // Text Properties elTextText.value = ""; elTextLineHeight.value = ""; @@ -1089,14 +1102,14 @@ function loaded() { elTextBackgroundColorRed.value = ""; elTextBackgroundColorGreen.value = ""; elTextBackgroundColorBlue.value = ""; - + // Image Properties elImageURL.value = ""; - + // Web Properties elWebSourceURL.value = ""; elWebDPI.value = ""; - + // Material Properties elMaterialURL.value = ""; elParentMaterialNameNumber.value = ""; @@ -1107,13 +1120,13 @@ function loaded() { elMaterialMappingScaleX.value = ""; elMaterialMappingScaleY.value = ""; elMaterialMappingRot.value = ""; - + deleteJSONMaterialEditor(); elMaterialData.value = ""; showMaterialDataTextArea(); showSaveMaterialDataButton(); showNewJSONMaterialEditorButton(); - + disableProperties(); } else if (data.selections.length > 1) { deleteJSONEditor(); @@ -1250,7 +1263,7 @@ function loaded() { elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; elCloneableLimit.value = properties.cloneLimit; elCloneableLifetime.value = properties.cloneLifetime; - + var grabbablesSet = false; var parsedUserData = {}; try { @@ -1476,6 +1489,14 @@ function loaded() { elZoneHazeBaseRef.value = properties.haze.hazeBaseRef.toFixed(0); elZoneHazeCeiling.value = properties.haze.hazeCeiling.toFixed(0); + elZoneBloomModeInherit.checked = (properties.bloomMode === 'inherit'); + elZoneBloomModeDisabled.checked = (properties.bloomMode === 'disabled'); + elZoneBloomModeEnabled.checked = (properties.bloomMode === 'enabled'); + + elZoneBloomIntensity.value = properties.bloom.bloomIntensity.toFixed(2); + elZoneBloomThreshold.value = properties.bloom.bloomThreshold.toFixed(2); + elZoneBloomSize.value = properties.bloom.bloomSize.toFixed(2); + elShapeType.value = properties.shapeType; elCompoundShapeURL.value = properties.compoundShapeURL; @@ -1502,6 +1523,9 @@ function loaded() { showElements(document.getElementsByClassName('haze-section'), elZoneHazeModeEnabled.checked); + + showElements(document.getElementsByClassName('bloom-section'), + elZoneBloomModeEnabled.checked); } else if (properties.type === "PolyVox") { elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2); elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2); @@ -2067,6 +2091,18 @@ function loaded() { elZoneHazeBackgroundBlend.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeBackgroundBlend')); + // Bloom + var bloomModeChanged = createZoneComponentModeChangedFunction('bloomMode', + elZoneBloomModeInherit, elZoneBloomModeDisabled, elZoneBloomModeEnabled); + + elZoneBloomModeInherit.addEventListener('change', bloomModeChanged); + elZoneBloomModeDisabled.addEventListener('change', bloomModeChanged); + elZoneBloomModeEnabled.addEventListener('change', bloomModeChanged); + + elZoneBloomIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomIntensity')); + elZoneBloomThreshold.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomThreshold')); + elZoneBloomSize.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomSize')); + var zoneSkyboxColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('skybox', 'color', elZoneSkyboxColorRed, elZoneSkyboxColorGreen, elZoneSkyboxColorBlue); elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction); From fb75b42059a6fc318f23579f9b9aebfaf8265459 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 7 Aug 2018 18:18:58 -0700 Subject: [PATCH 03/23] working on enabling bloom --- .../src/RenderableZoneEntityItem.cpp | 50 ++++++ .../src/RenderableZoneEntityItem.h | 31 ++-- libraries/entities/src/BloomPropertyGroup.cpp | 159 +++++++++++++++++ libraries/entities/src/BloomPropertyGroup.h | 94 ++++++++++ .../entities/src/EntityItemProperties.cpp | 51 +++++- libraries/entities/src/EntityItemProperties.h | 4 + libraries/entities/src/EntityPropertyFlags.h | 5 + libraries/entities/src/ZoneEntityItem.cpp | 165 ++++++++++-------- libraries/entities/src/ZoneEntityItem.h | 14 +- libraries/graphics/src/graphics/Bloom.cpp | 18 ++ libraries/graphics/src/graphics/Bloom.h | 44 +++++ .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/render-utils/src/BloomEffect.cpp | 93 +++++----- libraries/render-utils/src/BloomEffect.h | 49 +----- libraries/render-utils/src/BloomStage.cpp | 80 +++++++++ libraries/render-utils/src/BloomStage.h | 122 +++++++++++++ libraries/render-utils/src/HazeStage.h | 1 - .../render-utils/src/RenderDeferredTask.cpp | 9 +- .../render-utils/src/UpdateSceneTask.cpp | 2 + libraries/render-utils/src/ZoneRenderer.cpp | 10 +- scripts/system/html/entityProperties.html | 46 +++++ scripts/system/html/js/entityProperties.js | 88 +++++++--- 23 files changed, 919 insertions(+), 221 deletions(-) create mode 100644 libraries/entities/src/BloomPropertyGroup.cpp create mode 100644 libraries/entities/src/BloomPropertyGroup.h create mode 100644 libraries/graphics/src/graphics/Bloom.cpp create mode 100644 libraries/graphics/src/graphics/Bloom.h create mode 100644 libraries/render-utils/src/BloomStage.cpp create mode 100644 libraries/render-utils/src/BloomStage.h diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index c5035431f6..928d5ca6a3 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -64,6 +64,13 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity _hazeIndex = INVALID_INDEX; } } + + if (_bloomStage) { + if (!BloomStage::isIndexInvalid(_bloomIndex)) { + _bloomStage->removeBloom(_bloomIndex); + _bloomIndex = INVALID_INDEX; + } + } } void ZoneEntityRenderer::doRender(RenderArgs* args) { @@ -112,6 +119,11 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { assert(_hazeStage); } + if (!_bloomStage) { + _bloomStage = args->_scene->getStage(); + assert(_bloomStage); + } + { // Sun // Need an update ? if (_needSunUpdate) { @@ -161,6 +173,15 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { } } + { + if (_needBloomUpdate) { + if (BloomStage::isIndexInvalid(_bloomIndex)) { + _bloomIndex = _bloomStage->addBloom(_bloom); + } + _needBloomUpdate = false; + } + } + if (_visible) { // Finally, push the lights visible in the frame // @@ -190,6 +211,12 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { if (_hazeMode != COMPONENT_MODE_INHERIT) { _hazeStage->_currentFrame.pushHaze(_hazeIndex); } + + if (_bloomMode == COMPONENT_MODE_DISABLED) { + _bloomStage->_currentFrame.pushBloom(INVALID_INDEX); + } else if (_ambientLightMode == COMPONENT_MODE_ENABLED) { + _bloomStage->_currentFrame.pushBloom(_bloomIndex); + } } } @@ -211,6 +238,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen bool ambientLightChanged = entity->ambientLightPropertiesChanged(); bool skyboxChanged = entity->skyboxPropertiesChanged(); bool hazeChanged = entity->hazePropertiesChanged(); + bool bloomChanged = entity->bloomPropertiesChanged(); entity->resetRenderingPropertiesChanged(); _lastPosition = entity->getWorldPosition(); @@ -221,6 +249,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen _ambientLightProperties = entity->getAmbientLightProperties(); _skyboxProperties = entity->getSkyboxProperties(); _hazeProperties = entity->getHazeProperties(); + _bloomProperties = entity->getBloomProperties(); #if 0 if (_lastShapeURL != _typedEntity->getCompoundShapeURL()) { @@ -258,6 +287,10 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen if (hazeChanged) { updateHazeFromEntity(entity); } + + if (bloomChanged) { + updateBloomFromEntity(entity); + } } void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { @@ -276,6 +309,7 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint if (entity->keyLightPropertiesChanged() || entity->ambientLightPropertiesChanged() || entity->hazePropertiesChanged() || + entity->bloomPropertiesChanged() || entity->skyboxPropertiesChanged()) { return true; @@ -388,6 +422,18 @@ void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity) haze->setTransform(entity->getTransform().getMatrix()); } +void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity) { + setBloomMode((ComponentMode)entity->getBloomMode()); + + const auto& bloom = editBloom(); + + const uint32_t bloomMode = entity->getBloomMode(); + bloom->setBloomActive(bloomMode == COMPONENT_MODE_ENABLED); + bloom->setBloomIntensity(_bloomProperties.getBloomIntensity()); + bloom->setBloomThreshold(_bloomProperties.getBloomThreshold()); + bloom->setBloomSize(_bloomProperties.getBloomSize()); +} + void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) { setSkyboxMode((ComponentMode)entity->getSkyboxMode()); @@ -510,6 +556,10 @@ void ZoneEntityRenderer::setSkyboxMode(ComponentMode mode) { _skyboxMode = mode; } +void ZoneEntityRenderer::setBloomMode(ComponentMode mode) { + _bloomMode = mode; +} + void ZoneEntityRenderer::setSkyboxColor(const glm::vec3& color) { editSkybox()->setColor(color); } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index c48679e5d4..3e2690e1bd 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -1,7 +1,6 @@ // // RenderableZoneEntityItem.h // -// // Created by Clement on 4/22/15. // Copyright 2015 High Fidelity, Inc. // @@ -15,10 +14,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include "RenderableEntityItem.h" #include @@ -50,6 +51,7 @@ private: void updateAmbientLightFromEntity(const TypedEntityPointer& entity); void updateHazeFromEntity(const TypedEntityPointer& entity); void updateKeyBackgroundFromEntity(const TypedEntityPointer& entity); + void updateBloomFromEntity(const TypedEntityPointer& entity); void updateAmbientMap(); void updateSkyboxMap(); void setAmbientURL(const QString& ambientUrl); @@ -59,6 +61,7 @@ private: void setKeyLightMode(ComponentMode mode); void setAmbientLightMode(ComponentMode mode); void setSkyboxMode(ComponentMode mode); + void setBloomMode(ComponentMode mode); void setSkyboxColor(const glm::vec3& color); void setProceduralUserData(const QString& userData); @@ -68,6 +71,7 @@ private: graphics::SunSkyStagePointer editBackground() { _needBackgroundUpdate = true; return _background; } graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); } graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; } + graphics::BloomPointer editBloom() { _needBloomUpdate = true; return _bloom; } glm::vec3 _lastPosition; glm::vec3 _lastDimensions; @@ -82,36 +86,43 @@ private: #endif LightStagePointer _stage; - const graphics::LightPointer _sunLight{ std::make_shared() }; - const graphics::LightPointer _ambientLight{ std::make_shared() }; - const graphics::SunSkyStagePointer _background{ std::make_shared() }; - const graphics::HazePointer _haze{ std::make_shared() }; + const graphics::LightPointer _sunLight { std::make_shared() }; + const graphics::LightPointer _ambientLight { std::make_shared() }; + const graphics::SunSkyStagePointer _background { std::make_shared() }; + const graphics::HazePointer _haze { std::make_shared() }; + const graphics::BloomPointer _bloom { std::make_shared() }; ComponentMode _keyLightMode { COMPONENT_MODE_INHERIT }; ComponentMode _ambientLightMode { COMPONENT_MODE_INHERIT }; ComponentMode _skyboxMode { COMPONENT_MODE_INHERIT }; ComponentMode _hazeMode { COMPONENT_MODE_INHERIT }; + ComponentMode _bloomMode { COMPONENT_MODE_INHERIT }; - indexed_container::Index _sunIndex{ LightStage::INVALID_INDEX }; - indexed_container::Index _shadowIndex{ LightStage::INVALID_INDEX }; - indexed_container::Index _ambientIndex{ LightStage::INVALID_INDEX }; + indexed_container::Index _sunIndex { LightStage::INVALID_INDEX }; + indexed_container::Index _shadowIndex { LightStage::INVALID_INDEX }; + indexed_container::Index _ambientIndex { LightStage::INVALID_INDEX }; BackgroundStagePointer _backgroundStage; - BackgroundStage::Index _backgroundIndex{ BackgroundStage::INVALID_INDEX }; + BackgroundStage::Index _backgroundIndex { BackgroundStage::INVALID_INDEX }; HazeStagePointer _hazeStage; - HazeStage::Index _hazeIndex{ HazeStage::INVALID_INDEX }; + HazeStage::Index _hazeIndex { HazeStage::INVALID_INDEX }; + + BloomStagePointer _bloomStage; + BloomStage::Index _bloomIndex { BloomStage::INVALID_INDEX }; bool _needUpdate{ true }; bool _needSunUpdate{ true }; bool _needAmbientUpdate{ true }; bool _needBackgroundUpdate{ true }; bool _needHazeUpdate{ true }; + bool _needBloomUpdate { true }; KeyLightPropertyGroup _keyLightProperties; AmbientLightPropertyGroup _ambientLightProperties; HazePropertyGroup _hazeProperties; SkyboxPropertyGroup _skyboxProperties; + BloomPropertyGroup _bloomProperties; // More attributes used for rendering: QString _ambientTextureURL; diff --git a/libraries/entities/src/BloomPropertyGroup.cpp b/libraries/entities/src/BloomPropertyGroup.cpp new file mode 100644 index 0000000000..2c4d46ab35 --- /dev/null +++ b/libraries/entities/src/BloomPropertyGroup.cpp @@ -0,0 +1,159 @@ +// +// BloomPropertyGroup.cpp +// libraries/entities/src +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BloomPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" +#include "EntityItemPropertiesMacros.h" + +void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize); +} + +void BloomPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomIntensity, float, setBloomIntensity); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomThreshold, float, setBloomThreshold); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomSize, float, setBloomSize); +} + +void BloomPropertyGroup::merge(const BloomPropertyGroup& other) { + COPY_PROPERTY_IF_CHANGED(bloomIntensity); + COPY_PROPERTY_IF_CHANGED(bloomThreshold); + COPY_PROPERTY_IF_CHANGED(bloomSize); +} + +void BloomPropertyGroup::debugDump() const { + qCDebug(entities) << " BloomPropertyGroup: ---------------------------------------------"; + qCDebug(entities) << " _bloomIntensity:" << _bloomIntensity; + qCDebug(entities) << " _bloomThreshold:" << _bloomThreshold; + qCDebug(entities) << " _bloomSize:" << _bloomSize; +} + +void BloomPropertyGroup::listChangedProperties(QList& out) { + if (bloomIntensityChanged()) { + out << "bloom-bloomIntensity"; + } + if (bloomThresholdChanged()) { + out << "bloom-bloomThreshold"; + } + if (bloomSizeChanged()) { + out << "bloom-bloomSize"; + } +} + +bool BloomPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize()); + + return true; +} + +bool BloomPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + + READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity); + READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold); + READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize); + + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_INTENSITY, BloomIntensity); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_THRESHOLD, BloomThreshold); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_SIZE, BloomSize); + + processedBytes += bytesRead; + + Q_UNUSED(somethingChanged); + + return true; +} + +void BloomPropertyGroup::markAllChanged() { + _bloomIntensityChanged = true; + _bloomThresholdChanged = true; + _bloomSizeChanged = true; +} + +EntityPropertyFlags BloomPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + + CHECK_PROPERTY_CHANGE(PROP_BLOOM_INTENSITY, bloomIntensity); + CHECK_PROPERTY_CHANGE(PROP_BLOOM_THRESHOLD, bloomThreshold); + CHECK_PROPERTY_CHANGE(PROP_BLOOM_SIZE, bloomSize); + + return changedProperties; +} + +void BloomPropertyGroup::getProperties(EntityItemProperties& properties) const { + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomIntensity, getBloomIntensity); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomThreshold, getBloomThreshold); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomSize, getBloomSize); +} + +bool BloomPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomIntensity, bloomIntensity, setBloomIntensity); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomThreshold, bloomThreshold, setBloomThreshold); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomSize, bloomSize, setBloomSize); + + return somethingChanged; +} + +EntityPropertyFlags BloomPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + + requestedProperties += PROP_BLOOM_INTENSITY; + requestedProperties += PROP_BLOOM_THRESHOLD; + requestedProperties += PROP_BLOOM_SIZE; + + return requestedProperties; +} + +void BloomPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize()); +} + +int BloomPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity); + READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold); + READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize); + + return bytesRead; +} diff --git a/libraries/entities/src/BloomPropertyGroup.h b/libraries/entities/src/BloomPropertyGroup.h new file mode 100644 index 0000000000..a1f9b6d748 --- /dev/null +++ b/libraries/entities/src/BloomPropertyGroup.h @@ -0,0 +1,94 @@ +// +// BloomPropertyGroup.h +// libraries/entities/src +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_BloomPropertyGroup_h +#define hifi_BloomPropertyGroup_h + +#include +#include + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; + +static const float INITIAL_BLOOM_INTENSITY { 0.25f }; +static const float INITIAL_BLOOM_THRESHOLD { 0.7f }; +static const float INITIAL_BLOOM_SIZE { 0.9f }; + +/**jsdoc + * Bloom is defined by the following properties. + * @typedef {object} Entities.Bloom + * + * @property {number} bloomIntensity=0.25 - The intensity of the bloom effect. + * @property {number} bloomThreshold=0.7 - The threshold for the bloom effect. + * @property {number} bloomSize=0.9 - The size of the bloom effect. + */ +class BloomPropertyGroup : public PropertyGroup { +public: + // EntityItemProperty related helpers + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, + QScriptEngine* engine, bool skipDefaults, + EntityItemProperties& defaultEntityProperties) const override; + virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + + void merge(const BloomPropertyGroup& other); + + virtual void debugDump() const override; + virtual void listChangedProperties(QList& out) override; + + virtual bool appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags, + const unsigned char*& dataAt, int& processedBytes) override; + virtual void markAllChanged() override; + virtual EntityPropertyFlags getChangedProperties() const override; + + // EntityItem related helpers + // methods for getting/setting all properties of an entity + virtual void getProperties(EntityItemProperties& propertiesOut) const override; + + /// returns true if something changed + virtual bool setProperties(const EntityItemProperties& properties) override; + + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + DEFINE_PROPERTY(PROP_BLOOM_INTENSITY, BloomIntensity, bloomIntensity, float, INITIAL_BLOOM_INTENSITY); + DEFINE_PROPERTY(PROP_BLOOM_THRESHOLD, BloomThreshold, bloomThreshold, float, INITIAL_BLOOM_THRESHOLD); + DEFINE_PROPERTY(PROP_BLOOM_SIZE, BloomSize, bloomSize, float, INITIAL_BLOOM_SIZE); + +}; + +#endif // hifi_BloomPropertyGroup_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 1f9bf2eb18..68d0e6aed4 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -37,6 +37,7 @@ AnimationPropertyGroup EntityItemProperties::_staticAnimation; SkyboxPropertyGroup EntityItemProperties::_staticSkybox; HazePropertyGroup EntityItemProperties::_staticHaze; +BloomPropertyGroup EntityItemProperties::_staticBloom; KeyLightPropertyGroup EntityItemProperties::_staticKeyLight; AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight; @@ -84,6 +85,7 @@ void EntityItemProperties::debugDump() const { getHaze().debugDump(); getKeyLight().debugDump(); getAmbientLight().debugDump(); + getBloom().debugDump(); qCDebug(entities) << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); @@ -211,6 +213,10 @@ QString EntityItemProperties::getHazeModeAsString() const { return getComponentModeAsString(_hazeMode); } +QString EntityItemProperties::getBloomModeAsString() const { + return getComponentModeAsString(_bloomMode); +} + QString EntityItemProperties::getComponentModeString(uint32_t mode) { // return "inherit" if mode is not valid if (mode < COMPONENT_MODE_ITEM_COUNT) { @@ -235,6 +241,15 @@ void EntityItemProperties::setHazeModeFromString(const QString& hazeMode) { } } +void EntityItemProperties::setBloomModeFromString(const QString& bloomMode) { + auto result = findComponent(bloomMode); + + if (result != COMPONENT_MODES.end()) { + _bloomMode = result->first; + _bloomModeChanged = true; + } +} + QString EntityItemProperties::getKeyLightModeAsString() const { return getComponentModeAsString(_keyLightMode); } @@ -394,6 +409,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_KEY_LIGHT_MODE, keyLightMode); CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode); CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode); + CHECK_PROPERTY_CHANGE(PROP_BLOOM_MODE, bloomMode); CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); @@ -454,6 +470,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { changedProperties += _ambientLight.getChangedProperties(); changedProperties += _skybox.getChangedProperties(); changedProperties += _haze.getChangedProperties(); + changedProperties += _bloom.getChangedProperties(); return changedProperties; } @@ -1164,6 +1181,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * "enabled": The haze properties of this zone are enabled, overriding the haze from any enclosing zone. * @property {Entities.Haze} haze - The haze properties of the zone. * + * @property {string} bloomMode="inherit" - Configures the bloom in the zone. Possible values:
+ * "inherit": The bloom from any enclosing zone continues into this zone.
+ * "disabled": The bloom from any enclosing zone and the bloom of this zone are disabled in this zone.
+ * "enabled": The bloom properties of this zone are enabled, overriding the bloom from any enclosing zone. + * @property {Entities.Bloom} bloom - The bloom properties of the zone. + * * @property {boolean} flyingAllowed=true - If true then visitors can fly in the zone; otherwise they cannot. * @property {boolean} ghostingAllowed=true - If true then visitors with avatar collisions turned off will not * collide with content in the zone; otherwise visitors will always collide with content in the zone. @@ -1382,6 +1405,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString()); _haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString()); + _bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString()); @@ -1630,6 +1656,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(keyLightMode, KeyLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(bloomMode, BloomMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize); @@ -1662,6 +1689,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool _ambientLight.copyFromScriptValue(object, _defaultSettings); _skybox.copyFromScriptValue(object, _defaultSettings); _haze.copyFromScriptValue(object, _defaultSettings); + _bloom.copyFromScriptValue(object, _defaultSettings); COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL); @@ -1803,6 +1831,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(keyLightMode); COPY_PROPERTY_IF_CHANGED(ambientLightMode); COPY_PROPERTY_IF_CHANGED(skyboxMode); + COPY_PROPERTY_IF_CHANGED(bloomMode); COPY_PROPERTY_IF_CHANGED(sourceUrl); COPY_PROPERTY_IF_CHANGED(voxelVolumeSize); @@ -1825,6 +1854,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { _ambientLight.merge(other._ambientLight); _skybox.merge(other._skybox); _haze.merge(other._haze); + _bloom.merge(other._bloom); COPY_PROPERTY_IF_CHANGED(xTextureURL); COPY_PROPERTY_IF_CHANGED(yTextureURL); @@ -2096,6 +2126,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_RANGE, Haze, haze, HazeKeyLightRange, hazeKeyLightRange); ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_ALTITUDE, Haze, haze, HazeKeyLightAltitude, hazeKeyLightAltitude); + ADD_PROPERTY_TO_MAP(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t); + ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity); + ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold); + ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize); + ADD_PROPERTY_TO_MAP(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t); @@ -2357,6 +2392,10 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy _staticHaze.setProperties(properties); _staticHaze.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode()); + _staticBloom.setProperties(properties); + _staticBloom.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)properties.getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)properties.getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)properties.getSkyboxMode()); @@ -2731,6 +2770,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode); properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode); + properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); @@ -3044,10 +3086,12 @@ void EntityItemProperties::markAllChanged() { _skyboxModeChanged = true; _ambientLightModeChanged = true; _hazeModeChanged = true; + _bloomModeChanged = true; _animation.markAllChanged(); _skybox.markAllChanged(); _haze.markAllChanged(); + _bloom.markAllChanged(); _sourceUrlChanged = true; _voxelVolumeSizeChanged = true; @@ -3442,15 +3486,15 @@ QList EntityItemProperties::listChangedProperties() { if (hazeModeChanged()) { out += "hazeMode"; } - + if (bloomModeChanged()) { + out += "bloomMode"; + } if (keyLightModeChanged()) { out += "keyLightMode"; } - if (ambientLightModeChanged()) { out += "ambientLightMode"; } - if (skyboxModeChanged()) { out += "skyboxMode"; } @@ -3581,6 +3625,7 @@ QList EntityItemProperties::listChangedProperties() { getAmbientLight().listChangedProperties(out); getSkybox().listChangedProperties(out); getHaze().listChangedProperties(out); + getBloom().listChangedProperties(out); return out; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 04e54c54a5..50305345de 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -42,6 +42,7 @@ #include "SimulationOwner.h" #include "SkyboxPropertyGroup.h" #include "HazePropertyGroup.h" +#include "BloomPropertyGroup.h" #include "TextEntityItem.h" #include "ZoneEntityItem.h" @@ -195,9 +196,11 @@ public: DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); + DEFINE_PROPERTY_REF_ENUM(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup); DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup); + DEFINE_PROPERTY_GROUP(Bloom, bloom, BloomPropertyGroup); DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup); DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, ""); DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float, LineEntityItem::DEFAULT_LINE_WIDTH); @@ -533,6 +536,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, KeyLightMode, keyLightMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AmbientLightMode, ambientLightMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, SkyboxMode, skyboxMode, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, BloomMode, bloomMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Cloneable, cloneable, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneLifetime, cloneLifetime, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 156c5d9dd4..3932730661 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -257,6 +257,11 @@ enum EntityPropertyList { PROP_SPIN_SPREAD, PROP_PARTICLE_ROTATE_WITH_ENTITY, + PROP_BLOOM_MODE, + PROP_BLOOM_INTENSITY, + PROP_BLOOM_THRESHOLD, + PROP_BLOOM_SIZE, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index f2550e5d3c..a7dfa1a41e 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -47,33 +47,27 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(en EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class - // Contains a QString property, must be synchronized + // Contain QString properties, must be synchronized withReadLock([&] { _keyLightProperties.getProperties(properties); - }); - - withReadLock([&] { _ambientLightProperties.getProperties(properties); + _skyboxProperties.getProperties(properties); }); + _hazeProperties.getProperties(properties); + _bloomProperties.getProperties(properties); COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL); - // Contains a QString property, must be synchronized - withReadLock([&] { - _skyboxProperties.getProperties(properties); - }); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed); COPY_ENTITY_PROPERTY_TO_PROPERTIES(filterURL, getFilterURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode); - _hazeProperties.getProperties(properties); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightMode, getKeyLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientLightMode, getAmbientLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(skyboxMode, getSkyboxMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(bloomMode, getBloomMode); return properties; } @@ -102,32 +96,27 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie // Contains a QString property, must be synchronized withWriteLock([&] { _keyLightPropertiesChanged = _keyLightProperties.setProperties(properties); - }); - withWriteLock([&] { _ambientLightPropertiesChanged = _ambientLightProperties.setProperties(properties); + _skyboxPropertiesChanged = _skyboxProperties.setProperties(properties); }); + _hazePropertiesChanged = _hazeProperties.setProperties(properties); + _bloomPropertiesChanged = _bloomProperties.setProperties(properties); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); - // Contains a QString property, must be synchronized - withWriteLock([&] { - _skyboxPropertiesChanged = _skyboxProperties.setProperties(properties); - }); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode); - _hazePropertiesChanged = _hazeProperties.setProperties(properties); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightMode, setKeyLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(skyboxMode, setSkyboxMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode); somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged || - _stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged; + _stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged; return somethingChanged; } @@ -139,54 +128,67 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - int bytesFromKeylight; - withWriteLock([&] { - bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _keyLightPropertiesChanged); - }); + { + int bytesFromKeylight; + withWriteLock([&] { + bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _keyLightPropertiesChanged); + }); + somethingChanged = somethingChanged || _keyLightPropertiesChanged; + bytesRead += bytesFromKeylight; + dataAt += bytesFromKeylight; + } - somethingChanged = somethingChanged || _keyLightPropertiesChanged; - bytesRead += bytesFromKeylight; - dataAt += bytesFromKeylight; + { + int bytesFromAmbientlight; + withWriteLock([&] { + bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged); + }); + somethingChanged = somethingChanged || _ambientLightPropertiesChanged; + bytesRead += bytesFromAmbientlight; + dataAt += bytesFromAmbientlight; + } - int bytesFromAmbientlight; - withWriteLock([&] { - bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged); - }); + { + int bytesFromSkybox; + withWriteLock([&] { + bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _skyboxPropertiesChanged); + }); + somethingChanged = somethingChanged || _skyboxPropertiesChanged; + bytesRead += bytesFromSkybox; + dataAt += bytesFromSkybox; + } - somethingChanged = somethingChanged || _ambientLightPropertiesChanged; - bytesRead += bytesFromAmbientlight; - dataAt += bytesFromAmbientlight; + { + int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _hazePropertiesChanged); + somethingChanged = somethingChanged || _hazePropertiesChanged; + bytesRead += bytesFromHaze; + dataAt += bytesFromHaze; + } + + { + int bytesFromBloom = _bloomProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, _bloomPropertiesChanged); + somethingChanged = somethingChanged || _bloomPropertiesChanged; + bytesRead += bytesFromBloom; + dataAt += bytesFromBloom; + } READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - int bytesFromSkybox; - withWriteLock([&] { - bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _skyboxPropertiesChanged); - }); - somethingChanged = somethingChanged || _skyboxPropertiesChanged; - bytesRead += bytesFromSkybox; - dataAt += bytesFromSkybox; - READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed); READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed); READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL); READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode); - - int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _hazePropertiesChanged); - - somethingChanged = somethingChanged || _hazePropertiesChanged; - bytesRead += bytesFromHaze; - dataAt += bytesFromHaze; - READ_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); + READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode); return bytesRead; } @@ -196,29 +198,24 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p withReadLock([&] { requestedProperties += _keyLightProperties.getEntityProperties(params); - }); - - withReadLock([&] { requestedProperties += _ambientLightProperties.getEntityProperties(params); + requestedProperties += _skyboxProperties.getEntityProperties(params); }); + requestedProperties += _hazeProperties.getEntityProperties(params); + requestedProperties += _bloomProperties.getEntityProperties(params); requestedProperties += PROP_SHAPE_TYPE; requestedProperties += PROP_COMPOUND_SHAPE_URL; - withReadLock([&] { - requestedProperties += _skyboxProperties.getEntityProperties(params); - }); - requestedProperties += PROP_FLYING_ALLOWED; requestedProperties += PROP_GHOSTING_ALLOWED; requestedProperties += PROP_FILTER_URL; requestedProperties += PROP_HAZE_MODE; - requestedProperties += _hazeProperties.getEntityProperties(params); - requestedProperties += PROP_KEY_LIGHT_MODE; requestedProperties += PROP_AMBIENT_LIGHT_MODE; requestedProperties += PROP_SKYBOX_MODE; + requestedProperties += PROP_BLOOM_MODE; return requestedProperties; } @@ -235,44 +232,46 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits _keyLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - _ambientLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + _hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + _bloomProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL()); - _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed()); APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed()); APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL()); APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode()); - _hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)getSkyboxMode()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode()); } void ZoneEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); - qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeString(_hazeMode); - qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode); - qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode); - qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode); + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeString(_hazeMode); + qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode); + qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode); + qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode); + qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeString(_bloomMode); _keyLightProperties.debugDump(); _ambientLightProperties.debugDump(); _skyboxProperties.debugDump(); _hazeProperties.debugDump(); + _bloomProperties.debugDump(); } ShapeType ZoneEntityItem::getShapeType() const { @@ -344,6 +343,7 @@ void ZoneEntityItem::resetRenderingPropertiesChanged() { _ambientLightPropertiesChanged = false; _skyboxPropertiesChanged = false; _hazePropertiesChanged = false; + _bloomPropertiesChanged = false; _stagePropertiesChanged = false; }); } @@ -359,6 +359,17 @@ uint32_t ZoneEntityItem::getHazeMode() const { return _hazeMode; } +void ZoneEntityItem::setBloomMode(const uint32_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _bloomMode) { + _bloomMode = value; + _bloomPropertiesChanged = true; + } +} + +uint32_t ZoneEntityItem::getBloomMode() const { + return _bloomMode; +} + void ZoneEntityItem::setKeyLightMode(const uint32_t value) { if (value < COMPONENT_MODE_ITEM_COUNT && value != _keyLightMode) { _keyLightMode = value; diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 0aaa32a57a..e2ebf16f11 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -18,6 +18,7 @@ #include "EntityTree.h" #include "SkyboxPropertyGroup.h" #include "HazePropertyGroup.h" +#include "BloomPropertyGroup.h" #include class ZoneEntityItem : public EntityItem { @@ -79,9 +80,13 @@ public: void setSkyboxMode(uint32_t value); uint32_t getSkyboxMode() const; + void setBloomMode(const uint32_t value); + uint32_t getBloomMode() const; + SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock([&] { return _skyboxProperties; }); } const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; } + const BloomPropertyGroup& getBloomProperties() const { return _bloomProperties; } bool getFlyingAllowed() const { return _flyingAllowed; } void setFlyingAllowed(bool value) { _flyingAllowed = value; } @@ -93,10 +98,8 @@ public: bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; } bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; } bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; } - - bool hazePropertiesChanged() const { - return _hazePropertiesChanged; - } + bool hazePropertiesChanged() const { return _hazePropertiesChanged; } + bool bloomPropertiesChanged() const { return _bloomPropertiesChanged; } bool stagePropertiesChanged() const { return _stagePropertiesChanged; } @@ -133,9 +136,11 @@ protected: uint32_t _ambientLightMode { COMPONENT_MODE_INHERIT }; uint32_t _hazeMode { COMPONENT_MODE_INHERIT }; + uint32_t _bloomMode { COMPONENT_MODE_INHERIT }; SkyboxPropertyGroup _skyboxProperties; HazePropertyGroup _hazeProperties; + BloomPropertyGroup _bloomProperties; bool _flyingAllowed { DEFAULT_FLYING_ALLOWED }; bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED }; @@ -146,6 +151,7 @@ protected: bool _ambientLightPropertiesChanged { false }; bool _skyboxPropertiesChanged { false }; bool _hazePropertiesChanged{ false }; + bool _bloomPropertiesChanged { false }; bool _stagePropertiesChanged { false }; static bool _drawZoneBoundaries; diff --git a/libraries/graphics/src/graphics/Bloom.cpp b/libraries/graphics/src/graphics/Bloom.cpp new file mode 100644 index 0000000000..f8dcda3292 --- /dev/null +++ b/libraries/graphics/src/graphics/Bloom.cpp @@ -0,0 +1,18 @@ +// +// Bloom.cpp +// libraries/graphics/src/graphics +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Bloom.h" + +using namespace graphics; + +const float Bloom::INITIAL_BLOOM_INTENSITY { 0.25f }; +const float Bloom::INITIAL_BLOOM_THRESHOLD { 0.7f }; +const float Bloom::INITIAL_BLOOM_SIZE { 0.9f }; \ No newline at end of file diff --git a/libraries/graphics/src/graphics/Bloom.h b/libraries/graphics/src/graphics/Bloom.h new file mode 100644 index 0000000000..02362ce25d --- /dev/null +++ b/libraries/graphics/src/graphics/Bloom.h @@ -0,0 +1,44 @@ +// +// Bloom.h +// libraries/graphics/src/graphics +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_model_Bloom_h +#define hifi_model_Bloom_h + +#include + +namespace graphics { + class Bloom { + public: + // Initial values + static const float INITIAL_BLOOM_INTENSITY; + static const float INITIAL_BLOOM_THRESHOLD; + static const float INITIAL_BLOOM_SIZE; + + Bloom() {} + + void setBloomIntensity(const float bloomIntensity) { _bloomIntensity = bloomIntensity; } + void setBloomThreshold(const float bloomThreshold) { _bloomThreshold = bloomThreshold; } + void setBloomSize(const float bloomSize) { _bloomSize = bloomSize; } + void setBloomActive(const bool isBloomActive) { _isBloomActive = isBloomActive; } + + float getBloomIntensity() { return _bloomIntensity; } + float getBloomThreshold() { return _bloomThreshold; } + float getBloomSize() { return _bloomSize; } + bool getBloomActive() { return _isBloomActive; } + + private: + bool _isBloomActive { false }; + float _bloomIntensity { INITIAL_BLOOM_INTENSITY }; + float _bloomThreshold {INITIAL_BLOOM_THRESHOLD }; + float _bloomSize { INITIAL_BLOOM_SIZE }; + }; + using BloomPointer = std::shared_ptr; +} +#endif // hifi_model_Bloom_h diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 82e9820509..ae165af5d1 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::ParticleSpin); + return static_cast(EntityVersion::BloomEffect); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 64c5bfe534..bfc92b9bde 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -240,7 +240,8 @@ enum class EntityVersion : PacketVersion { CollisionMask16Bytes, YieldSimulationOwnership, ParticleEntityFix, - ParticleSpin + ParticleSpin, + BloomEffect }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 2a9a9b3850..bd1f0fa9d2 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -25,11 +25,7 @@ BloomThreshold::BloomThreshold(unsigned int downsamplingFactor) { _parameters.edit()._sampleCount = downsamplingFactor; } -void BloomThreshold::configure(const Config& config) { - if (_parameters.get()._threshold != config.threshold) { - _parameters.edit()._threshold = config.threshold; - } -} +void BloomThreshold::configure(const Config& config) {} void BloomThreshold::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); @@ -39,6 +35,7 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons const auto frameTransform = inputs.get0(); const auto inputFrameBuffer = inputs.get1(); + const auto bloom = inputs.get2(); assert(inputFrameBuffer->hasColor()); @@ -68,6 +65,28 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y }; + if (!bloom || !bloom->getBloomActive()) { + outputs = _outputBuffer; + return; + } + + _parameters.edit()._threshold = bloom->getBloomThreshold(); + auto sigma = 0.5f + bloom->getBloomSize() * 3.5f; + + //{ + // std::string blurName { "BloomBlurN" }; + // auto task = static_cast(this); + + // for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { + // blurName.back() = '0' + i; + // auto blurJobIt = task->editJob(blurName); + // assert(blurJobIt != task->_jobs.end()); + // auto& gaussianBlur = blurJobIt->edit(); + // auto gaussianBlurParams = gaussianBlur.getParameters(); + // gaussianBlurParams->setFilterGaussianTaps(9, sigma); + // } + //} + gpu::doInBatch("BloomThreshold::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); @@ -90,16 +109,7 @@ BloomApply::BloomApply() { } -void BloomApply::configure(const Config& config) { - const auto newIntensity = config.intensity / 3.0f; - - if (_parameters.get()._intensities.x != newIntensity) { - auto& parameters = _parameters.edit(); - parameters._intensities.x = newIntensity; - parameters._intensities.y = newIntensity; - parameters._intensities.z = newIntensity; - } -} +void BloomApply::configure(const Config& config) {} void BloomApply::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { assert(renderContext->args); @@ -123,8 +133,19 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In const auto blur0FB = inputs.get1(); const auto blur1FB = inputs.get2(); const auto blur2FB = inputs.get3(); + const auto bloom = inputs.get4(); const glm::ivec4 viewport{ 0, 0, framebufferSize.x, framebufferSize.y }; + if (!bloom || !bloom->getBloomActive()) { + return; + } + + const auto newIntensity = bloom->getBloomIntensity() / 3.0f; + auto& parameters = _parameters.edit(); + parameters._intensities.x = newIntensity; + parameters._intensities.y = newIntensity; + parameters._intensities.z = newIntensity; + gpu::doInBatch("BloomApply::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); @@ -266,43 +287,9 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In }); } -void BloomConfig::setIntensity(float value) { - auto task = static_cast(_task); - auto blurJobIt = task->editJob("BloomApply"); - assert(blurJobIt != task->_jobs.end()); - blurJobIt->getConfiguration()->setProperty("intensity", value); -} +BloomEffect::BloomEffect() {} -float BloomConfig::getIntensity() const { - auto task = static_cast(_task); - auto blurJobIt = task->getJob("BloomApply"); - assert(blurJobIt != task->_jobs.end()); - return blurJobIt->getConfiguration()->property("intensity").toFloat(); -} - -void BloomConfig::setSize(float value) { - std::string blurName{ "BloomBlurN" }; - auto sigma = 0.5f+value*3.5f; - auto task = static_cast(_task); - - for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { - blurName.back() = '0' + i; - auto blurJobIt = task->editJob(blurName); - assert(blurJobIt != task->_jobs.end()); - auto& gaussianBlur = blurJobIt->edit(); - auto gaussianBlurParams = gaussianBlur.getParameters(); - gaussianBlurParams->setFilterGaussianTaps(9, sigma); - } - auto blurJobIt = task->getJob("BloomApply"); - assert(blurJobIt != task->_jobs.end()); - blurJobIt->getConfiguration()->setProperty("sigma", sigma); -} - -Bloom::Bloom() { - -} - -void Bloom::configure(const Config& config) { +void BloomEffect::configure(const Config& config) { std::string blurName{ "BloomBlurN" }; for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { @@ -312,7 +299,7 @@ void Bloom::configure(const Config& config) { } } -void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { +void BloomEffect::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { // Start by computing threshold of color buffer input at quarter resolution const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs, 4U); @@ -325,7 +312,7 @@ void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying const auto& frameBuffer = input[1]; // Mix all blur levels at quarter resolution - const auto applyInput = BloomApply::Inputs(bloomInputBuffer, blurFB0, blurFB1, blurFB2).asVarying(); + const auto applyInput = BloomApply::Inputs(bloomInputBuffer, blurFB0, blurFB1, blurFB2, input[2]).asVarying(); task.addJob("BloomApply", applyInput); // And then blend result in additive manner on top of final color buffer const auto drawInput = BloomDraw::Inputs(frameBuffer, bloomInputBuffer).asVarying(); diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index 04cb4a9474..150a134dac 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -14,42 +14,21 @@ #include +#include "graphics/Bloom.h" + #include "DeferredFrameTransform.h" class BloomConfig : public render::Task::Config { Q_OBJECT - Q_PROPERTY(float intensity READ getIntensity WRITE setIntensity NOTIFY dirty) - Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty) - -public: - - BloomConfig() : render::Task::Config(false) {} - - float size{ 0.7f }; - - void setIntensity(float value); - float getIntensity() const; - void setSize(float value); - -signals: - void dirty(); }; class BloomThresholdConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty) - -public: - - float threshold{ 0.9f }; - -signals: - void dirty(); }; class BloomThreshold { public: - using Inputs = render::VaryingSet2; + using Inputs = render::VaryingSet3; using Outputs = gpu::FramebufferPointer; using Config = BloomThresholdConfig; using JobModel = render::Job::ModelIO; @@ -71,21 +50,11 @@ private: class BloomApplyConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(float intensity MEMBER intensity NOTIFY dirty) - Q_PROPERTY(float sigma MEMBER sigma NOTIFY dirty) - -public: - - float intensity{ 0.25f }; - float sigma{ 1.0f }; - -signals: - void dirty(); }; class BloomApply { public: - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet5; using Config = BloomApplyConfig; using JobModel = render::Job::ModelI; @@ -118,7 +87,7 @@ private: class DebugBloomConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(int mode MEMBER mode NOTIFY dirty) + Q_PROPERTY(int mode MEMBER mode NOTIFY dirty) public: @@ -155,13 +124,13 @@ private: DebugBloomConfig::Mode _mode; }; -class Bloom { +class BloomEffect { public: - using Inputs = render::VaryingSet2; + using Inputs = render::VaryingSet3; using Config = BloomConfig; - using JobModel = render::Task::ModelI; + using JobModel = render::Task::ModelI; - Bloom(); + BloomEffect(); void configure(const Config& config); void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); diff --git a/libraries/render-utils/src/BloomStage.cpp b/libraries/render-utils/src/BloomStage.cpp new file mode 100644 index 0000000000..9a1c8ee183 --- /dev/null +++ b/libraries/render-utils/src/BloomStage.cpp @@ -0,0 +1,80 @@ +// +// BloomStage.cpp +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "BloomStage.h" + +#include "DeferredLightingEffect.h" + +#include + +std::string BloomStage::_stageName { "BLOOM_STAGE"}; +const BloomStage::Index BloomStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; + +FetchBloomStage::FetchBloomStage() { + _bloom = std::make_shared(); +} + +void FetchBloomStage::configure(const Config& config) { + _bloom->setBloomIntensity(config.bloomIntensity); + _bloom->setBloomThreshold(config.bloomThreshold); + _bloom->setBloomSize(config.bloomSize); + _bloom->setBloomActive(config.isBloomActive); +} + +BloomStage::Index BloomStage::findBloom(const BloomPointer& bloom) const { + auto found = _bloomMap.find(bloom); + if (found != _bloomMap.end()) { + return INVALID_INDEX; + } else { + return (*found).second; + } +} + +BloomStage::Index BloomStage::addBloom(const BloomPointer& bloom) { + auto found = _bloomMap.find(bloom); + if (found == _bloomMap.end()) { + auto bloomId = _blooms.newElement(bloom); + // Avoid failing to allocate a bloom, just pass + if (bloomId != INVALID_INDEX) { + // Insert the bloom and its index in the reverse map + _bloomMap.insert(BloomMap::value_type(bloom, bloomId)); + } + return bloomId; + } else { + return (*found).second; + } +} + +BloomStage::BloomPointer BloomStage::removeBloom(Index index) { + BloomPointer removed = _blooms.freeElement(index); + if (removed) { + _bloomMap.erase(removed); + } + return removed; +} + +BloomStageSetup::BloomStageSetup() {} + +void BloomStageSetup::run(const render::RenderContextPointer& renderContext) { + auto stage = renderContext->_scene->getStage(BloomStage::getName()); + if (!stage) { + renderContext->_scene->resetStage(BloomStage::getName(), std::make_shared()); + } +} + +void FetchBloomStage::run(const render::RenderContextPointer& renderContext, graphics::BloomPointer& bloom) { + auto bloomStage = renderContext->_scene->getStage(); + assert(bloomStage); + + bloom = nullptr; + if (bloomStage->_currentFrame._blooms.size() != 0) { + auto bloomId = bloomStage->_currentFrame._blooms.front(); + bloom = bloomStage->getBloom(bloomId); + } +} diff --git a/libraries/render-utils/src/BloomStage.h b/libraries/render-utils/src/BloomStage.h new file mode 100644 index 0000000000..76829a19a6 --- /dev/null +++ b/libraries/render-utils/src/BloomStage.h @@ -0,0 +1,122 @@ +// +// BloomStage.h + +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_render_utils_BloomStage_h +#define hifi_render_utils_BloomStage_h + +#include +#include +#include +#include +#include + +#include +#include +#include + +// Bloom stage to set up bloom-related rendering tasks +class BloomStage : public render::Stage { +public: + static std::string _stageName; + static const std::string& getName() { return _stageName; } + + using Index = render::indexed_container::Index; + static const Index INVALID_INDEX; + static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } + + using BloomPointer = graphics::BloomPointer; + using Blooms = render::indexed_container::IndexedPointerVector; + using BloomMap = std::unordered_map; + + using BloomIndices = std::vector; + + Index findBloom(const BloomPointer& bloom) const; + Index addBloom(const BloomPointer& bloom); + + BloomPointer removeBloom(Index index); + + bool checkBloomId(Index index) const { return _blooms.checkIndex(index); } + + Index getNumBlooms() const { return _blooms.getNumElements(); } + Index getNumFreeBlooms() const { return _blooms.getNumFreeIndices(); } + Index getNumAllocatedBlooms() const { return _blooms.getNumAllocatedIndices(); } + + BloomPointer getBloom(Index bloomId) const { + return _blooms.get(bloomId); + } + + Blooms _blooms; + BloomMap _bloomMap; + + class Frame { + public: + Frame() {} + + void clear() { _blooms.clear(); } + + void pushBloom(BloomStage::Index index) { _blooms.emplace_back(index); } + + BloomStage::BloomIndices _blooms; + }; + + Frame _currentFrame; +}; +using BloomStagePointer = std::shared_ptr; + +class BloomStageSetup { +public: + using JobModel = render::Job::Model; + + BloomStageSetup(); + void run(const render::RenderContextPointer& renderContext); + +protected: +}; + +class FetchBloomConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(float bloomIntensity MEMBER bloomIntensity WRITE setBloomIntensity NOTIFY dirty); + Q_PROPERTY(float bloomThreshold MEMBER bloomThreshold WRITE setBloomThreshold NOTIFY dirty); + Q_PROPERTY(float bloomSize MEMBER bloomSize WRITE setBloomSize NOTIFY dirty); + Q_PROPERTY(bool isBloomActive MEMBER isBloomActive WRITE setBloomActive NOTIFY dirty); + +public: + FetchBloomConfig() : render::Job::Config() {} + + float bloomIntensity { graphics::Bloom::INITIAL_BLOOM_INTENSITY }; + float bloomThreshold { graphics::Bloom::INITIAL_BLOOM_THRESHOLD }; + float bloomSize { graphics::Bloom::INITIAL_BLOOM_SIZE }; + + bool isBloomActive { false }; + +public slots: + void setBloomIntensity(const float value) { bloomIntensity = value; emit dirty(); } + void setBloomThreshold(const float value) { bloomThreshold = value; emit dirty(); } + void setBloomSize(const float value) { bloomSize = value; emit dirty(); } + void setBloomActive(const bool active) { isBloomActive = active; emit dirty(); } + +signals: + void dirty(); +}; + +class FetchBloomStage { +public: + using Config = FetchBloomConfig; + using JobModel = render::Job::ModelO; + + FetchBloomStage(); + + void configure(const Config& config); + void run(const render::RenderContextPointer& renderContext, graphics::BloomPointer& bloom); + +private: + graphics::BloomPointer _bloom; +}; +#endif diff --git a/libraries/render-utils/src/HazeStage.h b/libraries/render-utils/src/HazeStage.h index 8f137cb280..b48168e376 100644 --- a/libraries/render-utils/src/HazeStage.h +++ b/libraries/render-utils/src/HazeStage.h @@ -163,6 +163,5 @@ public: private: graphics::HazePointer _haze; - gpu::PipelinePointer _hazePipeline; }; #endif diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 59c86acd19..49851524cd 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -45,6 +45,7 @@ #include "TextureCache.h" #include "ZoneRenderer.h" #include "FadeEffect.h" +#include "BloomStage.h" #include "RenderUtilsLogging.h" #include "AmbientOcclusionEffect.h" @@ -171,7 +172,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto velocityBufferOutputs = task.addJob("VelocityBuffer", velocityBufferInputs); const auto velocityBuffer = velocityBufferOutputs.getN(0); - // Clear Light, Haze and Skybox Stages and render zones from the general metas bucket + // Clear Light, Haze, Bloom, and Skybox Stages and render zones from the general metas bucket const auto zones = task.addJob("ZoneRenderer", metas); // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. @@ -184,6 +185,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Add haze model const auto hazeModel = task.addJob("HazeModel"); + // Add Bloom model + const auto bloomModel = task.addJob("BloomModel"); // DeferredBuffer is complete, now let's shade it into the LightingBuffer const auto deferredLightingInputs = RenderDeferred::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, @@ -240,8 +243,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("Antialiasing", antialiasingInputs); // Add bloom - const auto bloomInputs = Bloom::Inputs(deferredFrameTransform, lightingFramebuffer).asVarying(); - task.addJob("Bloom", bloomInputs); + const auto bloomInputs = BloomEffect::Inputs(deferredFrameTransform, lightingFramebuffer, bloomModel).asVarying(); + task.addJob("Bloom", bloomInputs); // Lighting Buffer ready for tone mapping const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, scaledPrimaryFramebuffer).asVarying(); diff --git a/libraries/render-utils/src/UpdateSceneTask.cpp b/libraries/render-utils/src/UpdateSceneTask.cpp index e05f28ef0d..be61953073 100644 --- a/libraries/render-utils/src/UpdateSceneTask.cpp +++ b/libraries/render-utils/src/UpdateSceneTask.cpp @@ -14,6 +14,7 @@ #include "LightStage.h" #include "BackgroundStage.h" #include "HazeStage.h" +#include "BloomStage.h" #include #include #include "DeferredLightingEffect.h" @@ -22,6 +23,7 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render task.addJob("LightStageSetup"); task.addJob("BackgroundStageSetup"); task.addJob("HazeStageSetup"); + task.addJob("BloomStageSetup"); task.addJob("TransitionStageSetup"); task.addJob("HighlightStageSetup"); diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index 3299b0c41c..d85818a21a 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -21,11 +21,12 @@ #include "StencilMaskPass.h" #include "DeferredLightingEffect.h" - #include "render-utils/ShaderConstants.h" #include "StencilMaskPass.h" #include "DeferredLightingEffect.h" +#include "BloomStage.h" + namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; @@ -63,7 +64,7 @@ void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& oupu } void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) { - // Grab light, background and haze stages and clear them + // Grab light, background, haze, and bloom stages and clear them auto lightStage = context->_scene->getStage(); assert(lightStage); lightStage->_currentFrame.clear(); @@ -76,6 +77,10 @@ void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) assert(hazeStage); hazeStage->_currentFrame.clear(); + auto bloomStage = context->_scene->getStage(); + assert(bloomStage); + bloomStage->_currentFrame.clear(); + // call render over the zones to grab their components in the correct order first... render::renderItems(context, inputs); @@ -84,6 +89,7 @@ void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) lightStage->_currentFrame.pushAmbientLight(lightStage->getDefaultLight()); backgroundStage->_currentFrame.pushBackground(0); hazeStage->_currentFrame.pushHaze(0); + bloomStage->_currentFrame.pushBloom(0); } const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() { diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 9614f8b8fe..744150253d 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -678,6 +678,52 @@
+
+ + Bloom + +
+ Inherit + Off + On +
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index d2cea2d394..43ea6bf22f 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -839,7 +839,7 @@ function loaded() { var elZoneHazeModeInherit = document.getElementById("property-zone-haze-mode-inherit"); var elZoneHazeModeDisabled = document.getElementById("property-zone-haze-mode-disabled"); var elZoneHazeModeEnabled = document.getElementById("property-zone-haze-mode-enabled"); - + var elZoneHazeRange = document.getElementById("property-zone-haze-range"); var elZoneHazeColor = document.getElementById("property-zone-haze-color"); var elZoneHazeColorRed = document.getElementById("property-zone-haze-color-red"); @@ -858,6 +858,15 @@ function loaded() { var elZoneHazeBackgroundBlend = document.getElementById("property-zone-haze-background-blend"); + // Bloom + var elZoneBloomModeInherit = document.getElementById("property-zone-bloom-mode-inherit"); + var elZoneBloomModeDisabled = document.getElementById("property-zone-bloom-mode-disabled"); + var elZoneBloomModeEnabled = document.getElementById("property-zone-bloom-mode-enabled"); + + var elZoneBloomIntensity = document.getElementById("property-zone-bloom-intensity"); + var elZoneBloomThreshold = document.getElementById("property-zone-bloom-threshold"); + var elZoneBloomSize = document.getElementById("property-zone-bloom-size"); + var elZoneSkyboxColor = document.getElementById("property-zone-skybox-color"); var elZoneSkyboxColorRed = document.getElementById("property-zone-skybox-color-red"); var elZoneSkyboxColorGreen = document.getElementById("property-zone-skybox-color-green"); @@ -914,19 +923,19 @@ function loaded() { deleteJSONMaterialEditor(); } } - + elTypeIcon.style.display = "none"; elType.innerHTML = "No selection"; elPropertiesList.className = ''; - + elID.value = ""; elName.value = ""; elLocked.checked = false; elVisible.checked = false; - + elParentID.value = ""; elParentJointIndex.value = ""; - + elColorRed.value = ""; elColorGreen.value = ""; elColorBlue.value = ""; @@ -935,15 +944,15 @@ function loaded() { elPositionX.value = ""; elPositionY.value = ""; elPositionZ.value = ""; - + elRotationX.value = ""; elRotationY.value = ""; elRotationZ.value = ""; - + elDimensionsX.value = ""; elDimensionsY.value = ""; elDimensionsZ.value = ""; - + elRegistrationX.value = ""; elRegistrationY.value = ""; elRegistrationZ.value = ""; @@ -965,14 +974,14 @@ function loaded() { elAccelerationX.value = ""; elAccelerationY.value = ""; elAccelerationZ.value = ""; - + elRestitution.value = ""; elFriction.value = ""; elDensity.value = ""; - + elCollisionless.checked = false; elDynamic.checked = false; - + elCollideStatic.checked = false; elCollideKinematic.checked = false; elCollideDynamic.checked = false; @@ -989,27 +998,27 @@ function loaded() { elCloneableGroup.style.display = "none"; elCloneableLimit.value = ""; elCloneableLifetime.value = ""; - - showElements(document.getElementsByClassName('can-cast-shadow-section'), true); + + showElements(document.getElementsByClassName('can-cast-shadow-section'), true); elCanCastShadow.checked = false; - + elCollisionSoundURL.value = ""; elLifetime.value = ""; elScriptURL.value = ""; elServerScripts.value = ""; elHyperlinkHref.value = ""; elDescription.value = ""; - + deleteJSONEditor(); elUserData.value = ""; showUserDataTextArea(); showSaveUserDataButton(); showNewJSONEditorButton(); - + // Shape Properties elShape.value = "Cube"; setDropdownText(elShape); - + // Light Properties elLightSpotLight.checked = false; elLightColor.style.backgroundColor = "rgb(" + 0 + "," + 0 + "," + 0 + ")"; @@ -1020,7 +1029,7 @@ function loaded() { elLightFalloffRadius.value = ""; elLightExponent.value = ""; elLightCutoff.value = ""; - + // Model Properties elModelURL.value = ""; elCompoundShapeURL.value = ""; @@ -1037,7 +1046,7 @@ function loaded() { elModelAnimationAllowTranslation.checked = false; elModelTextures.value = ""; elModelOriginalTextures.value = ""; - + // Zone Properties elZoneFlyingAllowed.checked = false; elZoneGhostingAllowed.checked = false; @@ -1067,6 +1076,9 @@ function loaded() { elZoneHazeAltitudeEffect.checked = false; elZoneHazeBaseRef.value = ""; elZoneHazeCeiling.value = ""; + elZoneBloomIntensity.value = ""; + elZoneBloomThreshold.value = ""; + elZoneBloomSize.value = ""; elZoneSkyboxColor.style.backgroundColor = "rgb(" + 0 + "," + 0 + "," + 0 + ")"; elZoneSkyboxColorRed.value = ""; elZoneSkyboxColorGreen.value = ""; @@ -1076,7 +1088,8 @@ function loaded() { showElements(document.getElementsByClassName('skybox-section'), true); showElements(document.getElementsByClassName('ambient-section'), true); showElements(document.getElementsByClassName('haze-section'), true); - + showElements(document.getElementsByClassName('bloom-section'), true); + // Text Properties elTextText.value = ""; elTextLineHeight.value = ""; @@ -1089,14 +1102,14 @@ function loaded() { elTextBackgroundColorRed.value = ""; elTextBackgroundColorGreen.value = ""; elTextBackgroundColorBlue.value = ""; - + // Image Properties elImageURL.value = ""; - + // Web Properties elWebSourceURL.value = ""; elWebDPI.value = ""; - + // Material Properties elMaterialURL.value = ""; elParentMaterialNameNumber.value = ""; @@ -1107,13 +1120,13 @@ function loaded() { elMaterialMappingScaleX.value = ""; elMaterialMappingScaleY.value = ""; elMaterialMappingRot.value = ""; - + deleteJSONMaterialEditor(); elMaterialData.value = ""; showMaterialDataTextArea(); showSaveMaterialDataButton(); showNewJSONMaterialEditorButton(); - + disableProperties(); } else if (data.selections.length > 1) { deleteJSONEditor(); @@ -1250,7 +1263,7 @@ function loaded() { elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; elCloneableLimit.value = properties.cloneLimit; elCloneableLifetime.value = properties.cloneLifetime; - + var grabbablesSet = false; var parsedUserData = {}; try { @@ -1476,6 +1489,14 @@ function loaded() { elZoneHazeBaseRef.value = properties.haze.hazeBaseRef.toFixed(0); elZoneHazeCeiling.value = properties.haze.hazeCeiling.toFixed(0); + elZoneBloomModeInherit.checked = (properties.bloomMode === 'inherit'); + elZoneBloomModeDisabled.checked = (properties.bloomMode === 'disabled'); + elZoneBloomModeEnabled.checked = (properties.bloomMode === 'enabled'); + + elZoneBloomIntensity.value = properties.bloom.bloomIntensity.toFixed(2); + elZoneBloomThreshold.value = properties.bloom.bloomThreshold.toFixed(2); + elZoneBloomSize.value = properties.bloom.bloomSize.toFixed(2); + elShapeType.value = properties.shapeType; elCompoundShapeURL.value = properties.compoundShapeURL; @@ -1502,6 +1523,9 @@ function loaded() { showElements(document.getElementsByClassName('haze-section'), elZoneHazeModeEnabled.checked); + + showElements(document.getElementsByClassName('bloom-section'), + elZoneBloomModeEnabled.checked); } else if (properties.type === "PolyVox") { elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2); elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2); @@ -2067,6 +2091,18 @@ function loaded() { elZoneHazeBackgroundBlend.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeBackgroundBlend')); + // Bloom + var bloomModeChanged = createZoneComponentModeChangedFunction('bloomMode', + elZoneBloomModeInherit, elZoneBloomModeDisabled, elZoneBloomModeEnabled); + + elZoneBloomModeInherit.addEventListener('change', bloomModeChanged); + elZoneBloomModeDisabled.addEventListener('change', bloomModeChanged); + elZoneBloomModeEnabled.addEventListener('change', bloomModeChanged); + + elZoneBloomIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomIntensity')); + elZoneBloomThreshold.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomThreshold')); + elZoneBloomSize.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomSize')); + var zoneSkyboxColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('skybox', 'color', elZoneSkyboxColorRed, elZoneSkyboxColorGreen, elZoneSkyboxColorBlue); elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction); From 05ff99a1d2f2f0aa8387bd505d665de26bc58519 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 9 Aug 2018 18:39:19 -0700 Subject: [PATCH 04/23] working on blendshapes --- interface/src/avatar/AvatarManager.cpp | 4 +- .../render-utils/src/CauterizedModel.cpp | 5 ++ .../render-utils/src/MeshPartPayload.cpp | 5 +- libraries/render-utils/src/Model.cpp | 54 +++++-------------- libraries/render-utils/src/Model.h | 2 +- 5 files changed, 26 insertions(+), 44 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index dbafd06611..efd1c103d9 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -353,15 +353,14 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { QReadLocker locker(&_hashLock); QVector::iterator avatarItr = _avatarsToFade.begin(); const render::ScenePointer& scene = qApp->getMain3DScene(); + render::Transaction transaction; while (avatarItr != _avatarsToFade.end()) { auto avatar = std::static_pointer_cast(*avatarItr); avatar->updateFadingStatus(scene); if (!avatar->isFading()) { // fading to zero is such a rare event we push a unique transaction for each if (avatar->isInScene()) { - render::Transaction transaction; avatar->removeFromScene(*avatarItr, scene, transaction); - scene->enqueueTransaction(transaction); } avatarItr = _avatarsToFade.erase(avatarItr); } else { @@ -370,6 +369,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { ++avatarItr; } } + scene->enqueueTransaction(transaction); } AvatarSharedPointer AvatarManager::newSharedAvatar() { diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 80a9c5ccae..ba394b8b2f 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -75,6 +75,7 @@ void CauterizedModel::createRenderItemSet() { // Run through all of the meshes, and place them into their segregated, but unsorted buckets int shapeID = 0; + const FBXGeometry& fbxGeometry = getFBXGeometry(); uint32_t numMeshes = (uint32_t)meshes.size(); for (uint32_t i = 0; i < numMeshes; i++) { const auto& mesh = meshes.at(i); @@ -85,6 +86,10 @@ void CauterizedModel::createRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { + if (!fbxGeometry.meshes[i].blendshapes.empty()) { + _blendedVertexBuffers[i] = std::make_shared(); + _blendedVertexBuffers[i]->resize(fbxGeometry.meshes[i].vertices.size() * (sizeof(glm::vec3) + 2 * sizeof(NormalType))); + } auto ptr = std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::static_pointer_cast(ptr); auto material = getGeometry()->getShapeMaterial(shapeID); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index ca6e736a65..58f4f170a0 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -208,7 +208,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning(); - _blendedVertexBuffer = model->_blendedVertexBuffers[_meshIndex]; + auto blendedVertexBuffer = model->_blendedVertexBuffers.find(_meshIndex); + if (blendedVertexBuffer != model->_blendedVertexBuffers.end()) { + _blendedVertexBuffer = blendedVertexBuffer->second; + } auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); const Model::MeshState& state = model->getMeshState(_meshIndex); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ba0d714f7a..f92a6809f3 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -305,36 +305,6 @@ bool Model::updateGeometry() { state.clusterDualQuaternions.resize(mesh.clusters.size()); state.clusterMatrices.resize(mesh.clusters.size()); _meshStates.push_back(state); - - // Note: we add empty buffers for meshes that lack blendshapes so we can access the buffers by index - // later in ModelMeshPayload, however the vast majority of meshes will not have them. - // TODO? make _blendedVertexBuffers a map instead of vector and only add for meshes with blendshapes? - auto buffer = std::make_shared(); - if (!mesh.blendshapes.isEmpty()) { - std::vector normalsAndTangents; - normalsAndTangents.reserve(mesh.normals.size() + mesh.tangents.size()); - - for (auto normalIt = mesh.normals.begin(), tangentIt = mesh.tangents.begin(); - normalIt != mesh.normals.end(); - ++normalIt, ++tangentIt) { -#if FBX_PACK_NORMALS - glm::uint32 finalNormal; - glm::uint32 finalTangent; - buffer_helpers::packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent); -#else - const auto finalNormal = *normalIt; - const auto finalTangent = *tangentIt; -#endif - normalsAndTangents.push_back(finalNormal); - normalsAndTangents.push_back(finalTangent); - } - - buffer->resize(mesh.vertices.size() * (sizeof(glm::vec3) + 2 * sizeof(NormalType))); - buffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (const gpu::Byte*) mesh.vertices.constData()); - buffer->setSubData(mesh.vertices.size() * sizeof(glm::vec3), - mesh.normals.size() * 2 * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data()); - } - _blendedVertexBuffers.push_back(buffer); } needFullUpdate = true; emit rigReady(); @@ -1280,9 +1250,9 @@ void Blender::run() { } // post the result to the geometry cache, which will dispatch to the model if still alive QMetaObject::invokeMethod(DependencyManager::get().data(), "setBlendedVertices", - Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), - Q_ARG(const Geometry::WeakPointer&, _geometry), Q_ARG(const QVector&, vertices), - Q_ARG(const QVector&, normals), Q_ARG(const QVector&, tangents)); + Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), + Q_ARG(const Geometry::WeakPointer&, _geometry), Q_ARG(const QVector&, vertices), + Q_ARG(const QVector&, normals), Q_ARG(const QVector&, tangents)); } void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) { @@ -1463,7 +1433,7 @@ bool Model::maybeStartBlender() { void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry, const QVector& vertices, const QVector& normals, const QVector& tangents) { auto geometryRef = geometry.lock(); - if (!geometryRef || _renderGeometry != geometryRef || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) { + if (!geometryRef || _renderGeometry != geometryRef || blendNumber < _appliedBlendNumber) { return; } _appliedBlendNumber = blendNumber; @@ -1476,13 +1446,13 @@ void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geo continue; } - gpu::BufferPointer& buffer = _blendedVertexBuffers[i]; + gpu::BufferPointer buffer = _blendedVertexBuffers[i]; const auto vertexCount = mesh.vertices.size(); const auto verticesSize = vertexCount * sizeof(glm::vec3); const auto offset = index * sizeof(glm::vec3); normalsAndTangents.clear(); - normalsAndTangents.resize(normals.size()+tangents.size()); + normalsAndTangents.resize(normals.size() + tangents.size()); // assert(normalsAndTangents.size() == 2 * vertexCount); // Interleave normals and tangents @@ -1510,7 +1480,7 @@ void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geo } #else // Parallel version for performance - tbb::parallel_for(tbb::blocked_range(index, index+vertexCount), [&](const tbb::blocked_range& range) { + tbb::parallel_for(tbb::blocked_range(index, index + vertexCount), [&](const tbb::blocked_range& range) { auto normalsRange = std::make_pair(normals.begin() + range.begin(), normals.begin() + range.end()); auto tangentsRange = std::make_pair(tangents.begin() + range.begin(), tangents.begin() + range.end()); auto normalsAndTangentsIt = normalsAndTangents.begin() + (range.begin()-index)*2; @@ -1603,6 +1573,7 @@ void Model::createRenderItemSet() { // Run through all of the meshes, and place them into their segregated, but unsorted buckets int shapeID = 0; uint32_t numMeshes = (uint32_t)meshes.size(); + const FBXGeometry& fbxGeometry = getFBXGeometry(); for (uint32_t i = 0; i < numMeshes; i++) { const auto& mesh = meshes.at(i); if (!mesh) { @@ -1612,6 +1583,10 @@ void Model::createRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { + if (!fbxGeometry.meshes[i].blendshapes.empty()) { + _blendedVertexBuffers[i] = std::make_shared(); + _blendedVertexBuffers[i]->resize(fbxGeometry.meshes[i].vertices.size() * (sizeof(glm::vec3) + 2 * sizeof(NormalType))); + } _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); auto material = getGeometry()->getShapeMaterial(shapeID); _modelMeshMaterialNames.push_back(material ? material->getName() : ""); @@ -1724,8 +1699,8 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) { } } -void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, - const QVector& vertices, const QVector& normals, +void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, + const QVector& vertices, const QVector& normals, const QVector& tangents) { if (model) { model->setBlendedVertices(blendNumber, geometry, vertices, normals, tangents); @@ -1744,4 +1719,3 @@ void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, const } } } - diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 627e5fddab..1d0570f087 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -413,7 +413,7 @@ protected: QUrl _url; - gpu::Buffers _blendedVertexBuffers; + std::unordered_map _blendedVertexBuffers; QVector > > _dilatedTextures; From 15665b25e8fc3d751b5bc647862fc0cf46923266 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Aug 2018 16:05:18 -0700 Subject: [PATCH 05/23] give OtherAvatars a proxy in workload --- interface/src/Application.cpp | 4 ++ interface/src/avatar/AvatarManager.cpp | 55 +++++++++++++++++++++----- interface/src/avatar/AvatarManager.h | 9 +++++ interface/src/avatar/OtherAvatar.cpp | 13 ++++++ interface/src/avatar/OtherAvatar.h | 11 ++++++ 5 files changed, 82 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1d515392b0..c0e024ec1e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1094,6 +1094,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Set File Logger Session UUID auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; + if (avatarManager) { + workload::SpacePointer space = getEntities()->getWorkloadSpace(); + avatarManager->setSpace(space); + } auto accountManager = DependencyManager::get(); _logger->setSessionID(accountManager->getSessionID()); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 0d180bc40d..551847324a 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -81,6 +81,22 @@ AvatarManager::AvatarManager(QObject* parent) : }); } +AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { + AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer); + + const auto otherAvatar = std::static_pointer_cast(avatar); + if (otherAvatar && _space) { + std::unique_lock lock(_spaceLock); + auto spaceIndex = _space->allocateID(); + otherAvatar->setSpaceIndex(spaceIndex); + workload::Sphere sphere(otherAvatar->getWorldPosition(), otherAvatar->getBoundingRadius()); + workload::Transaction transaction; + transaction.reset(spaceIndex, sphere, workload::Owner(otherAvatar)); + _space->enqueueTransaction(transaction); + } + return avatar; +} + AvatarManager::~AvatarManager() { assert(_motionStates.empty()); } @@ -104,6 +120,11 @@ void AvatarManager::init() { } } +void AvatarManager::setSpace(workload::SpacePointer& space ) { + assert(!_space); + _space = space; +} + void AvatarManager::updateMyAvatar(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()"); @@ -194,18 +215,19 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { int numAVatarsNotUpdated = 0; bool physicsEnabled = qApp->isPhysicsEnabled(); - render::Transaction transaction; + render::Transaction renderTransaction; + workload::Transaction workloadTransaction; while (!sortedAvatars.empty()) { const SortableAvatar& sortData = sortedAvatars.top(); - const auto avatar = std::static_pointer_cast(sortData.getAvatar()); - const auto otherAvatar = std::static_pointer_cast(sortData.getAvatar()); + const auto avatar = std::static_pointer_cast(sortData.getAvatar()); + // TODO: to help us scale to more avatars it would be nice to not have to poll orb state here // if the geometry is loaded then turn off the orb if (avatar->getSkeletonModel()->isLoaded()) { // remove the orb if it is there - otherAvatar->removeOrb(); + avatar->removeOrb(); } else { - otherAvatar->updateOrbPosition(); + avatar->updateOrbPosition(); } bool ignoring = DependencyManager::get()->isPersonalMutingNode(avatar->getID()); @@ -241,15 +263,16 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { numAvatarsUpdated++; } avatar->simulate(deltaTime, inView); - avatar->updateRenderItem(transaction); + avatar->updateRenderItem(renderTransaction); + avatar->updateSpaceProxy(workloadTransaction); avatar->setLastRenderUpdateTime(startTime); } else { // we've spent our full time budget --> bail on the rest of the avatar updates // --> more avatars may freeze until their priority trickles up - // --> some scale or fade animations may glitch + // --> some scale animations may glitch // --> some avatar velocity measurements may be a little off - // no time simulate, but we take the time to count how many were tragically missed + // no time to simulate, but we take the time to count how many were tragically missed bool inView = sortData.getPriority() > OUT_OF_VIEW_THRESHOLD; if (!inView) { break; @@ -275,6 +298,14 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { if (_shouldRender) { qApp->getMain3DScene()->enqueueTransaction(transaction); } + + if (!_spaceProxiesToDelete.empty() && _space) { + std::unique_lock lock(_spaceLock); + workloadTransaction.remove(_spaceProxiesToDelete); + _spaceProxiesToDelete.clear(); + } + _space->enqueueTransaction(workloadTransaction); + _numAvatarsUpdated = numAvatarsUpdated; _numAvatarsNotUpdated = numAVatarsNotUpdated; @@ -363,10 +394,14 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() { } void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { - AvatarHashMap::handleRemovedAvatar(removedAvatar, removalReason); + auto avatar = std::static_pointer_cast(removedAvatar); + { + std::unique_lock lock(_spaceLock); + _spaceProxiesToDelete.push_back(avatar->getSpaceIndex()); + } + AvatarHashMap::handleRemovedAvatar(avatar, removalReason); // remove from physics - auto avatar = std::static_pointer_cast(removedAvatar); avatar->setPhysicsCallback(nullptr); AvatarMotionStateMap::iterator itr = _motionStates.find(avatar.get()); if (itr != _motionStates.end()) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index ecf9a2d735..316e247aa0 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "AvatarMotionState.h" #include "MyAvatar.h" @@ -62,6 +63,7 @@ public: virtual ~AvatarManager(); void init(); + void setSpace(workload::SpacePointer& space ); std::shared_ptr getMyAvatar() { return _myAvatar; } glm::vec3 getMyAvatarPosition() const { return _myAvatar->getWorldPosition(); } @@ -183,6 +185,9 @@ public slots: */ void updateAvatarRenderStatus(bool shouldRenderAvatars); +protected: + AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) override; + private: explicit AvatarManager(QObject* parent = 0); explicit AvatarManager(const AvatarManager& other); @@ -212,6 +217,10 @@ private: float _avatarSimulationTime { 0.0f }; bool _shouldRender { true }; mutable int _identityRequestsSent { 0 }; + + mutable std::mutex _spaceLock; + workload::SpacePointer _space; + std::vector _spaceProxiesToDelete; }; #endif // hifi_AvatarManager_h diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index 2061df6004..579301aab1 100644 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -58,3 +58,16 @@ void OtherAvatar::createOrb() { _otherAvatarOrbMeshPlaceholder->setVisible(true); } } + +void OtherAvatar::setSpaceIndex(int32_t index) { + assert(_spaceIndex == -1); + _spaceIndex = index; +} + +void OtherAvatar::updateSpaceProxy(workload::Transaction& transaction) const { + if (_spaceIndex > -1) { + float approximateBoundingRadius = glm::length(getTargetScale()); + workload::Sphere sphere(getWorldPosition(), approximateBoundingRadius); + transaction.update(_spaceIndex, sphere); + } +} diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index f33952b78b..8d32e49579 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -14,7 +14,10 @@ #include "ui/overlays/Sphere3DOverlay.h" #include "InterfaceLogging.h" +#include + class OtherAvatar : public Avatar { + Q_OBJECT public: explicit OtherAvatar(QThread* thread); virtual ~OtherAvatar(); @@ -24,9 +27,17 @@ public: void updateOrbPosition(); void removeOrb(); + void setSpaceIndex(int32_t index); + int32_t getSpaceIndex() const { return _spaceIndex; } + void updateSpaceProxy(workload::Transaction& transaction) const; + +signals: + void spaceUpdate(std::pair data); + protected: std::shared_ptr _otherAvatarOrbMeshPlaceholder { nullptr }; OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID }; + int32_t _spaceIndex { -1 }; }; #endif // hifi_OtherAvatar_h From 21adbf49c06e2780a8b134a7626b5a3a6a7e1f2e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Aug 2018 17:03:04 -0700 Subject: [PATCH 06/23] remove cruft --- interface/src/avatar/OtherAvatar.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index 8d32e49579..27a5b29353 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -17,7 +17,6 @@ #include class OtherAvatar : public Avatar { - Q_OBJECT public: explicit OtherAvatar(QThread* thread); virtual ~OtherAvatar(); @@ -31,9 +30,6 @@ public: int32_t getSpaceIndex() const { return _spaceIndex; } void updateSpaceProxy(workload::Transaction& transaction) const; -signals: - void spaceUpdate(std::pair data); - protected: std::shared_ptr _otherAvatarOrbMeshPlaceholder { nullptr }; OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID }; From 55b1a6762cc3fa68017078a3c49bc20e50b02641 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 15 Aug 2018 10:19:32 -0700 Subject: [PATCH 07/23] explicit delete default ctor, make _nestableType private --- libraries/shared/src/SpatiallyNestable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 361f0aaf17..a50e687a9b 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -212,7 +212,6 @@ public: virtual void parentDeleted() { } // called on children of a deleted parent protected: - const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; mutable SpatiallyNestableWeakPointer _parent; @@ -232,6 +231,8 @@ protected: quint64 _rotationChanged { 0 }; private: + SpatiallyNestable() = delete; + const NestableType _nestableType; // EntityItem or an AvatarData QUuid _parentID; // what is this thing's transform relative to? quint16 _parentJointIndex { INVALID_JOINT_INDEX }; // which joint of the parent is this relative to? From 3c01433e12ebfaed4df2dbf46b5297426fd46f2c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 15 Aug 2018 10:20:58 -0700 Subject: [PATCH 08/23] stub for avatars changing workload regions --- interface/src/avatar/AvatarManager.cpp | 8 +++++-- interface/src/avatar/AvatarManager.h | 12 ++++++---- interface/src/avatar/OtherAvatar.h | 4 ++++ interface/src/workload/PhysicsBoundary.cpp | 24 ++++++++++++++++--- interface/src/workload/PhysicsBoundary.h | 3 --- .../src/EntityTreeRenderer.cpp | 3 ++- 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 551847324a..06c259f907 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -44,7 +44,6 @@ #include "InterfaceLogging.h" #include "Menu.h" #include "MyAvatar.h" -#include "OtherAvatar.h" #include "SceneScriptingInterface.h" // 50 times per second - target is 45hz, but this helps account for any small deviations @@ -91,7 +90,8 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe otherAvatar->setSpaceIndex(spaceIndex); workload::Sphere sphere(otherAvatar->getWorldPosition(), otherAvatar->getBoundingRadius()); workload::Transaction transaction; - transaction.reset(spaceIndex, sphere, workload::Owner(otherAvatar)); + SpatiallyNestablePointer nestable = std::static_pointer_cast(otherAvatar); + transaction.reset(spaceIndex, sphere, workload::Owner(nestable)); _space->enqueueTransaction(transaction); } return avatar; @@ -393,6 +393,10 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() { return AvatarSharedPointer(new OtherAvatar(qApp->thread()), [](OtherAvatar* ptr) { ptr->deleteLater(); }); } +void AvatarManager::handleSpaceChange(OtherAvatarPointer avatar) { + // WORKLOAD_AVATARS_BOOKMARK: implement this +} + void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { auto avatar = std::static_pointer_cast(removedAvatar); { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 316e247aa0..bbf13d25c4 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -27,6 +27,7 @@ #include "AvatarMotionState.h" #include "MyAvatar.h" +#include "OtherAvatar.h" /**jsdoc * The AvatarManager API has properties and methods which manage Avatars within the same domain. @@ -94,6 +95,7 @@ public: void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates); void getObjectsToAddToPhysics(VectorOfMotionStates& motionStates); void getObjectsToChange(VectorOfMotionStates& motionStates); + void handleChangedMotionStates(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); @@ -104,23 +106,21 @@ public: * @returns {number} */ Q_INVOKABLE float getAvatarDataRate(const QUuid& sessionID, const QString& rateName = QString("")) const; - + /**jsdoc * @function AvatarManager.getAvatarUpdateRate * @param {Uuid} sessionID * @param {string} [rateName=""] * @returns {number} */ - Q_INVOKABLE float getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName = QString("")) const; - + /**jsdoc * @function AvatarManager.getAvatarSimulationRate * @param {Uuid} sessionID * @param {string} [rateName=""] * @returns {number} */ - Q_INVOKABLE float getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName = QString("")) const; /**jsdoc @@ -155,7 +155,7 @@ public: */ // TODO: remove this HACK once we settle on optimal default sort coefficients Q_INVOKABLE float getAvatarSortCoefficient(const QString& name); - + /**jsdoc * @function AvatarManager.setAvatarSortCoefficient * @param {string} name @@ -185,6 +185,8 @@ public slots: */ void updateAvatarRenderStatus(bool shouldRenderAvatars); + void handleSpaceChange(OtherAvatarPointer avatar); + protected: AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) override; diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index 27a5b29353..dcd54332c6 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -9,6 +9,8 @@ #ifndef hifi_OtherAvatar_h #define hifi_OtherAvatar_h +#include + #include #include "ui/overlays/Overlays.h" #include "ui/overlays/Sphere3DOverlay.h" @@ -36,4 +38,6 @@ protected: int32_t _spaceIndex { -1 }; }; +using OtherAvatarPointer = std::shared_ptr; + #endif // hifi_OtherAvatar_h diff --git a/interface/src/workload/PhysicsBoundary.cpp b/interface/src/workload/PhysicsBoundary.cpp index 927121ac04..d1de9ad6b2 100644 --- a/interface/src/workload/PhysicsBoundary.cpp +++ b/interface/src/workload/PhysicsBoundary.cpp @@ -10,9 +10,13 @@ #include "PhysicsBoundary.h" +#include +#include #include #include +#include "avatar/AvatarManager.h" +#include "avatar/OtherAvatar.h" #include "workload/GameWorkload.h" void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const Inputs& inputs) { @@ -22,12 +26,26 @@ void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const } GameWorkloadContext* gameContext = static_cast(context.get()); PhysicalEntitySimulationPointer simulation = gameContext->_simulation; + auto avatarManager = DependencyManager::get(); const auto& regionChanges = inputs.get0(); for (uint32_t i = 0; i < (uint32_t)regionChanges.size(); ++i) { const workload::Space::Change& change = regionChanges[i]; - auto entity = space->getOwner(change.proxyId).get(); - if (entity) { - simulation->changeEntity(entity); + auto nestable = space->getOwner(change.proxyId).get(); + if (nestable) { + switch (nestable->getNestableType()) { + case NestableType::Entity: { + EntityItemPointer entity = std::static_pointer_cast(nestable); + simulation->changeEntity(entity); + } + break; + case NestableType::Avatar: { + auto avatar = std::static_pointer_cast(nestable); + avatarManager->handleSpaceChange(avatar); + } + break; + default: + break; + } } } } diff --git a/interface/src/workload/PhysicsBoundary.h b/interface/src/workload/PhysicsBoundary.h index c316fa5686..e4d0411104 100644 --- a/interface/src/workload/PhysicsBoundary.h +++ b/interface/src/workload/PhysicsBoundary.h @@ -10,12 +10,9 @@ #ifndef hifi_PhysicsGatekeeper_h #define hifi_PhysicsGatekeeper_h -#include #include #include -#include "PhysicalEntitySimulation.h" - class PhysicsBoundary { public: using Config = workload::Job::Config; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 34d8dbbaef..c3c4095251 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -295,7 +295,8 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r auto spaceIndex = _space->allocateID(); workload::Sphere sphere(entity->getWorldPosition(), entity->getBoundingRadius()); workload::Transaction transaction; - transaction.reset(spaceIndex, sphere, workload::Owner(entity)); + SpatiallyNestablePointer nestable = std::static_pointer_cast(entity); + transaction.reset(spaceIndex, sphere, workload::Owner(nestable)); _space->enqueueTransaction(transaction); entity->setSpaceIndex(spaceIndex); connect(entity.get(), &EntityItem::spaceUpdate, this, &EntityTreeRenderer::handleSpaceUpdate, Qt::QueuedConnection); From 598a227f1a866090600ae901e1f56ac215323697 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 15 Aug 2018 12:48:53 -0700 Subject: [PATCH 09/23] use OtherAvatar instead of Avatar in AvatarMotionState --- interface/src/avatar/AvatarMotionState.cpp | 8 ++++---- interface/src/avatar/AvatarMotionState.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 07e6b3f6b0..ca67f634c8 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -16,7 +16,7 @@ #include -AvatarMotionState::AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { +AvatarMotionState::AvatarMotionState(OtherAvatarPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { assert(_avatar); _type = MOTIONSTATE_TYPE_AVATAR; cacheShapeDiameter(); @@ -57,7 +57,7 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const { // virtual and protected const btCollisionShape* AvatarMotionState::computeNewShape() { ShapeInfo shapeInfo; - std::static_pointer_cast(_avatar)->computeShapeInfo(shapeInfo); + _avatar->computeShapeInfo(shapeInfo); return getShapeManager()->getShape(shapeInfo); } @@ -151,7 +151,7 @@ glm::vec3 AvatarMotionState::getObjectAngularVelocity() const { // virtual glm::vec3 AvatarMotionState::getObjectGravity() const { - return std::static_pointer_cast(_avatar)->getAcceleration(); + return _avatar->getAcceleration(); } // virtual @@ -176,7 +176,7 @@ void AvatarMotionState::computeCollisionGroupAndMask(int32_t& group, int32_t& ma // virtual float AvatarMotionState::getMass() const { - return std::static_pointer_cast(_avatar)->computeMass(); + return _avatar->computeMass(); } void AvatarMotionState::cacheShapeDiameter() { diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index a458704b1a..2533c11d56 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -14,14 +14,14 @@ #include -#include #include #include +#include "OtherAvatar.h" class AvatarMotionState : public ObjectMotionState { public: - AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape); + AvatarMotionState(OtherAvatarPointer avatar, const btCollisionShape* shape); virtual void handleEasyChanges(uint32_t& flags) override; virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override; @@ -85,7 +85,7 @@ protected: virtual bool isReadyToComputeShape() const override { return true; } virtual const btCollisionShape* computeNewShape() override; - AvatarSharedPointer _avatar; + OtherAvatarPointer _avatar; float _diameter { 0.0f }; uint32_t _dirtyFlags; From 615b8addd0bc5848301e51044e43b3e53c25b15a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 15 Aug 2018 13:23:20 -0700 Subject: [PATCH 10/23] fix order of includes --- interface/src/avatar/OtherAvatar.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index dcd54332c6..3ecf6bea38 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -12,11 +12,11 @@ #include #include +#include + +#include "InterfaceLogging.h" #include "ui/overlays/Overlays.h" #include "ui/overlays/Sphere3DOverlay.h" -#include "InterfaceLogging.h" - -#include class OtherAvatar : public Avatar { public: From 1c87d7b109a48eaeccb5030e2a2b0f7dacfb2089 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 15 Aug 2018 15:36:01 -0700 Subject: [PATCH 11/23] reorder initialization to remove compile warning --- libraries/shared/src/SpatiallyNestable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index ccb275ffc9..4b8768704a 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -22,8 +22,8 @@ const float defaultAACubeSize = 1.0f; const int MAX_PARENTING_CHAIN_SIZE = 30; SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) : - _nestableType(nestableType), _id(id), + _nestableType(nestableType), _transform() { // set flags in _transform _transform.setTranslation(glm::vec3(0.0f)); From 99aafb1f95f4b23012ca9c77ab2ce1400cfab1a7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 15 Aug 2018 15:07:15 -0700 Subject: [PATCH 12/23] move code from Avatar to OtherAvatar --- interface/src/avatar/OtherAvatar.cpp | 18 ++++++++++++++++++ interface/src/avatar/OtherAvatar.h | 13 +++++++++++-- .../src/avatars-renderer/Avatar.cpp | 17 ----------------- .../src/avatars-renderer/Avatar.h | 10 +--------- 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index 579301aab1..74ad9af915 100644 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -71,3 +71,21 @@ void OtherAvatar::updateSpaceProxy(workload::Transaction& transaction) const { transaction.update(_spaceIndex, sphere); } } + +int OtherAvatar::parseDataFromBuffer(const QByteArray& buffer) { + int32_t bytesRead = Avatar::parseDataFromBuffer(buffer); + if (_moving && _physicsCallback) { + _physicsCallback(Simulation::DIRTY_POSITION); + } + return bytesRead; +} + +void OtherAvatar::rebuildCollisionShape() { + if (_physicsCallback) { + _physicsCallback(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); + } +} + +void OtherAvatar::setPhysicsCallback(AvatarPhysicsCallback cb) { + _physicsCallback = cb; +} diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index 3ecf6bea38..9f06b05ef0 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -1,6 +1,6 @@ // -// Created by Bradley Austin Davis on 2017/04/27 -// Copyright 2013-2017 High Fidelity, Inc. +// Created by amantly 2018.06.26 +// Copyright 2018 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -18,6 +18,8 @@ #include "ui/overlays/Overlays.h" #include "ui/overlays/Sphere3DOverlay.h" +using AvatarPhysicsCallback = std::function; + class OtherAvatar : public Avatar { public: explicit OtherAvatar(QThread* thread); @@ -32,9 +34,16 @@ public: int32_t getSpaceIndex() const { return _spaceIndex; } void updateSpaceProxy(workload::Transaction& transaction) const; + int parseDataFromBuffer(const QByteArray& buffer) override; + + void setPhysicsCallback(AvatarPhysicsCallback cb); + bool isInPhysicsSimulation() const { return _physicsCallback != nullptr; } + void rebuildCollisionShape() override; + protected: std::shared_ptr _otherAvatarOrbMeshPlaceholder { nullptr }; OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID }; + AvatarPhysicsCallback _physicsCallback { nullptr }; int32_t _spaceIndex { -1 }; }; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 7dbee0e669..a9af3b7725 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1483,9 +1483,6 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) { const float MOVE_DISTANCE_THRESHOLD = 0.001f; _moving = glm::distance(oldPosition, getWorldPosition()) > MOVE_DISTANCE_THRESHOLD; - if (_moving) { - addPhysicsFlags(Simulation::DIRTY_POSITION); - } if (_moving || _hasNewJointData) { locationChanged(); } @@ -1627,20 +1624,6 @@ float Avatar::computeMass() { return _density * TWO_PI * radius * radius * (glm::length(end - start) + 2.0f * radius / 3.0f); } -void Avatar::rebuildCollisionShape() { - addPhysicsFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); -} - -void Avatar::setPhysicsCallback(AvatarPhysicsCallback cb) { - _physicsCallback = cb; -} - -void Avatar::addPhysicsFlags(uint32_t flags) { - if (_physicsCallback) { - _physicsCallback(flags); - } -} - // thread-safe glm::vec3 Avatar::getLeftPalmPosition() const { return _leftPalmPositionCache.get(); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index c6e8ac59f1..7d3ec39c4f 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -50,8 +50,6 @@ enum ScreenTintLayer { class Texture; -using AvatarPhysicsCallback = std::function; - class Avatar : public AvatarData, public scriptable::ModelProvider { Q_OBJECT @@ -244,7 +242,7 @@ public: // (otherwise floating point error will cause problems at large positions). void applyPositionDelta(const glm::vec3& delta); - virtual void rebuildCollisionShape(); + virtual void rebuildCollisionShape() = 0; virtual void computeShapeInfo(ShapeInfo& shapeInfo); void getCapsule(glm::vec3& start, glm::vec3& end, float& radius); @@ -332,10 +330,6 @@ public: render::ItemID getRenderItemID() { return _renderItemID; } bool isMoving() const { return _moving; } - void setPhysicsCallback(AvatarPhysicsCallback cb); - void addPhysicsFlags(uint32_t flags); - bool isInPhysicsSimulation() const { return _physicsCallback != nullptr; } - void fadeIn(render::ScenePointer scene); void fadeOut(render::ScenePointer scene, KillAvatarReason reason); bool isFading() const { return _isFading; } @@ -530,8 +524,6 @@ protected: int _voiceSphereID; - AvatarPhysicsCallback _physicsCallback { nullptr }; - float _displayNameTargetAlpha { 1.0f }; float _displayNameAlpha { 1.0f }; From 3ecabb6583285fd424cae527dcb626d822f6b55c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 15 Aug 2018 15:20:54 -0700 Subject: [PATCH 13/23] cleanup after removing spaghetti --- interface/src/avatar/AvatarManager.cpp | 4 ++-- interface/src/avatar/OtherAvatar.cpp | 14 ++++++++------ interface/src/avatar/OtherAvatar.h | 8 ++++---- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 06c259f907..11257e0808 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -247,7 +247,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { if (shape) { AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); motionState->setMass(avatar->computeMass()); - avatar->setPhysicsCallback([=] (uint32_t flags) { motionState->addDirtyFlags(flags); }); + avatar->setMotionState(motionState); _motionStates.insert(avatar.get(), motionState); _motionStatesToAddToPhysics.insert(motionState); } @@ -406,7 +406,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar AvatarHashMap::handleRemovedAvatar(avatar, removalReason); // remove from physics - avatar->setPhysicsCallback(nullptr); + avatar->setMotionState(nullptr); AvatarMotionStateMap::iterator itr = _motionStates.find(avatar.get()); if (itr != _motionStates.end()) { AvatarMotionState* motionState = *itr; diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index 74ad9af915..653b6c4533 100644 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -9,6 +9,8 @@ #include "OtherAvatar.h" #include "Application.h" +#include "AvatarMotionState.h" + OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) { // give the pointer to our head to inherited _headData variable from AvatarData _headData = new Head(this); @@ -74,18 +76,18 @@ void OtherAvatar::updateSpaceProxy(workload::Transaction& transaction) const { int OtherAvatar::parseDataFromBuffer(const QByteArray& buffer) { int32_t bytesRead = Avatar::parseDataFromBuffer(buffer); - if (_moving && _physicsCallback) { - _physicsCallback(Simulation::DIRTY_POSITION); + if (_moving && _motionState) { + _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); } return bytesRead; } void OtherAvatar::rebuildCollisionShape() { - if (_physicsCallback) { - _physicsCallback(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); + if (_motionState) { + _motionState->addDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); } } -void OtherAvatar::setPhysicsCallback(AvatarPhysicsCallback cb) { - _physicsCallback = cb; +void OtherAvatar::setMotionState(AvatarMotionState* motionState) { + _motionState = motionState; } diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index 9f06b05ef0..e34d4d767b 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -18,7 +18,7 @@ #include "ui/overlays/Overlays.h" #include "ui/overlays/Sphere3DOverlay.h" -using AvatarPhysicsCallback = std::function; +class AvatarMotionState; class OtherAvatar : public Avatar { public: @@ -36,14 +36,14 @@ public: int parseDataFromBuffer(const QByteArray& buffer) override; - void setPhysicsCallback(AvatarPhysicsCallback cb); - bool isInPhysicsSimulation() const { return _physicsCallback != nullptr; } + void setMotionState(AvatarMotionState* motionState); + bool isInPhysicsSimulation() const { return _motionState != nullptr; } void rebuildCollisionShape() override; protected: std::shared_ptr _otherAvatarOrbMeshPlaceholder { nullptr }; OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID }; - AvatarPhysicsCallback _physicsCallback { nullptr }; + AvatarMotionState* _motionState { nullptr }; int32_t _spaceIndex { -1 }; }; From 87223946ad2813c9e71c1738678e385cacf7b52f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 17 Aug 2018 17:43:17 -0700 Subject: [PATCH 14/23] add/remove avatars according to workload region --- interface/src/Application.cpp | 24 +++-- interface/src/avatar/AvatarManager.cpp | 111 ++++++++++----------- interface/src/avatar/AvatarManager.h | 17 ++-- interface/src/avatar/OtherAvatar.cpp | 12 ++- interface/src/avatar/OtherAvatar.h | 8 +- interface/src/workload/PhysicsBoundary.cpp | 10 +- libraries/physics/src/PhysicsEngine.cpp | 51 ++++++++++ libraries/physics/src/PhysicsEngine.h | 14 +++ 8 files changed, 157 insertions(+), 90 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c0e024ec1e..bfc781fa2a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2540,11 +2540,15 @@ void Application::cleanupBeforeQuit() { Application::~Application() { // remove avatars from physics engine - DependencyManager::get()->clearOtherAvatars(); - VectorOfMotionStates motionStates; - DependencyManager::get()->getObjectsToRemoveFromPhysics(motionStates); - _physicsEngine->removeObjects(motionStates); - DependencyManager::get()->deleteAllAvatars(); + auto avatarManager = DependencyManager::get(); + avatarManager->clearOtherAvatars(); + + PhysicsEngine::Transaction transaction; + avatarManager->buildPhysicsTransaction(transaction); + _physicsEngine->processTransaction(transaction); + avatarManager->handleProcessedPhysicsTransaction(transaction); + + avatarManager->deleteAllAvatars(); _physicsEngine->setCharacterController(nullptr); @@ -5706,12 +5710,10 @@ void Application::update(float deltaTime) { t1 = std::chrono::high_resolution_clock::now(); - avatarManager->getObjectsToRemoveFromPhysics(motionStates); - _physicsEngine->removeObjects(motionStates); - avatarManager->getObjectsToAddToPhysics(motionStates); - _physicsEngine->addObjects(motionStates); - avatarManager->getObjectsToChange(motionStates); - _physicsEngine->changeObjects(motionStates); + PhysicsEngine::Transaction transaction; + avatarManager->buildPhysicsTransaction(transaction); + _physicsEngine->processTransaction(transaction); + avatarManager->handleProcessedPhysicsTransaction(transaction); myAvatar->prepareForPhysicsSimulation(); _physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) { diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 11257e0808..62eadeddef 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -98,7 +98,7 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe } AvatarManager::~AvatarManager() { - assert(_motionStates.empty()); + assert(_avatarsToChangeInPhysics.empty()); } void AvatarManager::init() { @@ -213,7 +213,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { uint64_t updateExpiry = startTime + UPDATE_BUDGET; int numAvatarsUpdated = 0; int numAVatarsNotUpdated = 0; - bool physicsEnabled = qApp->isPhysicsEnabled(); render::Transaction renderTransaction; workload::Transaction workloadTransaction; @@ -240,18 +239,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { if (_shouldRender) { avatar->ensureInScene(avatar, qApp->getMain3DScene()); } - if (physicsEnabled && !avatar->isInPhysicsSimulation()) { - ShapeInfo shapeInfo; - avatar->computeShapeInfo(shapeInfo); - btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); - if (shape) { - AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); - motionState->setMass(avatar->computeMass()); - avatar->setMotionState(motionState); - _motionStates.insert(avatar.get(), motionState); - _motionStatesToAddToPhysics.insert(motionState); - } - } avatar->animateScaleChanges(deltaTime); const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY; @@ -393,8 +380,52 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() { return AvatarSharedPointer(new OtherAvatar(qApp->thread()), [](OtherAvatar* ptr) { ptr->deleteLater(); }); } -void AvatarManager::handleSpaceChange(OtherAvatarPointer avatar) { - // WORKLOAD_AVATARS_BOOKMARK: implement this +void AvatarManager::queuePhysicsChange(const OtherAvatarPointer& avatar) { + _avatarsToChangeInPhysics.insert(avatar); +} + +void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transaction) { + SetOfOtherAvatars failedShapeBuilds; + for (auto avatar : _avatarsToChangeInPhysics) { + bool isInPhysics = avatar->isInPhysicsSimulation(); + if (isInPhysics != avatar->shouldBeInPhysicsSimulation()) { + if (isInPhysics) { + transaction.objectsToRemove.push_back(avatar->_motionState); + avatar->_motionState = nullptr; + } else { + ShapeInfo shapeInfo; + avatar->computeShapeInfo(shapeInfo); + btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); + if (shape) { + AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); + motionState->setMass(avatar->computeMass()); + avatar->_motionState = motionState; + transaction.objectsToAdd.push_back(motionState); + } else { + failedShapeBuilds.insert(avatar); + } + } + } else if (isInPhysics) { + transaction.objectsToChange.push_back(avatar->_motionState); + } + } + _avatarsToChangeInPhysics.swap(failedShapeBuilds); +} + +void AvatarManager::handleProcessedPhysicsTransaction(PhysicsEngine::Transaction& transaction) { + // things on objectsToChange correspond to failed changes + // so we push them back onto _avatarsToChangeInPhysics + for (auto object : transaction.objectsToChange) { + AvatarMotionState* motionState = static_cast(object); + assert(motionState); + assert(motionState->_avatar); + _avatarsToChangeInPhysics.insert(motionState->_avatar); + } + // things on objectsToRemove are ready for delete + for (auto object : transaction.objectsToRemove) { + delete object; + } + transaction.clear(); } void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { @@ -405,15 +436,8 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar } AvatarHashMap::handleRemovedAvatar(avatar, removalReason); - // remove from physics - avatar->setMotionState(nullptr); - AvatarMotionStateMap::iterator itr = _motionStates.find(avatar.get()); - if (itr != _motionStates.end()) { - AvatarMotionState* motionState = *itr; - _motionStatesToAddToPhysics.remove(motionState); - _motionStatesToRemoveFromPhysics.push_back(motionState); - _motionStates.erase(itr); - } + avatar->die(); + queuePhysicsChange(avatar); if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) { emit DependencyManager::get()->enteredIgnoreRadius(); @@ -449,8 +473,7 @@ void AvatarManager::clearOtherAvatars() { } void AvatarManager::deleteAllAvatars() { - assert(_motionStates.empty()); // should have called clearOtherAvatars() before getting here - deleteMotionStates(); + assert(_avatarsToChangeInPhysics.empty()); QReadLocker locker(&_hashLock); AvatarHash::iterator avatarIterator = _avatarHash.begin(); @@ -458,39 +481,7 @@ void AvatarManager::deleteAllAvatars() { auto avatar = std::static_pointer_cast(avatarIterator.value()); avatarIterator = _avatarHash.erase(avatarIterator); avatar->die(); - } -} - -void AvatarManager::deleteMotionStates() { - // delete motionstates that were removed from physics last frame - for (auto state : _motionStatesToDelete) { - delete state; - } - _motionStatesToDelete.clear(); -} - -void AvatarManager::getObjectsToRemoveFromPhysics(VectorOfMotionStates& result) { - deleteMotionStates(); - result = _motionStatesToRemoveFromPhysics; - _motionStatesToDelete.swap(_motionStatesToRemoveFromPhysics); -} - -void AvatarManager::getObjectsToAddToPhysics(VectorOfMotionStates& result) { - result.clear(); - for (auto motionState : _motionStatesToAddToPhysics) { - result.push_back(motionState); - } - _motionStatesToAddToPhysics.clear(); -} - -void AvatarManager::getObjectsToChange(VectorOfMotionStates& result) { - result.clear(); - AvatarMotionStateMap::iterator motionStateItr = _motionStates.begin(); - while (motionStateItr != _motionStates.end()) { - if ((*motionStateItr)->getIncomingDirtyFlags() != 0) { - result.push_back(*motionStateItr); - } - ++motionStateItr; + assert(!avatar->_motionState); } } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index bbf13d25c4..36df2f0aaf 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -12,6 +12,8 @@ #ifndef hifi_AvatarManager_h #define hifi_AvatarManager_h +#include + #include #include #include @@ -177,16 +179,17 @@ public: float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); } int getIdentityRequestsSent() const { return _identityRequestsSent; } -public slots: + void queuePhysicsChange(const OtherAvatarPointer& avatar); + void buildPhysicsTransaction(PhysicsEngine::Transaction& transaction); + void handleProcessedPhysicsTransaction(PhysicsEngine::Transaction& transaction); +public slots: /**jsdoc * @function AvatarManager.updateAvatarRenderStatus * @param {boolean} shouldRenderAvatars */ void updateAvatarRenderStatus(bool shouldRenderAvatars); - void handleSpaceChange(OtherAvatarPointer avatar); - protected: AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) override; @@ -197,16 +200,12 @@ private: void simulateAvatarFades(float deltaTime); AvatarSharedPointer newSharedAvatar() override; - void deleteMotionStates(); void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; QVector _avatarsToFade; - using AvatarMotionStateMap = QMap; - AvatarMotionStateMap _motionStates; - VectorOfMotionStates _motionStatesToRemoveFromPhysics; - VectorOfMotionStates _motionStatesToDelete; - SetOfMotionStates _motionStatesToAddToPhysics; + using SetOfOtherAvatars = std::set; + SetOfOtherAvatars _avatarsToChangeInPhysics; std::shared_ptr _myAvatar; quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate. diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index 653b6c4533..29ad5aed91 100644 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -82,12 +82,16 @@ int OtherAvatar::parseDataFromBuffer(const QByteArray& buffer) { return bytesRead; } +void OtherAvatar::setWorkloadRegion(uint8_t region) { + _workloadRegion = region; +} + +bool OtherAvatar::shouldBeInPhysicsSimulation() const { + return (_workloadRegion < workload::Region::R3 && !isDead()); +} + void OtherAvatar::rebuildCollisionShape() { if (_motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); } } - -void OtherAvatar::setMotionState(AvatarMotionState* motionState) { - _motionState = motionState; -} diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index e34d4d767b..ccfe42dbed 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -18,6 +18,7 @@ #include "ui/overlays/Overlays.h" #include "ui/overlays/Sphere3DOverlay.h" +class AvatarManager; class AvatarMotionState; class OtherAvatar : public Avatar { @@ -36,15 +37,20 @@ public: int parseDataFromBuffer(const QByteArray& buffer) override; - void setMotionState(AvatarMotionState* motionState); bool isInPhysicsSimulation() const { return _motionState != nullptr; } void rebuildCollisionShape() override; + void setWorkloadRegion(uint8_t region); + bool shouldBeInPhysicsSimulation() const; + + friend AvatarManager; + protected: std::shared_ptr _otherAvatarOrbMeshPlaceholder { nullptr }; OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID }; AvatarMotionState* _motionState { nullptr }; int32_t _spaceIndex { -1 }; + uint8_t _workloadRegion { workload::Region::INVALID }; }; using OtherAvatarPointer = std::shared_ptr; diff --git a/interface/src/workload/PhysicsBoundary.cpp b/interface/src/workload/PhysicsBoundary.cpp index d1de9ad6b2..cc78789145 100644 --- a/interface/src/workload/PhysicsBoundary.cpp +++ b/interface/src/workload/PhysicsBoundary.cpp @@ -25,8 +25,6 @@ void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const return; } GameWorkloadContext* gameContext = static_cast(context.get()); - PhysicalEntitySimulationPointer simulation = gameContext->_simulation; - auto avatarManager = DependencyManager::get(); const auto& regionChanges = inputs.get0(); for (uint32_t i = 0; i < (uint32_t)regionChanges.size(); ++i) { const workload::Space::Change& change = regionChanges[i]; @@ -34,13 +32,15 @@ void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const if (nestable) { switch (nestable->getNestableType()) { case NestableType::Entity: { - EntityItemPointer entity = std::static_pointer_cast(nestable); - simulation->changeEntity(entity); + gameContext->_simulation->changeEntity(std::static_pointer_cast(nestable)); } break; case NestableType::Avatar: { auto avatar = std::static_pointer_cast(nestable); - avatarManager->handleSpaceChange(avatar); + avatar->setWorkloadRegion(change.region); + if (avatar->isInPhysicsSimulation() != avatar->shouldBeInPhysicsSimulation()) { + DependencyManager::get()->queuePhysicsChange(avatar); + } } break; default: diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 163005bc81..92ae3d546d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -279,6 +279,57 @@ void PhysicsEngine::reinsertObject(ObjectMotionState* object) { } } +void PhysicsEngine::processTransaction(PhysicsEngine::Transaction& transaction) { + // removes + for (auto object : transaction.objectsToRemove) { + btRigidBody* body = object->getRigidBody(); + if (body) { + removeDynamicsForBody(body); + _dynamicsWorld->removeRigidBody(body); + + // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. + object->setRigidBody(nullptr); + body->setMotionState(nullptr); + delete body; + } + object->clearIncomingDirtyFlags(); + } + + // adds + for (auto object : transaction.objectsToAdd) { + addObjectToDynamicsWorld(object); + } + + // changes + std::vector failedChanges; + for (auto object : transaction.objectsToChange) { + uint32_t flags = object->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; + if (flags & HARD_DIRTY_PHYSICS_FLAGS) { + if (object->handleHardAndEasyChanges(flags, this)) { + object->clearIncomingDirtyFlags(); + } else { + failedChanges.push_back(object); + } + } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { + object->handleEasyChanges(flags); + object->clearIncomingDirtyFlags(); + } + if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) { + _activeStaticBodies.insert(object->getRigidBody()); + } + } + // activeStaticBodies have changed (in an Easy way) and need their Aabbs updated + // but we've configured Bullet to NOT update them automatically (for improved performance) + // so we must do it ourselves + std::set::const_iterator itr = _activeStaticBodies.begin(); + while (itr != _activeStaticBodies.end()) { + _dynamicsWorld->updateSingleAabb(*itr); + ++itr; + } + // we replace objectsToChange with any that failed + transaction.objectsToChange.swap(failedChanges); +} + void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { // trigger events for new/existing/old contacts ContactMap::iterator contactItr = _contactMap.begin(); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index c6e165632b..0f40a06825 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -70,6 +70,18 @@ using CollisionEvents = std::vector; class PhysicsEngine { public: + class Transaction { + public: + void clear() { + objectsToRemove.clear(); + objectsToAdd.clear(); + objectsToChange.clear(); + } + std::vector objectsToRemove; + std::vector objectsToAdd; + std::vector objectsToChange; + }; + PhysicsEngine(const glm::vec3& offset); ~PhysicsEngine(); void init(); @@ -83,6 +95,8 @@ public: VectorOfMotionStates changeObjects(const VectorOfMotionStates& objects); void reinsertObject(ObjectMotionState* object); + void processTransaction(Transaction& transaction); + void stepSimulation(); void harvestPerformanceStats(); void printPerformanceStatsToFile(const QString& filename); From f5cae61b433293d812ae0a0dafb90d975fa751e4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 20 Aug 2018 14:11:22 -0700 Subject: [PATCH 15/23] fix typo causing compile failure --- interface/src/avatar/AvatarManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 62eadeddef..86daf94bfa 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -283,7 +283,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } if (_shouldRender) { - qApp->getMain3DScene()->enqueueTransaction(transaction); + qApp->getMain3DScene()->enqueueTransaction(renderTransaction); } if (!_spaceProxiesToDelete.empty() && _space) { From 777b90bdc06a58e4d236290b50e52334d7d84292 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 20 Aug 2018 16:35:46 -0700 Subject: [PATCH 16/23] add 'physics body count' to debug stats --- interface/resources/qml/Stats.qml | 3 +++ interface/src/Application.cpp | 4 ++++ interface/src/Application.h | 1 + interface/src/ui/Stats.cpp | 1 + interface/src/ui/Stats.h | 9 +++++++++ libraries/physics/src/PhysicsEngine.cpp | 7 +++++++ libraries/physics/src/PhysicsEngine.h | 5 ++++- 7 files changed, 29 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 2e6e909312..d89e3333e6 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -60,6 +60,9 @@ Item { StatText { text: "Game Rate: " + root.gameLoopRate } + StatText { + text: "Physics Body Count: " + root.physicsBodyCount + } StatText { visible: root.expanded text: root.gameUpdateStats diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bfc781fa2a..9057bdea28 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6184,6 +6184,10 @@ bool Application::isHMDMode() const { return getActiveDisplayPlugin()->isHmd(); } +float Application::getNumRigidBodies() const { + return _physicsEngine ? _physicsEngine->getNumRigidBodies() : 0; +} + float Application::getTargetRenderFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); } QRect Application::getDesirableApplicationGeometry() const { diff --git a/interface/src/Application.h b/interface/src/Application.h index 742cf075f6..e415b28343 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -207,6 +207,7 @@ public: size_t getRenderFrameCount() const { return _renderFrameCount; } float getRenderLoopRate() const { return _renderLoopCounter.rate(); } + float getNumRigidBodies() const; float getTargetRenderFrameRate() const; // frames/second float getFieldOfView() { return _fieldOfView.get(); } diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index ce1cd51de1..9c1e1802c7 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -121,6 +121,7 @@ void Stats::updateStats(bool force) { auto avatarManager = DependencyManager::get(); // we need to take one avatar out so we don't include ourselves STAT_UPDATE(avatarCount, avatarManager->size() - 1); + STAT_UPDATE(physicsBodyCount, qApp->getNumRigidBodies()); STAT_UPDATE(updatedAvatarCount, avatarManager->getNumAvatarsUpdated()); STAT_UPDATE(notUpdatedAvatarCount, avatarManager->getNumAvatarsNotUpdated()); STAT_UPDATE(serverCount, (int)nodeList->size()); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index cf624b54c3..35eeb78caa 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -49,6 +49,7 @@ private: \ * @property {number} presentdroprate - Read-only. * @property {number} gameLoopRate - Read-only. * @property {number} avatarCount - Read-only. + * @property {number} physicsBodyCount - Read-only. * @property {number} updatedAvatarCount - Read-only. * @property {number} notUpdatedAvatarCount - Read-only. * @property {number} packetInCount - Read-only. @@ -195,6 +196,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(float, presentdroprate, 0) STATS_PROPERTY(int, gameLoopRate, 0) STATS_PROPERTY(int, avatarCount, 0) + STATS_PROPERTY(int, physicsBodyCount, 0) STATS_PROPERTY(int, updatedAvatarCount, 0) STATS_PROPERTY(int, notUpdatedAvatarCount, 0) STATS_PROPERTY(int, packetInCount, 0) @@ -406,6 +408,13 @@ signals: */ void gameLoopRateChanged(); + /**jsdoc + * Trigered when + * @function Stats.numPhysicsBodiesChanged + * @returns {Signal} + */ + void physicsBodyCountChanged(); + /**jsdoc * Triggered when the value of the avatarCount property changes. * @function Stats.avatarCountChanged diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 92ae3d546d..8c7b63e046 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -93,6 +93,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { btCollisionShape* shape = const_cast(motionState->getShape()); assert(shape); body = new btRigidBody(mass, motionState, shape, inertia); + ++_numRigidBodies; motionState->setRigidBody(body); } else { body->setMassProps(mass, inertia); @@ -116,6 +117,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { shape->calculateLocalInertia(mass, inertia); if (!body) { body = new btRigidBody(mass, motionState, shape, inertia); + ++_numRigidBodies; motionState->setRigidBody(body); } else { body->setMassProps(mass, inertia); @@ -139,6 +141,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { if (!body) { assert(motionState->getShape()); body = new btRigidBody(mass, motionState, const_cast(motionState->getShape()), inertia); + ++_numRigidBodies; motionState->setRigidBody(body); } else { body->setMassProps(mass, inertia); @@ -206,6 +209,7 @@ void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) { if (body) { removeDynamicsForBody(body); _dynamicsWorld->removeRigidBody(body); + --_numRigidBodies; // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); @@ -223,6 +227,7 @@ void PhysicsEngine::removeSetOfObjects(const SetOfMotionStates& objects) { if (body) { removeDynamicsForBody(body); _dynamicsWorld->removeRigidBody(body); + --_numRigidBodies; // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); @@ -274,6 +279,7 @@ void PhysicsEngine::reinsertObject(ObjectMotionState* object) { btRigidBody* body = object->getRigidBody(); if (body) { _dynamicsWorld->removeRigidBody(body); + --_numRigidBodies; // add it back addObjectToDynamicsWorld(object); } @@ -286,6 +292,7 @@ void PhysicsEngine::processTransaction(PhysicsEngine::Transaction& transaction) if (body) { removeDynamicsForBody(body); _dynamicsWorld->removeRigidBody(body); + --_numRigidBodies; // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 0f40a06825..74e0c046a1 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -143,6 +143,8 @@ public: // See PhysicsCollisionGroups.h for mask flags. std::vector contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group = USER_COLLISION_GROUP_DYNAMIC) const; + int32_t getNumRigidBodies() const { return _numRigidBodies; } + private: QList removeDynamicsForBody(btRigidBody* body); void addObjectToDynamicsWorld(ObjectMotionState* motionState); @@ -174,7 +176,8 @@ private: CharacterController* _myAvatarController; - uint32_t _numContactFrames = 0; + uint32_t _numContactFrames { 0 }; + int32_t _numRigidBodies { 0 }; bool _dumpNextStats { false }; bool _saveNextStats { false }; From 8f2141b59237b5bb66cbede01f49cd22a993612f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 21 Aug 2018 09:19:29 -0700 Subject: [PATCH 17/23] fix compile error --- interface/src/avatar/AvatarManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 86daf94bfa..3112b6e8bd 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -478,7 +478,7 @@ void AvatarManager::deleteAllAvatars() { QReadLocker locker(&_hashLock); AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { - auto avatar = std::static_pointer_cast(avatarIterator.value()); + auto avatar = std::static_pointer_cast(avatarIterator.value()); avatarIterator = _avatarHash.erase(avatarIterator); avatar->die(); assert(!avatar->_motionState); From abf4a926d8688230871cc385c397b483c9dde93f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 21 Aug 2018 15:16:54 -0700 Subject: [PATCH 18/23] cleanup --- interface/src/workload/PhysicsBoundary.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/workload/PhysicsBoundary.h b/interface/src/workload/PhysicsBoundary.h index e4d0411104..bc1e851285 100644 --- a/interface/src/workload/PhysicsBoundary.h +++ b/interface/src/workload/PhysicsBoundary.h @@ -7,8 +7,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_PhysicsGatekeeper_h -#define hifi_PhysicsGatekeeper_h +#ifndef hifi_PhysicsBoundary_h +#define hifi_PhysicsBoundary_h #include #include @@ -18,11 +18,11 @@ public: using Config = workload::Job::Config; using Inputs = workload::RegionTracker::Outputs; using Outputs = bool; - using JobModel = workload::Job::ModelI; // this doesn't work + using JobModel = workload::Job::ModelI; PhysicsBoundary() {} void configure(const Config& config) { } void run(const workload::WorkloadContextPointer& context, const Inputs& inputs); }; -#endif // hifi_PhysicsGatekeeper_h +#endif // hifi_PhysicsBoundary_h From 10d0833c19c4eadd9bf9cfafeb4ee9badeeecd81 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 23 Aug 2018 15:57:54 -0700 Subject: [PATCH 19/23] use DynamicsWorld::numCollisionObjects instead of our own count --- interface/resources/qml/Stats.qml | 2 +- interface/src/Application.cpp | 4 ++-- interface/src/Application.h | 2 +- interface/src/ui/Stats.cpp | 2 +- interface/src/ui/Stats.h | 6 +++--- libraries/physics/src/PhysicsEngine.cpp | 11 ++++------- libraries/physics/src/PhysicsEngine.h | 4 +--- 7 files changed, 13 insertions(+), 18 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index d89e3333e6..54798f8762 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -61,7 +61,7 @@ Item { text: "Game Rate: " + root.gameLoopRate } StatText { - text: "Physics Body Count: " + root.physicsBodyCount + text: "Physics Object Count: " + root.physicsObjectCount } StatText { visible: root.expanded diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9057bdea28..b27af7316f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6184,8 +6184,8 @@ bool Application::isHMDMode() const { return getActiveDisplayPlugin()->isHmd(); } -float Application::getNumRigidBodies() const { - return _physicsEngine ? _physicsEngine->getNumRigidBodies() : 0; +float Application::getNumCollisionObjects() const { + return _physicsEngine ? _physicsEngine->getNumCollisionObjects() : 0; } float Application::getTargetRenderFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index e415b28343..ae7e686f35 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -207,7 +207,7 @@ public: size_t getRenderFrameCount() const { return _renderFrameCount; } float getRenderLoopRate() const { return _renderLoopCounter.rate(); } - float getNumRigidBodies() const; + float getNumCollisionObjects() const; float getTargetRenderFrameRate() const; // frames/second float getFieldOfView() { return _fieldOfView.get(); } diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 9c1e1802c7..557635469b 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -121,7 +121,7 @@ void Stats::updateStats(bool force) { auto avatarManager = DependencyManager::get(); // we need to take one avatar out so we don't include ourselves STAT_UPDATE(avatarCount, avatarManager->size() - 1); - STAT_UPDATE(physicsBodyCount, qApp->getNumRigidBodies()); + STAT_UPDATE(physicsObjectCount, qApp->getNumCollisionObjects()); STAT_UPDATE(updatedAvatarCount, avatarManager->getNumAvatarsUpdated()); STAT_UPDATE(notUpdatedAvatarCount, avatarManager->getNumAvatarsNotUpdated()); STAT_UPDATE(serverCount, (int)nodeList->size()); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 35eeb78caa..84a114b72d 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -49,7 +49,7 @@ private: \ * @property {number} presentdroprate - Read-only. * @property {number} gameLoopRate - Read-only. * @property {number} avatarCount - Read-only. - * @property {number} physicsBodyCount - Read-only. + * @property {number} physicsObjectCount - Read-only. * @property {number} updatedAvatarCount - Read-only. * @property {number} notUpdatedAvatarCount - Read-only. * @property {number} packetInCount - Read-only. @@ -196,7 +196,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(float, presentdroprate, 0) STATS_PROPERTY(int, gameLoopRate, 0) STATS_PROPERTY(int, avatarCount, 0) - STATS_PROPERTY(int, physicsBodyCount, 0) + STATS_PROPERTY(int, physicsObjectCount, 0) STATS_PROPERTY(int, updatedAvatarCount, 0) STATS_PROPERTY(int, notUpdatedAvatarCount, 0) STATS_PROPERTY(int, packetInCount, 0) @@ -413,7 +413,7 @@ signals: * @function Stats.numPhysicsBodiesChanged * @returns {Signal} */ - void physicsBodyCountChanged(); + void physicsObjectCountChanged(); /**jsdoc * Triggered when the value of the avatarCount property changes. diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 8c7b63e046..d5ce60bef9 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -77,6 +77,10 @@ uint32_t PhysicsEngine::getNumSubsteps() const { return _dynamicsWorld->getNumSubsteps(); } +int32_t PhysicsEngine::getNumCollisionObjects() const { + return _dynamicsWorld ? _dynamicsWorld->getNumCollisionObjects() : 0; +} + // private void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { assert(motionState); @@ -93,7 +97,6 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { btCollisionShape* shape = const_cast(motionState->getShape()); assert(shape); body = new btRigidBody(mass, motionState, shape, inertia); - ++_numRigidBodies; motionState->setRigidBody(body); } else { body->setMassProps(mass, inertia); @@ -117,7 +120,6 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { shape->calculateLocalInertia(mass, inertia); if (!body) { body = new btRigidBody(mass, motionState, shape, inertia); - ++_numRigidBodies; motionState->setRigidBody(body); } else { body->setMassProps(mass, inertia); @@ -141,7 +143,6 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { if (!body) { assert(motionState->getShape()); body = new btRigidBody(mass, motionState, const_cast(motionState->getShape()), inertia); - ++_numRigidBodies; motionState->setRigidBody(body); } else { body->setMassProps(mass, inertia); @@ -209,7 +210,6 @@ void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) { if (body) { removeDynamicsForBody(body); _dynamicsWorld->removeRigidBody(body); - --_numRigidBodies; // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); @@ -227,7 +227,6 @@ void PhysicsEngine::removeSetOfObjects(const SetOfMotionStates& objects) { if (body) { removeDynamicsForBody(body); _dynamicsWorld->removeRigidBody(body); - --_numRigidBodies; // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); @@ -279,7 +278,6 @@ void PhysicsEngine::reinsertObject(ObjectMotionState* object) { btRigidBody* body = object->getRigidBody(); if (body) { _dynamicsWorld->removeRigidBody(body); - --_numRigidBodies; // add it back addObjectToDynamicsWorld(object); } @@ -292,7 +290,6 @@ void PhysicsEngine::processTransaction(PhysicsEngine::Transaction& transaction) if (body) { removeDynamicsForBody(body); _dynamicsWorld->removeRigidBody(body); - --_numRigidBodies; // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 74e0c046a1..317f7ef312 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -87,6 +87,7 @@ public: void init(); uint32_t getNumSubsteps() const; + int32_t getNumCollisionObjects() const; void removeObjects(const VectorOfMotionStates& objects); void removeSetOfObjects(const SetOfMotionStates& objects); // only called during teardown @@ -143,8 +144,6 @@ public: // See PhysicsCollisionGroups.h for mask flags. std::vector contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group = USER_COLLISION_GROUP_DYNAMIC) const; - int32_t getNumRigidBodies() const { return _numRigidBodies; } - private: QList removeDynamicsForBody(btRigidBody* body); void addObjectToDynamicsWorld(ObjectMotionState* motionState); @@ -177,7 +176,6 @@ private: CharacterController* _myAvatarController; uint32_t _numContactFrames { 0 }; - int32_t _numRigidBodies { 0 }; bool _dumpNextStats { false }; bool _saveNextStats { false }; From 1263db568823c5577bd7fa1cddf897acd7711c5a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Aug 2018 16:08:16 -0700 Subject: [PATCH 20/23] force NL reset if the domain changes session ID or local ID --- libraries/networking/src/NodeList.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index dd351ef940..4e8cbbf9db 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -273,6 +273,7 @@ void NodeList::reset(bool skipDomainHandlerReset) { // refresh the owner UUID to the NULL UUID setSessionUUID(QUuid()); + setSessionLocalID(Node::NULL_LOCAL_ID); // if we setup the DTLS socket, also disconnect from the DTLS socket readyRead() so it can handle handshaking if (_dtlsSocket) { @@ -647,6 +648,17 @@ void NodeList::processDomainServerList(QSharedPointer message) Node::LocalID newLocalID; packetStream >> newUUID; packetStream >> newLocalID; + + // when connected, if the session ID or local ID were not null and changed, we should reset + auto currentLocalID = getSessionLocalID(); + auto currentSessionID = getSessionUUID(); + if (_domainHandler.isConnected() && + ((currentLocalID != Node::NULL_LOCAL_ID && newLocalID != currentLocalID) || + (!currentSessionID.isNull() && newUUID != currentSessionID))) { + qCDebug(networking) << "Local ID or Session ID changed while connected to domain - forcing NodeList reset"; + reset(true); + } + setSessionLocalID(newLocalID); setSessionUUID(newUUID); From cb4ce4fedb8bc6155b71ae08ad074037b750defd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Aug 2018 13:05:04 -0700 Subject: [PATCH 21/23] make sure settings are re-requested on new connection --- libraries/networking/src/NodeList.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 4e8cbbf9db..e458ffab7e 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -656,7 +656,13 @@ void NodeList::processDomainServerList(QSharedPointer message) ((currentLocalID != Node::NULL_LOCAL_ID && newLocalID != currentLocalID) || (!currentSessionID.isNull() && newUUID != currentSessionID))) { qCDebug(networking) << "Local ID or Session ID changed while connected to domain - forcing NodeList reset"; + + // reset the nodelist, but don't do a domain handler reset since we're about to process a good domain list reset(true); + + // tell the domain handler that we're no longer connected so that below + // it can re-perform actions as if we just connected + _domainHandler.setIsConnected(false); } setSessionLocalID(newLocalID); From d8b5a1a4a6ddd80ec02ce3bce8911c6ff9d9766a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Aug 2018 14:21:54 -0700 Subject: [PATCH 22/23] always remove old socket-matching node before add --- domain-server/src/DomainGatekeeper.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 2307b1be3b..e23d9e57a8 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -463,19 +463,15 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect limitedNodeList->eachNodeBreakable([nodeConnection, username, &existingNodeID](const SharedNodePointer& node){ if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) { - // we have a node that already has these exact sockets - this can occur if a node - // is failing to connect to the domain - - // we'll re-use the existing node ID - // as long as the user hasn't changed their username (by logging in or logging out) - auto existingNodeData = static_cast(node->getLinkedData()); - - if (existingNodeData->getUsername() == username) { - qDebug() << "Deleting existing connection from same sockaddr: " << node->getUUID(); - existingNodeID = node->getUUID(); - return false; - } + // we have a node that already has these exact sockets + // this can occur if a node is failing to connect to the domain + + // remove the old node before adding the new node + qDebug() << "Deleting existing connection from same sockaddr: " << node->getUUID(); + existingNodeID = node->getUUID(); + return false; } + return true; }); From ff6020e0ef2489f3cfbe5e883d1688b73a0b3971 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 24 Aug 2018 15:41:25 -0700 Subject: [PATCH 23/23] fix compile errors, maybe --- libraries/render-utils/src/Model.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 4fc8e265ab..71250c6483 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -319,7 +319,7 @@ bool Model::updateGeometry() { // Interleave normals and tangents // Parallel version for performance - tbb::parallel_for(tbb::blocked_range(0, mesh.normals.size()), [&](const tbb::blocked_range& range) { + tbb::parallel_for(tbb::blocked_range(0, mesh.normals.size()), [&](const tbb::blocked_range& range) { auto normalsRange = std::make_pair(mesh.normals.begin() + range.begin(), mesh.normals.begin() + range.end()); auto tangentsRange = std::make_pair(mesh.tangents.begin() + range.begin(), mesh.tangents.begin() + range.end()); auto normalsAndTangentsIt = normalsAndTangents.begin() + 2 * range.begin(); @@ -1281,7 +1281,7 @@ void Blender::run() { } float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE; const FBXBlendshape& blendshape = mesh.blendshapes.at(i); - tbb::parallel_for(tbb::blocked_range(0, blendshape.indices.size()), [&](const tbb::blocked_range& range) { + tbb::parallel_for(tbb::blocked_range(0, blendshape.indices.size()), [&](const tbb::blocked_range& range) { for (auto j = range.begin(); j < range.end(); j++) { int index = blendshape.indices.at(j); meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient;