Graphics: rework ubershaders to prevent duplicate shaders modules
Also rename all remaining conditions to options
This commit is contained in:
parent
9ab47edd11
commit
a895e553d4
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
#include <ShaderNode/Widgets/ConditionEditDialog.hpp>
|
|
||||||
|
|
@ -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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
#include <ShaderNode/Widgets/ConditionEditor.hpp>
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/OptionEditDialog.hpp>
|
||||||
|
|
@ -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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/OptionEditor.hpp>
|
||||||
Loading…
Reference in New Issue