ShaderAst: Big refactor + add binding/location support
This commit is contained in:
@@ -11,16 +11,15 @@
|
||||
namespace Nz
|
||||
{
|
||||
GlslWriter::GlslWriter() :
|
||||
m_currentFunction(nullptr),
|
||||
m_currentState(nullptr),
|
||||
m_glslVersion(110)
|
||||
{
|
||||
}
|
||||
|
||||
String GlslWriter::Generate(const ShaderAst::StatementPtr& node)
|
||||
std::string GlslWriter::Generate(const ShaderAst& shader)
|
||||
{
|
||||
std::string error;
|
||||
if (!ShaderAst::Validate(node, &error))
|
||||
if (!ValidateShader(shader, &error))
|
||||
throw std::runtime_error("Invalid shader AST: " + error);
|
||||
|
||||
State state;
|
||||
@@ -30,91 +29,54 @@ namespace Nz
|
||||
m_currentState = nullptr;
|
||||
});
|
||||
|
||||
// Register global variables (uniforms, varying, ..)
|
||||
node->Register(*this);
|
||||
|
||||
// Header
|
||||
Append("#version ");
|
||||
AppendLine(String::Number(m_glslVersion));
|
||||
AppendLine(std::to_string(m_glslVersion));
|
||||
AppendLine();
|
||||
|
||||
// Global variables (uniforms, input and outputs)
|
||||
DeclareVariables(state.uniforms, "uniform", "Uniforms");
|
||||
DeclareVariables(state.inputs, "in", "Inputs");
|
||||
DeclareVariables(state.outputs, "out", "Outputs");
|
||||
// Extensions
|
||||
|
||||
Function entryPoint;
|
||||
entryPoint.name = "main"; //< GLSL has only one entry point name possible
|
||||
entryPoint.node = node;
|
||||
entryPoint.retType = ShaderAst::ExpressionType::Void;
|
||||
std::vector<std::string> requiredExtensions;
|
||||
|
||||
AppendFunction(entryPoint);
|
||||
// GL_ARB_shading_language_420pack (required for layout(binding = X))
|
||||
if (m_glslVersion < 420 && HasExplicitBinding(shader))
|
||||
requiredExtensions.emplace_back("GL_ARB_shading_language_420pack");
|
||||
|
||||
return state.stream;
|
||||
}
|
||||
// GL_ARB_explicit_uniform_location (required for layout(location = X))
|
||||
if (m_glslVersion < 430 && HasExplicitLocation(shader))
|
||||
requiredExtensions.emplace_back("GL_ARB_explicit_uniform_location");
|
||||
|
||||
void GlslWriter::RegisterFunction(const String& name, ShaderAst::StatementPtr statement, std::initializer_list<ShaderAst::NamedVariablePtr> parameters, ShaderAst::ExpressionType retType)
|
||||
{
|
||||
Function func;
|
||||
func.retType = retType;
|
||||
func.name = name;
|
||||
func.node = std::move(statement);
|
||||
func.parameters.assign(parameters);
|
||||
|
||||
m_functions[name] = std::move(func);
|
||||
}
|
||||
|
||||
void GlslWriter::RegisterVariable(ShaderAst::VariableType kind, const String& name, ShaderAst::ExpressionType type)
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
NazaraAssert(kind != ShaderAst::VariableType::Builtin, "Builtin variables should not be registered");
|
||||
|
||||
switch (kind)
|
||||
if (!requiredExtensions.empty())
|
||||
{
|
||||
case ShaderAst::VariableType::Builtin: //< Only there to make compiler happy
|
||||
case ShaderAst::VariableType::Variable:
|
||||
break;
|
||||
for (const std::string& ext : requiredExtensions)
|
||||
AppendLine("#extension " + ext + " : require");
|
||||
|
||||
case ShaderAst::VariableType::Input:
|
||||
m_currentState->inputs.emplace(type, name);
|
||||
break;
|
||||
|
||||
case ShaderAst::VariableType::Output:
|
||||
m_currentState->outputs.emplace(type, name);
|
||||
break;
|
||||
|
||||
case ShaderAst::VariableType::Parameter:
|
||||
{
|
||||
if (m_currentFunction)
|
||||
{
|
||||
bool found = false;
|
||||
for (const auto& varPtr : m_currentFunction->parameters)
|
||||
{
|
||||
if (varPtr->name == name)
|
||||
{
|
||||
found = true;
|
||||
if (varPtr->type != type)
|
||||
{
|
||||
//TODO: AstParseError
|
||||
throw std::runtime_error("Function uses parameter \"" + name.ToStdString() + "\" with a different type than specified in the function arguments");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
//TODO: AstParseError
|
||||
throw std::runtime_error("Function has no parameter \"" + name.ToStdString() + "\"");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ShaderAst::VariableType::Uniform:
|
||||
m_currentState->uniforms.emplace(type, name);
|
||||
break;
|
||||
AppendLine();
|
||||
}
|
||||
|
||||
// Global variables (uniforms, input and outputs)
|
||||
DeclareVariables(shader.GetUniforms(), "uniform", "Uniforms");
|
||||
DeclareVariables(shader.GetInputs(), "in", "Inputs");
|
||||
DeclareVariables(shader.GetOutputs(), "out", "Outputs");
|
||||
|
||||
std::size_t functionCount = shader.GetFunctionCount();
|
||||
if (functionCount > 1)
|
||||
{
|
||||
AppendCommentSection("Prototypes");
|
||||
for (const auto& func : shader.GetFunctions())
|
||||
{
|
||||
if (func.name != "main")
|
||||
{
|
||||
AppendFunctionPrototype(func);
|
||||
AppendLine(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& func : shader.GetFunctions())
|
||||
AppendFunction(func);
|
||||
|
||||
return state.stream.str();
|
||||
}
|
||||
|
||||
void GlslWriter::SetGlslVersion(unsigned int version)
|
||||
@@ -122,22 +84,127 @@ namespace Nz
|
||||
m_glslVersion = version;
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::Sample2D& node)
|
||||
void GlslWriter::Append(ShaderNodes::BuiltinEntry builtin)
|
||||
{
|
||||
Append("texture(");
|
||||
Visit(node.sampler);
|
||||
Append(", ");
|
||||
Visit(node.coordinates);
|
||||
Append(")");
|
||||
switch (builtin)
|
||||
{
|
||||
case ShaderNodes::BuiltinEntry::VertexPosition:
|
||||
Append("gl_Position");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::AssignOp& node)
|
||||
void GlslWriter::Append(ShaderNodes::ExpressionType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ShaderNodes::ExpressionType::Boolean:
|
||||
Append("bool");
|
||||
break;
|
||||
case ShaderNodes::ExpressionType::Float1:
|
||||
Append("float");
|
||||
break;
|
||||
case ShaderNodes::ExpressionType::Float2:
|
||||
Append("vec2");
|
||||
break;
|
||||
case ShaderNodes::ExpressionType::Float3:
|
||||
Append("vec3");
|
||||
break;
|
||||
case ShaderNodes::ExpressionType::Float4:
|
||||
Append("vec4");
|
||||
break;
|
||||
case ShaderNodes::ExpressionType::Mat4x4:
|
||||
Append("mat4");
|
||||
break;
|
||||
case ShaderNodes::ExpressionType::Sampler2D:
|
||||
Append("sampler2D");
|
||||
break;
|
||||
case ShaderNodes::ExpressionType::Void:
|
||||
Append("void");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::AppendCommentSection(const std::string& section)
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
String stars((section.size() < 33) ? (36 - section.size()) / 2 : 3, '*');
|
||||
m_currentState->stream << "/*" << stars << ' ' << section << ' ' << stars << "*/";
|
||||
AppendLine();
|
||||
}
|
||||
|
||||
void GlslWriter::AppendFunction(const ShaderAst::Function& func)
|
||||
{
|
||||
NazaraAssert(!m_context.currentFunction, "A function is already being processed");
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
AppendFunctionPrototype(func);
|
||||
|
||||
m_context.currentFunction = &func;
|
||||
CallOnExit onExit([this] ()
|
||||
{
|
||||
m_context.currentFunction = nullptr;
|
||||
});
|
||||
|
||||
EnterScope();
|
||||
{
|
||||
Visit(func.statement);
|
||||
}
|
||||
LeaveScope();
|
||||
}
|
||||
|
||||
void GlslWriter::AppendFunctionPrototype(const ShaderAst::Function& func)
|
||||
{
|
||||
Append(func.returnType);
|
||||
|
||||
Append(" ");
|
||||
Append(func.name);
|
||||
|
||||
Append("(");
|
||||
for (std::size_t i = 0; i < func.parameters.size(); ++i)
|
||||
{
|
||||
if (i != 0)
|
||||
Append(", ");
|
||||
|
||||
Append(func.parameters[i].type);
|
||||
Append(" ");
|
||||
Append(func.parameters[i].name);
|
||||
}
|
||||
Append(")\n");
|
||||
}
|
||||
|
||||
void GlslWriter::AppendLine(const std::string& txt)
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
m_currentState->stream << txt << '\n' << std::string(m_currentState->indentLevel, '\t');
|
||||
}
|
||||
|
||||
void GlslWriter::EnterScope()
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
m_currentState->indentLevel++;
|
||||
AppendLine("{");
|
||||
}
|
||||
|
||||
void GlslWriter::LeaveScope()
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
m_currentState->indentLevel--;
|
||||
AppendLine();
|
||||
AppendLine("}");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::AssignOp& node)
|
||||
{
|
||||
Visit(node.left);
|
||||
|
||||
switch (node.op)
|
||||
{
|
||||
case ShaderAst::AssignType::Simple:
|
||||
case ShaderNodes::AssignType::Simple:
|
||||
Append(" = ");
|
||||
break;
|
||||
}
|
||||
@@ -145,7 +212,7 @@ namespace Nz
|
||||
Visit(node.right);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::Branch& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::Branch& node)
|
||||
{
|
||||
bool first = true;
|
||||
for (const auto& statement : node.condStatements)
|
||||
@@ -174,45 +241,25 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::BinaryFunc& node)
|
||||
{
|
||||
switch (node.intrinsic)
|
||||
{
|
||||
case ShaderAst::BinaryIntrinsic::CrossProduct:
|
||||
Append("cross");
|
||||
break;
|
||||
|
||||
case ShaderAst::BinaryIntrinsic::DotProduct:
|
||||
Append("dot");
|
||||
break;
|
||||
}
|
||||
|
||||
Append("(");
|
||||
Visit(node.left);
|
||||
Append(", ");
|
||||
Visit(node.right);
|
||||
Append(")");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::BinaryOp& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::BinaryOp& node)
|
||||
{
|
||||
Visit(node.left);
|
||||
|
||||
switch (node.op)
|
||||
{
|
||||
case ShaderAst::BinaryType::Add:
|
||||
case ShaderNodes::BinaryType::Add:
|
||||
Append(" + ");
|
||||
break;
|
||||
case ShaderAst::BinaryType::Substract:
|
||||
case ShaderNodes::BinaryType::Substract:
|
||||
Append(" - ");
|
||||
break;
|
||||
case ShaderAst::BinaryType::Multiply:
|
||||
case ShaderNodes::BinaryType::Multiply:
|
||||
Append(" * ");
|
||||
break;
|
||||
case ShaderAst::BinaryType::Divide:
|
||||
case ShaderNodes::BinaryType::Divide:
|
||||
Append(" / ");
|
||||
break;
|
||||
case ShaderAst::BinaryType::Equality:
|
||||
case ShaderNodes::BinaryType::Equality:
|
||||
Append(" == ");
|
||||
break;
|
||||
}
|
||||
@@ -220,18 +267,18 @@ namespace Nz
|
||||
Visit(node.right);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::BuiltinVariable& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::BuiltinVariable& var)
|
||||
{
|
||||
Append(node.var);
|
||||
Append(var.type);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::Cast& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::Cast& node)
|
||||
{
|
||||
Append(node.exprType);
|
||||
Append("(");
|
||||
|
||||
unsigned int i = 0;
|
||||
unsigned int requiredComponents = ShaderAst::Node::GetComponentCount(node.exprType);
|
||||
unsigned int requiredComponents = ShaderNodes::Node::GetComponentCount(node.exprType);
|
||||
while (requiredComponents > 0)
|
||||
{
|
||||
if (i != 0)
|
||||
@@ -241,34 +288,34 @@ namespace Nz
|
||||
NazaraAssert(exprPtr, "Invalid expression");
|
||||
|
||||
Visit(exprPtr);
|
||||
requiredComponents -= ShaderAst::Node::GetComponentCount(exprPtr->GetExpressionType());
|
||||
requiredComponents -= ShaderNodes::Node::GetComponentCount(exprPtr->GetExpressionType());
|
||||
}
|
||||
|
||||
Append(")");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::Constant& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::Constant& node)
|
||||
{
|
||||
switch (node.exprType)
|
||||
{
|
||||
case ShaderAst::ExpressionType::Boolean:
|
||||
case ShaderNodes::ExpressionType::Boolean:
|
||||
Append((node.values.bool1) ? "true" : "false");
|
||||
break;
|
||||
|
||||
case ShaderAst::ExpressionType::Float1:
|
||||
Append(String::Number(node.values.vec1));
|
||||
case ShaderNodes::ExpressionType::Float1:
|
||||
Append(std::to_string(node.values.vec1));
|
||||
break;
|
||||
|
||||
case ShaderAst::ExpressionType::Float2:
|
||||
Append("vec2(" + String::Number(node.values.vec2.x) + ", " + String::Number(node.values.vec2.y) + ")");
|
||||
case ShaderNodes::ExpressionType::Float2:
|
||||
Append("vec2(" + std::to_string(node.values.vec2.x) + ", " + std::to_string(node.values.vec2.y) + ")");
|
||||
break;
|
||||
|
||||
case ShaderAst::ExpressionType::Float3:
|
||||
Append("vec3(" + String::Number(node.values.vec3.x) + ", " + String::Number(node.values.vec3.y) + ", " + String::Number(node.values.vec3.z) + ")");
|
||||
case ShaderNodes::ExpressionType::Float3:
|
||||
Append("vec3(" + std::to_string(node.values.vec3.x) + ", " + std::to_string(node.values.vec3.y) + ", " + std::to_string(node.values.vec3.z) + ")");
|
||||
break;
|
||||
|
||||
case ShaderAst::ExpressionType::Float4:
|
||||
Append("vec4(" + String::Number(node.values.vec4.x) + ", " + String::Number(node.values.vec4.y) + ", " + String::Number(node.values.vec4.z) + ", " + String::Number(node.values.vec4.w) + ")");
|
||||
case ShaderNodes::ExpressionType::Float4:
|
||||
Append("vec4(" + std::to_string(node.values.vec4.x) + ", " + std::to_string(node.values.vec4.y) + ", " + std::to_string(node.values.vec4.z) + ", " + std::to_string(node.values.vec4.w) + ")");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -276,9 +323,9 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::DeclareVariable& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::DeclareVariable& node)
|
||||
{
|
||||
Append(node.variable->GetExpressionType());
|
||||
Append(node.variable->type);
|
||||
Append(" ");
|
||||
Append(node.variable->name);
|
||||
if (node.expression)
|
||||
@@ -292,21 +339,76 @@ namespace Nz
|
||||
AppendLine(";");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::ExpressionStatement& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::ExpressionStatement& node)
|
||||
{
|
||||
Visit(node.expression);
|
||||
Append(";");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::NamedVariable& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::Identifier& node)
|
||||
{
|
||||
Append(node.name);
|
||||
Visit(node.var);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::StatementBlock& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::InputVariable& var)
|
||||
{
|
||||
Append(var.name);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::IntrinsicCall& node)
|
||||
{
|
||||
switch (node.intrinsic)
|
||||
{
|
||||
case ShaderNodes::IntrinsicType::CrossProduct:
|
||||
Append("cross");
|
||||
break;
|
||||
|
||||
case ShaderNodes::IntrinsicType::DotProduct:
|
||||
Append("dot");
|
||||
break;
|
||||
}
|
||||
|
||||
m_currentState->stream << '(';
|
||||
for (std::size_t i = 0; i < node.parameters.size(); ++i)
|
||||
{
|
||||
if (i != 0)
|
||||
m_currentState->stream << ", ";
|
||||
|
||||
Visit(node.parameters[i]);
|
||||
m_currentState->stream << ' ';
|
||||
Visit(node.parameters[i]);
|
||||
}
|
||||
m_currentState->stream << ")\n";
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::LocalVariable& var)
|
||||
{
|
||||
Append(var.name);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::ParameterVariable& var)
|
||||
{
|
||||
Append(var.name);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::OutputVariable& var)
|
||||
{
|
||||
Append(var.name);
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::Sample2D& node)
|
||||
{
|
||||
Append("texture(");
|
||||
Visit(node.sampler);
|
||||
Append(", ");
|
||||
Visit(node.coordinates);
|
||||
Append(")");
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderNodes::StatementBlock& node)
|
||||
{
|
||||
bool first = true;
|
||||
for (const ShaderAst::StatementPtr& statement : node.statements)
|
||||
for (const ShaderNodes::StatementPtr& statement : node.statements)
|
||||
{
|
||||
if (!first)
|
||||
AppendLine();
|
||||
@@ -317,7 +419,7 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Visit(const ShaderAst::SwizzleOp& node)
|
||||
void GlslWriter::Visit(const ShaderNodes::SwizzleOp& node)
|
||||
{
|
||||
Visit(node.expression);
|
||||
Append(".");
|
||||
@@ -326,166 +428,55 @@ namespace Nz
|
||||
{
|
||||
switch (node.components[i])
|
||||
{
|
||||
case ShaderAst::SwizzleComponent::First:
|
||||
case ShaderNodes::SwizzleComponent::First:
|
||||
Append("x");
|
||||
break;
|
||||
|
||||
case ShaderAst::SwizzleComponent::Second:
|
||||
case ShaderNodes::SwizzleComponent::Second:
|
||||
Append("y");
|
||||
break;
|
||||
|
||||
case ShaderAst::SwizzleComponent::Third:
|
||||
case ShaderNodes::SwizzleComponent::Third:
|
||||
Append("z");
|
||||
break;
|
||||
|
||||
case ShaderAst::SwizzleComponent::Fourth:
|
||||
case ShaderNodes::SwizzleComponent::Fourth:
|
||||
Append("w");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Append(ShaderAst::BuiltinEntry builtin)
|
||||
void GlslWriter::Visit(const ShaderNodes::UniformVariable& var)
|
||||
{
|
||||
switch (builtin)
|
||||
Append(var.name);
|
||||
}
|
||||
|
||||
bool GlslWriter::HasExplicitBinding(const ShaderAst& shader)
|
||||
{
|
||||
for (const auto& uniform : shader.GetUniforms())
|
||||
{
|
||||
case ShaderAst::BuiltinEntry::VertexPosition:
|
||||
Append("gl_Position");
|
||||
break;
|
||||
if (uniform.bindingIndex.has_value())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GlslWriter::Append(ShaderAst::ExpressionType type)
|
||||
bool GlslWriter::HasExplicitLocation(const ShaderAst& shader)
|
||||
{
|
||||
switch (type)
|
||||
for (const auto& input : shader.GetInputs())
|
||||
{
|
||||
case ShaderAst::ExpressionType::Boolean:
|
||||
Append("bool");
|
||||
break;
|
||||
case ShaderAst::ExpressionType::Float1:
|
||||
Append("float");
|
||||
break;
|
||||
case ShaderAst::ExpressionType::Float2:
|
||||
Append("vec2");
|
||||
break;
|
||||
case ShaderAst::ExpressionType::Float3:
|
||||
Append("vec3");
|
||||
break;
|
||||
case ShaderAst::ExpressionType::Float4:
|
||||
Append("vec4");
|
||||
break;
|
||||
case ShaderAst::ExpressionType::Mat4x4:
|
||||
Append("mat4");
|
||||
break;
|
||||
case ShaderAst::ExpressionType::Sampler2D:
|
||||
Append("sampler2D");
|
||||
break;
|
||||
case ShaderAst::ExpressionType::Void:
|
||||
Append("void");
|
||||
break;
|
||||
if (input.locationIndex.has_value())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Append(const String& txt)
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
m_currentState->stream << txt;
|
||||
}
|
||||
|
||||
void GlslWriter::AppendCommentSection(const String& section)
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
String stars((section.GetSize() < 33) ? (36 - section.GetSize()) / 2 : 3, '*');
|
||||
m_currentState->stream << "/*" << stars << ' ' << section << ' ' << stars << "*/";
|
||||
AppendLine();
|
||||
}
|
||||
|
||||
void GlslWriter::AppendFunction(Function& func)
|
||||
{
|
||||
NazaraAssert(!m_currentFunction, "A function is already being processed");
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
m_currentFunction = &func;
|
||||
CallOnExit onExit([this] ()
|
||||
for (const auto& output : shader.GetOutputs())
|
||||
{
|
||||
m_currentFunction = nullptr;
|
||||
});
|
||||
|
||||
func.node->Register(*this);
|
||||
|
||||
Append(func.retType);
|
||||
|
||||
m_currentState->stream << ' ';
|
||||
Append(func.name);
|
||||
|
||||
m_currentState->stream << '(';
|
||||
for (std::size_t i = 0; i < func.parameters.size(); ++i)
|
||||
{
|
||||
if (i != 0)
|
||||
m_currentState->stream << ", ";
|
||||
|
||||
Append(func.parameters[i]->type);
|
||||
m_currentState->stream << ' ';
|
||||
Append(func.parameters[i]->name);
|
||||
if (output.locationIndex.has_value())
|
||||
return true;
|
||||
}
|
||||
m_currentState->stream << ")\n";
|
||||
|
||||
EnterScope();
|
||||
{
|
||||
Visit(func.node);
|
||||
}
|
||||
LeaveScope();
|
||||
return false;
|
||||
}
|
||||
|
||||
void GlslWriter::AppendLine(const String& txt)
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
m_currentState->stream << txt << '\n' << String(m_currentState->indentLevel, '\t');
|
||||
}
|
||||
|
||||
void GlslWriter::DeclareVariables(const VariableContainer& variables, const String& keyword, const String& section)
|
||||
{
|
||||
if (!variables.empty())
|
||||
{
|
||||
if (!section.IsEmpty())
|
||||
AppendCommentSection(section);
|
||||
|
||||
for (const auto& pair : variables)
|
||||
{
|
||||
if (!keyword.IsEmpty())
|
||||
{
|
||||
Append(keyword);
|
||||
Append(" ");
|
||||
}
|
||||
|
||||
Append(pair.first);
|
||||
Append(" ");
|
||||
Append(pair.second);
|
||||
AppendLine(";");
|
||||
}
|
||||
|
||||
AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::EnterScope()
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
m_currentState->indentLevel++;
|
||||
AppendLine("{");
|
||||
}
|
||||
|
||||
void GlslWriter::LeaveScope()
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
m_currentState->indentLevel--;
|
||||
AppendLine();
|
||||
AppendLine("}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,275 +3,40 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ShaderAst.hpp>
|
||||
#include <Nazara/Core/ByteStream.hpp>
|
||||
#include <Nazara/Renderer/ShaderSerializer.hpp>
|
||||
#include <Nazara/Renderer/ShaderWriter.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz::ShaderAst
|
||||
namespace Nz
|
||||
{
|
||||
Node::~Node() = default;
|
||||
|
||||
ExpressionCategory Expression::GetExpressionCategory() const
|
||||
void ShaderAst::AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector<FunctionParameter> parameters, ShaderNodes::ExpressionType returnType)
|
||||
{
|
||||
return ExpressionCategory::RValue;
|
||||
auto& functionEntry = m_functions.emplace_back();
|
||||
functionEntry.name = std::move(name);
|
||||
functionEntry.parameters = std::move(parameters);
|
||||
functionEntry.returnType = returnType;
|
||||
functionEntry.statement = std::move(statement);
|
||||
}
|
||||
|
||||
void ExpressionStatement::Register(ShaderWriter& visitor)
|
||||
void ShaderAst::AddInput(std::string name, ShaderNodes::ExpressionType type, std::optional<std::size_t> locationIndex)
|
||||
{
|
||||
expression->Register(visitor);
|
||||
auto& inputEntry = m_inputs.emplace_back();
|
||||
inputEntry.name = std::move(name);
|
||||
inputEntry.locationIndex = std::move(locationIndex);
|
||||
inputEntry.type = type;
|
||||
}
|
||||
|
||||
void ExpressionStatement::Visit(ShaderVisitor& visitor)
|
||||
void ShaderAst::AddOutput(std::string name, ShaderNodes::ExpressionType type, std::optional<std::size_t> locationIndex)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
auto& outputEntry = m_outputs.emplace_back();
|
||||
outputEntry.name = std::move(name);
|
||||
outputEntry.locationIndex = std::move(locationIndex);
|
||||
outputEntry.type = type;
|
||||
}
|
||||
|
||||
|
||||
void ConditionalStatement::Register(ShaderWriter& visitor)
|
||||
void ShaderAst::AddUniform(std::string name, ShaderNodes::ExpressionType type, std::optional<std::size_t> bindingIndex)
|
||||
{
|
||||
if (visitor.IsConditionEnabled(conditionName))
|
||||
statement->Register(visitor);
|
||||
}
|
||||
|
||||
void ConditionalStatement::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
if (visitor.IsConditionEnabled(conditionName))
|
||||
statement->Visit(visitor);
|
||||
}
|
||||
|
||||
|
||||
void StatementBlock::Register(ShaderWriter& visitor)
|
||||
{
|
||||
for (auto& statementPtr : statements)
|
||||
statementPtr->Register(visitor);
|
||||
}
|
||||
|
||||
void StatementBlock::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
ExpressionCategory Variable::GetExpressionCategory() const
|
||||
{
|
||||
return ExpressionCategory::LValue;
|
||||
}
|
||||
|
||||
ExpressionType Variable::GetExpressionType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
void BuiltinVariable::Register(ShaderWriter& /*visitor*/)
|
||||
{
|
||||
}
|
||||
|
||||
void BuiltinVariable::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
void NamedVariable::Register(ShaderWriter& visitor)
|
||||
{
|
||||
visitor.RegisterVariable(kind, name, type);
|
||||
}
|
||||
|
||||
void NamedVariable::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
void DeclareVariable::Register(ShaderWriter& visitor)
|
||||
{
|
||||
variable->Register(visitor);
|
||||
|
||||
if (expression)
|
||||
expression->Register(visitor);
|
||||
}
|
||||
|
||||
void DeclareVariable::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType AssignOp::GetExpressionType() const
|
||||
{
|
||||
return left->GetExpressionType();
|
||||
}
|
||||
|
||||
void AssignOp::Register(ShaderWriter& visitor)
|
||||
{
|
||||
left->Register(visitor);
|
||||
right->Register(visitor);
|
||||
}
|
||||
|
||||
void AssignOp::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType BinaryOp::GetExpressionType() const
|
||||
{
|
||||
ShaderAst::ExpressionType exprType = ShaderAst::ExpressionType::Void;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case ShaderAst::BinaryType::Add:
|
||||
case ShaderAst::BinaryType::Substract:
|
||||
exprType = left->GetExpressionType();
|
||||
break;
|
||||
|
||||
case ShaderAst::BinaryType::Divide:
|
||||
case ShaderAst::BinaryType::Multiply:
|
||||
//FIXME
|
||||
exprType = static_cast<ExpressionType>(std::max(UnderlyingCast(left->GetExpressionType()), UnderlyingCast(right->GetExpressionType())));
|
||||
break;
|
||||
|
||||
case ShaderAst::BinaryType::Equality:
|
||||
exprType = ExpressionType::Boolean;
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraAssert(exprType != ShaderAst::ExpressionType::Void, "Unhandled builtin");
|
||||
|
||||
return exprType;
|
||||
}
|
||||
|
||||
void BinaryOp::Register(ShaderWriter& visitor)
|
||||
{
|
||||
left->Register(visitor);
|
||||
right->Register(visitor);
|
||||
}
|
||||
|
||||
void BinaryOp::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
void Branch::Register(ShaderWriter& visitor)
|
||||
{
|
||||
for (ConditionalStatement& statement : condStatements)
|
||||
{
|
||||
statement.condition->Register(visitor);
|
||||
statement.statement->Register(visitor);
|
||||
}
|
||||
|
||||
if (elseStatement)
|
||||
elseStatement->Register(visitor);
|
||||
}
|
||||
|
||||
void Branch::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType Constant::GetExpressionType() const
|
||||
{
|
||||
return exprType;
|
||||
}
|
||||
|
||||
void Constant::Register(ShaderWriter&)
|
||||
{
|
||||
}
|
||||
|
||||
void Constant::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
ExpressionType Cast::GetExpressionType() const
|
||||
{
|
||||
return exprType;
|
||||
}
|
||||
|
||||
void Cast::Register(ShaderWriter& visitor)
|
||||
{
|
||||
auto it = expressions.begin();
|
||||
(*it)->Register(visitor);
|
||||
|
||||
for (; it != expressions.end(); ++it)
|
||||
{
|
||||
if (!*it)
|
||||
break;
|
||||
|
||||
(*it)->Register(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
void Cast::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionCategory SwizzleOp::GetExpressionCategory() const
|
||||
{
|
||||
return ExpressionCategory::LValue;
|
||||
}
|
||||
|
||||
ExpressionType SwizzleOp::GetExpressionType() const
|
||||
{
|
||||
return static_cast<ExpressionType>(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1);
|
||||
}
|
||||
|
||||
void SwizzleOp::Register(ShaderWriter& visitor)
|
||||
{
|
||||
expression->Register(visitor);
|
||||
}
|
||||
|
||||
void SwizzleOp::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType Sample2D::GetExpressionType() const
|
||||
{
|
||||
return ExpressionType::Float4;
|
||||
}
|
||||
|
||||
void Sample2D::Register(ShaderWriter& visitor)
|
||||
{
|
||||
sampler->Register(visitor);
|
||||
coordinates->Register(visitor);
|
||||
}
|
||||
|
||||
void Sample2D::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType BinaryFunc::GetExpressionType() const
|
||||
{
|
||||
switch (intrinsic)
|
||||
{
|
||||
case BinaryIntrinsic::CrossProduct:
|
||||
return left->GetExpressionType();
|
||||
|
||||
case BinaryIntrinsic::DotProduct:
|
||||
return ExpressionType::Float1;
|
||||
}
|
||||
|
||||
NazaraAssert(false, "Unhandled builtin");
|
||||
return ExpressionType::Void;
|
||||
}
|
||||
|
||||
void BinaryFunc::Register(ShaderWriter& visitor)
|
||||
{
|
||||
left->Register(visitor);
|
||||
right->Register(visitor);
|
||||
}
|
||||
|
||||
void BinaryFunc::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
auto& uniformEntry = m_uniforms.emplace_back();
|
||||
uniformEntry.bindingIndex = std::move(bindingIndex);
|
||||
uniformEntry.name = std::move(name);
|
||||
uniformEntry.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
179
src/Nazara/Renderer/ShaderNodes.cpp
Normal file
179
src/Nazara/Renderer/ShaderNodes.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ShaderNodes.hpp>
|
||||
#include <Nazara/Renderer/ShaderSerializer.hpp>
|
||||
#include <Nazara/Renderer/ShaderVisitor.hpp>
|
||||
#include <Nazara/Renderer/ShaderWriter.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz::ShaderNodes
|
||||
{
|
||||
Node::~Node() = default;
|
||||
|
||||
ExpressionCategory Expression::GetExpressionCategory() const
|
||||
{
|
||||
return ExpressionCategory::RValue;
|
||||
}
|
||||
|
||||
void ExpressionStatement::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
void ConditionalStatement::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
if (visitor.IsConditionEnabled(conditionName))
|
||||
statement->Visit(visitor);
|
||||
}
|
||||
|
||||
|
||||
void StatementBlock::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
void DeclareVariable::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionCategory Identifier::GetExpressionCategory() const
|
||||
{
|
||||
return ExpressionCategory::LValue;
|
||||
}
|
||||
|
||||
ExpressionType Identifier::GetExpressionType() const
|
||||
{
|
||||
assert(var);
|
||||
return var->type;
|
||||
}
|
||||
|
||||
void Identifier::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType AssignOp::GetExpressionType() const
|
||||
{
|
||||
return left->GetExpressionType();
|
||||
}
|
||||
|
||||
void AssignOp::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType BinaryOp::GetExpressionType() const
|
||||
{
|
||||
ShaderNodes::ExpressionType exprType = ShaderNodes::ExpressionType::Void;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case ShaderNodes::BinaryType::Add:
|
||||
case ShaderNodes::BinaryType::Substract:
|
||||
exprType = left->GetExpressionType();
|
||||
break;
|
||||
|
||||
case ShaderNodes::BinaryType::Divide:
|
||||
case ShaderNodes::BinaryType::Multiply:
|
||||
//FIXME
|
||||
exprType = static_cast<ExpressionType>(std::max(UnderlyingCast(left->GetExpressionType()), UnderlyingCast(right->GetExpressionType())));
|
||||
break;
|
||||
|
||||
case ShaderNodes::BinaryType::Equality:
|
||||
exprType = ExpressionType::Boolean;
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraAssert(exprType != ShaderNodes::ExpressionType::Void, "Unhandled builtin");
|
||||
|
||||
return exprType;
|
||||
}
|
||||
|
||||
void BinaryOp::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
void Branch::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType Constant::GetExpressionType() const
|
||||
{
|
||||
return exprType;
|
||||
}
|
||||
|
||||
void Constant::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
ExpressionType Cast::GetExpressionType() const
|
||||
{
|
||||
return exprType;
|
||||
}
|
||||
|
||||
void Cast::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionCategory SwizzleOp::GetExpressionCategory() const
|
||||
{
|
||||
return ExpressionCategory::LValue;
|
||||
}
|
||||
|
||||
ExpressionType SwizzleOp::GetExpressionType() const
|
||||
{
|
||||
return static_cast<ExpressionType>(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1);
|
||||
}
|
||||
|
||||
void SwizzleOp::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType Sample2D::GetExpressionType() const
|
||||
{
|
||||
return ExpressionType::Float4;
|
||||
}
|
||||
|
||||
void Sample2D::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
ExpressionType IntrinsicCall::GetExpressionType() const
|
||||
{
|
||||
switch (intrinsic)
|
||||
{
|
||||
case IntrinsicType::CrossProduct:
|
||||
return parameters.front()->GetExpressionType();
|
||||
|
||||
case IntrinsicType::DotProduct:
|
||||
return ExpressionType::Float1;
|
||||
}
|
||||
|
||||
NazaraAssert(false, "Unhandled builtin");
|
||||
return ExpressionType::Void;
|
||||
}
|
||||
|
||||
void IntrinsicCall::Visit(ShaderVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,15 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ShaderSerializer.hpp>
|
||||
#include <Nazara/Renderer/ShaderVarVisitor.hpp>
|
||||
#include <Nazara/Renderer/ShaderVisitor.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz::ShaderAst
|
||||
namespace Nz::ShaderNodes
|
||||
{
|
||||
namespace
|
||||
{
|
||||
class ShaderSerializerVisitor : public ShaderVisitor
|
||||
class ShaderSerializerVisitor : public ShaderVisitor, public ShaderVarVisitor
|
||||
{
|
||||
public:
|
||||
ShaderSerializerVisitor(ShaderSerializerBase& serializer) :
|
||||
@@ -22,11 +24,6 @@ namespace Nz::ShaderAst
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const BinaryFunc& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const BinaryOp& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
@@ -37,11 +34,6 @@ namespace Nz::ShaderAst
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const BuiltinVariable& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const Cast& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
@@ -62,7 +54,12 @@ namespace Nz::ShaderAst
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const NamedVariable& node) override
|
||||
void Visit(const Identifier& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
void Visit(const IntrinsicCall& node) override
|
||||
{
|
||||
Serialize(node);
|
||||
}
|
||||
@@ -82,6 +79,37 @@ namespace Nz::ShaderAst
|
||||
Serialize(node);
|
||||
}
|
||||
|
||||
|
||||
void Visit(const ShaderNodes::BuiltinVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::InputVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::LocalVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::OutputVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::ParameterVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
void Visit(const ShaderNodes::UniformVariable& var) override
|
||||
{
|
||||
Serialize(var);
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void Serialize(const T& node)
|
||||
@@ -101,13 +129,6 @@ namespace Nz::ShaderAst
|
||||
Node(node.right);
|
||||
}
|
||||
|
||||
void ShaderSerializerBase::Serialize(BinaryFunc& node)
|
||||
{
|
||||
Enum(node.intrinsic);
|
||||
Node(node.left);
|
||||
Node(node.right);
|
||||
}
|
||||
|
||||
void ShaderSerializerBase::Serialize(BinaryOp& node)
|
||||
{
|
||||
Enum(node.op);
|
||||
@@ -129,7 +150,7 @@ namespace Nz::ShaderAst
|
||||
|
||||
void ShaderSerializerBase::Serialize(BuiltinVariable& node)
|
||||
{
|
||||
Enum(node.var);
|
||||
Enum(node.type);
|
||||
Enum(node.type);
|
||||
}
|
||||
|
||||
@@ -170,7 +191,7 @@ namespace Nz::ShaderAst
|
||||
|
||||
void ShaderSerializerBase::Serialize(DeclareVariable& node)
|
||||
{
|
||||
Node(node.variable);
|
||||
Variable(node.variable);
|
||||
Node(node.expression);
|
||||
}
|
||||
|
||||
@@ -179,10 +200,22 @@ namespace Nz::ShaderAst
|
||||
Node(node.expression);
|
||||
}
|
||||
|
||||
void ShaderSerializerBase::Serialize(Identifier& node)
|
||||
{
|
||||
Variable(node.var);
|
||||
}
|
||||
|
||||
void ShaderSerializerBase::Serialize(IntrinsicCall& node)
|
||||
{
|
||||
Enum(node.intrinsic);
|
||||
Container(node.parameters);
|
||||
for (auto& param : node.parameters)
|
||||
Node(param);
|
||||
}
|
||||
|
||||
void ShaderSerializerBase::Serialize(NamedVariable& node)
|
||||
{
|
||||
Value(node.name);
|
||||
Enum(node.kind);
|
||||
Enum(node.type);
|
||||
}
|
||||
|
||||
@@ -272,6 +305,18 @@ namespace Nz::ShaderAst
|
||||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderSerializer::Variable(VariablePtr& var)
|
||||
{
|
||||
VariableType nodeType = (var) ? var->GetType() : VariableType::None;
|
||||
m_stream << static_cast<Int32>(nodeType);
|
||||
|
||||
if (var)
|
||||
{
|
||||
ShaderSerializerVisitor visitor(*this);
|
||||
var->Visit(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
ByteArray Serialize(const StatementPtr& shader)
|
||||
{
|
||||
ByteArray byteArray;
|
||||
@@ -309,27 +354,26 @@ namespace Nz::ShaderAst
|
||||
|
||||
NodeType nodeType = static_cast<NodeType>(nodeTypeInt);
|
||||
|
||||
#define HandleNodeType(Type) case NodeType:: Type : node = std::make_shared<Type>(); break
|
||||
#define HandleType(Type) case NodeType:: Type : node = std::make_shared<Type>(); break
|
||||
switch (nodeType)
|
||||
{
|
||||
case NodeType::None: break;
|
||||
|
||||
HandleNodeType(AssignOp);
|
||||
HandleNodeType(BinaryFunc);
|
||||
HandleNodeType(BinaryOp);
|
||||
HandleNodeType(Branch);
|
||||
HandleNodeType(BuiltinVariable);
|
||||
HandleNodeType(Cast);
|
||||
HandleNodeType(Constant);
|
||||
HandleNodeType(ConditionalStatement);
|
||||
HandleNodeType(DeclareVariable);
|
||||
HandleNodeType(ExpressionStatement);
|
||||
HandleNodeType(NamedVariable);
|
||||
HandleNodeType(Sample2D);
|
||||
HandleNodeType(SwizzleOp);
|
||||
HandleNodeType(StatementBlock);
|
||||
HandleType(AssignOp);
|
||||
HandleType(BinaryOp);
|
||||
HandleType(Branch);
|
||||
HandleType(Cast);
|
||||
HandleType(Constant);
|
||||
HandleType(ConditionalStatement);
|
||||
HandleType(DeclareVariable);
|
||||
HandleType(ExpressionStatement);
|
||||
HandleType(Identifier);
|
||||
HandleType(IntrinsicCall);
|
||||
HandleType(Sample2D);
|
||||
HandleType(SwizzleOp);
|
||||
HandleType(StatementBlock);
|
||||
}
|
||||
#undef HandleNodeType
|
||||
#undef HandleType
|
||||
|
||||
if (node)
|
||||
{
|
||||
@@ -372,5 +416,32 @@ namespace Nz::ShaderAst
|
||||
{
|
||||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderUnserializer::Variable(VariablePtr& var)
|
||||
{
|
||||
Int32 nodeTypeInt;
|
||||
m_stream >> nodeTypeInt;
|
||||
|
||||
VariableType nodeType = static_cast<VariableType>(nodeTypeInt);
|
||||
|
||||
#define HandleType(Type) case VariableType:: Type : var = std::make_shared<Type>(); break
|
||||
switch (nodeType)
|
||||
{
|
||||
case VariableType::None: break;
|
||||
|
||||
HandleType(BuiltinVariable);
|
||||
HandleType(InputVariable);
|
||||
HandleType(LocalVariable);
|
||||
HandleType(OutputVariable);
|
||||
HandleType(UniformVariable);
|
||||
}
|
||||
#undef HandleType
|
||||
|
||||
if (var)
|
||||
{
|
||||
ShaderSerializerVisitor visitor(*this);
|
||||
var->Visit(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,20 +3,49 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ShaderValidator.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Renderer/ShaderAst.hpp>
|
||||
#include <Nazara/Renderer/ShaderVariables.hpp>
|
||||
#include <vector>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz::ShaderAst
|
||||
namespace Nz
|
||||
{
|
||||
struct AstError
|
||||
{
|
||||
std::string errMsg;
|
||||
};
|
||||
|
||||
bool ShaderValidator::Validate(const StatementPtr& shader, std::string* error)
|
||||
struct ShaderValidator::Context
|
||||
{
|
||||
struct Local
|
||||
{
|
||||
std::string name;
|
||||
ShaderNodes::ExpressionType type;
|
||||
};
|
||||
|
||||
const ShaderAst::Function* currentFunction;
|
||||
std::vector<Local> declaredLocals;
|
||||
std::vector<std::size_t> blockLocalIndex;
|
||||
};
|
||||
|
||||
bool ShaderValidator::Validate(std::string* error)
|
||||
{
|
||||
try
|
||||
{
|
||||
shader->Visit(*this);
|
||||
for (std::size_t i = 0; i < m_shader.GetFunctionCount(); ++i)
|
||||
{
|
||||
const auto& func = m_shader.GetFunction(i);
|
||||
|
||||
Context currentContext;
|
||||
currentContext.currentFunction = &func;
|
||||
|
||||
m_context = ¤tContext;
|
||||
CallOnExit resetContext([&] { m_context = nullptr; });
|
||||
|
||||
func.statement->Visit(*this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const AstError& e)
|
||||
@@ -28,14 +57,14 @@ namespace Nz::ShaderAst
|
||||
}
|
||||
}
|
||||
|
||||
const ExpressionPtr& ShaderValidator::MandatoryExpr(const ExpressionPtr& node)
|
||||
const ShaderNodes::ExpressionPtr& ShaderValidator::MandatoryExpr(const ShaderNodes::ExpressionPtr& node)
|
||||
{
|
||||
MandatoryNode(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
const NodePtr& ShaderValidator::MandatoryNode(const NodePtr& node)
|
||||
const ShaderNodes::NodePtr& ShaderValidator::MandatoryNode(const ShaderNodes::NodePtr& node)
|
||||
{
|
||||
if (!node)
|
||||
throw AstError{ "Invalid node" };
|
||||
@@ -43,90 +72,76 @@ namespace Nz::ShaderAst
|
||||
return node;
|
||||
}
|
||||
|
||||
void ShaderValidator::TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right)
|
||||
void ShaderValidator::TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right)
|
||||
{
|
||||
if (left->GetExpressionType() != right->GetExpressionType())
|
||||
return TypeMustMatch(left->GetExpressionType(), right->GetExpressionType());
|
||||
}
|
||||
|
||||
void ShaderValidator::TypeMustMatch(ShaderNodes::ExpressionType left, ShaderNodes::ExpressionType right)
|
||||
{
|
||||
if (left != right)
|
||||
throw AstError{ "Left expression type must match right expression type" };
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const AssignOp& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::AssignOp& node)
|
||||
{
|
||||
MandatoryNode(node.left);
|
||||
MandatoryNode(node.right);
|
||||
TypeMustMatch(node.left, node.right);
|
||||
|
||||
Visit(node.left);
|
||||
Visit(node.right);
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const BinaryFunc& node)
|
||||
{
|
||||
MandatoryNode(node.left);
|
||||
MandatoryNode(node.right);
|
||||
TypeMustMatch(node.left, node.right);
|
||||
|
||||
switch (node.intrinsic)
|
||||
{
|
||||
case BinaryIntrinsic::CrossProduct:
|
||||
{
|
||||
if (node.left->GetExpressionType() != ExpressionType::Float3)
|
||||
throw AstError{ "CrossProduct only works with Float3 expressions" };
|
||||
}
|
||||
|
||||
case BinaryIntrinsic::DotProduct:
|
||||
break;
|
||||
}
|
||||
if (node.left->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue)
|
||||
throw AstError { "Assignation is only possible with a l-value" };
|
||||
|
||||
Visit(node.left);
|
||||
Visit(node.right);
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const BinaryOp& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::BinaryOp& node)
|
||||
{
|
||||
MandatoryNode(node.left);
|
||||
MandatoryNode(node.right);
|
||||
|
||||
ExpressionType leftType = node.left->GetExpressionType();
|
||||
ExpressionType rightType = node.right->GetExpressionType();
|
||||
ShaderNodes::ExpressionType leftType = node.left->GetExpressionType();
|
||||
ShaderNodes::ExpressionType rightType = node.right->GetExpressionType();
|
||||
|
||||
switch (node.op)
|
||||
{
|
||||
case BinaryType::Add:
|
||||
case BinaryType::Equality:
|
||||
case BinaryType::Substract:
|
||||
case ShaderNodes::BinaryType::Add:
|
||||
case ShaderNodes::BinaryType::Equality:
|
||||
case ShaderNodes::BinaryType::Substract:
|
||||
TypeMustMatch(node.left, node.right);
|
||||
break;
|
||||
|
||||
case BinaryType::Multiply:
|
||||
case BinaryType::Divide:
|
||||
case ShaderNodes::BinaryType::Multiply:
|
||||
case ShaderNodes::BinaryType::Divide:
|
||||
{
|
||||
switch (leftType)
|
||||
{
|
||||
case ExpressionType::Float1:
|
||||
case ShaderNodes::ExpressionType::Float1:
|
||||
{
|
||||
if (Node::GetComponentType(rightType) != ExpressionType::Float1)
|
||||
if (ShaderNodes::Node::GetComponentType(rightType) != ShaderNodes::ExpressionType::Float1)
|
||||
throw AstError{ "Left expression type is not compatible with right expression type" };
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ExpressionType::Float2:
|
||||
case ExpressionType::Float3:
|
||||
case ExpressionType::Float4:
|
||||
case ShaderNodes::ExpressionType::Float2:
|
||||
case ShaderNodes::ExpressionType::Float3:
|
||||
case ShaderNodes::ExpressionType::Float4:
|
||||
{
|
||||
if (leftType != rightType && rightType != ExpressionType::Float1)
|
||||
if (leftType != rightType && rightType != ShaderNodes::ExpressionType::Float1)
|
||||
throw AstError{ "Left expression type is not compatible with right expression type" };
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ExpressionType::Mat4x4:
|
||||
case ShaderNodes::ExpressionType::Mat4x4:
|
||||
{
|
||||
switch (rightType)
|
||||
{
|
||||
case ExpressionType::Float1:
|
||||
case ExpressionType::Float4:
|
||||
case ExpressionType::Mat4x4:
|
||||
case ShaderNodes::ExpressionType::Float1:
|
||||
case ShaderNodes::ExpressionType::Float4:
|
||||
case ShaderNodes::ExpressionType::Mat4x4:
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -146,7 +161,7 @@ namespace Nz::ShaderAst
|
||||
Visit(node.right);
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const Branch& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::Branch& node)
|
||||
{
|
||||
for (const auto& condStatement : node.condStatements)
|
||||
{
|
||||
@@ -155,11 +170,7 @@ namespace Nz::ShaderAst
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const BuiltinVariable& /*node*/)
|
||||
{
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const Cast& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::Cast& node)
|
||||
{
|
||||
unsigned int componentCount = 0;
|
||||
unsigned int requiredComponents = node.GetComponentCount(node.exprType);
|
||||
@@ -176,55 +187,203 @@ namespace Nz::ShaderAst
|
||||
throw AstError{ "Component count doesn't match required component count" };
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const Constant& /*node*/)
|
||||
void ShaderValidator::Visit(const ShaderNodes::Constant& /*node*/)
|
||||
{
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const DeclareVariable& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::DeclareVariable& node)
|
||||
{
|
||||
assert(m_context);
|
||||
|
||||
if (node.expression)
|
||||
Visit(node.expression);
|
||||
|
||||
auto& local = m_context->declaredLocals.emplace_back();
|
||||
local.name = node.variable->name;
|
||||
local.type = node.variable->type;
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const ShaderNodes::ExpressionStatement& node)
|
||||
{
|
||||
Visit(MandatoryNode(node.expression));
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const ExpressionStatement& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::Identifier& node)
|
||||
{
|
||||
Visit(MandatoryNode(node.expression));
|
||||
assert(m_context);
|
||||
|
||||
if (!node.var)
|
||||
throw AstError{ "Invalid variable" };
|
||||
|
||||
//< FIXME: Use variable visitor
|
||||
switch (node.var->GetType())
|
||||
{
|
||||
case ShaderNodes::VariableType::BuiltinVariable:
|
||||
break;
|
||||
|
||||
case ShaderNodes::VariableType::InputVariable:
|
||||
{
|
||||
auto& namedVar = static_cast<ShaderNodes::InputVariable&>(*node.var);
|
||||
|
||||
for (std::size_t i = 0; i < m_shader.GetInputCount(); ++i)
|
||||
{
|
||||
const auto& input = m_shader.GetInput(i);
|
||||
if (input.name == namedVar.name)
|
||||
{
|
||||
TypeMustMatch(input.type, namedVar.type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw AstError{ "Input not found" };
|
||||
}
|
||||
|
||||
case ShaderNodes::VariableType::LocalVariable:
|
||||
{
|
||||
auto& localVar = static_cast<ShaderNodes::LocalVariable&>(*node.var);
|
||||
const auto& vars = m_context->declaredLocals;
|
||||
|
||||
auto it = std::find_if(vars.begin(), vars.end(), [&](const auto& var) { return var.name == localVar.name; });
|
||||
if (it == vars.end())
|
||||
throw AstError{ "Local variable not found in this block" };
|
||||
|
||||
TypeMustMatch(it->type, localVar.type);
|
||||
break;
|
||||
}
|
||||
|
||||
case ShaderNodes::VariableType::OutputVariable:
|
||||
{
|
||||
auto& outputVar = static_cast<ShaderNodes::OutputVariable&>(*node.var);
|
||||
|
||||
for (std::size_t i = 0; i < m_shader.GetOutputCount(); ++i)
|
||||
{
|
||||
const auto& input = m_shader.GetOutput(i);
|
||||
if (input.name == outputVar.name)
|
||||
{
|
||||
TypeMustMatch(input.type, outputVar.type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw AstError{ "Output not found" };
|
||||
}
|
||||
|
||||
case ShaderNodes::VariableType::ParameterVariable:
|
||||
{
|
||||
assert(m_context->currentFunction);
|
||||
|
||||
auto& parameter = static_cast<ShaderNodes::ParameterVariable&>(*node.var);
|
||||
const auto& parameters = m_context->currentFunction->parameters;
|
||||
|
||||
auto it = std::find_if(parameters.begin(), parameters.end(), [&](const auto& parameter) { return parameter.name == parameter.name; });
|
||||
if (it == parameters.end())
|
||||
throw AstError{ "Parameter not found in function" };
|
||||
|
||||
TypeMustMatch(it->type, parameter.type);
|
||||
break;
|
||||
}
|
||||
|
||||
case ShaderNodes::VariableType::UniformVariable:
|
||||
{
|
||||
auto& uniformVar = static_cast<ShaderNodes::UniformVariable&>(*node.var);
|
||||
|
||||
for (std::size_t i = 0; i < m_shader.GetUniformCount(); ++i)
|
||||
{
|
||||
const auto& uniform = m_shader.GetUniform(i);
|
||||
if (uniform.name == uniformVar.name)
|
||||
{
|
||||
TypeMustMatch(uniform.type, uniformVar.type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw AstError{ "Uniform not found" };
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const NamedVariable& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::IntrinsicCall& node)
|
||||
{
|
||||
if (node.name.empty())
|
||||
throw AstError{ "Variable has empty name" };
|
||||
switch (node.intrinsic)
|
||||
{
|
||||
case ShaderNodes::IntrinsicType::CrossProduct:
|
||||
case ShaderNodes::IntrinsicType::DotProduct:
|
||||
{
|
||||
if (node.parameters.size() != 2)
|
||||
throw AstError { "Expected 2 parameters" };
|
||||
|
||||
for (auto& param : node.parameters)
|
||||
MandatoryNode(param);
|
||||
|
||||
ShaderNodes::ExpressionType type = node.parameters.front()->GetExpressionType();
|
||||
for (std::size_t i = 1; i < node.parameters.size(); ++i)
|
||||
{
|
||||
if (type != node.parameters[i]->GetExpressionType())
|
||||
throw AstError{ "All type must match" };
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (node.intrinsic)
|
||||
{
|
||||
case ShaderNodes::IntrinsicType::CrossProduct:
|
||||
{
|
||||
if (node.parameters[0]->GetExpressionType() != ShaderNodes::ExpressionType::Float3)
|
||||
throw AstError{ "CrossProduct only works with Float3 expressions" };
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ShaderNodes::IntrinsicType::DotProduct:
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto& param : node.parameters)
|
||||
Visit(param);
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const Sample2D& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::Sample2D& node)
|
||||
{
|
||||
if (MandatoryExpr(node.sampler)->GetExpressionType() != ExpressionType::Sampler2D)
|
||||
if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderNodes::ExpressionType::Sampler2D)
|
||||
throw AstError{ "Sampler must be a Sampler2D" };
|
||||
|
||||
if (MandatoryExpr(node.coordinates)->GetExpressionType() != ExpressionType::Float2)
|
||||
if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderNodes::ExpressionType::Float2)
|
||||
throw AstError{ "Coordinates must be a Float2" };
|
||||
|
||||
Visit(node.sampler);
|
||||
Visit(node.coordinates);
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const StatementBlock& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::StatementBlock& node)
|
||||
{
|
||||
assert(m_context);
|
||||
|
||||
m_context->blockLocalIndex.push_back(m_context->declaredLocals.size());
|
||||
|
||||
for (const auto& statement : node.statements)
|
||||
Visit(MandatoryNode(statement));
|
||||
|
||||
assert(m_context->declaredLocals.size() >= m_context->blockLocalIndex.back());
|
||||
m_context->declaredLocals.resize(m_context->blockLocalIndex.back());
|
||||
m_context->blockLocalIndex.pop_back();
|
||||
}
|
||||
|
||||
void ShaderValidator::Visit(const SwizzleOp& node)
|
||||
void ShaderValidator::Visit(const ShaderNodes::SwizzleOp& node)
|
||||
{
|
||||
if (node.componentCount > 4)
|
||||
throw AstError{ "Cannot swizzle more than four elements" };
|
||||
|
||||
switch (MandatoryExpr(node.expression)->GetExpressionType())
|
||||
{
|
||||
case ExpressionType::Float1:
|
||||
case ExpressionType::Float2:
|
||||
case ExpressionType::Float3:
|
||||
case ExpressionType::Float4:
|
||||
case ShaderNodes::ExpressionType::Float1:
|
||||
case ShaderNodes::ExpressionType::Float2:
|
||||
case ShaderNodes::ExpressionType::Float3:
|
||||
case ShaderNodes::ExpressionType::Float4:
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -234,9 +393,9 @@ namespace Nz::ShaderAst
|
||||
Visit(node.expression);
|
||||
}
|
||||
|
||||
bool Validate(const StatementPtr& shader, std::string* error)
|
||||
bool ValidateShader(const ShaderAst& shader, std::string* error)
|
||||
{
|
||||
ShaderValidator validator;
|
||||
return validator.Validate(shader, error);
|
||||
ShaderValidator validator(shader);
|
||||
return validator.Validate(error);
|
||||
}
|
||||
}
|
||||
|
||||
16
src/Nazara/Renderer/ShaderVarVisitor.cpp
Normal file
16
src/Nazara/Renderer/ShaderVarVisitor.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ShaderVarVisitor.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
ShaderVarVisitor::~ShaderVarVisitor() = default;
|
||||
|
||||
void ShaderVarVisitor::Visit(const ShaderNodes::VariablePtr& node)
|
||||
{
|
||||
node->Visit(*this);
|
||||
}
|
||||
}
|
||||
77
src/Nazara/Renderer/ShaderVariables.cpp
Normal file
77
src/Nazara/Renderer/ShaderVariables.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ShaderVariables.hpp>
|
||||
#include <Nazara/Renderer/ShaderVarVisitor.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz::ShaderNodes
|
||||
{
|
||||
ShaderNodes::Variable::~Variable() = default;
|
||||
|
||||
VariableType BuiltinVariable::GetType() const
|
||||
{
|
||||
return VariableType::BuiltinVariable;
|
||||
}
|
||||
|
||||
void BuiltinVariable::Visit(ShaderVarVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
VariableType InputVariable::GetType() const
|
||||
{
|
||||
return VariableType::InputVariable;
|
||||
}
|
||||
|
||||
void InputVariable::Visit(ShaderVarVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
VariableType LocalVariable::GetType() const
|
||||
{
|
||||
return VariableType::LocalVariable;
|
||||
}
|
||||
|
||||
void LocalVariable::Visit(ShaderVarVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
VariableType OutputVariable::GetType() const
|
||||
{
|
||||
return VariableType::OutputVariable;
|
||||
}
|
||||
|
||||
void OutputVariable::Visit(ShaderVarVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
VariableType ParameterVariable::GetType() const
|
||||
{
|
||||
return VariableType::ParameterVariable;
|
||||
}
|
||||
|
||||
void ParameterVariable::Visit(ShaderVarVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
|
||||
|
||||
VariableType UniformVariable::GetType() const
|
||||
{
|
||||
return VariableType::UniformVariable;
|
||||
}
|
||||
|
||||
void UniformVariable::Visit(ShaderVarVisitor& visitor)
|
||||
{
|
||||
visitor.Visit(*this);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Nz
|
||||
{
|
||||
ShaderVisitor::~ShaderVisitor() = default;
|
||||
|
||||
void ShaderVisitor::EnableCondition(const String& name, bool cond)
|
||||
void ShaderVisitor::EnableCondition(const std::string& name, bool cond)
|
||||
{
|
||||
if (cond)
|
||||
m_conditions.insert(name);
|
||||
@@ -17,12 +17,12 @@ namespace Nz
|
||||
m_conditions.erase(name);
|
||||
}
|
||||
|
||||
bool ShaderVisitor::IsConditionEnabled(const String& name) const
|
||||
bool ShaderVisitor::IsConditionEnabled(const std::string& name) const
|
||||
{
|
||||
return m_conditions.count(name) != 0;
|
||||
}
|
||||
|
||||
void ShaderVisitor::Visit(const ShaderAst::NodePtr& node)
|
||||
void ShaderVisitor::Visit(const ShaderNodes::NodePtr& node)
|
||||
{
|
||||
node->Visit(*this);
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
ShaderWriter::~ShaderWriter() = default;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user