add choice widget type to postprocessing uniforms

esm4-texture
Cody Glassman 9 months ago
parent 82bc6674dc
commit 098396822f

@ -168,10 +168,11 @@ namespace MWGui
if (static_cast<size_t>(index) != selected)
{
auto technique = *mActiveList->getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
if (technique->getDynamic())
if (technique->getDynamic() || technique->getInternal())
return;
if (processor->enableTechnique(std::move(technique), index) != MWRender::PostProcessor::Status_Error)
if (processor->enableTechnique(std::move(technique), index - mOffset)
!= MWRender::PostProcessor::Status_Error)
processor->saveChain();
}
}
@ -444,10 +445,16 @@ namespace MWGui
}
}
mOffset = 0;
for (auto technique : processor->getTechniques())
{
if (!technique->getHidden())
{
mActiveList->addItem(technique->getName(), technique);
if (technique->getInternal())
mOffset++;
}
}
auto tryFocus = [this](ListWrapper* widget, const std::string& hint) {
@ -484,6 +491,7 @@ namespace MWGui
factory.registerFactory<fx::Widgets::EditNumberFloat>("Widget");
factory.registerFactory<fx::Widgets::EditNumberInt>("Widget");
factory.registerFactory<fx::Widgets::EditBool>("Widget");
factory.registerFactory<fx::Widgets::EditChoice>("Widget");
factory.registerFactory<ListWrapper>("Widget");
}
}

@ -96,6 +96,8 @@ namespace MWGui
Gui::AutoSizedEditBox* mShaderInfo;
std::string mOverrideHint;
int mOffset = 0;
};
}

@ -1,5 +1,7 @@
#include "pingpongcanvas.hpp"
#include <cassert>
#include <components/shader/shadermanager.hpp>
#include <components/stereo/multiview.hpp>
#include <components/stereo/stereomanager.hpp>

