diff --git a/build.zig b/build.zig index 396abde..07f8ac9 100644 --- a/build.zig +++ b/build.zig @@ -1,5 +1,92 @@ const std = @import("std"); +const BuildConfig = struct { + module_target: std.Build.ResolvedTarget, + spirv_target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, + + fn scan_demos(self: BuildConfig, ona_module: *std.Build.Module) void { + const b = ona_module.owner; + const build_demos_step = b.step("demos", "Build demos"); + + b.default_step.dependOn(build_demos_step); + + const cwd = std.fs.cwd(); + + var demos_dir = cwd.openDir("src/demos/", .{ .iterate = true }) catch { + return build_demos_step.dependOn(&b.addFail("failed to open demo files directory").step); + }; + + defer { + demos_dir.close(); + } + + var demos_iterator = demos_dir.iterate(); + + while (demos_iterator.next() catch { + return build_demos_step.dependOn(&b.addFail("failed to iterate over next entry in demos directory").step); + }) |entry| { + if (entry.kind != .file) { + continue; + } + + if (!std.mem.eql(u8, std.fs.path.extension(entry.name), ".zig")) { + continue; + } + + const demo_executable = b.addExecutable(.{ + .name = std.fmt.allocPrint(b.allocator, "{s}_demo", .{std.fs.path.stem(entry.name)}) catch { + return build_demos_step.dependOn(&b.addFail("failed to allocate demo name buffer").step); + }, + + .root_module = b.createModule(.{ + .root_source_file = b.path(b.pathJoin(&.{ "src/demos/", entry.name })), + .target = self.module_target, + .optimize = self.optimize, + + .imports = &.{ + .{ + .name = "ona", + .module = ona_module, + }, + }, + }), + }); + + demo_executable.linkSystemLibrary2("SDL3", .{ + .needed = true, + .preferred_link_mode = .dynamic, + }); + + const demo_installation = b.addInstallArtifact(demo_executable, .{}); + + build_demos_step.dependOn(&demo_installation.step); + } + } + + // TODO: Revisit Zig shaders once the SPIRV target becomes more mature. + // pub fn addShaders(self: BuildConfig, module: *std.Build.Module, shader_paths: []const []const u8) void { + // const b = module.owner; + + // for (shader_paths) |shader_path| { + // const shader_path_stem = std.fs.path.stem(shader_path); + + // const module_identifier = std.mem.join(b.allocator, ".", &.{ shader_path_stem, "spirv" }) catch { + // @panic("OOM"); + // }; + + // const spirv_object = b.addObject(.{ + // .name = module_identifier, + // .root_source_file = b.path(shader_path), + // .target = self.spirv_target, + // .use_llvm = false, + // }); + + // module.addAnonymousImport(module_identifier, .{ .root_source_file = spirv_object.getEmittedBin() }); + // } + // } +}; + const CommonArgs = struct { target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, @@ -7,19 +94,31 @@ const CommonArgs = struct { }; pub fn build(b: *std.Build) void { - const target = b.standardTargetOptions(.{}); - const optimize = b.standardOptimizeOption(.{}); + const config = BuildConfig{ + .optimize = b.standardOptimizeOption(.{}), + .module_target = b.standardTargetOptions(.{}), + + .spirv_target = b.resolveTargetQuery(.{ + .cpu_arch = .spirv64, + .os_tag = .vulkan, + .cpu_model = .{ .explicit = &std.Target.spirv.cpu.vulkan_v1_2 }, + .cpu_features_add = std.Target.spirv.featureSet(&.{.int64}), + .ofmt = .spirv, + }), + }; + + const shaderc_dependency = b.dependency("shaderc_zig", .{}); const coral_module = b.addModule("coral", .{ .root_source_file = b.path("src/coral/coral.zig"), - .target = target, - .optimize = optimize, + .target = config.module_target, + .optimize = config.optimize, }); const ext_module = b.createModule(.{ .root_source_file = b.path("src/ext/ext.zig"), - .target = target, - .optimize = optimize, + .target = config.module_target, + .optimize = config.optimize, .link_libc = true, }); @@ -28,10 +127,12 @@ pub fn build(b: *std.Build) void { .preferred_link_mode = .dynamic, }); + ext_module.linkLibrary(shaderc_dependency.artifact("shaderc")); + const ona_module = b.addModule("ona", .{ .root_source_file = b.path("src/ona/ona.zig"), - .target = target, - .optimize = optimize, + .target = config.module_target, + .optimize = config.optimize, .link_libc = true, .imports = &.{ @@ -46,17 +147,18 @@ pub fn build(b: *std.Build) void { }, }); - scan_demos(b, .{ - .target = target, - .optimize = optimize, - .ona_module = ona_module, - }); + // config.addShaders(ona_module, &.{ + // "./src/ona/gfx/effect_shader.zig", + // "./src/ona/gfx/effect_fragment.zig", + // }); + + config.scan_demos(ona_module); const test_tests = b.addTest(.{ .root_module = b.createModule(.{ .root_source_file = b.path("src/tests.zig"), - .target = target, - .optimize = optimize, + .target = config.module_target, + .optimize = config.optimize, .imports = &.{ .{ @@ -72,61 +174,3 @@ pub fn build(b: *std.Build) void { test_step.dependOn(&b.addRunArtifact(test_tests).step); test_step.dependOn(&b.addInstallArtifact(test_tests, .{}).step); } - -fn scan_demos(b: *std.Build, common: CommonArgs) void { - const build_demos_step = b.step("demos", "Build demos"); - - b.default_step.dependOn(build_demos_step); - - const cwd = std.fs.cwd(); - - var demos_dir = cwd.openDir("src/demos/", .{ .iterate = true }) catch { - return build_demos_step.dependOn(&b.addFail("failed to open demo files directory").step); - }; - - defer { - demos_dir.close(); - } - - var demos_iterator = demos_dir.iterate(); - - while (demos_iterator.next() catch { - return build_demos_step.dependOn(&b.addFail("failed to iterate over next entry in demos directory").step); - }) |entry| { - if (entry.kind != .file) { - continue; - } - - if (!std.mem.eql(u8, std.fs.path.extension(entry.name), ".zig")) { - continue; - } - - const demo_executable = b.addExecutable(.{ - .name = std.fmt.allocPrint(b.allocator, "{s}_demo", .{std.fs.path.stem(entry.name)}) catch { - return build_demos_step.dependOn(&b.addFail("failed to allocate demo name buffer").step); - }, - - .root_module = b.createModule(.{ - .root_source_file = b.path(b.pathJoin(&.{ "src/demos/", entry.name })), - .target = common.target, - .optimize = common.optimize, - - .imports = &.{ - .{ - .name = "ona", - .module = common.ona_module, - }, - }, - }), - }); - - demo_executable.linkSystemLibrary2("SDL3", .{ - .needed = true, - .preferred_link_mode = .dynamic, - }); - - const demo_installation = b.addInstallArtifact(demo_executable, .{}); - - build_demos_step.dependOn(&demo_installation.step); - } -} diff --git a/build.zig.zon b/build.zig.zon index 2087239..3867e7f 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,6 +1,14 @@ .{ .name = .ona, .version = "0.0.0", + + .dependencies = .{ + .shaderc_zig = .{ + .url = "git+https://github.com/tiawl/shaderc.zig#06565d2af3beec9780b11524984211ebd104fd21", + .hash = "shaderc_zig-1.0.0-mOl840tjAwBiAnMSfRskq0Iq3JJ9jPRHy2JoEgnUvSpV", + }, + }, + .fingerprint = 0x7d0142e88b22421d, .minimum_zig_version = "0.14.0", diff --git a/src/coral/coral.zig b/src/coral/coral.zig index c754758..fa09b83 100644 --- a/src/coral/coral.zig +++ b/src/coral/coral.zig @@ -16,8 +16,6 @@ pub const map = @import("./map.zig"); pub const scalars = @import("./scalars.zig"); -pub const shaders = @import("./shaders.zig"); - const std = @import("std"); pub const tree = @import("./tree.zig"); diff --git a/src/coral/shaders.zig b/src/coral/shaders.zig deleted file mode 100644 index 5c4cfbd..0000000 --- a/src/coral/shaders.zig +++ /dev/null @@ -1,349 +0,0 @@ -pub const Field = @import("./shaders/Field.zig"); - -pub const Root = @import("./shaders/Root.zig"); - -pub const Scope = @import("./shaders/Scope.zig"); - -pub const Type = @import("./shaders/Type.zig"); - -const coral = @import("./coral.zig"); - -const std = @import("std"); - -const tokens = @import("./shaders/tokens.zig"); - -pub const Argument = struct { - expression: *const Expression, - has_next: ?*const Argument = null, -}; - -pub const Block = struct { - scope: *const Scope, - depth: usize, - statements: ?*const Statement = null, - - pub fn hasLastStatement(self: Block) ?*const Statement { - var statement = self.statements orelse { - return null; - }; - - while (true) { - statement = switch (statement.*) { - .declare_local => |local_declaration| local_declaration.has_next orelse { - return statement; - }, - - .mutate_local => |local_mutation| local_mutation.has_next orelse { - return statement; - }, - - .mutate_output => |output_mutation| output_mutation.has_next orelse { - return statement; - }, - - .return_expression => { - return statement; - }, - }; - } - } -}; - -pub const DefinitionError = std.mem.Allocator.Error || error{ - TooManySymbols, - DuplicateIdentifier, -}; - -pub const Expression = union(enum) { - constant: [:0]const u8, - group_expression: *const Expression, - add: BinaryOperation, - subtract: BinaryOperation, - multiply: BinaryOperation, - divide: BinaryOperation, - equal: BinaryOperation, - greater_than: BinaryOperation, - greater_equal: BinaryOperation, - lesser_than: BinaryOperation, - lesser_equal: BinaryOperation, - negate_expression: *const Expression, - get_local: *const Local, - get_parameter: *const Parameter, - get_uniform: GetUniform, - get_object: GetObject, - mutate_local: LocalMutation, - mutate_output: OutputMutation, - get_texture: *const Texture, - get_output: *const Output, - get_input: *const Input, - invoke: Invocation, - convert: Conversion, - pow: Intrinsic, - abs: Intrinsic, - sin: Intrinsic, - sample: Builtin, - - pub const BinaryOperation = struct { - rhs_expression: *const Expression, - lhs_expression: *const Expression, - type: *const Type, - }; - - pub const Builtin = struct { - has_argument: ?*const Argument, - signatures: []const Signature, - - pub const Signature = struct { - parameter_types: []const *const Type, - return_type: *const Type, - }; - - pub fn inferType(self: Builtin) TypeError!*const Type { - signature_matching: for (self.signatures) |signature| { - var parameter_index: usize = 0; - var has_argument = self.has_argument; - - while (has_argument) |argument| : ({ - has_argument = argument.has_next; - parameter_index += 1; - }) { - if (signature.parameter_types.len == parameter_index) { - continue :signature_matching; - } - - if (signature.parameter_types[parameter_index] != try argument.expression.inferType()) { - continue :signature_matching; - } - } - - return signature.return_type; - } - - return error.IncompatibleArguments; - } - }; - - pub const Conversion = struct { - target_type: *const Type, - first_argument: *const Argument, - parameter_types: []const *const Type, - }; - - pub const Intrinsic = struct { - allowed_parameter_types: []const *const Type, - expected_parameter_count: usize, - first_argument: *const Argument, - - pub fn inferType(self: Intrinsic) TypeError!*const Type { - std.debug.assert(self.expected_parameter_count != 0); - - const return_type = try self.first_argument.expression.inferType(); - - if (std.mem.indexOfScalar(*const Type, self.allowed_parameter_types, return_type) == null) { - return error.IncompatibleTypes; - } - - var has_next_argument = self.first_argument.has_next; - var arguments_remaining = self.expected_parameter_count - 1; - - while (has_next_argument) |next_argument| : ({ - has_next_argument = next_argument.has_next; - arguments_remaining -= 1; - }) { - if (arguments_remaining == 0) { - return error.IncompatibleArguments; - } - - if (try next_argument.expression.inferType() != return_type) { - return error.IncompatibleTypes; - } - } - - if (arguments_remaining != 0) { - return error.IncompatibleArguments; - } - - return return_type; - } - }; - - pub const GetObject = struct { - field: *const Field, - object_expression: *const Expression, - }; - - pub const GetUniform = struct { - field: *const Field, - uniform: *const Uniform, - }; - - pub const Invocation = struct { - function: *const Function, - arguments: ?*const Argument = null, - argument_count: usize = 0, - - pub fn inferType(self: Invocation) TypeError!*const Type { - var parameters = self.function.parameters; - var arguments = self.arguments; - - while (parameters) |parameter| { - const argument = arguments orelse { - return error.IncompatibleArguments; - }; - - defer { - parameters = parameter.has_next; - arguments = argument.has_next; - } - - if (parameter.type != try argument.expression.inferType()) { - return error.IncompatibleTypes; - } - } - - if (arguments != null) { - return error.IncompatibleArguments; - } - - return self.function.has_return_type orelse error.IncompatibleTypes; - } - }; - - pub const OutputMutation = struct { - output: *const Output, - expression: *const Expression, - }; - - pub const LocalMutation = struct { - local: *const Local, - expression: *const Expression, - }; - - pub fn inferType(self: Expression) TypeError!*const Type { - return switch (self) { - .constant => |constant| switch (std.mem.indexOfScalar(u8, constant, '.') == null) { - true => .int, - false => .float, - }, - - .negate_expression, .group_expression => |expression| expression.inferType(), - .abs, .pow, .sin => |generic| generic.inferType(), - .convert => |convert| convert.target_type, - .invoke => |invoke| invoke.inferType(), - .mutate_local => |mutate_local| mutate_local.local.type, - .get_local => |local| local.type, - .get_object => |get_object| get_object.field.type, - .get_parameter => |get_parameter| get_parameter.type, - .sample => |builtin| builtin.inferType(), - .get_uniform => |uniform| uniform.field.type, - .get_input => |input| input.type, - .get_output => |output| output.type, - .mutate_output => |mutate_output| mutate_output.output.type, - - .get_texture => |texture| switch (texture.layout) { - .dimensions_2 => .texture2, - }, - - .add, - .subtract, - .multiply, - .divide, - .equal, - .greater_than, - .greater_equal, - .lesser_than, - .lesser_equal, - => |binary_op| binary_op.type, - }; - } -}; - -pub const Function = struct { - identifier: [:0]const u8, - signature: [:0]const u8, - has_return_type: ?*const Type = null, - parameters: ?*const Parameter = null, - parameter_count: usize = 0, - block: *const Block, -}; - -pub const Input = struct { - identifier: [:0]const u8, - type: *const Type, - location: u8, -}; - -pub const InternError = std.mem.Allocator.Error || error{ - TooManyConstants, -}; - -pub const Output = struct { - identifier: [:0]const u8, - type: *const Type, - location: u8, -}; - -pub const Parameter = struct { - identifier: [:0]const u8, - type: *const Type, - has_next: ?*const Parameter = null, -}; - -pub const ParsingError = std.mem.Allocator.Error || tokens.ExpectationError || DefinitionError || TypeError || InternError || error{ - ImmutableStorage, - UndefinedIdentifier, - MissingReturn, -}; - -pub const Texture = struct { - identifier: [:0]const u8, - binding: u8, - layout: Layout, - - pub const Layout = enum { - dimensions_2, - }; -}; - -pub const Statement = union(enum) { - declare_local: LocalDeclaration, - mutate_local: LocalMutation, - mutate_output: OutputMutation, - return_expression: *const Expression, - - pub const LocalDeclaration = struct { - local: *const Local, - has_next: ?*const Statement = null, - }; - - pub const LocalMutation = struct { - local: *const Local, - expression: *const Expression, - has_next: ?*const Statement = null, - }; - - pub const OutputMutation = struct { - output: *const Output, - expression: *const Expression, - has_next: ?*const Statement = null, - }; -}; - -pub const Local = struct { - identifier: [:0]const u8, - expression: *const Expression, - type: *const Type, - is_constant: bool, -}; - -pub const TypeError = error{ - IncompatibleTypes, - IncompatibleArguments, -}; - -pub const Uniform = struct { - identifier: [:0]const u8, - semantic: [:0]const u8, - binding: u8, - has_field: ?*const Field = null, -}; diff --git a/src/coral/shaders/Field.zig b/src/coral/shaders/Field.zig deleted file mode 100644 index c1e56a4..0000000 --- a/src/coral/shaders/Field.zig +++ /dev/null @@ -1,1782 +0,0 @@ -const coral = @import("../coral.zig"); - -const std = @import("std"); - -identifier: [:0]const u8, -type: *const coral.shaders.Type, -has_next: ?*const Self = null, - -const Self = @This(); - -pub fn fieldsOf(comptime Aggregate: type) ?*const Self { - return switch (@typeInfo(Aggregate)) { - .@"union" => |@"union"| unionFields(@"union".fields), - - .@"struct" => |@"struct"| switch (@"struct".is_tuple) { - false => structFields(@"struct".fields), - true => @compileError("tuple types are unsupported as their fields are unidentifierd"), - }, - - else => @compileError(std.fmt.comptimePrint("non-aggregate types like {s} are unsupported as they do not contain fields", .{ - @typeName(Aggregate), - })), - }; -} - -pub fn has(self: *const Self, identifier: []const u8) ?*const Self { - var field = self; - - while (true) { - if (std.mem.eql(u8, field.identifier, identifier)) { - return field; - } - - field = field.has_next orelse { - return null; - }; - } -} - -fn structFields(comptime fields: []const std.builtin.Type.StructField) ?*const Self { - if (fields.len != 0) { - const field = fields[0]; - - const struct_fields = struct { - const instance = Self{ - .identifier = field.name, - .type = typeOf(field.type), - .has_next = structFields(fields[1..]), - }; - }; - - return &struct_fields.instance; - } - - return null; -} - -pub fn typeOf(comptime FieldType: type) *const coral.shaders.Type { - return switch (FieldType) { - i32 => .int, - f32 => .float, - else => @compileError(std.fmt.comptimePrint("{s} is not a valid field type", .{@typeName(FieldType)})), - }; -} - -fn unionFields(comptime fields: []const std.builtin.Type.UnionField) ?*const Self { - if (fields.len != 0) { - const field = fields[0]; - - const uniform_fields = struct { - const instance = Self{ - .identifier = field.name, - .type = typeOf(field.type), - .has_next = structFields(fields[1..]), - }; - }; - - return &uniform_fields.instance; - } - - return null; -} - -pub const vector_x = &Self{ - .identifier = "x", - .type = .float, -}; - -pub const vector_y = &Self{ - .identifier = "y", - .type = .float, -}; - -pub const vector_z = &Self{ - .identifier = "z", - .type = .float, -}; - -pub const vector_w = &Self{ - .identifier = "z", - .type = .float, -}; - -pub const vector_xx = &Self{ - .identifier = "xx", - .type = .float2, -}; - -pub const vector_xy = &Self{ - .identifier = "xy", - .type = .float2, -}; - -pub const vector_xz = &Self{ - .identifier = "xz", - .type = .float2, -}; - -pub const vector_xw = &Self{ - .identifier = "xz", - .type = .float2, -}; - -pub const vector_yx = &Self{ - .identifier = "yx", - .type = .float2, -}; - -pub const vector_yy = &Self{ - .identifier = "yy", - .type = .float2, -}; - -pub const vector_yz = &Self{ - .identifier = "yz", - .type = .float2, -}; - -pub const vector_yw = &Self{ - .identifier = "yz", - .type = .float2, -}; - -pub const vector_zx = &Self{ - .identifier = "zx", - .type = .float2, -}; - -pub const vector_zy = &Self{ - .identifier = "zy", - .type = .float2, -}; - -pub const vector_zz = &Self{ - .identifier = "zz", - .type = .float2, -}; - -pub const vector_zw = &Self{ - .identifier = "zw", - .type = .float2, -}; - -pub const vector_wx = &Self{ - .identifier = "wx", - .type = .float2, -}; - -pub const vector_wy = &Self{ - .identifier = "wy", - .type = .float2, -}; - -pub const vector_wz = &Self{ - .identifier = "wz", - .type = .float2, -}; - -pub const vector_ww = &Self{ - .identifier = "ww", - .type = .float2, -}; - -pub const vector_xxx = &Self{ - .identifier = "xxx", - .type = .float3, -}; - -pub const vector_xyx = &Self{ - .identifier = "xyx", - .type = .float3, -}; - -pub const vector_xzx = &Self{ - .identifier = "xzx", - .type = .float3, -}; - -pub const vector_xwx = &Self{ - .identifier = "xwx", - .type = .float3, -}; - -pub const vector_yxx = &Self{ - .identifier = "yxx", - .type = .float3, -}; - -pub const vector_yyx = &Self{ - .identifier = "yyx", - .type = .float3, -}; - -pub const vector_yzx = &Self{ - .identifier = "yzx", - .type = .float3, -}; - -pub const vector_ywx = &Self{ - .identifier = "ywx", - .type = .float3, -}; - -pub const vector_zxx = &Self{ - .identifier = "zxx", - .type = .float3, -}; - -pub const vector_zyx = &Self{ - .identifier = "zyx", - .type = .float3, -}; - -pub const vector_zzx = &Self{ - .identifier = "zzx", - .type = .float3, -}; - -pub const vector_zwx = &Self{ - .identifier = "zwx", - .type = .float3, -}; - -pub const vector_wxx = &Self{ - .identifier = "wxx", - .type = .float3, -}; - -pub const vector_wyx = &Self{ - .identifier = "wyy", - .type = .float3, -}; - -pub const vector_wzx = &Self{ - .identifier = "wzx", - .type = .float3, -}; - -pub const vector_wwx = &Self{ - .identifier = "wwx", - .type = .float3, -}; - -pub const vector_xxy = &Self{ - .identifier = "xxy", - .type = .float3, -}; - -pub const vector_xyy = &Self{ - .identifier = "xyy", - .type = .float3, -}; - -pub const vector_xzy = &Self{ - .identifier = "xzy", - .type = .float3, -}; - -pub const vector_xwy = &Self{ - .identifier = "xwy", - .type = .float3, -}; - -pub const vector_yxy = &Self{ - .identifier = "yxy", - .type = .float3, -}; - -pub const vector_yyy = &Self{ - .identifier = "yyy", - .type = .float3, -}; - -pub const vector_yzy = &Self{ - .identifier = "yzy", - .type = .float3, -}; - -pub const vector_ywy = &Self{ - .identifier = "ywy", - .type = .float3, -}; - -pub const vector_zxy = &Self{ - .identifier = "zxy", - .type = .float3, -}; - -pub const vector_zyy = &Self{ - .identifier = "zyy", - .type = .float3, -}; - -pub const vector_zzy = &Self{ - .identifier = "zzy", - .type = .float3, -}; - -pub const vector_zwy = &Self{ - .identifier = "zwy", - .type = .float3, -}; - -pub const vector_wxy = &Self{ - .identifier = "wxy", - .type = .float3, -}; - -pub const vector_wyy = &Self{ - .identifier = "wyy", - .type = .float3, -}; - -pub const vector_wzy = &Self{ - .identifier = "wzy", - .type = .float3, -}; - -pub const vector_wwy = &Self{ - .identifier = "wwy", - .type = .float3, -}; - -pub const vector_xxz = &Self{ - .identifier = "xxz", - .type = .float3, -}; - -pub const vector_xyz = &Self{ - .identifier = "xyz", - .type = .float3, -}; - -pub const vector_xzz = &Self{ - .identifier = "xzz", - .type = .float3, -}; - -pub const vector_xwz = &Self{ - .identifier = "xwz", - .type = .float3, -}; - -pub const vector_yxz = &Self{ - .identifier = "yxz", - .type = .float3, -}; - -pub const vector_yyz = &Self{ - .identifier = "yyz", - .type = .float3, -}; - -pub const vector_yzz = &Self{ - .identifier = "yzz", - .type = .float3, -}; - -pub const vector_ywz = &Self{ - .identifier = "ywz", - .type = .float3, -}; - -pub const vector_zxz = &Self{ - .identifier = "zxz", - .type = .float3, -}; - -pub const vector_zyz = &Self{ - .identifier = "zyz", - .type = .float3, -}; - -pub const vector_zzz = &Self{ - .identifier = "zzz", - .type = .float3, -}; - -pub const vector_zwz = &Self{ - .identifier = "zwz", - .type = .float3, -}; - -pub const vector_wxz = &Self{ - .identifier = "wxz", - .type = .float3, -}; - -pub const vector_wyz = &Self{ - .identifier = "wyz", - .type = .float3, -}; - -pub const vector_wzz = &Self{ - .identifier = "wzz", - .type = .float3, -}; - -pub const vector_wwz = &Self{ - .identifier = "wwz", - .type = .float3, -}; - -pub const vector_xxw = &Self{ - .identifier = "xxw", - .type = .float3, -}; - -pub const vector_xyw = &Self{ - .identifier = "xyw", - .type = .float3, -}; - -pub const vector_xzw = &Self{ - .identifier = "xzw", - .type = .float3, -}; - -pub const vector_xww = &Self{ - .identifier = "xww", - .type = .float3, -}; - -pub const vector_yxw = &Self{ - .identifier = "yxw", - .type = .float3, -}; - -pub const vector_yyw = &Self{ - .identifier = "yyw", - .type = .float3, -}; - -pub const vector_yzw = &Self{ - .identifier = "yzw", - .type = .float3, -}; - -pub const vector_yww = &Self{ - .identifier = "yww", - .type = .float3, -}; - -pub const vector_zxw = &Self{ - .identifier = "zxw", - .type = .float3, -}; - -pub const vector_zyw = &Self{ - .identifier = "zyw", - .type = .float3, -}; - -pub const vector_zzw = &Self{ - .identifier = "zzw", - .type = .float3, -}; - -pub const vector_zww = &Self{ - .identifier = "zww", - .type = .float3, -}; - -pub const vector_wxw = &Self{ - .identifier = "wxw", - .type = .float3, -}; - -pub const vector_wyw = &Self{ - .identifier = "wyw", - .type = .float3, -}; - -pub const vector_wzw = &Self{ - .identifier = "wzw", - .type = .float3, -}; - -pub const vector_www = &Self{ - .identifier = "www", - .type = .float3, -}; - -pub const vector_xxxx = &Self{ - .identifier = "xxxx", - .type = .float4, -}; - -pub const vector_xxxy = &Self{ - .identifier = "xxxy", - .type = .float4, -}; - -pub const vector_xxxz = &Self{ - .identifier = "xxxz", - .type = .float4, -}; - -pub const vector_xxxw = &Self{ - .identifier = "xxxw", - .type = .float4, -}; - -pub const vector_xxyx = &Self{ - .identifier = "xxyx", - .type = .float4, -}; - -pub const vector_xxyy = &Self{ - .identifier = "xxyy", - .type = .float4, -}; - -pub const vector_xxyz = &Self{ - .identifier = "xxyz", - .type = .float4, -}; - -pub const vector_xxyw = &Self{ - .identifier = "xxyw", - .type = .float4, -}; - -pub const vector_xxzx = &Self{ - .identifier = "xxzx", - .type = .float4, -}; - -pub const vector_xxzy = &Self{ - .identifier = "xxzy", - .type = .float4, -}; - -pub const vector_xxzz = &Self{ - .identifier = "xxzz", - .type = .float4, -}; - -pub const vector_xxzw = &Self{ - .identifier = "xxzw", - .type = .float4, -}; - -pub const vector_xxwx = &Self{ - .identifier = "xxwx", - .type = .float4, -}; - -pub const vector_xxwy = &Self{ - .identifier = "xxwy", - .type = .float4, -}; - -pub const vector_xxwz = &Self{ - .identifier = "xxwz", - .type = .float4, -}; - -pub const vector_xxww = &Self{ - .identifier = "xxww", - .type = .float4, -}; - -pub const vector_xyxx = &Self{ - .identifier = "xyxx", - .type = .float4, -}; - -pub const vector_xyxy = &Self{ - .identifier = "xyxy", - .type = .float4, -}; - -pub const vector_xyxz = &Self{ - .identifier = "xyxz", - .type = .float4, -}; - -pub const vector_xyxw = &Self{ - .identifier = "xyxw", - .type = .float4, -}; - -pub const vector_xyyx = &Self{ - .identifier = "xyyx", - .type = .float4, -}; - -pub const vector_xyyy = &Self{ - .identifier = "xyyy", - .type = .float4, -}; - -pub const vector_xyyz = &Self{ - .identifier = "xyyz", - .type = .float4, -}; - -pub const vector_xyyw = &Self{ - .identifier = "xyyw", - .type = .float4, -}; - -pub const vector_xyzx = &Self{ - .identifier = "xyzx", - .type = .float4, -}; - -pub const vector_xyzy = &Self{ - .identifier = "xyzy", - .type = .float4, -}; - -pub const vector_xyzz = &Self{ - .identifier = "xyzz", - .type = .float4, -}; - -pub const vector_xyzw = &Self{ - .identifier = "xyzw", - .type = .float4, -}; - -pub const vector_xywx = &Self{ - .identifier = "xywx", - .type = .float4, -}; - -pub const vector_xywy = &Self{ - .identifier = "xywy", - .type = .float4, -}; - -pub const vector_xywz = &Self{ - .identifier = "xywz", - .type = .float4, -}; - -pub const vector_xyww = &Self{ - .identifier = "xyww", - .type = .float4, -}; - -pub const vector_xzxx = &Self{ - .identifier = "xzxx", - .type = .float4, -}; - -pub const vector_xzxy = &Self{ - .identifier = "xzxy", - .type = .float4, -}; - -pub const vector_xzxz = &Self{ - .identifier = "xzxz", - .type = .float4, -}; - -pub const vector_xzxw = &Self{ - .identifier = "xzxw", - .type = .float4, -}; - -pub const vector_xzyx = &Self{ - .identifier = "xzyx", - .type = .float4, -}; - -pub const vector_xzyy = &Self{ - .identifier = "xzyy", - .type = .float4, -}; - -pub const vector_xzyz = &Self{ - .identifier = "xzyz", - .type = .float4, -}; - -pub const vector_xzyw = &Self{ - .identifier = "xzyw", - .type = .float4, -}; - -pub const vector_xzzx = &Self{ - .identifier = "xzzx", - .type = .float4, -}; - -pub const vector_xzzy = &Self{ - .identifier = "xzzy", - .type = .float4, -}; - -pub const vector_xzzz = &Self{ - .identifier = "xzzz", - .type = .float4, -}; - -pub const vector_xzzw = &Self{ - .identifier = "xzzw", - .type = .float4, -}; - -pub const vector_xzwx = &Self{ - .identifier = "xzwx", - .type = .float4, -}; - -pub const vector_xzwy = &Self{ - .identifier = "xzwy", - .type = .float4, -}; - -pub const vector_xzwz = &Self{ - .identifier = "xzwz", - .type = .float4, -}; - -pub const vector_xzww = &Self{ - .identifier = "xzww", - .type = .float4, -}; - -pub const vector_xwxx = &Self{ - .identifier = "xwxx", - .type = .float4, -}; - -pub const vector_xwxy = &Self{ - .identifier = "xwxy", - .type = .float4, -}; - -pub const vector_xwxz = &Self{ - .identifier = "xwxz", - .type = .float4, -}; - -pub const vector_xwxw = &Self{ - .identifier = "xwxw", - .type = .float4, -}; - -pub const vector_xwyx = &Self{ - .identifier = "xwyx", - .type = .float4, -}; - -pub const vector_xwyy = &Self{ - .identifier = "xwyy", - .type = .float4, -}; - -pub const vector_xwyz = &Self{ - .identifier = "xwyz", - .type = .float4, -}; - -pub const vector_xwyw = &Self{ - .identifier = "xwyw", - .type = .float4, -}; - -pub const vector_xwzx = &Self{ - .identifier = "xwzx", - .type = .float4, -}; - -pub const vector_xwzy = &Self{ - .identifier = "xwzy", - .type = .float4, -}; - -pub const vector_xwzz = &Self{ - .identifier = "xwzz", - .type = .float4, -}; - -pub const vector_xwzw = &Self{ - .identifier = "xwzw", - .type = .float4, -}; - -pub const vector_xwwx = &Self{ - .identifier = "xwwx", - .type = .float4, -}; - -pub const vector_xwwy = &Self{ - .identifier = "xwwy", - .type = .float4, -}; - -pub const vector_xwwz = &Self{ - .identifier = "xwwz", - .type = .float4, -}; - -pub const vector_xwww = &Self{ - .identifier = "xwww", - .type = .float4, -}; - -pub const vector_wxxx = &Self{ - .identifier = "wxxx", - .type = .float4, -}; - -pub const vector_wxxy = &Self{ - .identifier = "wxxy", - .type = .float4, -}; - -pub const vector_wxxz = &Self{ - .identifier = "wxxz", - .type = .float4, -}; - -pub const vector_wxxw = &Self{ - .identifier = "wxxw", - .type = .float4, -}; - -pub const vector_wxyx = &Self{ - .identifier = "wxyx", - .type = .float4, -}; - -pub const vector_wxyy = &Self{ - .identifier = "wxyy", - .type = .float4, -}; - -pub const vector_wxyz = &Self{ - .identifier = "wxyz", - .type = .float4, -}; - -pub const vector_wxyw = &Self{ - .identifier = "wxyw", - .type = .float4, -}; - -pub const vector_wxzx = &Self{ - .identifier = "wxzx", - .type = .float4, -}; - -pub const vector_wxzy = &Self{ - .identifier = "wxzy", - .type = .float4, -}; - -pub const vector_wxzz = &Self{ - .identifier = "wxzz", - .type = .float4, -}; - -pub const vector_wxzw = &Self{ - .identifier = "wxzw", - .type = .float4, -}; - -pub const vector_wxwx = &Self{ - .identifier = "wxwx", - .type = .float4, -}; - -pub const vector_wxwy = &Self{ - .identifier = "wxwy", - .type = .float4, -}; - -pub const vector_wxwz = &Self{ - .identifier = "wxwz", - .type = .float4, -}; - -pub const vector_wxww = &Self{ - .identifier = "wxww", - .type = .float4, -}; - -pub const vector_wyxx = &Self{ - .identifier = "wyxx", - .type = .float4, -}; - -pub const vector_wyxy = &Self{ - .identifier = "wyxy", - .type = .float4, -}; - -pub const vector_wyxz = &Self{ - .identifier = "wyxz", - .type = .float4, -}; - -pub const vector_wyxw = &Self{ - .identifier = "wyxw", - .type = .float4, -}; - -pub const vector_wyyx = &Self{ - .identifier = "wyyx", - .type = .float4, -}; - -pub const vector_wyyy = &Self{ - .identifier = "wyyy", - .type = .float4, -}; - -pub const vector_wyyz = &Self{ - .identifier = "wyyz", - .type = .float4, -}; - -pub const vector_wyyw = &Self{ - .identifier = "wyyw", - .type = .float4, -}; - -pub const vector_wyzx = &Self{ - .identifier = "wyzx", - .type = .float4, -}; - -pub const vector_wyzy = &Self{ - .identifier = "wyzy", - .type = .float4, -}; - -pub const vector_wyzz = &Self{ - .identifier = "wyzz", - .type = .float4, -}; - -pub const vector_wyzw = &Self{ - .identifier = "wyzw", - .type = .float4, -}; - -pub const vector_wywx = &Self{ - .identifier = "wywx", - .type = .float4, -}; - -pub const vector_wywy = &Self{ - .identifier = "wywy", - .type = .float4, -}; - -pub const vector_wywz = &Self{ - .identifier = "wywz", - .type = .float4, -}; - -pub const vector_wyww = &Self{ - .identifier = "wyww", - .type = .float4, -}; - -pub const vector_wzxx = &Self{ - .identifier = "wzxx", - .type = .float4, -}; - -pub const vector_wzxy = &Self{ - .identifier = "wzxy", - .type = .float4, -}; - -pub const vector_wzxz = &Self{ - .identifier = "wzxz", - .type = .float4, -}; - -pub const vector_wzxw = &Self{ - .identifier = "wzxw", - .type = .float4, -}; - -pub const vector_wzyx = &Self{ - .identifier = "wzyx", - .type = .float4, -}; - -pub const vector_wzyy = &Self{ - .identifier = "wzyy", - .type = .float4, -}; - -pub const vector_wzyz = &Self{ - .identifier = "wzyz", - .type = .float4, -}; - -pub const vector_wzyw = &Self{ - .identifier = "wzyw", - .type = .float4, -}; - -pub const vector_wzzx = &Self{ - .identifier = "wzzx", - .type = .float4, -}; - -pub const vector_wzzy = &Self{ - .identifier = "wzzy", - .type = .float4, -}; - -pub const vector_wzzz = &Self{ - .identifier = "wzzz", - .type = .float4, -}; - -pub const vector_wzzw = &Self{ - .identifier = "wzzw", - .type = .float4, -}; - -pub const vector_wzwx = &Self{ - .identifier = "wzwx", - .type = .float4, -}; - -pub const vector_wzwy = &Self{ - .identifier = "wzwy", - .type = .float4, -}; - -pub const vector_wzwz = &Self{ - .identifier = "wzwz", - .type = .float4, -}; - -pub const vector_wzww = &Self{ - .identifier = "wzww", - .type = .float4, -}; - -pub const vector_wwxx = &Self{ - .identifier = "wwxx", - .type = .float4, -}; - -pub const vector_wwxy = &Self{ - .identifier = "wwxy", - .type = .float4, -}; - -pub const vector_wwxz = &Self{ - .identifier = "wwxz", - .type = .float4, -}; - -pub const vector_wwxw = &Self{ - .identifier = "wwxw", - .type = .float4, -}; - -pub const vector_wwyx = &Self{ - .identifier = "wwyx", - .type = .float4, -}; - -pub const vector_wwyy = &Self{ - .identifier = "wwyy", - .type = .float4, -}; - -pub const vector_wwyz = &Self{ - .identifier = "wwyz", - .type = .float4, -}; - -pub const vector_wwyw = &Self{ - .identifier = "wwyw", - .type = .float4, -}; - -pub const vector_wwzx = &Self{ - .identifier = "wwzx", - .type = .float4, -}; - -pub const vector_wwzy = &Self{ - .identifier = "wwzy", - .type = .float4, -}; - -pub const vector_wwzz = &Self{ - .identifier = "wwzz", - .type = .float4, -}; - -pub const vector_wwzw = &Self{ - .identifier = "wwzw", - .type = .float4, -}; - -pub const vector_wwwx = &Self{ - .identifier = "wwwx", - .type = .float4, -}; - -pub const vector_wwwy = &Self{ - .identifier = "wwwy", - .type = .float4, -}; - -pub const vector_wwwz = &Self{ - .identifier = "wwwz", - .type = .float4, -}; - -pub const vector_wwww = &Self{ - .identifier = "wwww", - .type = .float4, -}; - -pub const vector_yxxx = &Self{ - .identifier = "yxxx", - .type = .float4, -}; - -pub const vector_yxxy = &Self{ - .identifier = "yxxy", - .type = .float4, -}; - -pub const vector_yxxz = &Self{ - .identifier = "yxxz", - .type = .float4, -}; - -pub const vector_yxxw = &Self{ - .identifier = "yxxw", - .type = .float4, -}; - -pub const vector_yxyx = &Self{ - .identifier = "yxyx", - .type = .float4, -}; - -pub const vector_yxyy = &Self{ - .identifier = "yxyy", - .type = .float4, -}; - -pub const vector_yxyz = &Self{ - .identifier = "yxyz", - .type = .float4, -}; - -pub const vector_yxyw = &Self{ - .identifier = "yxyw", - .type = .float4, -}; - -pub const vector_yxzx = &Self{ - .identifier = "yxzx", - .type = .float4, -}; - -pub const vector_yxzy = &Self{ - .identifier = "yxzy", - .type = .float4, -}; - -pub const vector_yxzz = &Self{ - .identifier = "yxzz", - .type = .float4, -}; - -pub const vector_yxzw = &Self{ - .identifier = "yxzw", - .type = .float4, -}; - -pub const vector_yxwx = &Self{ - .identifier = "yxwx", - .type = .float4, -}; - -pub const vector_yxwy = &Self{ - .identifier = "yxwy", - .type = .float4, -}; - -pub const vector_yxwz = &Self{ - .identifier = "yxwz", - .type = .float4, -}; - -pub const vector_yxww = &Self{ - .identifier = "yxww", - .type = .float4, -}; - -pub const vector_yyxx = &Self{ - .identifier = "yyxx", - .type = .float4, -}; - -pub const vector_yyxy = &Self{ - .identifier = "yyxy", - .type = .float4, -}; - -pub const vector_yyxz = &Self{ - .identifier = "yyxz", - .type = .float4, -}; - -pub const vector_yyxw = &Self{ - .identifier = "yyxw", - .type = .float4, -}; - -pub const vector_yyyx = &Self{ - .identifier = "yyyx", - .type = .float4, -}; - -pub const vector_yyyy = &Self{ - .identifier = "yyyy", - .type = .float4, -}; - -pub const vector_yyyz = &Self{ - .identifier = "yyyz", - .type = .float4, -}; - -pub const vector_yyyw = &Self{ - .identifier = "yyyw", - .type = .float4, -}; - -pub const vector_yyzx = &Self{ - .identifier = "yyzx", - .type = .float4, -}; - -pub const vector_yyzy = &Self{ - .identifier = "yyzy", - .type = .float4, -}; - -pub const vector_yyzz = &Self{ - .identifier = "yyzz", - .type = .float4, -}; - -pub const vector_yyzw = &Self{ - .identifier = "yyzw", - .type = .float4, -}; - -pub const vector_yywx = &Self{ - .identifier = "yywx", - .type = .float4, -}; - -pub const vector_yywy = &Self{ - .identifier = "yywy", - .type = .float4, -}; - -pub const vector_yywz = &Self{ - .identifier = "yywz", - .type = .float4, -}; - -pub const vector_yyww = &Self{ - .identifier = "yyww", - .type = .float4, -}; - -pub const vector_yzxx = &Self{ - .identifier = "yzxx", - .type = .float4, -}; - -pub const vector_yzxy = &Self{ - .identifier = "yzxy", - .type = .float4, -}; - -pub const vector_yzxz = &Self{ - .identifier = "yzxz", - .type = .float4, -}; - -pub const vector_yzxw = &Self{ - .identifier = "yzxw", - .type = .float4, -}; - -pub const vector_yzyx = &Self{ - .identifier = "yzyx", - .type = .float4, -}; - -pub const vector_yzyy = &Self{ - .identifier = "yzyy", - .type = .float4, -}; - -pub const vector_yzyz = &Self{ - .identifier = "yzyz", - .type = .float4, -}; - -pub const vector_yzyw = &Self{ - .identifier = "yzyw", - .type = .float4, -}; - -pub const vector_yzzx = &Self{ - .identifier = "yzzx", - .type = .float4, -}; - -pub const vector_yzzy = &Self{ - .identifier = "yzzy", - .type = .float4, -}; - -pub const vector_yzzz = &Self{ - .identifier = "yzzz", - .type = .float4, -}; - -pub const vector_yzzw = &Self{ - .identifier = "yzzw", - .type = .float4, -}; - -pub const vector_yzwx = &Self{ - .identifier = "yzwx", - .type = .float4, -}; - -pub const vector_yzwy = &Self{ - .identifier = "yzwy", - .type = .float4, -}; - -pub const vector_yzwz = &Self{ - .identifier = "yzwz", - .type = .float4, -}; - -pub const vector_yzww = &Self{ - .identifier = "yzww", - .type = .float4, -}; - -pub const vector_ywxx = &Self{ - .identifier = "ywxx", - .type = .float4, -}; - -pub const vector_ywxy = &Self{ - .identifier = "ywxy", - .type = .float4, -}; - -pub const vector_ywxz = &Self{ - .identifier = "ywxz", - .type = .float4, -}; - -pub const vector_ywxw = &Self{ - .identifier = "ywxw", - .type = .float4, -}; - -pub const vector_ywyx = &Self{ - .identifier = "ywyx", - .type = .float4, -}; - -pub const vector_ywyy = &Self{ - .identifier = "ywyy", - .type = .float4, -}; - -pub const vector_ywyz = &Self{ - .identifier = "ywyz", - .type = .float4, -}; - -pub const vector_ywyw = &Self{ - .identifier = "ywyw", - .type = .float4, -}; - -pub const vector_ywzx = &Self{ - .identifier = "ywzx", - .type = .float4, -}; - -pub const vector_ywzy = &Self{ - .identifier = "ywzy", - .type = .float4, -}; - -pub const vector_ywzz = &Self{ - .identifier = "ywzz", - .type = .float4, -}; - -pub const vector_ywzw = &Self{ - .identifier = "ywzw", - .type = .float4, -}; - -pub const vector_ywwx = &Self{ - .identifier = "ywwx", - .type = .float4, -}; - -pub const vector_ywwy = &Self{ - .identifier = "ywwy", - .type = .float4, -}; - -pub const vector_ywwz = &Self{ - .identifier = "ywwz", - .type = .float4, -}; - -pub const vector_ywww = &Self{ - .identifier = "ywww", - .type = .float4, -}; - -pub const vector_zxxx = &Self{ - .identifier = "zxxx", - .type = .float4, -}; - -pub const vector_zxxy = &Self{ - .identifier = "zxxy", - .type = .float4, -}; - -pub const vector_zxxz = &Self{ - .identifier = "zxxz", - .type = .float4, -}; - -pub const vector_zxxw = &Self{ - .identifier = "zxxw", - .type = .float4, -}; - -pub const vector_zxyx = &Self{ - .identifier = "zxyx", - .type = .float4, -}; - -pub const vector_zxyy = &Self{ - .identifier = "zxyy", - .type = .float4, -}; - -pub const vector_zxyz = &Self{ - .identifier = "zxyz", - .type = .float4, -}; - -pub const vector_zxyw = &Self{ - .identifier = "zxyw", - .type = .float4, -}; - -pub const vector_zxzx = &Self{ - .identifier = "zxzx", - .type = .float4, -}; - -pub const vector_zxzy = &Self{ - .identifier = "zxzy", - .type = .float4, -}; - -pub const vector_zxzz = &Self{ - .identifier = "zxzz", - .type = .float4, -}; - -pub const vector_zxzw = &Self{ - .identifier = "zxzw", - .type = .float4, -}; - -pub const vector_zxwx = &Self{ - .identifier = "zxwx", - .type = .float4, -}; - -pub const vector_zxwy = &Self{ - .identifier = "zxwy", - .type = .float4, -}; - -pub const vector_zxwz = &Self{ - .identifier = "zxwz", - .type = .float4, -}; - -pub const vector_zxww = &Self{ - .identifier = "zxww", - .type = .float4, -}; - -pub const vector_zyxx = &Self{ - .identifier = "zyxx", - .type = .float4, -}; - -pub const vector_zyxy = &Self{ - .identifier = "zyxy", - .type = .float4, -}; - -pub const vector_zyxz = &Self{ - .identifier = "zyxz", - .type = .float4, -}; - -pub const vector_zyxw = &Self{ - .identifier = "zyxw", - .type = .float4, -}; - -pub const vector_zyyx = &Self{ - .identifier = "zyyx", - .type = .float4, -}; - -pub const vector_zyyy = &Self{ - .identifier = "zyyy", - .type = .float4, -}; - -pub const vector_zyyz = &Self{ - .identifier = "zyyz", - .type = .float4, -}; - -pub const vector_zyyw = &Self{ - .identifier = "zyyw", - .type = .float4, -}; - -pub const vector_zyzx = &Self{ - .identifier = "zyzx", - .type = .float4, -}; - -pub const vector_zyzy = &Self{ - .identifier = "zyzy", - .type = .float4, -}; - -pub const vector_zyzz = &Self{ - .identifier = "zyzz", - .type = .float4, -}; - -pub const vector_zyzw = &Self{ - .identifier = "zyzw", - .type = .float4, -}; - -pub const vector_zywx = &Self{ - .identifier = "zywx", - .type = .float4, -}; - -pub const vector_zywy = &Self{ - .identifier = "zywy", - .type = .float4, -}; - -pub const vector_zywz = &Self{ - .identifier = "zywz", - .type = .float4, -}; - -pub const vector_zyww = &Self{ - .identifier = "zyww", - .type = .float4, -}; - -pub const vector_zzxx = &Self{ - .identifier = "zzxx", - .type = .float4, -}; - -pub const vector_zzxy = &Self{ - .identifier = "zzxy", - .type = .float4, -}; - -pub const vector_zzxz = &Self{ - .identifier = "zzxz", - .type = .float4, -}; - -pub const vector_zzxw = &Self{ - .identifier = "zzxw", - .type = .float4, -}; - -pub const vector_zzyx = &Self{ - .identifier = "zzyx", - .type = .float4, -}; - -pub const vector_zzyy = &Self{ - .identifier = "zzyy", - .type = .float4, -}; - -pub const vector_zzyz = &Self{ - .identifier = "zzyz", - .type = .float4, -}; - -pub const vector_zzyw = &Self{ - .identifier = "zzyw", - .type = .float4, -}; - -pub const vector_zzzx = &Self{ - .identifier = "zzzx", - .type = .float4, -}; - -pub const vector_zzzy = &Self{ - .identifier = "zzzy", - .type = .float4, -}; - -pub const vector_zzzz = &Self{ - .identifier = "zzzz", - .type = .float4, -}; - -pub const vector_zzzw = &Self{ - .identifier = "zzzw", - .type = .float4, -}; - -pub const vector_zzwx = &Self{ - .identifier = "zzwx", - .type = .float4, -}; - -pub const vector_zzwy = &Self{ - .identifier = "zzwy", - .type = .float4, -}; - -pub const vector_zzwz = &Self{ - .identifier = "zzwz", - .type = .float4, -}; - -pub const vector_zzww = &Self{ - .identifier = "zzww", - .type = .float4, -}; - -pub const vector_zwxx = &Self{ - .identifier = "zwxx", - .type = .float4, -}; - -pub const vector_zwxy = &Self{ - .identifier = "zwxy", - .type = .float4, -}; - -pub const vector_zwxz = &Self{ - .identifier = "zwxz", - .type = .float4, -}; - -pub const vector_zwxw = &Self{ - .identifier = "zwxw", - .type = .float4, -}; - -pub const vector_zwyx = &Self{ - .identifier = "zwyx", - .type = .float4, -}; - -pub const vector_zwyy = &Self{ - .identifier = "zwyy", - .type = .float4, -}; - -pub const vector_zwyz = &Self{ - .identifier = "zwyz", - .type = .float4, -}; - -pub const vector_zwyw = &Self{ - .identifier = "zwyw", - .type = .float4, -}; - -pub const vector_zwzx = &Self{ - .identifier = "zwzx", - .type = .float4, -}; - -pub const vector_zwzy = &Self{ - .identifier = "zwzy", - .type = .float4, -}; - -pub const vector_zwzz = &Self{ - .identifier = "zwzz", - .type = .float4, -}; - -pub const vector_zwzw = &Self{ - .identifier = "zwzw", - .type = .float4, -}; - -pub const vector_zwwx = &Self{ - .identifier = "zwwx", - .type = .float4, -}; - -pub const vector_zwwy = &Self{ - .identifier = "zwwy", - .type = .float4, -}; - -pub const vector_zwwz = &Self{ - .identifier = "zwwz", - .type = .float4, -}; - -pub const vector_zwww = &Self{ - .identifier = "zwww", - .type = .float4, -}; diff --git a/src/coral/shaders/Root.zig b/src/coral/shaders/Root.zig deleted file mode 100644 index 60ea92f..0000000 --- a/src/coral/shaders/Root.zig +++ /dev/null @@ -1,266 +0,0 @@ -const coral = @import("../coral.zig"); - -const spirv = @import("./spirv.zig"); - -const std = @import("std"); - -const tokens = @import("./tokens.zig"); - -scope: *coral.shaders.Scope, -inputs: std.BoundedArray(*const coral.shaders.Input, 15) = .{}, -outputs: std.BoundedArray(*const coral.shaders.Output, 15) = .{}, -uniforms: std.BoundedArray(*const coral.shaders.Uniform, 15) = .{}, -textures: std.BoundedArray(*const coral.shaders.Texture, 15) = .{}, -functions: std.BoundedArray(*const coral.shaders.Function, max_functions) = .{}, - -pub const BuildError = spirv.BuildError || error{ - InvalidEntryPoint, -}; - -pub const ParseResult = union(enum) { - ok, - failure: [:0]const u8, -}; - -const Self = @This(); - -pub fn buildSpirvFragment(self: *Self, arena: *std.heap.ArenaAllocator, identifier: []const u8) BuildError!spirv.Module { - var module = spirv.Module{ - .capabilities = &.{.shader}, - .memory_model = .{ .logical, .glsl450 }, - }; - - _ = try module.shaderEntryPoint(arena, .fragment, self.hasFunction(identifier) orelse { - return error.InvalidEntryPoint; - }); - - return module; -} - -pub fn clear(self: *Self) void { - self.scope.clear(); - self.inputs.clear(); - self.outputs.clear(); - self.uniforms.clear(); - self.textures.clear(); - self.functions.clear(); -} - -pub fn defineFunction(self: *Self, arena: *std.heap.ArenaAllocator, function: coral.shaders.Function) coral.shaders.DefinitionError!void { - self.functions.append(try self.scope.define(arena, function)) catch |append_error| { - return switch (append_error) { - error.Overflow => error.TooManySymbols, - }; - }; -} - -pub fn defineInput(self: *Self, arena: *std.heap.ArenaAllocator, input: coral.shaders.Input) coral.shaders.DefinitionError!void { - self.inputs.append(try self.scope.define(arena, input)) catch |append_error| { - return switch (append_error) { - error.Overflow => error.TooManySymbols, - }; - }; -} - -pub fn defineOutput(self: *Self, arena: *std.heap.ArenaAllocator, output: coral.shaders.Output) coral.shaders.DefinitionError!void { - self.outputs.append(try self.scope.define(arena, output)) catch |append_error| { - return switch (append_error) { - error.Overflow => error.TooManySymbols, - }; - }; -} - -pub fn defineTexture(self: *Self, arena: *std.heap.ArenaAllocator, texture: coral.shaders.Texture) coral.shaders.DefinitionError!void { - self.textures.append(try self.scope.define(arena, texture)) catch |append_error| { - return switch (append_error) { - error.Overflow => error.TooManySymbols, - }; - }; -} - -pub fn defineUniform(self: *Self, arena: *std.heap.ArenaAllocator, uniform: coral.shaders.Uniform) coral.shaders.DefinitionError!void { - self.uniforms.append(try self.scope.define(arena, uniform)) catch |append_error| { - return switch (append_error) { - error.Overflow => error.TooManySymbols, - }; - }; -} - -pub fn hasFunction(self: Self, identifier: []const u8) ?*const coral.shaders.Function { - return self.scope.hasLocal(coral.shaders.Function, identifier); -} - -pub fn hasInput(self: Self, identifier: []const u8) ?*const coral.shaders.Input { - return self.scope.hasLocal(coral.shaders.Input, identifier); -} - -pub fn hasOutput(self: Self, identifier: []const u8) ?*const coral.shaders.Output { - return self.scope.hasLocal(coral.shaders.Output, identifier); -} - -pub fn hasTexture(self: Self, identifier: []const u8) ?*const coral.shaders.Texture { - return self.scope.hasLocal(coral.shaders.Texture, identifier); -} - -pub fn hasUniform(self: Self, identifier: []const u8) ?*const coral.shaders.Uniform { - return self.scope.hasLocal(coral.shaders.Uniform, identifier); -} - -pub fn init(arena: *std.heap.ArenaAllocator) std.mem.Allocator.Error!Self { - const scope = try arena.allocator().create(coral.shaders.Scope); - - scope.* = .{}; - - return .{ .scope = scope }; -} - -const max_functions = 255; - -pub fn parse(self: *Self, arena: *std.heap.ArenaAllocator, source_text: []const u8) std.mem.Allocator.Error!ParseResult { - errdefer { - self.clear(); - } - - var source = tokens.Stream.init(source_text); - - self.parseDocument(arena, &source) catch |parse_error| { - const arena_allocator = arena.allocator(); - - return .{ - .failure = try switch (parse_error) { - error.OutOfMemory => error.OutOfMemory, - - error.TooManyConstants => coral.bytes.allocFormatted(arena_allocator, "{location}: number of literals in the current scope exceeded", .{ - .location = source.location, - }), - - error.ImmutableStorage => coral.bytes.allocFormatted(arena_allocator, "{location}: attempt to modify an immutable value", .{ - .location = source.location, - }), - - error.TooManySymbols => coral.bytes.allocFormatted(arena_allocator, "{location}: number of definitions in the current scope exceeded", .{ - .location = source.location, - }), - - error.IncompatibleArguments => coral.bytes.allocFormatted(arena_allocator, "{location}: incompatible set of arguments", .{ - .location = source.location, - }), - - error.IncompatibleTypes => coral.bytes.allocFormatted(arena_allocator, "{location}: incompatible types", .{ - .location = source.location, - }), - - error.DuplicateIdentifier => coral.bytes.allocFormatted(arena_allocator, "{location}: {kind} {token} already defined", .{ - .location = source.location, - .token = source.current, - .kind = std.meta.activeTag(source.current), - }), - - error.UnexpectedToken => coral.bytes.allocFormatted(arena_allocator, "{location}: unexpected {token}", .{ - .location = source.location, - .token = source.current, - }), - - error.UndefinedIdentifier => coral.bytes.allocFormatted(arena_allocator, "{location}: undefined identifier {token}", .{ - .location = source.location, - .token = source.current, - }), - - error.MissingReturn => coral.bytes.allocFormatted(arena_allocator, "{location}: value-returning function does not return at end", .{ - .location = source.location, - }), - }, - }; - }; - - return .ok; -} - -fn parseDocument(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!void { - while (source.skip(.newline) != .end) { - try switch (try source.current.expectAny(&.{.keyword_function})) { - .keyword_function => self.parseFunction(arena, source), - }; - } -} - -fn parseFunction(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!void { - const identifier = try arena.allocator().dupeZ(u8, try source.skip(.newline).expectIdentifier()); - - try source.skip(.newline).expect(.symbol_paren_left); - - const inner_scope = try self.scope.createScope(arena); - - const parameters = switch (try source.skip(.newline).expectAny(&.{ .symbol_paren_right, .identifier })) { - .identifier => try inner_scope.parseParameter(arena, source), - .symbol_paren_right => null, - }; - - const parameter_count = inner_scope.defined; - - try source.skip(.newline).expect(.symbol_arrow); - - var peeking = source.*; - const has_return_type = if (peeking.skip(.newline) == .symbol_brace_left) null else try self.scope.parseType(source); - const block = try inner_scope.parseBlock(arena, source); - - if (has_return_type) |return_type| { - const last_statement = block.hasLastStatement() orelse { - return error.MissingReturn; - }; - - if (last_statement.* != .return_expression) { - return error.MissingReturn; - } - - if (try last_statement.return_expression.inferType() != return_type) { - return error.IncompatibleTypes; - } - } - - try self.defineFunction(arena, .{ - .has_return_type = has_return_type, - .parameters = parameters, - .parameter_count = parameter_count, - .identifier = identifier, - .block = block, - .signature = try self.scope.intern(arena, try signature(arena, parameters, has_return_type)), - }); -} - -fn signature(arena: *std.heap.ArenaAllocator, parameters: ?*const coral.shaders.Parameter, has_return_type: ?*const coral.shaders.Type) std.mem.Allocator.Error![:0]const u8 { - var buffer_size = 2 + (if (has_return_type) |return_type| return_type.identifier.len else 0); - - if (parameters) |first_parameter| { - buffer_size += first_parameter.type.identifier.len; - - var has_parameter = first_parameter.has_next; - - while (has_parameter) |parameter| : (has_parameter = parameter.has_next) { - buffer_size += 1 + parameter.type.identifier.len; - } - } - - var buffer = coral.bytes.span(try arena.allocator().allocSentinel(u8, buffer_size, 0)); - - std.debug.assert(buffer.put('(')); - - if (parameters) |first_parameter| { - std.debug.assert(buffer.write(first_parameter.type.identifier) == first_parameter.type.identifier.len); - - var has_parameter = first_parameter.has_next; - - while (has_parameter) |parameter| : (has_parameter = parameter.has_next) { - std.debug.assert(buffer.put(',')); - std.debug.assert(buffer.write(parameter.type.identifier) == parameter.type.identifier.len); - } - } - - std.debug.assert(buffer.put(')')); - - if (has_return_type) |return_type| { - std.debug.assert(buffer.write(return_type.identifier) == return_type.identifier.len); - } - - return @ptrCast(buffer.bytes); -} diff --git a/src/coral/shaders/Scope.zig b/src/coral/shaders/Scope.zig deleted file mode 100644 index e7d7321..0000000 --- a/src/coral/shaders/Scope.zig +++ /dev/null @@ -1,747 +0,0 @@ -const coral = @import("../coral.zig"); - -const std = @import("std"); - -const tokens = @import("./tokens.zig"); - -interned: coral.tree.Binary([:0]const u8, void, coral.tree.sliceTraits([:0]const u8)) = .empty, -identifiers: [max_definitions][:0]const u8 = undefined, -symbols: [max_definitions]coral.Box = undefined, -defined: usize = 0, -has_enclosing: ?*Self = null, - -const Self = @This(); - -pub fn clear(self: *Self) void { - self.defined = 0; - - if (self.has_enclosing) |enclosing| { - enclosing.clear(); - } -} - -fn create(arena: *std.heap.ArenaAllocator, node: anytype) std.mem.Allocator.Error!*@TypeOf(node) { - const allocation = try arena.allocator().create(@TypeOf(node)); - - allocation.* = node; - - return allocation; -} - -pub fn createScope(self: *Self, arena: *std.heap.ArenaAllocator) std.mem.Allocator.Error!*Self { - return create(arena, Self{ - .has_enclosing = self, - }); -} - -pub fn define(self: *Self, arena: *std.heap.ArenaAllocator, symbol: anytype) coral.shaders.DefinitionError!*@TypeOf(symbol) { - const Symbol = @TypeOf(symbol); - const identifier_field = "identifier"; - const Identifier = [:0]const u8; - - const identifier = switch (@hasField(Symbol, identifier_field)) { - true => switch (@TypeOf(symbol.identifier)) { - Identifier => symbol.identifier, - - else => @compileError(std.fmt.comptimePrint("field {s}.{s} must be of type `{s}`", .{ - @typeName(Symbol), - identifier_field, - @typeName(Identifier), - })), - }, - - false => @compileError(std.fmt.comptimePrint("Type `{s}` must contain a field identifierd `{s}`", .{ - @typeName(Symbol), - identifier_field, - })), - }; - - if (self.definitionExists(identifier)) { - return error.DuplicateIdentifier; - } - - if (self.defined >= max_definitions) { - return error.TooManySymbols; - } - - const stored_symbol = &self.symbols[self.defined]; - - self.identifiers[self.defined] = identifier; - stored_symbol.* = try .initWithAllocator(arena.allocator(), symbol); - self.defined += 1; - - return stored_symbol.has(Symbol).?; -} - -fn definitionExists(self: Self, identifier: []const u8) bool { - for (self.identifiers[0..self.defined]) |existing_identifier| { - if (std.mem.eql(u8, existing_identifier, identifier)) { - return true; - } - } - - if (self.has_enclosing) |enclosing| { - return enclosing.definitionExists(identifier); - } - - return false; -} - -pub fn hasGlobal(self: *const Self, comptime Symbol: type, identifier: []const u8) ?*const Symbol { - if (self.hasLocal(Symbol, identifier)) |local| { - return local; - } - - if (self.has_enclosing) |enclosing| { - return enclosing.hasGlobal(Symbol, identifier); - } - - return null; -} - -pub fn hasLocal(self: *const Self, comptime Symbol: type, identifier: []const u8) ?*const Symbol { - for (0..self.defined) |i| { - if (std.mem.eql(u8, self.identifiers[i], identifier)) { - if (self.symbols[i].has(Symbol)) |symbol| { - return symbol; - } - } - } - - return null; -} - -pub fn intern(self: *Self, arena: *std.heap.ArenaAllocator, value: [:0]const u8) std.mem.Allocator.Error![:0]const u8 { - var scope: ?*Self = self; - - while (scope) |current| : (scope = current.has_enclosing) { - if (current.interned.getKey(value)) |existing| { - return existing; - } - } - - std.debug.assert(try self.interned.insert(arena.allocator(), value, {}) != null); - - return value; -} - -const max_definitions = 256; - -fn parseArgument(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Argument { - const expression = try self.parseExpression(arena, source); - - return switch (try source.current.expectAny(&.{ .symbol_paren_right, .symbol_comma })) { - .symbol_paren_right => try create(arena, coral.shaders.Argument{ - .expression = expression, - }), - - .symbol_comma => { - var peeking = source.*; - - if (peeking.skip(.newline) == .symbol_paren_right) { - source.* = peeking; - - return try create(arena, coral.shaders.Argument{ .expression = expression }); - } - - return try create(arena, coral.shaders.Argument{ - .expression = expression, - .has_next = try self.parseArgument(arena, source), - }); - }, - }; -} - -pub fn parseBlock(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Block { - try source.skip(.newline).expect(.symbol_brace_left); - - return create(arena, coral.shaders.Block{ - .scope = self, - .depth = source.depth, - - .statements = switch (source.skip(.newline)) { - .symbol_brace_right => null, - else => try self.parseBlockStatement(arena, source), - }, - }); -} - -fn parseBlockStatement(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Statement { - switch (try source.current.expectAny(&.{ .keyword_let, .keyword_var, .keyword_return, .identifier })) { - .identifier => { - const identifier = try source.current.expectIdentifier(); - - if (self.hasLocal(coral.shaders.Local, identifier)) |local| { - if (local.is_constant) { - return error.ImmutableStorage; - } - - try source.skip(.newline).expect(.symbol_equals); - - const expression = try self.parseExpression(arena, source); - - if (try expression.inferType() != local.type) { - return error.IncompatibleTypes; - } - - return try create(arena, coral.shaders.Statement{ - .mutate_local = .{ - .local = local, - .expression = expression, - - .has_next = switch (source.current) { - .symbol_brace_right => null, - else => try self.parseBlockStatement(arena, source), - }, - }, - }); - } - - if (self.hasGlobal(coral.shaders.Output, identifier)) |output| { - try source.skip(.newline).expect(.symbol_equals); - - const expression = try self.parseExpression(arena, source); - - if (try expression.inferType() != output.type) { - return error.IncompatibleTypes; - } - - return try create(arena, coral.shaders.Statement{ - .mutate_output = .{ - .output = output, - .expression = expression, - - .has_next = switch (source.current) { - .symbol_brace_right => null, - else => try self.parseBlockStatement(arena, source), - }, - }, - }); - } - - return error.ImmutableStorage; - }, - - .keyword_return => { - return try create(arena, coral.shaders.Statement{ - .return_expression = try self.parseExpression(arena, source), - }); - }, - - .keyword_var, .keyword_let => { - const local = try self.define(arena, coral.shaders.Local{ - .is_constant = source.current != .keyword_var, - .identifier = try arena.allocator().dupeZ(u8, try source.next().expectIdentifier()), - .expression = &.{ .constant = try self.intern(arena, "0") }, - .type = .int, - }); - - try source.skip(.newline).expect(.symbol_equals); - - local.expression = try self.parseExpression(arena, source); - local.type = try local.expression.inferType(); - - return try create(arena, coral.shaders.Statement{ - .declare_local = .{ - .local = local, - - .has_next = try switch (source.current) { - .symbol_brace_right => null, - else => self.parseBlockStatement(arena, source), - }, - }, - }); - }, - } -} - -fn parseExpression(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Expression { - const expression = try self.parseAdditiveExpression(arena, source); - - if (source.current == .symbol_equals) { - return switch (expression.*) { - .get_local => |local| switch (local.is_constant) { - false => try create(arena, coral.shaders.Expression{ - .mutate_local = .{ - .local = local, - .expression = try self.parseExpression(arena, source), - }, - }), - - true => error.ImmutableStorage, - }, - - else => error.UnexpectedToken, - }; - } - - return expression; -} - -fn parseAdditiveExpression(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Expression { - const lhs_expression = try self.parseEqualityExpression(arena, source); - - if (source.current == .symbol_plus) { - const rhs_expression = try self.parseEqualityExpression(arena, source); - const lhs_type = try lhs_expression.inferType(); - - if (lhs_type != try rhs_expression.inferType()) { - return error.IncompatibleTypes; - } - - return create(arena, coral.shaders.Expression{ - .add = .{ - .rhs_expression = rhs_expression, - .lhs_expression = lhs_expression, - .type = lhs_type, - }, - }); - } - - if (source.current == .symbol_minus) { - const rhs_expression = try self.parseEqualityExpression(arena, source); - const lhs_type = try lhs_expression.inferType(); - - if (lhs_type != try rhs_expression.inferType()) { - return error.IncompatibleTypes; - } - - return create(arena, coral.shaders.Expression{ - .subtract = .{ - .rhs_expression = rhs_expression, - .lhs_expression = lhs_expression, - .type = lhs_type, - }, - }); - } - - return lhs_expression; -} - -fn parseComparativeExpression(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Expression { - const lhs_expression = try self.parseTermExpression(arena, source); - - if (source.current == .symbol_greater_than) { - const rhs_expression = try self.parseTermExpression(arena, source); - const lhs_type = try lhs_expression.inferType(); - - if (lhs_type != try rhs_expression.inferType()) { - return error.IncompatibleTypes; - } - - return create(arena, coral.shaders.Expression{ - .greater_than = .{ - .rhs_expression = rhs_expression, - .lhs_expression = lhs_expression, - .type = lhs_type, - }, - }); - } - - if (source.current == .symbol_greater_equals) { - const rhs_expression = try self.parseTermExpression(arena, source); - const lhs_type = try lhs_expression.inferType(); - - if (lhs_type != try rhs_expression.inferType()) { - return error.IncompatibleTypes; - } - - return create(arena, coral.shaders.Expression{ - .greater_equal = .{ - .rhs_expression = rhs_expression, - .lhs_expression = lhs_expression, - .type = lhs_type, - }, - }); - } - - if (source.current == .symbol_lesser_than) { - const rhs_expression = try self.parseTermExpression(arena, source); - const lhs_type = try lhs_expression.inferType(); - - if (lhs_type != try rhs_expression.inferType()) { - return error.IncompatibleTypes; - } - - return create(arena, coral.shaders.Expression{ - .divide = .{ - .rhs_expression = rhs_expression, - .lhs_expression = lhs_expression, - .type = lhs_type, - }, - }); - } - - if (source.current == .symbol_lesser_equals) { - const rhs_expression = try self.parseTermExpression(arena, source); - const lhs_type = try lhs_expression.inferType(); - - if (lhs_type != try rhs_expression.inferType()) { - return error.IncompatibleTypes; - } - - return create(arena, coral.shaders.Expression{ - .divide = .{ - .rhs_expression = rhs_expression, - .lhs_expression = lhs_expression, - .type = lhs_type, - }, - }); - } - - return lhs_expression; -} - -fn parseEqualityExpression(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Expression { - const lhs_expression = try self.parseComparativeExpression(arena, source); - - if (source.current == .symbol_double_equals) { - const rhs_expression = try self.parseComparativeExpression(arena, source); - const lhs_type = try lhs_expression.inferType(); - - if (lhs_type != try rhs_expression.inferType()) { - return error.IncompatibleTypes; - } - - return create(arena, coral.shaders.Expression{ - .equal = .{ - .rhs_expression = rhs_expression, - .lhs_expression = lhs_expression, - .type = lhs_type, - }, - }); - } - - return lhs_expression; -} - -fn parseFactorExpression(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Expression { - var expression = try self.parseOperandExpression(arena, source); - - while (true) { - switch (source.skip(.newline)) { - .symbol_period => { - const object_type = try expression.inferType(); - - expression = try create(arena, coral.shaders.Expression{ - .get_object = .{ - .object_expression = expression, - - .field = object_type.hasField(try source.skip(.newline).expectIdentifier()) orelse { - return error.UndefinedIdentifier; - }, - }, - }); - }, - - else => { - return expression; - }, - } - } -} - -fn parseOperandExpression(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Expression { - switch (source.skip(.newline)) { - .symbol_minus => { - return try create(arena, coral.shaders.Expression{ - .negate_expression = try self.parseExpression(arena, source), - }); - }, - - .symbol_paren_left => { - return try create(arena, coral.shaders.Expression{ - .group_expression = try self.parseExpression(arena, source), - }); - }, - - .scalar => { - return try create(arena, coral.shaders.Expression{ - .constant = try arena.allocator().dupeZ(u8, try source.current.expectScalar()), - }); - }, - - .identifier => |identifier| { - if (self.hasGlobal(coral.shaders.Function, identifier)) |function| { - try source.skip(.newline).expect(.symbol_paren_left); - - var peeking = source.*; - - switch (peeking.skip(.newline)) { - .symbol_paren_left => { - source.* = peeking; - - return try create(arena, coral.shaders.Expression{ - .invoke = .{ - .function = function, - }, - }); - }, - - else => { - const arguments = try self.parseArgument(arena, source); - var argument_count: usize = 1; - - { - var subsequent_arguments = arguments.has_next; - - while (subsequent_arguments) |argument| : (subsequent_arguments = argument.has_next) { - argument_count += 1; - } - } - - return try create(arena, coral.shaders.Expression{ - .invoke = .{ - .function = function, - .argument_count = argument_count, - .arguments = arguments, - }, - }); - }, - } - } - - if (self.hasGlobal(coral.shaders.Uniform, identifier)) |uniform| { - try source.skip(.newline).expect(.symbol_period); - - const field_name = try source.skip(.newline).expectIdentifier(); - - const first_field = uniform.has_field orelse { - return error.UndefinedIdentifier; - }; - - return try create(arena, coral.shaders.Expression{ - .get_uniform = .{ - .uniform = uniform, - - .field = first_field.has(field_name) orelse { - return error.UndefinedIdentifier; - }, - }, - }); - } - - if (self.hasGlobal(coral.shaders.Texture, identifier)) |texture| { - return try create(arena, coral.shaders.Expression{ .get_texture = texture }); - } - - if (self.hasGlobal(coral.shaders.Output, identifier)) |output| { - return try create(arena, coral.shaders.Expression{ .get_output = output }); - } - - if (self.hasGlobal(coral.shaders.Input, identifier)) |input| { - return try create(arena, coral.shaders.Expression{ .get_input = input }); - } - - if (self.hasLocal(coral.shaders.Local, identifier)) |local| { - return try create(arena, coral.shaders.Expression{ .get_local = local }); - } - - if (self.hasLocal(coral.shaders.Parameter, identifier)) |parameter| { - return try create(arena, coral.shaders.Expression{ .get_parameter = parameter }); - } - - return error.UndefinedIdentifier; - }, - - .keyword_pow => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .pow = .{ - .allowed_parameter_types = &.{ .float, .float2, .float3, .float4 }, - .expected_parameter_count = 2, - .first_argument = try self.parseArgument(arena, source), - }, - }); - }, - - .keyword_abs => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .abs = .{ - .allowed_parameter_types = &.{ .float, .float2, .float3, .float4 }, - .expected_parameter_count = 1, - .first_argument = try self.parseArgument(arena, source), - }, - }); - }, - - .keyword_sin => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .sin = .{ - .allowed_parameter_types = &.{ .float, .float2, .float3, .float4 }, - .expected_parameter_count = 1, - .first_argument = try self.parseArgument(arena, source), - }, - }); - }, - - .keyword_int => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .convert = .{ - .target_type = .int, - .parameter_types = &.{.float}, - .first_argument = try self.parseArgument(arena, source), - }, - }); - }, - - .keyword_float => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .convert = .{ - .target_type = .float, - .parameter_types = &.{.int}, - .first_argument = try self.parseArgument(arena, source), - }, - }); - }, - - .keyword_float2 => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .convert = .{ - .target_type = .float2, - .parameter_types = &.{ .float, .float }, - .first_argument = try self.parseArgument(arena, source), - }, - }); - }, - - .keyword_float3 => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .convert = .{ - .target_type = .float3, - .parameter_types = &.{ .float, .float, .float }, - .first_argument = try self.parseArgument(arena, source), - }, - }); - }, - - .keyword_float4 => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .convert = .{ - .target_type = .float4, - .parameter_types = &.{ .float, .float, .float, .float }, - .first_argument = try self.parseArgument(arena, source), - }, - }); - }, - - .keyword_float4x4 => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .convert = .{ - .target_type = .float4x4, - .parameter_types = &.{ .float4, .float4, .float4, .float4 }, - .first_argument = try self.parseArgument(arena, source), - }, - }); - }, - - .keyword_sample => { - try source.skip(.newline).expect(.symbol_paren_left); - - return try create(arena, coral.shaders.Expression{ - .sample = .{ - .signatures = &.{ - .{ - .parameter_types = &.{ .texture2, .float2 }, - .return_type = .float4, - }, - }, - - .has_argument = try self.parseArgument(arena, source), - }, - }); - }, - - else => { - return error.UnexpectedToken; - }, - } -} - -fn parseTermExpression(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Expression { - const lhs_expression = try self.parseFactorExpression(arena, source); - - if (source.current == .symbol_asterisk) { - const rhs_expression = try self.parseFactorExpression(arena, source); - const lhs_type = try lhs_expression.inferType(); - - if (lhs_type != try rhs_expression.inferType()) { - return error.IncompatibleTypes; - } - - return try create(arena, coral.shaders.Expression{ - .multiply = .{ - .rhs_expression = rhs_expression, - .lhs_expression = lhs_expression, - .type = lhs_type, - }, - }); - } - - if (source.current == .symbol_forward_slash) { - const rhs_expression = try self.parseFactorExpression(arena, source); - const lhs_type = try lhs_expression.inferType(); - - if (lhs_type != try rhs_expression.inferType()) { - return error.IncompatibleTypes; - } - - return try create(arena, coral.shaders.Expression{ - .divide = .{ - .rhs_expression = rhs_expression, - .lhs_expression = lhs_expression, - .type = lhs_type, - }, - }); - } - - return lhs_expression; -} - -pub fn parseParameter(self: *Self, arena: *std.heap.ArenaAllocator, source: *tokens.Stream) coral.shaders.ParsingError!?*const coral.shaders.Parameter { - const parameter = try self.define(arena, coral.shaders.Parameter{ - .identifier = try arena.allocator().dupeZ(u8, try source.current.expectIdentifier()), - .type = .int, - }); - - parameter.type = try self.parseType(source); - - if (try source.skip(.newline).expectAny(&.{ .symbol_paren_right, .symbol_comma }) == .symbol_comma) { - parameter.has_next = switch (try source.skip(.newline).expectAny(&.{ .symbol_paren_right, .identifier })) { - .symbol_paren_right => null, - .identifier => try self.parseParameter(arena, source), - }; - } - - return parameter; -} - -pub fn parseType(self: *const Self, source: *tokens.Stream) coral.shaders.ParsingError!*const coral.shaders.Type { - return switch (source.skip(.newline)) { - .keyword_float => .float, - .keyword_float4x4 => .float4x4, - .keyword_float2 => .float2, - .keyword_float3 => .float3, - .keyword_float4 => .float4, - .keyword_int => .int, - .identifier => |identifier| self.hasGlobal(coral.shaders.Type, identifier) orelse error.UndefinedIdentifier, - else => error.UnexpectedToken, - }; -} diff --git a/src/coral/shaders/Type.zig b/src/coral/shaders/Type.zig deleted file mode 100644 index f48170c..0000000 --- a/src/coral/shaders/Type.zig +++ /dev/null @@ -1,984 +0,0 @@ -const coral = @import("../coral.zig"); - -const std = @import("std"); - -identifier: [:0]const u8, -layout: Layout, - -pub const Layout = union(enum) { - float: Scalar, - signed: Scalar, - unsigned: Scalar, - vector: Vector, - matrix: Matrix, - texture: Texture, - record: Record, -}; - -const Self = @This(); - -pub const Dimensions = enum(u2) { - @"2", - @"3", - @"4", - - pub fn count(self: Dimensions) std.math.IntFittingRange(2, 4) { - return switch (self) { - .@"2" => 2, - .@"3" => 3, - .@"4" => 4, - }; - } -}; - -pub const Matrix = struct { - element: *const Self, - dimensions: Dimensions, -}; - -pub const Record = struct { - field_count: usize = 0, - fields: ?*const coral.shaders.Field = null, -}; - -pub const Scalar = struct { - bits: u8, -}; - -pub const Texture = struct { - dimensions: Dimensions, - is_depth: bool, - is_arary: bool, - is_multi_sampled: bool, -}; - -pub const Vector = struct { - element: *const Self, - dimensions: Dimensions, -}; - -pub const float = &Self{ - .identifier = "float", - .layout = .{ .float = .{ .bits = 32 } }, -}; - -pub const float2 = &Self{ - .identifier = "float2", - - .layout = .{ - .vector = .{ - .element = .float, - .dimensions = .@"2", - }, - }, -}; - -pub const float3 = &Self{ - .identifier = "float3", - - .layout = .{ - .vector = .{ - .element = .float, - .dimensions = .@"3", - }, - }, -}; - -pub const float4 = &Self{ - .identifier = "float4", - - .layout = .{ - .vector = .{ - .element = .float, - .dimensions = .@"4", - }, - }, -}; - -pub const float4x4 = &Self{ - .identifier = "float4x4", - - .layout = .{ - .matrix = .{ - .element = .float, - .dimensions = .@"2", - }, - }, -}; - -pub fn hasField(self: Self, field_identifier: []const u8) ?*const coral.shaders.Field { - return switch (self.layout) { - .float, .signed, .unsigned, .matrix, .texture => null, - .record => |record| if (record.fields) |field| field.has(field_identifier) else null, - - .vector => |vector| switch (vector.dimensions) { - .@"2" => switch (field_identifier.len) { - 1 => switch (field_identifier[0]) { - 'x', 'r' => .vector_x, - 'y', 'g' => .vector_y, - else => null, - }, - - 2 => switch (field_identifier[0]) { - 'x', 'r' => switch (field_identifier[1]) { - 'x', 'r' => .vector_xx, - 'y', 'g' => .vector_xy, - else => null, - }, - - 'y', 'g' => switch (field_identifier[1]) { - 'x', 'r' => .vector_yx, - 'y', 'g' => .vector_yy, - else => null, - }, - - else => null, - }, - - else => null, - }, - - .@"3" => switch (field_identifier.len) { - 1 => switch (field_identifier[0]) { - 'x', 'r' => .vector_x, - 'y', 'g' => .vector_y, - 'z', 'b' => .vector_z, - else => null, - }, - - 2 => switch (field_identifier[0]) { - 'x', 'r' => switch (field_identifier[1]) { - 'x', 'r' => .vector_xx, - 'y', 'g' => .vector_xy, - 'z', 'b' => .vector_xz, - else => null, - }, - - 'y', 'g' => switch (field_identifier[1]) { - 'x', 'r' => .vector_yx, - 'y', 'g' => .vector_yy, - 'z', 'b' => .vector_yz, - else => null, - }, - - else => null, - }, - - 3 => switch (field_identifier[0]) { - 'x', 'r' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => .vector_xxx, - 'y', 'g' => .vector_xxy, - 'z', 'b' => .vector_xxz, - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => .vector_xyx, - 'y', 'g' => .vector_xyy, - 'z', 'b' => .vector_xyz, - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => .vector_xzx, - 'y', 'g' => .vector_xzy, - 'z', 'b' => .vector_xzz, - else => null, - }, - - else => null, - }, - - 'y', 'g' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => .vector_yxx, - 'y', 'g' => .vector_yxy, - 'z', 'b' => .vector_yxz, - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => .vector_yyx, - 'y', 'g' => .vector_yyy, - 'z', 'b' => .vector_yyz, - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => .vector_yzx, - 'y', 'g' => .vector_yzy, - 'z', 'b' => .vector_yzz, - else => null, - }, - - else => null, - }, - - 'z', 'b' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => .vector_zxx, - 'y', 'g' => .vector_zxy, - 'z', 'b' => .vector_zxz, - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => .vector_zyx, - 'y', 'g' => .vector_zyy, - 'z', 'b' => .vector_zyz, - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => .vector_zzx, - 'y', 'g' => .vector_zzy, - 'z', 'b' => .vector_zzz, - else => null, - }, - - else => null, - }, - - else => null, - }, - - else => null, - }, - - .@"4" => switch (field_identifier.len) { - 1 => switch (field_identifier[0]) { - 'x', 'r' => .vector_x, - 'y', 'g' => .vector_y, - 'z', 'b' => .vector_z, - 'w', 'a' => .vector_w, - else => null, - }, - - 2 => switch (field_identifier[0]) { - 'x', 'r' => switch (field_identifier[1]) { - 'x', 'r' => .vector_xx, - 'y', 'g' => .vector_xy, - 'z', 'b' => .vector_xz, - 'w', 'a' => .vector_xw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[1]) { - 'x', 'r' => .vector_yx, - 'y', 'g' => .vector_yy, - 'z', 'b' => .vector_yz, - 'w', 'a' => .vector_yz, - else => null, - }, - - else => null, - }, - - 3 => switch (field_identifier[0]) { - 'x', 'r' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => .vector_xxx, - 'y', 'g' => .vector_xxy, - 'z', 'b' => .vector_xxz, - 'w', 'a' => .vector_xxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => .vector_xyx, - 'y', 'g' => .vector_xyy, - 'z', 'b' => .vector_xyz, - 'w', 'a' => .vector_xyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => .vector_xzx, - 'y', 'g' => .vector_xzy, - 'z', 'b' => .vector_xzz, - 'w', 'a' => .vector_xzw, - else => null, - }, - - else => null, - }, - - 'y', 'g' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => .vector_yxx, - 'y', 'g' => .vector_yxy, - 'z', 'b' => .vector_yxz, - 'w', 'a' => .vector_yxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => .vector_yyx, - 'y', 'g' => .vector_yyy, - 'z', 'b' => .vector_yyz, - 'w', 'a' => .vector_yyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => .vector_yzx, - 'y', 'g' => .vector_yzy, - 'z', 'b' => .vector_yzz, - 'w', 'a' => .vector_yzw, - else => null, - }, - - else => null, - }, - - 'z', 'b' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => .vector_zxx, - 'y', 'g' => .vector_zxy, - 'z', 'b' => .vector_zxz, - 'w', 'a' => .vector_zxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => .vector_zyx, - 'y', 'g' => .vector_zyy, - 'z', 'b' => .vector_zyz, - 'w', 'a' => .vector_zyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => .vector_zzx, - 'y', 'g' => .vector_zzy, - 'z', 'b' => .vector_zzz, - 'w', 'a' => .vector_zzw, - else => null, - }, - - else => null, - }, - - else => null, - }, - - 4 => switch (field_identifier[0]) { - 'x', 'r' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xxxx, - 'y', 'g' => .vector_xxxy, - 'z', 'b' => .vector_xxxz, - 'w', 'a' => .vector_xxxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xxyx, - 'y', 'g' => .vector_xxyy, - 'z', 'b' => .vector_xxyz, - 'w', 'a' => .vector_xxyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xxzx, - 'y', 'g' => .vector_xxzy, - 'z', 'b' => .vector_xxzz, - 'w', 'a' => .vector_xxzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xxwx, - 'y', 'g' => .vector_xxwy, - 'z', 'b' => .vector_xxwz, - 'w', 'a' => .vector_xxww, - else => null, - }, - - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xyxx, - 'y', 'g' => .vector_xyxy, - 'z', 'b' => .vector_xyxz, - 'w', 'a' => .vector_xyxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xyyx, - 'y', 'g' => .vector_xyyy, - 'z', 'b' => .vector_xyyz, - 'w', 'a' => .vector_xyyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xyzx, - 'y', 'g' => .vector_xyzy, - 'z', 'b' => .vector_xyzz, - 'w', 'a' => .vector_xyzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xywx, - 'y', 'g' => .vector_xywy, - 'z', 'b' => .vector_xywz, - 'w', 'a' => .vector_xyww, - else => null, - }, - - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xzxx, - 'y', 'g' => .vector_xzxy, - 'z', 'b' => .vector_xzxz, - 'w', 'a' => .vector_xzxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xzyx, - 'y', 'g' => .vector_xzyy, - 'z', 'b' => .vector_xzyz, - 'w', 'a' => .vector_xzyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xzzx, - 'y', 'g' => .vector_xzzy, - 'z', 'b' => .vector_xzzz, - 'w', 'a' => .vector_xzzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xzwx, - 'y', 'g' => .vector_xzwy, - 'z', 'b' => .vector_xzwz, - 'w', 'a' => .vector_xzww, - else => null, - }, - - else => null, - }, - - 'w', 'a' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xwxx, - 'y', 'g' => .vector_xwxy, - 'z', 'b' => .vector_xwxz, - 'w', 'a' => .vector_xwxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xwyx, - 'y', 'g' => .vector_xwyy, - 'z', 'b' => .vector_xwyz, - 'w', 'a' => .vector_xwyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xwzx, - 'y', 'g' => .vector_xwzy, - 'z', 'b' => .vector_xwzz, - 'w', 'a' => .vector_xwzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_xwwx, - 'y', 'g' => .vector_xwwy, - 'z', 'b' => .vector_xwwz, - 'w', 'a' => .vector_xwww, - else => null, - }, - - else => null, - }, - - else => null, - }, - - 'y', 'g' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yxxx, - 'y', 'g' => .vector_yxxy, - 'z', 'b' => .vector_yxxz, - 'w', 'a' => .vector_yxxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yxyx, - 'y', 'g' => .vector_yxyy, - 'z', 'b' => .vector_yxyz, - 'w', 'a' => .vector_yxyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yxzx, - 'y', 'g' => .vector_yxzy, - 'z', 'b' => .vector_yxzz, - 'w', 'a' => .vector_yxzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yxwx, - 'y', 'g' => .vector_yxwy, - 'z', 'b' => .vector_yxwz, - 'w', 'a' => .vector_yxww, - else => null, - }, - - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yyxx, - 'y', 'g' => .vector_yyxy, - 'z', 'b' => .vector_yyxz, - 'w', 'a' => .vector_yyxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yyyx, - 'y', 'g' => .vector_yyyy, - 'z', 'b' => .vector_yyyz, - 'w', 'a' => .vector_yyyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yyzx, - 'y', 'g' => .vector_yyzy, - 'z', 'b' => .vector_yyzz, - 'w', 'a' => .vector_yyzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yywx, - 'y', 'g' => .vector_yywy, - 'z', 'b' => .vector_yywz, - 'w', 'a' => .vector_yyww, - else => null, - }, - - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yzxx, - 'y', 'g' => .vector_yzxy, - 'z', 'b' => .vector_yzxz, - 'w', 'a' => .vector_yzxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yzyx, - 'y', 'g' => .vector_yzyy, - 'z', 'b' => .vector_yzyz, - 'w', 'a' => .vector_yzyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yzzx, - 'y', 'g' => .vector_yzzy, - 'z', 'b' => .vector_yzzz, - 'w', 'a' => .vector_yzzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_yzwx, - 'y', 'g' => .vector_yzwy, - 'z', 'b' => .vector_yzwz, - 'w', 'a' => .vector_yzww, - else => null, - }, - - else => null, - }, - - 'w', 'a' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_ywxx, - 'y', 'g' => .vector_ywxy, - 'z', 'b' => .vector_ywxz, - 'w', 'a' => .vector_ywxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_ywyx, - 'y', 'g' => .vector_ywyy, - 'z', 'b' => .vector_ywyz, - 'w', 'a' => .vector_ywyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_ywzx, - 'y', 'g' => .vector_ywzy, - 'z', 'b' => .vector_ywzz, - 'w', 'a' => .vector_ywzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_ywwx, - 'y', 'g' => .vector_ywwy, - 'z', 'b' => .vector_ywwz, - 'w', 'a' => .vector_ywww, - else => null, - }, - - else => null, - }, - - else => null, - }, - - 'z', 'b' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zxxx, - 'y', 'g' => .vector_zxxy, - 'z', 'b' => .vector_zxxz, - 'w', 'a' => .vector_zxxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zxyx, - 'y', 'g' => .vector_zxyy, - 'z', 'b' => .vector_zxyz, - 'w', 'a' => .vector_zxyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zxzx, - 'y', 'g' => .vector_zxzy, - 'z', 'b' => .vector_zxzz, - 'w', 'a' => .vector_zxzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zxwx, - 'y', 'g' => .vector_zxwy, - 'z', 'b' => .vector_zxwz, - 'w', 'a' => .vector_zxww, - else => null, - }, - - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zyxx, - 'y', 'g' => .vector_zyxy, - 'z', 'b' => .vector_zyxz, - 'w', 'a' => .vector_zyxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zyyx, - 'y', 'g' => .vector_zyyy, - 'z', 'b' => .vector_zyyz, - 'w', 'a' => .vector_zyyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zyzx, - 'y', 'g' => .vector_zyzy, - 'z', 'b' => .vector_zyzz, - 'w', 'a' => .vector_zyzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zywx, - 'y', 'g' => .vector_zywy, - 'z', 'b' => .vector_zywz, - 'w', 'a' => .vector_zyww, - else => null, - }, - - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zzxx, - 'y', 'g' => .vector_zzxy, - 'z', 'b' => .vector_zzxz, - 'w', 'a' => .vector_zzxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zzyx, - 'y', 'g' => .vector_zzyy, - 'z', 'b' => .vector_zzyz, - 'w', 'a' => .vector_zzyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zzzx, - 'y', 'g' => .vector_zzzy, - 'z', 'b' => .vector_zzzz, - 'w', 'a' => .vector_zzzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zzwx, - 'y', 'g' => .vector_zzwy, - 'z', 'b' => .vector_zzwz, - 'w', 'a' => .vector_zzww, - else => null, - }, - - else => null, - }, - - 'w', 'a' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zwxx, - 'y', 'g' => .vector_zwxy, - 'z', 'b' => .vector_zwxz, - 'w', 'a' => .vector_zwxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zwyx, - 'y', 'g' => .vector_zwyy, - 'z', 'b' => .vector_zwyz, - 'w', 'a' => .vector_zwyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zwzx, - 'y', 'g' => .vector_zwzy, - 'z', 'b' => .vector_zwzz, - 'w', 'a' => .vector_zwzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_zwwx, - 'y', 'g' => .vector_zwwy, - 'z', 'b' => .vector_zwwz, - 'w', 'a' => .vector_zwww, - else => null, - }, - - else => null, - }, - - else => null, - }, - - 'w', 'a' => switch (field_identifier[1]) { - 'x', 'r' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wxxx, - 'y', 'g' => .vector_wxxy, - 'z', 'b' => .vector_wxxz, - 'w', 'a' => .vector_wxxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wxyx, - 'y', 'g' => .vector_wxyy, - 'z', 'b' => .vector_wxyz, - 'w', 'a' => .vector_wxyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wxzx, - 'y', 'g' => .vector_wxzy, - 'z', 'b' => .vector_wxzz, - 'w', 'a' => .vector_wxzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wxwx, - 'y', 'g' => .vector_wxwy, - 'z', 'b' => .vector_wxwz, - 'w', 'a' => .vector_wxww, - else => null, - }, - - else => null, - }, - - 'y', 'g' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wyxx, - 'y', 'g' => .vector_wyxy, - 'z', 'b' => .vector_wyxz, - 'w', 'a' => .vector_wyxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wyyx, - 'y', 'g' => .vector_wyyy, - 'z', 'b' => .vector_wyyz, - 'w', 'a' => .vector_wyyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wyzx, - 'y', 'g' => .vector_wyzy, - 'z', 'b' => .vector_wyzz, - 'w', 'a' => .vector_wyzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wywx, - 'y', 'g' => .vector_wywy, - 'z', 'b' => .vector_wywz, - 'w', 'a' => .vector_wyww, - else => null, - }, - - else => null, - }, - - 'z', 'b' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wzxx, - 'y', 'g' => .vector_wzxy, - 'z', 'b' => .vector_wzxz, - 'w', 'a' => .vector_wzxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wzyx, - 'y', 'g' => .vector_wzyy, - 'z', 'b' => .vector_wzyz, - 'w', 'a' => .vector_wzyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wzzx, - 'y', 'g' => .vector_wzzy, - 'z', 'b' => .vector_wzzz, - 'w', 'a' => .vector_wzzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wzwx, - 'y', 'g' => .vector_wzwy, - 'z', 'b' => .vector_wzwz, - 'w', 'a' => .vector_wzww, - else => null, - }, - - else => null, - }, - - 'w', 'a' => switch (field_identifier[2]) { - 'x', 'r' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wwxx, - 'y', 'g' => .vector_wwxy, - 'z', 'b' => .vector_wwxz, - 'w', 'a' => .vector_wwxw, - else => null, - }, - - 'y', 'g' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wwyx, - 'y', 'g' => .vector_wwyy, - 'z', 'b' => .vector_wwyz, - 'w', 'a' => .vector_wwyw, - else => null, - }, - - 'z', 'b' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wwzx, - 'y', 'g' => .vector_wwzy, - 'z', 'b' => .vector_wwzz, - 'w', 'a' => .vector_wwzw, - else => null, - }, - - 'w', 'a' => switch (field_identifier[3]) { - 'x', 'r' => .vector_wwwx, - 'y', 'g' => .vector_wwwy, - 'z', 'b' => .vector_wwwz, - 'w', 'a' => .vector_wwww, - else => null, - }, - - else => null, - }, - - else => null, - }, - - else => null, - }, - - else => null, - }, - }, - }; -} - -pub const int = &Self{ - .identifier = "int", - .layout = .{ .signed = .{ .bits = 32 } }, -}; - -pub const texture2 = &Self{ - .identifier = "texture2", - - .layout = .{ - .texture = .{ - .dimensions = .@"2", - .is_arary = false, - .is_depth = false, - .is_multi_sampled = false, - }, - }, -}; diff --git a/src/coral/shaders/glsl.zig b/src/coral/shaders/glsl.zig deleted file mode 100644 index 5cf29aa..0000000 --- a/src/coral/shaders/glsl.zig +++ /dev/null @@ -1,339 +0,0 @@ -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); -} diff --git a/src/coral/shaders/spirv.zig b/src/coral/shaders/spirv.zig deleted file mode 100644 index e4b4b0c..0000000 --- a/src/coral/shaders/spirv.zig +++ /dev/null @@ -1,625 +0,0 @@ -const coral = @import("../coral.zig"); - -const std = @import("std"); - -pub const AccessQualifier = enum(u32) { - read_only = 0, - write_only = 1, - read_write = 2, -}; - -pub const AddressingModel = enum(u32) { - logical = 0, -}; - -pub const BuildError = std.mem.Allocator.Error || error{OutOfIds}; - -pub const Capability = enum(u32) { - matrix = 0, - shader = 1, -}; - -pub const Dim = enum(u32) { - @"1d" = 0, - @"2d" = 1, - @"3d" = 2, - cube = 4, -}; - -pub const ExecutionModel = enum(u32) { - fragment = 4, -}; - -pub const FloatType = struct { - id: u32, - bits: u32, -}; - -pub const FunctionControl = packed struct(u32) { - @"inline": bool = false, - dont_inline: bool = false, - pure: bool = false, - @"const": bool = false, - reserved: u28 = 0, -}; - -pub const FunctionType = struct { - id: u32, - parameter_types: []const *const Type, - return_type: *const Type, -}; - -pub const ImageFormat = enum(u32) { - unknown = 0, -}; - -pub const ImageType = struct { - id: u32, - sampled_type: *const Type, - dimensions: Dim, - depth: u32, - arrayed: u32, - multi_sampled: u32, - sampled: u32, - format: ImageFormat, - access: AccessQualifier, -}; - -pub const IntType = struct { - id: u32, - bits: u32, - is_signed: bool, -}; - -pub const MemoryModel = enum(u32) { - glsl450 = 1, -}; - -pub const Module = struct { - ids_assigned: u32 = 0, - capabilities: []const Capability, - memory_model: struct { AddressingModel, MemoryModel }, - entry_points: PtrTree(*const coral.shaders.Function, EntryPoint) = .empty, - types: PtrTree(*allowzero const anyopaque, Type) = .empty, - inputs: PtrTree(*const coral.shaders.Input, Value) = .empty, - functions: PtrTree(*const coral.shaders.Function, Function) = .empty, - constants: PtrTree([*:0]const u8, Constant) = .empty, - - pub const Block = struct { - id: u32, - variables: PtrTree(*const coral.shaders.Local, Value) = .empty, - instructions: coral.list.Linked(Instruction, 8) = .empty, - - pub fn shaderExpression(self: *Block, module: *Module, function: *Function, arena: *std.heap.ArenaAllocator, shader_expression: *const coral.shaders.Expression) BuildError!*const Value { - const arena_allocator = arena.allocator(); - - switch (shader_expression.*) { - .group_expression => |expression| { - return self.shaderExpression(module, function, arena, expression); - }, - - .constant => |constant| { - return module.shaderConstant(arena, constant); - }, - - .get_input => |input| { - return module.shaderInput(arena, input); - }, - - .get_parameter => |parameter| { - return function.parameters.get(parameter) orelse { - @panic("parameter does not exist in function scope"); - }; - }, - - .convert => |_| { - // TODO: Review how type conversions are represented in AST. - unreachable; - }, - - .invoke => |invoke| { - const arguments = try arena.allocator().alloc(*const Value, invoke.argument_count); - - { - var shader_arguments = invoke.arguments; - - for (arguments) |*argument| { - argument.* = try self.shaderExpression(module, function, arena, shader_arguments.?.expression); - shader_arguments = shader_arguments.?.has_next; - } - } - - const instruction = try self.instructions.append(arena_allocator, .{ - .call_function = .{ - .arguments = arguments, - .function = try module.shaderFunction(arena, invoke.function), - - .result = .{ - .type = try module.shaderValueType(arena, invoke.function.has_return_type), - .id = try module.nextId(), - }, - }, - }); - - return &instruction.call_function.result; - }, - - .add => |binary_operation| { - const instruction = try self.instructions.append(arena_allocator, .{ - .add = .{ - .operands = .{ - try self.shaderExpression(module, function, arena, binary_operation.lhs_expression), - try self.shaderExpression(module, function, arena, binary_operation.rhs_expression), - }, - - .result = .{ - .type = try module.shaderValueType(arena, binary_operation.type), - .id = try module.nextId(), - }, - }, - }); - - return &instruction.add.result; - }, - - .subtract => |binary_operation| { - const instruction = try self.instructions.append(arena_allocator, .{ - .subtract = .{ - .operands = .{ - try self.shaderExpression(module, function, arena, binary_operation.lhs_expression), - try self.shaderExpression(module, function, arena, binary_operation.rhs_expression), - }, - - .result = .{ - .type = try module.shaderValueType(arena, binary_operation.type), - .id = try module.nextId(), - }, - }, - }); - - return &instruction.subtract.result; - }, - - .multiply => |binary_operation| { - const instruction = try self.instructions.append(arena_allocator, .{ - .add = .{ - .operands = .{ - try self.shaderExpression(module, function, arena, binary_operation.lhs_expression), - try self.shaderExpression(module, function, arena, binary_operation.rhs_expression), - }, - - .result = .{ - .type = try module.shaderValueType(arena, binary_operation.type), - .id = try module.nextId(), - }, - }, - }); - - return &instruction.multiply.result; - }, - - .divide => |binary_operation| { - const instruction = try self.instructions.append(arena_allocator, .{ - .add = .{ - .operands = .{ - try self.shaderExpression(module, function, arena, binary_operation.lhs_expression), - try self.shaderExpression(module, function, arena, binary_operation.rhs_expression), - }, - - .result = .{ - .type = try module.shaderValueType(arena, binary_operation.type), - .id = try module.nextId(), - }, - }, - }); - - return &instruction.divide.result; - }, - - else => unreachable, - } - } - - pub fn shaderVariable(self: *Block, module: *Module, function: *Function, arena: *std.heap.ArenaAllocator, local: *const coral.shaders.Local) BuildError!*const Value { - return self.variables.get(local) orelse { - const arena_allocator = arena.allocator(); - - const variable = (try self.variables.insert(arena_allocator, local, .{ - .type = try module.shaderValueType(arena, local.type), - .id = try module.nextId(), - })).?; - - _ = try self.instructions.append(arena_allocator, .{ - .store = .{ - .target = variable, - .source = try self.shaderExpression(module, function, arena, local.expression), - }, - }); - - return variable; - }; - } - }; - - pub const Constant = struct { - value: Value, - data: []const u32, - }; - - pub const EntryPoint = struct { - id: u32, - function: *const Function, - execution_model: ExecutionModel, - interfaces: PtrTree(*const Value, void) = .empty, - }; - - pub const Function = struct { - id: u32, - type: *const Type, - control: FunctionControl, - parameters: PtrTree(*const coral.shaders.Parameter, Value) = .empty, - block: Block, - }; - - pub const Instruction = union(enum) { - store: struct { target: *const Value, source: *const Value }, - call_function: FunctionCall, - add: BinaryOp, - subtract: BinaryOp, - multiply: BinaryOp, - divide: BinaryOp, - - pub const BinaryOp = struct { - result: Value, - operands: [2]*const Value, - }; - - pub const FunctionCall = struct { - result: Value, - function: *const Function, - arguments: []*const Value, - }; - }; - - fn PtrTree(comptime Ptr: type, comptime Node: type) type { - return coral.tree.Binary(Ptr, Node, coral.tree.scalarTraits(Ptr)); - } - - fn nextId(self: *Module) BuildError!u32 { - self.ids_assigned = coral.scalars.add(self.ids_assigned, 1) orelse { - return error.OutOfIds; - }; - - return self.ids_assigned; - } - - pub fn shaderConstant(self: *Module, arena: *std.heap.ArenaAllocator, shader_constant: [:0]const u8) BuildError!*const Value { - if (self.constants.get(shader_constant)) |constant| { - return &constant.value; - } - - const arena_allocator = arena.allocator(); - const data = try arena_allocator.alloc(u32, 1); - - if (std.mem.indexOfScalar(u8, shader_constant, '.') == null) { - data[0] = std.mem.nativeToLittle(u32, @bitCast(coral.utf8.DecFormat.c.parse(i32, shader_constant) orelse { - @panic("malformed constant"); - })); - - const constant = (try self.constants.insert(arena_allocator, shader_constant, .{ - .data = data, - - .value = .{ - .type = try self.shaderValueType(arena, .int), - .id = try self.nextId(), - }, - })).?; - - return &constant.value; - } else { - data[0] = std.mem.nativeToLittle(u32, @bitCast(coral.utf8.DecFormat.c.parse(f32, shader_constant) orelse { - @panic("malformed constant"); - })); - - const constant = (try self.constants.insert(arena_allocator, shader_constant, .{ - .data = data, - - .value = .{ - .type = try self.shaderValueType(arena, .float), - .id = try self.nextId(), - }, - })).?; - - return &constant.value; - } - } - - pub fn shaderEntryPoint( - self: *Module, - arena: *std.heap.ArenaAllocator, - execution_model: ExecutionModel, - shader_function: *const coral.shaders.Function, - ) BuildError!*const EntryPoint { - return self.entry_points.get(shader_function) orelse { - const arena_allocator = arena.allocator(); - - const entry_point = (try self.entry_points.insert(arena_allocator, shader_function, .{ - .execution_model = execution_model, - .function = try self.shaderFunction(arena, shader_function), - .id = try self.nextId(), - })).?; - - // try entry_point.registerBlockInterfaces(shader_function.block); - - return entry_point; - }; - } - - pub fn shaderFunction( - self: *Module, - arena: *std.heap.ArenaAllocator, - shader_function: *const coral.shaders.Function, - ) BuildError!*const Function { - return self.functions.get(shader_function) orelse { - const arena_allocator = arena.allocator(); - - const function = (try self.functions.insert(arena_allocator, shader_function, .{ - .control = .{}, - .type = try self.shaderFunctionType(arena, shader_function), - .id = try self.nextId(), - .block = .{ .id = try self.nextId() }, - })).?; - - { - var parameters = shader_function.parameters; - - while (parameters) |parameter| : (parameters = parameter.has_next) { - _ = try function.parameters.insert(arena_allocator, parameter, .{ - .type = try self.shaderValueType(arena, parameter.type), - .id = try self.nextId(), - }); - } - } - - { - var statements = shader_function.block.statements; - - while (statements) |statement| { - switch (statement.*) { - .declare_local => |local_declaration| { - _ = try function.block.shaderVariable(self, function, arena, local_declaration.local); - statements = local_declaration.has_next; - }, - - .mutate_local => {}, - .mutate_output => {}, - - .return_expression => |_| {}, - } - } - } - - return function; - }; - } - - pub fn shaderFunctionType( - self: *Module, - arena: *std.heap.ArenaAllocator, - shader_function: *const coral.shaders.Function, - ) BuildError!*const Type { - const function_signature_address: *allowzero const anyopaque = @ptrCast(shader_function.signature); - - return self.types.get(function_signature_address) orelse { - const arena_allocator = arena.allocator(); - const parameter_types = try arena_allocator.alloc(*const Type, shader_function.parameter_count); - - { - var parameters = shader_function.parameters; - - for (parameter_types) |*parameter_type| { - parameter_type.* = try self.shaderValueType(arena, parameters.?.type); - parameters = parameters.?.has_next; - } - } - - return (try self.types.insert(arena_allocator, function_signature_address, .{ - .function = .{ - .parameter_types = parameter_types, - .return_type = try self.shaderValueType(arena, shader_function.has_return_type), - .id = try self.nextId(), - }, - })).?; - }; - } - - pub fn shaderInput( - self: *Module, - arena: *std.heap.ArenaAllocator, - shader_input: *const coral.shaders.Input, - ) BuildError!*const Value { - return self.inputs.get(shader_input) orelse (try self.inputs.insert(arena.allocator(), shader_input, .{ - .type = try self.shaderValueType(arena, shader_input.type), - .id = try self.nextId(), - })).?; - } - - pub fn shaderValueType( - self: *Module, - arena: *std.heap.ArenaAllocator, - has_shader_type: ?*const coral.shaders.Type, - ) BuildError!*const Type { - const arena_allocator = arena.allocator(); - const symbol_address: *allowzero const anyopaque = @ptrCast(has_shader_type); - - return self.types.get(symbol_address) orelse { - const id = try self.nextId(); - - const symbol = has_shader_type orelse { - return (try self.types.insert(arena_allocator, symbol_address, .{ - .void = .{ - .id = id, - }, - })).?; - }; - - switch (symbol.layout) { - .signed, .unsigned => |scalar| { - return (try self.types.insert(arena_allocator, symbol_address, .{ - .int = .{ - .bits = scalar.bits, - .is_signed = (symbol.layout == .signed), - .id = id, - }, - })).?; - }, - - .float => |float| { - return (try self.types.insert(arena_allocator, symbol_address, .{ - .float = .{ - .bits = float.bits, - .id = id, - }, - })).?; - }, - - .vector => |vector| { - return (try self.types.insert(arena_allocator, symbol_address, .{ - .vector = .{ - .id = id, - .component_type = try self.shaderValueType(arena, vector.element), - .component_len = vector.dimensions.count(), - }, - })).?; - }, - - .matrix, .record => unreachable, - - .texture => { - const image_type = try arena_allocator.create(Type); - - image_type.* = .{ - .image = .{ - .depth = 0, - .arrayed = 0, - .multi_sampled = 0, - .sampled = 1, - .dimensions = .@"2d", - .format = .unknown, - .access = .read_only, - .sampled_type = try self.shaderValueType(arena, .float), - .id = try self.nextId(), - }, - }; - - return (try self.types.insert(arena_allocator, symbol_address, .{ - .sampled_image = .{ - .image_type = image_type, - .id = try self.nextId(), - }, - })).?; - }, - } - }; - } - - pub fn writeTo(self: Module, spirv: coral.bytes.Writable) coral.bytes.ReadWriteError!void { - const Header = extern struct { - magic_number: u32 = 0x07230203, // SPIR-V magic number in little-endian - version: u32, // SPIR-V version (e.g., 0x00010000 for 1.0) - generator_magic: u32, // Tool or generator identifier - id_upper_bound: u32, // Upper bound for IDs - reserved: u32 = 0, // Reserved, always 0 - }; - - const OpInstruction = enum(u32) { - memory_model = 14, - entry_point = 15, - execution_mode = 16, - }; - - try coral.bytes.writeLittle(spirv, Header{ - .magic_number = 0x07230203, - .version = 0x00010000, - .generator_magic = 0, - .id_upper_bound = self.ids_assigned, - }); - - { - const addressing, const memory = self.memory_model; - - try coral.bytes.writeLittle(spirv, OpInstruction.memory_model); - try coral.bytes.writeLittle(spirv, addressing); - try coral.bytes.writeLittle(spirv, memory); - } - - { - var entry_points = self.entry_points.keyValues(); - - while (entry_points.next()) |entry_point| { - try coral.bytes.writeLittle(spirv, OpInstruction.entry_point); - try coral.bytes.writeLittle(spirv, entry_point.value.execution_model); - try coral.bytes.writeLittle(spirv, entry_point.value.function.id); - try writeString(spirv, entry_point.key.identifier); - - var interfaces = entry_point.value.interfaces.keyValues(); - - while (interfaces.nextKey()) |interface| { - try coral.bytes.writeLittle(spirv, interface.*.id); - } - - try coral.bytes.writeLittle(spirv, OpInstruction.execution_mode); - try coral.bytes.writeLittle(spirv, entry_point.value.function.id); - try coral.bytes.writeLittle(spirv, @as(u32, 7)); - } - } - } -}; - -pub const Value = struct { - id: u32, - type: *const Type, -}; - -pub const SampledImageType = struct { - id: u32, - image_type: *const Type, -}; - -pub const StructType = struct { - id: u32, - member_types: []const *const Type, -}; - -pub const Type = union(enum) { - void: VoidType, - float: FloatType, - vector: VectorType, - image: ImageType, - @"struct": StructType, - function: FunctionType, - int: IntType, - sampled_image: SampledImageType, -}; - -pub const VectorType = struct { - id: u32, - component_type: *const Type, - component_len: u32, -}; - -pub const VoidType = struct { - id: u32, -}; - -fn writeString(spirv: coral.bytes.Writable, data: []const u8) coral.bytes.ReadWriteError!void { - const data_len_with_sentinel = data.len + 1; - const word_size = @sizeOf(u32); - const word_count = (data_len_with_sentinel + word_size) / word_size; - - try coral.bytes.writeSentineled(spirv, data, 0); - - const padding = (word_count * word_size) - data_len_with_sentinel; - - try coral.bytes.writeN(spirv, "\x00", padding); -} diff --git a/src/coral/shaders/tokens.zig b/src/coral/shaders/tokens.zig deleted file mode 100644 index 9d14206..0000000 --- a/src/coral/shaders/tokens.zig +++ /dev/null @@ -1,494 +0,0 @@ -const coral = @import("../coral.zig"); - -const std = @import("std"); - -pub const ExpectationError = error{ - UnexpectedToken, -}; - -pub const Kind = enum { - end, - unknown, - newline, - keyword_function, - keyword_return, - keyword_sample, - keyword_float, - keyword_float4x4, - keyword_float2, - keyword_float3, - keyword_float4, - keyword_int, - keyword_let, - keyword_var, - keyword_pow, - keyword_abs, - keyword_sin, - identifier, - scalar, - symbol_plus, - symbol_minus, - symbol_comma, - symbol_arrow, - symbol_equals, - symbol_period, - symbol_asterisk, - symbol_paren_left, - symbol_paren_right, - symbol_brace_left, - symbol_brace_right, - symbol_double_equals, - symbol_lesser_than, - symbol_lesser_equals, - symbol_greater_than, - symbol_greater_equals, - symbol_forward_slash, - - pub fn writeFormat(self: Kind, writer: coral.bytes.Writable) coral.bytes.ReadWriteError!void { - try coral.bytes.writeAll(writer, self.name()); - } - - pub fn name(self: Kind) [:0]const u8 { - return switch (self) { - .end => "end", - .unknown => "unknown", - .newline => "newline", - .keyword_function => "`function` keyword", - .keyword_return => "`return` keyword", - .keyword_sample => "`sample` keyword", - .keyword_float => "`float` keyword", - .keyword_float4x4 => "`float4x4` keyword", - .keyword_float2 => "`float2` keyword", - .keyword_float3 => "`float3` keyword", - .keyword_float4 => "`float4` keyword", - .keyword_int => "`int` keyword", - .keyword_let => "`let` keyword", - .keyword_var => "`var` keyword", - .keyword_pow => "`pow` keyword", - .keyword_abs => "`abs` keyword", - .keyword_sin => "`sin` keyword", - .identifier => "identifier", - .scalar => "scalar literal", - .symbol_plus => "`+`", - .symbol_minus => "`-`", - .symbol_comma => "`,`", - .symbol_arrow => "`->`", - .symbol_equals => "`=`", - .symbol_period => "`.`", - .symbol_asterisk => "`*`", - .symbol_paren_left => "`(`", - .symbol_paren_right => "`)`", - .symbol_brace_left => "`{`", - .symbol_brace_right => "`}`", - .symbol_double_equals => "`==`", - .symbol_lesser_than => "`<`", - .symbol_lesser_equals => "`<=`", - .symbol_greater_than => "`>`", - .symbol_greater_equals => "`>=`", - .symbol_forward_slash => "`/`", - }; - } -}; - -pub const Location = struct { - line_number: u32 = 1, - column_number: u32 = 1, - - pub fn writeFormat(self: Location, writer: coral.bytes.Writable) coral.bytes.ReadWriteError!void { - try coral.bytes.writeFormatted(writer, "({line}, {column})", .{ - .line = coral.utf8.cDec(self.line_number), - .column = coral.utf8.cDec(self.column_number), - }); - } -}; - -pub const Stream = struct { - source: []const u8, - current: Token, - location: Location, - depth: u32 = 0, - - pub fn isFinished(self: Stream) bool { - return self.source.len == 0; - } - - pub fn init(source: []const u8) Stream { - return .{ - .source = source, - .current = .end, - .location = .{}, - }; - } - - pub fn next(self: *Stream) Token { - const initial_len = self.source.len; - - self.current = consume(&self.source); - - switch (self.current) { - .end => { - self.depth = 0; - }, - - .symbol_brace_left => { - self.depth += 1; - }, - - .symbol_brace_right => { - self.depth -= 1; - }, - - .newline => { - self.location.line_number += 1; - self.location.column_number = 1; - }, - - else => { - const consumed_len: u32 = @intCast(initial_len - self.source.len); - - self.location.column_number += consumed_len; - }, - } - - return self.current; - } - - pub fn skip(self: *Stream, skip_kind: Kind) Token { - while (true) { - if (std.meta.activeTag(self.next()) != skip_kind) { - return self.current; - } - } - } -}; - -pub const Token = union(Kind) { - end, - unknown: []const u8, - newline, - keyword_function, - keyword_return, - keyword_sample, - keyword_float, - keyword_float4x4, - keyword_float2, - keyword_float3, - keyword_float4, - keyword_int, - keyword_let, - keyword_var, - keyword_pow, - keyword_abs, - keyword_sin, - identifier: []const u8, - scalar: []const u8, - symbol_plus, - symbol_minus, - symbol_comma, - symbol_arrow, - symbol_equals, - symbol_period, - symbol_asterisk, - symbol_paren_left, - symbol_paren_right, - symbol_brace_left, - symbol_brace_right, - symbol_double_equals, - symbol_lesser_than, - symbol_lesser_equals, - symbol_greater_than, - symbol_greater_equals, - symbol_forward_slash, - - pub fn ExpectedAnyEnum(comptime expecteds: []const Kind) type { - comptime var fields: [expecteds.len]std.builtin.Type.EnumField = undefined; - - inline for (0..expecteds.len) |i| { - fields[i] = .{ - .name = @tagName(expecteds[i]), - .value = i, - }; - } - - return @Type(.{ - .@"enum" = .{ - .tag_type = @typeInfo(Kind).@"enum".tag_type, - .fields = &fields, - .decls = &.{}, - .is_exhaustive = true, - }, - }); - } - - pub fn expect(self: Token, expected: Kind) ExpectationError!void { - if (std.meta.activeTag(self) != expected) { - return error.UnexpectedToken; - } - } - - pub fn expectAny(self: Token, comptime expecteds: []const Kind) ExpectationError!ExpectedAnyEnum(expecteds) { - if (std.mem.indexOfScalar(Kind, expecteds, std.meta.activeTag(self))) |index| { - return @enumFromInt(index); - } - - return error.UnexpectedToken; - } - - pub fn expectIdentifier(self: Token) ExpectationError![]const u8 { - try self.expect(.identifier); - - return self.identifier; - } - - pub fn expectScalar(self: Token) ExpectationError![]const u8 { - try self.expect(.scalar); - - return self.scalar; - } - - pub fn writeFormat(self: Token, writer: coral.bytes.Writable) coral.bytes.ReadWriteError!void { - try switch (self) { - .unknown => |unknown| coral.bytes.writeFormatted(writer, "`{name}`", .{ - .name = unknown, - }), - - .identifier => |identifier| coral.bytes.writeFormatted(writer, "`{name}`", .{ - .name = identifier, - }), - - .scalar => |literal| coral.bytes.writeFormatted(writer, "`{name}`", .{ - .name = literal, - }), - - else => std.meta.activeTag(self).writeFormat(writer), - }; - } -}; - -pub fn consume(source: *[]const u8) Token { - var cursor = @as(usize, 0); - - defer { - source.* = source.*[cursor..]; - } - - while (cursor < source.len) { - switch (source.*[cursor]) { - '#' => { - cursor += 1; - - while (cursor < source.len and source.*[cursor] != '\n') { - cursor += 1; - } - }, - - ' ', '\t' => { - cursor += 1; - }, - - '\n' => { - cursor += 1; - - return .newline; - }, - - '0'...'9' => { - const begin = cursor; - - cursor += 1; - - while (cursor < source.len) { - switch (source.*[cursor]) { - '0'...'9' => { - cursor += 1; - }, - - '.' => { - cursor += 1; - - while (cursor < source.len) { - switch (source.*[cursor]) { - '0'...'9' => { - cursor += 1; - }, - - else => { - break; - }, - } - } - - return .{ .scalar = source.*[begin..cursor] }; - }, - - else => { - break; - }, - } - } - - return .{ .scalar = source.*[begin..cursor] }; - }, - - 'A'...'Z', 'a'...'z', '_' => { - const begin = cursor; - - cursor += 1; - - while (cursor < source.len) { - switch (source.*[cursor]) { - '0'...'9', 'A'...'Z', 'a'...'z', '_' => cursor += 1, - else => break, - } - } - - const identifier = source.*[begin..cursor]; - - std.debug.assert(identifier.len != 0); - - const identifier_keyword_pairs = [_]struct { [:0]const u8, Kind }{ - .{ "float", .keyword_float }, - .{ "float2", .keyword_float2 }, - .{ "float3", .keyword_float3 }, - .{ "float4", .keyword_float4 }, - .{ "float4x4", .keyword_float4x4 }, - .{ "function", .keyword_function }, - .{ "let", .keyword_let }, - .{ "var", .keyword_var }, - .{ "return", .keyword_return }, - .{ "var", .keyword_var }, - .{ "pow", .keyword_pow }, - .{ "abs", .keyword_abs }, - .{ "sin", .keyword_sin }, - .{ "sample", .keyword_sample }, - }; - - inline for (identifier_keyword_pairs) |pair| { - const keyword_identifier, const keyword = pair; - - if (std.mem.eql(u8, identifier, keyword_identifier)) { - return keyword; - } - } - - return .{ .identifier = identifier }; - }, - - '{' => { - cursor += 1; - - return .symbol_brace_left; - }, - - '}' => { - cursor += 1; - - return .symbol_brace_right; - }, - - ',' => { - cursor += 1; - - return .symbol_comma; - }, - - ')' => { - cursor += 1; - - return .symbol_paren_right; - }, - - '(' => { - cursor += 1; - - return .symbol_paren_left; - }, - - '/' => { - cursor += 1; - - return .symbol_forward_slash; - }, - - '*' => { - cursor += 1; - - return .symbol_asterisk; - }, - - '-' => { - cursor += 1; - - if (cursor < source.len and source.*[cursor] == '>') { - cursor += 1; - - return .symbol_arrow; - } - - return .symbol_minus; - }, - - '+' => { - cursor += 1; - - return .symbol_plus; - }, - - '=' => { - cursor += 1; - - if (cursor < source.len and source.*[cursor] == '=') { - cursor += 1; - - return .symbol_double_equals; - } - - return .symbol_equals; - }, - - '<' => { - cursor += 1; - - if (cursor < source.len and (source.*[cursor] == '=')) { - cursor += 1; - - return .symbol_lesser_equals; - } - - return .symbol_lesser_than; - }, - - '>' => { - cursor += 1; - - if (cursor < source.len and (source.*[cursor] == '=')) { - cursor += 1; - - return .symbol_greater_equals; - } - - return .symbol_greater_than; - }, - - '.' => { - cursor += 1; - - return .symbol_period; - }, - - else => { - const begin = cursor; - - cursor += 1; - - while (cursor < source.len and !std.ascii.isWhitespace(source.*[cursor])) { - cursor += 1; - } - - return .{ .unknown = source.*[begin..cursor] }; - }, - } - } - - return .end; -} diff --git a/src/ext/ext.zig b/src/ext/ext.zig index 09e95f1..812aa47 100644 --- a/src/ext/ext.zig +++ b/src/ext/ext.zig @@ -1,3 +1,4 @@ pub usingnamespace @cImport({ @cInclude("SDL3/SDL.h"); + @cInclude("shaderc/shaderc.h"); }); diff --git a/src/ona/App.zig b/src/ona/App.zig index c0ac708..9cf1642 100644 --- a/src/ona/App.zig +++ b/src/ona/App.zig @@ -12,7 +12,11 @@ const std = @import("std"); initialized_states: coral.map.Hashed(*const coral.TypeId, coral.Box, coral.map.scalarTraits(*const coral.TypeId)), named_systems: coral.tree.Binary([]const u8, SystemGraph, coral.tree.sliceTraits([]const u8)), -is_running: bool, + +pub const Exit = union(enum) { + success, + failure: anyerror, +}; pub const RunError = std.mem.Allocator.Error || error{ MissingDependency, @@ -65,7 +69,6 @@ pub fn init() std.mem.Allocator.Error!Self { var self = Self{ .initialized_states = .empty, .named_systems = .empty, - .is_running = true, }; try self.setState(Time{ diff --git a/src/ona/gfx.zig b/src/ona/gfx.zig index 1b00722..4d7cf35 100644 --- a/src/ona/gfx.zig +++ b/src/ona/gfx.zig @@ -4,6 +4,8 @@ const coral = @import("coral"); const ext = @import("ext"); +const glsl = @import("./gfx/glsl.zig"); + const ona = @import("./ona.zig"); const std = @import("std"); @@ -17,11 +19,55 @@ pub const Display = struct { const Context = struct { window: *ext.SDL_Window, gpu_device: *ext.SDL_GPUDevice, - basic_shader: *ext.SDL_GPUShader = undefined, + shader_compiler: ext.shaderc_compiler_t, + spirv_options: ext.shaderc_compile_options_t, + + pub const AssembleError = std.mem.Allocator.Error || error{BadSyntax}; + + pub const AssemblyKind = enum(c_int) { + vertex, + fragment, + }; + + pub fn assemble(self: *Context, allocator: std.mem.Allocator, kind: AssemblyKind, name: [*:0]const u8, source: []const u8) AssembleError![]u8 { + const result = ext.shaderc_compile_into_spv(self.shader_compiler, source.ptr, source.len, switch (kind) { + .fragment => ext.shaderc_glsl_vertex_shader, + .vertex => ext.shaderc_glsl_vertex_shader, + }, name, "main", self.spirv_options) orelse { + return error.OutOfMemory; + }; + + defer { + ext.shaderc_result_release(result); + } + + return switch (ext.shaderc_result_get_compilation_status(result)) { + ext.shaderc_compilation_status_success => { + const compiled_len = ext.shaderc_result_get_length(result); + const compiled_ptr = ext.shaderc_result_get_bytes(result); + + return allocator.dupe(u8, compiled_ptr[0..compiled_len]); + }, + + ext.shaderc_compilation_status_compilation_error, ext.shaderc_compilation_status_invalid_stage => { + std.log.err("{s}", .{ext.shaderc_result_get_error_message(result)}); + std.log.debug("problematic shader:\n{s}", .{source}); + + return error.BadSyntax; + }, + + ext.shaderc_compilation_status_internal_error => @panic("shaderc internal compiler error"), + else => unreachable, + }; + } pub fn deinit(self: *Context) void { + ext.shaderc_compile_options_release(self.spirv_options); + ext.shaderc_compiler_release(self.shader_compiler); ext.SDL_DestroyGPUDevice(self.gpu_device); ext.SDL_DestroyWindow(self.window); + + self.* = undefined; } pub const traits = ona.Traits{ @@ -29,86 +75,89 @@ const Context = struct { }; }; -fn compile_shaders(_: ona.Write(Context), assets: ona.Assets) !void { +fn compile_shaders(context: ona.Write(Context)) !void { + const Camera = extern struct { + projection: [4]@Vector(4, f32), + }; + var arena = std.heap.ArenaAllocator.init(coral.heap.allocator); defer { arena.deinit(); } - const shader_path = "graphics_demo.eff"; - var root = try coral.shaders.Root.init(&arena); + const arena_allocator = arena.allocator(); - const Constants = extern struct { - screen_width: f32, - screen_height: f32, - time: f32, - }; + const vertex_spirv = try context.ptr.assemble(arena_allocator, .vertex, "./gfx/effect.vert", try glsl.inject(arena_allocator, @embedFile("./gfx/effect.vert"), .{ + .inputs = &.{ + .{ "model_xy", .vec2 }, + .{ "model_uv", .vec2 }, + .{ "model_rgba", .vec4 }, - try root.defineUniform(&arena, .{ - .identifier = "effect", - .semantic = "Effect", - .binding = 0, - .has_field = .fieldsOf(Constants), - }); - - try root.defineTexture(&arena, .{ - .identifier = "albedo", - .binding = 0, - .layout = .dimensions_2, - }); - - try root.defineInput(&arena, .{ - .identifier = "uv", - .type = .float2, - .location = 0, - }); - - try root.defineOutput(&arena, .{ - .identifier = "color", - .type = .float4, - .location = 0, - }); - - switch (try root.parse(&arena, try assets.load(shader_path, arena.allocator()))) { - .ok => { - const spirv_module = try root.buildSpirvFragment(&arena, "frag"); - var codes = coral.Stack(u8).empty; - - defer { - codes.deinit(); - } - - try spirv_module.writeTo(coral.bytes.stackWriter(&codes)); - - std.log.info("{s}", .{codes.values}); + .{ "instance_rect", .vec4 }, + .{ "instance_xbasis", .vec2 }, + .{ "instance_ybasis", .vec2 }, + .{ "instance_origin", .vec2 }, + .{ "instance_color", .vec4 }, + .{ "instance_depth", .float }, }, - .failure => |failure| { - std.log.err("failed to parse shader {s}: {s}", .{ shader_path, failure }); - - return error.ShaderParseFailure; + .outputs = &.{ + .{ "color", .vec4 }, + .{ "uv", .vec2 }, }, - } - @breakpoint(); + .uniforms = &.{ + .{ "camera", .init(0, Camera) }, + }, + })); - // const basic_shader = ext.SDL_CreateGPUShader(gpu_device, &.{ - // .code = spirv_code, - // .code_size = spirv_code.len, - // .stage = ext.SDL_GPU_SHADERSTAGE_FRAGMENT, - // .entrypoint = "frag_main", - // }) orelse { - // return sdl_failure("Failed to create basic shader"); - // }; + const fragment_spirv = try context.ptr.assemble(arena_allocator, .fragment, "./gfx/effect.frag", try glsl.inject(arena_allocator, @embedFile("./gfx/effect.frag"), .{ + .inputs = &.{ + .{ "vertex_color", .vec4 }, + .{ "vertex_uv", .vec2 }, + }, + + .samplers = &.{ + .{ "source_texture", .{ .sampler_2d = 0 } }, + }, + + .outputs = &.{ + .{ "color", .vec4 }, + }, + + .uniforms = &.{ + .{ "camera", .init(0, Camera) }, + }, + })); + + const effect_fragment = ext.SDL_CreateGPUShader(context.ptr.gpu_device, &.{ + .code = fragment_spirv.ptr, + .code_size = fragment_spirv.len, + .format = ext.SDL_GPU_SHADERFORMAT_SPIRV, + .entrypoint = "main", + }); + + const effect_vertex = ext.SDL_CreateGPUShader(context.ptr.gpu_device, &.{ + .code = vertex_spirv.ptr, + .code_size = vertex_spirv.len, + .format = ext.SDL_GPU_SHADERFORMAT_SPIRV, + .entrypoint = "main", + }); + + _ = effect_fragment; + _ = effect_vertex; } -pub fn poll(input_events: ona.Send(ona.hid.Event)) !void { +pub fn poll(exit: ona.Send(ona.App.Exit), hid_events: ona.Send(ona.hid.Event)) !void { var event: ext.SDL_Event = undefined; while (ext.SDL_PollEvent(&event)) { - try input_events.push(switch (event.type) { - ext.SDL_EVENT_QUIT => .quit, + try hid_events.push(switch (event.type) { + ext.SDL_EVENT_QUIT => { + return exit.push(.success); + }, + ext.SDL_EVENT_KEY_UP => .{ .key_up = @enumFromInt(event.key.scancode) }, ext.SDL_EVENT_KEY_DOWN => .{ .key_down = @enumFromInt(event.key.scancode) }, @@ -117,7 +166,10 @@ pub fn poll(input_events: ona.Send(ona.hid.Event)) !void { ext.SDL_BUTTON_LEFT => .left, ext.SDL_BUTTON_RIGHT => .right, ext.SDL_BUTTON_MIDDLE => .middle, - else => continue, + + else => { + continue; + }, }, }, @@ -126,7 +178,10 @@ pub fn poll(input_events: ona.Send(ona.hid.Event)) !void { ext.SDL_BUTTON_LEFT => .left, ext.SDL_BUTTON_RIGHT => .right, ext.SDL_BUTTON_MIDDLE => .middle, - else => continue, + + else => { + continue; + }, }, }, @@ -137,7 +192,9 @@ pub fn poll(input_events: ona.Send(ona.hid.Event)) !void { }, }, - else => continue, + else => { + continue; + }, }); } } @@ -215,7 +272,33 @@ pub fn setup(app: *ona.App) !void { return error.SdlFailure; } + const shader_compiler = ext.shaderc_compiler_initialize() orelse { + return error.OutOfMemory; + }; + + errdefer { + ext.shaderc_compiler_release(shader_compiler); + } + + const spirv_options = ext.shaderc_compile_options_initialize() orelse { + return error.OutOfMemory; + }; + + errdefer { + ext.shaderc_compile_options_release(spirv_options); + } + + ext.shaderc_compile_options_set_target_env(spirv_options, ext.shaderc_target_env_vulkan, ext.shaderc_env_version_vulkan_1_1); + + ext.shaderc_compile_options_set_optimization_level(spirv_options, switch (builtin.mode) { + .Debug, .ReleaseSafe => ext.shaderc_optimization_level_zero, + .ReleaseSmall => ext.shaderc_optimization_level_size, + .ReleaseFast => ext.shaderc_optimization_level_performance, + }); + try app.setState(Context{ + .shader_compiler = shader_compiler, + .spirv_options = spirv_options, .window = window, .gpu_device = gpu_device, }); diff --git a/src/ona/gfx/effect.frag b/src/ona/gfx/effect.frag new file mode 100644 index 0000000..5448564 --- /dev/null +++ b/src/ona/gfx/effect.frag @@ -0,0 +1,4 @@ + +void main() { + color = vertex_color * texture(source_texture, vertex_uv); +} diff --git a/src/ona/gfx/effect.vert b/src/ona/gfx/effect.vert new file mode 100644 index 0000000..23f04f3 --- /dev/null +++ b/src/ona/gfx/effect.vert @@ -0,0 +1,11 @@ + +void main() { + const vec2 world_position = instance_origin + model_xy.x * instance_xbasis + model_xy.y * instance_ybasis; + const vec2 projected_position = (camera.projection * vec4(world_position, 0, 1)).xy; + const vec2 rect_size = instance_rect.zw - instance_rect.xy; + const vec4 screen_position = vec4(projected_position, instance_depth, 1.0); + + gl_Position = screen_position; + color = model_rgba * instance_color; + uv = instance_rect.xy + (model_uv * rect_size); +} diff --git a/src/ona/gfx/glsl.zig b/src/ona/gfx/glsl.zig new file mode 100644 index 0000000..8be9ddb --- /dev/null +++ b/src/ona/gfx/glsl.zig @@ -0,0 +1,162 @@ +const coral = @import("coral"); + +const ona = @import("../ona.zig"); + +const std = @import("std"); + +pub const InjectOptions = struct { + version: u64 = 430, + inputs: []const Entry(Primitive) = &.{}, + outputs: []const Entry(Primitive) = &.{}, + uniforms: []const Entry(Uniform) = &.{}, + samplers: []const Entry(Sampler) = &.{}, + + pub fn Entry(comptime Item: type) type { + return struct { [:0]const u8, Item }; + } + + pub fn writeFormat(self: InjectOptions, source: coral.bytes.Writable) coral.bytes.ReadWriteError!void { + try coral.bytes.writeFormatted(source, "#version {version}\n\n", .{ .version = coral.utf8.cDec(self.version) }); + + for (0..self.inputs.len, self.inputs) |location, input| { + const name, const primitive = input; + + try coral.bytes.writeFormatted(source, "layout (location = {location}) in {primitive} {name};\n", .{ + .location = coral.utf8.cDec(location), + .primitive = @tagName(primitive), + .name = name, + }); + } + + try coral.bytes.writeAll(source, "\n"); + + for (0..self.outputs.len, self.outputs) |location, output| { + const name, const primitive = output; + + try coral.bytes.writeFormatted(source, "layout (location = {location}) out {primitive} {name};\n", .{ + .location = coral.utf8.cDec(location), + .primitive = @tagName(primitive), + .name = name, + }); + } + + try coral.bytes.writeAll(source, "\n"); + + for (self.samplers) |named_sampler| { + const name, const sampler = named_sampler; + + switch (sampler) { + .sampler_2d => |binding| { + try coral.bytes.writeFormatted(source, "layout (binding = {binding}) uniform sampler2D {name};\n\n", .{ + .binding = coral.utf8.cDec(binding), + .name = name, + }); + }, + } + } + + for (self.uniforms) |named_uniform| { + const name, const uniform = named_uniform; + + try coral.bytes.writeFormatted(source, "layout (binding = {binding}) uniform {type_name} {{\n", .{ + .binding = coral.utf8.cDec(uniform.binding), + .type_name = uniform.name, + }); + + var field = uniform.field; + + while (true) : (field = field.has_next orelse { + break; + }) { + try coral.bytes.writeFormatted(source, "\t{primitive} {name};\n", .{ + .primitive = @tagName(field.primitive), + .name = field.name, + }); + } + + try coral.bytes.writeFormatted(source, "}} {name};\n\n", .{ .name = name }); + } + + try coral.bytes.writeAll(source, "#line 1\n\n"); + } +}; + +pub const Primitive = enum { + float, + vec2, + vec3, + vec4, + mat4, +}; + +pub const Sampler = union(enum) { + sampler_2d: usize, +}; + +pub const Uniform = struct { + name: [:0]const u8, + binding: usize, + field: *const Field, + + pub const Field = struct { + name: [:0]const u8, + primitive: Primitive, + has_next: ?*const Field, + + fn of(comptime uniform_fields: []const std.builtin.Type.StructField) *const Field { + if (uniform_fields.len == 0) { + @compileError("Struct contains no fields"); + } + + const field = struct { + const instance = Field{ + .name = uniform_fields[0].name, + + .primitive = switch (uniform_fields[0].type) { + @Vector(4, f32) => .vec4, + [4]@Vector(4, f32) => .mat4, + else => @compileError("Unsupported uniform type"), + }, + + .has_next = switch (uniform_fields.len) { + 1 => null, + else => .of(uniform_fields[1..]), + }, + }; + }; + + return &field.instance; + } + }; + + pub fn init(binding: usize, comptime Struct: type) Uniform { + // TODO: Review how GLSL identifier-safe names are generated. + const struct_name = @typeName(Struct); + + const struct_type = switch (@typeInfo(Struct)) { + .@"struct" => |@"struct"| @"struct", + else => @compileError("`Struct` must be a struct type"), + }; + + if (struct_type.is_tuple) { + @compileError("`Struct` must be a non-tuple struct"); + } + + if (struct_type.layout != .@"extern") { + @compileError("`Struct` must use an extern layout"); + } + + return .{ + .name = if (std.mem.lastIndexOfScalar(u8, struct_name, '.')) |index| struct_name[index + 1 ..] else struct_name, + .field = .of(struct_type.fields), + .binding = binding, + }; + } +}; + +pub fn inject(allocator: std.mem.Allocator, source_base: []const u8, options: InjectOptions) std.mem.Allocator.Error![:0]u8 { + return coral.bytes.allocFormatted(allocator, "{injected_source}\n{original_source}\n", .{ + .injected_source = options, + .original_source = source_base, + }); +} diff --git a/src/ona/hid.zig b/src/ona/hid.zig index 9b6de62..419fa8f 100644 --- a/src/ona/hid.zig +++ b/src/ona/hid.zig @@ -1,5 +1,6 @@ +const ona = @import("ona.zig"); + pub const Event = union(enum) { - quit, key_up: KeyScancode, key_down: KeyScancode, mouse_up: MouseButton, diff --git a/src/ona/ona.zig b/src/ona/ona.zig index aae1573..49ac3ed 100644 --- a/src/ona/ona.zig +++ b/src/ona/ona.zig @@ -141,6 +141,7 @@ fn run_realtime_loop(app: *App) !void { const updates_per_frame = 60.0; const target_frame_time = 1.0 / updates_per_frame; const time = app.hasState(App.Time).?; + const exit_channel = app.hasState(Channel(App.Exit)).?; const virtual_thread_count = std.Thread.getCpuCount() catch 0; var tasks = try coral.asio.TaskQueue.init(virtual_thread_count / 2); @@ -155,7 +156,7 @@ fn run_realtime_loop(app: *App) !void { var ticks_previous = ticks_initial; var accumulated_time = @as(f64, 0); - while (app.is_running) { + while (true) { const ticks_current = std.time.milliTimestamp(); const milliseconds_per_second = 1000.0; @@ -172,7 +173,21 @@ fn run_realtime_loop(app: *App) !void { try app.run(&tasks, .post_update); try app.run(&tasks, .render); try app.run(&tasks, .finish); - } - try app.run(&tasks, .exit); + const exit_messages = exit_channel.messages(); + + if (exit_messages.len != 0) { + try app.run(&tasks, .exit); + + switch (exit_messages[exit_messages.len - 1]) { + .success => { + break; + }, + + .failure => |failure| { + return failure; + }, + } + } + } }