1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-05 06:45:34 +00:00

Merge branch 'save_me_not' into 'master'

[Postprocessing] Fix a couple awkward issues with Lua API

See merge request OpenMW/openmw!1946
This commit is contained in:
Petr Mikheev 2022-05-31 08:45:28 +00:00
commit 7bc0d46896
9 changed files with 74 additions and 29 deletions

View file

@ -30,7 +30,7 @@ namespace
{ {
auto technique = processor->getTechniques()[i]; auto technique = processor->getTechniques()[i];
if (!technique) if (!technique || technique->getDynamic())
continue; continue;
chain << technique->getName(); chain << technique->getName();
@ -140,10 +140,15 @@ namespace MWGui
{ {
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor(); auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
mOverrideHint = list->getItemNameAt(selected); mOverrideHint = list->getItemNameAt(selected);
auto technique = *list->getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
if (technique->getDynamic())
return;
if (enabled) if (enabled)
processor->enableTechnique(*list->getItemDataAt<std::shared_ptr<fx::Technique>>(selected)); processor->enableTechnique(technique);
else else
processor->disableTechnique(*list->getItemDataAt<std::shared_ptr<fx::Technique>>(selected)); processor->disableTechnique(technique);
saveChain(); saveChain();
} }
} }
@ -172,7 +177,11 @@ namespace MWGui
if (static_cast<size_t>(index) != selected) if (static_cast<size_t>(index) != selected)
{ {
if (processor->enableTechnique(*mActiveList->getItemDataAt<std::shared_ptr<fx::Technique>>(selected), index)) auto technique = *mActiveList->getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
if (technique->getDynamic())
return;
if (processor->enableTechnique(technique, index) != MWRender::PostProcessor::Status_Error)
saveChain(); saveChain();
} }
} }
@ -330,6 +339,9 @@ namespace MWGui
{ {
case fx::Technique::Status::Success: case fx::Technique::Status::Success:
case fx::Technique::Status::Uncompiled: case fx::Technique::Status::Uncompiled:
{
if (technique->getDynamic())
ss << "#{fontcolourhtml=header}Locked: #{fontcolourhtml=normal} Cannot be toggled or moved, controlled by external Lua script" << endl << endl;
ss << "#{fontcolourhtml=header}Author: #{fontcolourhtml=normal} " << author << endl << endl ss << "#{fontcolourhtml=header}Author: #{fontcolourhtml=normal} " << author << endl << endl
<< "#{fontcolourhtml=header}Version: #{fontcolourhtml=normal} " << version << endl << endl << "#{fontcolourhtml=header}Version: #{fontcolourhtml=normal} " << version << endl << endl
<< "#{fontcolourhtml=header}Description: #{fontcolourhtml=normal} " << description << endl << endl << "#{fontcolourhtml=header}Description: #{fontcolourhtml=normal} " << description << endl << endl
@ -338,6 +350,7 @@ namespace MWGui
<< "#{fontcolourhtml=header} Underwater: #{fontcolourhtml=normal} " << flag_underwater << "#{fontcolourhtml=header} Underwater: #{fontcolourhtml=normal} " << flag_underwater
<< "#{fontcolourhtml=header} Abovewater: #{fontcolourhtml=normal} " << flag_abovewater; << "#{fontcolourhtml=header} Abovewater: #{fontcolourhtml=normal} " << flag_abovewater;
break; break;
}
case fx::Technique::Status::Parse_Error: case fx::Technique::Status::Parse_Error:
ss << "#{fontcolourhtml=negative}Shader Compile Error: #{fontcolourhtml=normal} <" << std::string(technique->getName()) << "> failed to compile." << endl << endl ss << "#{fontcolourhtml=negative}Shader Compile Error: #{fontcolourhtml=normal} <" << std::string(technique->getName()) << "> failed to compile." << endl << endl
<< technique->getLastError(); << technique->getLastError();

View file

@ -16,6 +16,8 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwrender/postprocessor.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
@ -271,6 +273,7 @@ namespace MWLua
LuaUi::clearUserInterface(); LuaUi::clearUserInterface();
mUiResourceManager.clear(); mUiResourceManager.clear();
MWBase::Environment::get().getWindowManager()->setConsoleMode(""); MWBase::Environment::get().getWindowManager()->setConsoleMode("");
MWBase::Environment::get().getWorld()->getPostProcessor()->disableDynamicShaders();
mActiveLocalScripts.clear(); mActiveLocalScripts.clear();
mLocalEvents.clear(); mLocalEvents.clear();
mGlobalEvents.clear(); mGlobalEvents.clear();

View file

@ -117,10 +117,9 @@ namespace MWLua
[=, &shader] { [=, &shader] {
shader.mQueuedAction = Shader::Action_None; shader.mQueuedAction = Shader::Action_None;
if (!MWBase::Environment::get().getWorld()->getPostProcessor()->enableTechnique(shader.mShader, pos)) if (MWBase::Environment::get().getWorld()->getPostProcessor()->enableTechnique(shader.mShader, pos) == MWRender::PostProcessor::Status_Error)
throw std::runtime_error("Failed enabling shader '" + shader.mShader->getName() + "'"); throw std::runtime_error("Failed enabling shader '" + shader.mShader->getName() + "'");
}, }
"Enable shader " + (shader.mShader ? shader.mShader->getName() : "nil")
); );
}; };
@ -132,10 +131,9 @@ namespace MWLua
[&] { [&] {
shader.mQueuedAction = Shader::Action_None; shader.mQueuedAction = Shader::Action_None;
if (!MWBase::Environment::get().getWorld()->getPostProcessor()->disableTechnique(shader.mShader)) if (MWBase::Environment::get().getWorld()->getPostProcessor()->disableTechnique(shader.mShader) == MWRender::PostProcessor::Status_Error)
throw std::runtime_error("Failed disabling shader '" + shader.mShader->getName() + "'"); throw std::runtime_error("Failed disabling shader '" + shader.mShader->getName() + "'");
}, }
"Disable shader " + (shader.mShader ? shader.mShader->getName() : "nil")
); );
}; };
@ -168,6 +166,9 @@ namespace MWLua
if (!shader.mShader || !shader.mShader->isValid()) if (!shader.mShader || !shader.mShader->isValid())
throw std::runtime_error(Misc::StringUtils::format("Failed loading shader '%s'", name)); throw std::runtime_error(Misc::StringUtils::format("Failed loading shader '%s'", name));
if (!shader.mShader->getDynamic())
throw std::runtime_error(Misc::StringUtils::format("Shader '%s' is not marked as dynamic", name));
return shader; return shader;
}; };

