Overte C++ Documentation
EntityTreeRenderer.h
1 //
2 // EntityTreeRenderer.h
3 // interface/src
4 //
5 // Created by Brad Hefta-Gaub on 12/6/13.
6 // Copyright 2013 High Fidelity, Inc.
7 // Copyright 2023 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 // SPDX-License-Identifier: Apache-2.0
12 //
13 
14 #ifndef hifi_EntityTreeRenderer_h
15 #define hifi_EntityTreeRenderer_h
16 
17 #include <memory>
18 
19 #include <QtCore/QSet>
20 #include <QtCore/QStack>
21 #include <QtGui/QMouseEvent>
22 #include <QtCore/QSharedPointer>
23 
24 #include <AudioInjectorManager.h>
25 #include <EntityScriptingInterface.h> // for RayToEntityIntersectionResult
26 #include <EntityTree.h>
27 #include <PointerEvent.h>
28 #include <ScriptCache.h>
29 #include <TextureCache.h>
30 #include <OctreeProcessor.h>
31 #include <render/Forward.h>
32 #include <workload/Space.h>
33 #include <FadeProperties.h>
34 
37 class Model;
38 class ScriptEngine;
39 class ZoneEntityItem;
40 class EntityItem;
41 class ScriptEngine;
42 class ScriptManager;
43 using ScriptEnginePointer = std::shared_ptr<ScriptEngine>;
44 using ScriptManagerPointer = std::shared_ptr<ScriptManager>;
45 
46 namespace render { namespace entities {
47  class EntityRenderer;
48  using EntityRendererPointer = std::shared_ptr<EntityRenderer>;
49  using EntityRendererWeakPointer = std::weak_ptr<EntityRenderer>;
50 
51 } }
52 
53 using EntityRenderer = render::entities::EntityRenderer;
54 using EntityRendererPointer = render::entities::EntityRendererPointer;
55 using EntityRendererWeakPointer = render::entities::EntityRendererWeakPointer;
56 class Model;
57 using ModelPointer = std::shared_ptr<Model>;
58 using ModelWeakPointer = std::weak_ptr<Model>;
59 
60 using CalculateEntityLoadingPriority = std::function<float(const EntityItem& item)>;
61 
62 // Generic client side Octree renderer class.
63 class EntityTreeRenderer : public OctreeProcessor, public Dependency {
64  Q_OBJECT
65 public:
66  EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
67  AbstractScriptingServicesInterface* scriptingServices);
68  virtual ~EntityTreeRenderer();
69 
70  QSharedPointer<EntityTreeRenderer> getSharedFromThis() {
71  return qSharedPointerCast<EntityTreeRenderer>(sharedFromThis());
72  }
73 
74  virtual char getMyNodeType() const override { return NodeType::EntityServer; }
75  virtual PacketType getMyQueryMessageType() const override { return PacketType::EntityQuery; }
76  virtual PacketType getExpectedPacketType() const override { return PacketType::EntityData; }
77 
78  // Returns the priority at which an entity should be loaded. Higher values indicate higher priority.
79  static CalculateEntityLoadingPriority getEntityLoadingPriorityOperator() { return _calculateEntityLoadingPriorityFunc; }
80  static float getEntityLoadingPriority(const EntityItem& item) { return _calculateEntityLoadingPriorityFunc(item); }
81  static void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { _calculateEntityLoadingPriorityFunc = fn; }
82 
83  void setMouseRayPickID(unsigned int rayPickID) { _mouseRayPickID = rayPickID; }
84  unsigned int getMouseRayPickID() { return _mouseRayPickID; }
85  void setMouseRayPickResultOperator(std::function<RayToEntityIntersectionResult(unsigned int)> getPrevRayPickResultOperator) { _getPrevRayPickResultOperator = getPrevRayPickResultOperator; }
86  void setSetPrecisionPickingOperator(std::function<void(unsigned int, bool)> setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; }
87 
88  void shutdown();
89  void preUpdate();
90  void update(bool simulate);
91 
92  EntityTreePointer getTree() { return std::static_pointer_cast<EntityTree>(_tree); }
93 
94  void processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode);
95 
96  virtual void init() override;
97 
99  virtual void clearDomainAndNonOwnedEntities() override;
100  virtual void clear() override;
101 
103  void reloadEntityScripts();
104 
105  void fadeOutRenderable(const EntityRendererPointer& renderable);
106  FadeProperties getLayeredZoneFadeProperties(const TransitionType type) const { return _layeredZones.getFadeProperties(type); }
107 
108  // event handles which may generate entity related events
109  QUuid mousePressEvent(QMouseEvent* event);
110  void mouseReleaseEvent(QMouseEvent* event);
111  void mouseDoublePressEvent(QMouseEvent* event);
112  void mouseMoveEvent(QMouseEvent* event);
113 
116  void connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface);
117 
118  // For Scene.shouldRenderEntities
119  QList<EntityItemID>& getEntitiesLastInScene() { return _entityIDsLastInScene; }
120 
121  std::pair<bool, bool> getZoneInteractionProperties();
122 
123  bool wantsKeyboardFocus(const EntityItemID& id) const;
124  QObject* getEventHandler(const EntityItemID& id);
125  bool wantsHandControllerPointerEvents(const EntityItemID& id) const;
126  void setProxyWindow(const EntityItemID& id, QWindow* proxyWindow);
127  void setCollisionSound(const EntityItemID& id, const SharedSoundPointer& sound);
128  EntityItemPointer getEntity(const EntityItemID& id);
129  void deleteEntity(const EntityItemID& id) const;
130  void onEntityChanged(const EntityItemID& id);
131 
132  // Access the workload Space
133  workload::SpacePointer getWorkloadSpace() const { return _space; }
134 
135  EntityEditPacketSender* getPacketSender();
136 
137  static void setAddMaterialToEntityOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; }
138  static void setRemoveMaterialFromEntityOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromEntityOperator) { _removeMaterialFromEntityOperator = removeMaterialFromEntityOperator; }
139  static bool addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName);
140  static bool removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName);
141 
142  static void setAddMaterialToAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; }
143  static void setRemoveMaterialFromAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; }
144  static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName);
145  static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName);
146 
147  size_t getPrevNumEntityUpdates() const { return _prevNumEntityUpdates; }
148  size_t getPrevTotalNeededEntityUpdates() const { return _prevTotalNeededEntityUpdates; }
149 
150  bool layeredZonesHaveFade(const TransitionType type) const { return _layeredZones.hasFade(type); }
151 
152  bool checkAndCallPreload(const EntityItemID& entityID,
153  bool reload = false,
154  bool unloadFirst = false,
155  const QString& oldOverrideURL = "",
156  const QString& newOverrideURL = "");
157  void unloadEntityScript(const EntityItemID& entityID, const QString& scriptURL);
158  void updateScriptUserData(const EntityItemID& entityID, const QString& scriptURL, const QString& userData);
159 
160 signals:
161  void enterEntity(const EntityItemID& entityItemID);
162  void leaveEntity(const EntityItemID& entityItemID);
163  void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
164 
165 public slots:
166  void addingEntity(const EntityItemID& entityID);
167  void deletingEntity(const EntityItemID& entityID);
168  void entityScriptChanging(const EntityItemID& entityID, const bool reload);
169  void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
170  void updateEntityRenderStatus(bool shouldRenderEntities);
171  void updateZone(const EntityItemID& id);
172 
173  // optional slots that can be wired to menu items
174  void setDisplayModelBounds(bool value) { _displayModelBounds = value; }
175  void setPrecisionPicking(bool value) { _setPrecisionPickingOperator(_mouseRayPickID, value); }
176  EntityRendererPointer renderableForEntityId(const EntityItemID& id) const;
177  render::ItemID renderableIdForEntityId(const EntityItemID& id) const;
178 
179  void handleSpaceUpdate(std::pair<int32_t, glm::vec4> proxyUpdate);
180 
181 protected:
182  virtual OctreePointer createTree() override {
183  EntityTreePointer newTree = std::make_shared<EntityTree>(true);
184  newTree->createRootElement();
185  return newTree;
186  }
187 
188 private:
189  void addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction);
190  void updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction);
191  EntityRendererPointer renderableForEntity(const EntityItemPointer& entity) const { return renderableForEntityId(entity->getID()); }
192  render::ItemID renderableIdForEntity(const EntityItemPointer& entity) const { return renderableIdForEntityId(entity->getID()); }
193 
194  void resetPersistentEntitiesScriptEngine();
195  void resetNonPersistentEntitiesScriptEngine();
196  void setupEntityScriptEngineSignals(const ScriptManagerPointer& scriptManager);
197 
198  void findBestZoneAndMaybeContainingEntities(QSet<EntityItemID>& entitiesContainingAvatar);
199 
200  bool applyLayeredZones();
201  void stopDomainAndNonOwnedEntities();
202 
203  EntityItemID _currentHoverOverEntityID;
204  EntityItemID _currentClickingOnEntityID;
205 
206  ScriptValueList createEntityArgs(const EntityItemID& entityID);
207  void checkEnterLeaveEntities();
208  void leaveDomainAndNonOwnedEntities();
209  void leaveAllEntities();
210  void forceRecheckEntities();
211 
212  glm::vec3 _avatarPosition { 0.0f };
213  bool _forceRecheckEntities { true };
214  QSet<EntityItemID> _currentEntitiesInside;
215 
216  bool _wantScripts;
217  ScriptManagerPointer _nonPersistentEntitiesScriptManager; // used for domain + non-owned avatar entities, cleared on domain switch
218  ScriptManagerPointer _persistentEntitiesScriptManager; // used for local + owned avatar entities, persists on domain switch, cleared on reload content
219 
220  void playEntityCollisionSound(const EntityItemPointer& entity, const Collision& collision);
221 
222  bool _lastPointerEventValid;
223  PointerEvent _lastPointerEvent;
224  AbstractViewStateInterface* _viewState;
225  AbstractScriptingServicesInterface* _scriptingServices;
226  bool _displayModelBounds;
227 
228  bool _shuttingDown { false };
229 
230  QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
231 
232  unsigned int _mouseRayPickID;
233  std::function<RayToEntityIntersectionResult(unsigned int)> _getPrevRayPickResultOperator;
234  std::function<void(unsigned int, bool)> _setPrecisionPickingOperator;
235 
236  class LayeredZone {
237  public:
238  LayeredZone(std::shared_ptr<ZoneEntityItem> zone) : zone(zone), id(zone->getID()), volume(zone->getVolumeEstimate()) {}
239 
240  // We need to sort on volume AND id so that different clients sort zones with identical volumes the same way
241  bool operator<(const LayeredZone& r) const { return volume < r.volume || (volume == r.volume && id < r.id); }
242  bool operator==(const LayeredZone& r) const { return zone.lock() && zone.lock() == r.zone.lock(); }
243  bool operator!=(const LayeredZone& r) const { return !(*this == r); }
244  bool operator<=(const LayeredZone& r) const { return (*this < r) || (*this == r); }
245 
246  std::weak_ptr<ZoneEntityItem> zone;
247  QUuid id;
248  float volume;
249  };
250 
251  class LayeredZones : public std::vector<LayeredZone> {
252  public:
253  bool clearDomainAndNonOwnedZones();
254 
255  void sort() { std::sort(begin(), end(), std::less<LayeredZone>()); }
256  bool equals(const LayeredZones& other) const;
257  bool update(std::shared_ptr<ZoneEntityItem> zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer);
258 
259  void appendRenderIDs(render::ItemIDs& list, EntityTreeRenderer* entityTreeRenderer) const;
260  std::pair<bool, bool> getZoneInteractionProperties() const;
261  FadeProperties getFadeProperties(const TransitionType type) const;
262  bool hasFade(const TransitionType type) const;
263  };
264 
265  LayeredZones _layeredZones;
266  uint64_t _lastZoneCheck { 0 };
267  const uint64_t ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz
268  const float ZONE_CHECK_DISTANCE = 0.001f;
269 
270  float _avgRenderableUpdateCost { 0.0f };
271 
272  ReadWriteLockable _changedEntitiesGuard;
273  std::unordered_set<EntityItemID> _changedEntities;
274  size_t _prevNumEntityUpdates { 0 };
275  size_t _prevTotalNeededEntityUpdates { 0 };
276 
277  std::unordered_set<EntityRendererPointer> _renderablesToUpdate;
278  std::unordered_map<EntityItemID, EntityRendererPointer> _entitiesInScene;
279  std::unordered_map<EntityItemID, EntityItemWeakPointer> _entitiesToAdd;
280 
281  // For Scene.shouldRenderEntities
282  QList<EntityItemID> _entityIDsLastInScene;
283 
284  static int _entitiesScriptEngineCount;
285  static CalculateEntityLoadingPriority _calculateEntityLoadingPriorityFunc;
286 
287  mutable std::mutex _spaceLock;
288  workload::SpacePointer _space{ new workload::Space() };
289  workload::Transaction::Updates _spaceUpdates;
290 
291  static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToEntityOperator;
292  static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromEntityOperator;
293  static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator;
294  static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromAvatarOperator;
295 
296 };
297 
298 
299 #endif // hifi_EntityTreeRenderer_h
Interface provided by Application to other objects that need access to scripting services of the appl...
Definition: AbstractScriptingServicesInterface.h:26
Interface provided by Application to other objects that need access to the current view state details...
Definition: AbstractViewStateInterface.h:31
Utility for processing, packing, queueing and sending of outbound edit voxel messages.
Definition: EntityEditPacketSender.h:25
Abstract ID for editing model items. Used in EntityItem JS API.
Definition: EntityItemID.h:28
A generic 3D model displaying geometry loaded from a URL.
Definition: Model.h:85
Represents a 2D or 3D pointer to the scripting engine. Exposed as PointerEvent
Definition: PointerEvent.h:32
Provides an engine-independent interface for a scripting engine.
Definition: ScriptEngine.h:93
Manages a single scripting engine.
Definition: ScriptManager.h:281