Core: Add generic ParameterConfig
This still needs to be improved
This commit is contained in:
parent
86e26008b3
commit
f0fd3b232c
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_CORE_PARAMETERFILE_HPP
|
||||
#define NAZARA_CORE_PARAMETERFILE_HPP
|
||||
|
||||
#include <NazaraUtils/Prerequisites.hpp>
|
||||
#include <Nazara/Core/Config.hpp>
|
||||
#include <NazaraUtils/FixedVector.hpp>
|
||||
#include <NazaraUtils/FunctionRef.hpp>
|
||||
#include <NazaraUtils/FunctionTraits.hpp>
|
||||
#include <NazaraUtils/TypeList.hpp>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class Stream;
|
||||
|
||||
class NAZARA_CORE_API ParameterFile
|
||||
{
|
||||
public:
|
||||
inline ParameterFile(Stream& stream);
|
||||
ParameterFile(const ParameterFile&) = delete;
|
||||
ParameterFile(ParameterFile&&) = delete;
|
||||
~ParameterFile() = default;
|
||||
|
||||
template<typename... Args> void Block(Args&&... args);
|
||||
template<typename... Args> void Handle(Args&&... args);
|
||||
|
||||
ParameterFile& operator=(const ParameterFile&) = delete;
|
||||
ParameterFile& operator=(ParameterFile&&) = delete;
|
||||
|
||||
struct Keyword
|
||||
{
|
||||
std::string str;
|
||||
};
|
||||
|
||||
struct Array_t {};
|
||||
struct OptionalBlock_t {};
|
||||
|
||||
static constexpr Array_t Array{};
|
||||
static constexpr OptionalBlock_t OptionalBlock{};
|
||||
|
||||
private:
|
||||
using ValueHandler = std::function<void(ParameterFile& file)>;
|
||||
|
||||
struct KeyValue
|
||||
{
|
||||
std::string_view key;
|
||||
ValueHandler handler;
|
||||
};
|
||||
|
||||
template<typename T> static std::string_view BuildBlockKey(T&& key);
|
||||
template<typename... Args> static ValueHandler BuildBlockHandler(ParameterFile& file, ValueHandler handler);
|
||||
template<typename T> static ValueHandler BuildBlockHandler(ParameterFile& file, T* value);
|
||||
template<typename T> static ValueHandler BuildBlockHandler(ParameterFile& file, T&& handler, std::enable_if_t<IsFunctor_v<T>>* = nullptr);
|
||||
template<typename... Args> static ValueHandler BuildBlockHandler(ParameterFile& file, FunctionRef<void(Args...)> handler);
|
||||
|
||||
template<std::size_t N, typename K, typename V, typename... Rest> static void BuildKeyValues(ParameterFile& file, FixedVector<KeyValue, N>& keyValues, K&& key, V&& value, Rest&&... rest);
|
||||
template<typename V, typename... Rest> static ValueHandler GetSingleHandler(ParameterFile& file, V&& value, Rest&&... rest);
|
||||
|
||||
template<typename... Args> void HandleInner(std::string_view listEnd, Args&&... args);
|
||||
|
||||
template<typename T> static T ReadValue(ParameterFile& file);
|
||||
|
||||
template<typename T> static constexpr bool ShouldIgnoreImpl = std::is_same_v<T, Array_t> || std::is_same_v<T, OptionalBlock_t>;
|
||||
template<typename T> static constexpr bool ShouldIgnore = ShouldIgnoreImpl<std::decay_t<std::remove_const_t<T>>>;
|
||||
|
||||
bool EnsureLine(bool peek = false);
|
||||
std::string ReadKeyword(bool peek = false);
|
||||
std::string ReadString();
|
||||
|
||||
std::string m_currentLine;
|
||||
Stream& m_stream;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Core/ParameterFile.inl>
|
||||
|
||||
#endif // NAZARA_CORE_PARAMETERFILE_HPP
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline ParameterFile::ParameterFile(Stream& stream) :
|
||||
m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void ParameterFile::Block(Args&&... args)
|
||||
{
|
||||
using Types = TypeListTransform<TypeListTransform<TypeList<Args...>, std::remove_const>, std::decay>;
|
||||
|
||||
constexpr bool IsOptionalBlock = TypeListHas<Types, OptionalBlock_t>;
|
||||
if constexpr (IsOptionalBlock)
|
||||
{
|
||||
std::string nextKeyword = ReadKeyword(true);
|
||||
if (nextKeyword != "{")
|
||||
return;
|
||||
}
|
||||
|
||||
std::string beginToken = ReadKeyword();
|
||||
if (beginToken != "{")
|
||||
throw std::runtime_error(Format("expected \"{{\" token, got {}", beginToken));
|
||||
|
||||
HandleInner("}", std::forward<Args>(args)...);
|
||||
|
||||
std::string endToken = ReadKeyword();
|
||||
if (endToken != "}")
|
||||
throw std::runtime_error(Format("expected \"}}\" token, got {}", endToken));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void ParameterFile::Handle(Args&&... args)
|
||||
{
|
||||
HandleInner({}, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<std::size_t N, typename K, typename V, typename... Rest>
|
||||
void ParameterFile::BuildKeyValues(ParameterFile& file, FixedVector<KeyValue, N>& keyValues, K&& key, V&& value, Rest&&... rest)
|
||||
{
|
||||
if constexpr (ShouldIgnore<K>)
|
||||
return BuildKeyValues(file, keyValues, std::forward<V>(value), std::forward<Rest>(rest)...);
|
||||
else
|
||||
{
|
||||
auto& keyValue = keyValues.emplace_back();
|
||||
keyValue.key = BuildBlockKey(std::forward<K>(key));
|
||||
keyValue.handler = BuildBlockHandler(file, std::forward<V>(value));
|
||||
|
||||
if constexpr (sizeof...(Rest) > 0)
|
||||
BuildKeyValues(file, keyValues, std::forward<Rest>(rest)...);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename V, typename ...Rest>
|
||||
auto ParameterFile::GetSingleHandler(ParameterFile& file, V&& value, Rest&&... rest) -> ValueHandler
|
||||
{
|
||||
if constexpr (ShouldIgnore<V>)
|
||||
{
|
||||
static_assert(sizeof...(Rest) > 0, "expected a handler");
|
||||
return GetSingleHandler(file, std::forward<Rest>(rest)...);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof...(Rest) == 0, "expected a single handler");
|
||||
return BuildBlockHandler(file, std::forward<V>(value));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string_view ParameterFile::BuildBlockKey(T&& key)
|
||||
{
|
||||
static_assert(std::is_constructible_v<std::string_view, T>, "parameter key must be convertible to a std::string_view");
|
||||
return std::string_view(std::forward<T>(key));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto ParameterFile::BuildBlockHandler(ParameterFile& /*file*/, ValueHandler handler) -> ValueHandler
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto ParameterFile::BuildBlockHandler(ParameterFile& /*file*/, T* value) -> ValueHandler
|
||||
{
|
||||
return [value](ParameterFile& file)
|
||||
{
|
||||
*value = ReadValue<T>(file);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto ParameterFile::BuildBlockHandler(ParameterFile& file, T&& handler, std::enable_if_t<IsFunctor_v<T>>*) -> ValueHandler
|
||||
{
|
||||
using FunctionType = typename FunctionTraits<T>::FuncType;
|
||||
return BuildBlockHandler(file, FunctionRef<FunctionType>(handler));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto ParameterFile::BuildBlockHandler(ParameterFile& /*file*/, FunctionRef<void(Args...)> handler) -> ValueHandler
|
||||
{
|
||||
return [handler](ParameterFile& file)
|
||||
{
|
||||
std::tuple<Args...> args{ ReadValue<Args>(file)... };
|
||||
std::apply(handler, std::move(args));
|
||||
};
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void ParameterFile::HandleInner(std::string_view listEnd, Args&&... args)
|
||||
{
|
||||
using Types = TypeListTransform<TypeListTransform<TypeList<Args...>, std::remove_const>, std::decay>;
|
||||
constexpr bool IsArray = TypeListHas<Types, Array_t>;
|
||||
|
||||
if constexpr (IsArray)
|
||||
{
|
||||
ValueHandler handler = GetSingleHandler(*this, std::forward<Args>(args)...);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
std::string nextKeyword = ReadKeyword(true);
|
||||
if (nextKeyword == listEnd)
|
||||
break;
|
||||
|
||||
handler(*this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FixedVector<KeyValue, sizeof...(Args) / 2> keys;
|
||||
BuildKeyValues(*this, keys, std::forward<Args>(args)...);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
std::string nextKeyword = ReadKeyword(true);
|
||||
if (nextKeyword == listEnd)
|
||||
break;
|
||||
|
||||
auto it = std::find_if(keys.begin(), keys.end(), [nextKeyword = ReadKeyword()](const KeyValue& keyValue) { return keyValue.key == nextKeyword; });
|
||||
if (it == keys.end())
|
||||
throw std::runtime_error(Format("unexpected keyword \"{}\"", nextKeyword));
|
||||
|
||||
const ValueHandler& handler = it->handler;
|
||||
handler(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ParameterFile::ReadValue(ParameterFile& file)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, std::string>)
|
||||
return file.ReadString();
|
||||
else if constexpr (std::is_same_v<T, Keyword>)
|
||||
return Keyword{ file.ReadKeyword() };
|
||||
else
|
||||
static_assert(AlwaysFalse<T>(), "unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Core/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/ParameterFile.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Stream.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool ParameterFile::EnsureLine(bool peek)
|
||||
{
|
||||
while (m_currentLine.find_first_not_of(" \r\t\n") == m_currentLine.npos)
|
||||
{
|
||||
m_currentLine.clear();
|
||||
m_stream.ReadLine(m_currentLine);
|
||||
if (m_currentLine.empty())
|
||||
{
|
||||
if (!peek)
|
||||
throw std::runtime_error("unexpected end of file");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string ParameterFile::ReadKeyword(bool peek)
|
||||
{
|
||||
std::size_t beginOffset;
|
||||
do
|
||||
{
|
||||
if (!EnsureLine(peek))
|
||||
return {};
|
||||
|
||||
beginOffset = m_currentLine.find_first_not_of(" \r\t\n");
|
||||
} while (beginOffset == m_currentLine.npos);
|
||||
|
||||
if (m_currentLine[beginOffset] == '"')
|
||||
throw std::runtime_error("expected a keyword, got a string");
|
||||
|
||||
std::size_t endOffset = m_currentLine.find_first_of(" \r\t\n", beginOffset + 1);
|
||||
if (endOffset == m_currentLine.npos)
|
||||
endOffset = m_currentLine.size();
|
||||
|
||||
std::string currentToken = std::string(m_currentLine.substr(beginOffset, endOffset - beginOffset));
|
||||
if (!peek)
|
||||
m_currentLine.erase(m_currentLine.begin(), m_currentLine.begin() + endOffset);
|
||||
|
||||
return currentToken;
|
||||
}
|
||||
|
||||
std::string ParameterFile::ReadString()
|
||||
{
|
||||
std::size_t beginOffset;
|
||||
do
|
||||
{
|
||||
EnsureLine();
|
||||
beginOffset = m_currentLine.find_first_not_of(" \r\t\n");
|
||||
} while (beginOffset == m_currentLine.npos);
|
||||
|
||||
if (m_currentLine[beginOffset] != '"')
|
||||
throw std::runtime_error("expected a string, got a keyword");
|
||||
|
||||
std::string str;
|
||||
for (std::size_t i = beginOffset + 1; i < m_currentLine.size(); ++i)
|
||||
{
|
||||
switch (m_currentLine[i])
|
||||
{
|
||||
case '\0':
|
||||
case '\n':
|
||||
case '\r':
|
||||
throw std::runtime_error("expected a string, got a keyword");
|
||||
|
||||
case '"':
|
||||
{
|
||||
m_currentLine.erase(m_currentLine.begin(), m_currentLine.begin() + beginOffset + i);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
case '\\':
|
||||
{
|
||||
i++;
|
||||
char character;
|
||||
switch (m_currentLine[i])
|
||||
{
|
||||
case 'n': character = '\n'; break;
|
||||
case 'r': character = '\r'; break;
|
||||
case 't': character = '\t'; break;
|
||||
case '"': character = '"'; break;
|
||||
case '\\': character = '\\'; break;
|
||||
default:
|
||||
throw std::runtime_error(Format("unrecognized character {}", character));
|
||||
}
|
||||
|
||||
str.push_back(character);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
str.push_back(m_currentLine[i]);
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("unfinished string");
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/Formats/PipelinePassListLoader.hpp>
|
||||
#include <Nazara/Core/ParameterFile.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <optional>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
|
@ -15,7 +16,7 @@ namespace Nz::Loaders
|
|||
{
|
||||
public:
|
||||
PassListLoader(Stream& stream, const PipelinePassListParams& /*parameters*/) :
|
||||
m_stream(stream)
|
||||
m_paramFile(stream)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -23,59 +24,45 @@ namespace Nz::Loaders
|
|||
{
|
||||
try
|
||||
{
|
||||
ExpectKeyword("passlist");
|
||||
std::string finalOutputAttachment;
|
||||
|
||||
std::string passListName = ReadString();
|
||||
m_paramFile.Handle(
|
||||
"passlist", [&](std::string passListName)
|
||||
{
|
||||
m_current.emplace();
|
||||
m_current->passList = std::make_shared<PipelinePassList>();
|
||||
m_paramFile.Block(
|
||||
"attachment", [this](std::string attachmentName)
|
||||
{
|
||||
HandleAttachment(std::move(attachmentName));
|
||||
},
|
||||
"attachmentproxy", [this](std::string proxyName, std::string targetName)
|
||||
{
|
||||
HandleAttachmentProxy(std::move(proxyName), std::move(targetName));
|
||||
},
|
||||
"pass", [this](std::string passName)
|
||||
{
|
||||
HandlePass(std::move(passName));
|
||||
},
|
||||
"output", &finalOutputAttachment
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
m_current.emplace();
|
||||
m_current->passList = std::make_shared<PipelinePassList>();
|
||||
Block([this]
|
||||
if (finalOutputAttachment.empty())
|
||||
{
|
||||
std::string kw = ReadKeyword();
|
||||
if (kw == "attachment")
|
||||
HandleAttachment();
|
||||
else if (kw == "attachmentproxy")
|
||||
{
|
||||
std::string proxyName = ReadString();
|
||||
std::string targetName = ReadString();
|
||||
NazaraError("missing passlist output attachment");
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
auto it = m_current->attachmentsByName.find(targetName);
|
||||
if (it == m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("unknown attachment {}", targetName);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
auto it = m_current->attachmentsByName.find(finalOutputAttachment);
|
||||
if (it == m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("unknown attachment {}", finalOutputAttachment);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
if (m_current->attachmentsByName.find(proxyName) != m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("attachment {} already exists", proxyName);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
std::size_t proxyId = m_current->passList->AddAttachmentProxy(proxyName, it->second);
|
||||
m_current->attachmentsByName.emplace(std::move(proxyName), proxyId);
|
||||
}
|
||||
else if (kw == "pass")
|
||||
HandlePass();
|
||||
else if (kw == "output")
|
||||
{
|
||||
std::string attachmentName = ReadString();
|
||||
|
||||
auto it = m_current->attachmentsByName.find(attachmentName);
|
||||
if (it == m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("unknown attachment {}", attachmentName);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
m_current->passList->SetFinalOutput(it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraErrorFmt("unexpected keyword {}", kw);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
});
|
||||
m_current->passList->SetFinalOutput(it->second);
|
||||
|
||||
return Ok(std::move(m_current->passList));
|
||||
}
|
||||
|
|
@ -86,58 +73,13 @@ namespace Nz::Loaders
|
|||
}
|
||||
|
||||
private:
|
||||
void Block(const FunctionRef<void()>& callback)
|
||||
void HandleAttachment(std::string attachmentName)
|
||||
{
|
||||
std::string beginToken = ReadKeyword();
|
||||
if (beginToken != "{")
|
||||
{
|
||||
NazaraErrorFmt("expected \"{{\" token, got {}", beginToken);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
std::string nextKeyword = ReadKeyword(true);
|
||||
if (nextKeyword == "}")
|
||||
break;
|
||||
|
||||
callback();
|
||||
}
|
||||
|
||||
std::string endToken = ReadKeyword();
|
||||
if (endToken != "}")
|
||||
{
|
||||
NazaraErrorFmt("expected \"}}\" token, got {}", endToken);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
}
|
||||
|
||||
void ExpectKeyword(std::string_view expectedKeyword)
|
||||
{
|
||||
std::string keyword = ReadKeyword();
|
||||
if (keyword != expectedKeyword)
|
||||
{
|
||||
NazaraErrorFmt("expected \"{}\" keyword, got {}", expectedKeyword, keyword);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleAttachment()
|
||||
{
|
||||
std::string attachmentName = ReadString();
|
||||
|
||||
std::string format;
|
||||
Block([&]
|
||||
{
|
||||
std::string kw = ReadKeyword();
|
||||
if (kw == "format")
|
||||
format = ReadString();
|
||||
else
|
||||
{
|
||||
NazaraErrorFmt("unexpected keyword {}", kw);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
});
|
||||
|
||||
m_paramFile.Block(
|
||||
"format", &format
|
||||
);
|
||||
|
||||
if (format.empty())
|
||||
{
|
||||
|
|
@ -172,11 +114,28 @@ namespace Nz::Loaders
|
|||
|
||||
m_current->attachmentsByName.emplace(attachmentName, attachmentId);
|
||||
}
|
||||
|
||||
void HandlePass()
|
||||
{
|
||||
std::string passName = ReadString();
|
||||
|
||||
void HandleAttachmentProxy(std::string proxyName, std::string targetName)
|
||||
{
|
||||
auto it = m_current->attachmentsByName.find(targetName);
|
||||
if (it == m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("unknown attachment {}", targetName);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
if (m_current->attachmentsByName.find(proxyName) != m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("attachment {} already exists", proxyName);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
std::size_t proxyId = m_current->passList->AddAttachmentProxy(proxyName, it->second);
|
||||
m_current->attachmentsByName.emplace(std::move(proxyName), proxyId);
|
||||
}
|
||||
|
||||
void HandlePass(std::string passName)
|
||||
{
|
||||
struct InputOutput
|
||||
{
|
||||
std::string name;
|
||||
|
|
@ -191,58 +150,37 @@ namespace Nz::Loaders
|
|||
std::vector<InputOutput> outputs;
|
||||
std::vector<std::string> flags;
|
||||
|
||||
Block([&]
|
||||
{
|
||||
std::string kw = ReadKeyword();
|
||||
|
||||
if (kw == "impl")
|
||||
m_paramFile.Block(
|
||||
"depthstencilinput", &depthstencilInput,
|
||||
"depthstenciloutput", &depthstencilOutput,
|
||||
"impl", [&](std::string passImpl)
|
||||
{
|
||||
impl = ReadString();
|
||||
|
||||
std::string nextKeyword = ReadKeyword(true);
|
||||
if (nextKeyword == "{")
|
||||
impl = std::move(passImpl);
|
||||
m_paramFile.Block(ParameterFile::OptionalBlock,
|
||||
ParameterFile::Array, [&](ParameterFile::Keyword key, std::string value)
|
||||
{
|
||||
Block([&]
|
||||
{
|
||||
std::string key = ReadKeyword();
|
||||
std::string value = ReadString();
|
||||
|
||||
implConfig.SetParameter(std::move(key), std::move(value));
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (kw == "depthstencilinput")
|
||||
depthstencilInput = ReadString();
|
||||
else if (kw == "depthstenciloutput")
|
||||
depthstencilOutput = ReadString();
|
||||
else if (kw == "flag")
|
||||
flags.push_back(ReadString());
|
||||
else if (kw == "input")
|
||||
implConfig.SetParameter(std::move(key.str), std::move(value));
|
||||
});
|
||||
},
|
||||
"input", [&](std::string name, std::string attachment)
|
||||
{
|
||||
std::string name = ReadString();
|
||||
std::string attachment = ReadString();
|
||||
|
||||
inputs.push_back({
|
||||
std::move(name),
|
||||
std::move(attachment),
|
||||
});
|
||||
}
|
||||
else if (kw == "output")
|
||||
},
|
||||
"output", [&](std::string name, std::string attachment)
|
||||
{
|
||||
std::string name = ReadString();
|
||||
std::string attachment = ReadString();
|
||||
|
||||
outputs.push_back({
|
||||
std::move(name),
|
||||
std::move(attachment),
|
||||
});
|
||||
}
|
||||
else
|
||||
},
|
||||
"flag", [&](std::string flag)
|
||||
{
|
||||
NazaraErrorFmt("unexpected keyword {}", kw);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
flags.push_back(std::move(flag));
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
FramePipelinePassRegistry& passRegistry = Graphics::Instance()->GetFramePipelinePassRegistry();
|
||||
|
||||
|
|
@ -329,107 +267,6 @@ namespace Nz::Loaders
|
|||
}
|
||||
}
|
||||
|
||||
std::string ReadKeyword(bool peek = false)
|
||||
{
|
||||
std::size_t beginOffset;
|
||||
do
|
||||
{
|
||||
EnsureLine();
|
||||
beginOffset = m_currentLine.find_first_not_of(" \r\t\n");
|
||||
}
|
||||
while (beginOffset == m_currentLine.npos);
|
||||
|
||||
if (m_currentLine[beginOffset] == '"')
|
||||
{
|
||||
NazaraError("expected a keyword, got a string");
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
std::size_t endOffset = m_currentLine.find_first_of(" \r\t\n", beginOffset + 1);
|
||||
if (endOffset == m_currentLine.npos)
|
||||
endOffset = m_currentLine.size();
|
||||
|
||||
std::string currentToken = std::string(m_currentLine.substr(beginOffset, endOffset - beginOffset));
|
||||
if (!peek)
|
||||
m_currentLine.erase(m_currentLine.begin(), m_currentLine.begin() + endOffset);
|
||||
|
||||
return currentToken;
|
||||
}
|
||||
|
||||
std::string ReadString()
|
||||
{
|
||||
std::size_t beginOffset;
|
||||
do
|
||||
{
|
||||
EnsureLine();
|
||||
beginOffset = m_currentLine.find_first_not_of(" \r\t\n");
|
||||
}
|
||||
while (beginOffset == m_currentLine.npos);
|
||||
|
||||
if (m_currentLine[beginOffset] != '"')
|
||||
{
|
||||
NazaraError("expected a string, got a keyword");
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
std::string str;
|
||||
for (std::size_t i = beginOffset + 1; i < m_currentLine.size(); ++i)
|
||||
{
|
||||
switch (m_currentLine[i])
|
||||
{
|
||||
case '\0':
|
||||
case '\n':
|
||||
case '\r':
|
||||
NazaraError("unfinished string");
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
|
||||
case '"':
|
||||
{
|
||||
m_currentLine.erase(m_currentLine.begin(), m_currentLine.begin() + beginOffset + i);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
case '\\':
|
||||
{
|
||||
i++;
|
||||
char character;
|
||||
switch (m_currentLine[i])
|
||||
{
|
||||
case 'n': character = '\n'; break;
|
||||
case 'r': character = '\r'; break;
|
||||
case 't': character = '\t'; break;
|
||||
case '"': character = '"'; break;
|
||||
case '\\': character = '\\'; break;
|
||||
default:
|
||||
NazaraErrorFmt("unrecognized character {}", character);
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
str.push_back(character);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
str.push_back(m_currentLine[i]);
|
||||
}
|
||||
}
|
||||
|
||||
NazaraError("unfinished string");
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
|
||||
void EnsureLine()
|
||||
{
|
||||
while (m_currentLine.find_first_not_of(" \r\t\n") == m_currentLine.npos)
|
||||
{
|
||||
m_currentLine.clear();
|
||||
m_stream.ReadLine(m_currentLine);
|
||||
if (m_currentLine.empty())
|
||||
throw ResourceLoadingError::DecodingError;
|
||||
}
|
||||
}
|
||||
|
||||
struct CurrentPassList
|
||||
{
|
||||
std::shared_ptr<PipelinePassList> passList;
|
||||
|
|
@ -438,8 +275,7 @@ namespace Nz::Loaders
|
|||
|
||||
std::optional<CurrentPassList> m_current;
|
||||
std::string m_currentLine;
|
||||
|
||||
Stream& m_stream;
|
||||
ParameterFile m_paramFile;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue