Overte C++ Documentation
Item.h
1 //
2 // Item.h
3 // render/src/render
4 //
5 // Created by Sam Gateau on 1/26/16.
6 // Copyright 2014 High Fidelity, Inc.
7 // Copyright 2024 Overte e.V.
8 //
9 // Distributed under the Apache License, Version 2.0.
10 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 //
12 
13 #ifndef hifi_render_Item_h
14 #define hifi_render_Item_h
15 
16 #include <atomic>
17 #include <bitset>
18 #include <map>
19 #include <memory>
20 #include <mutex>
21 #include <queue>
22 #include <set>
23 #include <vector>
24 
25 #include <AABox.h>
26 
27 #include "Args.h"
28 
29 #include <graphics/Material.h>
30 #include "ShapePipeline.h"
31 
32 #include "BlendshapeConstants.h"
33 #include "HighlightStyle.h"
34 
35 namespace render {
36 
37 typedef int32_t Index;
38 const Index INVALID_INDEX{ -1 };
39 
40 class Context;
41 
42 // Key is the KEY to filter Items and create specialized lists
43 class ItemKey {
44 public:
45  // 8 tags are available to organize the items and filter them against as fields of the ItemKey.
46  // TAG & TAG_BITS are defined from several bits in the Key.
47  // An Item can be tagged and filtering can rely on the tags to keep or exclude items
48  // ItemKey are not taged by default
49  enum Tag : uint8_t {
50  TAG_0 = 0, // 8 Tags
51  TAG_1,
52  TAG_2,
53  TAG_3,
54  TAG_4,
55  TAG_5,
56  TAG_6,
57  TAG_7,
58 
59  NUM_TAGS,
60 
61  // Tag bits are derived from the Tag enum
62  TAG_BITS_ALL = 0xFF,
63  TAG_BITS_NONE = 0x00,
64  TAG_BITS_0 = 0x01,
65  TAG_BITS_1 = 0x02,
66  TAG_BITS_2 = 0x04,
67  TAG_BITS_3 = 0x08,
68  TAG_BITS_4 = 0x10,
69  TAG_BITS_5 = 0x20,
70  TAG_BITS_6 = 0x40,
71  TAG_BITS_7 = 0x80,
72  };
73 
74  // Items are organized in layers, an item belongs to one of the 8 Layers available.
75  // By default an item is in the 'LAYER_DEFAULT' meaning that it is NOT layered.
76  // THere is NO ordering relationship between layers.
77  enum Layer : uint8_t {
78  LAYER_DEFAULT = 0, // layer 0 aka Default is a 'NOT' layer, items are not considered layered, this is the default value
79  LAYER_1,
80  LAYER_2,
81  LAYER_3,
82  LAYER_4,
83  LAYER_5,
84  LAYER_6,
85  LAYER_BACKGROUND, // Last Layer is the background by convention
86 
87  NUM_LAYERS,
88 
89  // Layer bits are derived from the Layer enum, the number of bits needed to represent integer 0 to NUM_LAYERS
90  NUM_LAYER_BITS = 3,
91  LAYER_BITS_ALL = 0x07,
92  };
93 
94  enum FlagBit : uint32_t {
95  TYPE_SHAPE = 0, // Item is a Shape: Implements the Shape Interface that draw a Geometry rendered with a Material
96  TYPE_LIGHT, // Item is a Light: Implements the Light Interface that
97  TYPE_CAMERA, // Item is a Camera: Implements the Camera Interface
98  TYPE_META, // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items
99 
100  TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work...
101  VIEW_SPACE, // Transformed in view space, and not in world space
102  DYNAMIC, // Dynamic and bound will change unlike static item
103  DEFORMED, // Deformed within bound, not solid
104  INVISIBLE, // Visible or not in the scene?
105  SHADOW_CASTER, // Item cast shadows
106  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
107  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
108 
109  FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against
110  LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS,
111 
112  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
113  LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS,
114 
115  OUTLINE, // Item has an outline
116 
117  __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)
118 
119  NUM_FLAGS, // Not a valid flag
120  };
121  typedef std::bitset<NUM_FLAGS> Flags;
122 
123  // All the bits touching tag bits sets to true
124  const static uint32_t KEY_TAG_BITS_MASK;
125  static uint32_t evalTagBitsWithKeyBits(uint8_t tagBits, const uint32_t keyBits) {
126  return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT);
127  }
128 
129  // All the bits touching layer bits sets to true
130  const static uint32_t KEY_LAYER_BITS_MASK;
131  static uint32_t evalLayerBitsWithKeyBits(uint8_t layer, const uint32_t keyBits) {
132  return (keyBits & ~KEY_LAYER_BITS_MASK) | (((uint32_t)layer & LAYER_BITS_ALL) << FIRST_LAYER_BIT);
133  }
134 
135  // The key is the Flags
136  Flags _flags;
137 
138  ItemKey() : _flags(0) {}
139  ItemKey(const Flags& flags) : _flags(flags) {}
140 
141  bool operator== (const ItemKey& rhs) const { return _flags == rhs._flags; }
142  bool operator!= (const ItemKey& rhs) const { return _flags != rhs._flags; }
143 
144  class Builder {
145  friend class ItemKey;
146  Flags _flags{ 0 };
147  public:
148  Builder() {}
149  Builder(const ItemKey& key) : _flags{ key._flags } {}
150 
151  ItemKey build() const { return ItemKey(_flags); }
152 
153  Builder& withTypeShape() { _flags.set(TYPE_SHAPE); return (*this); }
154  Builder& withTypeLight() { _flags.set(TYPE_LIGHT); return (*this); }
155  Builder& withTypeMeta() { _flags.set(TYPE_META); return (*this); }
156  Builder& withTransparent() { _flags.set(TRANSLUCENT); return (*this); }
157  Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); }
158  Builder& withoutViewSpace() { _flags.reset(VIEW_SPACE); return (*this); }
159  Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); }
160  Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
161  Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
162  Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); }
163  Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); }
164  Builder& withoutShadowCaster() { _flags.reset(SHADOW_CASTER); return (*this); }
165  Builder& withMetaCullGroup() { _flags.set(META_CULL_GROUP); return (*this); }
166  Builder& withoutMetaCullGroup() { _flags.reset(META_CULL_GROUP); return (*this); }
167  Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); }
168  Builder& withoutSubMetaCulled() { _flags.reset(SUB_META_CULLED); return (*this); }
169 
170  Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); }
171  // Set ALL the tags in one call using the Tag bits
172  Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong()); return (*this); }
173 
174  Builder& withLayer(uint8_t layer) { _flags = evalLayerBitsWithKeyBits(layer, _flags.to_ulong()); return (*this); }
175  Builder& withoutLayer() { return withLayer(LAYER_DEFAULT); }
176 
177  Builder& withOutline() { _flags.set(OUTLINE); return (*this); }
178  Builder& withoutOutline() { _flags.reset(OUTLINE); return (*this); }
179 
180  // Convenient standard keys that we will keep on using all over the place
181  static Builder opaqueShape() { return Builder().withTypeShape(); }
182  static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); }
183  static Builder light() { return Builder().withTypeLight(); }
184  static Builder background() { return Builder().withViewSpace().withLayer(LAYER_BACKGROUND); }
185  };
186  ItemKey(const Builder& builder) : ItemKey(builder._flags) {}
187 
188  bool isShape() const { return _flags[TYPE_SHAPE]; }
189  bool isLight() const { return _flags[TYPE_LIGHT]; }
190  bool isMeta() const { return _flags[TYPE_META]; }
191 
192  bool isOpaque() const { return !_flags[TRANSLUCENT]; }
193  bool isTransparent() const { return _flags[TRANSLUCENT]; }
194 
195  bool isWorldSpace() const { return !_flags[VIEW_SPACE]; }
196  bool isViewSpace() const { return _flags[VIEW_SPACE]; }
197 
198  bool isStatic() const { return !_flags[DYNAMIC]; }
199  bool isDynamic() const { return _flags[DYNAMIC]; }
200 
201  bool isRigid() const { return !_flags[DEFORMED]; }
202  bool isDeformed() const { return _flags[DEFORMED]; }
203 
204  bool isVisible() const { return !_flags[INVISIBLE]; }
205  bool isInvisible() const { return _flags[INVISIBLE]; }
206 
207  bool isShadowCaster() const { return _flags[SHADOW_CASTER]; }
208 
209  bool isMetaCullGroup() const { return _flags[META_CULL_GROUP]; }
210  void setMetaCullGroup(bool cullGroup) { (cullGroup ? _flags.set(META_CULL_GROUP) : _flags.reset(META_CULL_GROUP)); }
211 
212  bool isSubMetaCulled() const { return _flags[SUB_META_CULLED]; }
213  void setSubMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(SUB_META_CULLED) : _flags.reset(SUB_META_CULLED)); }
214 
215  bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; }
216  uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); }
217 
218  uint8_t getLayer() const { return ((_flags.to_ulong() & KEY_LAYER_BITS_MASK) >> FIRST_LAYER_BIT); }
219  bool isLayer(uint8_t layer) const { return getLayer() == layer; }
220  bool isLayered() const { return getLayer() != LAYER_DEFAULT; }
221  bool isSpatial() const { return !isLayered(); }
222 
223  bool isOutline() const { return _flags[OUTLINE]; }
224 
225  // Probably not public, flags used by the scene
226  bool isSmall() const { return _flags[__SMALLER]; }
227  void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); }
228 
229  bool operator==(const ItemKey& key) { return (_flags == key._flags); }
230  bool operator!=(const ItemKey& key) { return (_flags != key._flags); }
231 };
232 using ItemKeys = std::vector<ItemKey>;
233 
234 inline QDebug operator<<(QDebug debug, const ItemKey& itemKey) {
235  debug << "[ItemKey: isOpaque:" << itemKey.isOpaque()
236  << ", isStatic:" << itemKey.isStatic()
237  << ", isWorldSpace:" << itemKey.isWorldSpace()
238  << "]";
239  return debug;
240 }
241 
242 class ItemFilter {
243 public:
244  ItemKey::Flags _value{ 0 };
245  ItemKey::Flags _mask{ 0 };
246 
247 
248  ItemFilter(const ItemKey::Flags& value = ItemKey::Flags(0), const ItemKey::Flags& mask = ItemKey::Flags(0)) : _value(value), _mask(mask) {}
249 
250  class Builder {
251  friend class ItemFilter;
252  ItemKey::Flags _value{ 0 };
253  ItemKey::Flags _mask{ 0 };
254  public:
255  Builder() {}
256  Builder(const ItemFilter& srcFilter) : _value(srcFilter._value), _mask(srcFilter._mask) {}
257 
258  ItemFilter build() const { return ItemFilter(_value, _mask); }
259 
260  Builder& withTypeShape() { _value.set(ItemKey::TYPE_SHAPE); _mask.set(ItemKey::TYPE_SHAPE); return (*this); }
261  Builder& withTypeLight() { _value.set(ItemKey::TYPE_LIGHT); _mask.set(ItemKey::TYPE_LIGHT); return (*this); }
262  Builder& withTypeMeta() { _value.set(ItemKey::TYPE_META); _mask.set(ItemKey::TYPE_META); return (*this); }
263 
264  Builder& withOpaque() { _value.reset(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); }
265  Builder& withTransparent() { _value.set(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); }
266 
267  Builder& withWorldSpace() { _value.reset(ItemKey::VIEW_SPACE); _mask.set(ItemKey::VIEW_SPACE); return (*this); }
268  Builder& withViewSpace() { _value.set(ItemKey::VIEW_SPACE); _mask.set(ItemKey::VIEW_SPACE); return (*this); }
269 
270  Builder& withStatic() { _value.reset(ItemKey::DYNAMIC); _mask.set(ItemKey::DYNAMIC); return (*this); }
271  Builder& withDynamic() { _value.set(ItemKey::DYNAMIC); _mask.set(ItemKey::DYNAMIC); return (*this); }
272 
273  Builder& withRigid() { _value.reset(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); }
274  Builder& withDeformed() { _value.set(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); }
275 
276  Builder& withVisible() { _value.reset(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); }
277  Builder& withInvisible() { _value.set(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); }
278 
279  Builder& withNoShadowCaster() { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
280  Builder& withShadowCaster() { _value.set(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
281 
282  Builder& withoutMetaCullGroup() { _value.reset(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); }
283  Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); }
284 
285  Builder& withoutSubMetaCulled() { _value.reset(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); }
286  Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); }
287 
288  Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); }
289  Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); }
290  // Set ALL the tags in one call using the Tag bits and the Tag bits touched
291  Builder& withTagBits(uint8_t tagBits, uint8_t tagMask) { _value = ItemKey::evalTagBitsWithKeyBits(tagBits, _value.to_ulong()); _mask = ItemKey::evalTagBitsWithKeyBits(tagMask, _mask.to_ulong()); return (*this); }
292 
293  Builder& withoutLayered() { _value = ItemKey::evalLayerBitsWithKeyBits(ItemKey::LAYER_DEFAULT, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); }
294  Builder& withLayer(uint8_t layer) { _value = ItemKey::evalLayerBitsWithKeyBits(layer, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); }
295 
296  Builder& withoutOutline() { _value.reset(ItemKey::OUTLINE); _mask.set(ItemKey::OUTLINE); return (*this); }
297  Builder& withOutline() { _value.set(ItemKey::OUTLINE); _mask.set(ItemKey::OUTLINE); return (*this); }
298 
299  Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); }
300 
301  // Convenient standard keys that we will keep on using all over the place
302  static Builder visibleWorldItems() { return Builder().withVisible().withWorldSpace(); }
303  static Builder opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace(); }
304  static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); }
305  static Builder light() { return Builder().withTypeLight(); }
306  static Builder meta() { return Builder().withTypeMeta(); }
307  static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); }
308  static Builder nothing() { return Builder().withNothing(); }
309  };
310 
311  ItemFilter(const Builder& builder) : ItemFilter(builder._value, builder._mask) {}
312 
313  // Item Filter operator testing if a key pass the filter
314  bool test(const ItemKey& key) const { return (key._flags & _mask) == (_value & _mask); }
315  bool selectsNothing() const { return !_mask.any(); }
316 
317  class Less {
318  public:
319  bool operator() (const ItemFilter& left, const ItemFilter& right) const {
320  if (left._value.to_ulong() == right._value.to_ulong()) {
321  return left._mask.to_ulong() < right._mask.to_ulong();
322  } else {
323  return left._value.to_ulong() < right._value.to_ulong();
324  }
325  }
326  };
327 };
328 
329 inline QDebug operator<<(QDebug debug, const ItemFilter& me) {
330  debug << "[ItemFilter: opaqueShape:" << me.test(ItemKey::Builder::opaqueShape().build())
331  << "]";
332  return debug;
333 }
334 
335 // Handy type to just pass the ID and the bound of an item
336 class ItemBound {
337  public:
338  ItemBound() {}
339  ItemBound(ItemID id) : id(id) { }
340  ItemBound(ItemID id, const AABox& bound) : id(id), bound(bound) { }
341 
342  ItemID id;
343  AABox bound;
344  uint32_t padding;
345 };
346 
347 // many Item Bounds in a vector
348 using ItemBounds = std::vector<ItemBound>;
349 
350 // Item is the proxy to a bounded "object" in the scene
351 // An item is described by its Key
352 class Item {
353 public:
354  typedef std::vector<Item> Vector;
355  typedef ItemID ID;
356 
357  static const ID INVALID_ITEM_ID;
358  static const ItemCell INVALID_CELL;
359 
360  // Convenient function to clear an ID or check it s valid
361  static void clearID(ID& id) { id = INVALID_ITEM_ID; }
362  static bool isValidID(const ID id) { return id != INVALID_ITEM_ID; }
363 
364  // Bound is the AABBox fully containing this item
365  typedef AABox Bound;
366 
367  // Status records the life history and performances of this item while performing at rendering and updating.
368  // This is Used for monitoring and dynamically adjust the quality
369  class Status {
370  public:
371 
372  enum class Icon {
373  ACTIVE_IN_BULLET = 0,
374  PACKET_SENT = 1,
375  PACKET_RECEIVED = 2,
376  SIMULATION_OWNER = 3,
377  HAS_ACTIONS = 4,
378  OTHER_SIMULATION_OWNER = 5,
379  ENTITY_HOST_TYPE = 6,
380  GENERIC_TRANSITION = 7,
381  GENERIC_TRANSITION_OUT = 8,
382  GENERIC_TRANSITION_IN = 9,
383  USER_TRANSITION_OUT = 10,
384  USER_TRANSITION_IN = 11,
385  NONE = 255
386  };
387 
388  // Status::Value class is the data used to represent the transient information of a status as a square icon
389  // The "icon" is a square displayed in the 3D scene over the render::Item AABB center.
390  // It can be scaled in the range [0, 1] and the color hue in the range [0, 360] representing the color wheel hue
391  class Value {
392  unsigned short _scale = 0xFFFF;
393  unsigned char _color = 0xFF;
394  unsigned char _icon = 0xFF;
395  public:
396  const static Value INVALID; // Invalid value meanss the status won't show
397 
398  Value() {}
399  Value(float scale, float hue, unsigned char icon = 0xFF) { setScale(scale); setColor(hue); setIcon(icon); }
400 
401  // It can be scaled in the range [0, 1]
402  void setScale(float scale);
403  // the color hue in the range [0, 360] representing the color wheel hue
404  void setColor(float hue);
405  // the icon to display in the range [0, 255], where 0 means no icon, just filled quad and anything else would
406  // hopefully have an icon available to display (see DrawStatusJob)
407  void setIcon(unsigned char icon);
408 
409  // Standard color Hue
410  static const float RED; // 0.0f;
411  static const float YELLOW; // 60.0f;
412  static const float GREEN; // 120.0f;
413  static const float CYAN; // 180.0f;
414  static const float BLUE; // 240.0f;
415  static const float MAGENTA; // 300.0f;
416 
417  // Retreive the Value data tightely packed as an int
418  int getPackedData() const { return *((const int*) this); }
419  };
420 
421  typedef std::function<Value()> Getter;
422  typedef std::vector<Getter> Getters;
423 
424  Getters _values;
425 
426  void addGetter(const Getter& getter) { _values.push_back(getter); }
427 
428  size_t getNumValues() const { return _values.size(); }
429 
430  using Values = std::vector <Value>;
431  Values getCurrentValues() const;
432  };
433  typedef std::shared_ptr<Status> StatusPointer;
434 
435  // Update Functor
436  class UpdateFunctorInterface {
437  public:
438  virtual ~UpdateFunctorInterface() {}
439  };
440  typedef std::shared_ptr<UpdateFunctorInterface> UpdateFunctorPointer;
441 
442  // Payload is whatever is in this Item and implement the Payload Interface
443  class PayloadInterface {
444  public:
445  virtual const ItemKey getKey() const = 0;
446  virtual const Bound getBound(RenderArgs* args) const = 0;
447  virtual void render(RenderArgs* args) = 0;
448 
449  virtual const ShapeKey getShapeKey() const = 0;
450 
451  virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const = 0;
452 
453  virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0;
454 
455  virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const = 0;
456 
457  ~PayloadInterface() {}
458 
459  // Status interface is local to the base class
460  const StatusPointer& getStatus() const { return _status; }
461  void addStatusGetter(const Status::Getter& getter);
462  void addStatusGetters(const Status::Getters& getters);
463 
464  protected:
465  StatusPointer _status;
466 
467  friend class Item;
468  virtual void update(const UpdateFunctorPointer& functor) = 0;
469  };
470  typedef std::shared_ptr<PayloadInterface> PayloadPointer;
471 
472  Item() {}
473  ~Item() {}
474 
475  // Item exists if it has a valid payload
476  bool exist() const { return (bool)(_payload); }
477 
478  // Main scene / item managment interface reset/update/kill
479  void resetPayload(const PayloadPointer& payload);
480  void resetCell(ItemCell cell = INVALID_CELL, bool _small = false) { _cell = cell; _key.setSmaller(_small); }
481  void update(const UpdateFunctorPointer& updateFunctor); // communicate update to payload
482  void kill() { _payload.reset(); resetCell(); _key._flags.reset(); } // forget the payload, key, cell
483 
484  // Check heuristic key
485  const ItemKey& getKey() const { return _key; }
486 
487  // Check spatial cell
488  const ItemCell& getCell() const { return _cell; }
489 
490  // Payload Interface
491 
492  // Get the bound of the item expressed in world space (or eye space depending on the key.isWorldSpace())
493  const Bound getBound(RenderArgs* args) const { return _payload->getBound(args); }
494 
495  // Get the layer where the item belongs, simply reflecting the key.
496  int getLayer() const { return _key.getLayer(); }
497 
498  // Render call for the item
499  void render(RenderArgs* args) const { _payload->render(args); }
500 
501  // Shape Type Interface
502  const ShapeKey getShapeKey() const;
503 
504  // Meta Type Interface
505  uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); }
506  uint32_t fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene, RenderArgs* args) const;
507 
508  bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); }
509 
510  HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const { return _payload->getOutlineStyle(viewFrustum, height); }
511 
512  // Access the status
513  const StatusPointer& getStatus() const { return _payload->getStatus(); }
514 
515  void setTransitionId(Index id) { _transitionId = id; }
516  Index getTransitionId() const { return _transitionId; }
517 
518 protected:
519  PayloadPointer _payload;
520  ItemKey _key;
521  ItemCell _cell { INVALID_CELL };
522  Index _transitionId { INVALID_INDEX };
523 
524  friend class Scene;
525 };
526 
527 
528 typedef Item::UpdateFunctorInterface UpdateFunctorInterface;
529 typedef Item::UpdateFunctorPointer UpdateFunctorPointer;
530 typedef std::vector<UpdateFunctorPointer> UpdateFunctors;
531 
532 template <class T> class UpdateFunctor : public Item::UpdateFunctorInterface {
533 public:
534  typedef std::function<void(T&)> Func;
535  Func _func;
536 
537  UpdateFunctor(Func func): _func(func) {}
538  ~UpdateFunctor() {}
539 };
540 
541 
542 inline QDebug operator<<(QDebug debug, const Item& item) {
543  debug << "[Item: _key:" << item.getKey() << "]";
544  return debug;
545 }
546 
547 // Item shared interface supported by the payload
548 template <class T> const ItemKey payloadGetKey(const std::shared_ptr<T>& payloadData) { return ItemKey(); }
549 template <class T> const Item::Bound payloadGetBound(const std::shared_ptr<T>& payloadData, RenderArgs* args) { return Item::Bound(); }
550 template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { }
551 
552 // Shape type interface
553 // This allows shapes to characterize their pipeline via a ShapeKey, to be picked with a subclass of Shape.
554 // When creating a new shape payload you need to create a specialized version, or the ShapeKey will be ownPipeline,
555 // implying that the shape will setup its own pipeline without the use of the ShapeKey.
556 template <class T> const ShapeKey shapeGetShapeKey(const std::shared_ptr<T>& payloadData) { return ShapeKey::Builder::ownPipeline(); }
557 
558 // Meta Type Interface
559 // Meta items act as the grouping object for several sub items (typically shapes).
560 template <class T> uint32_t metaFetchMetaSubItems(const std::shared_ptr<T>& payloadData, ItemIDs& subItems) { return 0; }
561 
562 // Zone Occlusion Interface
563 // Allows payloads to determine if they should render or not, based on the zones that contain the current camera
564 template <class T> bool payloadPassesZoneOcclusionTest(const std::shared_ptr<T>& payloadData, const std::unordered_set<QUuid>& containingZones) { return true; }
565 
566 // Outline Interface
567 // Allows payloads to specify an outline style
568 template <class T> HighlightStyle payloadGetOutlineStyle(const std::shared_ptr<T>& payloadData, const ViewFrustum& viewFrustum, const size_t height) {
569  return HighlightStyle();
570 }
571 
572 // THe Payload class is the real Payload to be used
573 // THis allow anything to be turned into a Payload as long as the required interface functions are available
574 // When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff"
575 // of the Payload interface
576 template <class T> class Payload : public Item::PayloadInterface {
577 public:
578  typedef std::shared_ptr<T> DataPointer;
579  typedef UpdateFunctor<T> Updater;
580 
581  Payload(const DataPointer& data) : _data(data) {}
582  virtual ~Payload() = default;
583 
584  // Payload general interface
585  virtual const ItemKey getKey() const override { return payloadGetKey<T>(_data); }
586  virtual const Item::Bound getBound(RenderArgs* args) const override { return payloadGetBound<T>(_data, args); }
587 
588  virtual void render(RenderArgs* args) override { payloadRender<T>(_data, args); }
589 
590  // Shape Type interface
591  virtual const ShapeKey getShapeKey() const override { return shapeGetShapeKey<T>(_data); }
592 
593  // Meta Type Interface
594  virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const override { return metaFetchMetaSubItems<T>(_data, subItems); }
595 
596  virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override { return payloadPassesZoneOcclusionTest<T>(_data, containingZones); }
597 
598  virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const override { return payloadGetOutlineStyle<T>(_data, viewFrustum, height); }
599 
600 protected:
601  DataPointer _data;
602 
603  // Update mechanics
604  virtual void update(const UpdateFunctorPointer& functor) override {
605  std::static_pointer_cast<Updater>(functor)->_func((*_data));
606  }
607  friend class Item;
608 };
609 
610 // Let's show how to make a simple FooPayload example:
611 /*
612 class Foo {
613 public:
614  mutable ItemKey _myownKey;
615  void makeMywnKey() const {
616  _myownKey = ItemKey::Builder().withTypeShape().build();
617  }
618 
619  const Item::Bound evaluateMyBound() {
620  // Do stuff here to get your final Bound
621  return Item::Bound();
622  }
623 };
624 
625 typedef Payload<Foo> FooPayload;
626 typedef std::shared_ptr<Foo> FooPointer;
627 
628 // In a Source file, not a header, implement the Payload interface function specialized for Foo:
629 template <> const ItemKey payloadGetKey(const FooPointer& foo) {
630  // Foo's way of provinding its Key
631  foo->makeMyKey();
632  return foo->_myownKey;
633 }
634 template <> const Item::Bound payloadGetBound(const FooPointer& foo, RenderArgs* args) {
635  // evaluate Foo's own bound
636  return foo->evaluateMyBound(args);
637 }
638 
639 // In this example, do not specialize the payloadRender call which means the compiler will use the default version which does nothing
640 
641 */
642 // End of the example
643 
644 class PayloadProxyInterface {
645 public:
646  using ProxyPayload = Payload<PayloadProxyInterface>;
647  using Pointer = ProxyPayload::DataPointer;
648 
649  virtual ItemKey getKey() = 0;
650  virtual ShapeKey getShapeKey() = 0;
651  virtual Item::Bound getBound(RenderArgs* args) = 0;
652  virtual void render(RenderArgs* args) = 0;
653  virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0;
654  virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0;
655  virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const = 0;
656 
657  // FIXME: this isn't the best place for this since it's only used for ModelEntities, but currently all Entities use PayloadProxyInterface
658  virtual void handleBlendedVertices(int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets,
659  const QVector<int>& blendedMeshSizes, const render::ItemIDs& subItemIDs) {};
660 };
661 
662 template <> const ItemKey payloadGetKey(const PayloadProxyInterface::Pointer& payload);
663 template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload, RenderArgs* args);
664 template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, RenderArgs* args);
665 template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems);
666 template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload);
667 template <> bool payloadPassesZoneOcclusionTest(const PayloadProxyInterface::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
668 template <> HighlightStyle payloadGetOutlineStyle(const PayloadProxyInterface::Pointer& payload, const ViewFrustum& viewFrustum, const size_t height);
669 
670 typedef Item::PayloadPointer PayloadPointer;
671 typedef std::vector<PayloadPointer> Payloads;
672 
673 // A map of items by ShapeKey to optimize rendering pipeline assignments
674 using ShapeBounds = std::unordered_map<ShapeKey, ItemBounds, ShapeKey::Hash, ShapeKey::KeyEqual>;
675 
676 }
677 
678 #endif // hifi_render_Item_h