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:
|
||||
struct ConditionIndexes
|
||||
struct OptionIndexes
|
||||
{
|
||||
std::size_t alphaTest;
|
||||
std::size_t hasAlphaMap;
|
||||
|
|
@ -74,13 +74,13 @@ namespace Nz
|
|||
|
||||
Material& m_material;
|
||||
std::size_t m_uniformBlockIndex;
|
||||
ConditionIndexes m_conditionIndexes;
|
||||
OptionIndexes m_optionIndexes;
|
||||
TextureIndexes m_textureIndexes;
|
||||
UniformOffsets m_uniformOffsets;
|
||||
|
||||
static std::shared_ptr<MaterialSettings> s_materialSettings;
|
||||
static std::size_t s_uniformBlockIndex;
|
||||
static ConditionIndexes s_conditionIndexes;
|
||||
static OptionIndexes s_optionIndexes;
|
||||
static TextureIndexes s_textureIndexes;
|
||||
static UniformOffsets s_uniformOffsets;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ namespace Nz
|
|||
*/
|
||||
inline void BasicMaterial::EnableAlphaTest(bool alphaTest)
|
||||
{
|
||||
NazaraAssert(HasAlphaTest(), "Material has no alpha test condition");
|
||||
m_material.EnableCondition(m_conditionIndexes.alphaTest, alphaTest);
|
||||
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
|
||||
m_material.EnableOption(m_optionIndexes.alphaTest, alphaTest);
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<Texture>& BasicMaterial::GetAlphaMap() const
|
||||
|
|
@ -55,8 +55,8 @@ namespace Nz
|
|||
|
||||
inline bool BasicMaterial::IsAlphaTestEnabled() const
|
||||
{
|
||||
NazaraAssert(HasAlphaTest(), "Material has no alpha test condition");
|
||||
return m_material.IsConditionEnabled(m_conditionIndexes.alphaTest);
|
||||
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
|
||||
return m_material.IsOptionEnabled(m_optionIndexes.alphaTest);
|
||||
}
|
||||
|
||||
inline bool BasicMaterial::HasAlphaMap() const
|
||||
|
|
@ -66,7 +66,7 @@ namespace Nz
|
|||
|
||||
inline bool BasicMaterial::HasAlphaTest() const
|
||||
{
|
||||
return m_conditionIndexes.alphaTest != MaterialSettings::InvalidIndex;
|
||||
return m_optionIndexes.alphaTest != MaterialSettings::InvalidIndex;
|
||||
}
|
||||
|
||||
inline bool BasicMaterial::HasAlphaTestThreshold() const
|
||||
|
|
@ -90,8 +90,8 @@ namespace Nz
|
|||
bool hasAlphaMap = (alphaMap != nullptr);
|
||||
m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap));
|
||||
|
||||
if (m_conditionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
|
||||
m_material.EnableCondition(m_conditionIndexes.hasAlphaMap, hasAlphaMap);
|
||||
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
|
||||
m_material.EnableOption(m_optionIndexes.hasAlphaMap, hasAlphaMap);
|
||||
}
|
||||
|
||||
inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler)
|
||||
|
|
@ -106,8 +106,8 @@ namespace Nz
|
|||
bool hasDiffuseMap = (diffuseMap != nullptr);
|
||||
m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap));
|
||||
|
||||
if (m_conditionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
|
||||
m_material.EnableCondition(m_conditionIndexes.hasDiffuseMap, hasDiffuseMap);
|
||||
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
|
||||
m_material.EnableOption(m_optionIndexes.hasDiffuseMap, hasDiffuseMap);
|
||||
}
|
||||
|
||||
inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler)
|
||||
|
|
|
|||
|
|
@ -41,11 +41,11 @@ namespace Nz
|
|||
|
||||
inline void EnableBlending(bool blending);
|
||||
inline void EnableColorWrite(bool colorWrite);
|
||||
inline void EnableCondition(std::size_t conditionIndex, bool enable);
|
||||
inline void EnableDepthBuffer(bool depthBuffer);
|
||||
inline void EnableDepthSorting(bool depthSorting);
|
||||
inline void EnableDepthWrite(bool depthWrite);
|
||||
inline void EnableFaceCulling(bool faceCulling);
|
||||
inline void EnableOption(std::size_t optionIndex, bool enable);
|
||||
inline void EnableReflectionMapping(bool reflection);
|
||||
inline void EnableScissorTest(bool scissorTest);
|
||||
inline void EnableShadowCasting(bool castShadows);
|
||||
|
|
@ -83,11 +83,11 @@ namespace Nz
|
|||
|
||||
inline bool IsBlendingEnabled() const;
|
||||
inline bool IsColorWriteEnabled() const;
|
||||
inline bool IsConditionEnabled(std::size_t conditionIndex) const;
|
||||
inline bool IsDepthBufferEnabled() const;
|
||||
inline bool IsDepthSortingEnabled() const;
|
||||
inline bool IsDepthWriteEnabled() const;
|
||||
inline bool IsFaceCullingEnabled() const;
|
||||
inline bool IsOptionEnabled(std::size_t optionIndex) const;
|
||||
inline bool IsReflectionMappingEnabled() const;
|
||||
inline bool IsScissorTestEnabled() const;
|
||||
inline bool IsStencilTestEnabled() const;
|
||||
|
|
@ -117,7 +117,7 @@ namespace Nz
|
|||
inline void InvalidateShaderBinding();
|
||||
inline void InvalidateTextureSampler(std::size_t textureIndex);
|
||||
inline void InvalidateUniformData(std::size_t uniformBufferIndex);
|
||||
inline void UpdatePipeline() const;
|
||||
void UpdatePipeline() const;
|
||||
void UpdateShaderBinding();
|
||||
|
||||
struct MaterialTexture
|
||||
|
|
@ -138,7 +138,7 @@ namespace Nz
|
|||
std::vector<MaterialTexture> m_textures;
|
||||
std::vector<UniformBuffer> m_uniformBuffers;
|
||||
mutable std::shared_ptr<MaterialPipeline> m_pipeline;
|
||||
UInt64 m_enabledConditions;
|
||||
UInt64 m_enabledOptions;
|
||||
mutable MaterialPipelineInfo m_pipelineInfo;
|
||||
ShaderBindingPtr m_shaderBinding;
|
||||
mutable bool m_pipelineUpdated;
|
||||
|
|
|
|||
|
|
@ -90,15 +90,6 @@ namespace Nz
|
|||
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
|
||||
*
|
||||
|
|
@ -189,6 +180,15 @@ namespace Nz
|
|||
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
|
||||
*
|
||||
|
|
@ -515,11 +515,6 @@ namespace Nz
|
|||
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
|
||||
* \return true If it is the case
|
||||
|
|
@ -556,6 +551,11 @@ namespace Nz
|
|||
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
|
||||
* \return true If it is the case
|
||||
|
|
@ -766,25 +766,6 @@ namespace Nz
|
|||
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ namespace Nz
|
|||
|
||||
struct MaterialPipelineInfo : RenderStates
|
||||
{
|
||||
struct ShaderStage
|
||||
struct Shader
|
||||
{
|
||||
std::shared_ptr<UberShader> uberShader;
|
||||
Nz::UInt64 enabledConditions = 0;
|
||||
Nz::UInt64 enabledOptions = 0;
|
||||
};
|
||||
|
||||
bool depthSorting = false;
|
||||
|
|
@ -32,7 +32,7 @@ namespace Nz
|
|||
bool reflectionMapping = false;
|
||||
bool shadowReceive = true;
|
||||
|
||||
std::array<ShaderStage, ShaderStageTypeCount> shaders;
|
||||
std::vector<Shader> shaders;
|
||||
std::shared_ptr<const MaterialSettings> settings;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace Nz
|
|||
|
||||
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;
|
||||
|
||||
if (lhs.shaders[i].uberShader != rhs.shaders[i].uberShader)
|
||||
|
|
@ -85,7 +85,7 @@ namespace std
|
|||
|
||||
for (const auto& shader : pipelineInfo.shaders)
|
||||
{
|
||||
Nz::HashCombine(seed, shader.enabledConditions);
|
||||
Nz::HashCombine(seed, shader.enabledOptions);
|
||||
Nz::HashCombine(seed, shader.uberShader.get());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,8 @@ namespace Nz
|
|||
class MaterialSettings
|
||||
{
|
||||
public:
|
||||
using Shaders = std::array<std::shared_ptr<UberShader>, ShaderStageTypeCount>;
|
||||
|
||||
struct Builder;
|
||||
struct Condition;
|
||||
struct Option;
|
||||
struct SharedUniformBlock;
|
||||
struct Texture;
|
||||
struct UniformBlock;
|
||||
|
|
@ -39,11 +37,11 @@ namespace Nz
|
|||
~MaterialSettings() = default;
|
||||
|
||||
inline const Builder& GetBuilderData() const;
|
||||
inline const std::vector<Condition>& GetConditions() const;
|
||||
inline std::size_t GetConditionIndex(const std::string_view& name) const;
|
||||
inline const std::vector<Option>& GetOptions() 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<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 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;
|
||||
|
|
@ -60,17 +58,17 @@ namespace Nz
|
|||
|
||||
struct Builder
|
||||
{
|
||||
Shaders shaders;
|
||||
std::vector<Condition> conditions;
|
||||
std::vector<std::shared_ptr<UberShader>> shaders;
|
||||
std::vector<Option> options;
|
||||
std::vector<Texture> textures;
|
||||
std::vector<UniformBlock> uniformBlocks;
|
||||
std::vector<SharedUniformBlock> sharedUniformBlocks;
|
||||
};
|
||||
|
||||
struct Condition
|
||||
struct Option
|
||||
{
|
||||
std::string name;
|
||||
std::array<UInt64, ShaderStageTypeCount> enabledConditions;
|
||||
std::array<UInt64, ShaderStageTypeCount> enabledOptions;
|
||||
};
|
||||
|
||||
struct UniformVariable
|
||||
|
|
|
|||
|
|
@ -59,16 +59,16 @@ namespace Nz
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ namespace Nz
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,18 +20,20 @@ namespace Nz
|
|||
class NAZARA_GRAPHICS_API UberShader
|
||||
{
|
||||
public:
|
||||
UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst);
|
||||
UberShader(ShaderStageTypeFlags shaderStages, const ShaderAst::StatementPtr& shaderAst);
|
||||
~UberShader() = default;
|
||||
|
||||
UInt64 GetOptionFlagByName(const std::string& optionName) const;
|
||||
|
||||
inline ShaderStageTypeFlags GetSupportedStages() const;
|
||||
|
||||
const std::shared_ptr<ShaderModule>& Get(UInt64 combination);
|
||||
|
||||
private:
|
||||
std::unordered_map<UInt64 /*combination*/, std::shared_ptr<ShaderModule>> m_combinations;
|
||||
std::unordered_map<std::string, std::size_t> m_optionIndexByName;
|
||||
ShaderAst::StatementPtr m_shaderAst;
|
||||
ShaderStageType m_shaderStage;
|
||||
ShaderStageTypeFlags m_shaderStages;
|
||||
UInt64 m_combinationMask;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
inline ShaderStageTypeFlags UberShader::GetSupportedStages() const
|
||||
{
|
||||
return m_shaderStages;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
|
|
|||
|
|
@ -31,10 +31,12 @@ namespace Nz::ShaderAst
|
|||
|
||||
struct Callbacks
|
||||
{
|
||||
std::function<void(ShaderStageType stageType, const std::string& functionName)> onEntryPointDeclaration;
|
||||
std::function<void(const std::string& optionName, const ExpressionType& optionType)> onOptionDeclaration;
|
||||
};
|
||||
|
||||
private:
|
||||
void Visit(DeclareFunctionStatement& node) override;
|
||||
void Visit(DeclareOptionStatement& node) override;
|
||||
|
||||
const Callbacks* m_callbacks;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace Nz
|
|||
};
|
||||
|
||||
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:
|
||||
void Append(const ShaderAst::ExpressionType& type);
|
||||
|
|
|
|||
|
|
@ -33,16 +33,16 @@ namespace Nz
|
|||
const std::shared_ptr<const MaterialSettings>& materialSettings = material.GetSettings();
|
||||
if (materialSettings == s_materialSettings)
|
||||
{
|
||||
m_conditionIndexes = s_conditionIndexes;
|
||||
m_optionIndexes = s_optionIndexes;
|
||||
m_textureIndexes = s_textureIndexes;
|
||||
m_uniformBlockIndex = s_uniformBlockIndex;
|
||||
m_uniformOffsets = s_uniformOffsets;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_conditionIndexes.alphaTest = materialSettings->GetConditionIndex("AlphaTest");
|
||||
m_conditionIndexes.hasAlphaMap = materialSettings->GetConditionIndex("HasAlphaMap");
|
||||
m_conditionIndexes.hasDiffuseMap = materialSettings->GetConditionIndex("HasDiffuseMap");
|
||||
m_optionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest");
|
||||
m_optionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap");
|
||||
m_optionIndexes.hasDiffuseMap = materialSettings->GetOptionIndex("HasDiffuseMap");
|
||||
|
||||
m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
|
||||
m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse");
|
||||
|
|
@ -146,54 +146,51 @@ namespace Nz
|
|||
});
|
||||
|
||||
// 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)));
|
||||
auto uberShader = std::make_shared<UberShader>(ShaderStageType::Fragment | ShaderStageType::Vertex, shaderAst);
|
||||
|
||||
fragmentShader = std::make_shared<UberShader>(ShaderStageType::Fragment, shaderAst);
|
||||
vertexShader = std::make_shared<UberShader>(ShaderStageType::Vertex, shaderAst);
|
||||
settings.shaders.emplace_back(uberShader);
|
||||
|
||||
// Conditions
|
||||
// Options
|
||||
|
||||
// HasDiffuseMap
|
||||
{
|
||||
std::array<UInt64, ShaderStageTypeCount> shaderConditions;
|
||||
shaderConditions.fill(0);
|
||||
shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE");
|
||||
shaderConditions[UnderlyingCast(ShaderStageType::Vertex)] = vertexShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE");
|
||||
std::array<UInt64, ShaderStageTypeCount> shaderOptions;
|
||||
shaderOptions.fill(0);
|
||||
shaderOptions[UnderlyingCast(ShaderStageType::Fragment)] = uberShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE");
|
||||
shaderOptions[UnderlyingCast(ShaderStageType::Vertex)] = uberShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE");
|
||||
|
||||
s_conditionIndexes.hasDiffuseMap = settings.conditions.size();
|
||||
settings.conditions.push_back({
|
||||
s_optionIndexes.hasDiffuseMap = settings.options.size();
|
||||
settings.options.push_back({
|
||||
"HasDiffuseMap",
|
||||
shaderConditions
|
||||
shaderOptions
|
||||
});
|
||||
}
|
||||
|
||||
// HasAlphaMap
|
||||
{
|
||||
std::array<UInt64, ShaderStageTypeCount> shaderConditions;
|
||||
shaderConditions.fill(0);
|
||||
shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE");
|
||||
shaderConditions[UnderlyingCast(ShaderStageType::Vertex)] = vertexShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE");
|
||||
std::array<UInt64, ShaderStageTypeCount> shaderOptions;
|
||||
shaderOptions.fill(0);
|
||||
shaderOptions[UnderlyingCast(ShaderStageType::Fragment)] = uberShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE");
|
||||
shaderOptions[UnderlyingCast(ShaderStageType::Vertex)] = uberShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE");
|
||||
|
||||
s_conditionIndexes.hasAlphaMap = settings.conditions.size();
|
||||
settings.conditions.push_back({
|
||||
s_optionIndexes.hasAlphaMap = settings.options.size();
|
||||
settings.options.push_back({
|
||||
"HasAlphaMap",
|
||||
shaderConditions
|
||||
shaderOptions
|
||||
});
|
||||
}
|
||||
|
||||
// AlphaTest
|
||||
{
|
||||
std::array<UInt64, ShaderStageTypeCount> shaderConditions;
|
||||
shaderConditions.fill(0);
|
||||
shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("ALPHA_TEST");
|
||||
std::array<UInt64, ShaderStageTypeCount> shaderOptions;
|
||||
shaderOptions.fill(0);
|
||||
shaderOptions[UnderlyingCast(ShaderStageType::Fragment)] = uberShader->GetOptionFlagByName("ALPHA_TEST");
|
||||
|
||||
s_conditionIndexes.alphaTest = settings.conditions.size();
|
||||
settings.conditions.push_back({
|
||||
s_optionIndexes.alphaTest = settings.options.size();
|
||||
settings.options.push_back({
|
||||
"AlphaTest",
|
||||
shaderConditions
|
||||
shaderOptions
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +206,7 @@ namespace Nz
|
|||
|
||||
std::shared_ptr<MaterialSettings> BasicMaterial::s_materialSettings;
|
||||
std::size_t BasicMaterial::s_uniformBlockIndex;
|
||||
BasicMaterial::ConditionIndexes BasicMaterial::s_conditionIndexes;
|
||||
BasicMaterial::OptionIndexes BasicMaterial::s_optionIndexes;
|
||||
BasicMaterial::TextureIndexes BasicMaterial::s_textureIndexes;
|
||||
BasicMaterial::UniformOffsets BasicMaterial::s_uniformOffsets;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Graphics/BasicMaterial.hpp>
|
||||
#include <Nazara/Graphics/UberShader.hpp>
|
||||
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||
|
|
@ -27,7 +28,7 @@ namespace Nz
|
|||
*/
|
||||
Material::Material(std::shared_ptr<const MaterialSettings> settings) :
|
||||
m_settings(std::move(settings)),
|
||||
m_enabledConditions(0),
|
||||
m_enabledOptions(0),
|
||||
m_pipelineUpdated(false),
|
||||
m_shaderBindingUpdated(false),
|
||||
m_shadowCastingEnabled(true)
|
||||
|
|
@ -35,8 +36,11 @@ namespace Nz
|
|||
m_pipelineInfo.settings = m_settings;
|
||||
|
||||
const auto& shaders = m_settings->GetShaders();
|
||||
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
|
||||
m_pipelineInfo.shaders[i].uberShader = shaders[i];
|
||||
for (const auto& shader : shaders)
|
||||
{
|
||||
auto& shaderData = m_pipelineInfo.shaders.emplace_back();
|
||||
shaderData.uberShader = shader;
|
||||
}
|
||||
|
||||
const auto& textureSettings = m_settings->GetTextures();
|
||||
const auto& uboSettings = m_settings->GetUniformBlocks();
|
||||
|
|
@ -92,6 +96,33 @@ namespace Nz
|
|||
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()
|
||||
{
|
||||
assert(!m_shaderBinding);
|
||||
|
|
|
|||
|
|
@ -48,10 +48,10 @@ namespace Nz
|
|||
|
||||
renderPipelineInfo.pipelineLayout = m_pipelineInfo.settings->GetRenderPipelineLayout();
|
||||
|
||||
for (const auto& shaderEntry : m_pipelineInfo.shaders)
|
||||
for (const auto& shader : m_pipelineInfo.shaders)
|
||||
{
|
||||
if (shaderEntry.uberShader)
|
||||
renderPipelineInfo.shaderModules.push_back(shaderEntry.uberShader->Get(shaderEntry.enabledConditions));
|
||||
if (shader.uberShader)
|
||||
renderPipelineInfo.shaderModules.push_back(shader.uberShader->Get(shader.enabledOptions));
|
||||
}
|
||||
|
||||
renderPipelineInfo.vertexBuffers = vertexBuffers;
|
||||
|
|
|
|||
|
|
@ -13,15 +13,24 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
UberShader::UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst) :
|
||||
m_shaderStage(shaderStage)
|
||||
UberShader::UberShader(ShaderStageTypeFlags shaderStages, const ShaderAst::StatementPtr& shaderAst) :
|
||||
m_shaderStages(shaderStages)
|
||||
{
|
||||
NazaraAssert(m_shaderStages != 0, "there must be at least one shader stage");
|
||||
|
||||
//TODO: Try to partially sanitize shader?
|
||||
m_shaderAst = ShaderAst::Clone(*shaderAst);
|
||||
|
||||
std::size_t optionCount = 0;
|
||||
|
||||
ShaderStageTypeFlags supportedStageType;
|
||||
|
||||
ShaderAst::AstReflect::Callbacks callbacks;
|
||||
callbacks.onEntryPointDeclaration = [&](ShaderStageType stageType, const std::string& /*name*/)
|
||||
{
|
||||
supportedStageType |= stageType;
|
||||
};
|
||||
|
||||
callbacks.onOptionDeclaration = [&](const std::string& optionName, const ShaderAst::ExpressionType& optionType)
|
||||
{
|
||||
m_optionIndexByName[optionName] = optionCount;
|
||||
|
|
@ -31,6 +40,9 @@ namespace Nz
|
|||
ShaderAst::AstReflect reflect;
|
||||
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)
|
||||
throw std::runtime_error("Too many conditions");
|
||||
|
||||
|
|
@ -58,7 +70,7 @@ namespace Nz
|
|||
ShaderWriter::States states;
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,18 @@ namespace Nz::ShaderAst
|
|||
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)
|
||||
{
|
||||
assert(m_callbacks);
|
||||
|
|
|
|||
|
|
@ -203,11 +203,11 @@ namespace Nz
|
|||
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
|
||||
ShaderAst::SanitizeVisitor::Options options;
|
||||
options.enabledOptions = enabledConditions;
|
||||
options.enabledOptions = enabledOptions;
|
||||
options.makeVariableNameUnique = true;
|
||||
options.reservedIdentifiers = {
|
||||
// All reserved GLSL keywords as of GLSL ES 3.2
|
||||
|
|
|
|||
|
|
@ -14,20 +14,20 @@
|
|||
ConditionalExpression::ConditionalExpression(ShaderGraph& graph) :
|
||||
ShaderNode(graph)
|
||||
{
|
||||
m_onConditionListUpdateSlot.Connect(GetGraph().OnConditionListUpdate, [&](ShaderGraph*) { OnConditionListUpdate(); });
|
||||
m_onConditionUpdateSlot.Connect(GetGraph().OnConditionUpdate, [&](ShaderGraph*, std::size_t conditionIndex)
|
||||
m_onOptionListUpdateSlot.Connect(GetGraph().OnOptionListUpdate, [&](ShaderGraph*) { OnOptionListUpdate(); });
|
||||
m_onOptionUpdateSlot.Connect(GetGraph().OnOptionUpdate, [&](ShaderGraph*, std::size_t optionIndex)
|
||||
{
|
||||
if (m_currentConditionIndex == conditionIndex)
|
||||
if (m_currentOptionIndex == optionIndex)
|
||||
{
|
||||
UpdatePreview();
|
||||
Q_EMIT dataUpdated(0);
|
||||
}
|
||||
});
|
||||
|
||||
if (graph.GetConditionCount() > 0)
|
||||
if (graph.GetOptionCount() > 0)
|
||||
{
|
||||
m_currentConditionIndex = 0;
|
||||
UpdateConditionText();
|
||||
m_currentOptionIndex = 0;
|
||||
UpdateOptionText();
|
||||
}
|
||||
|
||||
EnablePreview();
|
||||
|
|
@ -40,18 +40,18 @@ Nz::ShaderAst::NodePtr ConditionalExpression::BuildNode(Nz::ShaderAst::Expressio
|
|||
assert(count == 2);
|
||||
assert(outputIndex == 0);
|
||||
|
||||
if (!m_currentConditionIndex)
|
||||
throw std::runtime_error("no condition");
|
||||
if (!m_currentOptionIndex)
|
||||
throw std::runtime_error("no option");
|
||||
|
||||
const ShaderGraph& graph = GetGraph();
|
||||
|
||||
const auto& conditionEntry = graph.GetCondition(*m_currentConditionIndex);
|
||||
return Nz::ShaderBuilder::ConditionalExpression(Nz::ShaderBuilder::Identifier(conditionEntry.name), std::move(expressions[0]), std::move(expressions[1]));
|
||||
const auto& optionEntry = graph.GetOption(*m_currentOptionIndex);
|
||||
return Nz::ShaderBuilder::ConditionalExpression(Nz::ShaderBuilder::Identifier(optionEntry.name), std::move(expressions[0]), std::move(expressions[1]));
|
||||
}
|
||||
|
||||
QString ConditionalExpression::caption() const
|
||||
{
|
||||
return "ConditionalExpression (" + QString::fromStdString(m_currentConditionText) + ")";
|
||||
return "ConditionalExpression (" + QString::fromStdString(m_currentOptionText) + ")";
|
||||
}
|
||||
|
||||
QString ConditionalExpression::name() const
|
||||
|
|
@ -74,29 +74,29 @@ void ConditionalExpression::BuildNodeEdition(QFormLayout* layout)
|
|||
{
|
||||
ShaderNode::BuildNodeEdition(layout);
|
||||
|
||||
QComboBox* conditionSelection = new QComboBox;
|
||||
for (const auto& conditionEntry : GetGraph().GetConditions())
|
||||
conditionSelection->addItem(QString::fromStdString(conditionEntry.name));
|
||||
QComboBox* optionSelection = new QComboBox;
|
||||
for (const auto& optionEntry : GetGraph().GetOptions())
|
||||
optionSelection->addItem(QString::fromStdString(optionEntry.name));
|
||||
|
||||
if (m_currentConditionIndex)
|
||||
conditionSelection->setCurrentIndex(int(*m_currentConditionIndex));
|
||||
if (m_currentOptionIndex)
|
||||
optionSelection->setCurrentIndex(int(*m_currentOptionIndex));
|
||||
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)
|
||||
m_currentConditionIndex = static_cast<std::size_t>(index);
|
||||
m_currentOptionIndex = static_cast<std::size_t>(index);
|
||||
else
|
||||
m_currentConditionIndex.reset();
|
||||
m_currentOptionIndex.reset();
|
||||
|
||||
UpdateConditionText();
|
||||
UpdateOptionText();
|
||||
UpdatePreview();
|
||||
|
||||
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
|
||||
|
|
@ -178,17 +178,17 @@ bool ConditionalExpression::portCaptionVisible(QtNodes::PortType portType, QtNod
|
|||
|
||||
std::shared_ptr<QtNodes::NodeData> ConditionalExpression::outData(QtNodes::PortIndex port)
|
||||
{
|
||||
if (!m_currentConditionIndex)
|
||||
if (!m_currentOptionIndex)
|
||||
return nullptr;
|
||||
|
||||
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)
|
||||
{
|
||||
m_currentConditionText = data["condition_name"].toString().toStdString();
|
||||
OnConditionListUpdate();
|
||||
m_currentOptionText = data["option_name"].toString().toStdString();
|
||||
OnOptionListUpdate();
|
||||
|
||||
ShaderNode::restore(data);
|
||||
}
|
||||
|
|
@ -196,7 +196,7 @@ void ConditionalExpression::restore(const QJsonObject& data)
|
|||
QJsonObject ConditionalExpression::save() const
|
||||
{
|
||||
QJsonObject data = ShaderNode::save();
|
||||
data["condition_name"] = QString::fromStdString(m_currentConditionText);
|
||||
data["option_name"] = QString::fromStdString(m_currentOptionText);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -223,8 +223,8 @@ QtNodes::NodeValidationState ConditionalExpression::validationState() const
|
|||
|
||||
QString ConditionalExpression::validationMessage() const
|
||||
{
|
||||
if (!m_currentConditionIndex)
|
||||
return "Invalid condition";
|
||||
if (!m_currentOptionIndex)
|
||||
return "Invalid option";
|
||||
|
||||
if (!m_truePath || !m_falsePath)
|
||||
return "Missing input";
|
||||
|
|
@ -234,7 +234,7 @@ QString ConditionalExpression::validationMessage() const
|
|||
|
||||
bool ConditionalExpression::ComputePreview(QPixmap& pixmap)
|
||||
{
|
||||
if (!m_currentConditionIndex)
|
||||
if (!m_currentOptionIndex)
|
||||
return false;
|
||||
|
||||
auto input = outData(0);
|
||||
|
|
@ -248,30 +248,30 @@ bool ConditionalExpression::ComputePreview(QPixmap& pixmap)
|
|||
return true;
|
||||
}
|
||||
|
||||
void ConditionalExpression::OnConditionListUpdate()
|
||||
void ConditionalExpression::OnOptionListUpdate()
|
||||
{
|
||||
m_currentConditionIndex.reset();
|
||||
m_currentOptionIndex.reset();
|
||||
|
||||
std::size_t conditionIndex = 0;
|
||||
for (const auto& conditionEntry : GetGraph().GetConditions())
|
||||
std::size_t optionIndex = 0;
|
||||
for (const auto& optionEntry : GetGraph().GetOptions())
|
||||
{
|
||||
if (conditionEntry.name == m_currentConditionText)
|
||||
if (optionEntry.name == m_currentOptionText)
|
||||
{
|
||||
m_currentConditionIndex = conditionIndex;
|
||||
m_currentOptionIndex = optionIndex;
|
||||
break;
|
||||
}
|
||||
|
||||
conditionIndex++;
|
||||
optionIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
void ConditionalExpression::UpdateConditionText()
|
||||
void ConditionalExpression::UpdateOptionText()
|
||||
{
|
||||
if (m_currentConditionIndex)
|
||||
if (m_currentOptionIndex)
|
||||
{
|
||||
auto& condition = GetGraph().GetCondition(*m_currentConditionIndex);
|
||||
m_currentConditionText = condition.name;
|
||||
auto& option = GetGraph().GetOption(*m_currentOptionIndex);
|
||||
m_currentOptionText = option.name;
|
||||
}
|
||||
else
|
||||
m_currentConditionText.clear();
|
||||
m_currentOptionText.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,16 +40,16 @@ class ConditionalExpression : public ShaderNode
|
|||
|
||||
private:
|
||||
bool ComputePreview(QPixmap& pixmap) override;
|
||||
void OnConditionListUpdate();
|
||||
void UpdateConditionText();
|
||||
void OnOptionListUpdate();
|
||||
void UpdateOptionText();
|
||||
|
||||
NazaraSlot(ShaderGraph, OnConditionListUpdate, m_onConditionListUpdateSlot);
|
||||
NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdateSlot);
|
||||
NazaraSlot(ShaderGraph, OnOptionListUpdate, m_onOptionListUpdateSlot);
|
||||
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_truePath;
|
||||
std::string m_currentConditionText;
|
||||
std::string m_currentOptionText;
|
||||
};
|
||||
|
||||
#include <ShaderNode/DataModels/BufferField.inl>
|
||||
|
|
|
|||
|
|
@ -121,13 +121,13 @@ std::size_t ShaderGraph::AddBuffer(std::string name, BufferType bufferType, std:
|
|||
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();
|
||||
auto& conditionEntry = m_conditions.emplace_back();
|
||||
conditionEntry.name = std::move(name);
|
||||
std::size_t index = m_options.size();
|
||||
auto& optionEntry = m_options.emplace_back();
|
||||
optionEntry.name = std::move(name);
|
||||
|
||||
OnConditionListUpdate(this);
|
||||
OnOptionListUpdate(this);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
|
@ -194,7 +194,7 @@ void ShaderGraph::Clear()
|
|||
m_flowScene->clear();
|
||||
|
||||
m_buffers.clear();
|
||||
m_conditions.clear();
|
||||
m_options.clear();
|
||||
m_inputs.clear();
|
||||
m_structs.clear();
|
||||
m_outputs.clear();
|
||||
|
|
@ -207,13 +207,13 @@ void ShaderGraph::Clear()
|
|||
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());
|
||||
auto& conditionEntry = m_conditions[conditionIndex];
|
||||
conditionEntry.enabled = enable;
|
||||
assert(optionIndex < m_options.size());
|
||||
auto& optionEntry = m_options[optionIndex];
|
||||
optionEntry.enabled = enable;
|
||||
|
||||
OnConditionUpdate(this, conditionIndex);
|
||||
OnOptionUpdate(this, optionIndex);
|
||||
}
|
||||
|
||||
void ShaderGraph::Load(const QJsonObject& data)
|
||||
|
|
@ -238,16 +238,16 @@ void ShaderGraph::Load(const QJsonObject& data)
|
|||
|
||||
OnBufferListUpdate(this);
|
||||
|
||||
QJsonArray conditionArray = data["conditions"].toArray();
|
||||
for (const auto& conditionDocRef : conditionArray)
|
||||
QJsonArray optionArray = data["options"].toArray();
|
||||
for (const auto& optionDocRef : optionArray)
|
||||
{
|
||||
QJsonObject conditionDoc = conditionDocRef.toObject();
|
||||
QJsonObject optionDoc = optionDocRef.toObject();
|
||||
|
||||
ConditionEntry& condition = m_conditions.emplace_back();
|
||||
condition.name = conditionDoc["name"].toString().toStdString();
|
||||
OptionEntry& option = m_options.emplace_back();
|
||||
option.name = optionDoc["name"].toString().toStdString();
|
||||
}
|
||||
|
||||
OnConditionListUpdate(this);
|
||||
OnOptionListUpdate(this);
|
||||
|
||||
QJsonArray inputArray = data["inputs"].toArray();
|
||||
for (const auto& inputDocRef : inputArray)
|
||||
|
|
@ -345,17 +345,17 @@ QJsonObject ShaderGraph::Save()
|
|||
}
|
||||
sceneJson["buffers"] = bufferArray;
|
||||
|
||||
QJsonArray conditionArray;
|
||||
QJsonArray optionArray;
|
||||
{
|
||||
for (const auto& condition : m_conditions)
|
||||
for (const auto& option : m_options)
|
||||
{
|
||||
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;
|
||||
{
|
||||
|
|
@ -462,8 +462,8 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() const
|
|||
std::vector<Nz::ShaderAst::StatementPtr> statements;
|
||||
|
||||
// Declare all options
|
||||
for (const auto& condition : m_conditions)
|
||||
statements.push_back(Nz::ShaderBuilder::DeclareOption(condition.name, Nz::ShaderAst::PrimitiveType::Boolean));
|
||||
for (const auto& option : m_options)
|
||||
statements.push_back(Nz::ShaderBuilder::DeclareOption(option.name, Nz::ShaderAst::PrimitiveType::Boolean));
|
||||
|
||||
// Declare all structures
|
||||
for (const auto& structInfo : m_structs)
|
||||
|
|
@ -590,13 +590,13 @@ void ShaderGraph::UpdateBuffer(std::size_t bufferIndex, std::string name, Buffer
|
|||
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());
|
||||
auto& conditionEntry = m_conditions[conditionIndex];
|
||||
conditionEntry.name = std::move(condition);
|
||||
assert(optionIndex < m_options.size());
|
||||
auto& optionEntry = m_options[optionIndex];
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class ShaderGraph
|
|||
{
|
||||
public:
|
||||
struct BufferEntry;
|
||||
struct ConditionEntry;
|
||||
struct OptionEntry;
|
||||
struct InputEntry;
|
||||
struct OutputEntry;
|
||||
struct StructEntry;
|
||||
|
|
@ -30,7 +30,7 @@ class 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 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 AddOutput(std::string name, PrimitiveType type, std::size_t locationIndex);
|
||||
std::size_t AddStruct(std::string name, std::vector<StructMemberEntry> members);
|
||||
|
|
@ -38,17 +38,17 @@ class ShaderGraph
|
|||
|
||||
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 std::size_t GetBufferCount() 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 std::size_t GetInputCount() 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 std::size_t GetOutputCount() const;
|
||||
inline const std::vector<OutputEntry>& GetOutputs() const;
|
||||
|
|
@ -62,7 +62,7 @@ class ShaderGraph
|
|||
inline const std::vector<TextureEntry>& GetTextures() 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);
|
||||
QJsonObject Save();
|
||||
|
|
@ -71,7 +71,7 @@ class ShaderGraph
|
|||
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 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 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);
|
||||
|
|
@ -88,7 +88,7 @@ class ShaderGraph
|
|||
BufferType type;
|
||||
};
|
||||
|
||||
struct ConditionEntry
|
||||
struct OptionEntry
|
||||
{
|
||||
std::string name;
|
||||
bool enabled = false;
|
||||
|
|
@ -133,8 +133,8 @@ class ShaderGraph
|
|||
|
||||
NazaraSignal(OnBufferListUpdate, ShaderGraph*);
|
||||
NazaraSignal(OnBufferUpdate, ShaderGraph*, std::size_t /*bufferIndex*/);
|
||||
NazaraSignal(OnConditionListUpdate, ShaderGraph*);
|
||||
NazaraSignal(OnConditionUpdate, ShaderGraph*, std::size_t /*conditionIndex*/);
|
||||
NazaraSignal(OnOptionListUpdate, ShaderGraph*);
|
||||
NazaraSignal(OnOptionUpdate, ShaderGraph*, std::size_t /*optionIndex*/);
|
||||
NazaraSignal(OnInputListUpdate, ShaderGraph*);
|
||||
NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/);
|
||||
NazaraSignal(OnOutputListUpdate, ShaderGraph*);
|
||||
|
|
@ -158,7 +158,7 @@ class ShaderGraph
|
|||
|
||||
mutable std::optional<QtNodes::FlowScene> m_flowScene;
|
||||
std::vector<BufferEntry> m_buffers;
|
||||
std::vector<ConditionEntry> m_conditions;
|
||||
std::vector<OptionEntry> m_options;
|
||||
std::vector<InputEntry> m_inputs;
|
||||
std::vector<OutputEntry> m_outputs;
|
||||
std::vector<StructEntry> m_structs;
|
||||
|
|
|
|||
|
|
@ -16,22 +16,6 @@ inline auto ShaderGraph::GetBuffers() const -> const std::vector<BufferEntry>&
|
|||
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&
|
||||
{
|
||||
assert(inputIndex < m_inputs.size());
|
||||
|
|
@ -48,6 +32,22 @@ inline auto ShaderGraph::GetInputs() const -> const std::vector<InputEntry>&
|
|||
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&
|
||||
{
|
||||
assert(outputIndex < m_outputs.size());
|
||||
|
|
@ -111,9 +111,9 @@ inline ShaderType ShaderGraph::GetType() const
|
|||
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());
|
||||
return m_conditions[conditionIndex].enabled;
|
||||
assert(optionIndex < m_options.size());
|
||||
return m_options[optionIndex].enabled;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,11 +55,11 @@ void CodeOutputWidget::Refresh()
|
|||
{
|
||||
try
|
||||
{
|
||||
Nz::UInt64 enabledConditions = 0;
|
||||
for (std::size_t i = 0; i < m_shaderGraph.GetConditionCount(); ++i)
|
||||
Nz::UInt64 enabledOptions = 0;
|
||||
for (std::size_t i = 0; i < m_shaderGraph.GetOptionCount(); ++i)
|
||||
{
|
||||
if (m_shaderGraph.IsConditionEnabled(i))
|
||||
enabledConditions = Nz::SetBit<Nz::UInt64>(enabledConditions, i);
|
||||
if (m_shaderGraph.IsOptionEnabled(i))
|
||||
enabledOptions = Nz::SetBit<Nz::UInt64>(enabledOptions, i);
|
||||
}
|
||||
|
||||
Nz::ShaderAst::StatementPtr shaderAst = m_shaderGraph.ToAst();
|
||||
|
|
@ -69,14 +69,14 @@ void CodeOutputWidget::Refresh()
|
|||
shaderAst = Nz::ShaderAst::Sanitize(*shaderAst);
|
||||
|
||||
Nz::ShaderAst::AstOptimizer::Options optimOptions;
|
||||
optimOptions.enabledOptions = enabledConditions;
|
||||
optimOptions.enabledOptions = enabledOptions;
|
||||
|
||||
Nz::ShaderAst::AstOptimizer optimiser;
|
||||
shaderAst = optimiser.Optimise(*shaderAst, optimOptions);
|
||||
}
|
||||
|
||||
Nz::ShaderWriter::States states;
|
||||
states.enabledOptions = enabledConditions;
|
||||
states.enabledOptions = enabledOptions;
|
||||
|
||||
std::string output;
|
||||
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/Widgets/BufferEditor.hpp>
|
||||
#include <ShaderNode/Widgets/CodeOutputWidget.hpp>
|
||||
#include <ShaderNode/Widgets/ConditionEditor.hpp>
|
||||
#include <ShaderNode/Widgets/OptionEditor.hpp>
|
||||
#include <ShaderNode/Widgets/InputEditor.hpp>
|
||||
#include <ShaderNode/Widgets/OutputEditor.hpp>
|
||||
#include <ShaderNode/Widgets/NodeEditor.hpp>
|
||||
|
|
@ -81,13 +81,13 @@ m_shaderGraph(graph)
|
|||
|
||||
addDockWidget(Qt::RightDockWidgetArea, structDock);
|
||||
|
||||
// Condition editor
|
||||
ConditionEditor* conditionEditor = new ConditionEditor(m_shaderGraph);
|
||||
// Option editor
|
||||
OptionEditor* optionEditor = new OptionEditor(m_shaderGraph);
|
||||
|
||||
QDockWidget* conditionDock = new QDockWidget(tr("Conditions"));
|
||||
conditionDock->setWidget(conditionEditor);
|
||||
QDockWidget* optionDock = new QDockWidget(tr("Options"));
|
||||
optionDock->setWidget(optionEditor);
|
||||
|
||||
addDockWidget(Qt::RightDockWidgetArea, conditionDock);
|
||||
addDockWidget(Qt::RightDockWidgetArea, optionDock);
|
||||
|
||||
// Code output
|
||||
CodeOutputWidget* codeOutput = new CodeOutputWidget(m_shaderGraph);
|
||||
|
|
@ -120,7 +120,7 @@ m_shaderGraph(graph)
|
|||
view->addAction(nodeEditorDock->toggleViewAction());
|
||||
view->addAction(bufferDock->toggleViewAction());
|
||||
view->addAction(structDock->toggleViewAction());
|
||||
view->addAction(conditionDock->toggleViewAction());
|
||||
view->addAction(optionDock->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())
|
||||
codeOutput->Refresh();
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class MainWindow : public QMainWindow
|
|||
void OnSave();
|
||||
void OnUpdateInfo();
|
||||
|
||||
NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdate);
|
||||
NazaraSlot(ShaderGraph, OnOptionUpdate, m_onOptionUpdate);
|
||||
NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate);
|
||||
|
||||
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