340 lines
12 KiB
Zig
340 lines
12 KiB
Zig
const coral = @import("../coral.zig");
|
|
|
|
const std = @import("std");
|
|
|
|
pub const Version = enum {
|
|
core_430,
|
|
};
|
|
|
|
pub fn generate(source: coral.bytes.Writable, root: coral.shaders.Root, version: Version) coral.shaders.GenerationError!void {
|
|
try coral.bytes.writeFormatted(source, "#version {version_name}\n", .{
|
|
.version_name = switch (version) {
|
|
.core_430 => "430 core",
|
|
},
|
|
});
|
|
|
|
for (root.uniforms.slice()) |uniform| {
|
|
try coral.bytes.writeFormatted(source, "\nlayout (binding = {binding}) uniform {semantic} {{\n", .{
|
|
.binding = coral.utf8.cDec(uniform.binding),
|
|
.semantic = uniform.semantic,
|
|
});
|
|
|
|
var has_field = uniform.has_field;
|
|
|
|
while (has_field) |field| : (has_field = field.has_next) {
|
|
try coral.bytes.writeAll(source, "\t");
|
|
try generateType(source, field.type);
|
|
try coral.bytes.writeFormatted(source, " {identifier};\n", .{ .identifier = field.identifier });
|
|
}
|
|
|
|
try coral.bytes.writeFormatted(source, "}} {identifier};\n", .{
|
|
.identifier = uniform.identifier,
|
|
});
|
|
}
|
|
|
|
for (root.textures.slice()) |texture| {
|
|
try coral.bytes.writeFormatted(source, "\nlayout (binding = {binding}) uniform {layout} {identifier};\n", .{
|
|
.binding = coral.utf8.cDec(texture.binding),
|
|
.identifier = texture.identifier,
|
|
|
|
.layout = switch (texture.layout) {
|
|
.dimensions_2 => "sampler2D",
|
|
},
|
|
});
|
|
}
|
|
|
|
for (root.inputs.slice()) |input| {
|
|
try coral.bytes.writeFormatted(source, "\nlayout (location = {location}) in ", .{
|
|
.location = coral.utf8.cDec(input.location),
|
|
});
|
|
|
|
try generateType(source, input.type);
|
|
try coral.bytes.writeFormatted(source, " {identifier};\n", .{ .identifier = input.identifier });
|
|
}
|
|
|
|
for (root.outputs.slice()) |output| {
|
|
try coral.bytes.writeFormatted(source, "\nlayout (location = {location}) out ", .{
|
|
.location = coral.utf8.cDec(output.location),
|
|
});
|
|
|
|
try generateType(source, output.type);
|
|
try coral.bytes.writeFormatted(source, " {identifier};\n", .{ .identifier = output.identifier });
|
|
}
|
|
|
|
for (root.functions.slice()) |function| {
|
|
if (function.has_return_type) |return_type| {
|
|
try coral.bytes.writeAll(source, "\n");
|
|
try generateType(source, return_type);
|
|
} else {
|
|
try coral.bytes.writeAll(source, "\nvoid");
|
|
}
|
|
|
|
try coral.bytes.writeFormatted(source, " {identifier}(", .{ .identifier = function.identifier });
|
|
|
|
var has_parameter = function.has_parameter;
|
|
|
|
if (has_parameter) |first_parameter| {
|
|
try generateType(source, first_parameter.type);
|
|
try coral.bytes.writeFormatted(source, " {identifier}", .{ .identifier = first_parameter.identifier });
|
|
|
|
has_parameter = first_parameter.has_next;
|
|
|
|
while (has_parameter) |parameter| : (has_parameter = parameter.has_next) {
|
|
try coral.bytes.writeAll(source, ", ");
|
|
try generateType(source, parameter.type);
|
|
try coral.bytes.writeFormatted(source, " {identifier}", .{ .identifier = parameter.identifier });
|
|
}
|
|
}
|
|
|
|
try coral.bytes.writeAll(source, ") ");
|
|
try generateBlock(source, function.block);
|
|
}
|
|
}
|
|
|
|
fn generateArguments(source: coral.bytes.Writable, first_argument: *const coral.shaders.Argument) coral.bytes.ReadWriteError!void {
|
|
try generateExpression(source, first_argument.expression);
|
|
|
|
var has_next_argument = first_argument.has_next;
|
|
|
|
while (has_next_argument) |next_argument| : (has_next_argument = next_argument.has_next) {
|
|
try coral.bytes.writeAll(source, ", ");
|
|
try generateExpression(source, next_argument.expression);
|
|
}
|
|
}
|
|
|
|
fn generateBlock(source: coral.bytes.Writable, block: *const coral.shaders.Block) coral.bytes.ReadWriteError!void {
|
|
try coral.bytes.writeAll(source, "{\n");
|
|
|
|
var has_next_statement = block.has_statement;
|
|
|
|
while (has_next_statement) |statement| {
|
|
try coral.bytes.writeN(source, "\t", block.depth);
|
|
|
|
switch (statement.*) {
|
|
.return_expression => |return_expression| {
|
|
try coral.bytes.writeAll(source, "return ");
|
|
|
|
if (return_expression) |expression| {
|
|
try generateExpression(source, expression);
|
|
}
|
|
|
|
try coral.bytes.writeAll(source, ";\n");
|
|
|
|
has_next_statement = null;
|
|
},
|
|
|
|
.declare_local => |declare_local| {
|
|
try generateType(source, declare_local.local.type);
|
|
try coral.bytes.writeFormatted(source, " {identifier} = ", .{ .identifier = declare_local.local.identifier });
|
|
try generateExpression(source, declare_local.local.expression);
|
|
try coral.bytes.writeAll(source, ";\n");
|
|
|
|
has_next_statement = declare_local.has_next;
|
|
},
|
|
|
|
.mutate_local => |mutate_local| {
|
|
try coral.bytes.writeFormatted(source, "{identifier} = ", .{ .identifier = mutate_local.local.identifier });
|
|
try generateExpression(source, mutate_local.expression);
|
|
try coral.bytes.writeAll(source, ";\n");
|
|
|
|
has_next_statement = mutate_local.has_next;
|
|
},
|
|
|
|
.mutate_output => |mutate_output| {
|
|
try coral.bytes.writeFormatted(source, "{identifier} = ", .{ .identifier = mutate_output.output.identifier });
|
|
try generateExpression(source, mutate_output.expression);
|
|
try coral.bytes.writeAll(source, ";\n");
|
|
|
|
has_next_statement = mutate_output.has_next;
|
|
},
|
|
}
|
|
}
|
|
|
|
try coral.bytes.writeAll(source, "}\n");
|
|
}
|
|
|
|
fn generateExpression(source: coral.bytes.Writable, expression: *const coral.shaders.Expression) coral.bytes.ReadWriteError!void {
|
|
switch (expression.*) {
|
|
.float => |float| {
|
|
try coral.bytes.writeFormatted(source, "{whole}.{decimal}", float);
|
|
},
|
|
|
|
.int => |int| {
|
|
try coral.bytes.writeAll(source, int.literal);
|
|
},
|
|
|
|
.group_expression => |group_expression| {
|
|
try coral.bytes.writeAll(source, "(");
|
|
try generateExpression(source, group_expression);
|
|
try coral.bytes.writeAll(source, ")");
|
|
},
|
|
|
|
.add => |add| {
|
|
try generateExpression(source, add.lhs_expression);
|
|
try coral.bytes.writeAll(source, " + ");
|
|
try generateExpression(source, add.rhs_expression);
|
|
},
|
|
|
|
.subtract => |subtract| {
|
|
try generateExpression(source, subtract.lhs_expression);
|
|
try coral.bytes.writeAll(source, " - ");
|
|
try generateExpression(source, subtract.rhs_expression);
|
|
},
|
|
|
|
.multiply => |multiply| {
|
|
try generateExpression(source, multiply.lhs_expression);
|
|
try coral.bytes.writeAll(source, " * ");
|
|
try generateExpression(source, multiply.rhs_expression);
|
|
},
|
|
|
|
.divide => |divide| {
|
|
try generateExpression(source, divide.lhs_expression);
|
|
try coral.bytes.writeAll(source, " / ");
|
|
try generateExpression(source, divide.rhs_expression);
|
|
},
|
|
|
|
.equal => |equal| {
|
|
try generateExpression(source, equal.lhs_expression);
|
|
try coral.bytes.writeAll(source, " == ");
|
|
try generateExpression(source, equal.rhs_expression);
|
|
},
|
|
|
|
.greater_than => |greater_than| {
|
|
try generateExpression(source, greater_than.lhs_expression);
|
|
try coral.bytes.writeAll(source, " > ");
|
|
try generateExpression(source, greater_than.rhs_expression);
|
|
},
|
|
|
|
.greater_equal => |greater_equal| {
|
|
try generateExpression(source, greater_equal.lhs_expression);
|
|
try coral.bytes.writeAll(source, " >= ");
|
|
try generateExpression(source, greater_equal.rhs_expression);
|
|
},
|
|
|
|
.lesser_than => |lesser_than| {
|
|
try generateExpression(source, lesser_than.lhs_expression);
|
|
try coral.bytes.writeAll(source, " < ");
|
|
try generateExpression(source, lesser_than.rhs_expression);
|
|
},
|
|
|
|
.lesser_equal => |lesser_equal| {
|
|
try generateExpression(source, lesser_equal.lhs_expression);
|
|
try coral.bytes.writeAll(source, " <= ");
|
|
try generateExpression(source, lesser_equal.rhs_expression);
|
|
},
|
|
|
|
.negate_expression => |negate_expression| {
|
|
try coral.bytes.writeAll(source, "-");
|
|
try generateExpression(source, negate_expression);
|
|
},
|
|
|
|
.get_local => |local| {
|
|
try coral.bytes.writeAll(source, local.identifier);
|
|
},
|
|
|
|
.mutate_local => |mutate_local| {
|
|
try coral.bytes.writeAll(source, mutate_local.local.identifier);
|
|
try coral.bytes.writeAll(source, " = ");
|
|
try generateExpression(source, mutate_local.expression);
|
|
},
|
|
|
|
.get_object => |get_object| {
|
|
try generateExpression(source, get_object.object_expression);
|
|
try coral.bytes.writeAll(source, ".");
|
|
try coral.bytes.writeAll(source, get_object.field.identifier);
|
|
},
|
|
|
|
.get_uniform => |get_uniform| {
|
|
try coral.bytes.writeFormatted(source, "{identifier}.", .{ .identifier = get_uniform.uniform.identifier });
|
|
try coral.bytes.writeAll(source, get_uniform.field.identifier);
|
|
},
|
|
|
|
.get_texture => |texture| {
|
|
try coral.bytes.writeAll(source, texture.identifier);
|
|
},
|
|
|
|
.get_parameter => |parameter| {
|
|
try coral.bytes.writeAll(source, parameter.identifier);
|
|
},
|
|
|
|
.get_output => |output| {
|
|
try coral.bytes.writeAll(source, output.identifier);
|
|
},
|
|
|
|
.mutate_output => |mutate_output| {
|
|
try coral.bytes.writeAll(source, mutate_output.output.identifier);
|
|
try coral.bytes.writeAll(source, " = ");
|
|
try generateExpression(source, mutate_output.expression);
|
|
},
|
|
|
|
.get_input => |input| {
|
|
try coral.bytes.writeAll(source, input.identifier);
|
|
},
|
|
|
|
.invoke => |invoke| {
|
|
try coral.bytes.writeFormatted(source, "{name}(", .{ .name = invoke.function.identifier });
|
|
|
|
if (invoke.has_argument) |first_argument| {
|
|
try generateArguments(source, first_argument);
|
|
}
|
|
|
|
try coral.bytes.writeAll(source, ")");
|
|
},
|
|
|
|
.convert => |convert| {
|
|
try generateType(source, convert.target_type);
|
|
try coral.bytes.writeAll(source, "(");
|
|
try generateArguments(source, convert.first_argument);
|
|
try coral.bytes.writeAll(source, ")");
|
|
},
|
|
|
|
.pow => |pow| {
|
|
try coral.bytes.writeAll(source, "pow(");
|
|
try generateArguments(source, pow.first_argument);
|
|
try coral.bytes.writeAll(source, ")");
|
|
},
|
|
|
|
.abs => |abs| {
|
|
try coral.bytes.writeAll(source, "abs(");
|
|
try generateArguments(source, abs.first_argument);
|
|
try coral.bytes.writeAll(source, ")");
|
|
},
|
|
|
|
.sin => |sin| {
|
|
try coral.bytes.writeAll(source, "sin(");
|
|
try generateArguments(source, sin.first_argument);
|
|
try coral.bytes.writeAll(source, ")");
|
|
},
|
|
|
|
.sample => |sample| {
|
|
try coral.bytes.writeAll(source, "texture(");
|
|
|
|
if (sample.has_argument) |first_argument| {
|
|
try generateArguments(source, first_argument);
|
|
}
|
|
|
|
try coral.bytes.writeAll(source, ")");
|
|
},
|
|
}
|
|
}
|
|
|
|
fn generateType(source: coral.bytes.Writable, @"type": *const coral.shaders.Type) coral.bytes.ReadWriteError!void {
|
|
if (@"type" == coral.shaders.Type.float2) {
|
|
return try coral.bytes.writeAll(source, "vec2");
|
|
}
|
|
|
|
if (@"type" == coral.shaders.Type.float3) {
|
|
return try coral.bytes.writeAll(source, "vec3");
|
|
}
|
|
|
|
if (@"type" == coral.shaders.Type.float4) {
|
|
return try coral.bytes.writeAll(source, "vec4");
|
|
}
|
|
|
|
if (@"type" == coral.shaders.Type.float4x4) {
|
|
return try coral.bytes.writeAll(source, "mat4");
|
|
}
|
|
|
|
try coral.bytes.writeAll(source, @"type".identifier);
|
|
}
|