Add conditional expression/statement support for shaders
This commit is contained in:
parent
ad88561245
commit
960817a1f1
|
|
@ -16,7 +16,6 @@
|
|||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -31,7 +30,7 @@ namespace Nz
|
|||
GlslWriter(GlslWriter&&) = delete;
|
||||
~GlslWriter() = default;
|
||||
|
||||
std::string Generate(const ShaderAst& shader) override;
|
||||
std::string Generate(const ShaderAst& shader, const States& conditions = {});
|
||||
|
||||
void SetEnv(Environment environment);
|
||||
|
||||
|
|
@ -70,6 +69,8 @@ namespace Nz
|
|||
void Visit(ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(ShaderNodes::BuiltinVariable& var) 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::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
|
|
@ -91,6 +92,7 @@ namespace Nz
|
|||
{
|
||||
const ShaderAst* shader = nullptr;
|
||||
const ShaderAst::Function* currentFunction = nullptr;
|
||||
const States* states = nullptr;
|
||||
};
|
||||
|
||||
struct State
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ namespace Nz
|
|||
class NAZARA_SHADER_API ShaderAst
|
||||
{
|
||||
public:
|
||||
struct Condition;
|
||||
struct Function;
|
||||
struct FunctionParameter;
|
||||
struct InputOutput;
|
||||
|
|
@ -33,12 +34,16 @@ namespace Nz
|
|||
ShaderAst(ShaderAst&&) noexcept = 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 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 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 = {});
|
||||
|
||||
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 std::size_t GetFunctionCount() const;
|
||||
inline const std::vector<Function>& GetFunctions() const;
|
||||
|
|
@ -59,6 +64,11 @@ namespace Nz
|
|||
ShaderAst& operator=(const ShaderAst&) = default;
|
||||
ShaderAst& operator=(ShaderAst&&) noexcept = default;
|
||||
|
||||
struct Condition
|
||||
{
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct VariableBase
|
||||
{
|
||||
std::string name;
|
||||
|
|
@ -101,6 +111,7 @@ namespace Nz
|
|||
};
|
||||
|
||||
private:
|
||||
std::vector<Condition> m_conditions;
|
||||
std::vector<Function> m_functions;
|
||||
std::vector<InputOutput> m_inputs;
|
||||
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&
|
||||
{
|
||||
assert(i < m_functions.size());
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ namespace Nz
|
|||
void Visit(ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(ShaderNodes::Branch& 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::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ namespace Nz
|
|||
void Visit(ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(ShaderNodes::Branch& 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::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ namespace Nz
|
|||
void Serialize(ShaderNodes::BuiltinVariable& var);
|
||||
void Serialize(ShaderNodes::Branch& node);
|
||||
void Serialize(ShaderNodes::Cast& node);
|
||||
void Serialize(ShaderNodes::ConditionalExpression& node);
|
||||
void Serialize(ShaderNodes::ConditionalStatement& node);
|
||||
void Serialize(ShaderNodes::Constant& node);
|
||||
void Serialize(ShaderNodes::DeclareVariable& node);
|
||||
void Serialize(ShaderNodes::ExpressionStatement& node);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ namespace Nz
|
|||
void Visit(ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(ShaderNodes::Branch& 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::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@
|
|||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Shader/Config.hpp>
|
||||
#include <Nazara/Shader/ShaderNodes.hpp>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -23,16 +21,14 @@ namespace Nz
|
|||
ShaderAstVisitor(ShaderAstVisitor&&) = delete;
|
||||
virtual ~ShaderAstVisitor();
|
||||
|
||||
void EnableCondition(const std::string& name, bool cond);
|
||||
|
||||
bool IsConditionEnabled(const std::string& name) const;
|
||||
|
||||
void Visit(const ShaderNodes::NodePtr& node);
|
||||
virtual void Visit(ShaderNodes::AccessMember& node) = 0;
|
||||
virtual void Visit(ShaderNodes::AssignOp& node) = 0;
|
||||
virtual void Visit(ShaderNodes::BinaryOp& node) = 0;
|
||||
virtual void Visit(ShaderNodes::Branch& 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::DeclareVariable& node) = 0;
|
||||
virtual void Visit(ShaderNodes::ExpressionStatement& node) = 0;
|
||||
|
|
@ -44,9 +40,6 @@ namespace Nz
|
|||
|
||||
ShaderAstVisitor& operator=(const 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::Branch& 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::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ namespace Nz::ShaderBuilder
|
|||
constexpr BuiltinBuilder Builtin;
|
||||
constexpr GenBuilder<ShaderNodes::StatementBlock> Block;
|
||||
constexpr GenBuilder<ShaderNodes::Branch> Branch;
|
||||
constexpr GenBuilder<ShaderNodes::ConditionalExpression> ConditionalExpression;
|
||||
constexpr GenBuilder<ShaderNodes::ConditionalStatement> ConditionalStatement;
|
||||
constexpr GenBuilder<ShaderNodes::Constant> Constant;
|
||||
constexpr GenBuilder<ShaderNodes::DeclareVariable> DeclareVariable;
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ namespace Nz::ShaderNodes
|
|||
Branch,
|
||||
Cast,
|
||||
Constant,
|
||||
ConditionalExpression,
|
||||
ConditionalStatement,
|
||||
DeclareVariable,
|
||||
ExpressionStatement,
|
||||
|
|
|
|||
|
|
@ -217,6 +217,20 @@ namespace Nz
|
|||
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
|
||||
{
|
||||
inline Constant();
|
||||
|
|
|
|||
|
|
@ -263,6 +263,20 @@ namespace Nz::ShaderNodes
|
|||
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() :
|
||||
Expression(NodeType::Constant)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Shader/Config.hpp>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -18,12 +19,17 @@ namespace Nz
|
|||
class NAZARA_SHADER_API ShaderWriter
|
||||
{
|
||||
public:
|
||||
struct States;
|
||||
|
||||
ShaderWriter() = default;
|
||||
ShaderWriter(const ShaderWriter&) = default;
|
||||
ShaderWriter(ShaderWriter&&) = default;
|
||||
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::BinaryOp& 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::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Nz
|
|||
{
|
||||
class SpirvSection;
|
||||
|
||||
class NAZARA_SHADER_API SpirvWriter
|
||||
class NAZARA_SHADER_API SpirvWriter : public ShaderWriter
|
||||
{
|
||||
friend class SpirvAstVisitor;
|
||||
friend class SpirvExpressionLoad;
|
||||
|
|
@ -38,7 +38,7 @@ namespace Nz
|
|||
SpirvWriter(SpirvWriter&&) = delete;
|
||||
~SpirvWriter() = default;
|
||||
|
||||
std::vector<UInt32> Generate(const ShaderAst& shader);
|
||||
std::vector<UInt32> Generate(const ShaderAst& shader, const States& conditions = {});
|
||||
|
||||
void SetEnv(Environment environment);
|
||||
|
||||
|
|
@ -66,6 +66,8 @@ namespace Nz
|
|||
UInt32 GetPointerTypeId(const ShaderExpressionType& type, SpirvStorageClass storageClass) const;
|
||||
UInt32 GetTypeId(const ShaderExpressionType& type) const;
|
||||
|
||||
inline bool IsConditionEnabled(const std::string& condition) const;
|
||||
|
||||
UInt32 ReadInputVariable(const std::string& name);
|
||||
std::optional<UInt32> ReadInputVariable(const std::string& name, OnlyCache);
|
||||
UInt32 ReadLocalVariable(const std::string& name);
|
||||
|
|
@ -88,6 +90,7 @@ namespace Nz
|
|||
{
|
||||
const ShaderAst* shader = nullptr;
|
||||
const ShaderAst::Function* currentFunction = nullptr;
|
||||
const States* states = nullptr;
|
||||
};
|
||||
|
||||
struct ExtVar
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
if (!ValidateShader(shader, &error))
|
||||
throw std::runtime_error("Invalid shader AST: " + error);
|
||||
|
||||
m_context.states = &conditions;
|
||||
m_context.shader = &shader;
|
||||
|
||||
State state;
|
||||
|
|
@ -461,6 +462,21 @@ namespace Nz
|
|||
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)
|
||||
{
|
||||
std::visit([&](auto&& arg)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@
|
|||
|
||||
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)
|
||||
{
|
||||
auto& functionEntry = m_functions.emplace_back();
|
||||
|
|
|
|||
|
|
@ -91,6 +91,16 @@ namespace Nz
|
|||
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)
|
||||
{
|
||||
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*/)
|
||||
{
|
||||
/* Nothing to do */
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ namespace Nz
|
|||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(ShaderNodes::ConditionalExpression& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(ShaderNodes::ConditionalStatement& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(ShaderNodes::Constant& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
|
|
@ -179,6 +189,19 @@ namespace Nz
|
|||
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)
|
||||
{
|
||||
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());
|
||||
for (const auto& s : shader.GetStructs())
|
||||
{
|
||||
|
|
@ -318,9 +347,11 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
// Inputs / Outputs
|
||||
SerializeInputOutput(shader.GetInputs());
|
||||
SerializeInputOutput(shader.GetOutputs());
|
||||
|
||||
// Uniforms
|
||||
m_stream << UInt32(shader.GetUniformCount());
|
||||
for (const auto& uniform : shader.GetUniforms())
|
||||
{
|
||||
|
|
@ -336,6 +367,7 @@ namespace Nz
|
|||
m_stream << UInt32(uniform.memoryLayout.value());
|
||||
}
|
||||
|
||||
// Functions
|
||||
m_stream << UInt32(shader.GetFunctionCount());
|
||||
for (const auto& func : shader.GetFunctions())
|
||||
{
|
||||
|
|
@ -495,6 +527,18 @@ namespace Nz
|
|||
|
||||
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;
|
||||
m_stream >> structCount;
|
||||
for (UInt32 i = 0; i < structCount; ++i)
|
||||
|
|
@ -514,6 +558,7 @@ namespace Nz
|
|||
shader.AddStruct(std::move(structName), std::move(members));
|
||||
}
|
||||
|
||||
// Inputs
|
||||
UInt32 inputCount;
|
||||
m_stream >> inputCount;
|
||||
for (UInt32 i = 0; i < inputCount; ++i)
|
||||
|
|
@ -529,6 +574,7 @@ namespace Nz
|
|||
shader.AddInput(std::move(inputName), std::move(inputType), location);
|
||||
}
|
||||
|
||||
// Outputs
|
||||
UInt32 outputCount;
|
||||
m_stream >> outputCount;
|
||||
for (UInt32 i = 0; i < outputCount; ++i)
|
||||
|
|
@ -544,6 +590,7 @@ namespace Nz
|
|||
shader.AddOutput(std::move(outputName), std::move(outputType), location);
|
||||
}
|
||||
|
||||
// Uniforms
|
||||
UInt32 uniformCount;
|
||||
m_stream >> uniformCount;
|
||||
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));
|
||||
}
|
||||
|
||||
// Functions
|
||||
UInt32 funcCount;
|
||||
m_stream >> funcCount;
|
||||
for (UInt32 i = 0; i < funcCount; ++i)
|
||||
|
|
@ -614,6 +662,7 @@ namespace Nz
|
|||
HandleType(Branch);
|
||||
HandleType(Cast);
|
||||
HandleType(Constant);
|
||||
HandleType(ConditionalExpression);
|
||||
HandleType(ConditionalStatement);
|
||||
HandleType(DeclareVariable);
|
||||
HandleType(ExpressionStatement);
|
||||
|
|
|
|||
|
|
@ -241,6 +241,35 @@ namespace Nz
|
|||
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*/)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,19 +9,6 @@ namespace Nz
|
|||
{
|
||||
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)
|
||||
{
|
||||
node->Visit(*this);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,16 @@ namespace Nz
|
|||
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*/)
|
||||
{
|
||||
throw std::runtime_error("unhandled Constant node");
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ namespace Nz::ShaderNodes
|
|||
|
||||
void ConditionalStatement::Visit(ShaderAstVisitor& visitor)
|
||||
{
|
||||
if (visitor.IsConditionEnabled(conditionName))
|
||||
statement->Visit(visitor);
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
{
|
||||
return expression->GetExpressionCategory();
|
||||
|
|
|
|||
|
|
@ -313,6 +313,20 @@ namespace Nz
|
|||
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)
|
||||
{
|
||||
std::visit([&] (const auto& value)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ namespace Nz
|
|||
using LocalContainer = std::unordered_set<std::shared_ptr<const ShaderNodes::LocalVariable>>;
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
|
@ -49,6 +50,20 @@ namespace Nz
|
|||
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
|
||||
{
|
||||
std::visit([&](auto&& arg)
|
||||
|
|
@ -126,6 +141,7 @@ namespace Nz
|
|||
ParameterContainer paramVars;
|
||||
|
||||
private:
|
||||
const SpirvWriter::States& m_conditions;
|
||||
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;
|
||||
if (!ValidateShader(shader, &error))
|
||||
throw std::runtime_error("Invalid shader AST: " + error);
|
||||
|
||||
m_context.shader = &shader;
|
||||
m_context.states = &conditions;
|
||||
|
||||
State state;
|
||||
m_currentState = &state;
|
||||
|
|
@ -212,7 +229,7 @@ namespace Nz
|
|||
|
||||
ShaderAstCloner cloner;
|
||||
|
||||
PreVisitor preVisitor(state.constantTypeCache);
|
||||
PreVisitor preVisitor(conditions, state.constantTypeCache);
|
||||
for (const auto& func : shader.GetFunctions())
|
||||
{
|
||||
functionStatements.emplace_back(cloner.Clone(func.statement));
|
||||
|
|
@ -450,7 +467,7 @@ namespace Nz
|
|||
m_environment = std::move(environment);
|
||||
}
|
||||
|
||||
UInt32 Nz::SpirvWriter::AllocateResultId()
|
||||
UInt32 SpirvWriter::AllocateResultId()
|
||||
{
|
||||
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();
|
||||
|
||||
std::size_t inputIndex = 0;
|
||||
for (const auto& inputEntry : GetGraph().GetOutputs())
|
||||
std::size_t outputIndex = 0;
|
||||
for (const auto& outputEntry : GetGraph().GetOutputs())
|
||||
{
|
||||
if (inputEntry.name == m_currentOutputText)
|
||||
if (outputEntry.name == m_currentOutputText)
|
||||
{
|
||||
m_currentOutputIndex = inputIndex;
|
||||
m_currentOutputIndex = outputIndex;
|
||||
break;
|
||||
}
|
||||
|
||||
inputIndex++;
|
||||
outputIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
ShaderNode::ShaderNode(ShaderGraph& graph) :
|
||||
m_previewSize(64, 64),
|
||||
m_pixmapLabel(nullptr),
|
||||
m_embeddedWidget(nullptr),
|
||||
m_graph(graph),
|
||||
m_enableCustomVariableName(true),
|
||||
m_isPreviewEnabled(false)
|
||||
|
|
@ -86,7 +87,24 @@ void ShaderNode::EnablePreview(bool enable)
|
|||
|
||||
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)
|
||||
|
|
@ -121,6 +139,11 @@ bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/)
|
|||
return false;
|
||||
}
|
||||
|
||||
QWidget* ShaderNode::EmbeddedWidget()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ShaderNode::UpdatePreview()
|
||||
{
|
||||
if (!m_pixmap)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class ShaderNode : public QtNodes::NodeDataModel
|
|||
protected:
|
||||
inline void DisableCustomVariableName();
|
||||
inline void EnableCustomVariableName(bool enable = true);
|
||||
virtual QWidget* EmbeddedWidget();
|
||||
void UpdatePreview();
|
||||
|
||||
private:
|
||||
|
|
@ -48,6 +49,7 @@ class ShaderNode : public QtNodes::NodeDataModel
|
|||
|
||||
Nz::Vector2i m_previewSize;
|
||||
QLabel* m_pixmapLabel;
|
||||
QWidget* m_embeddedWidget;
|
||||
std::optional<QPixmap> m_pixmap;
|
||||
std::string m_variableName;
|
||||
ShaderGraph& m_graph;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <Nazara/Core/StackArray.hpp>
|
||||
#include <ShaderNode/DataModels/BufferField.hpp>
|
||||
#include <ShaderNode/DataModels/Cast.hpp>
|
||||
#include <ShaderNode/DataModels/ConditionalExpression.hpp>
|
||||
#include <ShaderNode/DataModels/FloatValue.hpp>
|
||||
#include <ShaderNode/DataModels/InputValue.hpp>
|
||||
#include <ShaderNode/DataModels/OutputValue.hpp>
|
||||
|
|
@ -124,6 +125,17 @@ std::size_t ShaderGraph::AddBuffer(std::string name, BufferType bufferType, std:
|
|||
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 index = m_inputs.size();
|
||||
|
|
@ -185,6 +197,7 @@ void ShaderGraph::Clear()
|
|||
m_flowScene.clear();
|
||||
|
||||
m_buffers.clear();
|
||||
m_conditions.clear();
|
||||
m_inputs.clear();
|
||||
m_structs.clear();
|
||||
m_outputs.clear();
|
||||
|
|
@ -197,6 +210,15 @@ void ShaderGraph::Clear()
|
|||
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)
|
||||
{
|
||||
Clear();
|
||||
|
|
@ -218,6 +240,17 @@ void ShaderGraph::Load(const QJsonObject& data)
|
|||
|
||||
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();
|
||||
for (const auto& inputDocRef : inputArray)
|
||||
{
|
||||
|
|
@ -312,6 +345,18 @@ QJsonObject ShaderGraph::Save()
|
|||
}
|
||||
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;
|
||||
{
|
||||
for (const auto& input : m_inputs)
|
||||
|
|
@ -436,10 +481,15 @@ Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst()
|
|||
(*it)++;
|
||||
};
|
||||
|
||||
std::vector<QtNodes::Node*> outputNodes;
|
||||
|
||||
m_flowScene.iterateOverNodes([&](QtNodes::Node* node)
|
||||
{
|
||||
if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0)
|
||||
{
|
||||
DetectVariables(node);
|
||||
outputNodes.push_back(node);
|
||||
}
|
||||
});
|
||||
|
||||
QHash<QUuid, Nz::ShaderNodes::ExpressionPtr> variableExpressions;
|
||||
|
|
@ -510,13 +560,8 @@ Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst()
|
|||
return expression;
|
||||
};
|
||||
|
||||
m_flowScene.iterateOverNodes([&](QtNodes::Node* node)
|
||||
{
|
||||
if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0)
|
||||
{
|
||||
statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node)));
|
||||
}
|
||||
});
|
||||
for (QtNodes::Node* node : outputNodes)
|
||||
statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node)));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
assert(inputIndex < m_inputs.size());
|
||||
|
|
@ -687,6 +741,7 @@ std::shared_ptr<QtNodes::DataModelRegistry> ShaderGraph::BuildRegistry()
|
|||
RegisterShaderNode<CastToVec2>(*this, registry, "Casts");
|
||||
RegisterShaderNode<CastToVec3>(*this, registry, "Casts");
|
||||
RegisterShaderNode<CastToVec4>(*this, registry, "Casts");
|
||||
RegisterShaderNode<ConditionalExpression>(*this, registry, "Shader");
|
||||
RegisterShaderNode<FloatValue>(*this, registry, "Constants");
|
||||
RegisterShaderNode<InputValue>(*this, registry, "Inputs");
|
||||
RegisterShaderNode<PositionOutputValue>(*this, registry, "Outputs");
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class ShaderGraph
|
|||
{
|
||||
public:
|
||||
struct BufferEntry;
|
||||
struct ConditionEntry;
|
||||
struct InputEntry;
|
||||
struct OutputEntry;
|
||||
struct StructEntry;
|
||||
|
|
@ -28,6 +29,7 @@ class ShaderGraph
|
|||
~ShaderGraph();
|
||||
|
||||
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 AddOutput(std::string name, PrimitiveType type, std::size_t locationIndex);
|
||||
std::size_t AddStruct(std::string name, std::vector<StructMemberEntry> members);
|
||||
|
|
@ -35,9 +37,14 @@ class ShaderGraph
|
|||
|
||||
void Clear();
|
||||
|
||||
void EnableCondition(std::size_t conditionIndex, bool enable);
|
||||
|
||||
inline const BufferEntry& GetBuffer(std::size_t bufferIndex) const;
|
||||
inline std::size_t GetBufferCount() const;
|
||||
inline const std::vector<BufferEntry>& GetBuffers() const;
|
||||
inline const ConditionEntry& GetCondition(std::size_t conditionIndex) const;
|
||||
inline std::size_t GetConditionCount() const;
|
||||
inline const std::vector<ConditionEntry>& GetConditions() const;
|
||||
inline const InputEntry& GetInput(std::size_t bufferIndex) const;
|
||||
inline std::size_t GetInputCount() const;
|
||||
inline const std::vector<InputEntry>& GetInputs() const;
|
||||
|
|
@ -54,6 +61,8 @@ class ShaderGraph
|
|||
inline const std::vector<TextureEntry>& GetTextures() const;
|
||||
inline ShaderType GetType() const;
|
||||
|
||||
inline bool IsConditionEnabled(std::size_t conditionIndex) const;
|
||||
|
||||
void Load(const QJsonObject& data);
|
||||
QJsonObject Save();
|
||||
|
||||
|
|
@ -61,6 +70,7 @@ class ShaderGraph
|
|||
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 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 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);
|
||||
|
|
@ -76,6 +86,12 @@ class ShaderGraph
|
|||
BufferType type;
|
||||
};
|
||||
|
||||
struct ConditionEntry
|
||||
{
|
||||
std::string name;
|
||||
bool enabled = false;
|
||||
};
|
||||
|
||||
struct InputEntry
|
||||
{
|
||||
std::size_t locationIndex;
|
||||
|
|
@ -113,7 +129,9 @@ class 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(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/);
|
||||
NazaraSignal(OnOutputListUpdate, ShaderGraph*);
|
||||
|
|
@ -136,6 +154,7 @@ class ShaderGraph
|
|||
|
||||
QtNodes::FlowScene m_flowScene;
|
||||
std::vector<BufferEntry> m_buffers;
|
||||
std::vector<ConditionEntry> m_conditions;
|
||||
std::vector<InputEntry> m_inputs;
|
||||
std::vector<OutputEntry> m_outputs;
|
||||
std::vector<StructEntry> m_structs;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,22 @@ inline auto ShaderGraph::GetBuffers() const -> const std::vector<BufferEntry>&
|
|||
return m_buffers;
|
||||
}
|
||||
|
||||
inline auto ShaderGraph::GetCondition(std::size_t conditionIndex) const -> const ConditionEntry&
|
||||
{
|
||||
assert(conditionIndex < m_conditions.size());
|
||||
return m_conditions[conditionIndex];
|
||||
}
|
||||
|
||||
inline std::size_t ShaderGraph::GetConditionCount() const
|
||||
{
|
||||
return m_conditions.size();
|
||||
}
|
||||
|
||||
inline auto ShaderGraph::GetConditions() const -> const std::vector<ConditionEntry>&
|
||||
{
|
||||
return m_conditions;
|
||||
}
|
||||
|
||||
inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEntry&
|
||||
{
|
||||
assert(inputIndex < m_inputs.size());
|
||||
|
|
@ -95,3 +111,9 @@ inline ShaderType ShaderGraph::GetType() const
|
|||
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 <ShaderNode/ShaderGraph.hpp>
|
||||
#include <ShaderNode/Widgets/BufferEditor.hpp>
|
||||
#include <ShaderNode/Widgets/ConditionEditor.hpp>
|
||||
#include <ShaderNode/Widgets/InputEditor.hpp>
|
||||
#include <ShaderNode/Widgets/OutputEditor.hpp>
|
||||
#include <ShaderNode/Widgets/NodeEditor.hpp>
|
||||
|
|
@ -84,6 +85,15 @@ m_shaderGraph(graph)
|
|||
|
||||
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)
|
||||
{
|
||||
if (node)
|
||||
|
|
@ -99,6 +109,21 @@ m_shaderGraph(graph)
|
|||
|
||||
|
||||
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()
|
||||
|
|
@ -109,6 +134,7 @@ void MainWindow::BuildMenu()
|
|||
{
|
||||
QAction* loadShader = file->addAction(tr("Load..."));
|
||||
QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad);
|
||||
|
||||
QAction* saveShader = file->addAction(tr("Save..."));
|
||||
QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave);
|
||||
}
|
||||
|
|
@ -117,6 +143,7 @@ void MainWindow::BuildMenu()
|
|||
{
|
||||
QAction* settings = shader->addAction(tr("Settings..."));
|
||||
QObject::connect(settings, &QAction::triggered, this, &MainWindow::OnUpdateInfo);
|
||||
|
||||
QAction* compileShader = shader->addAction(tr("Compile..."));
|
||||
QObject::connect(compileShader, &QAction::triggered, this, &MainWindow::OnCompile);
|
||||
}
|
||||
|
|
@ -155,16 +182,20 @@ void MainWindow::OnGenerateGLSL()
|
|||
try
|
||||
{
|
||||
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;
|
||||
|
||||
QTextEdit* output = new QTextEdit;
|
||||
output->setReadOnly(true);
|
||||
output->setText(QString::fromStdString(glsl));
|
||||
output->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
output->setWindowTitle("GLSL Output");
|
||||
output->show();
|
||||
m_codeOutput->setText(QString::fromStdString(glsl));
|
||||
m_codeOutput->show();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
|
@ -238,6 +269,9 @@ Nz::ShaderAst MainWindow::ToShader()
|
|||
Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst();
|
||||
|
||||
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())
|
||||
shader.AddInput(input.name, m_shaderGraph.ToShaderExpressionType(input.type), input.locationIndex);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <ShaderNode/DataModels/ShaderNode.hpp>
|
||||
|
||||
class NodeEditor;
|
||||
class QTextEdit;
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -18,7 +19,7 @@ class MainWindow : public QMainWindow
|
|||
{
|
||||
public:
|
||||
MainWindow(ShaderGraph& graph);
|
||||
~MainWindow() = default;
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
void BuildMenu();
|
||||
|
|
@ -29,10 +30,12 @@ class MainWindow : public QMainWindow
|
|||
void OnUpdateInfo();
|
||||
Nz::ShaderAst ToShader();
|
||||
|
||||
NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdate);
|
||||
NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate);
|
||||
|
||||
NodeEditor* m_nodeEditor;
|
||||
ShaderGraph& m_shaderGraph;
|
||||
QTextEdit* m_codeOutput;
|
||||
};
|
||||
|
||||
#include <ShaderNode/Widgets/MainWindow.inl>
|
||||
|
|
|
|||
Loading…
Reference in New Issue