Graphics: rework ubershaders to prevent duplicate shaders modules

Also rename all remaining conditions to options
This commit is contained in:
Jérôme Leclercq 2021-07-08 14:52:39 +02:00
parent 9ab47edd11
commit a895e553d4
38 changed files with 524 additions and 485 deletions

View File

@ -56,7 +56,7 @@ namespace Nz
}; };
private: private:
struct ConditionIndexes struct OptionIndexes
{ {
std::size_t alphaTest; std::size_t alphaTest;
std::size_t hasAlphaMap; std::size_t hasAlphaMap;
@ -74,13 +74,13 @@ namespace Nz
Material& m_material; Material& m_material;
std::size_t m_uniformBlockIndex; std::size_t m_uniformBlockIndex;
ConditionIndexes m_conditionIndexes; OptionIndexes m_optionIndexes;
TextureIndexes m_textureIndexes; TextureIndexes m_textureIndexes;
UniformOffsets m_uniformOffsets; UniformOffsets m_uniformOffsets;
static std::shared_ptr<MaterialSettings> s_materialSettings; static std::shared_ptr<MaterialSettings> s_materialSettings;
static std::size_t s_uniformBlockIndex; static std::size_t s_uniformBlockIndex;
static ConditionIndexes s_conditionIndexes; static OptionIndexes s_optionIndexes;
static TextureIndexes s_textureIndexes; static TextureIndexes s_textureIndexes;
static UniformOffsets s_uniformOffsets; static UniformOffsets s_uniformOffsets;
}; };

View File

@ -25,8 +25,8 @@ namespace Nz
*/ */
inline void BasicMaterial::EnableAlphaTest(bool alphaTest) inline void BasicMaterial::EnableAlphaTest(bool alphaTest)
{ {
NazaraAssert(HasAlphaTest(), "Material has no alpha test condition"); NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
m_material.EnableCondition(m_conditionIndexes.alphaTest, alphaTest); m_material.EnableOption(m_optionIndexes.alphaTest, alphaTest);
} }
inline const std::shared_ptr<Texture>& BasicMaterial::GetAlphaMap() const inline const std::shared_ptr<Texture>& BasicMaterial::GetAlphaMap() const
@ -55,8 +55,8 @@ namespace Nz
inline bool BasicMaterial::IsAlphaTestEnabled() const inline bool BasicMaterial::IsAlphaTestEnabled() const
{ {
NazaraAssert(HasAlphaTest(), "Material has no alpha test condition"); NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
return m_material.IsConditionEnabled(m_conditionIndexes.alphaTest); return m_material.IsOptionEnabled(m_optionIndexes.alphaTest);
} }
inline bool BasicMaterial::HasAlphaMap() const inline bool BasicMaterial::HasAlphaMap() const
@ -66,7 +66,7 @@ namespace Nz
inline bool BasicMaterial::HasAlphaTest() const inline bool BasicMaterial::HasAlphaTest() const
{ {
return m_conditionIndexes.alphaTest != MaterialSettings::InvalidIndex; return m_optionIndexes.alphaTest != MaterialSettings::InvalidIndex;
} }
inline bool BasicMaterial::HasAlphaTestThreshold() const inline bool BasicMaterial::HasAlphaTestThreshold() const
@ -90,8 +90,8 @@ namespace Nz
bool hasAlphaMap = (alphaMap != nullptr); bool hasAlphaMap = (alphaMap != nullptr);
m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap)); m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap));
if (m_conditionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex) if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.EnableCondition(m_conditionIndexes.hasAlphaMap, hasAlphaMap); m_material.EnableOption(m_optionIndexes.hasAlphaMap, hasAlphaMap);
} }
inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler) inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler)
@ -106,8 +106,8 @@ namespace Nz
bool hasDiffuseMap = (diffuseMap != nullptr); bool hasDiffuseMap = (diffuseMap != nullptr);
m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap)); m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap));
if (m_conditionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex) if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.EnableCondition(m_conditionIndexes.hasDiffuseMap, hasDiffuseMap); m_material.EnableOption(m_optionIndexes.hasDiffuseMap, hasDiffuseMap);
} }
inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler) inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler)

View File

@ -41,11 +41,11 @@ namespace Nz
inline void EnableBlending(bool blending); inline void EnableBlending(bool blending);
inline void EnableColorWrite(bool colorWrite); inline void EnableColorWrite(bool colorWrite);
inline void EnableCondition(std::size_t conditionIndex, bool enable);
inline void EnableDepthBuffer(bool depthBuffer); inline void EnableDepthBuffer(bool depthBuffer);
inline void EnableDepthSorting(bool depthSorting); inline void EnableDepthSorting(bool depthSorting);
inline void EnableDepthWrite(bool depthWrite); inline void EnableDepthWrite(bool depthWrite);
inline void EnableFaceCulling(bool faceCulling); inline void EnableFaceCulling(bool faceCulling);
inline void EnableOption(std::size_t optionIndex, bool enable);
inline void EnableReflectionMapping(bool reflection); inline void EnableReflectionMapping(bool reflection);
inline void EnableScissorTest(bool scissorTest); inline void EnableScissorTest(bool scissorTest);
inline void EnableShadowCasting(bool castShadows); inline void EnableShadowCasting(bool castShadows);
@ -83,11 +83,11 @@ namespace Nz
inline bool IsBlendingEnabled() const; inline bool IsBlendingEnabled() const;
inline bool IsColorWriteEnabled() const; inline bool IsColorWriteEnabled() const;
inline bool IsConditionEnabled(std::size_t conditionIndex) const;
inline bool IsDepthBufferEnabled() const; inline bool IsDepthBufferEnabled() const;
inline bool IsDepthSortingEnabled() const; inline bool IsDepthSortingEnabled() const;
inline bool IsDepthWriteEnabled() const; inline bool IsDepthWriteEnabled() const;
inline bool IsFaceCullingEnabled() const; inline bool IsFaceCullingEnabled() const;
inline bool IsOptionEnabled(std::size_t optionIndex) const;
inline bool IsReflectionMappingEnabled() const; inline bool IsReflectionMappingEnabled() const;
inline bool IsScissorTestEnabled() const; inline bool IsScissorTestEnabled() const;
inline bool IsStencilTestEnabled() const; inline bool IsStencilTestEnabled() const;
@ -117,7 +117,7 @@ namespace Nz
inline void InvalidateShaderBinding(); inline void InvalidateShaderBinding();
inline void InvalidateTextureSampler(std::size_t textureIndex); inline void InvalidateTextureSampler(std::size_t textureIndex);
inline void InvalidateUniformData(std::size_t uniformBufferIndex); inline void InvalidateUniformData(std::size_t uniformBufferIndex);
inline void UpdatePipeline() const; void UpdatePipeline() const;
void UpdateShaderBinding(); void UpdateShaderBinding();
struct MaterialTexture struct MaterialTexture
@ -138,7 +138,7 @@ namespace Nz
std::vector<MaterialTexture> m_textures; std::vector<MaterialTexture> m_textures;
std::vector<UniformBuffer> m_uniformBuffers; std::vector<UniformBuffer> m_uniformBuffers;
mutable std::shared_ptr<MaterialPipeline> m_pipeline; mutable std::shared_ptr<MaterialPipeline> m_pipeline;
UInt64 m_enabledConditions; UInt64 m_enabledOptions;
mutable MaterialPipelineInfo m_pipelineInfo; mutable MaterialPipelineInfo m_pipelineInfo;
ShaderBindingPtr m_shaderBinding; ShaderBindingPtr m_shaderBinding;
mutable bool m_pipelineUpdated; mutable bool m_pipelineUpdated;

View File

