Add conditional expression/statement support for shaders
This commit is contained in:
parent
ad88561245
commit
960817a1f1
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ namespace Nz::ShaderNodes
|
||||||
Branch,
|
Branch,
|
||||||
Cast,
|
Cast,
|
||||||
Constant,
|
Constant,
|
||||||
|
ConditionalExpression,
|
||||||
ConditionalStatement,
|
ConditionalStatement,
|
||||||
DeclareVariable,
|
DeclareVariable,
|
||||||
ExpressionStatement,
|
ExpressionStatement,
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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*/)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
#include <ShaderNode/DataModels/BufferField.hpp>
|
||||||
|
#include <Nazara/Core/Algorithm.hpp>
|
||||||
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/ConditionEditDialog.hpp>
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/ConditionEditor.hpp>
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue