postprocessing lua api extensions

fix/shrink_builds
cody glassman 3 years ago
parent 02cfb7e258
commit 6093cb5f2c

@ -296,7 +296,7 @@ namespace MWGui
auto technique = processor->loadTechnique(name); auto technique = processor->loadTechnique(name);
if (!technique) if (!technique || technique->getStatus() == fx::Technique::Status::File_Not_exists)
return; return;
while (mConfigArea->getChildCount() > 0) while (mConfigArea->getChildCount() > 0)
@ -304,9 +304,6 @@ namespace MWGui
mShaderInfo->setCaption(""); mShaderInfo->setCaption("");
if (!technique)
return;
std::ostringstream ss; std::ostringstream ss;
const std::string NA = "NA"; const std::string NA = "NA";
@ -322,8 +319,8 @@ namespace MWGui
const auto flags = technique->getFlags(); const auto flags = technique->getFlags();
const auto flag_interior = serializeBool (!(flags & fx::Technique::Flag_Disable_Interiors)); const auto flag_interior = serializeBool(!(flags & fx::Technique::Flag_Disable_Interiors));
const auto flag_exterior = serializeBool (!(flags & fx::Technique::Flag_Disable_Exteriors)); const auto flag_exterior = serializeBool(!(flags & fx::Technique::Flag_Disable_Exteriors));
const auto flag_underwater = serializeBool(!(flags & fx::Technique::Flag_Disable_Underwater)); const auto flag_underwater = serializeBool(!(flags & fx::Technique::Flag_Disable_Underwater));
const auto flag_abovewater = serializeBool(!(flags & fx::Technique::Flag_Disable_Abovewater)); const auto flag_abovewater = serializeBool(!(flags & fx::Technique::Flag_Disable_Abovewater));
@ -339,14 +336,12 @@ 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::File_Not_exists:
ss << "#{fontcolourhtml=negative}Shader Error: #{fontcolourhtml=header} <" << std::string(technique->getFileName()) << ">#{fontcolourhtml=normal} not found." << endl << endl
<< "Ensure the shader file is in a 'Shaders/' sub directory in a data files directory";
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();
break; break;
case fx::Technique::Status::File_Not_exists:
break;
} }
mShaderInfo->setCaptionWithReplacing(ss.str()); mShaderInfo->setCaptionWithReplacing(ss.str());