@ -90,15 +90,6 @@ namespace Nz
InvalidatePipeline(); InvalidatePipeline();
} }
inline void Material::EnableCondition(std::size_t conditionIndex, bool enable)
{
if (TestBit<UInt64>(m_enabledConditions, conditionIndex) != enable)
{
m_enabledConditions = ToggleBit<UInt64>(m_enabledConditions, conditionIndex);
InvalidatePipeline();
}
}
/*! /*!
* \brief Enable/Disable depth buffer for this material * \brief Enable/Disable depth buffer for this material
* *
@ -189,6 +180,15 @@ namespace Nz
InvalidatePipeline(); InvalidatePipeline();
} }
inline void Material::EnableOption(std::size_t optionIndex, bool enable)
{
if (TestBit<UInt64>(m_enabledOptions, optionIndex) != enable)
{
m_enabledOptions = ToggleBit<UInt64>(m_enabledOptions, optionIndex);
InvalidatePipeline();
}
}
/*! /*!
* \brief Enable/Disable reflection mapping for this material * \brief Enable/Disable reflection mapping for this material
* *
@ -515,11 +515,6 @@ namespace Nz
return m_pipelineInfo.colorWrite; return m_pipelineInfo.colorWrite;
} }
inline bool Material::IsConditionEnabled(std::size_t conditionIndex) const
{
return TestBit<UInt64>(m_enabledConditions, conditionIndex);
}
/*! /*!
* \brief Checks whether this material has depth buffer enabled * \brief Checks whether this material has depth buffer enabled
* \return true If it is the case * \return true If it is the case
@ -556,6 +551,11 @@ namespace Nz
return m_pipelineInfo.faceCulling; return m_pipelineInfo.faceCulling;
} }
inline bool Material::IsOptionEnabled(std::size_t optionIndex) const
{
return TestBit<UInt64>(m_enabledOptions, optionIndex);
}
/*! /*!
* \brief Checks whether this material has reflection mapping enabled * \brief Checks whether this material has reflection mapping enabled
* \return true If it is the case * \return true If it is the case
@ -766,25 +766,6 @@ namespace Nz
OnMaterialInvalidated(this); OnMaterialInvalidated(this);
} }
inline void Material::UpdatePipeline() const
{
for (auto& shader : m_pipelineInfo.shaders)
shader.enabledConditions = 0;
const auto& conditions = m_settings->GetConditions();
for (std::size_t conditionIndex = 0; conditionIndex < conditions.size(); ++conditionIndex)
{
if (TestBit<UInt64>(m_enabledConditions, conditionIndex))
{
for (std::size_t shaderStage = 0; shaderStage < ShaderStageTypeCount; ++shaderStage)
m_pipelineInfo.shaders[shaderStage].enabledConditions |= conditions[conditionIndex].enabledConditions[shaderStage];
}
}
m_pipeline = MaterialPipeline::Get(m_pipelineInfo);
m_pipelineUpdated = true;
}
} }
#include <Nazara/Graphics/DebugOff.hpp> #include <Nazara/Graphics/DebugOff.hpp>

View File

@ -21,10 +21,10 @@ namespace Nz
struct MaterialPipelineInfo : RenderStates struct MaterialPipelineInfo : RenderStates
{ {
struct ShaderStage struct Shader
{ {
std::shared_ptr<UberShader> uberShader; std::shared_ptr<UberShader> uberShader;
Nz::UInt64 enabledConditions = 0; Nz::UInt64 enabledOptions = 0;
}; };
bool depthSorting = false; bool depthSorting = false;
@ -32,7 +32,7 @@ namespace Nz
bool reflectionMapping = false; bool reflectionMapping = false;
bool shadowReceive = true; bool shadowReceive = true;
std::array<ShaderStage, ShaderStageTypeCount> shaders; std::vector<Shader> shaders;
std::shared_ptr<const MaterialSettings> settings; std::shared_ptr<const MaterialSettings> settings;
}; };

View File

@ -40,7 +40,7 @@ namespace Nz
for (std::size_t i = 0; i < lhs.shaders.size(); ++i) for (std::size_t i = 0; i < lhs.shaders.size(); ++i)
{ {
if (lhs.shaders[i].enabledConditions != rhs.shaders[i].enabledConditions) if (lhs.shaders[i].enabledOptions != rhs.shaders[i].enabledOptions)
return false; return false;
if (lhs.shaders[i].uberShader != rhs.shaders[i].uberShader) if (lhs.shaders[i].uberShader != rhs.shaders[i].uberShader)
@ -85,7 +85,7 @@ namespace std
for (const auto& shader : pipelineInfo.shaders) for (const auto& shader : pipelineInfo.shaders)
{ {
Nz::HashCombine(seed, shader.enabledConditions); Nz::HashCombine(seed, shader.enabledOptions);
Nz::HashCombine(seed, shader.uberShader.get()); Nz::HashCombine(seed, shader.uberShader.get());
} }

View File

@ -24,10 +24,8 @@ namespace Nz
class MaterialSettings class MaterialSettings
{ {
public: public:
using Shaders = std::array<std::shared_ptr<UberShader>, ShaderStageTypeCount>;
struct Builder; struct Builder;
struct Condition; struct Option;
struct SharedUniformBlock; struct SharedUniformBlock;
struct Texture; struct Texture;
struct UniformBlock; struct UniformBlock;
@ -39,11 +37,11 @@ namespace Nz
~MaterialSettings() = default; ~MaterialSettings() = default;
inline const Builder& GetBuilderData() const; inline const Builder& GetBuilderData() const;
inline const std::vector<Condition>& GetConditions() const; inline const std::vector<Option>& GetOptions() const;
inline std::size_t GetConditionIndex(const std::string_view& name) const; inline std::size_t GetOptionIndex(const std::string_view& name) const;
inline const std::shared_ptr<RenderPipelineLayout>& GetRenderPipelineLayout() const; inline const std::shared_ptr<RenderPipelineLayout>& GetRenderPipelineLayout() const;
inline const std::shared_ptr<UberShader>& GetShader(ShaderStageType stage) const; inline const std::shared_ptr<UberShader>& GetShader(ShaderStageType stage) const;
inline const Shaders& GetShaders() const; inline const std::vector<std::shared_ptr<UberShader>>& GetShaders() const;
inline const std::vector<SharedUniformBlock>& GetSharedUniformBlocks() const; inline const std::vector<SharedUniformBlock>& GetSharedUniformBlocks() const;
inline std::size_t GetSharedUniformBlockIndex(const std::string_view& name) const; inline std::size_t GetSharedUniformBlockIndex(const std::string_view& name) const;
inline std::size_t GetSharedUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const; inline std::size_t GetSharedUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const;
@ -60,17 +58,17 @@ namespace Nz
struct Builder struct Builder
{ {
Shaders shaders; std::vector<std::shared_ptr<UberShader>> shaders;
std::vector<Condition> conditions; std::vector<Option> options;
std::vector<Texture> textures; std::vector<Texture> textures;
std::vector<UniformBlock> uniformBlocks; std::vector<UniformBlock> uniformBlocks;
std::vector<SharedUniformBlock> sharedUniformBlocks; std::vector<SharedUniformBlock> sharedUniformBlocks;
}; };
struct Condition struct Option
{ {
std::string name; std::string name;
std::array<UInt64, ShaderStageTypeCount> enabledConditions; std::array<UInt64, ShaderStageTypeCount> enabledOptions;
}; };
struct UniformVariable struct UniformVariable

View File

@ -59,16 +59,16 @@ namespace Nz
return m_data; return m_data;
} }
inline auto MaterialSettings::GetConditions() const -> const std::vector<Condition>& inline auto MaterialSettings::GetOptions() const -> const std::vector<Option>&
{ {
return m_data.conditions; return m_data.options;
} }
inline std::size_t MaterialSettings::GetConditionIndex(const std::string_view& name) const inline std::size_t MaterialSettings::GetOptionIndex(const std::string_view& name) const
{ {
for (std::size_t i = 0; i < m_data.conditions.size(); ++i) for (std::size_t i = 0; i < m_data.options.size(); ++i)
{ {
if (m_data.conditions[i].name == name) if (m_data.options[i].name == name)
return i; return i;
} }
@ -85,7 +85,7 @@ namespace Nz
return m_data.shaders[UnderlyingCast(stage)]; return m_data.shaders[UnderlyingCast(stage)];
} }
inline auto MaterialSettings::GetShaders() const -> const Shaders& inline const std::vector<std::shared_ptr<UberShader>>& MaterialSettings::GetShaders() const
{ {
return m_data.shaders; return m_data.shaders;
} }

View File

@ -20,18 +20,20 @@ namespace Nz
class NAZARA_GRAPHICS_API UberShader class NAZARA_GRAPHICS_API UberShader
{ {
public: public:
UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst); UberShader(ShaderStageTypeFlags shaderStages, const ShaderAst::StatementPtr& shaderAst);
~UberShader() = default; ~UberShader() = default;
UInt64 GetOptionFlagByName(const std::string& optionName) const; UInt64 GetOptionFlagByName(const std::string& optionName) const;
inline ShaderStageTypeFlags GetSupportedStages() const;
const std::shared_ptr<ShaderModule>& Get(UInt64 combination); const std::shared_ptr<ShaderModule>& Get(UInt64 combination);
private: private:
std::unordered_map<UInt64 /*combination*/, std::shared_ptr<ShaderModule>> m_combinations; std::unordered_map<UInt64 /*combination*/, std::shared_ptr<ShaderModule>> m_combinations;
std::unordered_map<std::string, std::size_t> m_optionIndexByName; std::unordered_map<std::string, std::size_t> m_optionIndexByName;
ShaderAst::StatementPtr m_shaderAst; ShaderAst::StatementPtr m_shaderAst;
ShaderStageType m_shaderStage; ShaderStageTypeFlags m_shaderStages;
UInt64 m_combinationMask; UInt64 m_combinationMask;
}; };
} }

View File

@ -7,6 +7,10 @@
namespace Nz namespace Nz
{ {
inline ShaderStageTypeFlags UberShader::GetSupportedStages() const
{
return m_shaderStages;
}
} }
#include <Nazara/Graphics/DebugOff.hpp> #include <Nazara/Graphics/DebugOff.hpp>

View File

@ -31,10 +31,12 @@ namespace Nz::ShaderAst
struct Callbacks struct Callbacks
{ {
std::function<void(ShaderStageType stageType, const std::string& functionName)> onEntryPointDeclaration;
std::function<void(const std::string& optionName, const ExpressionType& optionType)> onOptionDeclaration; std::function<void(const std::string& optionName, const ExpressionType& optionType)> onOptionDeclaration;
}; };
private: private:
void Visit(DeclareFunctionStatement& node) override;
void Visit(DeclareOptionStatement& node) override; void Visit(DeclareOptionStatement& node) override;
const Callbacks* m_callbacks; const Callbacks* m_callbacks;

View File

@ -46,7 +46,7 @@ namespace Nz
}; };
static const char* GetFlipYUniformName(); static const char* GetFlipYUniformName();
static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, UInt64 enabledConditions, std::string* error = nullptr); static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, UInt64 enabledOptions, std::string* error = nullptr);
private: private:
void Append(const ShaderAst::ExpressionType& type); void Append(const ShaderAst::ExpressionType& type);

