1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2024-12-28 00:15:06 +00:00
OpenMW/components/detournavigator/tilecachedrecastmeshmanager.hpp

169 lines
6.2 KiB
C++

#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 <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <LinearMath/btTransform.h>
#include <osg/Vec2i>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace DetourNavigator
{
class RecastMesh;
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(std::string_view 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<RecastMesh> getMesh(std::string_view worldspace, const TilePosition& tilePosition);
std::shared_ptr<RecastMesh> getCachedMesh(std::string_view worldspace, const TilePosition& tilePosition) const;
std::shared_ptr<RecastMesh> getNewMesh(std::string_view 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<osg::Vec2i, ChangeType> takeChangedTiles(const UpdateGuard* guard);
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<Report> mLastNavMeshReportedChange;
std::optional<Report> mLastNavMeshReport;
};
struct WaterData
{
Water mWater;
std::optional<TilesPositionsRange> mRange;
std::size_t mRevision;
};
struct HeightfieldData
{
int mCellSize;
HeightfieldShape mShape;
std::optional<TilesPositionsRange> mRange;
std::size_t mRevision;
};
struct CachedTile
{
Version mVersion;
std::shared_ptr<RecastMesh> mRecastMesh;
};
using IndexPoint = boost::geometry::model::point<int, 2, boost::geometry::cs::cartesian>;
using IndexBox = boost::geometry::model::box<IndexPoint>;
using ObjectIndexValue = std::pair<IndexBox, ObjectData*>;
using WaterIndexValue = std::pair<IndexBox, std::map<osg::Vec2i, WaterData>::const_iterator>;
using HeightfieldIndexValue = std::pair<IndexBox, std::map<osg::Vec2i, HeightfieldData>::const_iterator>;
const RecastSettings& mSettings;
TilesPositionsRange mRange;
std::string mWorldspace;
std::unordered_map<ObjectId, std::unique_ptr<ObjectData>> mObjects;
boost::geometry::index::rtree<ObjectIndexValue, boost::geometry::index::quadratic<16>> mObjectIndex;
std::map<osg::Vec2i, WaterData> mWater;
std::map<osg::Vec2i, WaterData>::const_iterator mInfiniteWater = mWater.end();
boost::geometry::index::rtree<WaterIndexValue, boost::geometry::index::linear<4>> mWaterIndex;
std::map<osg::Vec2i, HeightfieldData> mHeightfields;
std::map<osg::Vec2i, HeightfieldData>::const_iterator mInfiniteHeightfield = mHeightfields.end();
boost::geometry::index::rtree<HeightfieldIndexValue, boost::geometry::index::linear<4>> mHeightfieldIndex;
std::map<osg::Vec2i, ChangeType> mChangedTiles;
std::map<TilePosition, CachedTile> 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<osg::Vec2i, WaterData>::const_iterator it);
inline static HeightfieldIndexValue makeHeightfieldIndexValue(
const TilesPositionsRange& range, std::map<osg::Vec2i, HeightfieldData>::const_iterator it);
inline static auto makeIndexQuery(const TilePosition& tilePosition)
-> decltype(boost::geometry::index::intersects(IndexBox()));
inline std::shared_ptr<RecastMesh> makeMesh(const TilePosition& tilePosition) const;
inline void addChangedTiles(const std::optional<TilesPositionsRange>& range, ChangeType changeType);
};
}
#endif