View file

@ -182,7 +182,6 @@ namespace MWRender
if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt) if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt)
{ {
auto absolutePath = std::filesystem::path(mVFS->getAbsoluteFileName(name)); auto absolutePath = std::filesystem::path(mVFS->getAbsoluteFileName(name));
mTechniqueFileMap[absolutePath.stem().string()] = absolutePath; mTechniqueFileMap[absolutePath.stem().string()] = absolutePath;
} }
} }
@ -210,7 +209,6 @@ namespace MWRender
if (mUsePostProcessing && mTechniqueFileMap.empty()) if (mUsePostProcessing && mTechniqueFileMap.empty())
{ {
populateTechniqueFiles(); populateTechniqueFiles();
} }
mMainTemplate->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); mMainTemplate->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
@ -648,16 +646,16 @@ namespace MWRender
mRendering.getSkyManager()->setSunglare(sunglare); mRendering.getSkyManager()->setSunglare(sunglare);
} }
bool PostProcessor::enableTechnique(std::shared_ptr<fx::Technique> technique, std::optional<int> location) PostProcessor::Status PostProcessor::enableTechnique(std::shared_ptr<fx::Technique> technique, std::optional<int> location)
{ {
if (!isEnabled()) if (!isEnabled())
{ {
Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << technique->getName() << "'"; Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << technique->getName() << "'";
return false; return Status_Error;
} }
if (!technique || Misc::StringUtils::ciEqual(technique->getName(), "main") || (location.has_value() && location.value() <= 0)) if (!technique || Misc::StringUtils::ciEqual(technique->getName(), "main") || (location.has_value() && location.value() <= 0))
return false; return Status_Error;
disableTechnique(technique, false); disableTechnique(technique, false);
@ -666,23 +664,23 @@ namespace MWRender
mTechniques.insert(mTechniques.begin() + pos, technique); mTechniques.insert(mTechniques.begin() + pos, technique);
dirtyTechniques(); dirtyTechniques();
return true; return Status_Toggled;
} }
bool PostProcessor::disableTechnique(std::shared_ptr<fx::Technique> technique, bool dirty) PostProcessor::Status PostProcessor::disableTechnique(std::shared_ptr<fx::Technique> technique, bool dirty)
{ {
if (Misc::StringUtils::ciEqual(technique->getName(), "main")) if (Misc::StringUtils::ciEqual(technique->getName(), "main"))
return false; return Status_Error;
auto it = std::find(mTechniques.begin(), mTechniques.end(), technique); auto it = std::find(mTechniques.begin(), mTechniques.end(), technique);
if (it == std::end(mTechniques)) if (it == std::end(mTechniques))
return false; return Status_Unchanged;
mTechniques.erase(it); mTechniques.erase(it);
if (dirty) if (dirty)
dirtyTechniques(); dirtyTechniques();
return true; return Status_Toggled;
} }
bool PostProcessor::isTechniqueEnabled(const std::shared_ptr<fx::Technique>& technique) const bool PostProcessor::isTechniqueEnabled(const std::shared_ptr<fx::Technique>& technique) const
@ -792,7 +790,7 @@ namespace MWRender
if (technique->getStatus() != fx::Technique::Status::File_Not_exists) if (technique->getStatus() != fx::Technique::Status::File_Not_exists)
technique->setLastModificationTime(std::filesystem::last_write_time(mTechniqueFileMap[technique->getName()])); technique->setLastModificationTime(std::filesystem::last_write_time(mTechniqueFileMap[technique->getName()]));
if (!loadNextFrame) if (loadNextFrame)
{ {
mQueuedTemplates.push_back(technique); mQueuedTemplates.push_back(technique);
return technique; return technique;
@ -853,5 +851,12 @@ namespace MWRender
dirtyTechniques(); dirtyTechniques();
} }
void PostProcessor::disableDynamicShaders()
{
for (auto& technique : mTechniques)
if (technique->getDynamic())
disableTechnique(technique);
}
} }