View File

@ -33,16 +33,16 @@ namespace Nz
const std::shared_ptr<const MaterialSettings>& materialSettings = material.GetSettings(); const std::shared_ptr<const MaterialSettings>& materialSettings = material.GetSettings();
if (materialSettings == s_materialSettings) if (materialSettings == s_materialSettings)
{ {
m_conditionIndexes = s_conditionIndexes; m_optionIndexes = s_optionIndexes;
m_textureIndexes = s_textureIndexes; m_textureIndexes = s_textureIndexes;
m_uniformBlockIndex = s_uniformBlockIndex; m_uniformBlockIndex = s_uniformBlockIndex;
m_uniformOffsets = s_uniformOffsets; m_uniformOffsets = s_uniformOffsets;
} }
else else
{ {
m_conditionIndexes.alphaTest = materialSettings->GetConditionIndex("AlphaTest"); m_optionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest");
m_conditionIndexes.hasAlphaMap = materialSettings->GetConditionIndex("HasAlphaMap"); m_optionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap");
m_conditionIndexes.hasDiffuseMap = materialSettings->GetConditionIndex("HasDiffuseMap"); m_optionIndexes.hasDiffuseMap = materialSettings->GetOptionIndex("HasDiffuseMap");
m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha"); m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse"); m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse");
@ -146,54 +146,51 @@ namespace Nz
}); });
// Shaders // Shaders
auto& fragmentShader = settings.shaders[UnderlyingCast(ShaderStageType::Fragment)];
auto& vertexShader = settings.shaders[UnderlyingCast(ShaderStageType::Vertex)];
ShaderAst::StatementPtr shaderAst = ShaderLang::Parse(std::string_view(reinterpret_cast<const char*>(r_shader), sizeof(r_shader))); ShaderAst::StatementPtr shaderAst = ShaderLang::Parse(std::string_view(reinterpret_cast<const char*>(r_shader), sizeof(r_shader)));
auto uberShader = std::make_shared<UberShader>(ShaderStageType::Fragment | ShaderStageType::Vertex, shaderAst);
fragmentShader = std::make_shared<UberShader>(ShaderStageType::Fragment, shaderAst); settings.shaders.emplace_back(uberShader);
vertexShader = std::make_shared<UberShader>(ShaderStageType::Vertex, shaderAst);
// Conditions // Options
// HasDiffuseMap // HasDiffuseMap
{ {
std::array<UInt64, ShaderStageTypeCount> shaderConditions; std::array<UInt64, ShaderStageTypeCount> shaderOptions;
shaderConditions.fill(0); shaderOptions.fill(0);
shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE"); shaderOptions[UnderlyingCast(ShaderStageType::Fragment)] = uberShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE");
shaderConditions[UnderlyingCast(ShaderStageType::Vertex)] = vertexShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE"); shaderOptions[UnderlyingCast(ShaderStageType::Vertex)] = uberShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE");
s_conditionIndexes.hasDiffuseMap = settings.conditions.size(); s_optionIndexes.hasDiffuseMap = settings.options.size();
settings.conditions.push_back({ settings.options.push_back({
"HasDiffuseMap", "HasDiffuseMap",
shaderConditions shaderOptions
}); });
} }
// HasAlphaMap // HasAlphaMap
{ {
std::array<UInt64, ShaderStageTypeCount> shaderConditions; std::array<UInt64, ShaderStageTypeCount> shaderOptions;
shaderConditions.fill(0); shaderOptions.fill(0);
shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE"); shaderOptions[UnderlyingCast(ShaderStageType::Fragment)] = uberShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE");
shaderConditions[UnderlyingCast(ShaderStageType::Vertex)] = vertexShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE"); shaderOptions[UnderlyingCast(ShaderStageType::Vertex)] = uberShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE");
s_conditionIndexes.hasAlphaMap = settings.conditions.size(); s_optionIndexes.hasAlphaMap = settings.options.size();
settings.conditions.push_back({ settings.options.push_back({
"HasAlphaMap", "HasAlphaMap",
shaderConditions shaderOptions
}); });
} }
// AlphaTest // AlphaTest
{ {
std::array<UInt64, ShaderStageTypeCount> shaderConditions; std::array<UInt64, ShaderStageTypeCount> shaderOptions;
shaderConditions.fill(0); shaderOptions.fill(0);
shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("ALPHA_TEST"); shaderOptions[UnderlyingCast(ShaderStageType::Fragment)] = uberShader->GetOptionFlagByName("ALPHA_TEST");
s_conditionIndexes.alphaTest = settings.conditions.size(); s_optionIndexes.alphaTest = settings.options.size();
settings.conditions.push_back({ settings.options.push_back({
"AlphaTest", "AlphaTest",
shaderConditions shaderOptions
}); });
} }
@ -209,7 +206,7 @@ namespace Nz
std::shared_ptr<MaterialSettings> BasicMaterial::s_materialSettings; std::shared_ptr<MaterialSettings> BasicMaterial::s_materialSettings;
std::size_t BasicMaterial::s_uniformBlockIndex; std::size_t BasicMaterial::s_uniformBlockIndex;
BasicMaterial::ConditionIndexes BasicMaterial::s_conditionIndexes; BasicMaterial::OptionIndexes BasicMaterial::s_optionIndexes;
BasicMaterial::TextureIndexes BasicMaterial::s_textureIndexes; BasicMaterial::TextureIndexes BasicMaterial::s_textureIndexes;
BasicMaterial::UniformOffsets BasicMaterial::s_uniformOffsets; BasicMaterial::UniformOffsets BasicMaterial::s_uniformOffsets;
} }

View File

