ona/src/coral/shaders/glsl.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);
}