mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-14 01:19:59 +00:00
Merge branch 'luaprerenderhandle' into 'master'
Draft: Synchronous onPreRender lua engine handler and a visual position change method for local scripts See merge request OpenMW/openmw!4578
This commit is contained in:
commit
4fe788dabf
@ -348,6 +348,10 @@ bool OMW::Engine::frame(unsigned frameNumber, float frametime)
|
||||
mWorld->updateWindowManager();
|
||||
}
|
||||
|
||||
// Synchronised update that can safely be used for scene modifications that affect rendering, without using a
|
||||
// delayed action.
|
||||
mLuaManager->preRenderSynchronizedUpdate();
|
||||
|
||||
// if there is a separate Lua thread, it starts the update now
|
||||
mLuaWorker->allowUpdate(frameStart, frameNumber, *stats);
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwmechanics/aicombat.hpp"
|
||||
#include "../mwmechanics/aiescort.hpp"
|
||||
#include "../mwmechanics/aifollow.hpp"
|
||||
@ -19,7 +21,10 @@
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
#include "../mwrender/renderingmanager.hpp"
|
||||
|
||||
#include "context.hpp"
|
||||
#include "luamanagerimp.hpp"
|
||||
|
||||
namespace sol
|
||||
{
|
||||
@ -71,6 +76,16 @@ namespace MWLua
|
||||
{ { "NoAttack", MWMechanics::AttackType::NoAttack }, { "Any", MWMechanics::AttackType::Any },
|
||||
{ "Chop", MWMechanics::AttackType::Chop }, { "Slash", MWMechanics::AttackType::Slash },
|
||||
{ "Thrust", MWMechanics::AttackType::Thrust } }));
|
||||
selfAPI["visualMoveTo"] = [context](const SelfObject& self, const osg::Vec3f& pos) {
|
||||
if (!context.mLuaManager->isInPreRenderUpdate())
|
||||
throw "visualMoveTo can only be used in onPreRender engine handler.";
|
||||
MWBase::Environment::get().getWorld()->getRenderingManager()->moveObject(self.ptr(), pos);
|
||||
};
|
||||
selfAPI["visualRotate"] = [context](const SelfObject& self, const osg::Quat& rot) {
|
||||
if (!context.mLuaManager->isInPreRenderUpdate())
|
||||
throw "visualMoveTo can only be used in onPreRender engine handler.";
|
||||
MWBase::Environment::get().getWorld()->getRenderingManager()->rotateObject(self.ptr(), rot);
|
||||
};
|
||||
|
||||
using AiPackage = MWMechanics::AiPackage;
|
||||
sol::usertype<AiPackage> aiPackage = lua.new_usertype<AiPackage>("AiPackage");
|
||||
|
@ -239,6 +239,24 @@ namespace MWLua
|
||||
}
|
||||
}
|
||||
|
||||
void LuaManager::preRenderSynchronizedUpdate()
|
||||
{
|
||||
mLua.protectedCall([&](LuaUtil::LuaView&) { preRenderSynchronizedUpdateUnsafe(); });
|
||||
}
|
||||
|
||||
void LuaManager::preRenderSynchronizedUpdateUnsafe()
|
||||
{
|
||||
mInPreRenderUpdate = true;
|
||||
|
||||
float frameDuration = MWBase::Environment::get().getFrameDuration();
|
||||
for (LocalScripts* scripts : mActiveLocalScripts)
|
||||
scripts->preRenderUpdate(frameDuration);
|
||||
if (mGlobalScriptsStarted)
|
||||
mGlobalScripts.preRenderUpdate(frameDuration);
|
||||
|
||||
mInPreRenderUpdate = false;
|
||||
}
|
||||
|
||||
void LuaManager::synchronizedUpdate()
|
||||
{
|
||||
mLua.protectedCall([&](LuaUtil::LuaView&) { synchronizedUpdateUnsafe(); });
|
||||
|
@ -62,6 +62,12 @@ namespace MWLua
|
||||
// Can use the scene graph and applies the actions queued during update()
|
||||
void synchronizedUpdate();
|
||||
|
||||
// \brief Executes latency-critical and scene graph related Lua logic.
|
||||
//
|
||||
// Called by engine.cpp from the main thread between after the complete world update, right before rendering and
|
||||
// onUpdate. Can use the scene graph
|
||||
void preRenderSynchronizedUpdate();
|
||||
|
||||
// Normally it is called by `synchronizedUpdate` every frame.
|
||||
// Additionally must be called before making a save to ensure that there are no pending delayed
|
||||
// actions and the world is in a consistent state.
|
||||
@ -159,6 +165,7 @@ namespace MWLua
|
||||
LuaUi::ResourceManager* uiResourceManager() { return &mUiResourceManager; }
|
||||
|
||||
bool isProcessingInputEvents() const { return mProcessingInputEvents; }
|
||||
bool isInPreRenderUpdate() const { return mInPreRenderUpdate; }
|
||||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
||||
std::string formatResourceUsageStats() const override;
|
||||
@ -172,10 +179,12 @@ namespace MWLua
|
||||
std::optional<LuaUtil::ScriptIdsWithInitializationData> autoStartConf = std::nullopt);
|
||||
void reloadAllScriptsImpl();
|
||||
void synchronizedUpdateUnsafe();
|
||||
void preRenderSynchronizedUpdateUnsafe();
|
||||
|
||||
bool mInitialized = false;
|
||||
bool mGlobalScriptsStarted = false;
|
||||
bool mProcessingInputEvents = false;
|
||||
bool mInPreRenderUpdate = false;
|
||||
bool mApplyingDelayedActions = false;
|
||||
bool mNewGameStarted = false;
|
||||
bool mReloadAllScriptsRequested = false;
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <osg/Matrix>
|
||||
|
||||
#include <components/detournavigator/agentbounds.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
#include <components/settings/values.hpp>
|
||||
|
||||
#include "apps/openmw/mwbase/environment.hpp"
|
||||
@ -170,6 +173,31 @@ namespace MWLua
|
||||
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(*it);
|
||||
}
|
||||
|
||||
static std::optional<osg::Matrix> findBoneWorldTransform(
|
||||
const osg::ref_ptr<osg::Node> parentNode, const std::string_view boneName)
|
||||
{
|
||||
if (!parentNode)
|
||||
return std::nullopt;
|
||||
osg::Group* parentNodeGroup = parentNode->asGroup();
|
||||
if (!parentNodeGroup)
|
||||
return std::nullopt;
|
||||
|
||||
for (unsigned int i = 0; i < parentNodeGroup->getNumChildren(); ++i)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> child = parentNodeGroup->getChild(i);
|
||||
|
||||
// asMatrixTransform will break if its not a bone
|
||||
if (child->getName() == boneName)
|
||||
{
|
||||
return osg::computeLocalToWorld(child->getParentalNodePaths()[0]);
|
||||
}
|
||||
|
||||
return findBoneWorldTransform(child, boneName);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void addActorBindings(sol::table actor, const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.sol();
|
||||
@ -195,7 +223,34 @@ namespace MWLua
|
||||
{ "CarriedRight", MWWorld::InventoryStore::Slot_CarriedRight },
|
||||
{ "CarriedLeft", MWWorld::InventoryStore::Slot_CarriedLeft },
|
||||
{ "Ammunition", MWWorld::InventoryStore::Slot_Ammunition } }));
|
||||
actor["getBonePosition"] = [](const GObject& o, std::string_view boneName) -> sol::optional<osg::Vec3f> {
|
||||
const MWWorld::Class& cls = o.ptr().getClass();
|
||||
// Need to accept self OR a global object
|
||||
/*if (!cls.isActor())
|
||||
throw std::runtime_error("Actor expected");*/
|
||||
|
||||
std::optional<osg::Matrix> boneTransform
|
||||
= findBoneWorldTransform(o.ptr().getRefData().getBaseNode(), boneName);
|
||||
|
||||
if (!boneTransform.has_value())
|
||||
return sol::nullopt;
|
||||
|
||||
return static_cast<osg::Vec3f>(boneTransform.value().getTrans());
|
||||
};
|
||||
actor["getBoneRotation"] = [](const GObject& o, std::string_view boneName) -> sol::optional<osg::Quat> {
|
||||
const MWWorld::Class& cls = o.ptr().getClass();
|
||||
if (!cls.isActor())
|
||||
throw std::runtime_error("Actor expected");
|
||||
|
||||
std::optional<osg::Matrix> boneTransform
|
||||
= findBoneWorldTransform(o.ptr().getRefData().getBaseNode(), boneName);
|
||||
|
||||
if (!boneTransform.has_value())
|
||||
return sol::nullopt;
|
||||
|
||||
return boneTransform.value().getRotate();
|
||||
// return Misc::Convert::makeOsgQuat(pos.rot);
|
||||
};
|
||||
actor["getStance"] = [](const Object& o) {
|
||||
const MWWorld::Class& cls = o.ptr().getClass();
|
||||
if (cls.isActor())
|
||||
|
@ -37,6 +37,7 @@ namespace LuaUtil
|
||||
{
|
||||
sInstanceCount++;
|
||||
registerEngineHandlers({ &mUpdateHandlers });
|
||||
registerEngineHandlers({ &mPreRenderUpdateHandlers });
|
||||
if (load)
|
||||
{
|
||||
LoadedData& data = mData.emplace<LoadedData>();
|
||||
|
@ -107,6 +107,10 @@ namespace LuaUtil
|
||||
// Handlers are called in the same order as scripts were added.
|
||||
void update(float dt) { callEngineHandlers(mUpdateHandlers, dt); }
|
||||
|
||||
// Calls `onUpdate` (if present) for every script in the container.
|
||||
// Handlers are called in the same order as scripts were added.
|
||||
void preRenderUpdate(float dt) { callEngineHandlers(mPreRenderUpdateHandlers, dt); }
|
||||
|
||||
// Calls event handlers `eventName` (if present) for every script.
|
||||
// If several scripts register handlers for `eventName`, they are called in reverse order.
|
||||
// If some handler returns `false`, all remaining handlers are ignored. Any other return value
|
||||
@ -289,6 +293,7 @@ namespace LuaUtil
|
||||
LoadedData& ensureLoaded();
|
||||
|
||||
EngineHandlerList mUpdateHandlers{ "onUpdate" };
|
||||
EngineHandlerList mPreRenderUpdateHandlers{ "onPreRender" };
|
||||
std::map<std::string_view, EngineHandlerList*> mEngineHandlers;
|
||||
std::variant<UnloadedData, LoadedData> mData;
|
||||
int64_t mTemporaryCallbackCounter = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user