#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H #define OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H #include "areatype.hpp" #include "changetype.hpp" #include "commulativeaabb.hpp" #include "gettilespositions.hpp" #include "heightfieldshape.hpp" #include "objectid.hpp" #include "recastmesh.hpp" #include "recastmeshobject.hpp" #include "tileposition.hpp" #include "updateguard.hpp" #include "version.hpp" #include #include #include #include #include #include #include #include #include #include namespace DetourNavigator { class RecastMesh; struct TileCachedRecastMeshManagerStats; class TileCachedRecastMeshManager { public: explicit TileCachedRecastMeshManager(const RecastSettings& settings); ScopedUpdateGuard makeUpdateGuard() { mMutex.lock(); return ScopedUpdateGuard(&mUpdateGuard); } void setRange(const TilesPositionsRange& range, const UpdateGuard* guard); TilesPositionsRange getLimitedObjectsRange() const; void setWorldspace(ESM::RefId worldspace, const UpdateGuard* guard); bool addObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, AreaType areaType, const UpdateGuard* guard); bool updateObject(ObjectId id, const btTransform& transform, AreaType areaType, const UpdateGuard* guard); void removeObject(ObjectId id, const UpdateGuard* guard); void addWater(const osg::Vec2i& cellPosition, int cellSize, float level, const UpdateGuard* guard); void removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard); void addHeightfield( const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, const UpdateGuard* guard); void removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard); std::shared_ptr getMesh(ESM::RefId worldspace, const TilePosition& tilePosition); std::shared_ptr getCachedMesh(ESM::RefId worldspace, const TilePosition& tilePosition) const; std::shared_ptr getNewMesh(ESM::RefId worldspace, const TilePosition& tilePosition) const; std::size_t getRevision() const { return mRevision; } void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion); void addChangedTile(const TilePosition& tilePosition, ChangeType changeType); std::map takeChangedTiles(const UpdateGuard* guard); TileCachedRecastMeshManagerStats getStats() const; private: struct Report { std::size_t mRevision; Version mNavMeshVersion; }; struct ObjectData { RecastMeshObject mObject; TilesPositionsRange mRange; CommulativeAabb mAabb; std::size_t mGeneration = 0; std::size_t mRevision = 0; std::optional mLastNavMeshReportedChange; std::optional mLastNavMeshReport; }; struct WaterData { Water mWater; std::optional mRange; std::size_t mRevision; }; struct HeightfieldData { int mCellSize; HeightfieldShape mShape; std::optional mRange; std::size_t mRevision; }; struct CachedTile { Version mVersion; std::shared_ptr mRecastMesh; }; using IndexPoint = boost::geometry::model::point; using IndexBox = boost::geometry::model::box; using ObjectIndexValue = std::pair; using WaterIndexValue = std::pair::const_iterator>; using HeightfieldIndexValue = std::pair::const_iterator>; const RecastSettings& mSettings; TilesPositionsRange mRange; ESM::RefId mWorldspace; std::unordered_map> mObjects; boost::geometry::index::rtree> mObjectIndex; std::map mWater; std::map::const_iterator mInfiniteWater = mWater.end(); boost::geometry::index::rtree> mWaterIndex; std::map mHeightfields; std::map::const_iterator mInfiniteHeightfield = mHeightfields.end(); boost::geometry::index::rtree> mHeightfieldIndex; std::map mChangedTiles; std::map mCache; std::size_t mGeneration = 0; std::size_t mRevision = 0; mutable std::mutex mMutex; UpdateGuard mUpdateGuard{ mMutex }; inline static IndexPoint makeIndexPoint(const TilePosition& tilePosition); inline static IndexBox makeIndexBox(const TilesPositionsRange& range); inline static ObjectIndexValue makeObjectIndexValue(const TilesPositionsRange& range, ObjectData* data); inline static WaterIndexValue makeWaterIndexValue( const TilesPositionsRange& range, std::map::const_iterator it); inline static HeightfieldIndexValue makeHeightfieldIndexValue( const TilesPositionsRange& range, std::map::const_iterator it); inline static auto makeIndexQuery(const TilePosition& tilePosition) -> decltype(boost::geometry::index::intersects(IndexBox())); inline std::shared_ptr makeMesh(const TilePosition& tilePosition) const; inline void addChangedTiles(const std::optional& range, ChangeType changeType); }; } #endif