1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-04-01 15:36:40 +00:00

Add command and settings option to enable actors paths render

This commit is contained in:
elsid 2018-07-21 13:37:02 +03:00
parent c95cea414c
commit dc09674362
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
21 changed files with 334 additions and 8 deletions

View file

@ -21,7 +21,7 @@ add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin actoranimation landmanager navmesh renderbin actoranimation landmanager navmesh actorspaths
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput

View file

@ -4,6 +4,7 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <set> #include <set>
#include <deque>
#include <components/esm/cellid.hpp> #include <components/esm/cellid.hpp>
@ -597,6 +598,9 @@ namespace MWBase
virtual void preloadEffects(const ESM::EffectList* effectList) = 0; virtual void preloadEffects(const ESM::EffectList* effectList) = 0;
virtual DetourNavigator::Navigator* getNavigator() const = 0; virtual DetourNavigator::Navigator* getNavigator() const = 0;
virtual void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const = 0;
}; };
} }

View file

@ -5,6 +5,7 @@
#include <components/esm/loadcell.hpp> #include <components/esm/loadcell.hpp>
#include <components/esm/loadland.hpp> #include <components/esm/loadland.hpp>
#include <components/esm/loadmgef.hpp> #include <components/esm/loadmgef.hpp>
#include <components/detournavigator/navigator.hpp>
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -102,6 +103,12 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
const ESM::Position pos = actor.getRefData().getPosition(); //position of the actor const ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
{
const auto halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor);
MWBase::Environment::get().getWorld()->updateActorPath(actor, mPathFinder.getPath(), halfExtents,
pos.asVec3(), dest);
}
/// Stops the actor when it gets too close to a unloaded cell /// Stops the actor when it gets too close to a unloaded cell
//... At current time, this test is unnecessary. AI shuts down when actor is more than 7168 //... At current time, this test is unnecessary. AI shuts down when actor is more than 7168
//... units from player, and exterior cells are 8192 units long and wide. //... units from player, and exterior cells are 8192 units long and wide.

View file

@ -0,0 +1,99 @@
#include "actorspaths.hpp"
#include "vismask.hpp"
#include <components/sceneutil/agentpath.hpp>
#include <osg/PositionAttitudeTransform>
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 osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
const DetourNavigator::Settings& settings)
{
if (!mEnabled)
return;
const auto group = mGroups.find(actor);
if (group != mGroups.end())
mRootNode->removeChild(group->second);
const auto newGroup = SceneUtil::createAgentPathGroup(path, halfExtents, start, end, settings);
if (newGroup)
{
newGroup->setNodeMask(Mask_Debug);
mRootNode->addChild(newGroup);
mGroups[actor] = newGroup;
}
}
void ActorsPaths::remove(const MWWorld::ConstPtr& actor)
{
const auto group = mGroups.find(actor);
if (group != mGroups.end())
{
mRootNode->removeChild(group->second);
mGroups.erase(group);
}
}
void ActorsPaths::removeCell(const MWWorld::CellStore* const store)
{
for (auto it = mGroups.begin(); it != mGroups.end(); )
{
if (it->first.getCell() == store)
{
mRootNode->removeChild(it->second);
it = mGroups.erase(it);
}
else
++it;
}
}
void ActorsPaths::updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated)
{
const auto it = mGroups.find(old);
if (it == mGroups.end())
return;
auto group = std::move(it->second);
mGroups.erase(it);
mGroups.insert(std::make_pair(updated, std::move(group)));
}
void ActorsPaths::enable()
{
std::for_each(mGroups.begin(), mGroups.end(),
[&] (const Groups::value_type& v) { mRootNode->addChild(v.second); });
mEnabled = true;
}
void ActorsPaths::disable()
{
std::for_each(mGroups.begin(), mGroups.end(),
[&] (const Groups::value_type& v) { mRootNode->removeChild(v.second); });
mEnabled = false;
}
}

View file

