Add pathgrid to navmesh as off mesh connection

pull/578/head
elsid 5 years ago
parent 095a45c714
commit c4cd3b2c4f
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -86,7 +86,7 @@ add_openmw_dir (mwmechanics
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
character actors objects aistate coordinateconverter trading weaponpriority spellpriority weapontype spellutil tickableeffects
character actors objects aistate trading weaponpriority spellpriority weapontype spellutil tickableeffects
spellabsorption linkedeffects
)

@ -1,6 +1,7 @@
#include "aicombat.hpp"
#include <components/misc/rng.hpp>
#include <components/misc/coordinateconverter.hpp>
#include <components/esm/aisequence.hpp>
@ -21,7 +22,6 @@
#include "movement.hpp"
#include "character.hpp"
#include "aicombataction.hpp"
#include "coordinateconverter.hpp"
#include "actorutil.hpp"
namespace
@ -302,7 +302,7 @@ namespace MWMechanics
if (pathgrid && !actor.getClass().isPureWaterCreature(actor))
{
ESM::Pathgrid::PointList points;
CoordinateConverter coords(storage.mCell->getCell());
Misc::CoordinateConverter coords(storage.mCell->getCell());
osg::Vec3f localPos = actor.getRefData().getPosition().asVec3();
coords.toLocal(localPos);

@ -4,6 +4,7 @@
#include <components/esm/loadland.hpp>
#include <components/esm/loadmgef.hpp>
#include <components/detournavigator/navigator.hpp>
#include <components/misc/coordinateconverter.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
@ -20,7 +21,6 @@
#include "movement.hpp"
#include "steering.hpp"
#include "actorutil.hpp"
#include "coordinateconverter.hpp"
#include <osg/Quat>
@ -341,7 +341,7 @@ bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position)
if (playerCell->isExterior())
{
// get actor's distance from origin of center cell
CoordinateConverter(playerCell).toLocal(position);
Misc::CoordinateConverter(playerCell).toLocal(position);
// currently assumes 3 x 3 grid for exterior cells, with player at center cell.
// ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells

@ -6,6 +6,7 @@
#include <components/misc/rng.hpp>
#include <components/esm/aisequence.hpp>
#include <components/detournavigator/navigator.hpp>
#include <components/misc/coordinateconverter.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
@ -21,7 +22,6 @@
#include "pathgrid.hpp"
#include "creaturestats.hpp"
#include "movement.hpp"
#include "coordinateconverter.hpp"
#include "actorutil.hpp"
namespace MWMechanics
@ -566,7 +566,7 @@ namespace MWMechanics
void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell)
{
CoordinateConverter(cell).toWorld(point);
Misc::CoordinateConverter(cell).toWorld(point);
}
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes,
@ -767,7 +767,7 @@ namespace MWMechanics
{
// get NPC's position in local (i.e. cell) coordinates
osg::Vec3f npcPos(mInitialActorPosition);
CoordinateConverter(cell).toLocal(npcPos);
Misc::CoordinateConverter(cell).toLocal(npcPos);
// Find closest pathgrid point
int closestPointIndex = PathFinder::getClosestPoint(pathgrid, npcPos);

@ -1,44 +0,0 @@
#include "coordinateconverter.hpp"
#include <components/esm/loadcell.hpp>
#include <components/esm/loadland.hpp>
namespace MWMechanics
{
CoordinateConverter::CoordinateConverter(const ESM::Cell* cell)
: mCellX(0), mCellY(0)
{
if (cell->isExterior())
{
mCellX = cell->mData.mX * ESM::Land::REAL_SIZE;
mCellY = cell->mData.mY * ESM::Land::REAL_SIZE;
}
}
void CoordinateConverter::toWorld(ESM::Pathgrid::Point& point)
{
point.mX += mCellX;
point.mY += mCellY;
}
void CoordinateConverter::toWorld(osg::Vec3f& point)
{
point.x() += static_cast<float>(mCellX);
point.y() += static_cast<float>(mCellY);
}
void CoordinateConverter::toLocal(osg::Vec3f& point)
{
point.x() -= static_cast<float>(mCellX);
point.y() -= static_cast<float>(mCellY);
}
osg::Vec3f CoordinateConverter::toLocalVec3(const osg::Vec3f& point)
{
return osg::Vec3f(
point.x() - static_cast<float>(mCellX),
point.y() - static_cast<float>(mCellY),
point.z()
);
}
}

@ -1,37 +0,0 @@
#ifndef GAME_MWMECHANICS_COORDINATECONVERTER_H
#define GAME_MWMECHANICS_COORDINATECONVERTER_H
#include <components/esm/defs.hpp>
#include <components/esm/loadpgrd.hpp>
namespace ESM
{
struct Cell;
}
namespace MWMechanics
{
/// \brief convert coordinates between world and local cell
class CoordinateConverter
{
public:
CoordinateConverter(const ESM::Cell* cell);
/// in-place conversion from local to world
void toWorld(ESM::Pathgrid::Point& point);
/// in-place conversion from local to world
void toWorld(osg::Vec3f& point);
/// in-place conversion from world to local
void toLocal(osg::Vec3f& point);
osg::Vec3f toLocalVec3(const osg::Vec3f& point);
private:
int mCellX;
int mCellY;
};
}
#endif

@ -7,6 +7,7 @@
#include <components/detournavigator/debug.hpp>
#include <components/detournavigator/navigator.hpp>
#include <components/debug/debuglog.hpp>
#include <components/misc/coordinateconverter.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
@ -17,7 +18,6 @@
#include "../mwworld/class.hpp"
#include "pathgrid.hpp"
#include "coordinateconverter.hpp"
#include "actorutil.hpp"
namespace
@ -164,7 +164,7 @@ namespace MWMechanics
}
// NOTE: getClosestPoint expects local coordinates
CoordinateConverter converter(mCell->getCell());
Misc::CoordinateConverter converter(mCell->getCell());
// NOTE: It is possible that getClosestPoint returns a pathgrind point index
// that is unreachable in some situations. e.g. actor is standing
@ -331,6 +331,10 @@ namespace MWMechanics
if (!actor.getClass().isPureWaterCreature(actor) && !actor.getClass().isPureFlyingCreature(actor))
buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath));
if (mPath.empty())
buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents,
flags | DetourNavigator::Flag_usePathgrid, std::back_inserter(mPath));
if (mPath.empty())
buildPathByPathgridImpl(startPoint, endPoint, pathgridGraph, std::back_inserter(mPath));

