Add conditional expression/statement support for shaders

This commit is contained in:
Jérôme Leclercq 2020-11-19 13:56:54 +01:00
parent ad88561245
commit 960817a1f1
45 changed files with 996 additions and 56 deletions

View File

@ -16,7 +16,6 @@
#include <set> #include <set>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <unordered_map>
namespace Nz namespace Nz
{ {
@ -31,7 +30,7 @@ namespace Nz
GlslWriter(GlslWriter&&) = delete; GlslWriter(GlslWriter&&) = delete;
~GlslWriter() = default; ~GlslWriter() = default;
std::string Generate(const ShaderAst& shader) override; std::string Generate(const ShaderAst& shader, const States& conditions = {});
void SetEnv(Environment environment); void SetEnv(Environment environment);
@ -70,6 +69,8 @@ namespace Nz
void Visit(ShaderNodes::BinaryOp& node) override; void Visit(ShaderNodes::BinaryOp& node) override;
void Visit(ShaderNodes::BuiltinVariable& var) override; void Visit(ShaderNodes::BuiltinVariable& var) override;
void Visit(ShaderNodes::Cast& node) override; void Visit(ShaderNodes::Cast& node) override;
void Visit(ShaderNodes::ConditionalExpression& node) override;
void Visit(ShaderNodes::ConditionalStatement& node) override;
void Visit(ShaderNodes::Constant& node) override; void Visit(ShaderNodes::Constant& node) override;
void Visit(ShaderNodes::DeclareVariable& node) override; void Visit(ShaderNodes::DeclareVariable& node) override;
void Visit(ShaderNodes::ExpressionStatement& node) override; void Visit(ShaderNodes::ExpressionStatement& node) override;
@ -91,6 +92,7 @@ namespace Nz
{ {
const ShaderAst* shader = nullptr; const ShaderAst* shader = nullptr;
const ShaderAst::Function* currentFunction = nullptr; const ShaderAst::Function* currentFunction = nullptr;
const States* states = nullptr;
}; };
struct State struct State

View File

@ -20,6 +20,7 @@ namespace Nz
class NAZARA_SHADER_API ShaderAst class NAZARA_SHADER_API ShaderAst
{ {
public: public:
struct Condition;
struct Function; struct Function;
struct FunctionParameter; struct FunctionParameter;
struct InputOutput; struct InputOutput;
@ -33,12 +34,16 @@ namespace Nz
ShaderAst(ShaderAst&&) noexcept = default; ShaderAst(ShaderAst&&) noexcept = default;
~ShaderAst() = default; ~ShaderAst() = default;
void AddCondition(std::string name);
void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector<FunctionParameter> parameters = {}, ShaderNodes::BasicType returnType = ShaderNodes::BasicType::Void); void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector<FunctionParameter> parameters = {}, ShaderNodes::BasicType returnType = ShaderNodes::BasicType::Void);
void AddInput(std::string name, ShaderExpressionType type, std::optional<std::size_t> locationIndex = {}); void AddInput(std::string name, ShaderExpressionType type, std::optional<std::size_t> locationIndex = {});
void AddOutput(std::string name, ShaderExpressionType type, std::optional<std::size_t> locationIndex = {}); void AddOutput(std::string name, ShaderExpressionType type, std::optional<std::size_t> locationIndex = {});
void AddStruct(std::string name, std::vector<StructMember> members); void AddStruct(std::string name, std::vector<StructMember> members);
void AddUniform(std::string name, ShaderExpressionType type, std::optional<std::size_t> bindingIndex = {}, std::optional<ShaderNodes::MemoryLayout> memoryLayout = {}); void AddUniform(std::string name, ShaderExpressionType type, std::optional<std::size_t> bindingIndex = {}, std::optional<ShaderNodes::MemoryLayout> memoryLayout = {});
inline const Condition& GetCondition(std::size_t i) const;
inline std::size_t GetConditionCount() const;
inline const std::vector<Condition>& GetConditions() const;
inline const Function& GetFunction(std::size_t i) const; inline const Function& GetFunction(std::size_t i) const;
inline std::size_t GetFunctionCount() const; inline std::size_t GetFunctionCount() const;
inline const std::vector<Function>& GetFunctions() const; inline const std::vector<Function>& GetFunctions() const;
@ -59,6 +64,11 @@ namespace Nz
ShaderAst& operator=(const ShaderAst&) = default; ShaderAst& operator=(const ShaderAst&) = default;
ShaderAst& operator=(ShaderAst&&) noexcept = default; ShaderAst& operator=(ShaderAst&&) noexcept = default;
struct Condition
{
std::string name;
};
struct VariableBase struct VariableBase
{ {
std::string name; std::string name;
@ -101,6 +111,7 @@ namespace Nz
}; };
private: private:
std::vector<Condition> m_conditions;
std::vector<Function> m_functions; std::vector<Function> m_functions;
std::vector<InputOutput> m_inputs; std::vector<InputOutput> m_inputs;
std::vector<InputOutput> m_outputs; std::vector<InputOutput> m_outputs;

View File

@ -12,6 +12,22 @@ namespace Nz
{ {
} }
inline auto Nz::ShaderAst::GetCondition(std::size_t i) const -> const Condition&
{
assert(i < m_functions.size());
return m_conditions[i];
}
inline std::size_t ShaderAst::GetConditionCount() const
{
return m_conditions.size();
}
inline auto ShaderAst::GetConditions() const -> const std::vector<Condition>&
{
return m_conditions;
}
inline auto ShaderAst::GetFunction(std::size_t i) const -> const Function& inline auto ShaderAst::GetFunction(std::size_t i) const -> const Function&
{ {
assert(i < m_functions.size()); assert(i < m_functions.size());

View File

@ -38,6 +38,8 @@ namespace Nz
void Visit(ShaderNodes::BinaryOp& node) override; void Visit(ShaderNodes::BinaryOp& node) override;
void Visit(ShaderNodes::Branch& node) override; void Visit(ShaderNodes::Branch& node) override;
void Visit(ShaderNodes::Cast& node) override; void Visit(ShaderNodes::Cast& node) override;
void Visit(ShaderNodes::ConditionalExpression& node) override;
void Visit(ShaderNodes::ConditionalStatement& node) override;
void Visit(ShaderNodes::Constant& node) override; void Visit(ShaderNodes::Constant& node) override;
void Visit(ShaderNodes::DeclareVariable& node) override; void Visit(ShaderNodes::DeclareVariable& node) override;
void Visit(ShaderNodes::ExpressionStatement& node) override; void Visit(ShaderNodes::ExpressionStatement& node) override;

View File

@ -26,6 +26,8 @@ namespace Nz
void Visit(ShaderNodes::BinaryOp& node) override; void Visit(ShaderNodes::BinaryOp& node) override;
void Visit(ShaderNodes::Branch& node) override; void Visit(ShaderNodes::Branch& node) override;
void Visit(ShaderNodes::Cast& node) override; void Visit(ShaderNodes::Cast& node) override;
void Visit(ShaderNodes::ConditionalExpression& node) override;
void Visit(ShaderNodes::ConditionalStatement& node) override;
void Visit(ShaderNodes::Constant& node) override; void Visit(ShaderNodes::Constant& node) override;
void Visit(ShaderNodes::DeclareVariable& node) override; void Visit(ShaderNodes::DeclareVariable& node) override;
void Visit(ShaderNodes::ExpressionStatement& node) override; void Visit(ShaderNodes::ExpressionStatement& node) override;

View File

@ -31,6 +31,8 @@ namespace Nz
void Serialize(ShaderNodes::BuiltinVariable& var); void Serialize(ShaderNodes::BuiltinVariable& var);
void Serialize(ShaderNodes::Branch& node); void Serialize(ShaderNodes::Branch& node);
void Serialize(ShaderNodes::Cast& node); void Serialize(ShaderNodes::Cast& node);
void Serialize(ShaderNodes::ConditionalExpression& node);
void Serialize(ShaderNodes::ConditionalStatement& node);
void Serialize(ShaderNodes::Constant& node); void Serialize(ShaderNodes::Constant& node);
void Serialize(ShaderNodes::DeclareVariable& node); void Serialize(ShaderNodes::DeclareVariable& node);
void Serialize(ShaderNodes::ExpressionStatement& node); void Serialize(ShaderNodes::ExpressionStatement& node);

View File

@ -41,6 +41,8 @@ namespace Nz
void Visit(ShaderNodes::BinaryOp& node) override; void Visit(ShaderNodes::BinaryOp& node) override;
void Visit(ShaderNodes::Branch& node) override; void Visit(ShaderNodes::Branch& node) override;
void Visit(ShaderNodes::Cast& node) override; void Visit(ShaderNodes::Cast& node) override;
void Visit(ShaderNodes::ConditionalExpression& node) override;
void Visit(ShaderNodes::ConditionalStatement& node) override;
void Visit(ShaderNodes::Constant& node) override; void Visit(ShaderNodes::Constant& node) override;
void Visit(ShaderNodes::DeclareVariable& node) override; void Visit(ShaderNodes::DeclareVariable& node) override;
void Visit(ShaderNodes::ExpressionStatement& node) override; void Visit(ShaderNodes::ExpressionStatement& node) override;

View File

@ -10,8 +10,6 @@
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp> #include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderNodes.hpp> #include <Nazara/Shader/ShaderNodes.hpp>
#include <string>
#include <unordered_set>
namespace Nz namespace Nz
{ {
@ -23,16 +21,14 @@ namespace Nz
ShaderAstVisitor(ShaderAstVisitor&&) = delete; ShaderAstVisitor(ShaderAstVisitor&&) = delete;
virtual ~ShaderAstVisitor(); virtual ~ShaderAstVisitor();
void EnableCondition(const std::string& name, bool cond);
bool IsConditionEnabled(const std::string& name) const;
void Visit(const ShaderNodes::NodePtr& node); void Visit(const ShaderNodes::NodePtr& node);
virtual void Visit(ShaderNodes::AccessMember& node) = 0; virtual void Visit(ShaderNodes::AccessMember& node) = 0;
virtual void Visit(ShaderNodes::AssignOp& node) = 0; virtual void Visit(ShaderNodes::AssignOp& node) = 0;
virtual void Visit(ShaderNodes::BinaryOp& node) = 0; virtual void Visit(ShaderNodes::BinaryOp& node) = 0;
virtual void Visit(ShaderNodes::Branch& node) = 0; virtual void Visit(ShaderNodes::Branch& node) = 0;
virtual void Visit(ShaderNodes::Cast& node) = 0; virtual void Visit(ShaderNodes::Cast& node) = 0;
virtual void Visit(ShaderNodes::ConditionalExpression& node) = 0;
virtual void Visit(ShaderNodes::ConditionalStatement& node) = 0;
virtual void Visit(ShaderNodes::Constant& node) = 0; virtual void Visit(ShaderNodes::Constant& node) = 0;
virtual void Visit(ShaderNodes::DeclareVariable& node) = 0; virtual void Visit(ShaderNodes::DeclareVariable& node) = 0;
virtual void Visit(ShaderNodes::ExpressionStatement& node) = 0; virtual void Visit(ShaderNodes::ExpressionStatement& node) = 0;
@ -44,9 +40,6 @@ namespace Nz
ShaderAstVisitor& operator=(const ShaderAstVisitor&) = delete; ShaderAstVisitor& operator=(const ShaderAstVisitor&) = delete;
ShaderAstVisitor& operator=(ShaderAstVisitor&&) = delete; ShaderAstVisitor& operator=(ShaderAstVisitor&&) = delete;
private:
std::unordered_set<std::string> m_conditions;
}; };
} }

View File

@ -22,6 +22,8 @@ namespace Nz
void Visit(ShaderNodes::BinaryOp& node) override; void Visit(ShaderNodes::BinaryOp& node) override;
void Visit(ShaderNodes::Branch& node) override; void Visit(ShaderNodes::Branch& node) override;
void Visit(ShaderNodes::Cast& node) override; void Visit(ShaderNodes::Cast& node) override;
void Visit(ShaderNodes::ConditionalExpression& node) override;
void Visit(ShaderNodes::ConditionalStatement& node) override;
void Visit(ShaderNodes::Constant& node) override; void Visit(ShaderNodes::Constant& node) override;
void Visit(ShaderNodes::DeclareVariable& node) override; void Visit(ShaderNodes::DeclareVariable& node) override;
void Visit(ShaderNodes::ExpressionStatement& node) override; void Visit(ShaderNodes::ExpressionStatement& node) override;

View File

@ -50,6 +50,7 @@ namespace Nz::ShaderBuilder
constexpr BuiltinBuilder Builtin; constexpr BuiltinBuilder Builtin;
constexpr GenBuilder<ShaderNodes::StatementBlock> Block; constexpr GenBuilder<ShaderNodes::StatementBlock> Block;
constexpr GenBuilder<ShaderNodes::Branch> Branch; constexpr GenBuilder<ShaderNodes::Branch> Branch;
constexpr GenBuilder<ShaderNodes::ConditionalExpression> ConditionalExpression;
constexpr GenBuilder<ShaderNodes::ConditionalStatement> ConditionalStatement; constexpr GenBuilder<ShaderNodes::ConditionalStatement> ConditionalStatement;
constexpr GenBuilder<ShaderNodes::Constant> Constant; constexpr GenBuilder<ShaderNodes::Constant> Constant;
constexpr GenBuilder<ShaderNodes::DeclareVariable> DeclareVariable; constexpr GenBuilder<ShaderNodes::DeclareVariable> DeclareVariable;

View File

@ -78,6 +78,7 @@ namespace Nz::ShaderNodes
Branch, Branch,
Cast, Cast,
Constant, Constant,
ConditionalExpression,
ConditionalStatement, ConditionalStatement,
DeclareVariable, DeclareVariable,
ExpressionStatement, ExpressionStatement,

View File

@ -217,6 +217,20 @@ namespace Nz
static inline std::shared_ptr<Cast> Build(BasicType castTo, ExpressionPtr* expressions, std::size_t expressionCount); static inline std::shared_ptr<Cast> Build(BasicType castTo, ExpressionPtr* expressions, std::size_t expressionCount);
}; };
struct NAZARA_SHADER_API ConditionalExpression : public Expression
{
inline ConditionalExpression();
ShaderExpressionType GetExpressionType() const override;
void Visit(ShaderAstVisitor& visitor) override;
std::string conditionName;
ExpressionPtr falsePath;
ExpressionPtr truePath;
static inline std::shared_ptr<ConditionalExpression> Build(std::string condition, ExpressionPtr truePath, ExpressionPtr falsePath);
};
struct NAZARA_SHADER_API Constant : public Expression struct NAZARA_SHADER_API Constant : public Expression
{ {
inline Constant(); inline Constant();

View File

@ -263,6 +263,20 @@ namespace Nz::ShaderNodes
return node; return node;
} }
inline ConditionalExpression::ConditionalExpression() :
Expression(NodeType::ConditionalExpression)
{
}
inline std::shared_ptr<ConditionalExpression> ShaderNodes::ConditionalExpression::Build(std::string condition, ExpressionPtr truePath, ExpressionPtr falsePath)
{
auto node = std::make_shared<ConditionalExpression>();
node->conditionName = std::move(condition);
node->falsePath = std::move(falsePath);
node->truePath = std::move(truePath);
return node;
}
inline Constant::Constant() : inline Constant::Constant() :
Expression(NodeType::Constant) Expression(NodeType::Constant)