@ -0,0 +1,51 @@
#ifndef OPENMW_MWRENDER_AGENTSPATHS_H
#define OPENMW_MWRENDER_AGENTSPATHS_H
#include <apps/openmw/mwworld/ptr.hpp>
#include <components/detournavigator/navigator.hpp>
#include <osg/ref_ptr>
#include <unordered_map>
#include <deque>
namespace osg
{
class Group;
}
namespace MWRender
{
class ActorsPaths
{
public:
ActorsPaths(const osg::ref_ptr<osg::Group>& root, bool enabled);
~ActorsPaths();
bool toggle();
void update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
const DetourNavigator::Settings& settings);
void remove(const MWWorld::ConstPtr& actor);
void removeCell(const MWWorld::CellStore* const store);
void updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated);
void enable();
void disable();
private:
using Groups = std::map<MWWorld::ConstPtr, osg::ref_ptr<osg::Group>>;
osg::ref_ptr<osg::Group> mRootNode;
Groups mGroups;
bool mEnabled;
};
}
#endif

View file

@ -66,6 +66,7 @@
#include "terrainstorage.hpp" #include "terrainstorage.hpp"
#include "util.hpp" #include "util.hpp"
#include "navmesh.hpp" #include "navmesh.hpp"
#include "actorspaths.hpp"
namespace namespace
{ {
@ -234,7 +235,8 @@ namespace MWRender
mRootNode->addChild(mSceneRoot); mRootNode->addChild(mSceneRoot);
mNavMesh.reset(new NavMesh(mRootNode, Settings::Manager::getBool("enable render", "Navigator"))); mNavMesh.reset(new NavMesh(mRootNode, Settings::Manager::getBool("enable nav mesh render", "Navigator")));
mActorsPaths.reset(new ActorsPaths(mRootNode, Settings::Manager::getBool("enable agents paths render", "Navigator")));
mPathgrid.reset(new Pathgrid(mRootNode)); mPathgrid.reset(new Pathgrid(mRootNode));
mObjects.reset(new Objects(mResourceSystem, sceneRoot, mUnrefQueue.get())); mObjects.reset(new Objects(mResourceSystem, sceneRoot, mUnrefQueue.get()));
@ -472,6 +474,7 @@ namespace MWRender
void RenderingManager::removeCell(const MWWorld::CellStore *store) void RenderingManager::removeCell(const MWWorld::CellStore *store)
{ {
mPathgrid->removeCell(store); mPathgrid->removeCell(store);
mActorsPaths->removeCell(store);
mObjects->removeCell(store); mObjects->removeCell(store);
if (store->getCell()->isExterior()) if (store->getCell()->isExterior())
@ -527,6 +530,10 @@ namespace MWRender
{ {
return mNavMesh->toggle(); return mNavMesh->toggle();
} }
else if (mode == Render_ActorsPaths)
{
return mActorsPaths->toggle();
}
return false; return false;
} }
@ -666,6 +673,7 @@ namespace MWRender
void RenderingManager::removeObject(const MWWorld::Ptr &ptr) void RenderingManager::removeObject(const MWWorld::Ptr &ptr)
{ {
mActorsPaths->remove(ptr);
mObjects->removeObject(ptr); mObjects->removeObject(ptr);
mWater->removeEmitter(ptr); mWater->removeEmitter(ptr);
} }
@ -1049,6 +1057,7 @@ namespace MWRender
void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated)
{ {
mObjects->updatePtr(old, updated); mObjects->updatePtr(old, updated);
mActorsPaths->updatePtr(old, updated);
} }
void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX)
@ -1369,5 +1378,14 @@ namespace MWRender
return mTerrainStorage->getLandManager(); return mTerrainStorage->getLandManager();
} }
void RenderingManager::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const
{
mActorsPaths->update(actor, path, halfExtents, start, end, mNavigator.getSettings());
}
void RenderingManager::removeActorPath(const MWWorld::ConstPtr& actor) const
{
mActorsPaths->remove(actor);
}
} }

View file

@ -12,6 +12,8 @@
#include "renderinginterface.hpp" #include "renderinginterface.hpp"
#include "rendermode.hpp" #include "rendermode.hpp"
#include <deque>
namespace osg namespace osg
{ {
class Group; class Group;
@ -58,6 +60,7 @@ namespace SceneUtil
namespace DetourNavigator namespace DetourNavigator
{ {
class Navigator; class Navigator;
struct Settings;
} }
namespace MWRender namespace MWRender
@ -74,6 +77,7 @@ namespace MWRender
class TerrainStorage; class TerrainStorage;
class LandManager; class LandManager;
class NavMesh; class NavMesh;
class ActorsPaths;
class RenderingManager : public MWRender::RenderingInterface class RenderingManager : public MWRender::RenderingInterface
{ {
@ -219,6 +223,11 @@ namespace MWRender
bool toggleBorders(); bool toggleBorders();
void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const;
void removeActorPath(const MWWorld::ConstPtr& actor) const;
private: private:
void updateProjectionMatrix(); void updateProjectionMatrix();
void updateTextureFiltering(); void updateTextureFiltering();
@ -245,6 +254,7 @@ namespace MWRender
DetourNavigator::Navigator& mNavigator; DetourNavigator::Navigator& mNavigator;
std::unique_ptr<NavMesh> mNavMesh; std::unique_ptr<NavMesh> mNavMesh;
std::unique_ptr<ActorsPaths> mActorsPaths;
std::unique_ptr<Pathgrid> mPathgrid; std::unique_ptr<Pathgrid> mPathgrid;
std::unique_ptr<Objects> mObjects; std::unique_ptr<Objects> mObjects;
std::unique_ptr<Water> mWater; std::unique_ptr<Water> mWater;

View file

@ -12,6 +12,7 @@ namespace MWRender
Render_Water, Render_Water,
Render_Scene, Render_Scene,
Render_NavMesh, Render_NavMesh,
Render_ActorsPaths,
}; };
} }

View file

@ -456,5 +456,6 @@ op 0x2000305: Show, explicit
op 0x2000306: OnActivate, explicit op 0x2000306: OnActivate, explicit
op 0x2000307: ToggleBorders, tb op 0x2000307: ToggleBorders, tb
op 0x2000308: ToggleNavMesh op 0x2000308: ToggleNavMesh
op 0x2000309: ToggleActorsPaths
opcodes 0x2000309-0x3ffffff unused opcodes 0x200030a-0x3ffffff unused

View file

@ -1331,6 +1331,20 @@ namespace MWScript
} }
}; };
class OpToggleActorsPaths : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
bool enabled =
MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_ActorsPaths);
runtime.getContext().report (enabled ?
"Agents Paths Rendering -> On" : "Agents Paths Rendering -> Off");
}
};
void installOpcodes (Interpreter::Interpreter& interpreter) void installOpcodes (Interpreter::Interpreter& interpreter)
{ {
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox);
@ -1432,6 +1446,7 @@ namespace MWScript
interpreter.installSegment3 (Compiler::Misc::opcodeShowSceneGraphExplicit, new OpShowSceneGraph<ExplicitRef>); interpreter.installSegment3 (Compiler::Misc::opcodeShowSceneGraphExplicit, new OpShowSceneGraph<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeToggleBorders, new OpToggleBorders); interpreter.installSegment5 (Compiler::Misc::opcodeToggleBorders, new OpToggleBorders);
interpreter.installSegment5 (Compiler::Misc::opcodeToggleNavMesh, new OpToggleNavMesh); interpreter.installSegment5 (Compiler::Misc::opcodeToggleNavMesh, new OpToggleNavMesh);
interpreter.installSegment5 (Compiler::Misc::opcodeToggleActorsPaths, new OpToggleActorsPaths);
} }
} }
} }

View file