@ -8,6 +8,7 @@
#include <components/esm/loadpgrd.hpp>
#include <components/sceneutil/pathgridutil.hpp>
#include <components/misc/coordinateconverter.hpp>
#include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone
#include "../mwbase/environment.hpp"
@ -15,7 +16,6 @@
#include "../mwworld/cellstore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwmechanics/pathfinding.hpp"
#include "../mwmechanics/coordinateconverter.hpp"
#include "vismask.hpp"
@ -105,7 +105,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store)
if (!pathgrid) return;
osg::Vec3f cellPathGridPos(0, 0, 0);
MWMechanics::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos);
Misc::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos);
osg::ref_ptr<osg::PositionAttitudeTransform> cellPathGrid = new osg::PositionAttitudeTransform;
cellPathGrid->setPosition(cellPathGridPos);

@ -365,6 +365,9 @@ namespace MWWorld
if ((*iter)->getCell()->hasWater())
navigator->removeWater(osg::Vec2i(cellX, cellY));
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*(*iter)->getCell()))
navigator->removePathgrid(*pathgrid);
const auto player = world->getPlayerPtr();
navigator->update(player.getRefData().getPosition().asVec3());
@ -393,7 +396,8 @@ namespace MWWorld
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
const auto world = MWBase::Environment::get().getWorld();
const auto navigator = world->getNavigator();
const int cellX = cell->getCell()->getGridX();
const int cellY = cell->getCell()->getGridY();
@ -419,6 +423,9 @@ namespace MWWorld
heightField->getCollisionObject()->getWorldTransform());
}
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
navigator->addPathgrid(*cell->getCell(), *pathgrid);
// register local scripts
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);

