// // EntityTreeRenderer.h // interface/src // // Created by Brad Hefta-Gaub on 12/6/13. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #ifndef hifi_EntityTreeRenderer_h #define hifi_EntityTreeRenderer_h #include #include #include #include // for RayToEntityIntersectionResult #include #include #include #include #include class AbstractScriptingServicesInterface; class AbstractViewStateInterface; class Model; class ScriptEngine; class ZoneEntityItem; class EntityItem; class Model; using ModelPointer = std::shared_ptr; using ModelWeakPointer = std::weak_ptr; using CalculateEntityLoadingPriority = std::function; // Generic client side Octree renderer class. class EntityTreeRenderer : public OctreeRenderer, public EntityItemFBXService, public Dependency { Q_OBJECT public: EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState, AbstractScriptingServicesInterface* scriptingServices); virtual ~EntityTreeRenderer(); virtual char getMyNodeType() const { return NodeType::EntityServer; } virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; } virtual PacketType getExpectedPacketType() const { return PacketType::EntityData; } virtual void setTree(OctreePointer newTree); // Returns the priority at which an entity should be loaded. Higher values indicate higher priority. float getEntityLoadingPriority(const EntityItem& item) const { return _calculateEntityLoadingPriorityFunc(item); } void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { this->_calculateEntityLoadingPriorityFunc = fn; } void shutdown(); void update(); EntityTreePointer getTree() { return std::static_pointer_cast(_tree); } void processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode); virtual void init(); virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem); virtual ModelPointer getModelForEntityItem(EntityItemPointer entityItem); virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem); /// clears the tree virtual void clear(); /// reloads the entity scripts, calling unload and preload void reloadEntityScripts(); /// if a renderable entity item needs a model, we will allocate it for them Q_INVOKABLE ModelPointer allocateModel(const QString& url, const QString& collisionUrl, float loadingPriority = 0.0f); /// if a renderable entity item needs to update the URL of a model, we will handle that for the entity Q_INVOKABLE ModelPointer updateModel(ModelPointer original, const QString& newUrl, const QString& collisionUrl); /// if a renderable entity item is done with a model, it should return it to us void releaseModel(ModelPointer model); void deleteReleasedModels(); // event handles which may generate entity related events void mouseReleaseEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); /// connect our signals to anEntityScriptingInterface for firing of events related clicking, /// hovering over, and entering entities void connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface); // For Scene.shouldRenderEntities QList& getEntitiesLastInScene() { return _entityIDsLastInScene; } std::shared_ptr myAvatarZone() { return _bestZone; } signals: void mousePressOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event); void mousePressOffEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event); void mouseMoveOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event); void mouseReleaseOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event); void clickDownOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); void holdingClickOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); void clickReleaseOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); void hoverEnterEntity(const EntityItemID& entityItemID, const MouseEvent& event); void hoverOverEntity(const EntityItemID& entityItemID, const MouseEvent& event); void hoverLeaveEntity(const EntityItemID& entityItemID, const MouseEvent& event); void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); public slots: void addingEntity(const EntityItemID& entityID); void deletingEntity(const EntityItemID& entityID); void entitySciptChanging(const EntityItemID& entityID, const bool reload); void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); void updateEntityRenderStatus(bool shouldRenderEntities); void updateZone(const EntityItemID& id); // optional slots that can be wired to menu items void setDisplayModelBounds(bool value) { _displayModelBounds = value; } void setDontDoPrecisionPicking(bool value) { _dontDoPrecisionPicking = value; } protected: virtual OctreePointer createTree() { EntityTreePointer newTree = EntityTreePointer(new EntityTree(true)); newTree->createRootElement(); return newTree; } private: void resetEntitiesScriptEngine(); void addEntityToScene(EntityItemPointer entity); bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector* entitiesContainingAvatar); void applyZonePropertiesToScene(std::shared_ptr zone); void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false); QList _releasedModels; RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, bool precisionPicking, const QVector& entityIdsToInclude = QVector(), const QVector& entityIdsToDiscard = QVector()); EntityItemID _currentHoverOverEntityID; EntityItemID _currentClickingOnEntityID; QScriptValueList createEntityArgs(const EntityItemID& entityID); bool checkEnterLeaveEntities(); void leaveAllEntities(); void forceRecheckEntities(); glm::vec3 _lastAvatarPosition { 0.0f }; QVector _currentEntitiesInside; bool _pendingSkyboxTexture { false }; NetworkTexturePointer _skyboxTexture; bool _pendingAmbientTexture { false }; NetworkTexturePointer _ambientTexture; bool _wantScripts; QSharedPointer _entitiesScriptEngine; bool isCollisionOwner(const QUuid& myNodeID, EntityTreePointer entityTree, const EntityItemID& id, const Collision& collision); void playEntityCollisionSound(const QUuid& myNodeID, EntityTreePointer entityTree, const EntityItemID& id, const Collision& collision); bool _lastMouseEventValid; MouseEvent _lastMouseEvent; AbstractViewStateInterface* _viewState; AbstractScriptingServicesInterface* _scriptingServices; bool _displayModelBounds; bool _dontDoPrecisionPicking; bool _shuttingDown { false }; QMultiMap _waitingOnPreload; std::shared_ptr _bestZone; float _bestZoneVolume; QString _zoneUserData; quint64 _lastZoneCheck { 0 }; const quint64 ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz const float ZONE_CHECK_DISTANCE = 0.001f; QHash _entitiesInScene; // For Scene.shouldRenderEntities QList _entityIDsLastInScene; static int _entitiesScriptEngineCount; CalculateEntityLoadingPriority _calculateEntityLoadingPriorityFunc = [](const EntityItem& item) -> float { return 0.0f; }; }; #endif // hifi_EntityTreeRenderer_h