13 #ifndef hifi_render_Item_h
14 #define hifi_render_Item_h
29 #include <graphics/Material.h>
30 #include "ShapePipeline.h"
32 #include "BlendshapeConstants.h"
33 #include "HighlightStyle.h"
37 typedef int32_t Index;
38 const Index INVALID_INDEX{ -1 };
77 enum Layer : uint8_t {
91 LAYER_BITS_ALL = 0x07,
94 enum FlagBit : uint32_t {
110 LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS,
113 LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS,
121 typedef std::bitset<NUM_FLAGS> Flags;
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);
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);
138 ItemKey() : _flags(0) {}
139 ItemKey(
const Flags& flags) : _flags(flags) {}
141 bool operator== (
const ItemKey& rhs)
const {
return _flags == rhs._flags; }
142 bool operator!= (
const ItemKey& rhs)
const {
return _flags != rhs._flags; }
145 friend class ItemKey;
149 Builder(
const ItemKey& key) : _flags{ key._flags } {}
151 ItemKey build()
const {
return ItemKey(_flags); }
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); }
170 Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag);
return (*
this); }
172 Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong());
return (*
this); }
174 Builder& withLayer(uint8_t layer) { _flags = evalLayerBitsWithKeyBits(layer, _flags.to_ulong());
return (*
this); }
175 Builder& withoutLayer() {
return withLayer(LAYER_DEFAULT); }
177 Builder& withOutline() { _flags.set(OUTLINE);
return (*
this); }
178 Builder& withoutOutline() { _flags.reset(OUTLINE);
return (*
this); }
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); }
186 ItemKey(
const Builder& builder) : ItemKey(builder._flags) {}
188 bool isShape()
const {
return _flags[TYPE_SHAPE]; }
189 bool isLight()
const {
return _flags[TYPE_LIGHT]; }
190 bool isMeta()
const {
return _flags[TYPE_META]; }
192 bool isOpaque()
const {
return !_flags[TRANSLUCENT]; }
193 bool isTransparent()
const {
return _flags[TRANSLUCENT]; }
195 bool isWorldSpace()
const {
return !_flags[VIEW_SPACE]; }
196 bool isViewSpace()
const {
return _flags[VIEW_SPACE]; }
198 bool isStatic()
const {
return !_flags[DYNAMIC]; }
199 bool isDynamic()
const {
return _flags[DYNAMIC]; }
201 bool isRigid()
const {
return !_flags[DEFORMED]; }
202 bool isDeformed()
const {
return _flags[DEFORMED]; }
204 bool isVisible()
const {
return !_flags[INVISIBLE]; }
205 bool isInvisible()
const {
return _flags[INVISIBLE]; }
207 bool isShadowCaster()
const {
return _flags[SHADOW_CASTER]; }
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)); }
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)); }
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); }
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(); }
223 bool isOutline()
const {
return _flags[OUTLINE]; }
226 bool isSmall()
const {
return _flags[__SMALLER]; }
227 void setSmaller(
bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); }
229 bool operator==(
const ItemKey& key) {
return (_flags == key._flags); }
230 bool operator!=(
const ItemKey& key) {
return (_flags != key._flags); }
232 using ItemKeys = std::vector<ItemKey>;
234 inline QDebug operator<<(QDebug debug,
const ItemKey& itemKey) {
235 debug <<
"[ItemKey: isOpaque:" << itemKey.isOpaque()
236 <<
", isStatic:" << itemKey.isStatic()
237 <<
", isWorldSpace:" << itemKey.isWorldSpace()
244 ItemKey::Flags _value{ 0 };
245 ItemKey::Flags _mask{ 0 };
248 ItemFilter(
const ItemKey::Flags& value = ItemKey::Flags(0),
const ItemKey::Flags& mask = ItemKey::Flags(0)) : _value(value), _mask(mask) {}
251 friend class ItemFilter;
252 ItemKey::Flags _value{ 0 };
253 ItemKey::Flags _mask{ 0 };
256 Builder(
const ItemFilter& srcFilter) : _value(srcFilter._value), _mask(srcFilter._mask) {}
258 ItemFilter build()
const {
return ItemFilter(_value, _mask); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
299 Builder& withNothing() { _value.reset(); _mask.reset();
return (*
this); }
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(); }
311 ItemFilter(
const Builder& builder) : ItemFilter(builder._value, builder._mask) {}
314 bool test(
const ItemKey& key)
const {
return (key._flags & _mask) == (_value & _mask); }
315 bool selectsNothing()
const {
return !_mask.any(); }
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();
323 return left._value.to_ulong() < right._value.to_ulong();
329 inline QDebug operator<<(QDebug debug,
const ItemFilter& me) {
330 debug <<
"[ItemFilter: opaqueShape:" << me.test(ItemKey::Builder::opaqueShape().build())
339 ItemBound(ItemID
id) : id(id) { }
340 ItemBound(ItemID
id,
const AABox& bound) : id(id), bound(bound) { }
348 using ItemBounds = std::vector<ItemBound>;
354 typedef std::vector<Item> Vector;
357 static const ID INVALID_ITEM_ID;
358 static const ItemCell INVALID_CELL;
361 static void clearID(ID&
id) {
id = INVALID_ITEM_ID; }
362 static bool isValidID(
const ID
id) {
return id != INVALID_ITEM_ID; }
373 ACTIVE_IN_BULLET = 0,
376 SIMULATION_OWNER = 3,
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,
392 unsigned short _scale = 0xFFFF;
393 unsigned char _color = 0xFF;
394 unsigned char _icon = 0xFF;
396 const static Value INVALID;
399 Value(
float scale,
float hue,
unsigned char icon = 0xFF) { setScale(scale); setColor(hue); setIcon(icon); }
402 void setScale(
float scale);
404 void setColor(
float hue);
407 void setIcon(
unsigned char icon);
410 static const float RED;
411 static const float YELLOW;
412 static const float GREEN;
413 static const float CYAN;
414 static const float BLUE;
415 static const float MAGENTA;
418 int getPackedData()
const {
return *((
const int*)
this); }
421 typedef std::function<Value()> Getter;
422 typedef std::vector<Getter> Getters;
426 void addGetter(
const Getter& getter) { _values.push_back(getter); }
428 size_t getNumValues()
const {
return _values.size(); }
430 using Values = std::vector <Value>;
431 Values getCurrentValues()
const;
433 typedef std::shared_ptr<Status> StatusPointer;
436 class UpdateFunctorInterface {
438 virtual ~UpdateFunctorInterface() {}
440 typedef std::shared_ptr<UpdateFunctorInterface> UpdateFunctorPointer;
443 class PayloadInterface {
445 virtual const ItemKey getKey()
const = 0;
446 virtual const Bound getBound(RenderArgs* args)
const = 0;
447 virtual void render(RenderArgs* args) = 0;
449 virtual const ShapeKey getShapeKey()
const = 0;
451 virtual uint32_t fetchMetaSubItems(ItemIDs& subItems)
const = 0;
453 virtual bool passesZoneOcclusionTest(
const std::unordered_set<QUuid>& containingZones)
const = 0;
455 virtual HighlightStyle getOutlineStyle(
const ViewFrustum& viewFrustum,
const size_t height)
const = 0;
457 ~PayloadInterface() {}
460 const StatusPointer& getStatus()
const {
return _status; }
461 void addStatusGetter(
const Status::Getter& getter);
462 void addStatusGetters(
const Status::Getters& getters);
465 StatusPointer _status;
468 virtual void update(
const UpdateFunctorPointer& functor) = 0;
470 typedef std::shared_ptr<PayloadInterface> PayloadPointer;
476 bool exist()
const {
return (
bool)(_payload); }
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);
482 void kill() { _payload.reset(); resetCell(); _key._flags.reset(); }
485 const ItemKey& getKey()
const {
return _key; }
488 const ItemCell& getCell()
const {
return _cell; }
493 const Bound getBound(RenderArgs* args)
const {
return _payload->getBound(args); }
496 int getLayer()
const {
return _key.getLayer(); }
499 void render(RenderArgs* args)
const { _payload->render(args); }
502 const ShapeKey getShapeKey()
const;
505 uint32_t fetchMetaSubItems(ItemIDs& subItems)
const {
return _payload->fetchMetaSubItems(subItems); }
506 uint32_t fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene, RenderArgs* args)
const;
508 bool passesZoneOcclusionTest(
const std::unordered_set<QUuid>& containingZones)
const {
return _payload->passesZoneOcclusionTest(containingZones); }
510 HighlightStyle getOutlineStyle(
const ViewFrustum& viewFrustum,
const size_t height)
const {
return _payload->getOutlineStyle(viewFrustum, height); }
513 const StatusPointer& getStatus()
const {
return _payload->getStatus(); }
515 void setTransitionId(Index
id) { _transitionId = id; }
516 Index getTransitionId()
const {
return _transitionId; }
519 PayloadPointer _payload;
521 ItemCell _cell { INVALID_CELL };
522 Index _transitionId { INVALID_INDEX };
528 typedef Item::UpdateFunctorInterface UpdateFunctorInterface;
529 typedef Item::UpdateFunctorPointer UpdateFunctorPointer;
530 typedef std::vector<UpdateFunctorPointer> UpdateFunctors;
532 template <
class T>
class UpdateFunctor :
public Item::UpdateFunctorInterface {
534 typedef std::function<void(T&)> Func;
537 UpdateFunctor(Func func): _func(func) {}
542 inline QDebug operator<<(QDebug debug,
const Item& item) {
543 debug <<
"[Item: _key:" << item.getKey() <<
"]";
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) { }
556 template <
class T>
const ShapeKey shapeGetShapeKey(
const std::shared_ptr<T>& payloadData) {
return ShapeKey::Builder::ownPipeline(); }
560 template <
class T> uint32_t metaFetchMetaSubItems(
const std::shared_ptr<T>& payloadData, ItemIDs& subItems) {
return 0; }
564 template <
class T>
bool payloadPassesZoneOcclusionTest(
const std::shared_ptr<T>& payloadData,
const std::unordered_set<QUuid>& containingZones) {
return true; }
568 template <
class T> HighlightStyle payloadGetOutlineStyle(
const std::shared_ptr<T>& payloadData,
const ViewFrustum& viewFrustum,
const size_t height) {
569 return HighlightStyle();
576 template <
class T>
class Payload :
public Item::PayloadInterface {
578 typedef std::shared_ptr<T> DataPointer;
579 typedef UpdateFunctor<T> Updater;
581 Payload(
const DataPointer& data) : _data(data) {}
582 virtual ~Payload() =
default;
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); }
588 virtual void render(RenderArgs* args)
override { payloadRender<T>(_data, args); }
591 virtual const ShapeKey getShapeKey()
const override {
return shapeGetShapeKey<T>(_data); }
594 virtual uint32_t fetchMetaSubItems(ItemIDs& subItems)
const override {
return metaFetchMetaSubItems<T>(_data, subItems); }
596 virtual bool passesZoneOcclusionTest(
const std::unordered_set<QUuid>& containingZones)
const override {
return payloadPassesZoneOcclusionTest<T>(_data, containingZones); }
598 virtual HighlightStyle getOutlineStyle(
const ViewFrustum& viewFrustum,
const size_t height)
const override {
return payloadGetOutlineStyle<T>(_data, viewFrustum, height); }
604 virtual void update(
const UpdateFunctorPointer& functor)
override {
605 std::static_pointer_cast<Updater>(functor)->_func((*_data));
644 class PayloadProxyInterface {
646 using ProxyPayload = Payload<PayloadProxyInterface>;
647 using Pointer = ProxyPayload::DataPointer;
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;
658 virtual void handleBlendedVertices(
int blendshapeNumber,
const QVector<BlendshapeOffset>& blendshapeOffsets,
659 const QVector<int>& blendedMeshSizes,
const render::ItemIDs& subItemIDs) {};
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);
670 typedef Item::PayloadPointer PayloadPointer;
671 typedef std::vector<PayloadPointer> Payloads;
674 using ShapeBounds = std::unordered_map<ShapeKey, ItemBounds, ShapeKey::Hash, ShapeKey::KeyEqual>;