@ -278,7 +278,10 @@ namespace MWWorld
if (const auto object = mPhysics->getObject(ptr)) if (const auto object = mPhysics->getObject(ptr))
navigator->removeObject(reinterpret_cast<std::size_t>(object)); navigator->removeObject(reinterpret_cast<std::size_t>(object));
else if (const auto actor = mPhysics->getActor(ptr)) else if (const auto actor = mPhysics->getActor(ptr))
{
navigator->removeAgent(playerHalfExtents); navigator->removeAgent(playerHalfExtents);
mRendering.removeActorPath(ptr);
}
mPhysics->remove(ptr); mPhysics->remove(ptr);
} }

View file

@ -3745,4 +3745,10 @@ namespace MWWorld
return mNavigator.get(); return mNavigator.get();
} }
void World::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const
{
mRendering->updateActorPath(actor, path, halfExtents, start, end);
}
} }

View file

@ -691,6 +691,9 @@ namespace MWWorld
void preloadEffects(const ESM::EffectList* effectList) override; void preloadEffects(const ESM::EffectList* effectList) override;
DetourNavigator::Navigator* getNavigator() const override; DetourNavigator::Navigator* getNavigator() const override;
void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const override;
}; };
} }

View file

@ -51,7 +51,7 @@ add_component_dir (shader
add_component_dir (sceneutil add_component_dir (sceneutil
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer
actorutil detourdebugdraw navmesh actorutil detourdebugdraw navmesh agentpath
) )
add_component_dir (nif add_component_dir (nif

View file

@ -321,7 +321,7 @@ namespace Compiler
extensions.registerInstruction ("tb", "", opcodeToggleBorders); extensions.registerInstruction ("tb", "", opcodeToggleBorders);
extensions.registerInstruction ("toggleborders", "", opcodeToggleBorders); extensions.registerInstruction ("toggleborders", "", opcodeToggleBorders);
extensions.registerInstruction ("togglenavmesh", "", opcodeToggleNavMesh); extensions.registerInstruction ("togglenavmesh", "", opcodeToggleNavMesh);
extensions.registerInstruction ("tnm", "", opcodeToggleNavMesh); extensions.registerInstruction ("toggleactorspaths", "", opcodeToggleActorsPaths);
} }
} }

View file

@ -297,6 +297,7 @@ namespace Compiler
const int opcodeShowSceneGraphExplicit = 0x20030; const int opcodeShowSceneGraphExplicit = 0x20030;
const int opcodeToggleBorders = 0x2000307; const int opcodeToggleBorders = 0x2000307;
const int opcodeToggleNavMesh = 0x2000308; const int opcodeToggleNavMesh = 0x2000308;
const int opcodeToggleActorsPaths = 0x2000309;
} }
namespace Sky namespace Sky

View file

