//// Item.h// render/src/render//// Created by Sam Gateau on 1/26/16.// Copyright 2014 High Fidelity, Inc.// Copyright 2024 Overte e.V.//// 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_Item_h#define hifi_render_Item_h #include <atomic>#include <bitset>#include <map>#include <memory>#include <mutex>#include <queue>#include <set>#include <vector> #include <AABox.h> #include "Args.h" #include <graphics/Material.h>#include "ShapePipeline.h" #include "BlendshapeConstants.h"#include "HighlightStyle.h"#include "FadeProperties.h" namespace render { typedef int32_t Index;const Index INVALID_INDEX{ -1 }; class Context; // Key is the KEY to filter Items and create specialized listsclass ItemKey {public: // 8 tags are available to organize the items and filter them against as fields of the ItemKey. // TAG & TAG_BITS are defined from several bits in the Key. // An Item can be tagged and filtering can rely on the tags to keep or exclude items // ItemKey are not taged by default enum Tag : uint8_t { TAG_0 = 0, // 8 Tags TAG_1, TAG_2, TAG_3, TAG_4, TAG_5, TAG_6, TAG_7, NUM_TAGS, // Tag bits are derived from the Tag enum TAG_BITS_ALL = 0xFF, TAG_BITS_NONE = 0x00, TAG_BITS_0 = 0x01, TAG_BITS_1 = 0x02, TAG_BITS_2 = 0x04, TAG_BITS_3 = 0x08, TAG_BITS_4 = 0x10, TAG_BITS_5 = 0x20, TAG_BITS_6 = 0x40, TAG_BITS_7 = 0x80, }; // Items are organized in layers, an item belongs to one of the 8 Layers available. // By default an item is in the 'LAYER_DEFAULT' meaning that it is NOT layered. // THere is NO ordering relationship between layers. enum Layer : uint8_t { LAYER_DEFAULT = 0, // layer 0 aka Default is a 'NOT' layer, items are not considered layered, this is the default value LAYER_1, LAYER_2, LAYER_3, LAYER_4, LAYER_5, LAYER_6, LAYER_BACKGROUND, // Last Layer is the background by convention NUM_LAYERS, // Layer bits are derived from the Layer enum, the number of bits needed to represent integer 0 to NUM_LAYERS NUM_LAYER_BITS = 3, LAYER_BITS_ALL = 0x07, }; enum FlagBit : uint32_t { TYPE_SHAPE = 0, // Item is a Shape: Implements the Shape Interface that draw a Geometry rendered with a Material TYPE_LIGHT, // Item is a Light: Implements the Light Interface that TYPE_CAMERA, // Item is a Camera: Implements the Camera Interface TYPE_META, // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work... VIEW_SPACE, // Transformed in view space, and not in world space DYNAMIC, // Dynamic and bound will change unlike static item DEFORMED, // Deformed within bound, not solid INVISIBLE, // Visible or not in the scene? SHADOW_CASTER, // Item cast shadows META_CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the view SUB_META_CULLED, // As a sub item of a meta render item set as cull group, need to be set to my culling to the meta render it FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS, FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS, MIRROR, // Item is a mirror SIMULATE, // Item requires simulation OUTLINE, // Item has an outline __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) NUM_FLAGS, // Not a valid flag }; typedef std::bitset<NUM_FLAGS> Flags; // All the bits touching tag bits sets to true const static uint32_t KEY_TAG_BITS_MASK; static uint32_t evalTagBitsWithKeyBits(uint8_t tagBits, const uint32_t keyBits) { return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT); } // All the bits touching layer bits sets to true const static uint32_t KEY_LAYER_BITS_MASK; static uint32_t evalLayerBitsWithKeyBits(uint8_t layer, const uint32_t keyBits) { return (keyBits & ~KEY_LAYER_BITS_MASK) | (((uint32_t)layer & LAYER_BITS_ALL) << FIRST_LAYER_BIT); } // The key is the Flags Flags _flags; ItemKey() : _flags(0) {} ItemKey(const Flags& flags) : _flags(flags) {} bool operator== (const ItemKey& rhs) const { return _flags == rhs._flags; } bool operator!= (const ItemKey& rhs) const { return _flags != rhs._flags; } class Builder { friend class ItemKey; Flags _flags{ 0 }; public: Builder() {} Builder(const ItemKey& key) : _flags{ key._flags } {} ItemKey build() const { return ItemKey(_flags); } Builder& withTypeShape() { _flags.set(TYPE_SHAPE); return (*this); } Builder& withTypeLight() { _flags.set(TYPE_LIGHT); return (*this); } Builder& withTypeMeta() { _flags.set(TYPE_META); return (*this); } Builder& withTransparent() { _flags.set(TRANSLUCENT); return (*this); } Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); } Builder& withoutViewSpace() { _flags.reset(VIEW_SPACE); return (*this); } Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); } Builder& withDeformed() { _flags.set(DEFORMED); return (*this); } Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); } Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } Builder& withoutShadowCaster() { _flags.reset(SHADOW_CASTER); return (*this); } Builder& withMetaCullGroup() { _flags.set(META_CULL_GROUP); return (*this); } Builder& withoutMetaCullGroup() { _flags.reset(META_CULL_GROUP); return (*this); } Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); } Builder& withoutSubMetaCulled() { _flags.reset(SUB_META_CULLED); return (*this); } Builder& withMirror() { _flags.set(MIRROR); return (*this); } Builder& withSimulate() { _flags.set(SIMULATE); return (*this); } Builder& withTag(Tag tag) { _flags.set(static_cast<size_t>(FIRST_TAG_BIT) + static_cast<size_t>(tag)); return (*this); } // Set ALL the tags in one call using the Tag bits Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong()); return (*this); } Builder& withLayer(uint8_t layer) { _flags = evalLayerBitsWithKeyBits(layer, _flags.to_ulong()); return (*this); } Builder& withoutLayer() { return withLayer(LAYER_DEFAULT); } Builder& withOutline() { _flags.set(OUTLINE); return (*this); } Builder& withoutOutline() { _flags.reset(OUTLINE); return (*this); } // Convenient standard keys that we will keep on using all over the place static Builder opaqueShape() { return Builder().withTypeShape(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); } static Builder light() { return Builder().withTypeLight(); } static Builder background() { return Builder().withViewSpace().withLayer(LAYER_BACKGROUND); } }; ItemKey(const Builder& builder) : ItemKey(builder._flags) {} bool isShape() const { return _flags[TYPE_SHAPE]; } bool isLight() const { return _flags[TYPE_LIGHT]; } bool isMeta() const { return _flags[TYPE_META]; } bool isOpaque() const { return !_flags[TRANSLUCENT]; } bool isTransparent() const { return _flags[TRANSLUCENT]; } bool isWorldSpace() const { return !_flags[VIEW_SPACE]; } bool isViewSpace() const { return _flags[VIEW_SPACE]; } bool isStatic() const { return !_flags[DYNAMIC]; } bool isDynamic() const { return _flags[DYNAMIC]; } bool isRigid() const { return !_flags[DEFORMED]; } bool isDeformed() const { return _flags[DEFORMED]; } bool isVisible() const { return !_flags[INVISIBLE]; } bool isInvisible() const { return _flags[INVISIBLE]; } bool isShadowCaster() const { return _flags[SHADOW_CASTER]; } bool isMetaCullGroup() const { return _flags[META_CULL_GROUP]; } void setMetaCullGroup(bool cullGroup) { (cullGroup ? _flags.set(META_CULL_GROUP) : _flags.reset(META_CULL_GROUP)); } bool isSubMetaCulled() const { return _flags[SUB_META_CULLED]; } void setSubMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(SUB_META_CULLED) : _flags.reset(SUB_META_CULLED)); } bool isNotMirror() const { return !_flags[MIRROR]; } bool isMirror() const { return _flags[MIRROR]; } bool isNotSimulate() const { return !_flags[SIMULATE]; } bool isSimulate() const { return _flags[SIMULATE]; } bool isTag(Tag tag) const { return _flags[static_cast<size_t>(FIRST_TAG_BIT) + static_cast<size_t>(tag)]; } uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } uint8_t getLayer() const { return ((_flags.to_ulong() & KEY_LAYER_BITS_MASK) >> FIRST_LAYER_BIT); } bool isLayer(uint8_t layer) const { return getLayer() == layer; } bool isLayered() const { return getLayer() != LAYER_DEFAULT; } bool isSpatial() const { return !isLayered(); } bool isOutline() const { return _flags[OUTLINE]; } // Probably not public, flags used by the scene bool isSmall() const { return _flags[__SMALLER]; } void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); } bool operator==(const ItemKey& key) { return (_flags == key._flags); } bool operator!=(const ItemKey& key) { return (_flags != key._flags); }};using ItemKeys = std::vector<ItemKey>; inline QDebug operator<<(QDebug debug, const ItemKey& itemKey) { debug << "[ItemKey: isOpaque:" << itemKey.isOpaque() << ", isStatic:" << itemKey.isStatic() << ", isWorldSpace:" << itemKey.isWorldSpace() << "]"; return debug;} class ItemFilter {public: ItemKey::Flags _value{ 0 }; ItemKey::Flags _mask{ 0 }; ItemFilter(const ItemKey::Flags& value = ItemKey::Flags(0), const ItemKey::Flags& mask = ItemKey::Flags(0)) : _value(value), _mask(mask) {} class Builder { friend class ItemFilter; ItemKey::Flags _value{ 0 }; ItemKey::Flags _mask{ 0 }; public: Builder() {} Builder(const ItemFilter& srcFilter) : _value(srcFilter._value), _mask(srcFilter._mask) {} ItemFilter build() const { return ItemFilter(_value, _mask); } Builder& withTypeShape() { _value.set(ItemKey::TYPE_SHAPE); _mask.set(ItemKey::TYPE_SHAPE); return (*this); } Builder& withTypeLight() { _value.set(ItemKey::TYPE_LIGHT); _mask.set(ItemKey::TYPE_LIGHT); return (*this); } Builder& withTypeMeta() { _value.set(ItemKey::TYPE_META); _mask.set(ItemKey::TYPE_META); return (*this); } Builder& withOpaque() { _value.reset(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); } Builder& withTransparent() { _value.set(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); } Builder& withWorldSpace() { _value.reset(ItemKey::VIEW_SPACE); _mask.set(ItemKey::VIEW_SPACE); return (*this); } Builder& withViewSpace() { _value.set(ItemKey::VIEW_SPACE); _mask.set(ItemKey::VIEW_SPACE); return (*this); } Builder& withStatic() { _value.reset(ItemKey::DYNAMIC); _mask.set(ItemKey::DYNAMIC); return (*this); } Builder& withDynamic() { _value.set(ItemKey::DYNAMIC); _mask.set(ItemKey::DYNAMIC); return (*this); } Builder& withRigid() { _value.reset(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); } Builder& withDeformed() { _value.set(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); } Builder& withVisible() { _value.reset(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); } Builder& withInvisible() { _value.set(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); } Builder& withNoShadowCaster() { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } Builder& withShadowCaster() { _value.set(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } Builder& withoutMetaCullGroup() { _value.reset(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } Builder& withoutSubMetaCulled() { _value.reset(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } Builder& withoutMirror() { _value.reset(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } Builder& withMirror() { _value.set(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } Builder& withoutSimulate() { _value.reset(ItemKey::SIMULATE); _mask.set(ItemKey::SIMULATE); return (*this); } Builder& withSimulate() { _value.set(ItemKey::SIMULATE); _mask.set(ItemKey::SIMULATE); return (*this); } Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(static_cast<size_t>(ItemKey::FIRST_TAG_BIT) + static_cast<size_t>(tagIndex)); _mask.set(static_cast<size_t>(ItemKey::FIRST_TAG_BIT) + static_cast<size_t>(tagIndex)); return (*this); } Builder& withTag(ItemKey::Tag tagIndex) { _value.set(static_cast<size_t>(ItemKey::FIRST_TAG_BIT) + static_cast<size_t>(tagIndex)); _mask.set(static_cast<size_t>(ItemKey::FIRST_TAG_BIT) + static_cast<size_t>(tagIndex)); return (*this); } // Set ALL the tags in one call using the Tag bits and the Tag bits touched Builder& withTagBits(uint8_t tagBits, uint8_t tagMask) { _value = ItemKey::evalTagBitsWithKeyBits(tagBits, _value.to_ulong()); _mask = ItemKey::evalTagBitsWithKeyBits(tagMask, _mask.to_ulong()); return (*this); } Builder& withoutLayered() { _value = ItemKey::evalLayerBitsWithKeyBits(ItemKey::LAYER_DEFAULT, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); } Builder& withLayer(uint8_t layer) { _value = ItemKey::evalLayerBitsWithKeyBits(layer, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); } Builder& withoutOutline() { _value.reset(ItemKey::OUTLINE); _mask.set(ItemKey::OUTLINE); return (*this); } Builder& withOutline() { _value.set(ItemKey::OUTLINE); _mask.set(ItemKey::OUTLINE); return (*this); } Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); } // Convenient standard keys that we will keep on using all over the place static Builder visibleWorldItems() { return Builder().withVisible().withWorldSpace(); } static Builder opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); } static Builder light() { return Builder().withTypeLight(); } static Builder meta() { return Builder().withTypeMeta(); } static Builder mirror() { return Builder().withMirror(); } static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); } static Builder nothing() { return Builder().withNothing(); } }; ItemFilter(const Builder& builder) : ItemFilter(builder._value, builder._mask) {} // Item Filter operator testing if a key pass the filter bool test(const ItemKey& key) const { return (key._flags & _mask) == (_value & _mask); } bool selectsNothing() const { return !_mask.any(); } class Less { public: bool operator() (const ItemFilter& left, const ItemFilter& right) const { if (left._value.to_ulong() == right._value.to_ulong()) { return left._mask.to_ulong() < right._mask.to_ulong(); } else { return left._value.to_ulong() < right._value.to_ulong(); } } };}; inline QDebug operator<<(QDebug debug, const ItemFilter& me) { debug << "[ItemFilter: opaqueShape:" << me.test(ItemKey::Builder::opaqueShape().build()) << "]"; return debug;} // Handy type to just pass the ID and the bound of an itemclass ItemBound { public: ItemBound() {} ItemBound(ItemID id) : id(id) { } ItemBound(ItemID id, const AABox& bound) : id(id), bound(bound) { } ItemID id { 0 }; AABox bound; uint32_t padding { 0 };}; // many Item Bounds in a vectorusing ItemBounds = std::vector<ItemBound>; // Item is the proxy to a bounded "object" in the scene// An item is described by its Keyclass Item {public: typedef std::vector<Item> Vector; typedef ItemID ID; static const ID INVALID_ITEM_ID; static const ItemCell INVALID_CELL; // Convenient function to clear an ID or check it s valid static void clearID(ID& id) { id = INVALID_ITEM_ID; } static bool isValidID(const ID id) { return id != INVALID_ITEM_ID; } // Bound is the AABBox fully containing this item typedef AABox Bound; // Status records the life history and performances of this item while performing at rendering and updating. // This is Used for monitoring and dynamically adjust the quality class Status { public: enum class Icon { ACTIVE_IN_BULLET = 0, PACKET_SENT = 1, PACKET_RECEIVED = 2, SIMULATION_OWNER = 3, HAS_ACTIONS = 4, OTHER_SIMULATION_OWNER = 5, ENTITY_HOST_TYPE = 6, GENERIC_TRANSITION = 7, GENERIC_TRANSITION_OUT = 8, GENERIC_TRANSITION_IN = 9, USER_TRANSITION_OUT = 10, USER_TRANSITION_IN = 11, NONE = 255 }; // Status::Value class is the data used to represent the transient information of a status as a square icon // The "icon" is a square displayed in the 3D scene over the render::Item AABB center. // It can be scaled in the range [0, 1] and the color hue in the range [0, 360] representing the color wheel hue class Value { unsigned short _scale = 0xFFFF; unsigned char _color = 0xFF; unsigned char _icon = 0xFF; public: const static Value INVALID; // Invalid value meanss the status won't show Value() {} Value(float scale, float hue, unsigned char icon = 0xFF) { setScale(scale); setColor(hue); setIcon(icon); } // It can be scaled in the range [0, 1] void setScale(float scale); // the color hue in the range [0, 360] representing the color wheel hue void setColor(float hue); // the icon to display in the range [0, 255], where 0 means no icon, just filled quad and anything else would // hopefully have an icon available to display (see DrawStatusJob) void setIcon(unsigned char icon); // Standard color Hue static const float RED; // 0.0f; static const float YELLOW; // 60.0f; static const float GREEN; // 120.0f; static const float CYAN; // 180.0f; static const float BLUE; // 240.0f; static const float MAGENTA; // 300.0f; // Retreive the Value data tightely packed as an int int getPackedData() const { return *((const int*) this); } }; typedef std::function<Value()> Getter; typedef std::vector<Getter> Getters; Getters _values; void addGetter(const Getter& getter) { _values.push_back(getter); } size_t getNumValues() const { return _values.size(); } using Values = std::vector <Value>; Values getCurrentValues() const; }; typedef std::shared_ptr<Status> StatusPointer; // Update Functor class UpdateFunctorInterface { public: virtual ~UpdateFunctorInterface() {} }; typedef std::shared_ptr<UpdateFunctorInterface> UpdateFunctorPointer; // Payload is whatever is in this Item and implement the Payload Interface class PayloadInterface { public: virtual const ItemKey getKey() const = 0; virtual const Bound getBound(RenderArgs* args) const = 0; virtual void render(RenderArgs* args) = 0; virtual void renderSimulate(RenderArgs* args) = 0; virtual const ShapeKey getShapeKey() const = 0; virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const = 0; virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0; virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const = 0; virtual FadeProperties getFadeProperties(const TransitionType type) const = 0; ~PayloadInterface() {} // Status interface is local to the base class const StatusPointer& getStatus() const { return _status; } void addStatusGetter(const Status::Getter& getter); void addStatusGetters(const Status::Getters& getters); protected: StatusPointer _status; friend class Item; virtual void update(const UpdateFunctorPointer& functor) = 0; }; typedef std::shared_ptr<PayloadInterface> PayloadPointer; Item() {} ~Item() {} // Item exists if it has a valid payload bool exist() const { return (bool)(_payload); } Lines 1–500 of 727. Load more
// // Item.h // render/src/render // // Created by Sam Gateau on 1/26/16. // Copyright 2014 High Fidelity, Inc. // Copyright 2024 Overte e.V. // // 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_Item_h #define hifi_render_Item_h #include <atomic> #include <bitset> #include <map> #include <memory> #include <mutex> #include <queue> #include <set> #include <vector> #include <AABox.h> #include "Args.h" #include <graphics/Material.h> #include "ShapePipeline.h" #include "BlendshapeConstants.h" #include "HighlightStyle.h" #include "FadeProperties.h" namespace render { typedef int32_t Index; const Index INVALID_INDEX{ -1 }; class Context; // Key is the KEY to filter Items and create specialized lists class ItemKey { public: // 8 tags are available to organize the items and filter them against as fields of the ItemKey. // TAG & TAG_BITS are defined from several bits in the Key. // An Item can be tagged and filtering can rely on the tags to keep or exclude items // ItemKey are not taged by default enum Tag : uint8_t { TAG_0 = 0, // 8 Tags TAG_1, TAG_2, TAG_3, TAG_4, TAG_5, TAG_6, TAG_7, NUM_TAGS, // Tag bits are derived from the Tag enum TAG_BITS_ALL = 0xFF, TAG_BITS_NONE = 0x00, TAG_BITS_0 = 0x01, TAG_BITS_1 = 0x02, TAG_BITS_2 = 0x04, TAG_BITS_3 = 0x08, TAG_BITS_4 = 0x10, TAG_BITS_5 = 0x20, TAG_BITS_6 = 0x40, TAG_BITS_7 = 0x80, }; // Items are organized in layers, an item belongs to one of the 8 Layers available. // By default an item is in the 'LAYER_DEFAULT' meaning that it is NOT layered. // THere is NO ordering relationship between layers. enum Layer : uint8_t { LAYER_DEFAULT = 0, // layer 0 aka Default is a 'NOT' layer, items are not considered layered, this is the default value LAYER_1, LAYER_2, LAYER_3, LAYER_4, LAYER_5, LAYER_6, LAYER_BACKGROUND, // Last Layer is the background by convention NUM_LAYERS, // Layer bits are derived from the Layer enum, the number of bits needed to represent integer 0 to NUM_LAYERS NUM_LAYER_BITS = 3, LAYER_BITS_ALL = 0x07, }; enum FlagBit : uint32_t { TYPE_SHAPE = 0, // Item is a Shape: Implements the Shape Interface that draw a Geometry rendered with a Material TYPE_LIGHT, // Item is a Light: Implements the Light Interface that TYPE_CAMERA, // Item is a Camera: Implements the Camera Interface TYPE_META, // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work... VIEW_SPACE, // Transformed in view space, and not in world space DYNAMIC, // Dynamic and bound will change unlike static item DEFORMED, // Deformed within bound, not solid INVISIBLE, // Visible or not in the scene? SHADOW_CASTER, // Item cast shadows META_CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the view SUB_META_CULLED, // As a sub item of a meta render item set as cull group, need to be set to my culling to the meta render it FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS, FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS, MIRROR, // Item is a mirror SIMULATE, // Item requires simulation OUTLINE, // Item has an outline __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) NUM_FLAGS, // Not a valid flag }; typedef std::bitset<NUM_FLAGS> Flags; // All the bits touching tag bits sets to true const static uint32_t KEY_TAG_BITS_MASK; static uint32_t evalTagBitsWithKeyBits(uint8_t tagBits, const uint32_t keyBits) { return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT); } // All the bits touching layer bits sets to true const static uint32_t KEY_LAYER_BITS_MASK; static uint32_t evalLayerBitsWithKeyBits(uint8_t layer, const uint32_t keyBits) { return (keyBits & ~KEY_LAYER_BITS_MASK) | (((uint32_t)layer & LAYER_BITS_ALL) << FIRST_LAYER_BIT); } // The key is the Flags Flags _flags; ItemKey() : _flags(0) {} ItemKey(const Flags& flags) : _flags(flags) {} bool operator== (const ItemKey& rhs) const { return _flags == rhs._flags; } bool operator!= (const ItemKey& rhs) const { return _flags != rhs._flags; } class Builder { friend class ItemKey; Flags _flags{ 0 }; public: Builder() {} Builder(const ItemKey& key) : _flags{ key._flags } {} ItemKey build() const { return ItemKey(_flags); } Builder& withTypeShape() { _flags.set(TYPE_SHAPE); return (*this); } Builder& withTypeLight() { _flags.set(TYPE_LIGHT); return (*this); } Builder& withTypeMeta() { _flags.set(TYPE_META); return (*this); } Builder& withTransparent() { _flags.set(TRANSLUCENT); return (*this); } Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); } Builder& withoutViewSpace() { _flags.reset(VIEW_SPACE); return (*this); } Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); } Builder& withDeformed() { _flags.set(DEFORMED); return (*this); } Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); } Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } Builder& withoutShadowCaster() { _flags.reset(SHADOW_CASTER); return (*this); } Builder& withMetaCullGroup() { _flags.set(META_CULL_GROUP); return (*this); } Builder& withoutMetaCullGroup() { _flags.reset(META_CULL_GROUP); return (*this); } Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); } Builder& withoutSubMetaCulled() { _flags.reset(SUB_META_CULLED); return (*this); } Builder& withMirror() { _flags.set(MIRROR); return (*this); } Builder& withSimulate() { _flags.set(SIMULATE); return (*this); } Builder& withTag(Tag tag) { _flags.set(static_cast<size_t>(FIRST_TAG_BIT) + static_cast<size_t>(tag)); return (*this); } // Set ALL the tags in one call using the Tag bits Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong()); return (*this); } Builder& withLayer(uint8_t layer) { _flags = evalLayerBitsWithKeyBits(layer, _flags.to_ulong()); return (*this); } Builder& withoutLayer() { return withLayer(LAYER_DEFAULT); } Builder& withOutline() { _flags.set(OUTLINE); return (*this); } Builder& withoutOutline() { _flags.reset(OUTLINE); return (*this); } // Convenient standard keys that we will keep on using all over the place static Builder opaqueShape() { return Builder().withTypeShape(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); } static Builder light() { return Builder().withTypeLight(); } static Builder background() { return Builder().withViewSpace().withLayer(LAYER_BACKGROUND); } }; ItemKey(const Builder& builder) : ItemKey(builder._flags) {} bool isShape() const { return _flags[TYPE_SHAPE]; } bool isLight() const { return _flags[TYPE_LIGHT]; } bool isMeta() const { return _flags[TYPE_META]; } bool isOpaque() const { return !_flags[TRANSLUCENT]; } bool isTransparent() const { return _flags[TRANSLUCENT]; } bool isWorldSpace() const { return !_flags[VIEW_SPACE]; } bool isViewSpace() const { return _flags[VIEW_SPACE]; } bool isStatic() const { return !_flags[DYNAMIC]; } bool isDynamic() const { return _flags[DYNAMIC]; } bool isRigid() const { return !_flags[DEFORMED]; } bool isDeformed() const { return _flags[DEFORMED]; } bool isVisible() const { return !_flags[INVISIBLE]; } bool isInvisible() const { return _flags[INVISIBLE]; } bool isShadowCaster() const { return _flags[SHADOW_CASTER]; } bool isMetaCullGroup() const { return _flags[META_CULL_GROUP]; } void setMetaCullGroup(bool cullGroup) { (cullGroup ? _flags.set(META_CULL_GROUP) : _flags.reset(META_CULL_GROUP)); } bool isSubMetaCulled() const { return _flags[SUB_META_CULLED]; } void setSubMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(SUB_META_CULLED) : _flags.reset(SUB_META_CULLED)); } bool isNotMirror() const { return !_flags[MIRROR]; } bool isMirror() const { return _flags[MIRROR]; } bool isNotSimulate() const { return !_flags[SIMULATE]; } bool isSimulate() const { return _flags[SIMULATE]; } bool isTag(Tag tag) const { return _flags[static_cast<size_t>(FIRST_TAG_BIT) + static_cast<size_t>(tag)]; } uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } uint8_t getLayer() const { return ((_flags.to_ulong() & KEY_LAYER_BITS_MASK) >> FIRST_LAYER_BIT); } bool isLayer(uint8_t layer) const { return getLayer() == layer; } bool isLayered() const { return getLayer() != LAYER_DEFAULT; } bool isSpatial() const { return !isLayered(); } bool isOutline() const { return _flags[OUTLINE]; } // Probably not public, flags used by the scene bool isSmall() const { return _flags[__SMALLER]; } void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); } bool operator==(const ItemKey& key) { return (_flags == key._flags); } bool operator!=(const ItemKey& key) { return (_flags != key._flags); } }; using ItemKeys = std::vector<ItemKey>; inline QDebug operator<<(QDebug debug, const ItemKey& itemKey) { debug << "[ItemKey: isOpaque:" << itemKey.isOpaque() << ", isStatic:" << itemKey.isStatic() << ", isWorldSpace:" << itemKey.isWorldSpace() << "]"; return debug; } class ItemFilter { public: ItemKey::Flags _value{ 0 }; ItemKey::Flags _mask{ 0 }; ItemFilter(const ItemKey::Flags& value = ItemKey::Flags(0), const ItemKey::Flags& mask = ItemKey::Flags(0)) : _value(value), _mask(mask) {} class Builder { friend class ItemFilter; ItemKey::Flags _value{ 0 }; ItemKey::Flags _mask{ 0 }; public: Builder() {} Builder(const ItemFilter& srcFilter) : _value(srcFilter._value), _mask(srcFilter._mask) {} ItemFilter build() const { return ItemFilter(_value, _mask); } Builder& withTypeShape() { _value.set(ItemKey::TYPE_SHAPE); _mask.set(ItemKey::TYPE_SHAPE); return (*this); } Builder& withTypeLight() { _value.set(ItemKey::TYPE_LIGHT); _mask.set(ItemKey::TYPE_LIGHT); return (*this); } Builder& withTypeMeta() { _value.set(ItemKey::TYPE_META); _mask.set(ItemKey::TYPE_META); return (*this); } Builder& withOpaque() { _value.reset(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); } Builder& withTransparent() { _value.set(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); } Builder& withWorldSpace() { _value.reset(ItemKey::VIEW_SPACE); _mask.set(ItemKey::VIEW_SPACE); return (*this); } Builder& withViewSpace() { _value.set(ItemKey::VIEW_SPACE); _mask.set(ItemKey::VIEW_SPACE); return (*this); } Builder& withStatic() { _value.reset(ItemKey::DYNAMIC); _mask.set(ItemKey::DYNAMIC); return (*this); } Builder& withDynamic() { _value.set(ItemKey::DYNAMIC); _mask.set(ItemKey::DYNAMIC); return (*this); } Builder& withRigid() { _value.reset(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); } Builder& withDeformed() { _value.set(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); } Builder& withVisible() { _value.reset(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); } Builder& withInvisible() { _value.set(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); } Builder& withNoShadowCaster() { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } Builder& withShadowCaster() { _value.set(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } Builder& withoutMetaCullGroup() { _value.reset(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } Builder& withoutSubMetaCulled() { _value.reset(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } Builder& withoutMirror() { _value.reset(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } Builder& withMirror() { _value.set(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } Builder& withoutSimulate() { _value.reset(ItemKey::SIMULATE); _mask.set(ItemKey::SIMULATE); return (*this); } Builder& withSimulate() { _value.set(ItemKey::SIMULATE); _mask.set(ItemKey::SIMULATE); return (*this); } Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(static_cast<size_t>(ItemKey::FIRST_TAG_BIT) + static_cast<size_t>(tagIndex)); _mask.set(static_cast<size_t>(ItemKey::FIRST_TAG_BIT) + static_cast<size_t>(tagIndex)); return (*this); } Builder& withTag(ItemKey::Tag tagIndex) { _value.set(static_cast<size_t>(ItemKey::FIRST_TAG_BIT) + static_cast<size_t>(tagIndex)); _mask.set(static_cast<size_t>(ItemKey::FIRST_TAG_BIT) + static_cast<size_t>(tagIndex)); return (*this); } // Set ALL the tags in one call using the Tag bits and the Tag bits touched Builder& withTagBits(uint8_t tagBits, uint8_t tagMask) { _value = ItemKey::evalTagBitsWithKeyBits(tagBits, _value.to_ulong()); _mask = ItemKey::evalTagBitsWithKeyBits(tagMask, _mask.to_ulong()); return (*this); } Builder& withoutLayered() { _value = ItemKey::evalLayerBitsWithKeyBits(ItemKey::LAYER_DEFAULT, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); } Builder& withLayer(uint8_t layer) { _value = ItemKey::evalLayerBitsWithKeyBits(layer, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); } Builder& withoutOutline() { _value.reset(ItemKey::OUTLINE); _mask.set(ItemKey::OUTLINE); return (*this); } Builder& withOutline() { _value.set(ItemKey::OUTLINE); _mask.set(ItemKey::OUTLINE); return (*this); } Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); } // Convenient standard keys that we will keep on using all over the place static Builder visibleWorldItems() { return Builder().withVisible().withWorldSpace(); } static Builder opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); } static Builder light() { return Builder().withTypeLight(); } static Builder meta() { return Builder().withTypeMeta(); } static Builder mirror() { return Builder().withMirror(); } static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); } static Builder nothing() { return Builder().withNothing(); } }; ItemFilter(const Builder& builder) : ItemFilter(builder._value, builder._mask) {} // Item Filter operator testing if a key pass the filter bool test(const ItemKey& key) const { return (key._flags & _mask) == (_value & _mask); } bool selectsNothing() const { return !_mask.any(); } class Less { public: bool operator() (const ItemFilter& left, const ItemFilter& right) const { if (left._value.to_ulong() == right._value.to_ulong()) { return left._mask.to_ulong() < right._mask.to_ulong(); } else { return left._value.to_ulong() < right._value.to_ulong(); } } }; }; inline QDebug operator<<(QDebug debug, const ItemFilter& me) { debug << "[ItemFilter: opaqueShape:" << me.test(ItemKey::Builder::opaqueShape().build()) << "]"; return debug; } // Handy type to just pass the ID and the bound of an item class ItemBound { public: ItemBound() {} ItemBound(ItemID id) : id(id) { } ItemBound(ItemID id, const AABox& bound) : id(id), bound(bound) { } ItemID id { 0 }; AABox bound; uint32_t padding { 0 }; }; // many Item Bounds in a vector using ItemBounds = std::vector<ItemBound>; // Item is the proxy to a bounded "object" in the scene // An item is described by its Key class Item { public: typedef std::vector<Item> Vector; typedef ItemID ID; static const ID INVALID_ITEM_ID; static const ItemCell INVALID_CELL; // Convenient function to clear an ID or check it s valid static void clearID(ID& id) { id = INVALID_ITEM_ID; } static bool isValidID(const ID id) { return id != INVALID_ITEM_ID; } // Bound is the AABBox fully containing this item typedef AABox Bound; // Status records the life history and performances of this item while performing at rendering and updating. // This is Used for monitoring and dynamically adjust the quality class Status { public: enum class Icon { ACTIVE_IN_BULLET = 0, PACKET_SENT = 1, PACKET_RECEIVED = 2, SIMULATION_OWNER = 3, HAS_ACTIONS = 4, OTHER_SIMULATION_OWNER = 5, ENTITY_HOST_TYPE = 6, GENERIC_TRANSITION = 7, GENERIC_TRANSITION_OUT = 8, GENERIC_TRANSITION_IN = 9, USER_TRANSITION_OUT = 10, USER_TRANSITION_IN = 11, NONE = 255 }; // Status::Value class is the data used to represent the transient information of a status as a square icon // The "icon" is a square displayed in the 3D scene over the render::Item AABB center. // It can be scaled in the range [0, 1] and the color hue in the range [0, 360] representing the color wheel hue class Value { unsigned short _scale = 0xFFFF; unsigned char _color = 0xFF; unsigned char _icon = 0xFF; public: const static Value INVALID; // Invalid value meanss the status won't show Value() {} Value(float scale, float hue, unsigned char icon = 0xFF) { setScale(scale); setColor(hue); setIcon(icon); } // It can be scaled in the range [0, 1] void setScale(float scale); // the color hue in the range [0, 360] representing the color wheel hue void setColor(float hue); // the icon to display in the range [0, 255], where 0 means no icon, just filled quad and anything else would // hopefully have an icon available to display (see DrawStatusJob) void setIcon(unsigned char icon); // Standard color Hue static const float RED; // 0.0f; static const float YELLOW; // 60.0f; static const float GREEN; // 120.0f; static const float CYAN; // 180.0f; static const float BLUE; // 240.0f; static const float MAGENTA; // 300.0f; // Retreive the Value data tightely packed as an int int getPackedData() const { return *((const int*) this); } }; typedef std::function<Value()> Getter; typedef std::vector<Getter> Getters; Getters _values; void addGetter(const Getter& getter) { _values.push_back(getter); } size_t getNumValues() const { return _values.size(); } using Values = std::vector <Value>; Values getCurrentValues() const; }; typedef std::shared_ptr<Status> StatusPointer; // Update Functor class UpdateFunctorInterface { public: virtual ~UpdateFunctorInterface() {} }; typedef std::shared_ptr<UpdateFunctorInterface> UpdateFunctorPointer; // Payload is whatever is in this Item and implement the Payload Interface class PayloadInterface { public: virtual const ItemKey getKey() const = 0; virtual const Bound getBound(RenderArgs* args) const = 0; virtual void render(RenderArgs* args) = 0; virtual void renderSimulate(RenderArgs* args) = 0; virtual const ShapeKey getShapeKey() const = 0; virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const = 0; virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0; virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const = 0; virtual FadeProperties getFadeProperties(const TransitionType type) const = 0; ~PayloadInterface() {} // Status interface is local to the base class const StatusPointer& getStatus() const { return _status; } void addStatusGetter(const Status::Getter& getter); void addStatusGetters(const Status::Getters& getters); protected: StatusPointer _status; friend class Item; virtual void update(const UpdateFunctorPointer& functor) = 0; }; typedef std::shared_ptr<PayloadInterface> PayloadPointer; Item() {} ~Item() {} // Item exists if it has a valid payload bool exist() const { return (bool)(_payload); }