Graphics: Add PipelinePassList loader (able to load from a file)
Fix compilation
This commit is contained in:
parent
ef0a34b7b1
commit
886991f86d
|
|
@ -44,7 +44,8 @@ namespace Nz
|
|||
inline StreamOptionFlags GetStreamOptions() const;
|
||||
|
||||
std::size_t Read(void* buffer, std::size_t size);
|
||||
virtual std::string ReadLine(unsigned int lineSize = 0);
|
||||
virtual void ReadLine(std::string& line, unsigned int lineSize = 0);
|
||||
inline std::string ReadLine(unsigned int lineSize = 0);
|
||||
|
||||
inline bool IsBufferingEnabled() const;
|
||||
inline bool IsMemoryMapped() const;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,27 @@ namespace Nz
|
|||
return m_streamOptions;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Reads a line from the stream
|
||||
*
|
||||
* Reads the stream until a line separator or the end of the stream is found.
|
||||
*
|
||||
* If lineSize does not equal zero, it represents the maximum character count to be read from the stream.
|
||||
*
|
||||
* \param lineSize Maximum number of characters to read, or zero for no limit
|
||||
*
|
||||
* \return Line read from file
|
||||
*
|
||||
* \remark With the text stream option, "\r\n" is treated as "\n"
|
||||
* \remark The line separator character is not returned as part of the string
|
||||
*/
|
||||
inline std::string Stream::ReadLine(unsigned int lineSize)
|
||||
{
|
||||
std::string line;
|
||||
ReadLine(line, lineSize);
|
||||
return line;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the stream is readable
|
||||
* \return true if it is the case
|
||||
|
|
|
|||
|
|
@ -33,17 +33,28 @@ namespace Nz
|
|||
inline std::unique_ptr<FramePipelinePass> BuildPass(std::size_t passIndex, FramePipelinePass::PassData& passData, std::string passName, const ParameterList& parameters) const;
|
||||
|
||||
inline std::size_t GetPassIndex(std::string_view passName) const;
|
||||
inline std::size_t GetPassInputIndex(std::size_t passIndex, std::string_view inputName) const;
|
||||
inline std::size_t GetPassOutputIndex(std::size_t passIndex, std::string_view inputName) const;
|
||||
|
||||
template<typename T> std::size_t RegisterPass(std::string passName);
|
||||
inline std::size_t RegisterPass(std::string passName, Factory factory);
|
||||
template<typename T> std::size_t RegisterPass(std::string passName, std::vector<std::string> inputs, std::vector<std::string> outputs);
|
||||
inline std::size_t RegisterPass(std::string passName, std::vector<std::string> inputs, std::vector<std::string> outputs, Factory factory);
|
||||
|
||||
FramePipelinePassRegistry& operator=(const FramePipelinePassRegistry&) = default;
|
||||
FramePipelinePassRegistry& operator=(FramePipelinePassRegistry&&) = default;
|
||||
|
||||
static constexpr std::size_t InvalidIndex = std::numeric_limits<std::size_t>::max();
|
||||
|
||||
private:
|
||||
struct Pass
|
||||
{
|
||||
Factory factory;
|
||||
std::vector<std::string> inputs;
|
||||
std::vector<std::string> outputs;
|
||||
};
|
||||
|
||||
std::list<std::string> m_passNames; //< in order to allow std::string_view as a key in C++17 (keep std::string stable as well because of SSO)
|
||||
std::unordered_map<std::string_view, std::size_t> m_passIndex;
|
||||
std::vector<Factory> m_passFactories;
|
||||
std::vector<Pass> m_passes;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,29 +9,51 @@ namespace Nz
|
|||
{
|
||||
inline std::unique_ptr<FramePipelinePass> FramePipelinePassRegistry::BuildPass(std::size_t passIndex, FramePipelinePass::PassData& passData, std::string passName, const ParameterList& parameters) const
|
||||
{
|
||||
assert(passIndex < m_passFactories.size());
|
||||
return m_passFactories[passIndex](passData, passName, parameters);
|
||||
assert(passIndex < m_passes.size());
|
||||
return m_passes[passIndex].factory(passData, passName, parameters);
|
||||
}
|
||||
|
||||
inline std::size_t FramePipelinePassRegistry::GetPassIndex(std::string_view passName) const
|
||||
{
|
||||
auto it = m_passIndex.find(passName);
|
||||
if (it == m_passIndex.end())
|
||||
throw std::runtime_error("pass " + std::string(passName) + " must be registered before being used");
|
||||
return InvalidIndex;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::size_t FramePipelinePassRegistry::RegisterPass(std::string passName)
|
||||
inline std::size_t FramePipelinePassRegistry::GetPassInputIndex(std::size_t passIndex, std::string_view inputName) const
|
||||
{
|
||||
return RegisterPass(std::move(passName), [](FramePipelinePass::PassData& passData, std::string passName, const ParameterList& parameters) -> std::unique_ptr<FramePipelinePass>
|
||||
assert(passIndex < m_passes.size());
|
||||
auto& passData = m_passes[passIndex];
|
||||
auto it = std::find(passData.inputs.begin(), passData.inputs.end(), inputName);
|
||||
if (it == passData.inputs.end())
|
||||
return InvalidIndex;
|
||||
|
||||
return std::distance(passData.inputs.begin(), it);
|
||||
}
|
||||
|
||||
inline std::size_t FramePipelinePassRegistry::GetPassOutputIndex(std::size_t passIndex, std::string_view outputName) const
|
||||
{
|
||||
assert(passIndex < m_passes.size());
|
||||
auto& passData = m_passes[passIndex];
|
||||
auto it = std::find(passData.outputs.begin(), passData.outputs.end(), outputName);
|
||||
if (it == passData.outputs.end())
|
||||
return InvalidIndex;
|
||||
|
||||
return std::distance(passData.outputs.begin(), it);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::size_t FramePipelinePassRegistry::RegisterPass(std::string passName, std::vector<std::string> inputs, std::vector<std::string> outputs)
|
||||
{
|
||||
return RegisterPass(std::move(passName), std::move(inputs), std::move(outputs), [](FramePipelinePass::PassData& passData, std::string passName, const ParameterList& parameters) -> std::unique_ptr<FramePipelinePass>
|
||||
{
|
||||
return std::make_unique<T>(passData, std::move(passName), parameters);
|
||||
});
|
||||
}
|
||||
|
||||
inline std::size_t FramePipelinePassRegistry::RegisterPass(std::string passName, Factory factory)
|
||||
inline std::size_t FramePipelinePassRegistry::RegisterPass(std::string passName, std::vector<std::string> inputs, std::vector<std::string> outputs, Factory factory)
|
||||
{
|
||||
if (m_passIndex.find(passName) != m_passIndex.end())
|
||||
throw std::runtime_error("pass " + passName + " is already registered");
|
||||
|
|
@ -40,7 +62,10 @@ namespace Nz
|
|||
|
||||
std::size_t passIndex = m_passIndex.size();
|
||||
m_passIndex.emplace(m_passNames.back(), passIndex);
|
||||
m_passFactories.emplace_back(std::move(factory));
|
||||
auto& passData = m_passes.emplace_back();
|
||||
passData.factory = std::move(factory);
|
||||
passData.inputs = std::move(inputs);
|
||||
passData.outputs = std::move(outputs);
|
||||
|
||||
return passIndex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ namespace Nz
|
|||
inline const MaterialInstanceLoader& GetMaterialInstanceLoader() const;
|
||||
inline MaterialLoader& GetMaterialLoader();
|
||||
inline const MaterialLoader& GetMaterialLoader() const;
|
||||
inline PipelinePassListLoader& GetPipelinePassListLoader();
|
||||
inline const PipelinePassListLoader& GetPipelinePassListLoader() const;
|
||||
inline PixelFormat GetPreferredDepthFormat() const;
|
||||
inline PixelFormat GetPreferredDepthStencilFormat() const;
|
||||
inline const std::shared_ptr<RenderDevice>& GetRenderDevice() const;
|
||||
|
|
@ -115,6 +117,7 @@ namespace Nz
|
|||
MaterialInstanceLoader m_materialInstanceLoader;
|
||||
MaterialLoader m_materialLoader;
|
||||
MaterialPassRegistry m_materialPassRegistry;
|
||||
PipelinePassListLoader m_pipelinePassListLoader;
|
||||
PixelFormat m_preferredDepthFormat;
|
||||
PixelFormat m_preferredDepthStencilFormat;
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,16 @@ namespace Nz
|
|||
return m_materialLoader;
|
||||
}
|
||||
|
||||
inline PipelinePassListLoader& Graphics::GetPipelinePassListLoader()
|
||||
{
|
||||
return m_pipelinePassListLoader;
|
||||
}
|
||||
|
||||
inline const PipelinePassListLoader& Graphics::GetPipelinePassListLoader() const
|
||||
{
|
||||
return m_pipelinePassListLoader;
|
||||
}
|
||||
|
||||
inline PixelFormat Graphics::GetPreferredDepthFormat() const
|
||||
{
|
||||
return m_preferredDepthFormat;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@
|
|||
#define NAZARA_GRAPHICS_PIPELINEPASSLIST_HPP
|
||||
|
||||
#include <NazaraUtils/Prerequisites.hpp>
|
||||
#include <Nazara/Core/ObjectLibrary.hpp>
|
||||
#include <Nazara/Core/ParameterList.hpp>
|
||||
#include <Nazara/Core/Resource.hpp>
|
||||
#include <Nazara/Core/ResourceLoader.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Graphics/FramePassAttachment.hpp>
|
||||
|
|
@ -21,11 +24,22 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class FrameGraph;
|
||||
struct NAZARA_GRAPHICS_API PipelinePassListParams : ResourceParameters
|
||||
{
|
||||
bool IsValid() const;
|
||||
};
|
||||
|
||||
class NAZARA_GRAPHICS_API PipelinePassList
|
||||
class FrameGraph;
|
||||
class PipelinePassList;
|
||||
|
||||
using PipelinePassListLibrary = ObjectLibrary<PipelinePassList>;
|
||||
using PipelinePassListLoader = ResourceLoader<PipelinePassList, PipelinePassListParams>;
|
||||
|
||||
class NAZARA_GRAPHICS_API PipelinePassList : public Resource
|
||||
{
|
||||
public:
|
||||
using Params = PipelinePassListParams;
|
||||
|
||||
PipelinePassList() = default;
|
||||
PipelinePassList(const PipelinePassList&) = delete;
|
||||
PipelinePassList(PipelinePassList&&) = delete;
|
||||
|
|
@ -50,6 +64,10 @@ namespace Nz
|
|||
PipelinePassList& operator=(const PipelinePassList&) = delete;
|
||||
PipelinePassList& operator=(PipelinePassList&&) = delete;
|
||||
|
||||
static std::shared_ptr<PipelinePassList> LoadFromFile(const std::filesystem::path& filePath, const PipelinePassListParams& params = PipelinePassListParams());
|
||||
static std::shared_ptr<PipelinePassList> LoadFromMemory(const void* data, std::size_t size, const PipelinePassListParams& params = PipelinePassListParams());
|
||||
static std::shared_ptr<PipelinePassList> LoadFromStream(Stream& stream, const PipelinePassListParams& params = PipelinePassListParams());
|
||||
|
||||
static constexpr std::size_t MaxPassAttachment = 8;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@ namespace Nz
|
|||
|
||||
static inline bool HasAlpha(PixelFormat format);
|
||||
|
||||
static PixelFormat IdentifyFormat(const PixelFormatDescription& info);
|
||||
static inline PixelFormat IdentifyFormat(const PixelFormatDescription& info);
|
||||
static inline PixelFormat IdentifyFormat(std::string_view formatName);
|
||||
|
||||
static inline bool IsCompressed(PixelFormat format);
|
||||
static inline bool IsConversionSupported(PixelFormat srcFormat, PixelFormat dstFormat);
|
||||
|
|
|
|||
|
|
@ -243,6 +243,30 @@ namespace Nz
|
|||
return s_pixelFormatInfos[format].alphaMask.TestAny();
|
||||
}
|
||||
|
||||
inline PixelFormat PixelFormatInfo::IdentifyFormat(const PixelFormatDescription& info)
|
||||
{
|
||||
for (auto&& [format, formatDesc] : s_pixelFormatInfos.iter_kv())
|
||||
{
|
||||
if (info.bitsPerPixel == formatDesc.bitsPerPixel && info.content == formatDesc.content &&
|
||||
info.redMask == formatDesc.redMask && info.greenMask == formatDesc.greenMask && info.blueMask == formatDesc.blueMask && info.alphaMask == formatDesc.alphaMask &&
|
||||
info.redType == formatDesc.redType && info.greenType == formatDesc.greenType && info.blueType == formatDesc.blueType && info.alphaType == formatDesc.alphaType)
|
||||
return format;
|
||||
}
|
||||
|
||||
return PixelFormat::Undefined;
|
||||
}
|
||||
|
||||
inline PixelFormat PixelFormatInfo::IdentifyFormat(std::string_view formatName)
|
||||
{
|
||||
for (auto&& [format, formatDesc] : s_pixelFormatInfos.iter_kv())
|
||||
{
|
||||
if (formatDesc.name == formatName)
|
||||
return format;
|
||||
}
|
||||
|
||||
return PixelFormat::Undefined;
|
||||
}
|
||||
|
||||
inline bool PixelFormatInfo::IsCompressed(PixelFormat format)
|
||||
{
|
||||
return s_pixelFormatInfos[format].IsCompressed();
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ namespace Nz
|
|||
*
|
||||
* If lineSize does not equal zero, it represents the maximum character count to be read from the stream.
|
||||
*
|
||||
* \param line Line object to use to store characters
|
||||
* \param lineSize Maximum number of characters to read, or zero for no limit
|
||||
*
|
||||
* \return Line read from file
|
||||
|
|
@ -142,9 +143,8 @@ namespace Nz
|
|||
* \remark With the text stream option, "\r\n" is treated as "\n"
|
||||
* \remark The line separator character is not returned as part of the string
|
||||
*/
|
||||
std::string Stream::ReadLine(unsigned int lineSize)
|
||||
void Stream::ReadLine(std::string& line, unsigned int lineSize)
|
||||
{
|
||||
std::string line;
|
||||
if (lineSize == 0) // Maximal size undefined
|
||||
{
|
||||
const unsigned int bufferSize = 64;
|
||||
|
|
@ -192,8 +192,9 @@ namespace Nz
|
|||
}
|
||||
else
|
||||
{
|
||||
line.resize(lineSize, '\0');
|
||||
std::size_t readSize = Read(&line[0], lineSize);
|
||||
std::size_t offset = line.size();
|
||||
line.resize(offset + lineSize, '\0');
|
||||
std::size_t readSize = Read(&line[offset], lineSize);
|
||||
std::size_t pos = line.find('\n');
|
||||
if (pos <= readSize) // False only if the character is not available (npos being the biggest integer)
|
||||
{
|
||||
|
|
@ -206,10 +207,8 @@ namespace Nz
|
|||
NazaraWarning("Failed to reset cursos pos");
|
||||
}
|
||||
else
|
||||
line.resize(readSize);
|
||||
line.resize(offset + readSize);
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
bool Stream::SetCursorPos(UInt64 offset)
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ namespace Nz
|
|||
// TODO: Log error if key is present but not of the right
|
||||
|
||||
Result<std::string_view, ParameterList::Error> passResult = parameters.GetStringViewParameter("MatPass");
|
||||
if (passIndexResult.IsOk())
|
||||
if (passResult.IsOk())
|
||||
{
|
||||
auto& materialPassRegistry = Graphics::Instance()->GetMaterialPassRegistry();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,548 @@
|
|||
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/Formats/PipelinePassListLoader.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <optional>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz::Loaders
|
||||
{
|
||||
namespace NAZARA_ANONYMOUS_NAMESPACE
|
||||
{
|
||||
class PassListLoader
|
||||
{
|
||||
public:
|
||||
PassListLoader(Stream& stream, const PipelinePassListParams& /*parameters*/) :
|
||||
m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
Result<std::shared_ptr<PipelinePassList>, ResourceLoadingError> Parse()
|
||||
{
|
||||
auto result = ExpectKeyword("passlist");
|
||||
if (!result)
|
||||
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
Result<std::string, ResourceLoadingError> passListName = GetString();
|
||||
if (!passListName)
|
||||
return Err(std::move(passListName).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
m_current.emplace();
|
||||
m_current->passList = std::make_shared<PipelinePassList>();
|
||||
result = Block([this]() -> Result<void, ResourceLoadingError>
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> kw = GetKeyword();
|
||||
if (!kw)
|
||||
return Err(std::move(kw).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
if (kw.GetValue() == "attachment")
|
||||
{
|
||||
auto result = HandleAttachment();
|
||||
if (!result)
|
||||
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
|
||||
}
|
||||
else if (kw.GetValue() == "pass")
|
||||
{
|
||||
auto result = HandlePass();
|
||||
if (!result)
|
||||
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
|
||||
}
|
||||
else if (kw.GetValue() == "output")
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> attachmentName = GetString();
|
||||
if (!attachmentName)
|
||||
return Err(std::move(attachmentName).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
auto it = m_current->attachmentsByName.find(attachmentName.GetValue());
|
||||
if (it == m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("unknown attachment {}", attachmentName.GetValue());
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
m_current->passList->SetFinalOutput(it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraErrorFmt("unexpected keyword {}", kw.GetValue());
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
});
|
||||
if (!result)
|
||||
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
return Ok(std::move(m_current->passList));
|
||||
}
|
||||
|
||||
private:
|
||||
Result<void, ResourceLoadingError> Block(const FunctionRef<Result<void, ResourceLoadingError>()>& callback)
|
||||
{
|
||||
auto beginBlock = GetKeyword();
|
||||
if (!beginBlock)
|
||||
return Err(std::move(beginBlock).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
if (beginBlock.GetValue() != "{")
|
||||
{
|
||||
NazaraErrorFmt("expected \"{{\" token, got {}", beginBlock.GetValue());
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto nextKw = GetKeyword(true);
|
||||
if (!nextKw)
|
||||
return Err(std::move(nextKw).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
if (nextKw.GetValue() == "}")
|
||||
break;
|
||||
|
||||
auto result = callback();
|
||||
if (!result)
|
||||
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
|
||||
}
|
||||
|
||||
auto endBlock = GetKeyword();
|
||||
if (!endBlock)
|
||||
return Err(std::move(endBlock).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
if (endBlock.GetValue() != "}")
|
||||
{
|
||||
NazaraErrorFmt("expected \"}}\" token, got {}", endBlock.GetValue());
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<void, ResourceLoadingError> ExpectKeyword(std::string_view expectedKeyword)
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> passListKw = GetKeyword();
|
||||
if (!passListKw)
|
||||
return Err(std::move(passListKw).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
if (passListKw.GetValue() != expectedKeyword)
|
||||
{
|
||||
NazaraErrorFmt("expected \"{}\" keyword, got {}", expectedKeyword, passListKw.GetValue());
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<void, ResourceLoadingError> HandleAttachment()
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> attachmentName = GetString();
|
||||
if (!attachmentName)
|
||||
return Err(std::move(attachmentName).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
std::string format;
|
||||
auto result = Block([&]() -> Result<void, ResourceLoadingError>
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> kw = GetKeyword();
|
||||
if (!kw)
|
||||
return Err(std::move(kw).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
if (kw.GetValue() == "format")
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> formatStr = GetString();
|
||||
if (!formatStr)
|
||||
return Err(std::move(formatStr).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
format = std::move(formatStr).GetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraErrorFmt("unexpected keyword {}", kw.GetValue());
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
});
|
||||
if (!result)
|
||||
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
if (format.empty())
|
||||
{
|
||||
NazaraErrorFmt("missing mandatory format in attachment {}", attachmentName.GetValue());
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
PixelFormat attachmentFormat = PixelFormat::Undefined;
|
||||
if (format == "PreferredDepth")
|
||||
attachmentFormat = Graphics::Instance()->GetPreferredDepthFormat();
|
||||
else if (format == "PreferredDepthStencil")
|
||||
attachmentFormat = Graphics::Instance()->GetPreferredDepthStencilFormat();
|
||||
else
|
||||
attachmentFormat = PixelFormatInfo::IdentifyFormat(format);
|
||||
|
||||
if (attachmentFormat == PixelFormat::Undefined)
|
||||
{
|
||||
NazaraErrorFmt("unknown format {}", format);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
if (m_current->attachmentsByName.find(attachmentName.GetValue()) != m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("attachment {} already exists", attachmentName.GetValue());
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
std::size_t attachmentId = m_current->passList->AddAttachment({
|
||||
attachmentName.GetValue(),
|
||||
attachmentFormat
|
||||
});
|
||||
|
||||
m_current->attachmentsByName.emplace(attachmentName.GetValue(), attachmentId);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<void, ResourceLoadingError> HandlePass()
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> passName = GetString();
|
||||
if (!passName)
|
||||
return Err(std::move(passName).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
struct InputOutput
|
||||
{
|
||||
std::string name;
|
||||
std::string attachmentName;
|
||||
};
|
||||
|
||||
ParameterList implConfig;
|
||||
std::string impl;
|
||||
std::string depthstencilInput;
|
||||
std::string depthstencilOutput;
|
||||
std::vector<InputOutput> inputs;
|
||||
std::vector<InputOutput> outputs;
|
||||
std::vector<std::string> flags;
|
||||
|
||||
auto result = Block([&]() -> Result<void, ResourceLoadingError>
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> kw = GetKeyword();
|
||||
if (!kw)
|
||||
return Err(std::move(kw).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
if (kw.GetValue() == "impl")
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> implStr = GetString();
|
||||
if (!implStr)
|
||||
return Err(std::move(implStr).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
impl = std::move(implStr).GetValue();
|
||||
|
||||
auto nextKw = GetKeyword(true);
|
||||
if (!nextKw)
|
||||
return Err(std::move(nextKw).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
if (nextKw.GetValue() == "{")
|
||||
{
|
||||
Block([&]() -> Result<void, ResourceLoadingError>
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> key = GetKeyword();
|
||||
if (!key)
|
||||
return Err(std::move(key).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
Result<std::string, ResourceLoadingError> value = GetString();
|
||||
if (!value)
|
||||
return Err(std::move(value).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
implConfig.SetParameter(key.GetValue(), value.GetValue());
|
||||
return Ok();
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (kw.GetValue() == "depthstencilinput")
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> attachmentStr = GetString();
|
||||
if (!attachmentStr)
|
||||
return Err(std::move(attachmentStr).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
depthstencilInput = std::move(attachmentStr).GetValue();
|
||||
}
|
||||
else if (kw.GetValue() == "depthstenciloutput")
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> attachmentStr = GetString();
|
||||
if (!attachmentStr)
|
||||
return Err(std::move(attachmentStr).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
depthstencilOutput = std::move(attachmentStr).GetValue();
|
||||
}
|
||||
else if (kw.GetValue() == "flag")
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> str = GetString();
|
||||
if (!str)
|
||||
return Err(std::move(str).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
flags.push_back(std::move(str).GetValue());
|
||||
}
|
||||
else if (kw.GetValue() == "input")
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> name = GetString();
|
||||
if (!name)
|
||||
return Err(std::move(name).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
Result<std::string, ResourceLoadingError> attachment = GetString();
|
||||
if (!attachment)
|
||||
return Err(std::move(attachment).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
inputs.push_back({
|
||||
std::move(name).GetValue(),
|
||||
std::move(attachment).GetValue(),
|
||||
});
|
||||
}
|
||||
else if (kw.GetValue() == "output")
|
||||
{
|
||||
Result<std::string, ResourceLoadingError> name = GetString();
|
||||
if (!name)
|
||||
return Err(std::move(name).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
Result<std::string, ResourceLoadingError> attachment = GetString();
|
||||
if (!attachment)
|
||||
return Err(std::move(attachment).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
outputs.push_back({
|
||||
std::move(name).GetValue(),
|
||||
std::move(attachment).GetValue(),
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraErrorFmt("unexpected keyword {}", kw.GetValue());
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
});
|
||||
if (!result)
|
||||
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
FramePipelinePassRegistry& passRegistry = Graphics::Instance()->GetFramePipelinePassRegistry();
|
||||
|
||||
std::size_t implIndex = passRegistry.GetPassIndex(impl);
|
||||
if (implIndex == FramePipelinePassRegistry::InvalidIndex)
|
||||
{
|
||||
NazaraErrorFmt("unknown pass {}", impl);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
std::size_t passId = m_current->passList->AddPass(passName.GetValue(), implIndex, std::move(implConfig));
|
||||
|
||||
for (auto&& [inputName, attachmentName] : inputs)
|
||||
{
|
||||
std::size_t inputIndex = passRegistry.GetPassInputIndex(implIndex, inputName);
|
||||
if (inputIndex == FramePipelinePassRegistry::InvalidIndex)
|
||||
{
|
||||
NazaraErrorFmt("pass {} has no input {}", impl, inputName);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
auto it = m_current->attachmentsByName.find(attachmentName);
|
||||
if (it == m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("unknown attachment {}", attachmentName);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
m_current->passList->SetPassInput(passId, inputIndex, it->second);
|
||||
}
|
||||
|
||||
for (auto&& [outputName, attachmentName] : outputs)
|
||||
{
|
||||
std::size_t inputIndex = passRegistry.GetPassOutputIndex(implIndex, outputName);
|
||||
if (inputIndex == FramePipelinePassRegistry::InvalidIndex)
|
||||
{
|
||||
NazaraErrorFmt("pass {} has no output {}", impl, outputName);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
auto it = m_current->attachmentsByName.find(attachmentName);
|
||||
if (it == m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("unknown attachment {}", attachmentName);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
m_current->passList->SetPassOutput(passId, inputIndex, it->second);
|
||||
}
|
||||
|
||||
if (!depthstencilInput.empty())
|
||||
{
|
||||
auto it = m_current->attachmentsByName.find(depthstencilInput);
|
||||
if (it == m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("unknown attachment {}", depthstencilInput);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
m_current->passList->SetPassDepthStencilInput(passId, it->second);
|
||||
}
|
||||
|
||||
if (!depthstencilOutput.empty())
|
||||
{
|
||||
auto it = m_current->attachmentsByName.find(depthstencilOutput);
|
||||
if (it == m_current->attachmentsByName.end())
|
||||
{
|
||||
NazaraErrorFmt("unknown attachment {}", depthstencilOutput);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
m_current->passList->SetPassDepthStencilOutput(passId, it->second);
|
||||
}
|
||||
|
||||
for (const auto& flagStr : flags)
|
||||
{
|
||||
if (flagStr == "LightShadowing")
|
||||
m_current->passList->EnablePassFlags(passId, FramePipelinePassFlag::LightShadowing);
|
||||
else
|
||||
{
|
||||
NazaraErrorFmt("unknown pass flag {}", flagStr);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<std::string, ResourceLoadingError> GetKeyword(bool peek = false)
|
||||
{
|
||||
std::size_t beginOffset;
|
||||
do
|
||||
{
|
||||
auto result = EnsureLine();
|
||||
if (result.IsErr())
|
||||
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
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");
|
||||
return Err(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;
|
||||
}
|
||||
|
||||
|
||||
Result<std::string, ResourceLoadingError> GetString()
|
||||
{
|
||||
std::size_t beginOffset;
|
||||
do
|
||||
{
|
||||
auto result = EnsureLine();
|
||||
if (result.IsErr())
|
||||
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
|
||||
|
||||
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");
|
||||
return Err(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");
|
||||
return Err(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);
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
str.push_back(character);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
str.push_back(m_currentLine[i]);
|
||||
}
|
||||
}
|
||||
|
||||
NazaraError("unfinished string");
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
Result<void, ResourceLoadingError> 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())
|
||||
return Err(ResourceLoadingError::DecodingError);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
struct CurrentPassList
|
||||
{
|
||||
std::shared_ptr<PipelinePassList> passList;
|
||||
std::unordered_map<std::string /*attachmentName*/, std::size_t /*attachmentId*/> attachmentsByName;
|
||||
};
|
||||
|
||||
std::optional<CurrentPassList> m_current;
|
||||
std::string m_currentLine;
|
||||
|
||||
Stream& m_stream;
|
||||
};
|
||||
}
|
||||
|
||||
PipelinePassListLoader::Entry GetPipelinePassListLoader()
|
||||
{
|
||||
NAZARA_USE_ANONYMOUS_NAMESPACE
|
||||
|
||||
PipelinePassListLoader::Entry entry;
|
||||
entry.extensionSupport = [](std::string_view ext) { return ext == ".passlist"; };
|
||||
entry.streamLoader = [](Stream& stream, const PipelinePassListParams& parameters)
|
||||
{
|
||||
PassListLoader passListLoader(stream, parameters);
|
||||
return passListLoader.Parse();
|
||||
};
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_GRAPHICS_FORMATS_PIPELINEPASSLISTLOADER_HPP
|
||||
#define NAZARA_GRAPHICS_FORMATS_PIPELINEPASSLISTLOADER_HPP
|
||||
|
||||
#include <NazaraUtils/Prerequisites.hpp>
|
||||
#include <Nazara/Graphics/PipelinePassList.hpp>
|
||||
|
||||
namespace Nz::Loaders
|
||||
{
|
||||
PipelinePassListLoader::Entry GetPipelinePassListLoader();
|
||||
}
|
||||
|
||||
#endif // NAZARA_GRAPHICS_FORMATS_PIPELINEPASSLISTLOADER_HPP
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
#include <Nazara/Graphics/PostProcessPipelinePass.hpp>
|
||||
#include <Nazara/Graphics/PredefinedMaterials.hpp>
|
||||
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
|
||||
#include <Nazara/Graphics/Formats/PipelinePassListLoader.hpp>
|
||||
#include <Nazara/Graphics/Formats/TextureLoader.hpp>
|
||||
#include <Nazara/Utility/Font.hpp>
|
||||
#include <NZSL/Ast/AstSerializer.hpp>
|
||||
|
|
@ -158,6 +159,7 @@ namespace Nz
|
|||
Font::SetDefaultAtlas(std::make_shared<GuillotineTextureAtlas>(*m_renderDevice));
|
||||
|
||||
m_materialInstanceLoader.RegisterLoader(Loaders::GetMaterialInstanceLoader_Texture()); // texture to material loader
|
||||
m_pipelinePassListLoader.RegisterLoader(Loaders::GetPipelinePassListLoader()); // texture to material loader
|
||||
}
|
||||
|
||||
Graphics::~Graphics()
|
||||
|
|
@ -466,10 +468,11 @@ namespace Nz
|
|||
|
||||
void Graphics::RegisterPipelinePasses()
|
||||
{
|
||||
m_pipelinePassRegistry.RegisterPass<DepthPipelinePass>("Depth");
|
||||
m_pipelinePassRegistry.RegisterPass<ForwardPipelinePass>("Forward");
|
||||
m_pipelinePassRegistry.RegisterPass<PostProcessPipelinePass>("PostProcess");
|
||||
m_pipelinePassRegistry.RegisterPass<DepthPipelinePass>("Depth", {}, {});
|
||||
m_pipelinePassRegistry.RegisterPass<ForwardPipelinePass>("Forward", {}, { "Output" });
|
||||
m_pipelinePassRegistry.RegisterPass<PostProcessPipelinePass>("PostProcess", { "Input" }, { "Output" });
|
||||
}
|
||||
|
||||
void Graphics::RegisterShaderModules()
|
||||
{
|
||||
m_shaderModuleResolver = std::make_shared<nzsl::FilesystemModuleResolver>();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
bool PipelinePassListParams::IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<FramePipelinePass>> PipelinePassList::BuildPasses(FramePipelinePass::PassData& passData) const
|
||||
{
|
||||
auto& passRegistry = Graphics::Instance()->GetFramePipelinePassRegistry();
|
||||
|
|
@ -66,4 +71,28 @@ namespace Nz
|
|||
|
||||
return GetAttachmentIndex(m_finalOutputAttachment);
|
||||
}
|
||||
|
||||
std::shared_ptr<PipelinePassList> PipelinePassList::LoadFromFile(const std::filesystem::path& filePath, const PipelinePassListParams& params)
|
||||
{
|
||||
Graphics* graphics = Graphics::Instance();
|
||||
NazaraAssert(graphics, "Graphics module has not been initialized");
|
||||
|
||||
return graphics->GetPipelinePassListLoader().LoadFromFile(filePath, params);
|
||||
}
|
||||
|
||||
std::shared_ptr<PipelinePassList> PipelinePassList::LoadFromMemory(const void* data, std::size_t size, const PipelinePassListParams& params)
|
||||
{
|
||||
Graphics* graphics = Graphics::Instance();
|
||||
NazaraAssert(graphics, "Graphics module has not been initialized");
|
||||
|
||||
return graphics->GetPipelinePassListLoader().LoadFromMemory(data, size, params);
|
||||
}
|
||||
|
||||
std::shared_ptr<PipelinePassList> PipelinePassList::LoadFromStream(Stream& stream, const PipelinePassListParams& params)
|
||||
{
|
||||
Graphics* graphics = Graphics::Instance();
|
||||
NazaraAssert(graphics, "Graphics module has not been initialized");
|
||||
|
||||
return graphics->GetPipelinePassListLoader().LoadFromStream(stream, params);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1467,19 +1467,6 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
PixelFormat PixelFormatInfo::IdentifyFormat(const PixelFormatDescription& info)
|
||||
{
|
||||
for (auto&& [format, formatDesc] : s_pixelFormatInfos.iter_kv())
|
||||
{
|
||||
if (info.bitsPerPixel == formatDesc.bitsPerPixel && info.content == formatDesc.content &&
|
||||
info.redMask == formatDesc.redMask && info.greenMask == formatDesc.greenMask && info.blueMask == formatDesc.blueMask && info.alphaMask == formatDesc.alphaMask &&
|
||||
info.redType == formatDesc.redType && info.greenType == formatDesc.greenType && info.blueType == formatDesc.blueType && info.alphaType == formatDesc.alphaType)
|
||||
return format;
|
||||
}
|
||||
|
||||
return PixelFormat::Undefined;
|
||||
}
|
||||
|
||||
bool PixelFormatInfo::Initialize()
|
||||
{
|
||||
NAZARA_USE_ANONYMOUS_NAMESPACE
|
||||
|
|
|
|||
Loading…
Reference in New Issue