@ -498,6 +498,37 @@ namespace fx
mDefinedUniforms.emplace_back(std::move(uniform));
}
template <class SrcT, class T>
SrcT Technique::getUniformValue()
{
constexpr bool isVec
= std::is_same_v<osg::Vec2f, SrcT> || std::is_same_v<osg::Vec3f, SrcT> || std::is_same_v<osg::Vec4f, SrcT>;
constexpr bool isFloat = std::is_same_v<float, SrcT>;
constexpr bool isInt = std::is_same_v<int, SrcT>;
constexpr bool isBool = std::is_same_v<bool, SrcT>;
static_assert(isVec || isFloat || isInt || isBool, "Unsupported type");
if constexpr (isVec)
{
return parseVec<SrcT, T>();
}
else if constexpr (isFloat)
{
return parseFloat();
}
else if constexpr (isInt)
{
return parseInteger();
}
else if constexpr (isBool)
{
return parseBool();
}
error(Misc::StringUtils::format("failed setting uniform type"));
}
template <class SrcT, class T>
void Technique::parseUniform()
{
@ -515,28 +546,13 @@ namespace fx
expect<Lexer::Equal>("error parsing config for uniform block");
constexpr bool isVec = std::is_same_v<osg::Vec2f,
SrcT> || std::is_same_v<osg::Vec3f, SrcT> || std::is_same_v<osg::Vec4f, SrcT>;
constexpr bool isFloat = std::is_same_v<float, SrcT>;
constexpr bool isInt = std::is_same_v<int, SrcT>;
constexpr bool isBool = std::is_same_v<bool, SrcT>;
static_assert(isVec || isFloat || isInt || isBool, "Unsupported type");
if (key == "default")
{
if constexpr (isVec)
data.mDefault = parseVec<SrcT, T>();
else if constexpr (isFloat)
data.mDefault = parseFloat();
else if constexpr (isInt)
data.mDefault = parseInteger();
else if constexpr (isBool)
data.mDefault = parseBool();
data.mDefault = getUniformValue<SrcT, T>();
}
else if (key == "size")
{
if constexpr (isBool)
if constexpr (std::is_same_v<bool, SrcT>)
error("bool arrays currently unsupported");
int size = parseInteger();
@ -545,25 +561,11 @@ namespace fx
}
else if (key == "min")
{
if constexpr (isVec)
data.mMin = parseVec<SrcT, T>();
else if constexpr (isFloat)
data.mMin = parseFloat();
else if constexpr (isInt)
data.mMin = parseInteger();
else if constexpr (isBool)
data.mMin = parseBool();
data.mMin = getUniformValue<SrcT, T>();
}
else if (key == "max")
{
if constexpr (isVec)
data.mMax = parseVec<SrcT, T>();
else if constexpr (isFloat)
data.mMax = parseFloat();
else if constexpr (isInt)
data.mMax = parseInteger();
else if constexpr (isBool)
data.mMax = parseBool();
data.mMax = getUniformValue<SrcT, T>();
}
else if (key == "step")
uniform->mStep = parseFloat();
@ -571,18 +573,19 @@ namespace fx
uniform->mStatic = parseBool();
else if (key == "description")
{
expect<Lexer::String>();
uniform->mDescription = std::get<Lexer::String>(mToken).value;
uniform->mDescription = parseString();
}
else if (key == "header")
{
expect<Lexer::String>();
uniform->mHeader = std::get<Lexer::String>(mToken).value;
uniform->mHeader = parseString();
}
else if (key == "display_name")
{
expect<Lexer::String>();
uniform->mDisplayName = std::get<Lexer::String>(mToken).value;
uniform->mDisplayName = parseString();
}
else if (key == "widget_type")
{
parseWidgetType<SrcT, T>(data);
}
else
error(Misc::StringUtils::format("unexpected key '%s'", std::string{ key }));
@ -1001,6 +1004,60 @@ namespace fx
error(Misc::StringUtils::format("unrecognized blend function '%s'", std::string{ asLiteral() }));
}
template <class SrcT, class T>
void Technique::parseWidgetType(Types::Uniform<SrcT>& uniform)
{
expect<Lexer::Literal>();
if (asLiteral() == "choice")
{
/* Example usage
widget_type = choice(
"Option A": <T>,
"Option B": <T>,
"Option C": <T>
);
*/
expect<Lexer::Open_Parenthesis>();
std::vector<fx::Types::Choice<SrcT>> choices;
while (!isNext<Lexer::Eof>())
{
fx::Types::Choice<SrcT> choice;
choice.mLabel = parseString();
expect<Lexer::Equal>();
choice.mValue = getUniformValue<SrcT, T>();
choices.push_back(choice);
if (isNext<Lexer::Comma>())
{
mToken = mLexer->next();
// Handle leading comma
if (isNext<Lexer::Close_Parenthesis>())
{
break;
}
continue;
}
break;
}
uniform.mChoices = std::move(choices);
expect<Lexer::Close_Parenthesis>();
}
else
{
error(Misc::StringUtils::format("unrecognized widget type '%s'", std::string{ asLiteral() }));
}
}
bool Technique::parseBool()
{
mToken = mLexer->next();

@ -228,6 +228,12 @@ namespace fx
int parseSourceFormat();
template <class SrcT, class T>
void parseWidgetType(Types::Uniform<SrcT>& uniform);
template <class SrcT, class T>
SrcT getUniformValue();
osg::BlendEquation::Equation parseBlendEquation();
osg::BlendFunc::BlendFuncMode parseBlendFuncMode();

@ -4,15 +4,9 @@
#include <optional>
#include <variant>
#include <osg/BlendEquation>
#include <osg/BlendFunc>
#include <osg/Camera>
#include <osg/FrameBufferObject>
#include <osg/Texture2D>
#include <osg/Uniform>
#include <MyGUI_Widget.h>
#include <components/debug/debuglog.hpp>
#include <components/misc/strings/format.hpp>
#include <components/sceneutil/depth.hpp>
@ -56,6 +50,13 @@ namespace fx
osg::Vec4f mClearColor = osg::Vec4f(0.0, 0.0, 0.0, 1.0);
};
template <class T>
struct Choice
{
std::string mLabel;
T mValue;
};
template <class T>
struct Uniform
{
@ -66,6 +67,8 @@ namespace fx
T mMin = std::numeric_limits<T>::lowest();
T mMax = std::numeric_limits<T>::max();
std::vector<Choice<T>> mChoices;
using value_type = T;
bool isArray() const { return mArray.has_value(); }

@ -28,35 +28,20 @@ namespace fx
{
void EditBool::setValue(bool value)
{
auto uniform = mUniform.lock();
if (!uniform)
return;
mCheckbutton->setCaptionWithReplacing(value ? "#{Interface:On}" : "#{Interface:Off}");
mFill->setVisible(value);
uniform->setValue<bool>(value);
mUniform->setValue<bool>(value);
}
void EditBool::setValueFromUniform()
{
auto uniform = mUniform.lock();
if (!uniform)
return;
setValue(uniform->template getValue<bool>());
setValue(mUniform->template getValue<bool>());
}
void EditBool::toDefault()
{
auto uniform = mUniform.lock();
if (!uniform)
return;
setValue(uniform->getDefault<bool>());
setValue(mUniform->getDefault<bool>());
}
void EditBool::initialiseOverride()
@ -71,12 +56,75 @@ namespace fx
void EditBool::notifyMouseButtonClick(MyGUI::Widget* sender)
{
auto uniform = mUniform.lock();
setValue(!mUniform->getValue<bool>());
}
template <class T>
void EditChoice::setValue(const T& value)
{
// Update the combo view
for (size_t i = 0; i < this->mChoices->getItemCount(); i++)
{
if (*this->mChoices->getItemDataAt<T>(i) == value)
{
this->mChoices->setIndexSelected(i);
break;
}
}
mUniform->template setValue<T>(value);
}
void EditChoice::notifyComboBoxChanged(MyGUI::ComboBox* sender, size_t pos)
{
std::visit(
[this, sender, pos](auto&& data) {
using T = typename std::decay_t<decltype(data)>::value_type;
setValue<T>(*sender->getItemDataAt<T>(pos));
},
mUniform->mData);
}
void EditChoice::setValueFromUniform()
{
std::visit(
[this](auto&& data) {
using T = typename std::decay_t<decltype(data)>::value_type;
size_t index = 0;
for (const auto& choice : data.mChoices)
{
this->mChoices->addItem(choice.mLabel, choice.mValue);
if (choice.mValue == mUniform->template getValue<T>())
{
this->mChoices->setIndexSelected(index);
}
index++;
}
setValue(mUniform->template getValue<T>());
},
mUniform->mData);
}
void EditChoice::toDefault()
{
std::visit(
[this](auto&& data) {
using T = typename std::decay_t<decltype(data)>::value_type;
setValue(mUniform->template getDefault<T>());
},
mUniform->mData);
}
void EditChoice::initialiseOverride()
{
Base::initialiseOverride();
if (!uniform)
return;
assignWidget(mChoices, "Choices");
setValue(!uniform->getValue<bool>());
mChoices->eventComboChangePosition += MyGUI::newDelegate(this, &EditChoice::notifyComboBoxChanged);
}
void UniformBase::init(const std::shared_ptr<fx::Types::UniformBase>& uniform)
@ -101,38 +149,48 @@ namespace fx
[this, &uniform](auto&& arg) {
using T = typename std::decay_t<decltype(arg)>::value_type;
if constexpr (std::is_same_v<osg::Vec4f, T>)
{
createVectorWidget<T, EditNumberFloat4>(uniform, mClient, this);
}
else if constexpr (std::is_same_v<osg::Vec3f, T>)
if (arg.mChoices.size() > 0)
{
createVectorWidget<T, EditNumberFloat3>(uniform, mClient, this);
}
else if constexpr (std::is_same_v<osg::Vec2f, T>)
{
createVectorWidget<T, EditNumberFloat2>(uniform, mClient, this);
}
else if constexpr (std::is_same_v<T, float>)
{
auto* widget = mClient->createWidget<EditNumberFloat>("MW_ValueEditNumber",
{ 0, 0, mClient->getWidth(), mClient->getHeight() }, MyGUI::Align::Stretch);
widget->setData(uniform);
mBases.emplace_back(widget);
}
else if constexpr (std::is_same_v<T, int>)
{
auto* widget = mClient->createWidget<EditNumberInt>("MW_ValueEditNumber",
auto* widget = mClient->createWidget<EditChoice>("MW_ValueEditChoice",
{ 0, 0, mClient->getWidth(), mClient->getHeight() }, MyGUI::Align::Stretch);
widget->setData(uniform);
mBases.emplace_back(widget);
}
else if constexpr (std::is_same_v<T, bool>)
else
{
auto* widget = mClient->createWidget<EditBool>("MW_ValueEditBool",
{ 0, 0, mClient->getWidth(), mClient->getHeight() }, MyGUI::Align::Stretch);
widget->setData(uniform);
mBases.emplace_back(widget);
if constexpr (std::is_same_v<osg::Vec4f, T>)
{
createVectorWidget<T, EditNumberFloat4>(uniform, mClient, this);
}
else if constexpr (std::is_same_v<osg::Vec3f, T>)
{
createVectorWidget<T, EditNumberFloat3>(uniform, mClient, this);
}
else if constexpr (std::is_same_v<osg::Vec2f, T>)
{
createVectorWidget<T, EditNumberFloat2>(uniform, mClient, this);
}
else if constexpr (std::is_same_v<T, float>)
{
auto* widget = mClient->createWidget<EditNumberFloat>("MW_ValueEditNumber",
{ 0, 0, mClient->getWidth(), mClient->getHeight() }, MyGUI::Align::Stretch);
widget->setData(uniform);
mBases.emplace_back(widget);
}
else if constexpr (std::is_same_v<T, int>)
{
auto* widget = mClient->createWidget<EditNumberInt>("MW_ValueEditNumber",
{ 0, 0, mClient->getWidth(), mClient->getHeight() }, MyGUI::Align::Stretch);
widget->setData(uniform);
mBases.emplace_back(widget);
}
else if constexpr (std::is_same_v<T, bool>)
{
auto* widget = mClient->createWidget<EditBool>("MW_ValueEditBool",
{ 0, 0, mClient->getWidth(), mClient->getHeight() }, MyGUI::Align::Stretch);
widget->setData(uniform);
mBases.emplace_back(widget);
}
}
mReset->eventMouseButtonClick += MyGUI::newDelegate(this, &UniformBase::notifyResetClicked);

@ -57,7 +57,7 @@ namespace fx
virtual void toDefault() = 0;
protected:
std::weak_ptr<fx::Types::UniformBase> mUniform;
std::shared_ptr<fx::Types::UniformBase> mUniform;
Index mIndex;
};
@ -95,22 +95,19 @@ namespace fx
float range = 0.f;
float min = 0.f;
if (auto uniform = mUniform.lock())
if constexpr (std::is_fundamental_v<UType>)
{
if constexpr (std::is_fundamental_v<UType>)
{
uniform->template setValue<UType>(mValue);
range = uniform->template getMax<UType>() - uniform->template getMin<UType>();
min = uniform->template getMin<UType>();
}
else
{
UType uvalue = uniform->template getValue<UType>();
uvalue[mIndex] = mValue;
uniform->template setValue<UType>(uvalue);
range = uniform->template getMax<UType>()[mIndex] - uniform->template getMin<UType>()[mIndex];
min = uniform->template getMin<UType>()[mIndex];
}
mUniform->template setValue<UType>(mValue);
range = mUniform->template getMax<UType>() - mUniform->template getMin<UType>();
min = mUniform->template getMin<UType>();
}
else
{
UType uvalue = mUniform->template getValue<UType>();
uvalue[mIndex] = mValue;
mUniform->template setValue<UType>(uvalue);
range = mUniform->template getMax<UType>()[mIndex] - mUniform->template getMin<UType>()[mIndex];
min = mUniform->template getMin<UType>()[mIndex];
}
float fill = (range == 0.f) ? 1.f : (mValue - min) / range;
@ -119,28 +116,22 @@ namespace fx
void setValueFromUniform() override
{
if (auto uniform = mUniform.lock())
{
T value;
T value;
if constexpr (std::is_fundamental_v<UType>)
value = uniform->template getValue<UType>();
else
value = uniform->template getValue<UType>()[mIndex];
if constexpr (std::is_fundamental_v<UType>)
value = mUniform->template getValue<UType>();
else
value = mUniform->template getValue<UType>()[mIndex];
setValue(value);
}
setValue(value);
}
void toDefault() override
{
if (auto uniform = mUniform.lock())
{
if constexpr (std::is_fundamental_v<UType>)
setValue(uniform->template getDefault<UType>());
else
setValue(uniform->template getDefault<UType>()[mIndex]);
}
if constexpr (std::is_fundamental_v<UType>)
setValue(mUniform->template getDefault<UType>());
else
setValue(mUniform->template getDefault<UType>()[mIndex]);
}
private:
@ -164,15 +155,10 @@ namespace fx
void notifyMouseWheel(MyGUI::Widget* sender, int rel)
{
auto uniform = mUniform.lock();
if (!uniform)
return;
if (rel > 0)
increment(uniform->mStep);
increment(mUniform->mStep);
else
increment(-uniform->mStep);
increment(-mUniform->mStep);
}
void notifyMouseButtonDragged(MyGUI::Widget* sender, int left, int top, MyGUI::MouseButton id)
@ -180,24 +166,19 @@ namespace fx
if (id != MyGUI::MouseButton::Left)
return;
auto uniform = mUniform.lock();
if (!uniform)
return;
int delta = left - mLastPointerX;
// allow finer tuning when shift is pressed
constexpr double scaling = 20.0;
T step
= MyGUI::InputManager::getInstance().isShiftPressed() ? uniform->mStep / scaling : uniform->mStep;
= MyGUI::InputManager::getInstance().isShiftPressed() ? mUniform->mStep / scaling : mUniform->mStep;
if (step == 0)
{
if constexpr (std::is_integral_v<T>)
step = 1;
else
step = uniform->mStep;
step = mUniform->mStep;
}
if (delta > 0)
@ -218,30 +199,20 @@ namespace fx
void increment(T step)
{
auto uniform = mUniform.lock();
if (!uniform)
return;
if constexpr (std::is_fundamental_v<UType>)
setValue(std::clamp<T>(uniform->template getValue<UType>() + step,
uniform->template getMin<UType>(), uniform->template getMax<T>()));
setValue(std::clamp<T>(mUniform->template getValue<UType>() + step,
mUniform->template getMin<UType>(), mUniform->template getMax<T>()));
else
setValue(std::clamp<T>(uniform->template getValue<UType>()[mIndex] + step,
uniform->template getMin<UType>()[mIndex], uniform->template getMax<UType>()[mIndex]));
setValue(std::clamp<T>(mUniform->template getValue<UType>()[mIndex] + step,
mUniform->template getMin<UType>()[mIndex], mUniform->template getMax<UType>()[mIndex]));
}
void notifyButtonClicked(MyGUI::Widget* sender)
{
auto uniform = mUniform.lock();
if (!uniform)
return;
if (sender == mButtonDecrease)
increment(-uniform->mStep);
increment(-mUniform->mStep);
else if (sender == mButtonIncrease)
increment(uniform->mStep);
increment(mUniform->mStep);
}
MyGUI::Button* mButtonDecrease{ nullptr };
@ -275,6 +246,23 @@ namespace fx
MYGUI_RTTI_DERIVED(EditNumberInt)
};
class EditChoice : public EditBase, public MyGUI::Widget
{
MYGUI_RTTI_DERIVED(EditChoice)
public:
template <class T>
void setValue(const T& value);
void setValueFromUniform() override;
void toDefault() override;
private:
void initialiseOverride() override;
void notifyComboBoxChanged(MyGUI::ComboBox* sender, size_t pos);
MyGUI::ComboBox* mChoices{ nullptr };
};
class UniformBase final : public MyGUI::Widget
{
MYGUI_RTTI_DERIVED(UniformBase)

@ -451,21 +451,21 @@ To use the sampler, define the appropriately named `sampler2D` in any of your pa
It is possible to define settings for your shaders that can be adjusted by either users or a Lua script.
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+
| Block | default | min | max | static | step | description | display_name | header |
+=================+==========+==========+==========+=========+==========+==============+===================+=========+
|``uniform_bool`` | boolean | x | x | boolean | x | string | string | string |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+
|``uniform_float``| float | float | float | boolean | float | string | string | string |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+
|``uniform_int`` | integer | integer | integer | boolean | integer | string | string | string |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+
|``uniform_vec2`` | vec2 | vec2 | vec2 | boolean | vec2 | string | string | string |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+
|``uniform_vec3`` | vec3 | vec3 | vec3 | boolean | vec3 | string | string | string |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+
|``uniform_vec4`` | vec4 | vec4 | vec4 | boolean | vec4 | string | string | string |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+--------------+
| Block | default | min | max | static | step | description | display_name | header | widget_type |
+=================+==========+==========+==========+=========+==========+==============+===================+=========+==============+
|``uniform_bool`` | boolean | x | x | boolean | x | string | string | string | choice(...) |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+--------------+
|``uniform_float``| float | float | float | boolean | float | string | string | string | choice(...) |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+--------------+
|``uniform_int`` | integer | integer | integer | boolean | integer | string | string | string | choice(...) |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+--------------+
|``uniform_vec2`` | vec2 | vec2 | vec2 | boolean | vec2 | string | string | string | choice(...) |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+--------------+
|``uniform_vec3`` | vec3 | vec3 | vec3 | boolean | vec3 | string | string | string | choice(...) |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+--------------+
|``uniform_vec4`` | vec4 | vec4 | vec4 | boolean | vec4 | string | string | string | choice(...) |
+-----------------+----------+----------+----------+---------+----------+--------------+-------------------+---------+--------------+
The ``description`` field is used to display a toolip when viewed in the in-game HUD. The ``header`` field
field can be used to organize uniforms into groups in the HUD. The ``display_name`` field can be used to create a
@ -509,6 +509,21 @@ These uniform blocks must be defined with the new ``size`` parameter.
size = 10;
}
You may also define a dropdown list for users to select specific values from instead of the default sliders using the ``widget_type`` field.
Each item in the dropdown has an associated display name, which can be a localized string.
.. code-block:: none
uniform_int uStrength {
default = 2;
display_name = "Strength";
widget_type = choice(
"Low" = 1,
"Medium" = 2,
"High" = 3
);
}
``render_target``
*****************

@ -1,6 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Resource" version="1.1">
<Resource type="ResourceLayout" name="MW_ValueEditChoice" version="3.2.0">
<Widget type="Widget" skin="" position="0 0 100 50" align="Stretch" name="Root">
<Widget type="ComboBox" skin="MW_ComboBox" position_real="0 0 1 1" align="Stretch" name="Choices">
<Property key="Caption" value=""/>
<UserString key="HStretch" value="true"/>
<UserString key="VStretch" value="true"/>
</Widget>
</Widget>
</Resource>
<Resource type="ResourceLayout" name="MW_ValueEditNumber" version="3.2.0">
<Widget type="Widget" skin="" position="0 0 100 50" align="Stretch" name="Root">
<Widget type="Widget" skin="BlackBG" position="0 0 100 50" name="Fill" align="Stretch">

Loading…
Cancel
Save