Commit 447b586d authored by Cody Glassman's avatar Cody Glassman Committed by Petr Mikheev
Browse files

[Postprocessing] Fix a couple awkward issues with Lua API

parent feb5d5bb
......@@ -30,7 +30,7 @@ namespace
{
auto technique = processor->getTechniques()[i];
if (!technique)
if (!technique || technique->getDynamic())
continue;
chain << technique->getName();
......@@ -140,10 +140,15 @@ namespace MWGui
{
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
mOverrideHint = list->getItemNameAt(selected);
auto technique = *list->getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
if (technique->getDynamic())
return;
if (enabled)
processor->enableTechnique(*list->getItemDataAt<std::shared_ptr<fx::Technique>>(selected));
processor->enableTechnique(technique);
else
processor->disableTechnique(*list->getItemDataAt<std::shared_ptr<fx::Technique>>(selected));
processor->disableTechnique(technique);
saveChain();
}
}
......@@ -172,7 +177,11 @@ namespace MWGui
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();
}
}
......@@ -330,6 +339,9 @@ namespace MWGui
{
case fx::Technique::Status::Success:
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
<< "#{fontcolourhtml=header}Version: #{fontcolourhtml=normal} " << version << 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} Abovewater: #{fontcolourhtml=normal} " << flag_abovewater;
break;
}
case fx::Technique::Status::Parse_Error:
ss << "#{fontcolourhtml=negative}Shader Compile Error: #{fontcolourhtml=normal} <" << std::string(technique->getName()) << "> failed to compile." << endl << endl
<< technique->getLastError();
......
......@@ -16,6 +16,8 @@
#include "../mwbase/windowmanager.hpp"
#include "../mwrender/postprocessor.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/ptr.hpp"
......@@ -271,6 +273,7 @@ namespace MWLua
LuaUi::clearUserInterface();
mUiResourceManager.clear();
MWBase::Environment::get().getWindowManager()->setConsoleMode("");
MWBase::Environment::get().getWorld()->getPostProcessor()->disableDynamicShaders();
mActiveLocalScripts.clear();
mLocalEvents.clear();
mGlobalEvents.clear();
......
......@@ -117,10 +117,9 @@ namespace MWLua
[=, &shader] {
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() + "'");
},
"Enable shader " + (shader.mShader ? shader.mShader->getName() : "nil")
}
);
};
......@@ -132,10 +131,9 @@ namespace MWLua
[&] {
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() + "'");
},
"Disable shader " + (shader.mShader ? shader.mShader->getName() : "nil")
}
);
};
......@@ -168,6 +166,9 @@ namespace MWLua
if (!shader.mShader || !shader.mShader->isValid())
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;
};
......
......@@ -182,7 +182,6 @@ namespace MWRender
if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt)
{
auto absolutePath = std::filesystem::path(mVFS->getAbsoluteFileName(name));
mTechniqueFileMap[absolutePath.stem().string()] = absolutePath;
}
}
......@@ -210,7 +209,6 @@ namespace MWRender
if (mUsePostProcessing && mTechniqueFileMap.empty())
{
populateTechniqueFiles();
}
mMainTemplate->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
......@@ -648,16 +646,16 @@ namespace MWRender
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())
{
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))
return false;
return Status_Error;
disableTechnique(technique, false);
......@@ -666,23 +664,23 @@ namespace MWRender
mTechniques.insert(mTechniques.begin() + pos, technique);
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"))
return false;
return Status_Error;
auto it = std::find(mTechniques.begin(), mTechniques.end(), technique);
if (it == std::end(mTechniques))
return false;
return Status_Unchanged;
mTechniques.erase(it);
if (dirty)
dirtyTechniques();
return true;
return Status_Toggled;
}
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)
technique->setLastModificationTime(std::filesystem::last_write_time(mTechniqueFileMap[technique->getName()]));
if (!loadNextFrame)
if (loadNextFrame)
{
mQueuedTemplates.push_back(technique);
return technique;
......@@ -853,5 +851,12 @@ namespace MWRender
dirtyTechniques();
}
void PostProcessor::disableDynamicShaders()
{
for (auto& technique : mTechniques)
if (technique->getDynamic())
disableTechnique(technique);
}
}
......@@ -110,9 +110,16 @@ namespace MWRender
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; }
......@@ -154,7 +161,7 @@ namespace MWRender
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; }
......@@ -168,6 +175,8 @@ namespace MWRender
void setRenderTargetSize(int width, int height) { mWidth = width; mHeight = height; }
void disableDynamicShaders();
private:
void populateTechniqueFiles();
......
......@@ -75,6 +75,7 @@ namespace fx
mGLSLExtensions.clear();
mGLSLVersion = mUBO ? 330 : 120;
mGLSLProfile.clear();
mDynamic = false;
}
std::string Technique::getBlockWithLineDirective()
......@@ -249,11 +250,13 @@ namespace fx
for (const auto& ext : parseLiteralList<Lexer::Comma>())
mGLSLExtensions.emplace(ext);
}
else if (key == "dynamic")
mDynamic = parseBool();
else
error(Misc::StringUtils::format("unexpected key '%s'", std::string{key}));
expect<Lexer::SemiColon>();
}
}
if (mPassKeys.empty())
error("pass list in 'technique' block cannot be empty.");
......
......@@ -159,6 +159,8 @@ namespace fx
UniformMap::iterator findUniform(const std::string& name);
bool getDynamic() const { return mDynamic; }
private:
[[noreturn]] void error(const std::string& msg);
......@@ -275,6 +277,8 @@ namespace fx
std::string mBuffer;
std::string mLastError;
bool mDynamic = false;
};
template<> void Technique::parseBlockImp<Lexer::Shared>();
......
......@@ -5,8 +5,8 @@ Connecting With Lua
Overview
########
Every shader can be controlled through the Lua scripting system. While 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>`.
Every shader that is marked as ``dynamic`` can be controlled through the Lua scripting system. Shaders can be disabled and enabled,
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
###############################
......@@ -42,12 +42,14 @@ It is assumed the shader has the filename ``desaturate.omwfx`` in this example.
technique {
description = "Desaturates scene";
passes = desaturate;
version = "1.0";
author = "Fargoth";
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.
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 {
description = "Desaturates scene";
passes = desaturate;
version = "1.0";
author = "Fargoth";
passes = desaturate;
flags = hidden;
dynamic = true;
}
This flag is usually used when the shader is associated with something special, like special weather, spell, or alcohol effects.
......
......@@ -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 |
+------------------+--------------------+---------------------------------------------------+
| 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.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment