727 lines · 32.9 KB · C
RawDownload
////  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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t