@ -5,6 +5,7 @@
#include <Nazara/Graphics/Material.hpp> #include <Nazara/Graphics/Material.hpp>
#include <Nazara/Core/ErrorFlags.hpp> #include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp> #include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/UberShader.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp> #include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/Renderer.hpp> #include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/RenderFrame.hpp> #include <Nazara/Renderer/RenderFrame.hpp>
@ -27,7 +28,7 @@ namespace Nz
*/ */
Material::Material(std::shared_ptr<const MaterialSettings> settings) : Material::Material(std::shared_ptr<const MaterialSettings> settings) :
m_settings(std::move(settings)), m_settings(std::move(settings)),
m_enabledConditions(0), m_enabledOptions(0),
m_pipelineUpdated(false), m_pipelineUpdated(false),
m_shaderBindingUpdated(false), m_shaderBindingUpdated(false),
m_shadowCastingEnabled(true) m_shadowCastingEnabled(true)
@ -35,8 +36,11 @@ namespace Nz
m_pipelineInfo.settings = m_settings; m_pipelineInfo.settings = m_settings;
const auto& shaders = m_settings->GetShaders(); const auto& shaders = m_settings->GetShaders();
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i) for (const auto& shader : shaders)
m_pipelineInfo.shaders[i].uberShader = shaders[i]; {
auto& shaderData = m_pipelineInfo.shaders.emplace_back();
shaderData.uberShader = shader;
}
const auto& textureSettings = m_settings->GetTextures(); const auto& textureSettings = m_settings->GetTextures();
const auto& uboSettings = m_settings->GetUniformBlocks(); const auto& uboSettings = m_settings->GetUniformBlocks();
@ -92,6 +96,33 @@ namespace Nz
return shouldRegenerateCommandBuffer; return shouldRegenerateCommandBuffer;
} }
void Material::UpdatePipeline() const
{
for (auto& shader : m_pipelineInfo.shaders)
shader.enabledOptions = 0;
const auto& options = m_settings->GetOptions();
for (std::size_t optionIndex = 0; optionIndex < options.size(); ++optionIndex)
{
if (TestBit<UInt64>(m_enabledOptions, optionIndex))
{
for (auto& shader : m_pipelineInfo.shaders)
{
ShaderStageTypeFlags supportedStages = shader.uberShader->GetSupportedStages();
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
{
ShaderStageType shaderStage = static_cast<ShaderStageType>(i);
if (supportedStages & shaderStage)
shader.enabledOptions |= options[optionIndex].enabledOptions[i];
}
}
}
}
m_pipeline = MaterialPipeline::Get(m_pipelineInfo);
m_pipelineUpdated = true;
}
void Material::UpdateShaderBinding() void Material::UpdateShaderBinding()
{ {
assert(!m_shaderBinding); assert(!m_shaderBinding);

View File

@ -48,10 +48,10 @@ namespace Nz
renderPipelineInfo.pipelineLayout = m_pipelineInfo.settings->GetRenderPipelineLayout(); renderPipelineInfo.pipelineLayout = m_pipelineInfo.settings->GetRenderPipelineLayout();
for (const auto& shaderEntry : m_pipelineInfo.shaders) for (const auto& shader : m_pipelineInfo.shaders)
{ {
if (shaderEntry.uberShader) if (shader.uberShader)
renderPipelineInfo.shaderModules.push_back(shaderEntry.uberShader->Get(shaderEntry.enabledConditions)); renderPipelineInfo.shaderModules.push_back(shader.uberShader->Get(shader.enabledOptions));
} }
renderPipelineInfo.vertexBuffers = vertexBuffers; renderPipelineInfo.vertexBuffers = vertexBuffers;

View File

@ -13,15 +13,24 @@
namespace Nz namespace Nz
{ {
UberShader::UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst) : UberShader::UberShader(ShaderStageTypeFlags shaderStages, const ShaderAst::StatementPtr& shaderAst) :
m_shaderStage(shaderStage) m_shaderStages(shaderStages)
{ {
NazaraAssert(m_shaderStages != 0, "there must be at least one shader stage");
//TODO: Try to partially sanitize shader? //TODO: Try to partially sanitize shader?
m_shaderAst = ShaderAst::Clone(*shaderAst); m_shaderAst = ShaderAst::Clone(*shaderAst);
std::size_t optionCount = 0; std::size_t optionCount = 0;
ShaderStageTypeFlags supportedStageType;
ShaderAst::AstReflect::Callbacks callbacks; ShaderAst::AstReflect::Callbacks callbacks;
callbacks.onEntryPointDeclaration = [&](ShaderStageType stageType, const std::string& /*name*/)
{
supportedStageType |= stageType;
};
callbacks.onOptionDeclaration = [&](const std::string& optionName, const ShaderAst::ExpressionType& optionType) callbacks.onOptionDeclaration = [&](const std::string& optionName, const ShaderAst::ExpressionType& optionType)
{ {
m_optionIndexByName[optionName] = optionCount; m_optionIndexByName[optionName] = optionCount;
@ -31,6 +40,9 @@ namespace Nz
ShaderAst::AstReflect reflect; ShaderAst::AstReflect reflect;
reflect.Reflect(*m_shaderAst, callbacks); reflect.Reflect(*m_shaderAst, callbacks);
if (m_shaderStages & shaderStages != m_shaderStages)
throw std::runtime_error("shader doesn't support all required shader stages");
if (optionCount >= 64) if (optionCount >= 64)
throw std::runtime_error("Too many conditions"); throw std::runtime_error("Too many conditions");
@ -58,7 +70,7 @@ namespace Nz
ShaderWriter::States states; ShaderWriter::States states;
states.enabledOptions = combination; states.enabledOptions = combination;
std::shared_ptr<ShaderModule> stage = Graphics::Instance()->GetRenderDevice()->InstantiateShaderModule(m_shaderStage, *m_shaderAst, std::move(states)); std::shared_ptr<ShaderModule> stage = Graphics::Instance()->GetRenderDevice()->InstantiateShaderModule(m_shaderStages, *m_shaderAst, std::move(states));
it = m_combinations.emplace(combination, std::move(stage)).first; it = m_combinations.emplace(combination, std::move(stage)).first;
} }

View File

@ -14,6 +14,18 @@ namespace Nz::ShaderAst
statement.Visit(*this); statement.Visit(*this);
} }
void AstReflect::Visit(DeclareFunctionStatement& node)
{
assert(m_callbacks);
if (m_callbacks->onEntryPointDeclaration)
{
if (!node.entryStage.HasValue())
return;
m_callbacks->onEntryPointDeclaration(node.entryStage.GetResultingValue(), node.name);
}
}
void AstReflect::Visit(DeclareOptionStatement& node) void AstReflect::Visit(DeclareOptionStatement& node)
{ {
assert(m_callbacks); assert(m_callbacks);

View File

@ -203,11 +203,11 @@ namespace Nz
return s_flipYUniformName; return s_flipYUniformName;
} }
ShaderAst::StatementPtr GlslWriter::Sanitize(ShaderAst::Statement& ast, UInt64 enabledConditions, std::string* error) ShaderAst::StatementPtr GlslWriter::Sanitize(ShaderAst::Statement& ast, UInt64 enabledOptions, std::string* error)
{ {
// Always sanitize for reserved identifiers // Always sanitize for reserved identifiers
ShaderAst::SanitizeVisitor::Options options; ShaderAst::SanitizeVisitor::Options options;
options.enabledOptions = enabledConditions; options.enabledOptions = enabledOptions;
options.makeVariableNameUnique = true; options.makeVariableNameUnique = true;
options.reservedIdentifiers = { options.reservedIdentifiers = {
// All reserved GLSL keywords as of GLSL ES 3.2 // All reserved GLSL keywords as of GLSL ES 3.2

View File

@ -14,20 +14,20 @@
ConditionalExpression::ConditionalExpression(ShaderGraph& graph) : ConditionalExpression::ConditionalExpression(ShaderGraph& graph) :
ShaderNode(graph) ShaderNode(graph)
{ {
m_onConditionListUpdateSlot.Connect(GetGraph().OnConditionListUpdate, [&](ShaderGraph*) { OnConditionListUpdate(); }); m_onOptionListUpdateSlot.Connect(GetGraph().OnOptionListUpdate, [&](ShaderGraph*) { OnOptionListUpdate(); });
m_onConditionUpdateSlot.Connect(GetGraph().OnConditionUpdate, [&](ShaderGraph*, std::size_t conditionIndex) m_onOptionUpdateSlot.Connect(GetGraph().OnOptionUpdate, [&](ShaderGraph*, std::size_t optionIndex)
{ {
if (m_currentConditionIndex == conditionIndex) if (m_currentOptionIndex == optionIndex)
{ {
UpdatePreview(); UpdatePreview();
Q_EMIT dataUpdated(0); Q_EMIT dataUpdated(0);
} }
}); });
if (graph.GetConditionCount() > 0) if (graph.GetOptionCount() > 0)
{ {
m_currentConditionIndex = 0; m_currentOptionIndex = 0;
UpdateConditionText(); UpdateOptionText();
} }
EnablePreview(); EnablePreview();
@ -40,18 +40,18 @@ Nz::ShaderAst::NodePtr ConditionalExpression::BuildNode(Nz::ShaderAst::Expressio
assert(count == 2); assert(count == 2);
assert(outputIndex == 0); assert(outputIndex == 0);
if (!m_currentConditionIndex) if (!m_currentOptionIndex)
throw std::runtime_error("no condition"); throw std::runtime_error("no option");
const ShaderGraph& graph = GetGraph(); const ShaderGraph& graph = GetGraph();
const auto& conditionEntry = graph.GetCondition(*m_currentConditionIndex); const auto& optionEntry = graph.GetOption(*m_currentOptionIndex);
return Nz::ShaderBuilder::ConditionalExpression(Nz::ShaderBuilder::Identifier(conditionEntry.name), std::move(expressions[0]), std::move(expressions[1])); return Nz::ShaderBuilder::ConditionalExpression(Nz::ShaderBuilder::Identifier(optionEntry.name), std::move(expressions[0]), std::move(expressions[1]));
} }
QString ConditionalExpression::caption() const QString ConditionalExpression::caption() const
{ {
return "ConditionalExpression (" + QString::fromStdString(m_currentConditionText) + ")"; return "ConditionalExpression (" + QString::fromStdString(m_currentOptionText) + ")";
} }
QString ConditionalExpression::name() const QString ConditionalExpression::name() const
@ -74,29 +74,29 @@ void ConditionalExpression::BuildNodeEdition(QFormLayout* layout)
{ {
ShaderNode::BuildNodeEdition(layout); ShaderNode::BuildNodeEdition(layout);
QComboBox* conditionSelection = new QComboBox; QComboBox* optionSelection = new QComboBox;
for (const auto& conditionEntry : GetGraph().GetConditions()) for (const auto& optionEntry : GetGraph().GetOptions())
conditionSelection->addItem(QString::fromStdString(conditionEntry.name)); optionSelection->addItem(QString::fromStdString(optionEntry.name));
if (m_currentConditionIndex) if (m_currentOptionIndex)
conditionSelection->setCurrentIndex(int(*m_currentConditionIndex)); optionSelection->setCurrentIndex(int(*m_currentOptionIndex));
else else
conditionSelection->setCurrentIndex(-1); optionSelection->setCurrentIndex(-1);
connect(conditionSelection, qOverload<int>(&QComboBox::currentIndexChanged), [&](int index) connect(optionSelection, qOverload<int>(&QComboBox::currentIndexChanged), [&](int index)
{ {
if (index >= 0) if (index >= 0)
m_currentConditionIndex = static_cast<std::size_t>(index); m_currentOptionIndex = static_cast<std::size_t>(index);
else else
m_currentConditionIndex.reset(); m_currentOptionIndex.reset();
UpdateConditionText(); UpdateOptionText();
UpdatePreview(); UpdatePreview();
Q_EMIT dataUpdated(0); Q_EMIT dataUpdated(0);
}); });
layout->addRow(tr("Condition"), conditionSelection); layout->addRow(tr("Option"), optionSelection);
} }
auto ConditionalExpression::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType auto ConditionalExpression::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType
@ -178,17 +178,17 @@ bool ConditionalExpression::portCaptionVisible(QtNodes::PortType portType, QtNod
std::shared_ptr<QtNodes::NodeData> ConditionalExpression::outData(QtNodes::PortIndex port) std::shared_ptr<QtNodes::NodeData> ConditionalExpression::outData(QtNodes::PortIndex port)
{ {
if (!m_currentConditionIndex) if (!m_currentOptionIndex)
return nullptr; return nullptr;
assert(port == 0); assert(port == 0);
return (GetGraph().IsConditionEnabled(*m_currentConditionIndex)) ? m_truePath : m_falsePath; return (GetGraph().IsOptionEnabled(*m_currentOptionIndex)) ? m_truePath : m_falsePath;
} }
void ConditionalExpression::restore(const QJsonObject& data) void ConditionalExpression::restore(const QJsonObject& data)
{ {
m_currentConditionText = data["condition_name"].toString().toStdString(); m_currentOptionText = data["option_name"].toString().toStdString();
OnConditionListUpdate(); OnOptionListUpdate();
ShaderNode::restore(data); ShaderNode::restore(data);
} }
@ -196,7 +196,7 @@ void ConditionalExpression::restore(const QJsonObject& data)
QJsonObject ConditionalExpression::save() const QJsonObject ConditionalExpression::save() const
{ {
QJsonObject data = ShaderNode::save(); QJsonObject data = ShaderNode::save();
data["condition_name"] = QString::fromStdString(m_currentConditionText); data["option_name"] = QString::fromStdString(m_currentOptionText);
return data; return data;
} }
@ -223,8 +223,8 @@ QtNodes::NodeValidationState ConditionalExpression::validationState() const
QString ConditionalExpression::validationMessage() const QString ConditionalExpression::validationMessage() const
{ {
if (!m_currentConditionIndex) if (!m_currentOptionIndex)
return "Invalid condition"; return "Invalid option";
if (!m_truePath || !m_falsePath) if (!m_truePath || !m_falsePath)
return "Missing input"; return "Missing input";
@ -234,7 +234,7 @@ QString ConditionalExpression::validationMessage() const
bool ConditionalExpression::ComputePreview(QPixmap& pixmap) bool ConditionalExpression::ComputePreview(QPixmap& pixmap)
{ {
if (!m_currentConditionIndex) if (!m_currentOptionIndex)
return false; return false;
auto input = outData(0); auto input = outData(0);
@ -248,30 +248,30 @@ bool ConditionalExpression::ComputePreview(QPixmap& pixmap)
return true; return true;
} }
void ConditionalExpression::OnConditionListUpdate() void ConditionalExpression::OnOptionListUpdate()
{ {
m_currentConditionIndex.reset(); m_currentOptionIndex.reset();
std::size_t conditionIndex = 0; std::size_t optionIndex = 0;
for (const auto& conditionEntry : GetGraph().GetConditions()) for (const auto& optionEntry : GetGraph().GetOptions())
{ {
if (conditionEntry.name == m_currentConditionText) if (optionEntry.name == m_currentOptionText)
{ {
m_currentConditionIndex = conditionIndex; m_currentOptionIndex = optionIndex;
break; break;
} }
conditionIndex++; optionIndex++;
} }
} }
void ConditionalExpression::UpdateConditionText() void ConditionalExpression::UpdateOptionText()
{ {
if (m_currentConditionIndex) if (m_currentOptionIndex)
{ {
auto& condition = GetGraph().GetCondition(*m_currentConditionIndex); auto& option = GetGraph().GetOption(*m_currentOptionIndex);
m_currentConditionText = condition.name; m_currentOptionText = option.name;
} }
else else
m_currentConditionText.clear(); m_currentOptionText.clear();
} }

View File

@ -40,16 +40,16 @@ class ConditionalExpression : public ShaderNode
private: private:
bool ComputePreview(QPixmap& pixmap) override; bool ComputePreview(QPixmap& pixmap) override;
void OnConditionListUpdate(); void OnOptionListUpdate();
void UpdateConditionText(); void UpdateOptionText();
NazaraSlot(ShaderGraph, OnConditionListUpdate, m_onConditionListUpdateSlot); NazaraSlot(ShaderGraph, OnOptionListUpdate, m_onOptionListUpdateSlot);
NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdateSlot); NazaraSlot(ShaderGraph, OnOptionUpdate, m_onOptionUpdateSlot);
std::optional<std::size_t> m_currentConditionIndex; std::optional<std::size_t> m_currentOptionIndex;
std::shared_ptr<QtNodes::NodeData> m_falsePath; std::shared_ptr<QtNodes::NodeData> m_falsePath;
std::shared_ptr<QtNodes::NodeData> m_truePath; std::shared_ptr<QtNodes::NodeData> m_truePath;
std::string m_currentConditionText; std::string m_currentOptionText;
}; };
#include <ShaderNode/DataModels/BufferField.inl> #include <ShaderNode/DataModels/BufferField.inl>

View File

@ -121,13 +121,13 @@ std::size_t ShaderGraph::AddBuffer(std::string name, BufferType bufferType, std:
return index; return index;
} }
std::size_t ShaderGraph::AddCondition(std::string name) std::size_t ShaderGraph::AddOption(std::string name)
{ {
std::size_t index = m_conditions.size(); std::size_t index = m_options.size();
auto& conditionEntry = m_conditions.emplace_back(); auto& optionEntry = m_options.emplace_back();
conditionEntry.name = std::move(name); optionEntry.name = std::move(name);
OnConditionListUpdate(this); OnOptionListUpdate(this);
return index; return index;
} }
@ -194,7 +194,7 @@ void ShaderGraph::Clear()
m_flowScene->clear(); m_flowScene->clear();
m_buffers.clear(); m_buffers.clear();
m_conditions.clear(); m_options.clear();
m_inputs.clear(); m_inputs.clear();
m_structs.clear(); m_structs.clear();
m_outputs.clear(); m_outputs.clear();
@ -207,13 +207,13 @@ void ShaderGraph::Clear()
OnTextureListUpdate(this); OnTextureListUpdate(this);
} }
void ShaderGraph::EnableCondition(std::size_t conditionIndex, bool enable) void ShaderGraph::EnableOption(std::size_t optionIndex, bool enable)
{ {
assert(conditionIndex < m_conditions.size()); assert(optionIndex < m_options.size());
auto& conditionEntry = m_conditions[conditionIndex]; auto& optionEntry = m_options[optionIndex];
conditionEntry.enabled = enable; optionEntry.enabled = enable;
OnConditionUpdate(this, conditionIndex); OnOptionUpdate(this, optionIndex);
} }
void ShaderGraph::Load(const QJsonObject& data) void ShaderGraph::Load(const QJsonObject& data)
@ -238,16 +238,16 @@ void ShaderGraph::Load(const QJsonObject& data)
OnBufferListUpdate(this); OnBufferListUpdate(this);
QJsonArray conditionArray = data["conditions"].toArray(); QJsonArray optionArray = data["options"].toArray();
for (const auto& conditionDocRef : conditionArray) for (const auto& optionDocRef : optionArray)
{ {
QJsonObject conditionDoc = conditionDocRef.toObject(); QJsonObject optionDoc = optionDocRef.toObject();
ConditionEntry& condition = m_conditions.emplace_back(); OptionEntry& option = m_options.emplace_back();
condition.name = conditionDoc["name"].toString().toStdString(); option.name = optionDoc["name"].toString().toStdString();
} }
OnConditionListUpdate(this); OnOptionListUpdate(this);
QJsonArray inputArray = data["inputs"].toArray(); QJsonArray inputArray = data["inputs"].toArray();
for (const auto& inputDocRef : inputArray) for (const auto& inputDocRef : inputArray)
@ -345,17 +345,17 @@ QJsonObject ShaderGraph::Save()
} }
sceneJson["buffers"] = bufferArray; sceneJson["buffers"] = bufferArray;
QJsonArray conditionArray; QJsonArray optionArray;
{ {
for (const auto& condition : m_conditions) for (const auto& option : m_options)
{ {
QJsonObject inputDoc; QJsonObject inputDoc;
inputDoc["name"] = QString::fromStdString(condition.name); inputDoc["name"] = QString::fromStdString(option.name);
conditionArray.append(inputDoc); optionArray.append(inputDoc);
} }
} }
sceneJson["conditions"] = conditionArray; sceneJson["options"] = optionArray;
QJsonArray inputArray; QJsonArray inputArray;
{ {
@ -462,8 +462,8 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() const
std::vector<Nz::ShaderAst::StatementPtr> statements; std::vector<Nz::ShaderAst::StatementPtr> statements;
// Declare all options // Declare all options
for (const auto& condition : m_conditions) for (const auto& option : m_options)
statements.push_back(Nz::ShaderBuilder::DeclareOption(condition.name, Nz::ShaderAst::PrimitiveType::Boolean)); statements.push_back(Nz::ShaderBuilder::DeclareOption(option.name, Nz::ShaderAst::PrimitiveType::Boolean));
// Declare all structures // Declare all structures
for (const auto& structInfo : m_structs) for (const auto& structInfo : m_structs)
@ -590,13 +590,13 @@ void ShaderGraph::UpdateBuffer(std::size_t bufferIndex, std::string name, Buffer
OnBufferUpdate(this, bufferIndex); OnBufferUpdate(this, bufferIndex);
} }
void ShaderGraph::UpdateCondition(std::size_t conditionIndex, std::string condition) void ShaderGraph::UpdateOption(std::size_t optionIndex, std::string option)
{ {
assert(conditionIndex < m_conditions.size()); assert(optionIndex < m_options.size());
auto& conditionEntry = m_conditions[conditionIndex]; auto& optionEntry = m_options[optionIndex];
conditionEntry.name = std::move(condition); optionEntry.name = std::move(option);
OnConditionUpdate(this, conditionIndex); OnOptionUpdate(this, optionIndex);
} }
void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex)

View File

@ -19,7 +19,7 @@ class ShaderGraph
{ {
public: public:
struct BufferEntry; struct BufferEntry;
struct ConditionEntry; struct OptionEntry;
struct InputEntry; struct InputEntry;
struct OutputEntry; struct OutputEntry;
struct StructEntry; struct StructEntry;
@ -30,7 +30,7 @@ class ShaderGraph
~ShaderGraph(); ~ShaderGraph();
std::size_t AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t setIndex, std::size_t bindingIndex); std::size_t AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t setIndex, std::size_t bindingIndex);
std::size_t AddCondition(std::string name); std::size_t AddOption(std::string name);
std::size_t AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); std::size_t AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex);
std::size_t AddOutput(std::string name, PrimitiveType type, std::size_t locationIndex); std::size_t AddOutput(std::string name, PrimitiveType type, std::size_t locationIndex);
std::size_t AddStruct(std::string name, std::vector<StructMemberEntry> members); std::size_t AddStruct(std::string name, std::vector<StructMemberEntry> members);
@ -38,17 +38,17 @@ class ShaderGraph
void Clear(); void Clear();
void EnableCondition(std::size_t conditionIndex, bool enable); void EnableOption(std::size_t optionIndex, bool enable);
inline const BufferEntry& GetBuffer(std::size_t bufferIndex) const; inline const BufferEntry& GetBuffer(std::size_t bufferIndex) const;
inline std::size_t GetBufferCount() const; inline std::size_t GetBufferCount() const;
inline const std::vector<BufferEntry>& GetBuffers() const; inline const std::vector<BufferEntry>& GetBuffers() const;
inline const ConditionEntry& GetCondition(std::size_t conditionIndex) const;
inline std::size_t GetConditionCount() const;
inline const std::vector<ConditionEntry>& GetConditions() const;
inline const InputEntry& GetInput(std::size_t bufferIndex) const; inline const InputEntry& GetInput(std::size_t bufferIndex) const;
inline std::size_t GetInputCount() const; inline std::size_t GetInputCount() const;
inline const std::vector<InputEntry>& GetInputs() const; inline const std::vector<InputEntry>& GetInputs() const;
inline const OptionEntry& GetOption(std::size_t optionIndex) const;
inline std::size_t GetOptionCount() const;
inline const std::vector<OptionEntry>& GetOptions() const;
inline const OutputEntry& GetOutput(std::size_t outputIndex) const; inline const OutputEntry& GetOutput(std::size_t outputIndex) const;
inline std::size_t GetOutputCount() const; inline std::size_t GetOutputCount() const;
inline const std::vector<OutputEntry>& GetOutputs() const; inline const std::vector<OutputEntry>& GetOutputs() const;
@ -62,7 +62,7 @@ class ShaderGraph
inline const std::vector<TextureEntry>& GetTextures() const; inline const std::vector<TextureEntry>& GetTextures() const;
inline ShaderType GetType() const; inline ShaderType GetType() const;
inline bool IsConditionEnabled(std::size_t conditionIndex) const; inline bool IsOptionEnabled(std::size_t optionIndex) const;
void Load(const QJsonObject& data); void Load(const QJsonObject& data);
QJsonObject Save(); QJsonObject Save();
@ -71,7 +71,7 @@ class ShaderGraph
Nz::ShaderAst::ExpressionType ToShaderExpressionType(const std::variant<PrimitiveType, std::size_t>& type) const; Nz::ShaderAst::ExpressionType ToShaderExpressionType(const std::variant<PrimitiveType, std::size_t>& type) const;
void UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t setIndex, std::size_t bindingIndex); void UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t setIndex, std::size_t bindingIndex);
void UpdateCondition(std::size_t conditionIndex, std::string condition); void UpdateOption(std::size_t optionIndex, std::string option);
void UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); void UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex);
void UpdateOutput(std::size_t outputIndex, std::string name, PrimitiveType type, std::size_t locationIndex); void UpdateOutput(std::size_t outputIndex, std::string name, PrimitiveType type, std::size_t locationIndex);
void UpdateStruct(std::size_t structIndex, std::string name, std::vector<StructMemberEntry> members); void UpdateStruct(std::size_t structIndex, std::string name, std::vector<StructMemberEntry> members);
@ -88,7 +88,7 @@ class ShaderGraph
BufferType type; BufferType type;
}; };
struct ConditionEntry struct OptionEntry
{ {
std::string name; std::string name;
bool enabled = false; bool enabled = false;
@ -133,8 +133,8 @@ class ShaderGraph
NazaraSignal(OnBufferListUpdate, ShaderGraph*); NazaraSignal(OnBufferListUpdate, ShaderGraph*);
NazaraSignal(OnBufferUpdate, ShaderGraph*, std::size_t /*bufferIndex*/); NazaraSignal(OnBufferUpdate, ShaderGraph*, std::size_t /*bufferIndex*/);
NazaraSignal(OnConditionListUpdate, ShaderGraph*); NazaraSignal(OnOptionListUpdate, ShaderGraph*);
NazaraSignal(OnConditionUpdate, ShaderGraph*, std::size_t /*conditionIndex*/); NazaraSignal(OnOptionUpdate, ShaderGraph*, std::size_t /*optionIndex*/);
NazaraSignal(OnInputListUpdate, ShaderGraph*); NazaraSignal(OnInputListUpdate, ShaderGraph*);
NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/); NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/);
NazaraSignal(OnOutputListUpdate, ShaderGraph*); NazaraSignal(OnOutputListUpdate, ShaderGraph*);
@ -158,7 +158,7 @@ class ShaderGraph
mutable std::optional<QtNodes::FlowScene> m_flowScene; mutable std::optional<QtNodes::FlowScene> m_flowScene;
std::vector<BufferEntry> m_buffers; std::vector<BufferEntry> m_buffers;
std::vector<ConditionEntry> m_conditions; std::vector<OptionEntry> m_options;
std::vector<InputEntry> m_inputs; std::vector<InputEntry> m_inputs;
std::vector<OutputEntry> m_outputs; std::vector<OutputEntry> m_outputs;
std::vector<StructEntry> m_structs; std::vector<StructEntry> m_structs;

