mirror of
https://github.com/OpenMW/openmw.git
synced 2025-10-15 20:46:35 +00:00
Merge branch 'thegaidenshinjieffect' into 'master'
Use std::string_view and std::format in components/fx See merge request OpenMW/openmw!4857
This commit is contained in:
commit
14d9be7885
10 changed files with 210 additions and 124 deletions
|
@ -135,6 +135,17 @@ namespace
|
||||||
EXPECT_EQ(std::get<Integer>(token).value, 123);
|
EXPECT_EQ(std::get<Integer>(token).value, 123);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(LexerTest, float_suffix_should_be_float)
|
||||||
|
{
|
||||||
|
Lexer lexer(R"(
|
||||||
|
123f
|
||||||
|
)");
|
||||||
|
|
||||||
|
auto token = lexer.next();
|
||||||
|
EXPECT_TRUE(std::holds_alternative<Float>(token));
|
||||||
|
EXPECT_FLOAT_EQ(std::get<Float>(token).value, 123.f);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(LexerTest, simple_string)
|
TEST(LexerTest, simple_string)
|
||||||
{
|
{
|
||||||
Lexer lexer(R"(
|
Lexer lexer(R"(
|
||||||
|
|
|
@ -90,6 +90,56 @@ namespace
|
||||||
technique { passes = main; }
|
technique { passes = main; }
|
||||||
)" };
|
)" };
|
||||||
|
|
||||||
|
constexpr VFS::Path::NormalizedView invalidNumberInfPath("shaders/invalid_number_inf.omwfx");
|
||||||
|
|
||||||
|
TestingOpenMW::VFSTestFile invalidNumberInf{ R"(
|
||||||
|
uniform_vec4 uVec4 {
|
||||||
|
step = inf;
|
||||||
|
}
|
||||||
|
fragment main { }
|
||||||
|
technique { passes = main; }
|
||||||
|
)" };
|
||||||
|
|
||||||
|
constexpr VFS::Path::NormalizedView invalidNumberNegativeInfPath("shaders/invalid_number_negative_inf.omwfx");
|
||||||
|
|
||||||
|
TestingOpenMW::VFSTestFile invalidNumberNegativeInf{ R"(
|
||||||
|
uniform_vec4 uVec4 {
|
||||||
|
step = -inf;
|
||||||
|
}
|
||||||
|
fragment main { }
|
||||||
|
technique { passes = main; }
|
||||||
|
)" };
|
||||||
|
|
||||||
|
constexpr VFS::Path::NormalizedView invalidNumberUnsignedLongPath("shaders/invalid_number_ulong.omwfx");
|
||||||
|
|
||||||
|
TestingOpenMW::VFSTestFile invalidNumberUnsignedLong{ R"(
|
||||||
|
uniform_vec4 uVec4 {
|
||||||
|
step = 18446744073709551615;
|
||||||
|
}
|
||||||
|
fragment main { }
|
||||||
|
technique { passes = main; }
|
||||||
|
)" };
|
||||||
|
|
||||||
|
constexpr VFS::Path::NormalizedView invalidNumberHexFloatPath("shaders/invalid_number_hex.omwfx");
|
||||||
|
|
||||||
|
TestingOpenMW::VFSTestFile invalidNumberHexFloat{ R"(
|
||||||
|
uniform_vec4 uVec4 {
|
||||||
|
step = 0x1.fffffep+12;
|
||||||
|
}
|
||||||
|
fragment main { }
|
||||||
|
technique { passes = main; }
|
||||||
|
)" };
|
||||||
|
|
||||||
|
constexpr VFS::Path::NormalizedView invalidNumberDoublePath("shaders/invalid_number_double.omwfx");
|
||||||
|
|
||||||
|
TestingOpenMW::VFSTestFile invalidNumberDouble{ R"(
|
||||||
|
uniform_vec4 uVec4 {
|
||||||
|
step = 1.79769e+50;
|
||||||
|
}
|
||||||
|
fragment main { }
|
||||||
|
technique { passes = main; }
|
||||||
|
)" };
|
||||||
|
|
||||||
using namespace testing;
|
using namespace testing;
|
||||||
using namespace Fx;
|
using namespace Fx;
|
||||||
|
|
||||||
|
@ -106,6 +156,11 @@ namespace
|
||||||
{ uniformPropertiesPath, &uniformProperties },
|
{ uniformPropertiesPath, &uniformProperties },
|
||||||
{ missingSamplerSourcePath, &missingSamplerSource },
|
{ missingSamplerSourcePath, &missingSamplerSource },
|
||||||
{ repeatedSharedBlockPath, &repeatedSharedBlock },
|
{ repeatedSharedBlockPath, &repeatedSharedBlock },
|
||||||
|
{ invalidNumberInfPath, &invalidNumberInf },
|
||||||
|
{ invalidNumberNegativeInfPath, &invalidNumberNegativeInf },
|
||||||
|
{ invalidNumberUnsignedLongPath, &invalidNumberUnsignedLong },
|
||||||
|
{ invalidNumberHexFloatPath, &invalidNumberHexFloat },
|
||||||
|
{ invalidNumberDoublePath, &invalidNumberDouble },
|
||||||
}))
|
}))
|
||||||
, mImageManager(mVFS.get(), 0)
|
, mImageManager(mVFS.get(), 0)
|
||||||
{
|
{
|
||||||
|
@ -117,6 +172,17 @@ namespace
|
||||||
*mVFS.get(), mImageManager, Technique::makeFileName(name), name, 1, 1, true, true);
|
*mVFS.get(), mImageManager, Technique::makeFileName(name), name, 1, 1, true, true);
|
||||||
mTechnique->compile();
|
mTechnique->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void expectFailure(const std::string& name, std::string_view errorString)
|
||||||
|
{
|
||||||
|
internal::CaptureStdout();
|
||||||
|
|
||||||
|
compile(name);
|
||||||
|
|
||||||
|
std::string output = internal::GetCapturedStdout();
|
||||||
|
Log(Debug::Error) << output;
|
||||||
|
EXPECT_THAT(output, HasSubstr(errorString));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(TechniqueTest, technique_properties)
|
TEST_F(TechniqueTest, technique_properties)
|
||||||
|
@ -183,23 +249,24 @@ namespace
|
||||||
|
|
||||||
TEST_F(TechniqueTest, fail_with_missing_source_for_sampler)
|
TEST_F(TechniqueTest, fail_with_missing_source_for_sampler)
|
||||||
{
|
{
|
||||||
internal::CaptureStdout();
|
expectFailure("missing_sampler_source", "sampler_1d 'mysampler1d' requires a filename");
|
||||||
|
|
||||||
compile("missing_sampler_source");
|
|
||||||
|
|
||||||
std::string output = internal::GetCapturedStdout();
|
|
||||||
Log(Debug::Error) << output;
|
|
||||||
EXPECT_THAT(output, HasSubstr("sampler_1d 'mysampler1d' requires a filename"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TechniqueTest, fail_with_repeated_shared_block)
|
TEST_F(TechniqueTest, fail_with_repeated_shared_block)
|
||||||
{
|
{
|
||||||
internal::CaptureStdout();
|
expectFailure("repeated_shared_block", "repeated 'shared' block");
|
||||||
|
}
|
||||||
|
|
||||||
compile("repeated_shared_block");
|
TEST_F(TechniqueTest, fail_with_invalid_float)
|
||||||
|
{
|
||||||
|
expectFailure("invalid_number_inf", "expected float value");
|
||||||
|
expectFailure("invalid_number_negative_inf", "expected float value");
|
||||||
|
expectFailure("invalid_number_hex", "expected float value");
|
||||||
|
}
|
||||||
|
|
||||||
std::string output = internal::GetCapturedStdout();
|
TEST_F(TechniqueTest, fail_with_out_of_range)
|
||||||
Log(Debug::Error) << output;
|
{
|
||||||
EXPECT_THAT(output, HasSubstr("repeated 'shared' block"));
|
expectFailure("invalid_number_ulong", "number out of range");
|
||||||
|
expectFailure("invalid_number_double", "number out of range");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "MyGUI_LanguageManager.h"
|
#include "MyGUI_LanguageManager.h"
|
||||||
|
|
||||||
#include <components/lua/util.hpp>
|
#include <components/lua/util.hpp>
|
||||||
|
#include <components/misc/strings/format.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
#include "lexer.hpp"
|
#include "lexer.hpp"
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <optional>
|
#include <format>
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
#include <components/misc/strings/format.hpp>
|
#include <components/misc/strings/algorithm.hpp>
|
||||||
|
|
||||||
namespace Fx
|
namespace Fx
|
||||||
{
|
{
|
||||||
|
@ -124,9 +123,9 @@ namespace Fx
|
||||||
return mLastJumpBlock;
|
return mLastJumpBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void Lexer::error(const std::string& msg)
|
[[noreturn]] void Lexer::error(std::string_view msg)
|
||||||
{
|
{
|
||||||
throw LexerException(Misc::StringUtils::format("Line %zu Col %zu. %s", mLine + 1, mColumn, msg));
|
throw LexerException(std::format("Line {} Col {}. {}", mLine + 1, mColumn, msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lexer::advance()
|
void Lexer::advance()
|
||||||
|
@ -136,7 +135,7 @@ namespace Fx
|
||||||
mColumn++;
|
mColumn++;
|
||||||
}
|
}
|
||||||
|
|
||||||
char Lexer::head()
|
unsigned char Lexer::head()
|
||||||
{
|
{
|
||||||
return *mHead;
|
return *mHead;
|
||||||
}
|
}
|
||||||
|
@ -209,7 +208,7 @@ namespace Fx
|
||||||
advance();
|
advance();
|
||||||
return { Comma{} };
|
return { Comma{} };
|
||||||
default:
|
default:
|
||||||
error(Misc::StringUtils::format("unexpected token <%c>", head()));
|
error(std::format("unexpected token <{:c}>", head()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,23 +292,42 @@ namespace Fx
|
||||||
Token Lexer::scanNumber()
|
Token Lexer::scanNumber()
|
||||||
{
|
{
|
||||||
double buffer;
|
double buffer;
|
||||||
|
char* endPtr = nullptr;
|
||||||
char* endPtr;
|
|
||||||
buffer = std::strtod(mHead, &endPtr);
|
buffer = std::strtod(mHead, &endPtr);
|
||||||
|
if (endPtr == nullptr || endPtr == mHead)
|
||||||
if (endPtr == nullptr)
|
|
||||||
error("critical error while parsing number");
|
error("critical error while parsing number");
|
||||||
|
|
||||||
const char* tmp = mHead;
|
bool isDefinitelyAFloat = false;
|
||||||
mHead = endPtr;
|
// GLSL allows floats to end on f/F
|
||||||
|
if (endPtr != mTail && Misc::StringUtils::toLower(*endPtr) == 'f')
|
||||||
for (; tmp != endPtr; ++tmp)
|
|
||||||
{
|
{
|
||||||
if ((*tmp == '.'))
|
isDefinitelyAFloat = true;
|
||||||
return Float{ static_cast<float>(buffer) };
|
++endPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Integer{ static_cast<int>(buffer) };
|
std::string_view literal(mHead, endPtr);
|
||||||
|
mHead = endPtr;
|
||||||
|
|
||||||
|
// Disallow -inf, -nan, and values that cannot be represented as doubles
|
||||||
|
if (!std::isfinite(buffer))
|
||||||
|
return Literal{ literal };
|
||||||
|
// Disallow hex notation (not allowed in GLSL so confusing to partially allow)
|
||||||
|
if (Misc::StringUtils::ciStartsWith(literal, "0x") || Misc::StringUtils::ciStartsWith(literal, "-0x"))
|
||||||
|
return Literal{ literal };
|
||||||
|
|
||||||
|
constexpr std::string_view floatCharacters = ".eE";
|
||||||
|
if (!isDefinitelyAFloat && literal.find_first_of(floatCharacters) == std::string_view::npos)
|
||||||
|
{
|
||||||
|
// This is supposed to be an int, but that doesn't mean it can fit in one
|
||||||
|
int intValue = static_cast<int>(buffer);
|
||||||
|
if (intValue != buffer)
|
||||||
|
error("number out of range");
|
||||||
|
return Integer{ intValue };
|
||||||
|
}
|
||||||
|
float floatValue = static_cast<float>(buffer);
|
||||||
|
if (!std::isfinite(floatValue))
|
||||||
|
error("number out of range");
|
||||||
|
return Float{ floatValue };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,12 +46,12 @@ namespace Fx
|
||||||
|
|
||||||
Block getLastJumpBlock() const;
|
Block getLastJumpBlock() const;
|
||||||
|
|
||||||
[[noreturn]] void error(const std::string& msg);
|
[[noreturn]] void error(std::string_view msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void drop();
|
void drop();
|
||||||
void advance();
|
void advance();
|
||||||
char head();
|
unsigned char head();
|
||||||
bool peekChar(char c);
|
bool peekChar(char c);
|
||||||
|
|
||||||
Token scanToken();
|
Token scanToken();
|
||||||
|
|
|
@ -300,7 +300,7 @@ float omw_EstimateFogCoverageFromUV(vec2 uv)
|
||||||
header.replace(pos, define.size(), value);
|
header.replace(pos, define.size(), value);
|
||||||
|
|
||||||
for (const auto& target : mRenderTargets)
|
for (const auto& target : mRenderTargets)
|
||||||
header.append("uniform sampler2D " + std::string(target) + ";");
|
header.append("uniform sampler2D " + target + ";");
|
||||||
|
|
||||||
for (auto& uniform : technique.getUniformMap())
|
for (auto& uniform : technique.getUniformMap())
|
||||||
if (auto glsl = uniform->getGLSL())
|
if (auto glsl = uniform->getGLSL())
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "technique.hpp"
|
#include "technique.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <format>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
@ -91,16 +92,13 @@ namespace Fx
|
||||||
std::string Technique::getBlockWithLineDirective()
|
std::string Technique::getBlockWithLineDirective()
|
||||||
{
|
{
|
||||||
auto block = mLexer->getLastJumpBlock();
|
auto block = mLexer->getLastJumpBlock();
|
||||||
std::string content = std::string(block.content);
|
return std::format("\n#line {}\n{}\n", block.line + 1, block.content);
|
||||||
|
|
||||||
content = "\n#line " + std::to_string(block.line + 1) + "\n" + std::string(block.content) + "\n";
|
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Technique::UniformMap::iterator Technique::findUniform(const std::string& name)
|
Technique::UniformMap::iterator Technique::findUniform(std::string_view name)
|
||||||
{
|
{
|
||||||
return std::find_if(mDefinedUniforms.begin(), mDefinedUniforms.end(),
|
return std::find_if(mDefinedUniforms.begin(), mDefinedUniforms.end(),
|
||||||
[&name](const auto& uniform) { return uniform->mName == name; });
|
[name](const auto& uniform) { return uniform->mName == name; });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Technique::compile()
|
bool Technique::compile()
|
||||||
|
@ -140,9 +138,9 @@ namespace Fx
|
||||||
|
|
||||||
if (it == mPassMap.end())
|
if (it == mPassMap.end())
|
||||||
error(
|
error(
|
||||||
Misc::StringUtils::format("pass '%s' was found in the pass list, but there was no matching "
|
std::format("pass '{}' was found in the pass list, but there was no matching 'fragment', "
|
||||||
"'fragment', 'vertex' or 'compute' block",
|
"'vertex' or 'compute' block",
|
||||||
std::string(name)));
|
name));
|
||||||
|
|
||||||
if (mLastAppliedType != Pass::Type::None && mLastAppliedType != it->second->mType)
|
if (mLastAppliedType != Pass::Type::None && mLastAppliedType != it->second->mType)
|
||||||
{
|
{
|
||||||
|
@ -167,7 +165,7 @@ namespace Fx
|
||||||
{
|
{
|
||||||
auto rtIt = mRenderTargets.find(it->second->mTarget);
|
auto rtIt = mRenderTargets.find(it->second->mTarget);
|
||||||
if (rtIt == mRenderTargets.end())
|
if (rtIt == mRenderTargets.end())
|
||||||
error(Misc::StringUtils::format("target '%s' not defined", std::string(it->second->mTarget)));
|
error(std::format("target '{}' not defined", it->second->mTarget));
|
||||||
}
|
}
|
||||||
|
|
||||||
mPasses.emplace_back(it->second);
|
mPasses.emplace_back(it->second);
|
||||||
|
@ -203,7 +201,7 @@ namespace Fx
|
||||||
return isDirty;
|
return isDirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void Technique::error(const std::string& msg)
|
[[noreturn]] void Technique::error(std::string_view msg)
|
||||||
{
|
{
|
||||||
mLexer->error(msg);
|
mLexer->error(msg);
|
||||||
}
|
}
|
||||||
|
@ -212,7 +210,7 @@ namespace Fx
|
||||||
void Technique::parseBlockImp<Lexer::Shared>()
|
void Technique::parseBlockImp<Lexer::Shared>()
|
||||||
{
|
{
|
||||||
if (!mLexer->jump())
|
if (!mLexer->jump())
|
||||||
error(Misc::StringUtils::format("unterminated 'shared' block, expected closing brackets"));
|
error("unterminated 'shared' block, expected closing brackets");
|
||||||
|
|
||||||
if (!mShared.empty())
|
if (!mShared.empty())
|
||||||
error("repeated 'shared' block, only one allowed per technique file");
|
error("repeated 'shared' block, only one allowed per technique file");
|
||||||
|
@ -255,7 +253,7 @@ namespace Fx
|
||||||
else if (key == "glsl_profile")
|
else if (key == "glsl_profile")
|
||||||
{
|
{
|
||||||
expect<Lexer::String>();
|
expect<Lexer::String>();
|
||||||
mGLSLProfile = std::string(std::get<Lexer::String>(mToken).value);
|
mGLSLProfile = std::get<Lexer::String>(mToken).value;
|
||||||
}
|
}
|
||||||
else if (key == "glsl_extensions")
|
else if (key == "glsl_extensions")
|
||||||
{
|
{
|
||||||
|
@ -265,7 +263,7 @@ namespace Fx
|
||||||
else if (key == "dynamic")
|
else if (key == "dynamic")
|
||||||
mDynamic = parseBool();
|
mDynamic = parseBool();
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("unexpected key '%s'", std::string{ key }));
|
error(std::format("unexpected key '{}'", key));
|
||||||
|
|
||||||
expect<Lexer::SemiColon>();
|
expect<Lexer::SemiColon>();
|
||||||
}
|
}
|
||||||
|
@ -278,7 +276,7 @@ namespace Fx
|
||||||
void Technique::parseBlockImp<Lexer::Render_Target>()
|
void Technique::parseBlockImp<Lexer::Render_Target>()
|
||||||
{
|
{
|
||||||
if (mRenderTargets.count(mBlockName))
|
if (mRenderTargets.count(mBlockName))
|
||||||
error(Misc::StringUtils::format("redeclaration of render target '%s'", std::string(mBlockName)));
|
error(std::format("redeclaration of render target '{}'", mBlockName));
|
||||||
|
|
||||||
Fx::Types::RenderTarget rt;
|
Fx::Types::RenderTarget rt;
|
||||||
rt.mTarget->setTextureSize(mWidth, mHeight);
|
rt.mTarget->setTextureSize(mWidth, mHeight);
|
||||||
|
@ -324,7 +322,7 @@ namespace Fx
|
||||||
else if (key == "clear_color")
|
else if (key == "clear_color")
|
||||||
rt.mClearColor = parseVec<osg::Vec4f, Lexer::Vec4>();
|
rt.mClearColor = parseVec<osg::Vec4f, Lexer::Vec4>();
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("unexpected key '%s'", std::string(key)));
|
error(std::format("unexpected key '{}'", key));
|
||||||
|
|
||||||
expect<Lexer::SemiColon>();
|
expect<Lexer::SemiColon>();
|
||||||
}
|
}
|
||||||
|
@ -336,7 +334,7 @@ namespace Fx
|
||||||
void Technique::parseBlockImp<Lexer::Vertex>()
|
void Technique::parseBlockImp<Lexer::Vertex>()
|
||||||
{
|
{
|
||||||
if (!mLexer->jump())
|
if (!mLexer->jump())
|
||||||
error(Misc::StringUtils::format("unterminated 'vertex' block, expected closing brackets"));
|
error("unterminated 'vertex' block, expected closing brackets");
|
||||||
|
|
||||||
auto& pass = mPassMap[mBlockName];
|
auto& pass = mPassMap[mBlockName];
|
||||||
|
|
||||||
|
@ -346,11 +344,11 @@ namespace Fx
|
||||||
pass->mName = mBlockName;
|
pass->mName = mBlockName;
|
||||||
|
|
||||||
if (pass->mCompute)
|
if (pass->mCompute)
|
||||||
error(Misc::StringUtils::format("'compute' block already defined. Usage is ambiguous."));
|
error("'compute' block already defined. Usage is ambiguous.");
|
||||||
else if (!pass->mVertex)
|
else if (!pass->mVertex)
|
||||||
pass->mVertex = new osg::Shader(osg::Shader::VERTEX, getBlockWithLineDirective());
|
pass->mVertex = new osg::Shader(osg::Shader::VERTEX, getBlockWithLineDirective());
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("duplicate vertex shader for block '%s'", std::string(mBlockName)));
|
error(std::format("duplicate vertex shader for block '{}'", mBlockName));
|
||||||
|
|
||||||
pass->mType = Pass::Type::Pixel;
|
pass->mType = Pass::Type::Pixel;
|
||||||
}
|
}
|
||||||
|
@ -359,7 +357,7 @@ namespace Fx
|
||||||
void Technique::parseBlockImp<Lexer::Fragment>()
|
void Technique::parseBlockImp<Lexer::Fragment>()
|
||||||
{
|
{
|
||||||
if (!mLexer->jump())
|
if (!mLexer->jump())
|
||||||
error(Misc::StringUtils::format("unterminated 'fragment' block, expected closing brackets"));
|
error("unterminated 'fragment' block, expected closing brackets");
|
||||||
|
|
||||||
auto& pass = mPassMap[mBlockName];
|
auto& pass = mPassMap[mBlockName];
|
||||||
|
|
||||||
|
@ -370,11 +368,11 @@ namespace Fx
|
||||||
pass->mName = mBlockName;
|
pass->mName = mBlockName;
|
||||||
|
|
||||||
if (pass->mCompute)
|
if (pass->mCompute)
|
||||||
error(Misc::StringUtils::format("'compute' block already defined. Usage is ambiguous."));
|
error("'compute' block already defined. Usage is ambiguous.");
|
||||||
else if (!pass->mFragment)
|
else if (!pass->mFragment)
|
||||||
pass->mFragment = new osg::Shader(osg::Shader::FRAGMENT, getBlockWithLineDirective());
|
pass->mFragment = new osg::Shader(osg::Shader::FRAGMENT, getBlockWithLineDirective());
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("duplicate vertex shader for block '%s'", std::string(mBlockName)));
|
error(std::format("duplicate fragment shader for block '{}'", mBlockName));
|
||||||
|
|
||||||
pass->mType = Pass::Type::Pixel;
|
pass->mType = Pass::Type::Pixel;
|
||||||
}
|
}
|
||||||
|
@ -383,7 +381,7 @@ namespace Fx
|
||||||
void Technique::parseBlockImp<Lexer::Compute>()
|
void Technique::parseBlockImp<Lexer::Compute>()
|
||||||
{
|
{
|
||||||
if (!mLexer->jump())
|
if (!mLexer->jump())
|
||||||
error(Misc::StringUtils::format("unterminated 'compute' block, expected closing brackets"));
|
error("unterminated 'compute' block, expected closing brackets");
|
||||||
|
|
||||||
auto& pass = mPassMap[mBlockName];
|
auto& pass = mPassMap[mBlockName];
|
||||||
|
|
||||||
|
@ -393,13 +391,13 @@ namespace Fx
|
||||||
pass->mName = mBlockName;
|
pass->mName = mBlockName;
|
||||||
|
|
||||||
if (pass->mFragment)
|
if (pass->mFragment)
|
||||||
error(Misc::StringUtils::format("'fragment' block already defined. Usage is ambiguous."));
|
error("'fragment' block already defined. Usage is ambiguous.");
|
||||||
else if (pass->mVertex)
|
else if (pass->mVertex)
|
||||||
error(Misc::StringUtils::format("'vertex' block already defined. Usage is ambiguous."));
|
error("'vertex' block already defined. Usage is ambiguous.");
|
||||||
else if (!pass->mFragment)
|
else if (!pass->mFragment)
|
||||||
pass->mCompute = new osg::Shader(osg::Shader::COMPUTE, getBlockWithLineDirective());
|
pass->mCompute = new osg::Shader(osg::Shader::COMPUTE, getBlockWithLineDirective());
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("duplicate vertex shader for block '%s'", std::string(mBlockName)));
|
error(std::format("duplicate compute shader for block '{}'", mBlockName));
|
||||||
|
|
||||||
pass->mType = Pass::Type::Compute;
|
pass->mType = Pass::Type::Compute;
|
||||||
}
|
}
|
||||||
|
@ -407,8 +405,8 @@ namespace Fx
|
||||||
template <class T>
|
template <class T>
|
||||||
void Technique::parseSampler()
|
void Technique::parseSampler()
|
||||||
{
|
{
|
||||||
if (findUniform(std::string(mBlockName)) != mDefinedUniforms.end())
|
if (findUniform(mBlockName) != mDefinedUniforms.end())
|
||||||
error(Misc::StringUtils::format("redeclaration of uniform '%s'", std::string(mBlockName)));
|
error(std::format("redeclaration of uniform '{}'", mBlockName));
|
||||||
|
|
||||||
ProxyTextureData proxy;
|
ProxyTextureData proxy;
|
||||||
osg::ref_ptr<osg::Texture> sampler;
|
osg::ref_ptr<osg::Texture> sampler;
|
||||||
|
@ -466,13 +464,12 @@ namespace Fx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("unexpected key '%s'", std::string{ key }));
|
error(std::format("unexpected key '{}'", key));
|
||||||
|
|
||||||
expect<Lexer::SemiColon>();
|
expect<Lexer::SemiColon>();
|
||||||
}
|
}
|
||||||
if (!sampler)
|
if (!sampler)
|
||||||
error(Misc::StringUtils::format(
|
error(std::format("{} '{}' requires a filename", T::repr, mBlockName));
|
||||||
"%s '%s' requires a filename", std::string(T::repr), std::string{ mBlockName }));
|
|
||||||
|
|
||||||
if (!is1D)
|
if (!is1D)
|
||||||
{
|
{
|
||||||
|
@ -497,7 +494,7 @@ namespace Fx
|
||||||
|
|
||||||
std::shared_ptr<Types::UniformBase> uniform = std::make_shared<Types::UniformBase>();
|
std::shared_ptr<Types::UniformBase> uniform = std::make_shared<Types::UniformBase>();
|
||||||
uniform->mSamplerType = type;
|
uniform->mSamplerType = type;
|
||||||
uniform->mName = std::string(mBlockName);
|
uniform->mName = mBlockName;
|
||||||
mDefinedUniforms.emplace_back(std::move(uniform));
|
mDefinedUniforms.emplace_back(std::move(uniform));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,8 +530,8 @@ namespace Fx
|
||||||
template <class SrcT, class T>
|
template <class SrcT, class T>
|
||||||
void Technique::parseUniform()
|
void Technique::parseUniform()
|
||||||
{
|
{
|
||||||
if (findUniform(std::string(mBlockName)) != mDefinedUniforms.end())
|
if (findUniform(mBlockName) != mDefinedUniforms.end())
|
||||||
error(Misc::StringUtils::format("redeclaration of uniform '%s'", std::string(mBlockName)));
|
error(std::format("redeclaration of uniform '{}'", 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>();
|
Types::Uniform<SrcT> data = Types::Uniform<SrcT>();
|
||||||
|
@ -591,7 +588,7 @@ namespace Fx
|
||||||
parseWidgetType<SrcT, T>(data);
|
parseWidgetType<SrcT, T>(data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("unexpected key '%s'", std::string{ key }));
|
error(std::format("unexpected key '{}'", key));
|
||||||
|
|
||||||
expect<Lexer::SemiColon>();
|
expect<Lexer::SemiColon>();
|
||||||
}
|
}
|
||||||
|
@ -599,7 +596,7 @@ namespace Fx
|
||||||
if (data.isArray())
|
if (data.isArray())
|
||||||
uniform->mStatic = false;
|
uniform->mStatic = false;
|
||||||
|
|
||||||
uniform->mName = std::string(mBlockName);
|
uniform->mName = mBlockName;
|
||||||
uniform->mData = data;
|
uniform->mData = data;
|
||||||
uniform->mTechniqueName = mName;
|
uniform->mTechniqueName = mName;
|
||||||
|
|
||||||
|
@ -674,29 +671,28 @@ namespace Fx
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void Technique::expect(const std::string& err)
|
void Technique::expect(std::string_view err)
|
||||||
{
|
{
|
||||||
mToken = mLexer->next();
|
mToken = mLexer->next();
|
||||||
if (!std::holds_alternative<T>(mToken))
|
if (!std::holds_alternative<T>(mToken))
|
||||||
{
|
{
|
||||||
if (err.empty())
|
if (err.empty())
|
||||||
error(Misc::StringUtils::format("Expected %s", std::string(T::repr)));
|
error(std::format("Expected {}", T::repr));
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("%s. Expected %s", err, std::string(T::repr)));
|
error(std::format("{}. Expected {}", err, T::repr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class T2>
|
template <class T, class T2>
|
||||||
void Technique::expect(const std::string& err)
|
void Technique::expect(std::string_view err)
|
||||||
{
|
{
|
||||||
mToken = mLexer->next();
|
mToken = mLexer->next();
|
||||||
if (!std::holds_alternative<T>(mToken) && !std::holds_alternative<T2>(mToken))
|
if (!std::holds_alternative<T>(mToken) && !std::holds_alternative<T2>(mToken))
|
||||||
{
|
{
|
||||||
if (err.empty())
|
if (err.empty())
|
||||||
error(Misc::StringUtils::format(
|
error(std::format("Expected {} or {}", T::repr, T2::repr));
|
||||||
"%s. Expected %s or %s", err, std::string(T::repr), std::string(T2::repr)));
|
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("Expected %s or %s", std::string(T::repr), std::string(T2::repr)));
|
error(std::format("{}. Expected {} or {}", err, T::repr, T2::repr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,7 +758,7 @@ namespace Fx
|
||||||
|
|
||||||
if (named)
|
if (named)
|
||||||
{
|
{
|
||||||
expect<Lexer::Literal>("name is required for preceeding block decleration");
|
expect<Lexer::Literal>("name is required for preceeding block declaration");
|
||||||
|
|
||||||
mBlockName = std::get<Lexer::Literal>(mToken).value;
|
mBlockName = std::get<Lexer::Literal>(mToken).value;
|
||||||
|
|
||||||
|
@ -856,14 +852,14 @@ namespace Fx
|
||||||
pass->mBlendEq = blendEq;
|
pass->mBlendEq = blendEq;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
error(Misc::StringUtils::format("unrecognized key '%s' in block header", std::string(key)));
|
error(std::format("unrecognized key '{}' in block header", key));
|
||||||
|
|
||||||
mToken = mLexer->next();
|
mToken = mLexer->next();
|
||||||
|
|
||||||
if (std::holds_alternative<Lexer::Comma>(mToken))
|
if (std::holds_alternative<Lexer::Comma>(mToken))
|
||||||
{
|
{
|
||||||
if (std::holds_alternative<Lexer::Close_Parenthesis>(mLexer->peek()))
|
if (std::holds_alternative<Lexer::Close_Parenthesis>(mLexer->peek()))
|
||||||
error(Misc::StringUtils::format("leading comma in '%s' is not allowed", std::string(mBlockName)));
|
error(std::format("leading comma in '{}' is not allowed", mBlockName));
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -888,7 +884,7 @@ namespace Fx
|
||||||
if (Misc::StringUtils::ciEqual(term, identifer))
|
if (Misc::StringUtils::ciEqual(term, identifer))
|
||||||
return bit;
|
return bit;
|
||||||
}
|
}
|
||||||
error(Misc::StringUtils::format("unrecognized flag '%s'", std::string(term)));
|
error(std::format("unrecognized flag '{}'", term));
|
||||||
};
|
};
|
||||||
|
|
||||||
FlagsType flag = 0;
|
FlagsType flag = 0;
|
||||||
|
@ -908,7 +904,7 @@ namespace Fx
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
error(Misc::StringUtils::format("unrecognized filter mode '%s'", std::string{ asLiteral() }));
|
error(std::format("unrecognized filter mode '{}'", asLiteral()));
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Texture::WrapMode Technique::parseWrapMode()
|
osg::Texture::WrapMode Technique::parseWrapMode()
|
||||||
|
@ -926,7 +922,7 @@ namespace Fx
|
||||||
"unsupported wrap mode 'clamp'; 'clamp_to_edge' was likely intended, look for an updated shader or "
|
"unsupported wrap mode 'clamp'; 'clamp_to_edge' was likely intended, look for an updated shader or "
|
||||||
"contact author");
|
"contact author");
|
||||||
|
|
||||||
error(Misc::StringUtils::format("unrecognized wrap mode '%s'", std::string{ asLiteral() }));
|
error(std::format("unrecognized wrap mode '{}'", asLiteral()));
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Texture::InternalFormatMode Technique::parseCompression()
|
osg::Texture::InternalFormatMode Technique::parseCompression()
|
||||||
|
@ -939,7 +935,7 @@ namespace Fx
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
error(Misc::StringUtils::format("unrecognized compression '%s'", std::string{ asLiteral() }));
|
error(std::format("unrecognized compression '{}'", asLiteral()));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Technique::parseInternalFormat()
|
int Technique::parseInternalFormat()
|
||||||
|
@ -952,7 +948,7 @@ namespace Fx
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
error(Misc::StringUtils::format("unrecognized internal format '%s'", std::string{ asLiteral() }));
|
error(std::format("unrecognized internal format '{}'", asLiteral()));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Technique::parseSourceType()
|
int Technique::parseSourceType()
|
||||||
|
@ -965,7 +961,7 @@ namespace Fx
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
error(Misc::StringUtils::format("unrecognized source type '%s'", std::string{ asLiteral() }));
|
error(std::format("unrecognized source type '{}'", asLiteral()));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Technique::parseSourceFormat()
|
int Technique::parseSourceFormat()
|
||||||
|
@ -978,7 +974,7 @@ namespace Fx
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
error(Misc::StringUtils::format("unrecognized source format '%s'", std::string{ asLiteral() }));
|
error(std::format("unrecognized source format '{}'", asLiteral()));
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::BlendEquation::Equation Technique::parseBlendEquation()
|
osg::BlendEquation::Equation Technique::parseBlendEquation()
|
||||||
|
@ -991,7 +987,7 @@ namespace Fx
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
error(Misc::StringUtils::format("unrecognized blend equation '%s'", std::string{ asLiteral() }));
|
error(std::format("unrecognized blend equation '{}'", asLiteral()));
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::BlendFunc::BlendFuncMode Technique::parseBlendFuncMode()
|
osg::BlendFunc::BlendFuncMode Technique::parseBlendFuncMode()
|
||||||
|
@ -1004,7 +1000,7 @@ namespace Fx
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
error(Misc::StringUtils::format("unrecognized blend function '%s'", std::string{ asLiteral() }));
|
error(std::format("unrecognized blend function '{}'", asLiteral()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class SrcT, class T>
|
template <class SrcT, class T>
|
||||||
|
@ -1057,7 +1053,7 @@ namespace Fx
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error(Misc::StringUtils::format("unrecognized widget type '%s'", std::string{ asLiteral() }));
|
error(std::format("unrecognized widget type '{}'", asLiteral()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -172,7 +172,7 @@ namespace Fx
|
||||||
|
|
||||||
std::string getLastError() const { return mLastError; }
|
std::string getLastError() const { return mLastError; }
|
||||||
|
|
||||||
UniformMap::iterator findUniform(const std::string& name);
|
UniformMap::iterator findUniform(std::string_view name);
|
||||||
|
|
||||||
bool getDynamic() const { return mDynamic; }
|
bool getDynamic() const { return mDynamic; }
|
||||||
|
|
||||||
|
@ -183,17 +183,17 @@ namespace Fx
|
||||||
bool getInternal() const { return mInternal; }
|
bool getInternal() const { return mInternal; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[noreturn]] void error(const std::string& msg);
|
[[noreturn]] void error(std::string_view msg);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
std::string_view asLiteral() const;
|
std::string_view asLiteral() const;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void expect(const std::string& err = "");
|
void expect(std::string_view err = {});
|
||||||
|
|
||||||
template <class T, class T2>
|
template <class T, class T2>
|
||||||
void expect(const std::string& err = "");
|
void expect(std::string_view err = {});
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
bool isNext();
|
bool isNext();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef OPENMW_COMPONENTS_FX_TYPES_HPP
|
#ifndef OPENMW_COMPONENTS_FX_TYPES_HPP
|
||||||
#define OPENMW_COMPONENTS_FX_TYPES_HPP
|
#define OPENMW_COMPONENTS_FX_TYPES_HPP
|
||||||
|
|
||||||
|
#include <format>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
@ -8,7 +9,6 @@
|
||||||
#include <osg/Uniform>
|
#include <osg/Uniform>
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/misc/strings/format.hpp>
|
|
||||||
#include <components/sceneutil/depth.hpp>
|
#include <components/sceneutil/depth.hpp>
|
||||||
#include <components/settings/shadermanager.hpp>
|
#include <components/settings/shadermanager.hpp>
|
||||||
|
|
||||||
|
@ -112,12 +112,7 @@ namespace Fx
|
||||||
|
|
||||||
size_t getNumElements() const
|
size_t getNumElements() const
|
||||||
{
|
{
|
||||||
return std::visit(
|
return std::visit([](auto&& arg) { return arg.isArray() ? arg.getArray().size() : 1; }, mData);
|
||||||
[&](auto&& arg) {
|
|
||||||
;
|
|
||||||
return arg.isArray() ? arg.getArray().size() : 1;
|
|
||||||
},
|
|
||||||
mData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -236,11 +231,11 @@ namespace Fx
|
||||||
switch (mSamplerType.value())
|
switch (mSamplerType.value())
|
||||||
{
|
{
|
||||||
case Texture_1D:
|
case Texture_1D:
|
||||||
return Misc::StringUtils::format("uniform sampler1D %s;", mName);
|
return std::format("uniform sampler1D {};", mName);
|
||||||
case Texture_2D:
|
case Texture_2D:
|
||||||
return Misc::StringUtils::format("uniform sampler2D %s;", mName);
|
return std::format("uniform sampler2D {};", mName);
|
||||||
case Texture_3D:
|
case Texture_3D:
|
||||||
return Misc::StringUtils::format("uniform sampler3D %s;", mName);
|
return std::format("uniform sampler3D {};", mName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,54 +248,53 @@ namespace Fx
|
||||||
const bool useUniform = arg.isArray()
|
const bool useUniform = arg.isArray()
|
||||||
|| (Settings::ShaderManager::get().getMode() == Settings::ShaderManager::Mode::Debug
|
|| (Settings::ShaderManager::get().getMode() == Settings::ShaderManager::Mode::Debug
|
||||||
|| mStatic == false);
|
|| mStatic == false);
|
||||||
const std::string uname = arg.isArray()
|
const std::string uname
|
||||||
? Misc::StringUtils::format("%s[%zu]", mName, arg.getArray().size())
|
= arg.isArray() ? std::format("{}[{}]", mName, arg.getArray().size()) : mName;
|
||||||
: 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;", uname);
|
return std::format("uniform vec2 {};", uname);
|
||||||
|
|
||||||
return Misc::StringUtils::format("const vec2 %s=vec2(%f,%f);", mName, value[0], value[1]);
|
return std::format("const vec2 {}=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;", uname);
|
return std::format("uniform vec3 {};", uname);
|
||||||
|
|
||||||
return Misc::StringUtils::format(
|
return std::format(
|
||||||
"const vec3 %s=vec3(%f,%f,%f);", mName, value[0], value[1], value[2]);
|
"const vec3 {}=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;", uname);
|
return std::format("uniform vec4 {};", uname);
|
||||||
|
|
||||||
return Misc::StringUtils::format(
|
return std::format("const vec4 {}=vec4({:f},{:f},{:f},{:f});", mName, value[0], value[1],
|
||||||
"const vec4 %s=vec4(%f,%f,%f,%f);", mName, value[0], value[1], value[2], value[3]);
|
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;", uname);
|
return std::format("uniform float {};", uname);
|
||||||
|
|
||||||
return Misc::StringUtils::format("const float %s=%f;", mName, value);
|
return std::format("const float {}={: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;", uname);
|
return std::format("uniform int {};", uname);
|
||||||
|
|
||||||
return Misc::StringUtils::format("const int %s=%i;", mName, value);
|
return std::format("const int {}={};", mName, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static_assert(std::is_same_v<T, bool>, "Non-exhaustive visitor");
|
static_assert(std::is_same_v<T, bool>, "Non-exhaustive visitor");
|
||||||
if (useUniform)
|
if (useUniform)
|
||||||
return Misc::StringUtils::format("uniform bool %s;", uname);
|
return std::format("uniform bool {};", uname);
|
||||||
|
|
||||||
return Misc::StringUtils::format("const bool %s=%s;", mName, value ? "true" : "false");
|
return std::format("const bool {}={};", mName, value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mData);
|
mData);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <MyGUI_Widget.h>
|
#include <MyGUI_Widget.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <format>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -18,8 +19,6 @@
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
#include <osg/Vec4f>
|
#include <osg/Vec4f>
|
||||||
|
|
||||||
#include <components/misc/strings/format.hpp>
|
|
||||||
|
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
|
|
||||||
namespace Gui
|
namespace Gui
|
||||||
|
@ -88,7 +87,7 @@ namespace Fx
|
||||||
{
|
{
|
||||||
mValue = value;
|
mValue = value;
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (std::is_floating_point_v<T>)
|
||||||
mValueLabel->setCaption(Misc::StringUtils::format("%.3f", mValue));
|
mValueLabel->setCaption(std::format("{:.3f}", mValue));
|
||||||
else
|
else
|
||||||
mValueLabel->setCaption(std::to_string(mValue));
|
mValueLabel->setCaption(std::to_string(mValue));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue