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