@ -9,6 +9,8 @@ namespace DetourNavigator
{
AreaType_null = RC_NULL_AREA,
AreaType_water,
AreaType_door,
AreaType_pathgrid,
AreaType_ground = RC_WALKABLE_AREA,
};
}

@ -13,6 +13,7 @@ namespace DetourNavigator
Flag_walk = 1 << 0,
Flag_swim = 1 << 1,
Flag_openDoor = 1 << 2,
Flag_usePathgrid = 1 << 3,
};
inline std::ostream& operator <<(std::ostream& stream, const Flag value)
@ -27,6 +28,8 @@ namespace DetourNavigator
return stream << "swim";
case Flag_openDoor:
return stream << "openDoor";
case Flag_usePathgrid:
return stream << "usePathgrid";
}
return stream;
@ -45,7 +48,7 @@ namespace DetourNavigator
else
{
bool first = true;
for (const auto flag : {Flag_walk, Flag_swim, Flag_openDoor})
for (const auto flag : {Flag_walk, Flag_swim, Flag_openDoor, Flag_usePathgrid})
{
if (value.mValue & flag)
{

@ -98,6 +98,42 @@ namespace
return result;
}
Flag getFlag(AreaType areaType)
{
switch (areaType)
{
case AreaType_null:
return Flag_none;
case AreaType_ground:
return Flag_walk;
case AreaType_water:
return Flag_swim;
case AreaType_door:
return Flag_openDoor;
case AreaType_pathgrid:
return Flag_usePathgrid;
}
return Flag_none;
}
std::vector<unsigned char> getOffMeshConAreas(const std::vector<OffMeshConnection>& connections)
{
std::vector<unsigned char> result;
result.reserve(connections.size());
std::transform(connections.begin(), connections.end(), std::back_inserter(result),
[] (const OffMeshConnection& v) { return v.mAreaType; });
return result;
}
std::vector<unsigned short> getOffMeshFlags(const std::vector<OffMeshConnection>& connections)
{
std::vector<unsigned short> result;
result.reserve(connections.size());
std::transform(connections.begin(), connections.end(), std::back_inserter(result),
[] (const OffMeshConnection& v) { return getFlag(v.mAreaType); });
return result;
}
rcConfig makeConfig(const osg::Vec3f& agentHalfExtents, const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax,
const Settings& settings)
{
@ -334,12 +370,7 @@ namespace
void setPolyMeshFlags(rcPolyMesh& polyMesh)
{
for (int i = 0; i < polyMesh.npolys; ++i)
{
if (polyMesh.areas[i] == AreaType_ground)
polyMesh.flags[i] = Flag_walk;
else if (polyMesh.areas[i] == AreaType_water)
polyMesh.flags[i] = Flag_swim;
}
polyMesh.flags[i] = getFlag(static_cast<AreaType>(polyMesh.areas[i]));
}
bool fillPolyMesh(rcContext& context, const rcConfig& config, rcHeightfield& solid, rcPolyMesh& polyMesh,
@ -395,8 +426,8 @@ namespace
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents));
const std::vector<unsigned char> offMeshConDir(offMeshConnections.size(), DT_OFFMESH_CON_BIDIR);
const std::vector<unsigned char> offMeshConAreas(offMeshConnections.size(), AreaType_ground);
const std::vector<unsigned short> offMeshConFlags(offMeshConnections.size(), Flag_openDoor);
const std::vector<unsigned char> offMeshConAreas = getOffMeshConAreas(offMeshConnections);
const std::vector<unsigned short> offMeshConFlags = getOffMeshFlags(offMeshConnections);
dtNavMeshCreateParams params;
params.verts = polyMesh.verts;

@ -9,6 +9,12 @@
#include "recastmesh.hpp"
#include "recastmeshtiles.hpp"
namespace ESM
{
struct Cell;
struct Pathgrid;
}
namespace DetourNavigator
{
struct ObjectShapes
@ -139,6 +145,10 @@ namespace DetourNavigator
*/
virtual bool removeWater(const osg::Vec2i& cellPosition) = 0;
virtual void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) = 0;
virtual void removePathgrid(const ESM::Pathgrid& pathgrid) = 0;
/**
* @brief update start background navmesh update using current scene state.
* @param playerPosition setup initial point to order build tiles of navmesh.

@ -2,6 +2,9 @@
#include "debug.hpp"
#include "settingsutils.hpp"
#include <components/esm/loadpgrd.hpp>
#include <components/misc/coordinateconverter.hpp>
#include <Recast.h>
namespace DetourNavigator
@ -54,7 +57,8 @@ namespace DetourNavigator
mNavMeshManager.addOffMeshConnection(
id,
toNavMeshCoordinates(mSettings, shapes.mConnectionStart),
toNavMeshCoordinates(mSettings, shapes.mConnectionEnd)
toNavMeshCoordinates(mSettings, shapes.mConnectionEnd),
AreaType_door
);
return true;
}
@ -95,7 +99,7 @@ namespace DetourNavigator
const auto water = mWaterIds.find(id);
if (water != mWaterIds.end())
result = mNavMeshManager.removeObject(water->second) || result;
mNavMeshManager.removeOffMeshConnection(id);
mNavMeshManager.removeOffMeshConnections(id);
return result;
}
@ -111,6 +115,27 @@ namespace DetourNavigator
return mNavMeshManager.removeWater(cellPosition);
}
void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid)
{
Misc::CoordinateConverter converter(&cell);
for (auto edge : pathgrid.mEdges)
{
const auto src = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV0]));
const auto dst = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV1]));
mNavMeshManager.addOffMeshConnection(
ObjectId(&pathgrid),
toNavMeshCoordinates(mSettings, src),
toNavMeshCoordinates(mSettings, dst),
AreaType_pathgrid
);
}
}
void NavigatorImpl::removePathgrid(const ESM::Pathgrid& pathgrid)
{
mNavMeshManager.removeOffMeshConnections(ObjectId(&pathgrid));
}
void NavigatorImpl::update(const osg::Vec3f& playerPosition)
{
removeUnusedNavMeshes();

@ -4,6 +4,8 @@
#include "navigator.hpp"
#include "navmeshmanager.hpp"
#include <set>
namespace DetourNavigator
{
class NavigatorImpl final : public Navigator
@ -38,6 +40,10 @@ namespace DetourNavigator
bool removeWater(const osg::Vec2i& cellPosition) override;
void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) final;
void removePathgrid(const ESM::Pathgrid& pathgrid) final;
void update(const osg::Vec3f& playerPosition) override;
void wait() override;
@ -58,6 +64,7 @@ namespace DetourNavigator
std::map<osg::Vec3f, std::size_t> mAgents;
std::unordered_map<ObjectId, ObjectId> mAvoidIds;
std::unordered_map<ObjectId, ObjectId> mWaterIds;
std::multimap<ObjectId, ObjectId> mOffMeshConnectionIds;
void updateAvoidShapeId(const ObjectId id, const ObjectId avoidId);
void updateWaterShapeId(const ObjectId id, const ObjectId waterId);

@ -60,6 +60,10 @@ namespace DetourNavigator
return false;
}
void addPathgrid(const ESM::Cell& /*cell*/, const ESM::Pathgrid& /*pathgrid*/) final {}
void removePathgrid(const ESM::Pathgrid& /*pathgrid*/) final {}
void update(const osg::Vec3f& /*playerPosition*/) override {}
void wait() override {}

@ -110,10 +110,9 @@ namespace DetourNavigator
return true;
}
void NavMeshManager::addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end)
void NavMeshManager::addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end, const AreaType areaType)
{
if (!mOffMeshConnectionsManager.add(id, OffMeshConnection {start, end}))
return;
mOffMeshConnectionsManager.add(id, OffMeshConnection {start, end, areaType});
const auto startTilePosition = getTilePosition(mSettings, start);
const auto endTilePosition = getTilePosition(mSettings, end);
@ -124,18 +123,11 @@ namespace DetourNavigator
addChangedTile(endTilePosition, ChangeType::add);
}
void NavMeshManager::removeOffMeshConnection(const ObjectId id)
{
if (const auto connection = mOffMeshConnectionsManager.remove(id))
void NavMeshManager::removeOffMeshConnections(const ObjectId id)
{
const auto startTilePosition = getTilePosition(mSettings, connection->mStart);
const auto endTilePosition = getTilePosition(mSettings, connection->mEnd);
addChangedTile(startTilePosition, ChangeType::remove);
if (startTilePosition != endTilePosition)
addChangedTile(endTilePosition, ChangeType::remove);
}
const auto changedTiles = mOffMeshConnectionsManager.remove(id);
for (const auto& tile : changedTiles)
addChangedTile(tile, ChangeType::update);
}
void NavMeshManager::update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents)

