You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/components/detournavigator/navmeshtilescache.hpp

157 lines
4.5 KiB
C++

#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVMESHTILESCACHE_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVMESHTILESCACHE_H
#include "agentbounds.hpp"
#include "preparednavmeshdata.hpp"
#include "recastmesh.hpp"
#include "tileposition.hpp"
#include <atomic>
#include <cassert>
#include <cstring>
#include <list>
#include <map>
#include <mutex>
#include <vector>
namespace DetourNavigator
{
struct RecastMeshData
{
Mesh mMesh;
std::vector<CellWater> mWater;
std::vector<Heightfield> mHeightfields;
std::vector<FlatHeightfield> mFlatHeightfields;
};
inline bool operator<(const RecastMeshData& lhs, const RecastMeshData& rhs)
{
return std::tie(lhs.mMesh, lhs.mWater, lhs.mHeightfields, lhs.mFlatHeightfields)
< std::tie(rhs.mMesh, rhs.mWater, rhs.mHeightfields, rhs.mFlatHeightfields);
}
inline bool operator<(const RecastMeshData& lhs, const RecastMesh& rhs)
{
return std::tie(lhs.mMesh, lhs.mWater, lhs.mHeightfields, lhs.mFlatHeightfields)
< std::tie(rhs.getMesh(), rhs.getWater(), rhs.getHeightfields(), rhs.getFlatHeightfields());
}
inline bool operator<(const RecastMesh& lhs, const RecastMeshData& rhs)
{
return std::tie(lhs.getMesh(), lhs.getWater(), lhs.getHeightfields(), lhs.getFlatHeightfields())
< std::tie(rhs.mMesh, rhs.mWater, rhs.mHeightfields, rhs.mFlatHeightfields);
}
struct NavMeshTilesCacheStats;
class NavMeshTilesCache
{
public:
struct Item
{
std::atomic<std::int64_t> mUseCount;
AgentBounds mAgentBounds;
TilePosition mChangedTile;
RecastMeshData mRecastMeshData;
std::unique_ptr<PreparedNavMeshData> mPreparedNavMeshData;
std::size_t mSize;
Item(const AgentBounds& agentBounds, const TilePosition& changedTile, RecastMeshData&& recastMeshData,
std::size_t size)
: mUseCount(0)
, mAgentBounds(agentBounds)
, mChangedTile(changedTile)
, mRecastMeshData(std::move(recastMeshData))
, mSize(size)
{
}
};
using ItemIterator = std::list<Item>::iterator;
class Value
{
public:
Value()
: mOwner(nullptr)
, mIterator()
{
}
Value(NavMeshTilesCache& owner, ItemIterator iterator)
: mOwner(&owner)
, mIterator(iterator)
{
}
Value(const Value& other) = delete;
Value(Value&& other)
: mOwner(other.mOwner)
, mIterator(other.mIterator)
{
other.mOwner = nullptr;
}
~Value()
{
if (mOwner)
mOwner->releaseItem(mIterator);
}
Value& operator=(const Value& other) = delete;
Value& operator=(Value&& other)
{
if (mOwner)
mOwner->releaseItem(mIterator);
mOwner = other.mOwner;
mIterator = other.mIterator;
other.mOwner = nullptr;
return *this;
}
const PreparedNavMeshData& get() const { return *mIterator->mPreparedNavMeshData; }
operator bool() const { return mOwner; }
private:
NavMeshTilesCache* mOwner;
ItemIterator mIterator;
};
NavMeshTilesCache(const std::size_t maxNavMeshDataSize);
Value get(const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh);
Value set(const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh,
std::unique_ptr<PreparedNavMeshData>&& value);
NavMeshTilesCacheStats getStats() const;
private:
mutable std::mutex mMutex;
std::size_t mMaxNavMeshDataSize;
std::size_t mUsedNavMeshDataSize;
std::size_t mFreeNavMeshDataSize;
std::size_t mHitCount;
std::size_t mGetCount;
std::list<Item> mBusyItems;
std::list<Item> mFreeItems;
std::map<std::tuple<AgentBounds, TilePosition, std::reference_wrapper<const RecastMeshData>>, ItemIterator,
std::less<>>
mValues;
void removeLeastRecentlyUsed();
void acquireItemUnsafe(ItemIterator iterator);
void releaseItem(ItemIterator iterator);
};
}
#endif