View File

@ -16,22 +16,6 @@ inline auto ShaderGraph::GetBuffers() const -> const std::vector<BufferEntry>&
return m_buffers; return m_buffers;
} }
inline auto ShaderGraph::GetCondition(std::size_t conditionIndex) const -> const ConditionEntry&
{
assert(conditionIndex < m_conditions.size());
return m_conditions[conditionIndex];
}
inline std::size_t ShaderGraph::GetConditionCount() const
{
return m_conditions.size();
}
inline auto ShaderGraph::GetConditions() const -> const std::vector<ConditionEntry>&
{
return m_conditions;
}
inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEntry& inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEntry&
{ {
assert(inputIndex < m_inputs.size()); assert(inputIndex < m_inputs.size());
@ -48,6 +32,22 @@ inline auto ShaderGraph::GetInputs() const -> const std::vector<InputEntry>&
return m_inputs; return m_inputs;
} }
inline auto ShaderGraph::GetOption(std::size_t optionIndex) const -> const OptionEntry&
{
assert(optionIndex < m_options.size());
return m_options[optionIndex];
}
inline std::size_t ShaderGraph::GetOptionCount() const
{
return m_options.size();
}
inline auto ShaderGraph::GetOptions() const -> const std::vector<OptionEntry>&
{
return m_options;
}
inline auto ShaderGraph::GetOutput(std::size_t outputIndex) const -> const OutputEntry& inline auto ShaderGraph::GetOutput(std::size_t outputIndex) const -> const OutputEntry&
{ {
assert(outputIndex < m_outputs.size()); assert(outputIndex < m_outputs.size());
@ -111,9 +111,9 @@ inline ShaderType ShaderGraph::GetType() const
return m_type; return m_type;
} }
inline bool ShaderGraph::IsConditionEnabled(std::size_t conditionIndex) const inline bool ShaderGraph::IsOptionEnabled(std::size_t optionIndex) const
{ {
assert(conditionIndex < m_conditions.size()); assert(optionIndex < m_options.size());
return m_conditions[conditionIndex].enabled; return m_options[optionIndex].enabled;
} }

