First rendering using Spir-V generated shaders \o/
This commit is contained in:
parent
3829f0a002
commit
0da2ee6c99
|
|
@ -1,5 +1,6 @@
|
|||
#include <Nazara/Utility.hpp>
|
||||
#include <Nazara/Renderer.hpp>
|
||||
#include <Nazara/Renderer/ShaderAstCloner.hpp>
|
||||
#include <Nazara/Renderer/SpirvWriter.hpp>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
|
@ -7,8 +8,8 @@
|
|||
#define SPIRV 0
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
{
|
||||
/*{
|
||||
Nz::File file("frag.shader");
|
||||
if (!file.Open(Nz::OpenMode_ReadOnly))
|
||||
return __LINE__;
|
||||
|
|
@ -39,7 +40,7 @@ int main()
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*/
|
||||
Nz::Initializer<Nz::Renderer> loader;
|
||||
if (!loader)
|
||||
{
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -61,26 +61,26 @@ namespace Nz
|
|||
|
||||
using ShaderVarVisitor::Visit;
|
||||
using ShaderAstVisitor::Visit;
|
||||
void Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false);
|
||||
void Visit(const ShaderNodes::AccessMember& node) override;
|
||||
void Visit(const ShaderNodes::AssignOp& node) override;
|
||||
void Visit(const ShaderNodes::Branch& node) override;
|
||||
void Visit(const ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(const ShaderNodes::BuiltinVariable& var) override;
|
||||
void Visit(const ShaderNodes::Cast& node) override;
|
||||
void Visit(const ShaderNodes::Constant& node) override;
|
||||
void Visit(const ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(const ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(const ShaderNodes::Identifier& node) override;
|
||||
void Visit(const ShaderNodes::InputVariable& var) override;
|
||||
void Visit(const ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(const ShaderNodes::LocalVariable& var) override;
|
||||
void Visit(const ShaderNodes::ParameterVariable& var) override;
|
||||
void Visit(const ShaderNodes::OutputVariable& var) override;
|
||||
void Visit(const ShaderNodes::Sample2D& node) override;
|
||||
void Visit(const ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(const ShaderNodes::SwizzleOp& node) override;
|
||||
void Visit(const ShaderNodes::UniformVariable& var) override;
|
||||
void Visit(ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false);
|
||||
void Visit(ShaderNodes::AccessMember& node) override;
|
||||
void Visit(ShaderNodes::AssignOp& node) override;
|
||||
void Visit(ShaderNodes::Branch& node) override;
|
||||
void Visit(ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(ShaderNodes::BuiltinVariable& var) override;
|
||||
void Visit(ShaderNodes::Cast& node) override;
|
||||
void Visit(ShaderNodes::Constant& node) override;
|
||||
void Visit(ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(ShaderNodes::Identifier& node) override;
|
||||
void Visit(ShaderNodes::InputVariable& var) override;
|
||||
void Visit(ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(ShaderNodes::LocalVariable& var) override;
|
||||
void Visit(ShaderNodes::ParameterVariable& var) override;
|
||||
void Visit(ShaderNodes::OutputVariable& var) override;
|
||||
void Visit(ShaderNodes::Sample2D& node) override;
|
||||
void Visit(ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(ShaderNodes::SwizzleOp& node) override;
|
||||
void Visit(ShaderNodes::UniformVariable& var) override;
|
||||
|
||||
static bool HasExplicitBinding(const ShaderAst& shader);
|
||||
static bool HasExplicitLocation(const ShaderAst& shader);
|
||||
|
|
|
|||
|
|
@ -33,26 +33,26 @@ namespace Nz
|
|||
ShaderNodes::StatementPtr CloneStatement(const ShaderNodes::StatementPtr& statement);
|
||||
ShaderNodes::VariablePtr CloneVariable(const ShaderNodes::VariablePtr& statement);
|
||||
|
||||
void Visit(const ShaderNodes::AccessMember& node) override;
|
||||
void Visit(const ShaderNodes::AssignOp& node) override;
|
||||
void Visit(const ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(const ShaderNodes::Branch& node) override;
|
||||
void Visit(const ShaderNodes::Cast& node) override;
|
||||
void Visit(const ShaderNodes::Constant& node) override;
|
||||
void Visit(const ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(const ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(const ShaderNodes::Identifier& node) override;
|
||||
void Visit(const ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(const ShaderNodes::Sample2D& node) override;
|
||||
void Visit(const ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(const ShaderNodes::SwizzleOp& node) override;
|
||||
void Visit(ShaderNodes::AccessMember& node) override;
|
||||
void Visit(ShaderNodes::AssignOp& node) override;
|
||||
void Visit(ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(ShaderNodes::Branch& node) override;
|
||||
void Visit(ShaderNodes::Cast& node) override;
|
||||
void Visit(ShaderNodes::Constant& node) override;
|
||||
void Visit(ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(ShaderNodes::Identifier& node) override;
|
||||
void Visit(ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(ShaderNodes::Sample2D& node) override;
|
||||
void Visit(ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(ShaderNodes::SwizzleOp& node) override;
|
||||
|
||||
void Visit(const ShaderNodes::BuiltinVariable& var) override;
|
||||
void Visit(const ShaderNodes::InputVariable& var) override;
|
||||
void Visit(const ShaderNodes::LocalVariable& var) override;
|
||||
void Visit(const ShaderNodes::OutputVariable& var) override;
|
||||
void Visit(const ShaderNodes::ParameterVariable& var) override;
|
||||
void Visit(const ShaderNodes::UniformVariable& var) override;
|
||||
void Visit(ShaderNodes::BuiltinVariable& var) override;
|
||||
void Visit(ShaderNodes::InputVariable& var) override;
|
||||
void Visit(ShaderNodes::LocalVariable& var) override;
|
||||
void Visit(ShaderNodes::OutputVariable& var) override;
|
||||
void Visit(ShaderNodes::ParameterVariable& var) override;
|
||||
void Visit(ShaderNodes::UniformVariable& var) override;
|
||||
|
||||
void PushExpression(ShaderNodes::ExpressionPtr expression);
|
||||
void PushStatement(ShaderNodes::StatementPtr statement);
|
||||
|
|
|
|||
|
|
@ -21,19 +21,19 @@ namespace Nz
|
|||
|
||||
using ShaderAstVisitor::Visit;
|
||||
|
||||
void Visit(const ShaderNodes::AccessMember& node) override;
|
||||
void Visit(const ShaderNodes::AssignOp& node) override;
|
||||
void Visit(const ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(const ShaderNodes::Branch& node) override;
|
||||
void Visit(const ShaderNodes::Cast& node) override;
|
||||
void Visit(const ShaderNodes::Constant& node) override;
|
||||
void Visit(const ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(const ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(const ShaderNodes::Identifier& node) override;
|
||||
void Visit(const ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(const ShaderNodes::Sample2D& node) override;
|
||||
void Visit(const ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(const ShaderNodes::SwizzleOp& node) override;
|
||||
void Visit(ShaderNodes::AccessMember& node) override;
|
||||
void Visit(ShaderNodes::AssignOp& node) override;
|
||||
void Visit(ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(ShaderNodes::Branch& node) override;
|
||||
void Visit(ShaderNodes::Cast& node) override;
|
||||
void Visit(ShaderNodes::Constant& node) override;
|
||||
void Visit(ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(ShaderNodes::Identifier& node) override;
|
||||
void Visit(ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(ShaderNodes::Sample2D& node) override;
|
||||
void Visit(ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(ShaderNodes::SwizzleOp& node) override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,9 +57,13 @@ namespace Nz
|
|||
virtual void Value(bool& val) = 0;
|
||||
virtual void Value(float& val) = 0;
|
||||
virtual void Value(std::string& val) = 0;
|
||||
virtual void Value(Int32& val) = 0;
|
||||
virtual void Value(Vector2f& val) = 0;
|
||||
virtual void Value(Vector3f& val) = 0;
|
||||
virtual void Value(Vector4f& val) = 0;
|
||||
virtual void Value(Vector2i32& val) = 0;
|
||||
virtual void Value(Vector3i32& val) = 0;
|
||||
virtual void Value(Vector4i32& val) = 0;
|
||||
virtual void Value(UInt8& val) = 0;
|
||||
virtual void Value(UInt16& val) = 0;
|
||||
virtual void Value(UInt32& val) = 0;
|
||||
|
|
@ -85,9 +89,13 @@ namespace Nz
|
|||
void Value(bool& val) override;
|
||||
void Value(float& val) override;
|
||||
void Value(std::string& val) override;
|
||||
void Value(Int32& val) override;
|
||||
void Value(Vector2f& val) override;
|
||||
void Value(Vector3f& val) override;
|
||||
void Value(Vector4f& val) override;
|
||||
void Value(Vector2i32& val) override;
|
||||
void Value(Vector3i32& val) override;
|
||||
void Value(Vector4i32& val) override;
|
||||
void Value(UInt8& val) override;
|
||||
void Value(UInt16& val) override;
|
||||
void Value(UInt32& val) override;
|
||||
|
|
@ -111,9 +119,13 @@ namespace Nz
|
|||
void Value(bool& val) override;
|
||||
void Value(float& val) override;
|
||||
void Value(std::string& val) override;
|
||||
void Value(Int32& val) override;
|
||||
void Value(Vector2f& val) override;
|
||||
void Value(Vector3f& val) override;
|
||||
void Value(Vector4f& val) override;
|
||||
void Value(Vector2i32& val) override;
|
||||
void Value(Vector3i32& val) override;
|
||||
void Value(Vector4i32& val) override;
|
||||
void Value(UInt8& val) override;
|
||||
void Value(UInt16& val) override;
|
||||
void Value(UInt32& val) override;
|
||||
|
|
|
|||
|
|
@ -34,27 +34,27 @@ namespace Nz
|
|||
void TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right);
|
||||
|
||||
using ShaderAstRecursiveVisitor::Visit;
|
||||
void Visit(const ShaderNodes::AccessMember& node) override;
|
||||
void Visit(const ShaderNodes::AssignOp& node) override;
|
||||
void Visit(const ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(const ShaderNodes::Branch& node) override;
|
||||
void Visit(const ShaderNodes::Cast& node) override;
|
||||
void Visit(const ShaderNodes::Constant& node) override;
|
||||
void Visit(const ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(const ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(const ShaderNodes::Identifier& node) override;
|
||||
void Visit(const ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(const ShaderNodes::Sample2D& node) override;
|
||||
void Visit(const ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(const ShaderNodes::SwizzleOp& node) override;
|
||||
void Visit(ShaderNodes::AccessMember& node) override;
|
||||
void Visit(ShaderNodes::AssignOp& node) override;
|
||||
void Visit(ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(ShaderNodes::Branch& node) override;
|
||||
void Visit(ShaderNodes::Cast& node) override;
|
||||
void Visit(ShaderNodes::Constant& node) override;
|
||||
void Visit(ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(ShaderNodes::Identifier& node) override;
|
||||
void Visit(ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(ShaderNodes::Sample2D& node) override;
|
||||
void Visit(ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(ShaderNodes::SwizzleOp& node) override;
|
||||
|
||||
using ShaderVarVisitor::Visit;
|
||||
void Visit(const ShaderNodes::BuiltinVariable& var) override;
|
||||
void Visit(const ShaderNodes::InputVariable& var) override;
|
||||
void Visit(const ShaderNodes::LocalVariable& var) override;
|
||||
void Visit(const ShaderNodes::OutputVariable& var) override;
|
||||
void Visit(const ShaderNodes::ParameterVariable& var) override;
|
||||
void Visit(const ShaderNodes::UniformVariable& var) override;
|
||||
void Visit(ShaderNodes::BuiltinVariable& var) override;
|
||||
void Visit(ShaderNodes::InputVariable& var) override;
|
||||
void Visit(ShaderNodes::LocalVariable& var) override;
|
||||
void Visit(ShaderNodes::OutputVariable& var) override;
|
||||
void Visit(ShaderNodes::ParameterVariable& var) override;
|
||||
void Visit(ShaderNodes::UniformVariable& var) override;
|
||||
|
||||
struct Context;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,20 +27,20 @@ namespace Nz
|
|||
|
||||
bool IsConditionEnabled(const std::string& name) const;
|
||||
|
||||
virtual void Visit(const ShaderNodes::AccessMember& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::AssignOp& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::BinaryOp& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::Branch& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::Cast& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::Constant& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::DeclareVariable& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::ExpressionStatement& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::Identifier& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::IntrinsicCall& node) = 0;
|
||||
void Visit(const ShaderNodes::NodePtr& node);
|
||||
virtual void Visit(const ShaderNodes::Sample2D& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::StatementBlock& node) = 0;
|
||||
virtual void Visit(const ShaderNodes::SwizzleOp& node) = 0;
|
||||
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::Constant& node) = 0;
|
||||
virtual void Visit(ShaderNodes::DeclareVariable& node) = 0;
|
||||
virtual void Visit(ShaderNodes::ExpressionStatement& node) = 0;
|
||||
virtual void Visit(ShaderNodes::Identifier& node) = 0;
|
||||
virtual void Visit(ShaderNodes::IntrinsicCall& node) = 0;
|
||||
virtual void Visit(ShaderNodes::Sample2D& node) = 0;
|
||||
virtual void Visit(ShaderNodes::StatementBlock& node) = 0;
|
||||
virtual void Visit(ShaderNodes::SwizzleOp& node) = 0;
|
||||
|
||||
private:
|
||||
std::unordered_set<std::string> m_conditions;
|
||||
|
|
|
|||
|
|
@ -18,15 +18,19 @@ namespace Nz::ShaderNodes
|
|||
|
||||
enum class BasicType
|
||||
{
|
||||
Boolean, // bool
|
||||
Float1, // float
|
||||
Float2, // vec2
|
||||
Float3, // vec3
|
||||
Float4, // vec4
|
||||
Mat4x4, // mat4
|
||||
Sampler2D, // sampler2D
|
||||
Boolean, //< bool
|
||||
Float1, //< float
|
||||
Float2, //< vec2
|
||||
Float3, //< vec3
|
||||
Float4, //< vec4
|
||||
Int1, //< int
|
||||
Int2, //< ivec2
|
||||
Int3, //< ivec3
|
||||
Int4, //< ivec4
|
||||
Mat4x4, //< mat4
|
||||
Sampler2D, //< sampler2D
|
||||
|
||||
Void // void
|
||||
Void //< void
|
||||
};
|
||||
|
||||
enum class BinaryType
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ namespace Nz
|
|||
|
||||
std::size_t memberIndex;
|
||||
ExpressionPtr structExpr;
|
||||
ShaderExpressionType exprType; //< FIXME: Use ShaderAst to automate
|
||||
ShaderExpressionType exprType;
|
||||
|
||||
static inline std::shared_ptr<AccessMember> Build(ExpressionPtr structExpr, std::size_t memberIndex, ShaderExpressionType exprType);
|
||||
};
|
||||
|
|
@ -225,9 +225,13 @@ namespace Nz
|
|||
using Variant = std::variant<
|
||||
bool,
|
||||
float,
|
||||
Int32,
|
||||
Vector2f,
|
||||
Vector3f,
|
||||
Vector4f
|
||||
Vector4f,
|
||||
Vector2i32,
|
||||
Vector3i32,
|
||||
Vector4i32
|
||||
>;
|
||||
|
||||
Variant value;
|
||||
|
|
|
|||
|
|
@ -28,12 +28,15 @@ namespace Nz::ShaderNodes
|
|||
switch (type)
|
||||
{
|
||||
case BasicType::Float2:
|
||||
case BasicType::Int2:
|
||||
return 2;
|
||||
|
||||
case BasicType::Float3:
|
||||
case BasicType::Int3:
|
||||
return 3;
|
||||
|
||||
case BasicType::Float4:
|
||||
case BasicType::Int4:
|
||||
return 4;
|
||||
|
||||
case BasicType::Mat4x4:
|
||||
|
|
@ -53,6 +56,11 @@ namespace Nz::ShaderNodes
|
|||
case BasicType::Float4:
|
||||
return BasicType::Float1;
|
||||
|
||||
case BasicType::Int2:
|
||||
case BasicType::Int3:
|
||||
case BasicType::Int4:
|
||||
return BasicType::Int1;
|
||||
|
||||
case BasicType::Mat4x4:
|
||||
return BasicType::Float4;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,13 +21,14 @@ namespace Nz
|
|||
ShaderVarVisitor(ShaderVarVisitor&&) = delete;
|
||||
virtual ~ShaderVarVisitor();
|
||||
|
||||
virtual void Visit(const ShaderNodes::BuiltinVariable& var) = 0;
|
||||
virtual void Visit(const ShaderNodes::InputVariable& var) = 0;
|
||||
virtual void Visit(const ShaderNodes::LocalVariable& var) = 0;
|
||||
virtual void Visit(const ShaderNodes::OutputVariable& var) = 0;
|
||||
virtual void Visit(const ShaderNodes::ParameterVariable& var) = 0;
|
||||
virtual void Visit(const ShaderNodes::UniformVariable& var) = 0;
|
||||
void Visit(const ShaderNodes::VariablePtr& node);
|
||||
|
||||
virtual void Visit(ShaderNodes::BuiltinVariable& var) = 0;
|
||||
virtual void Visit(ShaderNodes::InputVariable& var) = 0;
|
||||
virtual void Visit(ShaderNodes::LocalVariable& var) = 0;
|
||||
virtual void Visit(ShaderNodes::OutputVariable& var) = 0;
|
||||
virtual void Visit(ShaderNodes::ParameterVariable& var) = 0;
|
||||
virtual void Visit(ShaderNodes::UniformVariable& var) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/ShaderAst.hpp>
|
||||
#include <Nazara/Renderer/ShaderVarVisitor.hpp>
|
||||
#include <Nazara/Renderer/ShaderAstVisitor.hpp>
|
||||
#include <Nazara/Renderer/ShaderVarVisitor.hpp>
|
||||
#include <Nazara/Renderer/ShaderWriter.hpp>
|
||||
#include <Nazara/Utility/FieldOffsets.hpp>
|
||||
#include <string>
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_RENDERER_API SpirvWriter : public ShaderAstVisitor
|
||||
class NAZARA_RENDERER_API SpirvWriter : public ShaderAstVisitor, public ShaderVarVisitor
|
||||
{
|
||||
public:
|
||||
struct Environment;
|
||||
|
|
@ -41,6 +41,7 @@ namespace Nz
|
|||
};
|
||||
|
||||
private:
|
||||
struct ExtVar;
|
||||
struct Opcode;
|
||||
struct Raw;
|
||||
struct WordCount;
|
||||
|
|
@ -76,28 +77,39 @@ namespace Nz
|
|||
void AppendStructType(std::size_t structIndex, UInt32 resultId);
|
||||
void AppendTypes();
|
||||
|
||||
UInt32 EvaluateExpression(const ShaderNodes::ExpressionPtr& expr);
|
||||
|
||||
UInt32 GetConstantId(const ShaderNodes::Constant::Variant& value) const;
|
||||
UInt32 GetTypeId(const ShaderExpressionType& type) const;
|
||||
|
||||
void PushResultId(UInt32 value);
|
||||
UInt32 PopResultId();
|
||||
|
||||
UInt32 ReadVariable(ExtVar& var);
|
||||
UInt32 RegisterType(ShaderExpressionType type);
|
||||
|
||||
using ShaderAstVisitor::Visit;
|
||||
void Visit(const ShaderNodes::AccessMember& node) override;
|
||||
void Visit(const ShaderNodes::AssignOp& node) override;
|
||||
void Visit(const ShaderNodes::Branch& node) override;
|
||||
void Visit(const ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(const ShaderNodes::Cast& node) override;
|
||||
void Visit(const ShaderNodes::Constant& node) override;
|
||||
void Visit(const ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(const ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(const ShaderNodes::Identifier& node) override;
|
||||
void Visit(const ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(const ShaderNodes::Sample2D& node) override;
|
||||
void Visit(const ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(const ShaderNodes::SwizzleOp& node) override;
|
||||
void Visit(ShaderNodes::AccessMember& node) override;
|
||||
void Visit(ShaderNodes::AssignOp& node) override;
|
||||
void Visit(ShaderNodes::Branch& node) override;
|
||||
void Visit(ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(ShaderNodes::Cast& node) override;
|
||||
void Visit(ShaderNodes::Constant& node) override;
|
||||
void Visit(ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(ShaderNodes::Identifier& node) override;
|
||||
void Visit(ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(ShaderNodes::Sample2D& node) override;
|
||||
void Visit(ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(ShaderNodes::SwizzleOp& node) override;
|
||||
|
||||
using ShaderVarVisitor::Visit;
|
||||
void Visit(ShaderNodes::BuiltinVariable& var) override;
|
||||
void Visit(ShaderNodes::InputVariable& var) override;
|
||||
void Visit(ShaderNodes::LocalVariable& var) override;
|
||||
void Visit(ShaderNodes::OutputVariable& var) override;
|
||||
void Visit(ShaderNodes::ParameterVariable& var) override;
|
||||
void Visit(ShaderNodes::UniformVariable& var) override;
|
||||
|
||||
static void MergeBlocks(std::vector<UInt32>& output, const Section& from);
|
||||
|
||||
|
|
|
|||
|
|
@ -188,30 +188,18 @@ namespace Nz
|
|||
{
|
||||
switch (type)
|
||||
{
|
||||
case ShaderNodes::BasicType::Boolean:
|
||||
Append("bool");
|
||||
break;
|
||||
case ShaderNodes::BasicType::Float1:
|
||||
Append("float");
|
||||
break;
|
||||
case ShaderNodes::BasicType::Float2:
|
||||
Append("vec2");
|
||||
break;
|
||||
case ShaderNodes::BasicType::Float3:
|
||||
Append("vec3");
|
||||
break;
|
||||
case ShaderNodes::BasicType::Float4:
|
||||
Append("vec4");
|
||||
break;
|
||||
case ShaderNodes::BasicType::Mat4x4:
|
||||
Append("mat4");
|
||||
break;
|
||||
case ShaderNodes::BasicType::Sampler2D:
|
||||
Append("sampler2D");
|
||||
break;
|
||||
case ShaderNodes::BasicType::Void:
|
||||
Append("void");
|
||||
break;
|
||||
case ShaderNodes::BasicType::Boolean: return Append("bool");
|
||||
case ShaderNodes::BasicType::Float1: return Append("float");
|
||||
case ShaderNodes::BasicType::Float2: return Append("vec2");
|
||||
case ShaderNodes::BasicType::Float3: return Append("vec3");
|
||||
case ShaderNodes::BasicType::Float4: return Append("vec4");
|
||||
case ShaderNodes::BasicType::Int1: return Append("int");
|
||||
case ShaderNodes::BasicType::Int2: return Append("ivec2");
|
||||
case ShaderNodes::BasicType::Int3: return Append("ivec3");
|
||||
case ShaderNodes::BasicType::Int4: return Append("ivec4");
|
||||
case ShaderNodes::BasicType::Mat4x4: return Append("mat4");
|
||||
case ShaderNodes::BasicType::Sampler2D: return Append("sampler2D");
|
||||
case ShaderNodes::BasicType::Void: return Append("void");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +286,7 @@ namespace Nz
|
|||
AppendLine("}");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired)
|
||||
void GlslWriter::Visit(ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired)
|
||||
{
|
||||
bool enclose = encloseIfRequired && (expr->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue);
|
||||
|
||||
|
|
@ -311,7 +299,7 @@ namespace Nz
|
|||
Append(")");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::AccessMember& node)
|
||||
void GlslWriter::Visit(ShaderNodes::AccessMember& node)
|
||||
{
|
||||
Visit(node.structExpr, true);
|
||||
|
||||
|
|
@ -332,7 +320,7 @@ namespace Nz
|
|||
Append(member.name);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::AssignOp& node)
|
||||
void GlslWriter::Visit(ShaderNodes::AssignOp& node)
|
||||
{
|
||||
Visit(node.left);
|
||||
|
||||
|
|
@ -346,7 +334,7 @@ namespace Nz
|
|||
Visit(node.right);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::Branch& node)
|
||||
void GlslWriter::Visit(ShaderNodes::Branch& node)
|
||||
{
|
||||
bool first = true;
|
||||
for (const auto& statement : node.condStatements)
|
||||
|
|
@ -375,7 +363,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::BinaryOp& node)
|
||||
void GlslWriter::Visit(ShaderNodes::BinaryOp& node)
|
||||
{
|
||||
Visit(node.left, true);
|
||||
|
||||
|
|
@ -401,12 +389,12 @@ namespace Nz
|
|||
Visit(node.right, true);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::BuiltinVariable& var)
|
||||
void GlslWriter::Visit(ShaderNodes::BuiltinVariable& var)
|
||||
{
|
||||
Append(var.entry);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::Cast& node)
|
||||
void GlslWriter::Visit(ShaderNodes::Cast& node)
|
||||
{
|
||||
Append(node.exprType);
|
||||
Append("(");
|
||||
|
|
@ -425,28 +413,31 @@ namespace Nz
|
|||
Append(")");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::Constant& node)
|
||||
void GlslWriter::Visit(ShaderNodes::Constant& node)
|
||||
{
|
||||
std::visit([&](auto&& arg)
|
||||
{
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, Vector2i32> || std::is_same_v<T, Vector3i32> || std::is_same_v<T, Vector4i32>)
|
||||
Append("i"); //< for ivec
|
||||
|
||||
if constexpr (std::is_same_v<T, bool>)
|
||||
Append((arg) ? "true" : "false");
|
||||
else if constexpr (std::is_same_v<T, float>)
|
||||
else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, Int32>)
|
||||
Append(std::to_string(arg));
|
||||
else if constexpr (std::is_same_v<T, Vector2f>)
|
||||
else if constexpr (std::is_same_v<T, Vector2f> || std::is_same_v<T, Vector2i32>)
|
||||
Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")");
|
||||
else if constexpr (std::is_same_v<T, Vector3f>)
|
||||
else if constexpr (std::is_same_v<T, Vector3f> || std::is_same_v<T, Vector3i32>)
|
||||
Append("vec3(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")");
|
||||
else if constexpr (std::is_same_v<T, Vector4f>)
|
||||
else if constexpr (std::is_same_v<T, Vector4f> || std::is_same_v<T, Vector4i32>)
|
||||
Append("vec4(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")");
|
||||
else
|
||||
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
||||
}, node.value);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::DeclareVariable& node)
|
||||
void GlslWriter::Visit(ShaderNodes::DeclareVariable& node)
|
||||
{
|
||||
assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable);
|
||||
|
||||
|
|
@ -464,23 +455,23 @@ namespace Nz
|
|||
AppendLine(";");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::ExpressionStatement& node)
|
||||
void GlslWriter::Visit(ShaderNodes::ExpressionStatement& node)
|
||||
{
|
||||
Visit(node.expression);
|
||||
Append(";");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::Identifier& node)
|
||||
void GlslWriter::Visit(ShaderNodes::Identifier& node)
|
||||
{
|
||||
Visit(node.var);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::InputVariable& var)
|
||||
void GlslWriter::Visit(ShaderNodes::InputVariable& var)
|
||||
{
|
||||
Append(var.name);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::IntrinsicCall& node)
|
||||
void GlslWriter::Visit(ShaderNodes::IntrinsicCall& node)
|
||||
{
|
||||
switch (node.intrinsic)
|
||||
{
|
||||
|
|
@ -504,22 +495,22 @@ namespace Nz
|
|||
Append(")");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::LocalVariable& var)
|
||||
void GlslWriter::Visit(ShaderNodes::LocalVariable& var)
|
||||
{
|
||||
Append(var.name);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::ParameterVariable& var)
|
||||
void GlslWriter::Visit(ShaderNodes::ParameterVariable& var)
|
||||
{
|
||||
Append(var.name);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::OutputVariable& var)
|
||||
void GlslWriter::Visit(ShaderNodes::OutputVariable& var)
|
||||
{
|
||||
Append(var.name);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::Sample2D& node)
|
||||
void GlslWriter::Visit(ShaderNodes::Sample2D& node)
|
||||
{
|
||||
Append("texture(");
|
||||
Visit(node.sampler);
|
||||
|
|
@ -528,7 +519,7 @@ namespace Nz
|
|||
Append(")");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::StatementBlock& node)
|
||||
void GlslWriter::Visit(ShaderNodes::StatementBlock& node)
|
||||
{
|
||||
bool first = true;
|
||||
for (const ShaderNodes::StatementPtr& statement : node.statements)
|
||||
|
|
@ -542,7 +533,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::SwizzleOp& node)
|
||||
void GlslWriter::Visit(ShaderNodes::SwizzleOp& node)
|
||||
{
|
||||
Visit(node.expression);
|
||||
Append(".");
|
||||
|
|
@ -570,7 +561,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::UniformVariable& var)
|
||||
void GlslWriter::Visit(ShaderNodes::UniformVariable& var)
|
||||
{
|
||||
Append(var.name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ namespace Nz
|
|||
};
|
||||
|
||||
RegisterImpl("NazaraOpenGLRenderer" NazaraRendererDebugSuffix, [] { return 50; });
|
||||
//RegisterImpl("NazaraVulkanRenderer" NazaraRendererDebugSuffix, [] { return 100; });
|
||||
RegisterImpl("NazaraVulkanRenderer" NazaraRendererDebugSuffix, [] { return 100; });
|
||||
|
||||
std::sort(implementations.begin(), implementations.end(), [](const auto& lhs, const auto& rhs) { return lhs.score > rhs.score; });
|
||||
|
||||
|
|
|
|||
|
|
@ -45,22 +45,22 @@ namespace Nz
|
|||
return PopVariable();
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::AccessMember& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::AccessMember& node)
|
||||
{
|
||||
PushExpression(ShaderNodes::AccessMember::Build(CloneExpression(node.structExpr), node.memberIndex, node.exprType));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::AssignOp& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::AssignOp& node)
|
||||
{
|
||||
PushExpression(ShaderNodes::AssignOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right)));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::BinaryOp& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::BinaryOp& node)
|
||||
{
|
||||
PushExpression(ShaderNodes::BinaryOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right)));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::Branch& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::Branch& node)
|
||||
{
|
||||
std::vector<ShaderNodes::Branch::ConditionalStatement> condStatements;
|
||||
condStatements.reserve(node.condStatements.size());
|
||||
|
|
@ -75,7 +75,7 @@ namespace Nz
|
|||
PushStatement(ShaderNodes::Branch::Build(std::move(condStatements), CloneStatement(node.elseStatement)));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::Cast& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::Cast& node)
|
||||
{
|
||||
std::size_t expressionCount = 0;
|
||||
std::array<ShaderNodes::ExpressionPtr, 4> expressions;
|
||||
|
|
@ -91,27 +91,27 @@ namespace Nz
|
|||
PushExpression(ShaderNodes::Cast::Build(node.exprType, expressions.data(), expressionCount));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::Constant& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::Constant& node)
|
||||
{
|
||||
PushExpression(ShaderNodes::Constant::Build(node.value));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::DeclareVariable& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::DeclareVariable& node)
|
||||
{
|
||||
PushStatement(ShaderNodes::DeclareVariable::Build(CloneVariable(node.variable), CloneExpression(node.expression)));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::ExpressionStatement& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::ExpressionStatement& node)
|
||||
{
|
||||
PushStatement(ShaderNodes::ExpressionStatement::Build(CloneExpression(node.expression)));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::Identifier& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::Identifier& node)
|
||||
{
|
||||
PushExpression(ShaderNodes::Identifier::Build(CloneVariable(node.var)));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::IntrinsicCall& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::IntrinsicCall& node)
|
||||
{
|
||||
std::vector<ShaderNodes::ExpressionPtr> parameters;
|
||||
parameters.reserve(node.parameters.size());
|
||||
|
|
@ -122,12 +122,12 @@ namespace Nz
|
|||
PushExpression(ShaderNodes::IntrinsicCall::Build(node.intrinsic, std::move(parameters)));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::Sample2D& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::Sample2D& node)
|
||||
{
|
||||
PushExpression(ShaderNodes::Sample2D::Build(CloneExpression(node.sampler), CloneExpression(node.coordinates)));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::StatementBlock& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::StatementBlock& node)
|
||||
{
|
||||
std::vector<ShaderNodes::StatementPtr> statements;
|
||||
statements.reserve(node.statements.size());
|
||||
|
|
@ -138,37 +138,37 @@ namespace Nz
|
|||
PushStatement(ShaderNodes::StatementBlock::Build(std::move(statements)));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::SwizzleOp& node)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::SwizzleOp& node)
|
||||
{
|
||||
PushExpression(ShaderNodes::SwizzleOp::Build(PopExpression(), node.components.data(), node.componentCount));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::BuiltinVariable& var)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::BuiltinVariable& var)
|
||||
{
|
||||
PushVariable(ShaderNodes::BuiltinVariable::Build(var.entry, var.type));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::InputVariable& var)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::InputVariable& var)
|
||||
{
|
||||
PushVariable(ShaderNodes::InputVariable::Build(var.name, var.type));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::LocalVariable& var)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::LocalVariable& var)
|
||||
{
|
||||
PushVariable(ShaderNodes::LocalVariable::Build(var.name, var.type));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::OutputVariable& var)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::OutputVariable& var)
|
||||
{
|
||||
PushVariable(ShaderNodes::OutputVariable::Build(var.name, var.type));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::ParameterVariable& var)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::ParameterVariable& var)
|
||||
{
|
||||
PushVariable(ShaderNodes::ParameterVariable::Build(var.name, var.type));
|
||||
}
|
||||
|
||||
void ShaderAstCloner::Visit(const ShaderNodes::UniformVariable& var)
|
||||
void ShaderAstCloner::Visit(ShaderNodes::UniformVariable& var)
|
||||
{
|
||||
PushVariable(ShaderNodes::UniformVariable::Build(var.name, var.type));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,24 +7,24 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::AccessMember& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::AccessMember& node)
|
||||
{
|
||||
Visit(node.structExpr);
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::AssignOp& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::AssignOp& node)
|
||||
{
|
||||
Visit(node.left);
|
||||
Visit(node.right);
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::BinaryOp& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::BinaryOp& node)
|
||||
{
|
||||
Visit(node.left);
|
||||
Visit(node.right);
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Branch& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Branch& node)
|
||||
{
|
||||
for (auto& cond : node.condStatements)
|
||||
{
|
||||
|
|
@ -36,7 +36,7 @@ namespace Nz
|
|||
Visit(node.elseStatement);
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Cast& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Cast& node)
|
||||
{
|
||||
for (auto& expr : node.expressions)
|
||||
{
|
||||
|
|
@ -47,46 +47,46 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Constant& /*node*/)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Constant& /*node*/)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::DeclareVariable& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::DeclareVariable& node)
|
||||
{
|
||||
if (node.expression)
|
||||
Visit(node.expression);
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::ExpressionStatement& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::ExpressionStatement& node)
|
||||
{
|
||||
Visit(node.expression);
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Identifier& /*node*/)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Identifier& /*node*/)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::IntrinsicCall& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::IntrinsicCall& node)
|
||||
{
|
||||
for (auto& param : node.parameters)
|
||||
Visit(param);
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Sample2D& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Sample2D& node)
|
||||
{
|
||||
Visit(node.sampler);
|
||||
Visit(node.coordinates);
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::StatementBlock& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::StatementBlock& node)
|
||||
{
|
||||
for (auto& statement : node.statements)
|
||||
Visit(statement);
|
||||
}
|
||||
|
||||
void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::SwizzleOp& node)
|
||||
void ShaderAstRecursiveVisitor::Visit(ShaderNodes::SwizzleOp& node)
|
||||
{
|
||||
Visit(node.expression);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,98 +22,98 @@ namespace Nz
|
|||
{
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::AccessMember& node) override
|
||||
void Visit(ShaderNodes::AccessMember& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::AssignOp& node) override
|
||||
void Visit(ShaderNodes::AssignOp& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::BinaryOp& node) override
|
||||
void Visit(ShaderNodes::BinaryOp& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::Branch& node) override
|
||||
void Visit(ShaderNodes::Branch& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::Cast& node) override
|
||||
void Visit(ShaderNodes::Cast& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::Constant& node) override
|
||||
void Visit(ShaderNodes::Constant& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::DeclareVariable& node) override
|
||||
void Visit(ShaderNodes::DeclareVariable& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::ExpressionStatement& node) override
|
||||
void Visit(ShaderNodes::ExpressionStatement& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::Identifier& node) override
|
||||
void Visit(ShaderNodes::Identifier& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::IntrinsicCall& node) override
|
||||
void Visit(ShaderNodes::IntrinsicCall& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::Sample2D& node) override
|
||||
void Visit(ShaderNodes::Sample2D& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::StatementBlock& node) override
|
||||
void Visit(ShaderNodes::StatementBlock& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::SwizzleOp& node) override
|
||||
void Visit(ShaderNodes::SwizzleOp& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
|
||||
void Visit(const ShaderNodes::BuiltinVariable& var) override
|
||||
void Visit(ShaderNodes::BuiltinVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::InputVariable& var) override
|
||||
void Visit(ShaderNodes::InputVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::LocalVariable& var) override
|
||||
void Visit(ShaderNodes::LocalVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::OutputVariable& var) override
|
||||
void Visit(ShaderNodes::OutputVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::ParameterVariable& var) override
|
||||
void Visit(ShaderNodes::ParameterVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::UniformVariable& var) override
|
||||
void Visit(ShaderNodes::UniformVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
|
@ -193,14 +193,18 @@ namespace Nz
|
|||
Value(value);
|
||||
};
|
||||
|
||||
static_assert(std::variant_size_v<decltype(node.value)> == 5);
|
||||
static_assert(std::variant_size_v<decltype(node.value)> == 9);
|
||||
switch (typeIndex)
|
||||
{
|
||||
case 0: SerializeValue(bool()); break;
|
||||
case 1: SerializeValue(float()); break;
|
||||
case 2: SerializeValue(Vector2f()); break;
|
||||
case 3: SerializeValue(Vector3f()); break;
|
||||
case 4: SerializeValue(Vector4f()); break;
|
||||
case 2: SerializeValue(Int32()); break;
|
||||
case 3: SerializeValue(Vector2f()); break;
|
||||
case 4: SerializeValue(Vector3f()); break;
|
||||
case 5: SerializeValue(Vector4f()); break;
|
||||
case 6: SerializeValue(Vector2i32()); break;
|
||||
case 7: SerializeValue(Vector3i32()); break;
|
||||
case 8: SerializeValue(Vector4i32()); break;
|
||||
default: throw std::runtime_error("unexpected data type");
|
||||
}
|
||||
}
|
||||
|
|
@ -403,6 +407,11 @@ namespace Nz
|
|||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderAstSerializer::Value(Int32& val)
|
||||
{
|
||||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderAstSerializer::Value(Vector2f& val)
|
||||
{
|
||||
m_stream << val;
|
||||
|
|
@ -418,6 +427,21 @@ namespace Nz
|
|||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderAstSerializer::Value(Vector2i32& val)
|
||||
{
|
||||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderAstSerializer::Value(Vector3i32& val)
|
||||
{
|
||||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderAstSerializer::Value(Vector4i32& val)
|
||||
{
|
||||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderAstSerializer::Value(UInt8& val)
|
||||
{
|
||||
m_stream << val;
|
||||
|
|
@ -644,6 +668,11 @@ namespace Nz
|
|||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderAstUnserializer::Value(Int32& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderAstUnserializer::Value(Vector2f& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
|
|
@ -659,6 +688,21 @@ namespace Nz
|
|||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderAstUnserializer::Value(Vector2i32& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderAstUnserializer::Value(Vector3i32& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderAstUnserializer::Value(Vector4i32& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderAstUnserializer::Value(UInt8& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
|
|
@ -689,6 +733,7 @@ namespace Nz
|
|||
HandleType(BuiltinVariable);
|
||||
HandleType(InputVariable);
|
||||
HandleType(LocalVariable);
|
||||
HandleType(ParameterVariable);
|
||||
HandleType(OutputVariable);
|
||||
HandleType(UniformVariable);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ namespace Nz
|
|||
throw AstError{ "Left expression type must match right expression type" };
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::AccessMember& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::AccessMember& node)
|
||||
{
|
||||
const ShaderExpressionType& exprType = MandatoryExpr(node.structExpr)->GetExpressionType();
|
||||
if (!std::holds_alternative<std::string>(exprType))
|
||||
|
|
@ -105,7 +105,7 @@ namespace Nz
|
|||
throw AstError{ "member type does not match node type" };
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::AssignOp& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::AssignOp& node)
|
||||
{
|
||||
MandatoryNode(node.left);
|
||||
MandatoryNode(node.right);
|
||||
|
|
@ -117,7 +117,7 @@ namespace Nz
|
|||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::BinaryOp& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::BinaryOp& node)
|
||||
{
|
||||
MandatoryNode(node.left);
|
||||
MandatoryNode(node.right);
|
||||
|
|
@ -147,8 +147,9 @@ namespace Nz
|
|||
switch (leftType)
|
||||
{
|
||||
case ShaderNodes::BasicType::Float1:
|
||||
case ShaderNodes::BasicType::Int1:
|
||||
{
|
||||
if (ShaderNodes::Node::GetComponentType(rightType) != ShaderNodes::BasicType::Float1)
|
||||
if (ShaderNodes::Node::GetComponentType(rightType) != leftType)
|
||||
throw AstError{ "Left expression type is not compatible with right expression type" };
|
||||
|
||||
break;
|
||||
|
|
@ -157,8 +158,11 @@ namespace Nz
|
|||
case ShaderNodes::BasicType::Float2:
|
||||
case ShaderNodes::BasicType::Float3:
|
||||
case ShaderNodes::BasicType::Float4:
|
||||
case ShaderNodes::BasicType::Int2:
|
||||
case ShaderNodes::BasicType::Int3:
|
||||
case ShaderNodes::BasicType::Int4:
|
||||
{
|
||||
if (leftType != rightType && rightType != ShaderNodes::BasicType::Float1)
|
||||
if (leftType != rightType && rightType != ShaderNodes::Node::GetComponentType(leftType))
|
||||
throw AstError{ "Left expression type is not compatible with right expression type" };
|
||||
|
||||
break;
|
||||
|
|
@ -189,7 +193,7 @@ namespace Nz
|
|||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::Branch& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::Branch& node)
|
||||
{
|
||||
for (const auto& condStatement : node.condStatements)
|
||||
{
|
||||
|
|
@ -200,7 +204,7 @@ namespace Nz
|
|||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::Cast& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::Cast& node)
|
||||
{
|
||||
unsigned int componentCount = 0;
|
||||
unsigned int requiredComponents = node.GetComponentCount(node.exprType);
|
||||
|
|
@ -222,11 +226,11 @@ namespace Nz
|
|||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::Constant& /*node*/)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::Constant& /*node*/)
|
||||
{
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::DeclareVariable& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::DeclareVariable& node)
|
||||
{
|
||||
assert(m_context);
|
||||
|
||||
|
|
@ -242,14 +246,14 @@ namespace Nz
|
|||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::ExpressionStatement& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::ExpressionStatement& node)
|
||||
{
|
||||
MandatoryNode(node.expression);
|
||||
|
||||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::Identifier& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::Identifier& node)
|
||||
{
|
||||
assert(m_context);
|
||||
|
||||
|
|
@ -259,7 +263,7 @@ namespace Nz
|
|||
Visit(node.var);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::IntrinsicCall& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::IntrinsicCall& node)
|
||||
{
|
||||
switch (node.intrinsic)
|
||||
{
|
||||
|
|
@ -300,7 +304,7 @@ namespace Nz
|
|||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::Sample2D& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::Sample2D& node)
|
||||
{
|
||||
if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Sampler2D })
|
||||
throw AstError{ "Sampler must be a Sampler2D" };
|
||||
|
|
@ -311,7 +315,7 @@ namespace Nz
|
|||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::StatementBlock& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::StatementBlock& node)
|
||||
{
|
||||
assert(m_context);
|
||||
|
||||
|
|
@ -327,7 +331,7 @@ namespace Nz
|
|||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::SwizzleOp& node)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::SwizzleOp& node)
|
||||
{
|
||||
if (node.componentCount > 4)
|
||||
throw AstError{ "Cannot swizzle more than four elements" };
|
||||
|
|
@ -342,6 +346,10 @@ namespace Nz
|
|||
case ShaderNodes::BasicType::Float2:
|
||||
case ShaderNodes::BasicType::Float3:
|
||||
case ShaderNodes::BasicType::Float4:
|
||||
case ShaderNodes::BasicType::Int1:
|
||||
case ShaderNodes::BasicType::Int2:
|
||||
case ShaderNodes::BasicType::Int3:
|
||||
case ShaderNodes::BasicType::Int4:
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -351,12 +359,23 @@ namespace Nz
|
|||
ShaderAstRecursiveVisitor::Visit(node);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::BuiltinVariable& /*var*/)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::BuiltinVariable& var)
|
||||
{
|
||||
/* Nothing to do */
|
||||
switch (var.entry)
|
||||
{
|
||||
case ShaderNodes::BuiltinEntry::VertexPosition:
|
||||
if (!std::holds_alternative<ShaderNodes::BasicType>(var.type) ||
|
||||
std::get<ShaderNodes::BasicType>(var.type) != ShaderNodes::BasicType::Float4)
|
||||
throw AstError{ "Builtin is not of the expected type" };
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::InputVariable& var)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::InputVariable& var)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_shader.GetInputCount(); ++i)
|
||||
{
|
||||
|
|
@ -371,7 +390,7 @@ namespace Nz
|
|||
throw AstError{ "Input not found" };
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::LocalVariable& var)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::LocalVariable& var)
|
||||
{
|
||||
const auto& vars = m_context->declaredLocals;
|
||||
|
||||
|
|
@ -382,7 +401,7 @@ namespace Nz
|
|||
TypeMustMatch(it->type, var.type);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::OutputVariable& var)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::OutputVariable& var)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_shader.GetOutputCount(); ++i)
|
||||
{
|
||||
|
|
@ -397,7 +416,7 @@ namespace Nz
|
|||
throw AstError{ "Output not found" };
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::ParameterVariable& var)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::ParameterVariable& var)
|
||||
{
|
||||
assert(m_context->currentFunction);
|
||||
|
||||
|
|
@ -410,7 +429,7 @@ namespace Nz
|
|||
TypeMustMatch(it->type, var.type);
|
||||
}
|
||||
|
||||
void ShaderAstValidator::Visit(const ShaderNodes::UniformVariable& var)
|
||||
void ShaderAstValidator::Visit(ShaderNodes::UniformVariable& var)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_shader.GetUniformCount(); ++i)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ namespace Nz::ShaderNodes
|
|||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
ExpressionCategory ShaderNodes::AccessMember::GetExpressionCategory() const
|
||||
ExpressionCategory AccessMember::GetExpressionCategory() const
|
||||
{
|
||||
return ExpressionCategory::LValue;
|
||||
}
|
||||
|
|
@ -111,10 +111,14 @@ namespace Nz::ShaderNodes
|
|||
case BasicType::Float2:
|
||||
case BasicType::Float3:
|
||||
case BasicType::Float4:
|
||||
case BasicType::Int2:
|
||||
case BasicType::Int3:
|
||||
case BasicType::Int4:
|
||||
exprType = leftExprType;
|
||||
break;
|
||||
|
||||
case BasicType::Float1:
|
||||
case BasicType::Int1:
|
||||
case BasicType::Mat4x4:
|
||||
exprType = rightExprType;
|
||||
break;
|
||||
|
|
@ -159,12 +163,20 @@ namespace Nz::ShaderNodes
|
|||
return ShaderNodes::BasicType::Boolean;
|
||||
else if constexpr (std::is_same_v<T, float>)
|
||||
return ShaderNodes::BasicType::Float1;
|
||||
else if constexpr (std::is_same_v<T, Int32>)
|
||||
return ShaderNodes::BasicType::Int1;
|
||||
else if constexpr (std::is_same_v<T, Vector2f>)
|
||||
return ShaderNodes::BasicType::Float2;
|
||||
else if constexpr (std::is_same_v<T, Vector3f>)
|
||||
return ShaderNodes::BasicType::Float3;
|
||||
else if constexpr (std::is_same_v<T, Vector4f>)
|
||||
return ShaderNodes::BasicType::Float4;
|
||||
else if constexpr (std::is_same_v<T, Vector2i32>)
|
||||
return ShaderNodes::BasicType::Int2;
|
||||
else if constexpr (std::is_same_v<T, Vector3i32>)
|
||||
return ShaderNodes::BasicType::Int3;
|
||||
else if constexpr (std::is_same_v<T, Vector4i32>)
|
||||
return ShaderNodes::BasicType::Int4;
|
||||
else
|
||||
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
||||
}, value);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -57,7 +57,7 @@ namespace Nz
|
|||
String appName = "Another application made with Nazara Engine";
|
||||
String engineName = "Nazara Engine - Vulkan Renderer";
|
||||
|
||||
constexpr UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
UInt32 engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
|
||||
parameters.GetStringParameter("VkAppInfo_OverrideApplicationName", &appName);
|
||||
|
|
|
|||
|
|
@ -3,25 +3,61 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanShaderStage.hpp>
|
||||
#include <Nazara/Renderer/ShaderAst.hpp>
|
||||
#include <Nazara/Renderer/ShaderAstSerializer.hpp>
|
||||
#include <Nazara/Renderer/SpirvWriter.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool VulkanShaderStage::Create(Vk::Device& device, ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize)
|
||||
{
|
||||
if (lang != ShaderLanguage::SpirV)
|
||||
{
|
||||
NazaraError("Only Spir-V is supported for now");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_shaderModule.Create(device, reinterpret_cast<const Nz::UInt32*>(source), sourceSize))
|
||||
{
|
||||
NazaraError("Failed to create shader module");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_stage = type;
|
||||
|
||||
switch (lang)
|
||||
{
|
||||
case ShaderLanguage::NazaraBinary:
|
||||
{
|
||||
ByteStream byteStream(source, sourceSize);
|
||||
auto shader = Nz::UnserializeShader(byteStream);
|
||||
|
||||
if (shader.GetStage() != type)
|
||||
throw std::runtime_error("incompatible shader stage");
|
||||
|
||||
SpirvWriter::Environment env;
|
||||
|
||||
SpirvWriter writer;
|
||||
writer.SetEnv(env);
|
||||
|
||||
std::vector<UInt32> code = writer.Generate(shader);
|
||||
|
||||
if (!m_shaderModule.Create(device, code.data(), code.size() * sizeof(UInt32)))
|
||||
{
|
||||
NazaraError("Failed to create shader module");
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ShaderLanguage::SpirV:
|
||||
{
|
||||
if (!m_shaderModule.Create(device, reinterpret_cast<const Nz::UInt32*>(source), sourceSize))
|
||||
{
|
||||
NazaraError("Failed to create shader module");
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
NazaraError("this language is not supported");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue