1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-29 18:32:36 +00:00
OpenMW/apps/openmw/mwrender/actorspaths.cpp
elsid 1a12c453d6
Support different agent collision shape type for pathfinding
Actors may have different collision shapes. Currently there are axis-aligned
bounding boxes and rotating bounding boxes. With AABB it's required to use
bounding cylinder for navmesh agent to avoid providing paths where actor can't
pass. But for rotating bounding boxes cylinder with diameter equal to the front
face width should be used to not reduce of available paths. For example rats
have rotating bounding box as collision shape because of the difference between
front and side faces width.

* Add agent bounds to navmesh tile db cache key. This is required to distinguish
  tiles for agents with different bounds.
* Increase navmesh version because navmesh tile db cache key and data has changed.
* Move navmesh version to the code to avoid misconfiguration by users.
* Fix all places where wrong half extents were used for pathfinding.
2022-06-21 12:57:32 +02:00

107 lines
2.9 KiB
C++

#include "actorspaths.hpp"
#include "vismask.hpp"
#include <components/sceneutil/agentpath.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/detournavigator/settings.hpp>
#include <osg/PositionAttitudeTransform>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include <algorithm>
namespace MWRender
{
ActorsPaths::ActorsPaths(const osg::ref_ptr<osg::Group>& root, bool enabled)
: mRootNode(root)
, mEnabled(enabled)
{
}
ActorsPaths::~ActorsPaths()
{
if (mEnabled)
disable();
}
bool ActorsPaths::toggle()
{
if (mEnabled)
disable();
else
enable();
return mEnabled;
}
void ActorsPaths::update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end,
const DetourNavigator::Settings& settings)
{
if (!mEnabled)
return;
const auto group = mGroups.find(actor.mRef);
if (group != mGroups.end())
mRootNode->removeChild(group->second.mNode);
auto newGroup = SceneUtil::createAgentPathGroup(path, agentBounds, start, end, settings.mRecast);
if (newGroup)
{
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(newGroup, "debug");
newGroup->setNodeMask(Mask_Debug);
mRootNode->addChild(newGroup);
mGroups[actor.mRef] = Group {actor.mCell, std::move(newGroup)};
}
}
void ActorsPaths::remove(const MWWorld::ConstPtr& actor)
{
const auto group = mGroups.find(actor.mRef);
if (group != mGroups.end())
{
mRootNode->removeChild(group->second.mNode);
mGroups.erase(group);
}
}
void ActorsPaths::removeCell(const MWWorld::CellStore* const store)
{
for (auto it = mGroups.begin(); it != mGroups.end(); )
{
if (it->second.mCell == store)
{
mRootNode->removeChild(it->second.mNode);
it = mGroups.erase(it);
}
else
++it;
}
}
void ActorsPaths::updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated)
{
const auto it = mGroups.find(old.mRef);
if (it == mGroups.end())
return;
it->second.mCell = updated.mCell;
}
void ActorsPaths::enable()
{
std::for_each(mGroups.begin(), mGroups.end(),
[&] (const Groups::value_type& v) { mRootNode->addChild(v.second.mNode); });
mEnabled = true;
}
void ActorsPaths::disable()
{
std::for_each(mGroups.begin(), mGroups.end(),
[&] (const Groups::value_type& v) { mRootNode->removeChild(v.second.mNode); });
mEnabled = false;
}
}