@ -0,0 +1,71 @@
#include "agentpath.hpp"
#include "detourdebugdraw.hpp"
#include <components/detournavigator/settings.hpp>
#include <components/esm/loadpgrd.hpp>
#include <algorithm>
namespace
{
void drawAgent(duDebugDraw& debugDraw, const osg::Vec3f& pos, const float radius, const float height,
const float climb, const unsigned color)
{
debugDraw.depthMask(false);
duDebugDrawCylinderWire(&debugDraw, pos.x() - radius, pos.z() + 0.02f, pos.y() - radius, pos.x() + radius,
pos.z() + height, pos.y() + radius, color, radius * 0.2f);
duDebugDrawCircle(&debugDraw, pos.x(), pos.z() + climb, pos.y(), radius, duRGBA(0, 0 , 0, 64), radius * 0.1f);
const auto colb = duRGBA(0, 0, 0, 196);
debugDraw.begin(DU_DRAW_LINES);
debugDraw.vertex(pos.x(), pos.z() - climb, pos.y(), colb);
debugDraw.vertex(pos.x(), pos.z() + climb, pos.y(), colb);
debugDraw.vertex(pos.x() - radius / 2, pos.z() + 0.02f, pos.y(), colb);
debugDraw.vertex(pos.x() + radius / 2, pos.z() + 0.02f, pos.y(), colb);
debugDraw.vertex(pos.x(), pos.z() + 0.02f, pos.y() - radius / 2, colb);
debugDraw.vertex(pos.x(), pos.z() + 0.02f, pos.y() + radius / 2, colb);
debugDraw.end();
debugDraw.depthMask(true);
}
}
namespace SceneUtil
{
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
const DetourNavigator::Settings& settings)
{
using namespace DetourNavigator;
const osg::ref_ptr<osg::Group> group(new osg::Group);
DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1);
const auto agentRadius = halfExtents.x();
const auto agentHeight = 2.0f * halfExtents.z();
const auto agentClimb = settings.mMaxClimb;
const auto startColor = duRGBA(128, 25, 0, 192);
const auto endColor = duRGBA(51, 102, 0, 129);
drawAgent(debugDraw, start, agentRadius, agentHeight, agentClimb, startColor);
drawAgent(debugDraw, end, agentRadius, agentHeight, agentClimb, endColor);
const auto pathColor = duRGBA(0, 0, 0, 220);
debugDraw.depthMask(false);
debugDraw.begin(osg::PrimitiveSet::LINE_STRIP, agentRadius * 0.5f);
debugDraw.vertex(osg::Vec3f(start.x(), start.z() + agentClimb, start.y()).ptr(), startColor);
std::for_each(path.begin(), path.end(),
[&] (const osg::Vec3f& v) { debugDraw.vertex(osg::Vec3f(v.x(), v.z() + agentClimb, v.y()).ptr(), pathColor); });
debugDraw.vertex(osg::Vec3f(end.x(), end.z() + agentClimb, end.y()).ptr(), endColor);
debugDraw.end();
debugDraw.depthMask(true);
return group;
}
}

View file

@ -0,0 +1,26 @@
#ifndef OPENMW_COMPONENTS_SCENEUTIL_AGENTPATH_H
#define OPENMW_COMPONENTS_SCENEUTIL_AGENTPATH_H
#include <osg/ref_ptr>
#include <deque>
namespace osg
{
class Group;
class Vec3f;
}
namespace DetourNavigator
{
struct Settings;
}
namespace SceneUtil
{
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
const DetourNavigator::Settings& settings);
}
#endif

View file

@ -56,14 +56,19 @@ namespace SceneUtil
throw std::logic_error("DebugDraw does not support textures (at " __FILE__ ":" OPENMW_LINE_STRING ")"); throw std::logic_error("DebugDraw does not support textures (at " __FILE__ ":" OPENMW_LINE_STRING ")");
} }
void DebugDraw::begin(duDebugDrawPrimitives prim, float size) void DebugDraw::begin(osg::PrimitiveSet::Mode mode, float size)
{ {
mMode = toOsgPrimitiveSetMode(prim); mMode = mode;
mVertices = new osg::Vec3Array; mVertices = new osg::Vec3Array;
mColors = new osg::Vec4Array; mColors = new osg::Vec4Array;
mSize = size * mRecastInvertedScaleFactor; mSize = size * mRecastInvertedScaleFactor;
} }
void DebugDraw::begin(duDebugDrawPrimitives prim, float size)
{
begin(toOsgPrimitiveSetMode(prim), size);
}
void DebugDraw::vertex(const float* pos, unsigned color) void DebugDraw::vertex(const float* pos, unsigned color)
{ {
vertex(pos[0], pos[1], pos[2], color); vertex(pos[0], pos[1], pos[2], color);

View file

@ -18,6 +18,8 @@ namespace SceneUtil
void texture(bool state) override; void texture(bool state) override;
void begin(osg::PrimitiveSet::Mode mode, float size);
void begin(duDebugDrawPrimitives prim, float size) override; void begin(duDebugDrawPrimitives prim, float size) override;
void vertex(const float* pos, unsigned int color) override; void vertex(const float* pos, unsigned int color) override;

View file

@ -619,4 +619,7 @@ recast mesh path prefix =
nav mesh path prefix = nav mesh path prefix =
# Render nav mesh (true, false) # Render nav mesh (true, false)
enable render = false enable nav mesh render = false
# Render agents paths (true, false)
enable agents paths render = false