@ -59,9 +59,44 @@ namespace MWLua
return Misc::StringUtils::format("Shader(%s, %s)", mShader->getName(), mShader->getFileName()); return Misc::StringUtils::format("Shader(%s, %s)", mShader->getName(), mShader->getFileName());
} }
bool mQueuedAction = false; enum { Action_None, Action_Enable, Action_Disable } mQueuedAction = Action_None;
}; };
template <class T>
auto getSetter(const Context& context)
{
return [context](const Shader& shader, const std::string& name, const T& value) {
context.mLuaManager->addAction(std::make_unique<SetUniformShaderAction<T>>(context.mLua, shader.mShader, name, value));
};
}
template <class T>
auto getArraySetter(const Context& context)
{
return [context](const Shader& shader, const std::string& name, const sol::table& table) {
auto targetSize = MWBase::Environment::get().getWorld()->getPostProcessor()->getUniformSize(shader.mShader, name);
if (!targetSize.has_value())
throw std::runtime_error(Misc::StringUtils::format("Failed setting uniform array '%s'", name));
if (*targetSize != table.size())
throw std::runtime_error(Misc::StringUtils::format("Mismatching uniform array size, got %zu expected %zu", table.size(), *targetSize));
std::vector<T> values;
values.reserve(*targetSize);
for (size_t i = 0; i < *targetSize; ++i)
{
sol::object obj = table[i+1];
if (!obj.is<T>())
throw std::runtime_error("Invalid type for uniform array");
values.push_back(obj.as<T>());
}
context.mLuaManager->addAction(std::make_unique<SetUniformShaderAction<std::vector<T>>>(context.mLua, shader.mShader, name, values));
};
}
sol::table initPostprocessingPackage(const Context& context) sol::table initPostprocessingPackage(const Context& context)
{ {
sol::table api(context.mLua->sol(), sol::create); sol::table api(context.mLua->sol(), sol::create);
@ -76,62 +111,64 @@ namespace MWLua
pos = optPos.value(); pos = optPos.value();
if (shader.mShader && shader.mShader->isValid()) if (shader.mShader && shader.mShader->isValid())
shader.mQueuedAction = true; shader.mQueuedAction = Shader::Action_Enable;
context.mLuaManager->addAction( context.mLuaManager->addAction(
[=] { MWBase::Environment::get().getWorld()->getPostProcessor()->enableTechnique(shader.mShader, pos); }, [=, &shader] {
shader.mQueuedAction = Shader::Action_None;
if (!MWBase::Environment::get().getWorld()->getPostProcessor()->enableTechnique(shader.mShader, pos))
throw std::runtime_error("Failed enabling shader '" + shader.mShader->getName() + "'");
},
"Enable shader " + (shader.mShader ? shader.mShader->getName() : "nil") "Enable shader " + (shader.mShader ? shader.mShader->getName() : "nil")
); );
}; };
shader["disable"] = [context](Shader& shader) shader["disable"] = [context](Shader& shader)
{ {
shader.mQueuedAction = false; shader.mQueuedAction = Shader::Action_Disable;
context.mLuaManager->addAction( context.mLuaManager->addAction(
[&] { MWBase::Environment::get().getWorld()->getPostProcessor()->disableTechnique(shader.mShader); }, [&] {
shader.mQueuedAction = Shader::Action_None;
if (!MWBase::Environment::get().getWorld()->getPostProcessor()->disableTechnique(shader.mShader))
throw std::runtime_error("Failed disabling shader '" + shader.mShader->getName() + "'");
},
"Disable shader " + (shader.mShader ? shader.mShader->getName() : "nil") "Disable shader " + (shader.mShader ? shader.mShader->getName() : "nil")
); );
}; };
shader["isEnabled"] = [](const Shader& shader) shader["isEnabled"] = [](const Shader& shader)
{ {
return shader.mQueuedAction; if (shader.mQueuedAction == Shader::Action_Enable)
return true;
else if (shader.mQueuedAction == Shader::Action_Disable)
return false;
return MWBase::Environment::get().getWorld()->getPostProcessor()->isTechniqueEnabled(shader.mShader);
}; };
shader["setBool"] = [context](const Shader& shader, const std::string& name, bool value) shader["setBool"] = getSetter<bool>(context);
{ shader["setFloat"] = getSetter<float>(context);
context.mLuaManager->addAction(std::make_unique<SetUniformShaderAction<bool>>(context.mLua, shader.mShader, name, value)); shader["setInt"] = getSetter<int>(context);
}; shader["setVector2"] = getSetter<osg::Vec2f>(context);
shader["setVector3"] = getSetter<osg::Vec3f>(context);
shader["setFloat"] = [context](const Shader& shader, const std::string& name, float value) shader["setVector4"] = getSetter<osg::Vec4f>(context);
{
context.mLuaManager->addAction(std::make_unique<SetUniformShaderAction<float>>(context.mLua, shader.mShader, name, value));
};
shader["setInt"] = [context](const Shader& shader, const std::string& name, int value)
{
context.mLuaManager->addAction(std::make_unique<SetUniformShaderAction<int>>(context.mLua, shader.mShader, name, value));
};
shader["setVector2"] = [context](const Shader& shader, const std::string& name, const osg::Vec2f& value) shader["setFloatArray"] = getArraySetter<float>(context);
{ shader["setIntArray"] = getArraySetter<int>(context);
context.mLuaManager->addAction(std::make_unique<SetUniformShaderAction<osg::Vec2f>>(context.mLua, shader.mShader, name, value)); shader["setVector2Array"] = getArraySetter<osg::Vec2f>(context);
}; shader["setVector3Array"] = getArraySetter<osg::Vec3f>(context);
shader["setVector4Array"] = getArraySetter<osg::Vec4f>(context);
shader["setVector3"] = [context](const Shader& shader, const std::string& name, const osg::Vec3f& value) api["load"] = [](const std::string& name)
{ {
context.mLuaManager->addAction(std::make_unique<SetUniformShaderAction<osg::Vec3f>>(context.mLua, shader.mShader, name, value)); Shader shader{MWBase::Environment::get().getWorld()->getPostProcessor()->loadTechnique(name, false)};
};
shader["setVector4"] = [context](const Shader& shader, const std::string& name, const osg::Vec4f& value) if (!shader.mShader || !shader.mShader->isValid())
{ throw std::runtime_error(Misc::StringUtils::format("Failed loading shader '%s'", name));
context.mLuaManager->addAction(std::make_unique<SetUniformShaderAction<osg::Vec4f>>(context.mLua, shader.mShader, name, value));
};
api["load"] = [](const std::string& name) return shader;
{
return Shader(MWBase::Environment::get().getWorld()->getPostProcessor()->loadTechnique(name, false));
}; };
return LuaUtil::makeReadOnly(api); return LuaUtil::makeReadOnly(api);

@ -406,6 +406,13 @@ namespace MWRender
void PostProcessor::update(size_t frameId) void PostProcessor::update(size_t frameId)
{ {
while (!mQueuedTemplates.empty())
{
mTemplates.push_back(std::move(mQueuedTemplates.back()));
mQueuedTemplates.pop_back();
}
updateLiveReload(); updateLiveReload();
reloadIfRequired(); reloadIfRequired();
@ -582,7 +589,7 @@ namespace MWRender
if (uniform->mSamplerType) continue; if (uniform->mSamplerType) continue;
if (auto type = uniform->getType()) if (auto type = uniform->getType())
uniform->setUniform(node.mRootStateSet->getOrCreateUniform(uniform->mName, type.value())); uniform->setUniform(node.mRootStateSet->getOrCreateUniform(uniform->mName.c_str(), *type, uniform->getNumElements()));
} }
std::unordered_map<osg::Texture2D*, osg::Texture2D*> renderTargetCache; std::unordered_map<osg::Texture2D*, osg::Texture2D*> renderTargetCache;
@ -643,7 +650,13 @@ namespace MWRender
bool PostProcessor::enableTechnique(std::shared_ptr<fx::Technique> technique, std::optional<int> location) bool PostProcessor::enableTechnique(std::shared_ptr<fx::Technique> technique, std::optional<int> location)
{ {
if (!technique || technique->getName() == "main" || (location.has_value() && location.value() <= 0)) if (!isEnabled())
{
Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << technique->getName() << "'";
return false;
}
if (!technique || Misc::StringUtils::ciEqual(technique->getName(), "main") || (location.has_value() && location.value() <= 0))
return false; return false;
disableTechnique(technique, false); disableTechnique(technique, false);
@ -753,14 +766,21 @@ namespace MWRender
mHUDCamera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); mHUDCamera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
} }
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(const std::string& name, bool insert) std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame)
{ {
if (!isEnabled()) if (!isEnabled())
{
Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << name << "'";
return nullptr; return nullptr;
}
for (size_t i = 0; i < mTemplates.size(); ++i) for (const auto& technique : mTemplates)
if (name == mTemplates[i]->getName()) if (Misc::StringUtils::ciEqual(technique->getName(), name))
return mTemplates[i]; return technique;
for (const auto& technique : mQueuedTemplates)
if (Misc::StringUtils::ciEqual(technique->getName(), name))
return technique;
auto technique = std::make_shared<fx::Technique>(*mVFS, *mRendering.getResourceSystem()->getImageManager(), name, mWidth, mHeight, mUBO, mNormalsSupported); auto technique = std::make_shared<fx::Technique>(*mVFS, *mRendering.getResourceSystem()->getImageManager(), name, mWidth, mHeight, mUBO, mNormalsSupported);
@ -769,8 +789,11 @@ 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 (!insert) if (!loadNextFrame)
{
mQueuedTemplates.push_back(technique);
return technique; return technique;
}
reloadMainPass(*technique); reloadMainPass(*technique);
@ -779,18 +802,6 @@ namespace MWRender
return mTemplates.back(); return mTemplates.back();
} }
void PostProcessor::addTemplate(std::shared_ptr<fx::Technique> technique)
{
if (!isEnabled())
return;
for (size_t i = 0; i < mTemplates.size(); ++i)
if (technique.get() == mTemplates[i].get())
return;
mTemplates.push_back(technique);
}
void PostProcessor::reloadTechniques() void PostProcessor::reloadTechniques()
{ {
if (!isEnabled()) if (!isEnabled())
@ -810,7 +821,7 @@ namespace MWRender
if (techniqueName.empty()) if (techniqueName.empty())
continue; continue;
if ((&techniqueName != &techniqueStrings.front()) && Misc::StringUtils::ciEqual(techniqueName, "main")) if ((&techniqueName != &techniqueStrings.front()) && techniqueName == "main")
{ {
Log(Debug::Warning) << "main.omwfx techniqued specified in chain, this is not allowed. technique file will be ignored if it exists."; Log(Debug::Warning) << "main.omwfx techniqued specified in chain, this is not allowed. technique file will be ignored if it exists.";
continue; continue;

@ -136,6 +136,16 @@ namespace MWRender
(*it)->setValue(value); (*it)->setValue(value);
} }
std::optional<size_t> getUniformSize(std::shared_ptr<fx::Technique> technique, const std::string& name)
{
auto it = technique->findUniform(name);
if (it == technique->getUniformMap().end())
return std::nullopt;
return (*it)->getNumElements();
}
bool isTechniqueEnabled(const std::shared_ptr<fx::Technique>& technique) const; bool isTechniqueEnabled(const std::shared_ptr<fx::Technique>& technique) const;
void setExteriorFlag(bool exterior) { mExteriorFlag = exterior; } void setExteriorFlag(bool exterior) { mExteriorFlag = exterior; }
@ -144,9 +154,7 @@ namespace MWRender
void toggleMode(); void toggleMode();
std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool insert=true); std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame=true);
void addTemplate(std::shared_ptr<fx::Technique> technique);
bool isEnabled() const { return mUsePostProcessing && mEnabled; } bool isEnabled() const { return mUsePostProcessing && mEnabled; }
@ -192,6 +200,7 @@ namespace MWRender
TechniqueList mTechniques; TechniqueList mTechniques;
TechniqueList mTemplates; TechniqueList mTemplates;
TechniqueList mQueuedTemplates;
std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap; std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap;

@ -171,7 +171,7 @@ TestFile repeated_shared_block{R"(
const auto& uniform = mTechnique->getUniformMap().front(); const auto& uniform = mTechnique->getUniformMap().front();
EXPECT_TRUE(uniform->mStatic); EXPECT_TRUE(uniform->mStatic);
EXPECT_FLOAT_EQ(uniform->mStep, 0.5f); EXPECT_DOUBLE_EQ(uniform->mStep, 0.5);
EXPECT_EQ(uniform->getDefault<osg::Vec4f>(), osg::Vec4f(0,0,0,0)); EXPECT_EQ(uniform->getDefault<osg::Vec4f>(), osg::Vec4f(0,0,0,0));
EXPECT_EQ(uniform->getMin<osg::Vec4f>(), osg::Vec4f(0,1,0,0)); EXPECT_EQ(uniform->getMin<osg::Vec4f>(), osg::Vec4f(0,1,0,0));
EXPECT_EQ(uniform->getMax<osg::Vec4f>(), osg::Vec4f(0,0,1,0)); EXPECT_EQ(uniform->getMax<osg::Vec4f>(), osg::Vec4f(0,0,1,0));

@ -526,7 +526,7 @@ namespace fx
error(Misc::StringUtils::format("redeclaration of uniform '%s'", std::string(mBlockName))); error(Misc::StringUtils::format("redeclaration of uniform '%s'", std::string(mBlockName)));
std::shared_ptr<Types::UniformBase> uniform = std::make_shared<Types::UniformBase>(); std::shared_ptr<Types::UniformBase> uniform = std::make_shared<Types::UniformBase>();
Types::Uniform<SrcT> data; Types::Uniform<SrcT> data = Types::Uniform<SrcT>();
while (!isNext<Lexer::Close_bracket>() && !isNext<Lexer::Eof>()) while (!isNext<Lexer::Close_bracket>() && !isNext<Lexer::Eof>())
{ {
@ -543,11 +543,6 @@ namespace fx
static_assert(isVec || isFloat || isInt || isBool, "Unsupported type"); static_assert(isVec || isFloat || isInt || isBool, "Unsupported type");
std::optional<double> step;
if constexpr (isInt)
step = 1.0;
if (key == "default") if (key == "default")
{ {
if constexpr (isVec) if constexpr (isVec)
@ -559,6 +554,15 @@ namespace fx
else if constexpr (isBool) else if constexpr (isBool)
data.mDefault = parseBool(); data.mDefault = parseBool();
} }
else if (key == "size")
{
if constexpr (isBool)
error("bool arrays currently unsupported");
int size = parseInteger();
if (size > 1)
data.mArray = std::vector<SrcT>(size);
}
else if (key == "min") else if (key == "min")
{ {
if constexpr (isVec) if constexpr (isVec)
@ -582,7 +586,7 @@ namespace fx
data.mMax = parseBool(); data.mMax = parseBool();
} }
else if (key == "step") else if (key == "step")
step = parseFloat(); uniform->mStep = parseFloat();
else if (key == "static") else if (key == "static")
uniform->mStatic = parseBool(); uniform->mStatic = parseBool();
else if (key == "description") else if (key == "description")
@ -598,18 +602,28 @@ namespace fx
else else
error(Misc::StringUtils::format("unexpected key '%s'", std::string{key})); error(Misc::StringUtils::format("unexpected key '%s'", std::string{key}));
if (step)
uniform->mStep = step.value();
expect<Lexer::SemiColon>(); expect<Lexer::SemiColon>();
} }
if (data.isArray())
uniform->mStatic = false;
uniform->mName = std::string(mBlockName); uniform->mName = std::string(mBlockName);
uniform->mData = data; uniform->mData = data;
uniform->mTechniqueName = mName; uniform->mTechniqueName = mName;
if (auto cached = Settings::ShaderManager::get().getValue<SrcT>(mName, uniform->mName)) if (data.mArray)
uniform->setValue<SrcT>(cached.value()); {
if constexpr (!std::is_same_v<bool, SrcT>)
{
if (auto cached = Settings::ShaderManager::get().getValue<std::vector<SrcT>>(mName, uniform->mName))
uniform->setValue(cached.value());
}
}
else if (auto cached = Settings::ShaderManager::get().getValue<SrcT>(mName, uniform->mName))
{
uniform->setValue(cached.value());
}
mDefinedUniforms.emplace_back(std::move(uniform)); mDefinedUniforms.emplace_back(std::move(uniform));
} }

@ -60,12 +60,24 @@ namespace fx
struct Uniform struct Uniform
{ {
std::optional<T> mValue; std::optional<T> mValue;
T mDefault; std::optional<std::vector<T>> mArray;
T mDefault = {};
T mMin = std::numeric_limits<T>::lowest(); T mMin = std::numeric_limits<T>::lowest();
T mMax = std::numeric_limits<T>::max(); T mMax = std::numeric_limits<T>::max();
using value_type = T; using value_type = T;
bool isArray() const
{
return mArray.has_value();
}
const std::vector<T>& getArray() const
{
return *mArray;
}
T getValue() const T getValue() const
{ {
return mValue.value_or(mDefault); return mValue.value_or(mDefault);
@ -97,7 +109,7 @@ namespace fx
bool mStatic = true; bool mStatic = true;
std::optional<SamplerType> mSamplerType = std::nullopt; std::optional<SamplerType> mSamplerType = std::nullopt;
double mStep; double mStep = 1.0;
Uniform_t mData; Uniform_t mData;
@ -109,6 +121,11 @@ namespace fx
return value.value_or(std::get<Uniform<T>>(mData).getValue()); return value.value_or(std::get<Uniform<T>>(mData).getValue());
} }
size_t getNumElements() const
{
return std::visit([&](auto&& arg) { ;return arg.isArray() ? arg.getArray().size() : 1; }, mData);
}
template <class T> template <class T>
T getMin() const T getMin() const
{ {
@ -137,8 +154,7 @@ namespace fx
{ {
arg.mValue = value; arg.mValue = value;
if (mStatic) Settings::ShaderManager::get().setValue(mTechniqueName, mName, value);
Settings::ShaderManager::get().setValue<T>(mTechniqueName, mName, value);
} }
else else
{ {
@ -147,6 +163,28 @@ namespace fx
}, mData); }, mData);
} }
template <class T, class A>
void setValue(const std::vector<T, A>& value)
{
std::visit([&, value](auto&& arg) {
using U = typename std::decay_t<decltype(arg)>::value_type;
if (!arg.isArray() || arg.getArray().size() != value.size())
{
Log(Debug::Error) << "Attempting to set uniform array '" << mName << "' with mismatching array sizes";
return;
}
if constexpr (std::is_same_v<T, U>)
{
arg.mArray = value;
Settings::ShaderManager::get().setValue(mTechniqueName, mName, value);
}
else
Log(Debug::Warning) << "Attempting to set uniform array '" << mName << "' with wrong type";
}, mData);
}
void setUniform(osg::Uniform* uniform) void setUniform(osg::Uniform* uniform)
{ {
auto type = getType(); auto type = getType();
@ -155,8 +193,14 @@ namespace fx
std::visit([&](auto&& arg) std::visit([&](auto&& arg)
{ {
const auto value = arg.getValue(); if (arg.isArray())
uniform->set(value); {
for (size_t i = 0; i < arg.getArray().size(); ++i)
uniform->setElement(i, arg.getArray()[i]);
uniform->dirty();
}
else
uniform->set(arg.getValue());
}, mData); }, mData);
} }
@ -197,52 +241,53 @@ namespace fx
} }
} }
bool useUniform = (Settings::ShaderManager::get().getMode() == Settings::ShaderManager::Mode::Debug || mStatic == false);
return std::visit([&](auto&& arg) -> std::optional<std::string> { return std::visit([&](auto&& arg) -> std::optional<std::string> {
using T = typename std::decay_t<decltype(arg)>::value_type; using T = typename std::decay_t<decltype(arg)>::value_type;
auto value = arg.getValue(); auto value = arg.getValue();
const bool useUniform = arg.isArray() || (Settings::ShaderManager::get().getMode() == Settings::ShaderManager::Mode::Debug || mStatic == false);
const std::string uname = arg.isArray() ? Misc::StringUtils::format("%s[%zu]", mName, arg.getArray().size()) : mName;
if constexpr (std::is_same_v<T, osg::Vec2f>) if constexpr (std::is_same_v<T, osg::Vec2f>)
{ {
if (useUniform) if (useUniform)
return Misc::StringUtils::format("uniform vec2 %s;", mName); return Misc::StringUtils::format("uniform vec2 %s;", uname);
return Misc::StringUtils::format("const vec2 %s=vec2(%f,%f);", mName, value[0], value[1]); return Misc::StringUtils::format("const vec2 %s=vec2(%f,%f);", mName, value[0], value[1]);
} }
else if constexpr (std::is_same_v<T, osg::Vec3f>) else if constexpr (std::is_same_v<T, osg::Vec3f>)
{ {
if (useUniform) if (useUniform)
return Misc::StringUtils::format("uniform vec3 %s;", mName); return Misc::StringUtils::format("uniform vec3 %s;", uname);
return Misc::StringUtils::format("const vec3 %s=vec3(%f,%f,%f);", mName, value[0], value[1], value[2]); return Misc::StringUtils::format("const vec3 %s=vec3(%f,%f,%f);", mName, value[0], value[1], value[2]);
} }
else if constexpr (std::is_same_v<T, osg::Vec4f>) else if constexpr (std::is_same_v<T, osg::Vec4f>)
{ {
if (useUniform) if (useUniform)
return Misc::StringUtils::format("uniform vec4 %s;", mName); return Misc::StringUtils::format("uniform vec4 %s;", uname);
return Misc::StringUtils::format("const vec4 %s=vec4(%f,%f,%f,%f);", mName, value[0], value[1], value[2], value[3]); return Misc::StringUtils::format("const vec4 %s=vec4(%f,%f,%f,%f);", mName, value[0], value[1], value[2], value[3]);
} }
else if constexpr (std::is_same_v<T, float>) else if constexpr (std::is_same_v<T, float>)
{ {
if (useUniform) if (useUniform)
return Misc::StringUtils::format("uniform float %s;", mName); return Misc::StringUtils::format("uniform float %s;", uname);
return Misc::StringUtils::format("const float %s=%f;", mName, value); return Misc::StringUtils::format("const float %s=%f;", mName, value);
} }
else if constexpr (std::is_same_v<T, int>) else if constexpr (std::is_same_v<T, int>)
{ {
if (useUniform) if (useUniform)
return Misc::StringUtils::format("uniform int %s;", mName); return Misc::StringUtils::format("uniform int %s;", uname);
return Misc::StringUtils::format("const int %s=%i;", mName, value); return Misc::StringUtils::format("const int %s=%i;", mName, value);
} }
else if constexpr (std::is_same_v<T, bool>) else if constexpr (std::is_same_v<T, bool>)
{ {
if (useUniform) if (useUniform)
return Misc::StringUtils::format("uniform bool %s;", mName); return Misc::StringUtils::format("uniform bool %s;", uname);
return Misc::StringUtils::format("const bool %s=%s;", mName, value ? "true" : "false"); return Misc::StringUtils::format("const bool %s=%s;", mName, value ? "true" : "false");
} }

@ -5,6 +5,7 @@
#include <filesystem> #include <filesystem>
#include <optional> #include <optional>
#include <fstream> #include <fstream>
#include <vector>
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>

@ -271,10 +271,10 @@ Below is an example of passing a value through a custom vertex shader to the fra
} }
fragment pass { fragment pass {
omw_Out vec2 omw_TexCoord; omw_In vec2 omw_TexCoord;
// our custom output from the vertex shader is available // our custom output from the vertex shader is available
omw_Out float noise; omw_In float noise;
void main() void main()
{ {
@ -461,6 +461,14 @@ To use the uniform you can reference it in any pass, it should **not** be declar
} }
} }
You can use uniform arrays as well, but they are restricted to the `Lua API <../lua-scripting/openmw_postprocessing.html>`_ scripts.
These uniform blocks must be defined with the new ``size`` parameter.
.. code-block:: none
uniform_vec3 uArray {
size = 10;
}
``render_target`` ``render_target``
***************** *****************

@ -7,7 +7,7 @@ Overview
OpenMW supports a moddable post process framework for creating and OpenMW supports a moddable post process framework for creating and
controlling screenspace effects. This is integrated into OpenMW's Lua API, see controlling screenspace effects. This is integrated into OpenMW's Lua API, see
`reference <../lua-scripting/openmw_shader.html>`_ for details. `reference <../lua-scripting/openmw_postprocessing.html>`_ for details.
Basic concepts Basic concepts
============== ==============

@ -1,19 +1,18 @@
--- ---
-- `openmw.postprocessing` is an interface to postprocessing shaders. -- `openmw.postprocessing` is an interface to postprocessing shaders.
-- Can be used only by local scripts, that are attached to a player. -- Can be used only by local scripts, that are attached to a player.
-- @module shader -- @module postprocessing
-- @usage local postprocessing = require('openmw.postprocessing') -- @usage local postprocessing = require('openmw.postprocessing')
--- ---
-- Load a shader and return its handle. -- Load a shader and return its handle.
-- @function [parent=#postprocessing] load -- @function [parent=#postprocessing] load
-- @param #string name Name of the shader without its extension -- @param #string name Name of the shader without its extension
-- @return #Shader -- @return #Shader
-- @usage -- @usage
-- If the shader exists and compiles, the shader will still be off by default. -- -- If the shader exists and compiles, the shader will still be off by default.
-- It must be enabled to see its effect. -- -- It must be enabled to see its effect.
-- local vignetteShader = postprocessing.load('vignette') -- local vignetteShader = postprocessing.load('vignette')
--- ---
@ -72,21 +71,62 @@
-- @function [parent=#Shader] setVector2 -- @function [parent=#Shader] setVector2
-- @param self -- @param self
-- @param #string name Name of uniform -- @param #string name Name of uniform
-- @param #Vector2 value Value of uniform. -- @param openmw.util#Vector2 value Value of uniform.
--- ---
-- Set a non static Vector3 shader variable. -- Set a non static Vector3 shader variable.
-- @function [parent=#Shader] setVector3 -- @function [parent=#Shader] setVector3
-- @param self -- @param self
-- @param #string name Name of uniform -- @param #string name Name of uniform
-- @param #Vector3 value Value of uniform. -- @param openmw.util#Vector3 value Value of uniform.
--- ---
-- Set a non static Vector4 shader variable. -- Set a non static Vector4 shader variable.
-- @function [parent=#Shader] setVector4 -- @function [parent=#Shader] setVector4
-- @param self -- @param self
-- @param #string name Name of uniform -- @param #string name Name of uniform
-- @param #Vector4 value Value of uniform. -- @param openmw.util#Vector4 value Value of uniform.
---
-- Set a non static integer array shader variable.
-- @function [parent=#Shader] setIntArray
-- @param self
-- @param #string name Name of uniform
-- @param #table array Contains equal number of #number elements as the uniform array.
---
-- Set a non static float array shader variable.
-- @function [parent=#Shader] setFloatArray
-- @param self
-- @param #string name Name of uniform
-- @param #table array Contains equal number of #number elements as the uniform array.
---
-- Set a non static Vector2 array shader variable.
-- @function [parent=#Shader] setVector2Array
-- @param self
-- @param #string name Name of uniform
-- @param #table array Contains equal number of @{openmw.util#Vector2} elements as the uniform array.
---
-- Set a non static Vector3 array shader variable.
-- @function [parent=#Shader] setVector3Array
-- @param self
-- @param #string name Name of uniform
-- @param #table array Contains equal number of @{openmw.util#Vector3} elements as the uniform array.
---
-- Set a non static Vector4 array shader variable.
-- @function [parent=#Shader] setVector4Array
-- @param self
-- @param #string name Name of uniform
-- @param #table array Contains equal number of @{openmw.util#Vector4} elements as the uniform array.
-- @usage
-- -- Setting an array
-- local shader = postprocessing.load('godrays')
-- -- Toggle shader on
-- shader:enable()
-- -- Set new array uniform which was defined with length 2
-- shader:setVector4Array('myArray', { util.vector4(1,0,0,1), util.vector4(1,0,1,1) })
return nil return nil

Loading…
Cancel
Save