View file

@ -110,9 +110,16 @@ namespace MWRender
void resize(); void resize();
bool enableTechnique(std::shared_ptr<fx::Technique> technique, std::optional<int> location = std::nullopt); enum Status
{
Status_Error,
Status_Toggled,
Status_Unchanged
};
bool disableTechnique(std::shared_ptr<fx::Technique> technique, bool dirty = true); Status enableTechnique(std::shared_ptr<fx::Technique> technique, std::optional<int> location = std::nullopt);
Status disableTechnique(std::shared_ptr<fx::Technique> technique, bool dirty = true);
bool getSupportsNormalsRT() const { return mNormalsSupported; } bool getSupportsNormalsRT() const { return mNormalsSupported; }
@ -154,7 +161,7 @@ namespace MWRender
void toggleMode(); void toggleMode();
std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame=true); std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame=false);
bool isEnabled() const { return mUsePostProcessing && mEnabled; } bool isEnabled() const { return mUsePostProcessing && mEnabled; }
@ -168,6 +175,8 @@ namespace MWRender
void setRenderTargetSize(int width, int height) { mWidth = width; mHeight = height; } void setRenderTargetSize(int width, int height) { mWidth = width; mHeight = height; }
void disableDynamicShaders();
private: private:
void populateTechniqueFiles(); void populateTechniqueFiles();

View file

@ -75,6 +75,7 @@ namespace fx
mGLSLExtensions.clear(); mGLSLExtensions.clear();
mGLSLVersion = mUBO ? 330 : 120; mGLSLVersion = mUBO ? 330 : 120;
mGLSLProfile.clear(); mGLSLProfile.clear();
mDynamic = false;
} }
std::string Technique::getBlockWithLineDirective() std::string Technique::getBlockWithLineDirective()
@ -249,11 +250,13 @@ namespace fx
for (const auto& ext : parseLiteralList<Lexer::Comma>()) for (const auto& ext : parseLiteralList<Lexer::Comma>())
mGLSLExtensions.emplace(ext); mGLSLExtensions.emplace(ext);
} }
else if (key == "dynamic")
mDynamic = parseBool();
else else
error(Misc::StringUtils::format("unexpected key '%s'", std::string{key})); error(Misc::StringUtils::format("unexpected key '%s'", std::string{key}));
expect<Lexer::SemiColon>(); expect<Lexer::SemiColon>();
} }
if (mPassKeys.empty()) if (mPassKeys.empty())
error("pass list in 'technique' block cannot be empty."); error("pass list in 'technique' block cannot be empty.");

View file

@ -159,6 +159,8 @@ namespace fx
UniformMap::iterator findUniform(const std::string& name); UniformMap::iterator findUniform(const std::string& name);
bool getDynamic() const { return mDynamic; }
private: private:
[[noreturn]] void error(const std::string& msg); [[noreturn]] void error(const std::string& msg);
@ -275,6 +277,8 @@ namespace fx
std::string mBuffer; std::string mBuffer;
std::string mLastError; std::string mLastError;
bool mDynamic = false;
}; };
template<> void Technique::parseBlockImp<Lexer::Shared>(); template<> void Technique::parseBlockImp<Lexer::Shared>();

View file

@ -5,8 +5,8 @@ Connecting With Lua
Overview Overview
######## ########
Every shader can be controlled through the Lua scripting system. While shaders can be disabled and enabled, Every shader that is marked as ``dynamic`` can be controlled through the Lua scripting system. Shaders can be disabled and enabled,
shader uniforms can also be controlled. For details reference the API documentation, found :doc:`here<../lua-scripting/openmw_postprocessing>`. and their uniforms can be controlled via scripts. For details, reference the API documentation :doc:`here<../lua-scripting/openmw_postprocessing>`.
Toggling Shaders With a Keybind Toggling Shaders With a Keybind
############################### ###############################
@ -42,12 +42,14 @@ It is assumed the shader has the filename ``desaturate.omwfx`` in this example.
technique { technique {
description = "Desaturates scene"; description = "Desaturates scene";
passes = desaturate;
version = "1.0"; version = "1.0";
author = "Fargoth"; author = "Fargoth";
passes = desaturate; passes = desaturate;
dynamic = true;
} }
.. note::
The ``dynamic`` flag here is very important, otherwise Lua will not be able to interact with this shader.
Next, a script that is attached to the player is needed. The shader is loaded first, then toggled on and off in response to key presses. Next, a script that is attached to the player is needed. The shader is loaded first, then toggled on and off in response to key presses.
Below is a working example to illustrate this. Below is a working example to illustrate this.
@ -83,11 +85,11 @@ hidden in this HUD, this can done by adding the ``hidden`` flag to the main tech
technique { technique {
description = "Desaturates scene"; description = "Desaturates scene";
passes = desaturate;
version = "1.0"; version = "1.0";
author = "Fargoth"; author = "Fargoth";
passes = desaturate; passes = desaturate;
flags = hidden; flags = hidden;
dynamic = true;
} }
This flag is usually used when the shader is associated with something special, like special weather, spell, or alcohol effects. This flag is usually used when the shader is associated with something special, like special weather, spell, or alcohol effects.

View file

@ -314,6 +314,11 @@ Exactly one ``technique`` block is required for every shader file. In this we de
+------------------+--------------------+---------------------------------------------------+ +------------------+--------------------+---------------------------------------------------+
| flags | `SHADER_FLAG`_ | ``,`` separated list of shader flags | | flags | `SHADER_FLAG`_ | ``,`` separated list of shader flags |
+------------------+--------------------+---------------------------------------------------+ +------------------+--------------------+---------------------------------------------------+
| dynamic | boolean | Whether shader is exposed to Lua |
+------------------+--------------------+---------------------------------------------------+
When ``dynamic`` is set to ``true``, the shaders order cannot be manually moved, enabled, or disabled. The shaders state
can only be controlled via a Lua script.
In the code snippet below, a shader is defined that requires GLSL `330`, HDR capatiblities, and is only enabled underwater in exteriors. In the code snippet below, a shader is defined that requires GLSL `330`, HDR capatiblities, and is only enabled underwater in exteriors.