View File

@ -10,6 +10,7 @@
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp> #include <Nazara/Shader/Config.hpp>
#include <string> #include <string>
#include <unordered_set>
namespace Nz namespace Nz
{ {
@ -18,12 +19,17 @@ namespace Nz
class NAZARA_SHADER_API ShaderWriter class NAZARA_SHADER_API ShaderWriter
{ {
public: public:
struct States;
ShaderWriter() = default; ShaderWriter() = default;
ShaderWriter(const ShaderWriter&) = default; ShaderWriter(const ShaderWriter&) = default;
ShaderWriter(ShaderWriter&&) = default; ShaderWriter(ShaderWriter&&) = default;
virtual ~ShaderWriter(); virtual ~ShaderWriter();
virtual std::string Generate(const ShaderAst& shader) = 0; struct States
{
std::unordered_set<std::string> enabledConditions;
};
}; };
} }

View File

@ -32,6 +32,8 @@ namespace Nz
void Visit(ShaderNodes::AssignOp& node) override; void Visit(ShaderNodes::AssignOp& node) override;
void Visit(ShaderNodes::BinaryOp& node) override; void Visit(ShaderNodes::BinaryOp& node) override;
void Visit(ShaderNodes::Cast& node) override; void Visit(ShaderNodes::Cast& node) override;
void Visit(ShaderNodes::ConditionalExpression& node) override;
void Visit(ShaderNodes::ConditionalStatement& node) override;
void Visit(ShaderNodes::Constant& node) override; void Visit(ShaderNodes::Constant& node) override;
void Visit(ShaderNodes::DeclareVariable& node) override; void Visit(ShaderNodes::DeclareVariable& node) override;
void Visit(ShaderNodes::ExpressionStatement& node) override; void Visit(ShaderNodes::ExpressionStatement& node) override;

View File

@ -23,7 +23,7 @@ namespace Nz
{ {
class SpirvSection; class SpirvSection;
class NAZARA_SHADER_API SpirvWriter class NAZARA_SHADER_API SpirvWriter : public ShaderWriter
{ {
friend class SpirvAstVisitor; friend class SpirvAstVisitor;
friend class SpirvExpressionLoad; friend class SpirvExpressionLoad;
@ -38,7 +38,7 @@ namespace Nz
SpirvWriter(SpirvWriter&&) = delete; SpirvWriter(SpirvWriter&&) = delete;
~SpirvWriter() = default; ~SpirvWriter() = default;
std::vector<UInt32> Generate(const ShaderAst& shader); std::vector<UInt32> Generate(const ShaderAst& shader, const States& conditions = {});
void SetEnv(Environment environment); void SetEnv(Environment environment);
@ -66,6 +66,8 @@ namespace Nz
UInt32 GetPointerTypeId(const ShaderExpressionType& type, SpirvStorageClass storageClass) const; UInt32 GetPointerTypeId(const ShaderExpressionType& type, SpirvStorageClass storageClass) const;
UInt32 GetTypeId(const ShaderExpressionType& type) const; UInt32 GetTypeId(const ShaderExpressionType& type) const;
inline bool IsConditionEnabled(const std::string& condition) const;
UInt32 ReadInputVariable(const std::string& name); UInt32 ReadInputVariable(const std::string& name);
std::optional<UInt32> ReadInputVariable(const std::string& name, OnlyCache); std::optional<UInt32> ReadInputVariable(const std::string& name, OnlyCache);
UInt32 ReadLocalVariable(const std::string& name); UInt32 ReadLocalVariable(const std::string& name);
@ -88,6 +90,7 @@ namespace Nz
{ {
const ShaderAst* shader = nullptr; const ShaderAst* shader = nullptr;
const ShaderAst::Function* currentFunction = nullptr; const ShaderAst::Function* currentFunction = nullptr;
const States* states = nullptr;
}; };
struct ExtVar struct ExtVar

View File

@ -7,6 +7,10 @@
namespace Nz namespace Nz
{ {
inline bool SpirvWriter::IsConditionEnabled(const std::string& condition) const
{
return m_context.states->enabledConditions.find(condition) != m_context.states->enabledConditions.end();
}
} }
#include <Nazara/Shader/DebugOff.hpp> #include <Nazara/Shader/DebugOff.hpp>

View File

@ -48,12 +48,13 @@ namespace Nz
{ {
} }
std::string GlslWriter::Generate(const ShaderAst& shader) std::string GlslWriter::Generate(const ShaderAst& shader, const States& conditions)
{ {
std::string error; std::string error;
if (!ValidateShader(shader, &error)) if (!ValidateShader(shader, &error))
throw std::runtime_error("Invalid shader AST: " + error); throw std::runtime_error("Invalid shader AST: " + error);
m_context.states = &conditions;
m_context.shader = &shader; m_context.shader = &shader;
State state; State state;
@ -461,6 +462,21 @@ namespace Nz
Append(")"); Append(")");
} }
void GlslWriter::Visit(ShaderNodes::ConditionalExpression& node)
{
if (m_context.states->enabledConditions.count(node.conditionName) != 0)
Visit(node.truePath);
else
Visit(node.falsePath);
}
void GlslWriter::Visit(ShaderNodes::ConditionalStatement& node)
{
if (m_context.states->enabledConditions.count(node.conditionName) != 0)
Visit(node.statement);
}
void GlslWriter::Visit(ShaderNodes::Constant& node) void GlslWriter::Visit(ShaderNodes::Constant& node)
{ {
std::visit([&](auto&& arg) std::visit([&](auto&& arg)

View File

@ -7,6 +7,12 @@
namespace Nz namespace Nz
{ {
void ShaderAst::AddCondition(std::string name)
{
auto& conditionEntry = m_conditions.emplace_back();
conditionEntry.name = std::move(name);
}
void ShaderAst::AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector<FunctionParameter> parameters, ShaderNodes::BasicType returnType) void ShaderAst::AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector<FunctionParameter> parameters, ShaderNodes::BasicType returnType)
{ {
auto& functionEntry = m_functions.emplace_back(); auto& functionEntry = m_functions.emplace_back();

View File

@ -91,6 +91,16 @@ namespace Nz
PushExpression(ShaderNodes::Cast::Build(node.exprType, expressions.data(), expressionCount)); PushExpression(ShaderNodes::Cast::Build(node.exprType, expressions.data(), expressionCount));
} }
void ShaderAstCloner::Visit(ShaderNodes::ConditionalExpression& node)
{
PushExpression(ShaderNodes::ConditionalExpression::Build(node.conditionName, CloneExpression(node.truePath), CloneExpression(node.falsePath)));
}
void ShaderAstCloner::Visit(ShaderNodes::ConditionalStatement& node)
{
PushStatement(ShaderNodes::ConditionalStatement::Build(node.conditionName, CloneStatement(node.statement)));
}
void ShaderAstCloner::Visit(ShaderNodes::Constant& node) void ShaderAstCloner::Visit(ShaderNodes::Constant& node)
{ {
PushExpression(ShaderNodes::Constant::Build(node.value)); PushExpression(ShaderNodes::Constant::Build(node.value));

View File

@ -47,6 +47,17 @@ namespace Nz
} }
} }
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::ConditionalExpression& node)
{
Visit(node.truePath);
Visit(node.falsePath);
}
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::ConditionalStatement& node)
{
Visit(node.statement);
}
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Constant& /*node*/) void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Constant& /*node*/)
{ {
/* Nothing to do */ /* Nothing to do */

View File

@ -47,6 +47,16 @@ namespace Nz
Serialize(node); Serialize(node);
} }
void Visit(ShaderNodes::ConditionalExpression& node) override
{
Serialize(node);
}
void Visit(ShaderNodes::ConditionalStatement& node) override
{
Serialize(node);
}
void Visit(ShaderNodes::Constant& node) override void Visit(ShaderNodes::Constant& node) override
{ {
Serialize(node); Serialize(node);
@ -179,6 +189,19 @@ namespace Nz
Node(expr); Node(expr);
} }
void ShaderAstSerializerBase::Serialize(ShaderNodes::ConditionalExpression& node)
{
Value(node.conditionName);
Node(node.truePath);
Node(node.falsePath);
}
void ShaderAstSerializerBase::Serialize(ShaderNodes::ConditionalStatement& node)
{
Value(node.conditionName);
Node(node.statement);
}
void ShaderAstSerializerBase::Serialize(ShaderNodes::Constant& node) void ShaderAstSerializerBase::Serialize(ShaderNodes::Constant& node)
{ {
UInt32 typeIndex; UInt32 typeIndex;
@ -306,6 +329,12 @@ namespace Nz
} }
}; };
// Conditions
m_stream << UInt32(shader.GetConditionCount());
for (const auto& cond : shader.GetConditions())
m_stream << cond.name;
// Structs
m_stream << UInt32(shader.GetStructCount()); m_stream << UInt32(shader.GetStructCount());
for (const auto& s : shader.GetStructs()) for (const auto& s : shader.GetStructs())
{ {
@ -318,9 +347,11 @@ namespace Nz
} }
} }
// Inputs / Outputs
SerializeInputOutput(shader.GetInputs()); SerializeInputOutput(shader.GetInputs());
SerializeInputOutput(shader.GetOutputs()); SerializeInputOutput(shader.GetOutputs());
// Uniforms
m_stream << UInt32(shader.GetUniformCount()); m_stream << UInt32(shader.GetUniformCount());
for (const auto& uniform : shader.GetUniforms()) for (const auto& uniform : shader.GetUniforms())
{ {
@ -336,6 +367,7 @@ namespace Nz
m_stream << UInt32(uniform.memoryLayout.value()); m_stream << UInt32(uniform.memoryLayout.value());
} }
// Functions
m_stream << UInt32(shader.GetFunctionCount()); m_stream << UInt32(shader.GetFunctionCount());
for (const auto& func : shader.GetFunctions()) for (const auto& func : shader.GetFunctions())
{ {
@ -495,6 +527,18 @@ namespace Nz
ShaderAst shader(static_cast<ShaderStageType>(shaderStage)); ShaderAst shader(static_cast<ShaderStageType>(shaderStage));
// Conditions
UInt32 conditionCount;
m_stream >> conditionCount;
for (UInt32 i = 0; i < conditionCount; ++i)
{
std::string conditionName;
Value(conditionName);
shader.AddCondition(std::move(conditionName));
}
// Structs
UInt32 structCount; UInt32 structCount;
m_stream >> structCount; m_stream >> structCount;
for (UInt32 i = 0; i < structCount; ++i) for (UInt32 i = 0; i < structCount; ++i)
@ -514,6 +558,7 @@ namespace Nz
shader.AddStruct(std::move(structName), std::move(members)); shader.AddStruct(std::move(structName), std::move(members));
} }
// Inputs
UInt32 inputCount; UInt32 inputCount;
m_stream >> inputCount; m_stream >> inputCount;
for (UInt32 i = 0; i < inputCount; ++i) for (UInt32 i = 0; i < inputCount; ++i)
@ -529,6 +574,7 @@ namespace Nz
shader.AddInput(std::move(inputName), std::move(inputType), location); shader.AddInput(std::move(inputName), std::move(inputType), location);
} }
// Outputs
UInt32 outputCount; UInt32 outputCount;
m_stream >> outputCount; m_stream >> outputCount;
for (UInt32 i = 0; i < outputCount; ++i) for (UInt32 i = 0; i < outputCount; ++i)
@ -544,6 +590,7 @@ namespace Nz
shader.AddOutput(std::move(outputName), std::move(outputType), location); shader.AddOutput(std::move(outputName), std::move(outputType), location);
} }
// Uniforms
UInt32 uniformCount; UInt32 uniformCount;
m_stream >> uniformCount; m_stream >> uniformCount;
for (UInt32 i = 0; i < uniformCount; ++i) for (UInt32 i = 0; i < uniformCount; ++i)
@ -561,6 +608,7 @@ namespace Nz
shader.AddUniform(std::move(name), std::move(type), std::move(binding), std::move(memLayout)); shader.AddUniform(std::move(name), std::move(type), std::move(binding), std::move(memLayout));
} }
// Functions
UInt32 funcCount; UInt32 funcCount;
m_stream >> funcCount; m_stream >> funcCount;
for (UInt32 i = 0; i < funcCount; ++i) for (UInt32 i = 0; i < funcCount; ++i)
@ -614,6 +662,7 @@ namespace Nz
HandleType(Branch); HandleType(Branch);
HandleType(Cast); HandleType(Cast);
HandleType(Constant); HandleType(Constant);
HandleType(ConditionalExpression);
HandleType(ConditionalStatement); HandleType(ConditionalStatement);
HandleType(DeclareVariable); HandleType(DeclareVariable);
HandleType(ExpressionStatement); HandleType(ExpressionStatement);

View File

@ -241,6 +241,35 @@ namespace Nz
ShaderAstRecursiveVisitor::Visit(node); ShaderAstRecursiveVisitor::Visit(node);
} }
void ShaderAstValidator::Visit(ShaderNodes::ConditionalExpression& node)
{
MandatoryNode(node.truePath);
MandatoryNode(node.falsePath);
for (std::size_t i = 0; i < m_shader.GetConditionCount(); ++i)
{
const auto& condition = m_shader.GetCondition(i);
if (condition.name == node.conditionName)
return;
}
throw AstError{ "Condition not found" };
}
void ShaderAstValidator::Visit(ShaderNodes::ConditionalStatement& node)
{
MandatoryNode(node.statement);
for (std::size_t i = 0; i < m_shader.GetConditionCount(); ++i)
{
const auto& condition = m_shader.GetCondition(i);
if (condition.name == node.conditionName)
return;
}
throw AstError{ "Condition not found" };
}
void ShaderAstValidator::Visit(ShaderNodes::Constant& /*node*/) void ShaderAstValidator::Visit(ShaderNodes::Constant& /*node*/)
{ {
} }

View File

@ -9,19 +9,6 @@ namespace Nz
{ {
ShaderAstVisitor::~ShaderAstVisitor() = default; ShaderAstVisitor::~ShaderAstVisitor() = default;
void ShaderAstVisitor::EnableCondition(const std::string& name, bool cond)
{
if (cond)
m_conditions.insert(name);
else
m_conditions.erase(name);
}
bool ShaderAstVisitor::IsConditionEnabled(const std::string& name) const
{
return m_conditions.count(name) != 0;
}
void ShaderAstVisitor::Visit(const ShaderNodes::NodePtr& node) void ShaderAstVisitor::Visit(const ShaderNodes::NodePtr& node)
{ {
node->Visit(*this); node->Visit(*this);

View File

@ -33,6 +33,16 @@ namespace Nz
throw std::runtime_error("unhandled Cast node"); throw std::runtime_error("unhandled Cast node");
} }
void ShaderAstVisitorExcept::Visit(ShaderNodes::ConditionalExpression& /*node*/)
{
throw std::runtime_error("unhandled ConditionalExpression node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::ConditionalStatement& /*node*/)
{
throw std::runtime_error("unhandled ConditionalStatement node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::Constant& /*node*/) void ShaderAstVisitorExcept::Visit(ShaderNodes::Constant& /*node*/)
{ {
throw std::runtime_error("unhandled Constant node"); throw std::runtime_error("unhandled Constant node");

View File

@ -26,8 +26,7 @@ namespace Nz::ShaderNodes
void ConditionalStatement::Visit(ShaderAstVisitor& visitor) void ConditionalStatement::Visit(ShaderAstVisitor& visitor)
{ {
if (visitor.IsConditionEnabled(conditionName)) visitor.Visit(*this);
statement->Visit(visitor);
} }
@ -204,6 +203,18 @@ namespace Nz::ShaderNodes
} }
ShaderExpressionType ConditionalExpression::GetExpressionType() const
{
assert(truePath->GetExpressionType() == falsePath->GetExpressionType());
return truePath->GetExpressionType();
}
void ConditionalExpression::Visit(ShaderAstVisitor& visitor)
{
visitor.Visit(*this);
}
ExpressionCategory SwizzleOp::GetExpressionCategory() const ExpressionCategory SwizzleOp::GetExpressionCategory() const
{ {
return expression->GetExpressionCategory(); return expression->GetExpressionCategory();

View File

@ -313,6 +313,20 @@ namespace Nz
PushResultId(resultId); PushResultId(resultId);
} }
void SpirvAstVisitor::Visit(ShaderNodes::ConditionalExpression& node)
{
if (m_writer.IsConditionEnabled(node.conditionName))
Visit(node.truePath);
else
Visit(node.falsePath);
}
void SpirvAstVisitor::Visit(ShaderNodes::ConditionalStatement& node)
{
if (m_writer.IsConditionEnabled(node.conditionName))
Visit(node.statement);
}
void SpirvAstVisitor::Visit(ShaderNodes::Constant& node) void SpirvAstVisitor::Visit(ShaderNodes::Constant& node)
{ {
std::visit([&] (const auto& value) std::visit([&] (const auto& value)

View File

@ -33,7 +33,8 @@ namespace Nz
using LocalContainer = std::unordered_set<std::shared_ptr<const ShaderNodes::LocalVariable>>; using LocalContainer = std::unordered_set<std::shared_ptr<const ShaderNodes::LocalVariable>>;
using ParameterContainer = std::unordered_set< std::shared_ptr<const ShaderNodes::ParameterVariable>>; using ParameterContainer = std::unordered_set< std::shared_ptr<const ShaderNodes::ParameterVariable>>;
PreVisitor(SpirvConstantCache& constantCache) : PreVisitor(const SpirvWriter::States& conditions, SpirvConstantCache& constantCache) :
m_conditions(conditions),
m_constantCache(constantCache) m_constantCache(constantCache)
{ {
} }
@ -49,6 +50,20 @@ namespace Nz
ShaderAstRecursiveVisitor::Visit(node); ShaderAstRecursiveVisitor::Visit(node);
} }
void Visit(ShaderNodes::ConditionalExpression& node) override
{
if (m_conditions.enabledConditions.count(node.conditionName) != 0)
Visit(node.truePath);
else
Visit(node.falsePath);
}
void Visit(ShaderNodes::ConditionalStatement& node) override
{
if (m_conditions.enabledConditions.count(node.conditionName) != 0)
Visit(node.statement);
}
void Visit(ShaderNodes::Constant& node) override void Visit(ShaderNodes::Constant& node) override
{ {
std::visit([&](auto&& arg) std::visit([&](auto&& arg)
@ -126,6 +141,7 @@ namespace Nz
ParameterContainer paramVars; ParameterContainer paramVars;
private: private:
const SpirvWriter::States& m_conditions;
SpirvConstantCache& m_constantCache; SpirvConstantCache& m_constantCache;
}; };
@ -193,13 +209,14 @@ namespace Nz
{ {
} }
std::vector<UInt32> SpirvWriter::Generate(const ShaderAst& shader) std::vector<UInt32> SpirvWriter::Generate(const ShaderAst& shader, const States& conditions)
{ {
std::string error; std::string error;
if (!ValidateShader(shader, &error)) if (!ValidateShader(shader, &error))
throw std::runtime_error("Invalid shader AST: " + error); throw std::runtime_error("Invalid shader AST: " + error);
m_context.shader = &shader; m_context.shader = &shader;
m_context.states = &conditions;
State state; State state;
m_currentState = &state; m_currentState = &state;
@ -212,7 +229,7 @@ namespace Nz
ShaderAstCloner cloner; ShaderAstCloner cloner;
PreVisitor preVisitor(state.constantTypeCache); PreVisitor preVisitor(conditions, state.constantTypeCache);
for (const auto& func : shader.GetFunctions()) for (const auto& func : shader.GetFunctions())
{ {
functionStatements.emplace_back(cloner.Clone(func.statement)); functionStatements.emplace_back(cloner.Clone(func.statement));
@ -450,7 +467,7 @@ namespace Nz
m_environment = std::move(environment); m_environment = std::move(environment);
} }
UInt32 Nz::SpirvWriter::AllocateResultId() UInt32 SpirvWriter::AllocateResultId()
{ {
return m_currentState->nextVarIndex++; return m_currentState->nextVarIndex++;
} }

View File

@ -0,0 +1,240 @@
#include <ShaderNode/DataModels/ConditionalExpression.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <ShaderNode/ShaderGraph.hpp>
#include <ShaderNode/DataTypes/BoolData.hpp>
#include <ShaderNode/DataTypes/FloatData.hpp>
#include <ShaderNode/DataTypes/Matrix4Data.hpp>
#include <ShaderNode/DataTypes/VecData.hpp>
#include <Nazara/Shader/ShaderBuilder.hpp>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QFormLayout>
#include <iostream>
#include <sstream>
ConditionalExpression::ConditionalExpression(ShaderGraph& graph) :
ShaderNode(graph)
{
m_onConditionListUpdateSlot.Connect(GetGraph().OnConditionListUpdate, [&](ShaderGraph*) { OnConditionListUpdate(); });
m_onConditionUpdateSlot.Connect(GetGraph().OnConditionUpdate, [&](ShaderGraph*, std::size_t conditionIndex)
{
if (m_currentConditionIndex == conditionIndex)
{
UpdatePreview();
Q_EMIT dataUpdated(0);
}
});
if (graph.GetConditionCount() > 0)
{
m_currentConditionIndex = 0;
UpdateConditionText();
}
EnablePreview();
SetPreviewSize({ 128, 128 });
UpdatePreview();
}
Nz::ShaderNodes::ExpressionPtr ConditionalExpression::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const
{
assert(count == 2);
if (!m_currentConditionIndex)
throw std::runtime_error("no condition");
const ShaderGraph& graph = GetGraph();
const auto& conditionEntry = graph.GetCondition(*m_currentConditionIndex);
return Nz::ShaderBuilder::ConditionalExpression(conditionEntry.name, expressions[0], expressions[1]);
}
QString ConditionalExpression::caption() const
{
return "ConditionalExpression (" + QString::fromStdString(m_currentConditionText) + ")";
}
QString ConditionalExpression::name() const
{
return "ConditionalExpression";
}
unsigned int ConditionalExpression::nPorts(QtNodes::PortType portType) const
{
switch (portType)
{
case QtNodes::PortType::In: return 2;
case QtNodes::PortType::Out: return 1;
}
return 0;
}
void ConditionalExpression::BuildNodeEdition(QFormLayout* layout)
{
ShaderNode::BuildNodeEdition(layout);
QComboBox* conditionSelection = new QComboBox;
for (const auto& conditionEntry : GetGraph().GetConditions())
conditionSelection->addItem(QString::fromStdString(conditionEntry.name));
if (m_currentConditionIndex)
conditionSelection->setCurrentIndex(int(*m_currentConditionIndex));
else
conditionSelection->setCurrentIndex(-1);
connect(conditionSelection, qOverload<int>(&QComboBox::currentIndexChanged), [&](int index)
{
if (index >= 0)
m_currentConditionIndex = static_cast<std::size_t>(index);
else
m_currentConditionIndex.reset();
UpdateConditionText();
UpdatePreview();
Q_EMIT dataUpdated(0);
});
layout->addRow(tr("Condition"), conditionSelection);
}
auto ConditionalExpression::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType
{
return VecData::Type();
assert(portType == QtNodes::PortType::Out);
assert(portIndex == 0);
if (!m_truePath && !m_falsePath)
return VecData::Type();
return (m_truePath) ? m_truePath->type() : m_falsePath->type();
}
QString ConditionalExpression::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
{
switch (portType)
{
case QtNodes::PortType::In:
{
switch (portIndex)
{
case 0:
return "True path";
case 1:
return "False path";
default:
break;
}
}
default:
break;
}
return QString{};
}
bool ConditionalExpression::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex /*portIndex*/) const
{
return portType == QtNodes::PortType::In;
}
std::shared_ptr<QtNodes::NodeData> ConditionalExpression::outData(QtNodes::PortIndex port)
{
if (!m_currentConditionIndex)
return nullptr;
assert(port == 0);
return (GetGraph().IsConditionEnabled(*m_currentConditionIndex)) ? m_truePath : m_falsePath;
}
void ConditionalExpression::restore(const QJsonObject& data)
{
m_currentConditionText = data["condition_name"].toString().toStdString();
OnConditionListUpdate();
ShaderNode::restore(data);
}
QJsonObject ConditionalExpression::save() const
{
QJsonObject data = ShaderNode::save();
data["condition_name"] = QString::fromStdString(m_currentConditionText);
return data;
}
void ConditionalExpression::setInData(std::shared_ptr<QtNodes::NodeData> value, int index)
{
assert(index == 0 || index == 1);
if (index == 0)
m_truePath = std::move(value);
else
m_falsePath = std::move(value);
UpdatePreview();
}
QtNodes::NodeValidationState ConditionalExpression::validationState() const
{
if (!m_truePath || !m_falsePath)
return QtNodes::NodeValidationState::Error;
return QtNodes::NodeValidationState::Valid;
}
QString ConditionalExpression::validationMessage() const
{
if (!m_truePath || !m_falsePath)
return "Missing input";
return QString();
}
bool ConditionalExpression::ComputePreview(QPixmap& pixmap)
{
if (!m_currentConditionIndex)
return false;
auto input = outData(0);
if (!input || input->type().id != VecData::Type().id)
return false;
assert(dynamic_cast<VecData*>(input.get()) != nullptr);
const VecData& data = static_cast<const VecData&>(*input);
pixmap = QPixmap::fromImage(data.preview.GenerateImage());
return true;
}
void ConditionalExpression::OnConditionListUpdate()
{
m_currentConditionIndex.reset();
std::size_t conditionIndex = 0;
for (const auto& conditionEntry : GetGraph().GetConditions())
{
if (conditionEntry.name == m_currentConditionText)
{
m_currentConditionIndex = conditionIndex;
break;
}
conditionIndex++;
}
}
void ConditionalExpression::UpdateConditionText()
{
if (m_currentConditionIndex)
{
auto& condition = GetGraph().GetCondition(*m_currentConditionIndex);
m_currentConditionText = condition.name;
}
else
m_currentConditionText.clear();
}

View File

@ -0,0 +1,58 @@
#pragma once
#ifndef NAZARA_SHADERNODES_CONDITIONALEXPRESSION_HPP
#define NAZARA_SHADERNODES_CONDITIONALEXPRESSION_HPP
#include <ShaderNode/ShaderGraph.hpp>
#include <ShaderNode/DataModels/ShaderNode.hpp>
#include <optional>
#include <string>
#include <vector>
class ConditionalExpression : public ShaderNode
{
public:
ConditionalExpression(ShaderGraph& graph);
~ConditionalExpression() = default;
void BuildNodeEdition(QFormLayout* layout) override;
Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const override;
QString caption() const override;
QString name() const override;
unsigned int nPorts(QtNodes::PortType portType) const override;
QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
void restore(const QJsonObject& data) override;
QJsonObject save() const override;
void setInData(std::shared_ptr<QtNodes::NodeData> value, int index) override;
QtNodes::NodeValidationState validationState() const override;
QString validationMessage() const override;
private:
bool ComputePreview(QPixmap& pixmap) override;
void OnConditionListUpdate();
void UpdateConditionText();
NazaraSlot(ShaderGraph, OnConditionListUpdate, m_onConditionListUpdateSlot);
NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdateSlot);
std::optional<std::size_t> m_currentConditionIndex;
std::shared_ptr<QtNodes::NodeData> m_falsePath;
std::shared_ptr<QtNodes::NodeData> m_truePath;
std::string m_currentConditionText;
};
#include <ShaderNode/DataModels/BufferField.inl>
#endif

View File

@ -0,0 +1,2 @@
#include <ShaderNode/DataModels/BufferField.hpp>
#include <Nazara/Core/Algorithm.hpp>

View File

@ -238,16 +238,16 @@ void OutputValue::OnOutputListUpdate()
{ {
m_currentOutputIndex.reset(); m_currentOutputIndex.reset();
std::size_t inputIndex = 0; std::size_t outputIndex = 0;
for (const auto& inputEntry : GetGraph().GetOutputs()) for (const auto& outputEntry : GetGraph().GetOutputs())
{ {
if (inputEntry.name == m_currentOutputText) if (outputEntry.name == m_currentOutputText)
{ {
m_currentOutputIndex = inputIndex; m_currentOutputIndex = outputIndex;
break; break;
} }
inputIndex++; outputIndex++;
} }
} }

View File

@ -8,6 +8,7 @@
ShaderNode::ShaderNode(ShaderGraph& graph) : ShaderNode::ShaderNode(ShaderGraph& graph) :
m_previewSize(64, 64), m_previewSize(64, 64),
m_pixmapLabel(nullptr), m_pixmapLabel(nullptr),
m_embeddedWidget(nullptr),
m_graph(graph), m_graph(graph),
m_enableCustomVariableName(true), m_enableCustomVariableName(true),
m_isPreviewEnabled(false) m_isPreviewEnabled(false)
@ -86,7 +87,24 @@ void ShaderNode::EnablePreview(bool enable)
QWidget* ShaderNode::embeddedWidget() QWidget* ShaderNode::embeddedWidget()
{ {
return m_pixmapLabel; if (!m_embeddedWidget)
{
QWidget* embedded = EmbeddedWidget();
if (embedded)
{
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(embedded);
layout->addWidget(m_pixmapLabel);
m_embeddedWidget = new QWidget;
m_embeddedWidget->setStyleSheet("background-color: rgba(0,0,0,0)");
m_embeddedWidget->setLayout(layout);
}
else
m_embeddedWidget = m_pixmapLabel;
}
return m_embeddedWidget;
} }
void ShaderNode::restore(const QJsonObject& data) void ShaderNode::restore(const QJsonObject& data)
@ -121,6 +139,11 @@ bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/)
return false; return false;
} }
QWidget* ShaderNode::EmbeddedWidget()
{
return nullptr;
}
void ShaderNode::UpdatePreview() void ShaderNode::UpdatePreview()
{ {
if (!m_pixmap) if (!m_pixmap)

View File

@ -41,6 +41,7 @@ class ShaderNode : public QtNodes::NodeDataModel
protected: protected:
inline void DisableCustomVariableName(); inline void DisableCustomVariableName();
inline void EnableCustomVariableName(bool enable = true); inline void EnableCustomVariableName(bool enable = true);
virtual QWidget* EmbeddedWidget();
void UpdatePreview(); void UpdatePreview();
private: private:
@ -48,6 +49,7 @@ class ShaderNode : public QtNodes::NodeDataModel
Nz::Vector2i m_previewSize; Nz::Vector2i m_previewSize;
QLabel* m_pixmapLabel; QLabel* m_pixmapLabel;
QWidget* m_embeddedWidget;
std::optional<QPixmap> m_pixmap; std::optional<QPixmap> m_pixmap;
std::string m_variableName; std::string m_variableName;
ShaderGraph& m_graph; ShaderGraph& m_graph;

View File

@ -2,6 +2,7 @@
#include <Nazara/Core/StackArray.hpp> #include <Nazara/Core/StackArray.hpp>
#include <ShaderNode/DataModels/BufferField.hpp> #include <ShaderNode/DataModels/BufferField.hpp>
#include <ShaderNode/DataModels/Cast.hpp> #include <ShaderNode/DataModels/Cast.hpp>
#include <ShaderNode/DataModels/ConditionalExpression.hpp>
#include <ShaderNode/DataModels/FloatValue.hpp> #include <ShaderNode/DataModels/FloatValue.hpp>
#include <ShaderNode/DataModels/InputValue.hpp> #include <ShaderNode/DataModels/InputValue.hpp>
#include <ShaderNode/DataModels/OutputValue.hpp> #include <ShaderNode/DataModels/OutputValue.hpp>
@ -124,6 +125,17 @@ 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 index = m_conditions.size();
auto& conditionEntry = m_conditions.emplace_back();
conditionEntry.name = std::move(name);
OnConditionListUpdate(this);
return index;
}
std::size_t ShaderGraph::AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) std::size_t ShaderGraph::AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex)
{ {
std::size_t index = m_inputs.size(); std::size_t index = m_inputs.size();
@ -185,6 +197,7 @@ void ShaderGraph::Clear()
m_flowScene.clear(); m_flowScene.clear();
m_buffers.clear(); m_buffers.clear();
m_conditions.clear();
m_inputs.clear(); m_inputs.clear();
m_structs.clear(); m_structs.clear();
m_outputs.clear(); m_outputs.clear();
@ -197,6 +210,15 @@ void ShaderGraph::Clear()
OnTextureListUpdate(this); OnTextureListUpdate(this);
} }
void ShaderGraph::EnableCondition(std::size_t conditionIndex, bool enable)
{
assert(conditionIndex < m_conditions.size());
auto& conditionEntry = m_conditions[conditionIndex];
conditionEntry.enabled = enable;
OnConditionUpdate(this, conditionIndex);
}
void ShaderGraph::Load(const QJsonObject& data) void ShaderGraph::Load(const QJsonObject& data)
{ {
Clear(); Clear();
@ -218,6 +240,17 @@ void ShaderGraph::Load(const QJsonObject& data)
OnBufferListUpdate(this); OnBufferListUpdate(this);
QJsonArray conditionArray = data["conditions"].toArray();
for (const auto& conditionDocRef : conditionArray)
{
QJsonObject conditionDoc = conditionDocRef.toObject();
ConditionEntry& condition = m_conditions.emplace_back();
condition.name = conditionDoc["name"].toString().toStdString();
}
OnConditionListUpdate(this);
QJsonArray inputArray = data["inputs"].toArray(); QJsonArray inputArray = data["inputs"].toArray();
for (const auto& inputDocRef : inputArray) for (const auto& inputDocRef : inputArray)
{ {
@ -312,6 +345,18 @@ QJsonObject ShaderGraph::Save()
} }
sceneJson["buffers"] = bufferArray; sceneJson["buffers"] = bufferArray;
QJsonArray conditionArray;
{
for (const auto& condition : m_conditions)
{
QJsonObject inputDoc;
inputDoc["name"] = QString::fromStdString(condition.name);
conditionArray.append(inputDoc);
}
}
sceneJson["conditions"] = conditionArray;
QJsonArray inputArray; QJsonArray inputArray;
{ {
for (const auto& input : m_inputs) for (const auto& input : m_inputs)
@ -436,10 +481,15 @@ Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst()
(*it)++; (*it)++;
}; };
std::vector<QtNodes::Node*> outputNodes;
m_flowScene.iterateOverNodes([&](QtNodes::Node* node) m_flowScene.iterateOverNodes([&](QtNodes::Node* node)
{ {
if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0)
{
DetectVariables(node); DetectVariables(node);
outputNodes.push_back(node);
}
}); });
QHash<QUuid, Nz::ShaderNodes::ExpressionPtr> variableExpressions; QHash<QUuid, Nz::ShaderNodes::ExpressionPtr> variableExpressions;
@ -510,13 +560,8 @@ Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst()
return expression; return expression;
}; };
m_flowScene.iterateOverNodes([&](QtNodes::Node* node) for (QtNodes::Node* node : outputNodes)
{ statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node)));
if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0)
{
statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node)));
}
});
return Nz::ShaderNodes::StatementBlock::Build(std::move(statements)); return Nz::ShaderNodes::StatementBlock::Build(std::move(statements));
} }
@ -551,6 +596,15 @@ 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)
{
assert(conditionIndex < m_conditions.size());
auto& conditionEntry = m_conditions[conditionIndex];
conditionEntry.name = std::move(condition);
OnConditionUpdate(this, conditionIndex);
}
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)
{ {
assert(inputIndex < m_inputs.size()); assert(inputIndex < m_inputs.size());
@ -687,6 +741,7 @@ std::shared_ptr<QtNodes::DataModelRegistry> ShaderGraph::BuildRegistry()
RegisterShaderNode<CastToVec2>(*this, registry, "Casts"); RegisterShaderNode<CastToVec2>(*this, registry, "Casts");
RegisterShaderNode<CastToVec3>(*this, registry, "Casts"); RegisterShaderNode<CastToVec3>(*this, registry, "Casts");
RegisterShaderNode<CastToVec4>(*this, registry, "Casts"); RegisterShaderNode<CastToVec4>(*this, registry, "Casts");
RegisterShaderNode<ConditionalExpression>(*this, registry, "Shader");
RegisterShaderNode<FloatValue>(*this, registry, "Constants"); RegisterShaderNode<FloatValue>(*this, registry, "Constants");
RegisterShaderNode<InputValue>(*this, registry, "Inputs"); RegisterShaderNode<InputValue>(*this, registry, "Inputs");
RegisterShaderNode<PositionOutputValue>(*this, registry, "Outputs"); RegisterShaderNode<PositionOutputValue>(*this, registry, "Outputs");

View File

@ -18,6 +18,7 @@ class ShaderGraph
{ {
public: public:
struct BufferEntry; struct BufferEntry;
struct ConditionEntry;
struct InputEntry; struct InputEntry;
struct OutputEntry; struct OutputEntry;
struct StructEntry; struct StructEntry;
@ -28,6 +29,7 @@ class ShaderGraph
~ShaderGraph(); ~ShaderGraph();
std::size_t AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex); std::size_t AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex);
std::size_t AddCondition(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);
@ -35,9 +37,14 @@ class ShaderGraph
void Clear(); void Clear();
void EnableCondition(std::size_t conditionIndex, 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;
@ -54,6 +61,8 @@ 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;
void Load(const QJsonObject& data); void Load(const QJsonObject& data);
QJsonObject Save(); QJsonObject Save();
@ -61,6 +70,7 @@ class ShaderGraph
Nz::ShaderExpressionType ToShaderExpressionType(const std::variant<PrimitiveType, std::size_t>& type) const; Nz::ShaderExpressionType 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 bindingIndex); void UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex);
void UpdateCondition(std::size_t conditionIndex, std::string condition);
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);
@ -76,6 +86,12 @@ class ShaderGraph
BufferType type; BufferType type;
}; };
struct ConditionEntry
{
std::string name;
bool enabled = false;
};
struct InputEntry struct InputEntry
{ {
std::size_t locationIndex; std::size_t locationIndex;
@ -113,7 +129,9 @@ class ShaderGraph
}; };
NazaraSignal(OnBufferListUpdate, ShaderGraph*); NazaraSignal(OnBufferListUpdate, ShaderGraph*);
NazaraSignal(OnBufferUpdate, ShaderGraph*, std::size_t /*outputIndex*/); NazaraSignal(OnBufferUpdate, ShaderGraph*, std::size_t /*bufferIndex*/);
NazaraSignal(OnConditionListUpdate, ShaderGraph*);
NazaraSignal(OnConditionUpdate, ShaderGraph*, std::size_t /*conditionIndex*/);
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*);
@ -136,6 +154,7 @@ class ShaderGraph
QtNodes::FlowScene m_flowScene; QtNodes::FlowScene m_flowScene;
std::vector<BufferEntry> m_buffers; std::vector<BufferEntry> m_buffers;
std::vector<ConditionEntry> m_conditions;
std::vector<InputEntry> m_inputs; std::vector<InputEntry> m_inputs;
std::vector<OutputEntry> m_outputs; std::vector<OutputEntry> m_outputs;
std::vector<StructEntry> m_structs; std::vector<StructEntry> m_structs;

View File

@ -16,6 +16,22 @@ 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());
@ -95,3 +111,9 @@ inline ShaderType ShaderGraph::GetType() const
return m_type; return m_type;
} }
inline bool ShaderGraph::IsConditionEnabled(std::size_t conditionIndex) const
{
assert(conditionIndex < m_conditions.size());
return m_conditions[conditionIndex].enabled;
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,117 @@
#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);
}
}

View File

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

View File

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

View File

@ -4,6 +4,7 @@
#include <Nazara/Shader/ShaderAstSerializer.hpp> #include <Nazara/Shader/ShaderAstSerializer.hpp>
#include <ShaderNode/ShaderGraph.hpp> #include <ShaderNode/ShaderGraph.hpp>
#include <ShaderNode/Widgets/BufferEditor.hpp> #include <ShaderNode/Widgets/BufferEditor.hpp>
#include <ShaderNode/Widgets/ConditionEditor.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>
@ -84,6 +85,15 @@ m_shaderGraph(graph)
addDockWidget(Qt::RightDockWidgetArea, structDock); addDockWidget(Qt::RightDockWidgetArea, structDock);
// Condition editor
ConditionEditor* conditionEditor = new ConditionEditor(m_shaderGraph);
QDockWidget* conditionDock = new QDockWidget(tr("Conditions"));
conditionDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
conditionDock->setWidget(conditionEditor);
addDockWidget(Qt::RightDockWidgetArea, conditionDock);
m_onSelectedNodeUpdate.Connect(m_shaderGraph.OnSelectedNodeUpdate, [&](ShaderGraph*, ShaderNode* node) m_onSelectedNodeUpdate.Connect(m_shaderGraph.OnSelectedNodeUpdate, [&](ShaderGraph*, ShaderNode* node)
{ {
if (node) if (node)
@ -99,6 +109,21 @@ m_shaderGraph(graph)
BuildMenu(); BuildMenu();
m_codeOutput = new QTextEdit;
m_codeOutput->setReadOnly(true);
m_codeOutput->setWindowTitle("GLSL Output");
m_onConditionUpdate.Connect(m_shaderGraph.OnConditionUpdate, [&](ShaderGraph*, std::size_t conditionIndex)
{
if (m_codeOutput->isVisible())
OnGenerateGLSL();
});
}
MainWindow::~MainWindow()
{
delete m_codeOutput;
} }
void MainWindow::BuildMenu() void MainWindow::BuildMenu()
@ -109,6 +134,7 @@ void MainWindow::BuildMenu()
{ {
QAction* loadShader = file->addAction(tr("Load...")); QAction* loadShader = file->addAction(tr("Load..."));
QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad); QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad);
QAction* saveShader = file->addAction(tr("Save...")); QAction* saveShader = file->addAction(tr("Save..."));
QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave); QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave);
} }
@ -117,6 +143,7 @@ void MainWindow::BuildMenu()
{ {
QAction* settings = shader->addAction(tr("Settings...")); QAction* settings = shader->addAction(tr("Settings..."));
QObject::connect(settings, &QAction::triggered, this, &MainWindow::OnUpdateInfo); QObject::connect(settings, &QAction::triggered, this, &MainWindow::OnUpdateInfo);
QAction* compileShader = shader->addAction(tr("Compile...")); QAction* compileShader = shader->addAction(tr("Compile..."));
QObject::connect(compileShader, &QAction::triggered, this, &MainWindow::OnCompile); QObject::connect(compileShader, &QAction::triggered, this, &MainWindow::OnCompile);
} }
@ -155,16 +182,20 @@ void MainWindow::OnGenerateGLSL()
try try
{ {
Nz::GlslWriter writer; Nz::GlslWriter writer;
std::string glsl = writer.Generate(ToShader());
Nz::GlslWriter::States states;
for (const auto& condition : m_shaderGraph.GetConditions())
{
if (condition.enabled)
states.enabledConditions.insert(condition.name);
}
std::string glsl = writer.Generate(ToShader(), states);
std::cout << glsl << std::endl; std::cout << glsl << std::endl;
QTextEdit* output = new QTextEdit; m_codeOutput->setText(QString::fromStdString(glsl));
output->setReadOnly(true); m_codeOutput->show();
output->setText(QString::fromStdString(glsl));
output->setAttribute(Qt::WA_DeleteOnClose, true);
output->setWindowTitle("GLSL Output");
output->show();
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -238,6 +269,9 @@ Nz::ShaderAst MainWindow::ToShader()
Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst();
Nz::ShaderAst shader(ShaderGraph::ToShaderStageType(m_shaderGraph.GetType())); //< FIXME Nz::ShaderAst shader(ShaderGraph::ToShaderStageType(m_shaderGraph.GetType())); //< FIXME
for (const auto& condition : m_shaderGraph.GetConditions())
shader.AddCondition(condition.name);
for (const auto& input : m_shaderGraph.GetInputs()) for (const auto& input : m_shaderGraph.GetInputs())
shader.AddInput(input.name, m_shaderGraph.ToShaderExpressionType(input.type), input.locationIndex); shader.AddInput(input.name, m_shaderGraph.ToShaderExpressionType(input.type), input.locationIndex);

View File

@ -8,6 +8,7 @@
#include <ShaderNode/DataModels/ShaderNode.hpp> #include <ShaderNode/DataModels/ShaderNode.hpp>
class NodeEditor; class NodeEditor;
class QTextEdit;
namespace Nz namespace Nz
{ {
@ -18,7 +19,7 @@ class MainWindow : public QMainWindow
{ {
public: public:
MainWindow(ShaderGraph& graph); MainWindow(ShaderGraph& graph);
~MainWindow() = default; ~MainWindow();
private: private:
void BuildMenu(); void BuildMenu();
@ -29,10 +30,12 @@ class MainWindow : public QMainWindow
void OnUpdateInfo(); void OnUpdateInfo();
Nz::ShaderAst ToShader(); Nz::ShaderAst ToShader();
NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdate);
NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate); NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate);
NodeEditor* m_nodeEditor; NodeEditor* m_nodeEditor;
ShaderGraph& m_shaderGraph; ShaderGraph& m_shaderGraph;
QTextEdit* m_codeOutput;
}; };
#include <ShaderNode/Widgets/MainWindow.inl> #include <ShaderNode/Widgets/MainWindow.inl>