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  const QString& oldScriptURL = "",
154  const QString& newScriptURL = "");
155  void unloadEntityScript(const EntityItemID& entityID, const QString& scriptURL);
156  void updateScriptUserData(const EntityItemID& entityID, const QString& scriptURL, const QString& userData);
157 
158 signals:
159  void enterEntity(const EntityItemID& entityItemID);
160  void leaveEntity(const EntityItemID& entityItemID);
161  void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
162 
163 public slots:
164  void addingEntity(const EntityItemID& entityID);
165  void deletingEntity(const EntityItemID& entityID);
166  void entityScriptChanging(const EntityItemID& entityID, const QString& oldScriptURL, const QString& newScriptURL);
167  void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
168  void updateEntityRenderStatus(bool shouldRenderEntities);
169  void updateZone(const EntityItemID& id);
170 
171  // optional slots that can be wired to menu items
172  void setDisplayModelBounds(bool value) { _displayModelBounds = value; }
173  void setPrecisionPicking(bool value) { _setPrecisionPickingOperator(_mouseRayPickID, value); }
174  EntityRendererPointer renderableForEntityId(const EntityItemID& id) const;
175  render::ItemID renderableIdForEntityId(const EntityItemID& id) const;
176 
177  void handleSpaceUpdate(std::pair<int32_t, glm::vec4> proxyUpdate);
178 
179 protected:
180  virtual OctreePointer createTree() override {
181  EntityTreePointer newTree = std::make_shared<EntityTree>(true);
182  newTree->createRootElement();
183  return newTree;
184  }
185 
186 private:
187  void addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction);
188  void updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction);
189  EntityRendererPointer renderableForEntity(const EntityItemPointer& entity) const { return renderableForEntityId(entity->getID()); }
190  render::ItemID renderableIdForEntity(const EntityItemPointer& entity) const { return renderableIdForEntityId(entity->getID()); }
191 
192  void resetPersistentEntitiesScriptEngine();
193  void resetNonPersistentEntitiesScriptEngine();
194  void setupEntityScriptEngineSignals(const ScriptManagerPointer& scriptManager);
195 
196  void findBestZoneAndMaybeContainingEntities(QSet<EntityItemID>& entitiesContainingAvatar);
197 
198  bool applyLayeredZones();
199  void stopDomainAndNonOwnedEntities();
200 
201  EntityItemID _currentHoverOverEntityID;
202  EntityItemID _currentClickingOnEntityID;
203 
204  ScriptValueList createEntityArgs(const EntityItemID& entityID);
205  void checkEnterLeaveEntities();
206  void leaveDomainAndNonOwnedEntities();
207  void leaveAllEntities();
208  void forceRecheckEntities();
209 
210  glm::vec3 _avatarPosition { 0.0f };
211  bool _forceRecheckEntities { true };
212  QSet<EntityItemID> _currentEntitiesInside;
213 
214  bool _wantScripts;
215  ScriptManagerPointer _nonPersistentEntitiesScriptManager; // used for domain + non-owned avatar entities, cleared on domain switch
216  ScriptManagerPointer _persistentEntitiesScriptManager; // used for local + owned avatar entities, persists on domain switch, cleared on reload content
217 
218  void playEntityCollisionSound(const EntityItemPointer& entity, const Collision& collision);
219 
220  bool _lastPointerEventValid;
221  PointerEvent _lastPointerEvent;
222  AbstractViewStateInterface* _viewState;
223  AbstractScriptingServicesInterface* _scriptingServices;
224  bool _displayModelBounds;
225 
226  bool _shuttingDown { false };
227 
228  QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
229 
230  unsigned int _mouseRayPickID;
231  std::function<RayToEntityIntersectionResult(unsigned int)> _getPrevRayPickResultOperator;
232  std::function<void(unsigned int, bool)> _setPrecisionPickingOperator;
233 
234  class LayeredZone {
235  public:
236  LayeredZone(std::shared_ptr<ZoneEntityItem> zone) : zone(zone), id(zone->getID()), volume(zone->getVolumeEstimate()) {}
237 
238  // We need to sort on volume AND id so that different clients sort zones with identical volumes the same way
239  bool operator<(const LayeredZone& r) const { return volume < r.volume || (volume == r.volume && id < r.id); }
240  bool operator==(const LayeredZone& r) const { return zone.lock() && zone.lock() == r.zone.lock(); }
241  bool operator!=(const LayeredZone& r) const { return !(*this == r); }
242  bool operator<=(const LayeredZone& r) const { return (*this < r) || (*this == r); }
243 
244  std::weak_ptr<ZoneEntityItem> zone;
245  QUuid id;
246  float volume;
247  };
248 
249  class LayeredZones : public std::vector<LayeredZone> {
250  public:
251  bool clearDomainAndNonOwnedZones();
252 
253  void sort() { std::sort(begin(), end(), std::less<LayeredZone>()); }
254  bool equals(const LayeredZones& other) const;
255  bool update(std::shared_ptr<ZoneEntityItem> zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer);
256 
257  void appendRenderIDs(render::ItemIDs& list, EntityTreeRenderer* entityTreeRenderer) const;
258  std::pair<bool, bool> getZoneInteractionProperties() const;
259  FadeProperties getFadeProperties(const TransitionType type) const;
260  bool hasFade(const TransitionType type) const;
261  };
262 
263  LayeredZones _layeredZones;
264  uint64_t _lastZoneCheck { 0 };
265  const uint64_t ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz
266  const float ZONE_CHECK_DISTANCE = 0.001f;
267 
268  float _avgRenderableUpdateCost { 0.0f };
269 
270  ReadWriteLockable _changedEntitiesGuard;
271  std::unordered_set<EntityItemID> _changedEntities;
272  size_t _prevNumEntityUpdates { 0 };
273  size_t _prevTotalNeededEntityUpdates { 0 };
274 
275  std::unordered_set<EntityRendererPointer> _renderablesToUpdate;
276  std::unordered_map<EntityItemID, EntityRendererPointer> _entitiesInScene;
277  std::unordered_map<EntityItemID, EntityItemWeakPointer> _entitiesToAdd;
278 
279  // For Scene.shouldRenderEntities
280  QList<EntityItemID> _entityIDsLastInScene;
281 
282  static int _entitiesScriptEngineCount;
283  static CalculateEntityLoadingPriority _calculateEntityLoadingPriorityFunc;
284 
285  mutable std::mutex _spaceLock;
286  workload::SpacePointer _space{ new workload::Space() };
287  workload::Transaction::Updates _spaceUpdates;
288 
289  static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToEntityOperator;
290  static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromEntityOperator;
291  static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator;
292  static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromAvatarOperator;
293 
294 };
295 
296 
297 #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:282
Transaction is the mechanism to make any change to the scene. Whenever a new item need to be reset,...
Definition: Scene.h:40