@ -39,9 +39,9 @@ namespace DetourNavigator
bool reset(const osg::Vec3f& agentHalfExtents);
void addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end);
void addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end, const AreaType areaType);
void removeOffMeshConnection(const ObjectId id);
void removeOffMeshConnections(const ObjectId id);
void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents);

@ -1,6 +1,8 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_OFFMESHCONNECTION_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_OFFMESHCONNECTION_H
#include "areatype.hpp"
#include <osg/Vec3f>
namespace DetourNavigator
@ -9,6 +11,7 @@ namespace DetourNavigator
{
osg::Vec3f mStart;
osg::Vec3f mEnd;
AreaType mAreaType;
};
}

@ -11,14 +11,11 @@
#include <osg/Vec3f>
#include <boost/optional.hpp>
#include <algorithm>
#include <map>
#include <mutex>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <set>
namespace DetourNavigator
{
@ -29,12 +26,11 @@ namespace DetourNavigator
: mSettings(settings)
{}
bool add(const ObjectId id, const OffMeshConnection& value)
void add(const ObjectId id, const OffMeshConnection& value)
{
const auto values = mValues.lock();
if (!values->mById.insert(std::make_pair(id, value)).second)
return false;
values->mById.insert(std::make_pair(id, value));
const auto startTilePosition = getTilePosition(mSettings, value.mStart);
const auto endTilePosition = getTilePosition(mSettings, value.mEnd);
@ -43,32 +39,32 @@ namespace DetourNavigator
if (startTilePosition != endTilePosition)
values->mByTilePosition[endTilePosition].insert(id);
return true;
}
boost::optional<OffMeshConnection> remove(const ObjectId id)
std::set<TilePosition> remove(const ObjectId id)
{
const auto values = mValues.lock();
const auto itById = values->mById.find(id);
if (itById == values->mById.end())
return boost::none;
const auto result = itById->second;
const auto byId = values->mById.equal_range(id);
values->mById.erase(itById);
if (byId.first == byId.second) {
return {};
}
const auto startTilePosition = getTilePosition(mSettings, result.mStart);
const auto endTilePosition = getTilePosition(mSettings, result.mEnd);
std::set<TilePosition> removed;
removeByTilePosition(values->mByTilePosition, startTilePosition, id);
std::for_each(byId.first, byId.second, [&] (const auto& v) {
const auto startTilePosition = getTilePosition(mSettings, v.second.mStart);
const auto endTilePosition = getTilePosition(mSettings, v.second.mEnd);
removed.emplace(startTilePosition);
if (startTilePosition != endTilePosition)
removeByTilePosition(values->mByTilePosition, endTilePosition, id);
removed.emplace(endTilePosition);
});
return result;
values->mById.erase(byId.first, byId.second);
return removed;
}
std::vector<OffMeshConnection> get(const TilePosition& tilePosition)
@ -85,9 +81,8 @@ namespace DetourNavigator
std::for_each(itByTilePosition->second.begin(), itByTilePosition->second.end(),
[&] (const ObjectId v)
{
const auto itById = values->mById.find(v);
if (itById != values->mById.end())
result.push_back(itById->second);
const auto byId = values->mById.equal_range(v);
std::for_each(byId.first, byId.second, [&] (const auto& v) { result.push_back(v.second); });
});
return result;
@ -96,7 +91,7 @@ namespace DetourNavigator
private:
struct Values
{
std::unordered_map<ObjectId, OffMeshConnection> mById;
std::multimap<ObjectId, OffMeshConnection> mById;
std::map<TilePosition, std::unordered_set<ObjectId>> mByTilePosition;
};

@ -1,6 +1,8 @@
#ifndef OPENMW_COMPONENTS_MISC_CONVERT_H
#define OPENMW_COMPONENTS_MISC_CONVERT_H
#include <components/esm/loadpgrd.hpp>
#include <LinearMath/btTransform.h>
#include <LinearMath/btVector3.h>
#include <LinearMath/btQuaternion.h>
@ -21,6 +23,11 @@ namespace Convert
return osg::Vec3f(value.x(), value.y(), value.z());
}
inline osg::Vec3f makeOsgVec3f(const ESM::Pathgrid::Point& value)
{
return osg::Vec3f(value.mX, value.mY, value.mZ);
}
inline btVector3 toBullet(const osg::Vec3f& vec)
{
return btVector3(vec.x(), vec.y(), vec.z());

@ -0,0 +1,68 @@
#ifndef OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H
#define OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H
#include <components/esm/defs.hpp>
#include <components/esm/loadcell.hpp>
#include <components/esm/loadland.hpp>
#include <components/esm/loadpgrd.hpp>
namespace Misc
{
/// \brief convert coordinates between world and local cell
class CoordinateConverter
{
public:
CoordinateConverter(bool exterior, int cellX, int cellY)
: mCellX(exterior ? cellX * ESM::Land::REAL_SIZE : 0),
mCellY(exterior ? cellY * ESM::Land::REAL_SIZE : 0)
{
}
explicit CoordinateConverter(const ESM::Cell* cell)
: CoordinateConverter(cell->isExterior(), cell->mData.mX, cell->mData.mY)
{
}
/// in-place conversion from local to world
void toWorld(ESM::Pathgrid::Point& point) const
{
point.mX += mCellX;
point.mY += mCellY;
}
ESM::Pathgrid::Point toWorldPoint(ESM::Pathgrid::Point point) const
{
toWorld(point);
return point;
}
/// in-place conversion from local to world
void toWorld(osg::Vec3f& point) const
{
point.x() += static_cast<float>(mCellX);
point.y() += static_cast<float>(mCellY);
}
/// in-place conversion from world to local
void toLocal(osg::Vec3f& point) const
{
point.x() -= static_cast<float>(mCellX);
point.y() -= static_cast<float>(mCellY);
}
osg::Vec3f toLocalVec3(const osg::Vec3f& point) const
{
return osg::Vec3f(
point.x() - static_cast<float>(mCellX),
point.y() - static_cast<float>(mCellY),
point.z()
);
}
private:
int mCellX;
int mCellY;
};
}
#endif
Loading…
Cancel
Save