View File

@ -55,11 +55,11 @@ void CodeOutputWidget::Refresh()
{ {
try try
{ {
Nz::UInt64 enabledConditions = 0; Nz::UInt64 enabledOptions = 0;
for (std::size_t i = 0; i < m_shaderGraph.GetConditionCount(); ++i) for (std::size_t i = 0; i < m_shaderGraph.GetOptionCount(); ++i)
{ {
if (m_shaderGraph.IsConditionEnabled(i)) if (m_shaderGraph.IsOptionEnabled(i))
enabledConditions = Nz::SetBit<Nz::UInt64>(enabledConditions, i); enabledOptions = Nz::SetBit<Nz::UInt64>(enabledOptions, i);
} }
Nz::ShaderAst::StatementPtr shaderAst = m_shaderGraph.ToAst(); Nz::ShaderAst::StatementPtr shaderAst = m_shaderGraph.ToAst();
@ -69,14 +69,14 @@ void CodeOutputWidget::Refresh()
shaderAst = Nz::ShaderAst::Sanitize(*shaderAst); shaderAst = Nz::ShaderAst::Sanitize(*shaderAst);
Nz::ShaderAst::AstOptimizer::Options optimOptions; Nz::ShaderAst::AstOptimizer::Options optimOptions;
optimOptions.enabledOptions = enabledConditions; optimOptions.enabledOptions = enabledOptions;
Nz::ShaderAst::AstOptimizer optimiser; Nz::ShaderAst::AstOptimizer optimiser;
shaderAst = optimiser.Optimise(*shaderAst, optimOptions); shaderAst = optimiser.Optimise(*shaderAst, optimOptions);
} }
Nz::ShaderWriter::States states; Nz::ShaderWriter::States states;
states.enabledOptions = enabledConditions; states.enabledOptions = enabledOptions;
std::string output; std::string output;
OutputLanguage outputLang = static_cast<OutputLanguage>(m_outputLang->currentIndex()); OutputLanguage outputLang = static_cast<OutputLanguage>(m_outputLang->currentIndex());

View File

@ -1,55 +0,0 @@
#include <ShaderNode/Widgets/ConditionEditDialog.hpp>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDialogButtonBox>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QSpinBox>
#include <QtWidgets/QVBoxLayout>
ConditionEditDialog::ConditionEditDialog(QWidget* parent) :
QDialog(parent)
{
setWindowTitle(tr("Condition edit dialog"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_conditionName = new QLineEdit;
QFormLayout* formLayout = new QFormLayout;
formLayout->addRow(tr("Name"), m_conditionName);
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &ConditionEditDialog::OnAccept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
QVBoxLayout* verticalLayout = new QVBoxLayout;
verticalLayout->addLayout(formLayout);
verticalLayout->addWidget(buttonBox);
setLayout(verticalLayout);
}
ConditionEditDialog::ConditionEditDialog(const ConditionInfo& condition, QWidget* parent) :
ConditionEditDialog(parent)
{
m_conditionName->setText(QString::fromStdString(condition.name));
}
ConditionInfo ConditionEditDialog::GetConditionInfo() const
{
ConditionInfo inputInfo;
inputInfo.name = m_conditionName->text().toStdString();
return inputInfo;
}
void ConditionEditDialog::OnAccept()
{
if (m_conditionName->text().isEmpty())
{
QMessageBox::critical(this, tr("Empty name"), tr("Condition name must be set"), QMessageBox::Ok);
return;
}
accept();
}

View File

@ -1,35 +0,0 @@
#pragma once
#ifndef NAZARA_SHADERNODES_CONDITIONEDITDIALOG_HPP
#define NAZARA_SHADERNODES_CONDITIONEDITDIALOG_HPP
#include <ShaderNode/Enums.hpp>
#include <QtWidgets/QDialog>
class QComboBox;
class QLineEdit;
class QSpinBox;
struct ConditionInfo
{
std::string name;
};
class ConditionEditDialog : public QDialog
{
public:
ConditionEditDialog(QWidget* parent = nullptr);
ConditionEditDialog(const ConditionInfo& input, QWidget* parent = nullptr);
~ConditionEditDialog() = default;
ConditionInfo GetConditionInfo() const;
private:
void OnAccept();
QLineEdit* m_conditionName;
};
#include <ShaderNode/Widgets/ConditionEditDialog.inl>
#endif

View File

@ -1 +0,0 @@
#include <ShaderNode/Widgets/ConditionEditDialog.hpp>

View File

@ -1,119 +0,0 @@
#include <ShaderNode/Widgets/ConditionEditor.hpp>
#include <ShaderNode/Widgets/ConditionEditDialog.hpp>
#include <ShaderNode/ShaderGraph.hpp>
#include <QtGui/QStandardItemModel>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QTableView>
#include <QtWidgets/QVBoxLayout>
ConditionEditor::ConditionEditor(ShaderGraph& graph) :
m_shaderGraph(graph)
{
QTableView* tableView = new QTableView;
m_model = new QStandardItemModel(0, 2, tableView);
tableView->setModel(m_model);
m_model->setHorizontalHeaderLabels({ tr("Condition"), tr("Enabled") });
connect(tableView, &QTableView::doubleClicked, [this](const QModelIndex& index)
{
if (index.column() == 0)
OnEditCondition(index.row());
});
connect(m_model, &QStandardItemModel::itemChanged, [this](QStandardItem* item)
{
if (item->column() == 1)
{
std::size_t conditionIndex = static_cast<std::size_t>(item->row());
bool value = item->checkState() == Qt::Checked;
m_shaderGraph.EnableCondition(conditionIndex, value);
}
});
QPushButton* addStructButton = new QPushButton(tr("Add condition..."));
connect(addStructButton, &QPushButton::released, this, &ConditionEditor::OnAddCondition);
m_layout = new QVBoxLayout;
m_layout->addWidget(tableView);
m_layout->addWidget(addStructButton);
setLayout(m_layout);
m_onConditionListUpdateSlot.Connect(m_shaderGraph.OnConditionListUpdate, this, &ConditionEditor::OnConditionListUpdate);
m_onConditionUpdateSlot.Connect(m_shaderGraph.OnConditionUpdate, this, &ConditionEditor::OnConditionUpdate);
RefreshConditions();
}
void ConditionEditor::OnAddCondition()
{
ConditionEditDialog* dialog = new ConditionEditDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
connect(dialog, &QDialog::accepted, [this, dialog]
{
ConditionInfo conditionInfo = dialog->GetConditionInfo();
m_shaderGraph.AddCondition(std::move(conditionInfo.name));
});
dialog->open();
}
void ConditionEditor::OnEditCondition(int conditionIndex)
{
const auto& conditionInfo = m_shaderGraph.GetCondition(conditionIndex);
ConditionInfo info;
info.name = conditionInfo.name;
ConditionEditDialog* dialog = new ConditionEditDialog(info, this);
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
connect(dialog, &QDialog::accepted, [this, dialog, conditionIndex]
{
ConditionInfo conditionInfo = dialog->GetConditionInfo();
m_shaderGraph.UpdateCondition(conditionIndex, std::move(conditionInfo.name));
});
dialog->open();
}
void ConditionEditor::OnConditionListUpdate(ShaderGraph* /*graph*/)
{
RefreshConditions();
}
void ConditionEditor::OnConditionUpdate(ShaderGraph* /*graph*/, std::size_t conditionIndex)
{
const auto& conditionEntry = m_shaderGraph.GetCondition(conditionIndex);
int row = int(conditionIndex);
m_model->item(row, 0)->setText(QString::fromStdString(conditionEntry.name));
m_model->item(row, 1)->setCheckState((conditionEntry.enabled) ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
}
void ConditionEditor::RefreshConditions()
{
m_model->setRowCount(int(m_shaderGraph.GetConditionCount()));
int rowIndex = 0;
for (const auto& conditionEntry : m_shaderGraph.GetConditions())
{
QStandardItem* label = new QStandardItem(1);
label->setEditable(false);
label->setText(QString::fromStdString(conditionEntry.name));
m_model->setItem(rowIndex, 0, label);
QStandardItem* checkbox = new QStandardItem(1);
checkbox->setCheckable(true);
checkbox->setCheckState((conditionEntry.enabled) ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
m_model->setItem(rowIndex, 1, checkbox);
rowIndex++;
}
}

View File

@ -1,36 +0,0 @@
#pragma once
#ifndef NAZARA_SHADERNODES_CONDITIONEDITOR_HPP
#define NAZARA_SHADERNODES_CONDITIONEDITOR_HPP
#include <ShaderNode/ShaderGraph.hpp>
#include <QtWidgets/QWidget>
#include <optional>
class QStandardItemModel;
class QVBoxLayout;
class ConditionEditor : public QWidget
{
public:
ConditionEditor(ShaderGraph& graph);
~ConditionEditor() = default;
private:
void OnAddCondition();
void OnConditionListUpdate(ShaderGraph* graph);
void OnConditionUpdate(ShaderGraph* graph, std::size_t conditionIndex);
void OnEditCondition(int inputIndex);
void RefreshConditions();
NazaraSlot(ShaderGraph, OnStructListUpdate, m_onConditionListUpdateSlot);
NazaraSlot(ShaderGraph, OnStructUpdate, m_onConditionUpdateSlot);
ShaderGraph& m_shaderGraph;
QStandardItemModel* m_model;
QVBoxLayout* m_layout;
};
#include <ShaderNode/Widgets/ConditionEditor.inl>
#endif

View File

@ -1 +0,0 @@
#include <ShaderNode/Widgets/ConditionEditor.hpp>

View File

@ -5,7 +5,7 @@
#include <ShaderNode/ShaderGraph.hpp> #include <ShaderNode/ShaderGraph.hpp>
#include <ShaderNode/Widgets/BufferEditor.hpp> #include <ShaderNode/Widgets/BufferEditor.hpp>
#include <ShaderNode/Widgets/CodeOutputWidget.hpp> #include <ShaderNode/Widgets/CodeOutputWidget.hpp>
#include <ShaderNode/Widgets/ConditionEditor.hpp> #include <ShaderNode/Widgets/OptionEditor.hpp>
#include <ShaderNode/Widgets/InputEditor.hpp> #include <ShaderNode/Widgets/InputEditor.hpp>
#include <ShaderNode/Widgets/OutputEditor.hpp> #include <ShaderNode/Widgets/OutputEditor.hpp>
#include <ShaderNode/Widgets/NodeEditor.hpp> #include <ShaderNode/Widgets/NodeEditor.hpp>
@ -81,13 +81,13 @@ m_shaderGraph(graph)
addDockWidget(Qt::RightDockWidgetArea, structDock); addDockWidget(Qt::RightDockWidgetArea, structDock);
// Condition editor // Option editor
ConditionEditor* conditionEditor = new ConditionEditor(m_shaderGraph); OptionEditor* optionEditor = new OptionEditor(m_shaderGraph);
QDockWidget* conditionDock = new QDockWidget(tr("Conditions")); QDockWidget* optionDock = new QDockWidget(tr("Options"));
conditionDock->setWidget(conditionEditor); optionDock->setWidget(optionEditor);
addDockWidget(Qt::RightDockWidgetArea, conditionDock); addDockWidget(Qt::RightDockWidgetArea, optionDock);
// Code output // Code output
CodeOutputWidget* codeOutput = new CodeOutputWidget(m_shaderGraph); CodeOutputWidget* codeOutput = new CodeOutputWidget(m_shaderGraph);
@ -120,7 +120,7 @@ m_shaderGraph(graph)
view->addAction(nodeEditorDock->toggleViewAction()); view->addAction(nodeEditorDock->toggleViewAction());
view->addAction(bufferDock->toggleViewAction()); view->addAction(bufferDock->toggleViewAction());
view->addAction(structDock->toggleViewAction()); view->addAction(structDock->toggleViewAction());
view->addAction(conditionDock->toggleViewAction()); view->addAction(optionDock->toggleViewAction());
view->addAction(codeOutputDock->toggleViewAction()); view->addAction(codeOutputDock->toggleViewAction());
} }
@ -142,7 +142,7 @@ m_shaderGraph(graph)
}); });
}); });
m_onConditionUpdate.Connect(m_shaderGraph.OnConditionUpdate, [=](ShaderGraph*, std::size_t /*conditionIndex*/) m_onOptionUpdate.Connect(m_shaderGraph.OnOptionUpdate, [=](ShaderGraph*, std::size_t /*optionIndex*/)
{ {
if (codeOutput->isVisible()) if (codeOutput->isVisible())
codeOutput->Refresh(); codeOutput->Refresh();

View File

@ -22,7 +22,7 @@ class MainWindow : public QMainWindow
void OnSave(); void OnSave();
void OnUpdateInfo(); void OnUpdateInfo();
NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdate); NazaraSlot(ShaderGraph, OnOptionUpdate, m_onOptionUpdate);
NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate); NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate);
NodeEditor* m_nodeEditor; NodeEditor* m_nodeEditor;

View File

@ -0,0 +1,55 @@
#include <ShaderNode/Widgets/OptionEditDialog.hpp>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDialogButtonBox>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QSpinBox>
#include <QtWidgets/QVBoxLayout>
OptionEditDialog::OptionEditDialog(QWidget* parent) :
QDialog(parent)
{
setWindowTitle(tr("Option edit dialog"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_optionName = new QLineEdit;
QFormLayout* formLayout = new QFormLayout;
formLayout->addRow(tr("Name"), m_optionName);
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &OptionEditDialog::OnAccept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
QVBoxLayout* verticalLayout = new QVBoxLayout;
verticalLayout->addLayout(formLayout);
verticalLayout->addWidget(buttonBox);
setLayout(verticalLayout);
}
OptionEditDialog::OptionEditDialog(const OptionInfo& option, QWidget* parent) :
OptionEditDialog(parent)
{
m_optionName->setText(QString::fromStdString(option.name));
}
OptionInfo OptionEditDialog::GetOptionInfo() const
{
OptionInfo inputInfo;
inputInfo.name = m_optionName->text().toStdString();
return inputInfo;
}
void OptionEditDialog::OnAccept()
{
if (m_optionName->text().isEmpty())
{
QMessageBox::critical(this, tr("Empty name"), tr("Option name must be set"), QMessageBox::Ok);
return;
}
accept();
}

View File

@ -0,0 +1,35 @@
#pragma once
#ifndef NAZARA_SHADERNODES_OPTIONEDITDIALOG_HPP
#define NAZARA_SHADERNODES_OPTIONEDITDIALOG_HPP
#include <ShaderNode/Enums.hpp>
#include <QtWidgets/QDialog>
class QComboBox;
class QLineEdit;
class QSpinBox;
struct OptionInfo
{
std::string name;
};
class OptionEditDialog : public QDialog
{
public:
OptionEditDialog(QWidget* parent = nullptr);
OptionEditDialog(const OptionInfo& input, QWidget* parent = nullptr);
~OptionEditDialog() = default;
OptionInfo GetOptionInfo() const;
private:
void OnAccept();
QLineEdit* m_optionName;
};
#include <ShaderNode/Widgets/OptionEditDialog.inl>
#endif

View File

@ -0,0 +1 @@
#include <ShaderNode/Widgets/OptionEditDialog.hpp>

View File

@ -0,0 +1,119 @@
#include <ShaderNode/Widgets/OptionEditor.hpp>
#include <ShaderNode/Widgets/OptionEditDialog.hpp>
#include <ShaderNode/ShaderGraph.hpp>
#include <QtGui/QStandardItemModel>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QTableView>
#include <QtWidgets/QVBoxLayout>
OptionEditor::OptionEditor(ShaderGraph& graph) :
m_shaderGraph(graph)
{
QTableView* tableView = new QTableView;
m_model = new QStandardItemModel(0, 2, tableView);
tableView->setModel(m_model);
m_model->setHorizontalHeaderLabels({ tr("Option"), tr("Enabled") });
connect(tableView, &QTableView::doubleClicked, [this](const QModelIndex& index)
{
if (index.column() == 0)
OnEditOption(index.row());
});
connect(m_model, &QStandardItemModel::itemChanged, [this](QStandardItem* item)
{
if (item->column() == 1)
{
std::size_t optionIndex = static_cast<std::size_t>(item->row());
bool value = item->checkState() == Qt::Checked;
m_shaderGraph.EnableOption(optionIndex, value);
}
});
QPushButton* addStructButton = new QPushButton(tr("Add option..."));
connect(addStructButton, &QPushButton::released, this, &OptionEditor::OnAddOption);
m_layout = new QVBoxLayout;
m_layout->addWidget(tableView);
m_layout->addWidget(addStructButton);
setLayout(m_layout);
m_onOptionListUpdateSlot.Connect(m_shaderGraph.OnOptionListUpdate, this, &OptionEditor::OnOptionListUpdate);
m_onOptionUpdateSlot.Connect(m_shaderGraph.OnOptionUpdate, this, &OptionEditor::OnOptionUpdate);
RefreshOptions();
}
void OptionEditor::OnAddOption()
{
OptionEditDialog* dialog = new OptionEditDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
connect(dialog, &QDialog::accepted, [this, dialog]
{
OptionInfo optionInfo = dialog->GetOptionInfo();
m_shaderGraph.AddOption(std::move(optionInfo.name));
});
dialog->open();
}
void OptionEditor::OnEditOption(int optionIndex)
{
const auto& optionInfo = m_shaderGraph.GetOption(optionIndex);
OptionInfo info;
info.name = optionInfo.name;
OptionEditDialog* dialog = new OptionEditDialog(info, this);
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
connect(dialog, &QDialog::accepted, [this, dialog, optionIndex]
{
OptionInfo optionInfo = dialog->GetOptionInfo();
m_shaderGraph.UpdateOption(optionIndex, std::move(optionInfo.name));
});
dialog->open();
}
void OptionEditor::OnOptionListUpdate(ShaderGraph* /*graph*/)
{
RefreshOptions();
}
void OptionEditor::OnOptionUpdate(ShaderGraph* /*graph*/, std::size_t optionIndex)
{
const auto& optionEntry = m_shaderGraph.GetOption(optionIndex);
int row = int(optionIndex);
m_model->item(row, 0)->setText(QString::fromStdString(optionEntry.name));
m_model->item(row, 1)->setCheckState((optionEntry.enabled) ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
}
void OptionEditor::RefreshOptions()
{
m_model->setRowCount(int(m_shaderGraph.GetOptionCount()));
int rowIndex = 0;
for (const auto& optionEntry : m_shaderGraph.GetOptions())
{
QStandardItem* label = new QStandardItem(1);
label->setEditable(false);
label->setText(QString::fromStdString(optionEntry.name));
m_model->setItem(rowIndex, 0, label);
QStandardItem* checkbox = new QStandardItem(1);
checkbox->setCheckable(true);
checkbox->setCheckState((optionEntry.enabled) ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
m_model->setItem(rowIndex, 1, checkbox);
rowIndex++;
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#ifndef NAZARA_SHADERNODES_OPTIONEDITOR_HPP
#define NAZARA_SHADERNODES_OPTIONEDITOR_HPP
#include <ShaderNode/ShaderGraph.hpp>
#include <QtWidgets/QWidget>
#include <optional>
class QStandardItemModel;
class QVBoxLayout;
class OptionEditor : public QWidget
{
public:
OptionEditor(ShaderGraph& graph);
~OptionEditor() = default;
private:
void OnAddOption();
void OnOptionListUpdate(ShaderGraph* graph);
void OnOptionUpdate(ShaderGraph* graph, std::size_t optionIndex);
void OnEditOption(int optionIndex);
void RefreshOptions();
NazaraSlot(ShaderGraph, OnStructListUpdate, m_onOptionListUpdateSlot);
NazaraSlot(ShaderGraph, OnStructUpdate, m_onOptionUpdateSlot);
ShaderGraph& m_shaderGraph;
QStandardItemModel* m_model;
QVBoxLayout* m_layout;
};
#include <ShaderNode/Widgets/OptionEditor.inl>
#endif

View File

@ -0,0 +1 @@
#include <ShaderNode/Widgets/OptionEditor.hpp>