module: write components using a struct pattern
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
17db5498ee
commit
2115f5832a
8 changed files with 45 additions and 62 deletions
|
|
@ -17,7 +17,7 @@ spawning: bool = false,
|
||||||
spawn_timer: mach.Timer,
|
spawn_timer: mach.Timer,
|
||||||
|
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .follower, .type = void },
|
.follower = .{ .type = void },
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ pub const name = .renderer;
|
||||||
pub const Mod = mach.Mod(@This());
|
pub const Mod = mach.Mod(@This());
|
||||||
|
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .location, .type = Vec3 },
|
.location = .{ .type = Vec3 },
|
||||||
.{ .name = .rotation, .type = Vec3 },
|
.rotation = .{ .type = Vec3 },
|
||||||
.{ .name = .scale, .type = f32 },
|
.scale = .{ .type = f32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
|
|
|
||||||
|
|
@ -754,9 +754,9 @@ test "example" {
|
||||||
struct {
|
struct {
|
||||||
pub const name = .game;
|
pub const name = .game;
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .name, .type = []const u8 },
|
.name = .{ .type = []const u8 },
|
||||||
.{ .name = .location, .type = Location },
|
.location = .{ .type = Location },
|
||||||
.{ .name = .rotation, .type = Rotation },
|
.rotation = .{ .type = Rotation },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}){};
|
}){};
|
||||||
|
|
@ -858,9 +858,9 @@ test "many entities" {
|
||||||
struct {
|
struct {
|
||||||
pub const name = .game;
|
pub const name = .game;
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .name, .type = []const u8 },
|
.name = .{ .type = []const u8 },
|
||||||
.{ .name = .location, .type = Location },
|
.location = .{ .type = Location },
|
||||||
.{ .name = .rotation, .type = Rotation },
|
.rotation = .{ .type = Rotation },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}){};
|
}){};
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ test "example" {
|
||||||
|
|
||||||
pub const name = .physics;
|
pub const name = .physics;
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .id, .type = u32 },
|
.id = .{ .type = u32 },
|
||||||
};
|
};
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
.tick = .{ .handler = tick },
|
.tick = .{ .handler = tick },
|
||||||
|
|
@ -61,7 +61,7 @@ test "example" {
|
||||||
const Renderer = struct {
|
const Renderer = struct {
|
||||||
pub const name = .renderer;
|
pub const name = .renderer;
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .id, .type = u16 },
|
.id = .{ .type = u16 },
|
||||||
};
|
};
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
.tick = .{ .handler = tick },
|
.tick = .{ .handler = tick },
|
||||||
|
|
|
||||||
|
|
@ -74,14 +74,14 @@ test "query" {
|
||||||
struct {
|
struct {
|
||||||
pub const name = .game;
|
pub const name = .game;
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .name, .type = []const u8 },
|
.name = .{ .type = []const u8 },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
struct {
|
struct {
|
||||||
pub const name = .physics;
|
pub const name = .physics;
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .location, .type = Location },
|
.location = .{ .type = Location },
|
||||||
.{ .name = .rotation, .type = Rotation },
|
.rotation = .{ .type = Rotation },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@ pub const name = .mach_gfx_sprite;
|
||||||
pub const Mod = mach.Mod(@This());
|
pub const Mod = mach.Mod(@This());
|
||||||
|
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .pipeline, .type = u8, .description =
|
.pipeline = .{ .type = u8, .description =
|
||||||
\\ The ID of the pipeline this sprite belongs to. By default, zero.
|
\\ The ID of the pipeline this sprite belongs to. By default, zero.
|
||||||
\\
|
\\
|
||||||
\\ This determines which shader, textures, etc. are used for rendering the sprite.
|
\\ This determines which shader, textures, etc. are used for rendering the sprite.
|
||||||
},
|
},
|
||||||
|
|
||||||
.{ .name = .transform, .type = Mat4x4, .description =
|
.transform = .{ .type = Mat4x4, .description =
|
||||||
\\ The sprite model transformation matrix. A sprite is measured in pixel units, starting from
|
\\ The sprite model transformation matrix. A sprite is measured in pixel units, starting from
|
||||||
\\ (0, 0) at the top-left corner and extending to the size of the sprite. By default, the world
|
\\ (0, 0) at the top-left corner and extending to the size of the sprite. By default, the world
|
||||||
\\ origin (0, 0) lives at the center of the window.
|
\\ origin (0, 0) lives at the center of the window.
|
||||||
|
|
@ -34,11 +34,11 @@ pub const components = .{
|
||||||
\\ cover the top-right hand corner of the window.
|
\\ cover the top-right hand corner of the window.
|
||||||
},
|
},
|
||||||
|
|
||||||
.{ .name = .uv_transform, .type = Mat3x3, .description =
|
.uv_transform = .{ .type = Mat3x3, .description =
|
||||||
\\ UV coordinate transformation matrix describing top-left corner / origin of sprite, in pixels.
|
\\ UV coordinate transformation matrix describing top-left corner / origin of sprite, in pixels.
|
||||||
},
|
},
|
||||||
|
|
||||||
.{ .name = .size, .type = Vec2, .description =
|
.size = .{ .type = Vec2, .description =
|
||||||
\\ The size of the sprite, in pixels.
|
\\ The size of the sprite, in pixels.
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -28,52 +28,52 @@ pub const Mod = mach.Mod(@This());
|
||||||
// TODO: allow user to specify projection matrix (3d-space flat text etc.)
|
// TODO: allow user to specify projection matrix (3d-space flat text etc.)
|
||||||
|
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .pipeline, .type = u8, .description =
|
.pipeline = .{ .type = u8, .description =
|
||||||
\\ The ID of the pipeline this text belongs to. By default, zero.
|
\\ The ID of the pipeline this text belongs to. By default, zero.
|
||||||
\\
|
\\
|
||||||
\\ This determines which shader, textures, etc. are used for rendering the text.
|
\\ This determines which shader, textures, etc. are used for rendering the text.
|
||||||
},
|
},
|
||||||
|
|
||||||
.{ .name = .transform, .type = Mat4x4, .description =
|
.transform = .{ .type = Mat4x4, .description =
|
||||||
\\ The text model transformation matrix. Text is measured in pixel units, starting from
|
\\ The text model transformation matrix. Text is measured in pixel units, starting from
|
||||||
\\ (0, 0) at the top-left corner and extending to the size of the text. By default, the world
|
\\ (0, 0) at the top-left corner and extending to the size of the text. By default, the world
|
||||||
\\ origin (0, 0) lives at the center of the window.
|
\\ origin (0, 0) lives at the center of the window.
|
||||||
},
|
},
|
||||||
|
|
||||||
.{ .name = .text, .type = []const []const u8, .description =
|
.text = .{ .type = []const []const u8, .description =
|
||||||
\\ String segments of UTF-8 encoded text to render.
|
\\ String segments of UTF-8 encoded text to render.
|
||||||
\\
|
\\
|
||||||
\\ Expected to match the length of the style component.
|
\\ Expected to match the length of the style component.
|
||||||
},
|
},
|
||||||
|
|
||||||
.{ .name = .style, .type = []const mach.ecs.EntityID, .description =
|
.style = .{ .type = []const mach.ecs.EntityID, .description =
|
||||||
\\ The style to apply to each segment of text.
|
\\ The style to apply to each segment of text.
|
||||||
\\
|
\\
|
||||||
\\ Expected to match the length of the text component.
|
\\ Expected to match the length of the text component.
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: ship a default font
|
// TODO: ship a default font
|
||||||
.{ .name = .font_name, .type = []const u8, .description =
|
.font_name = .{ .type = []const u8, .description =
|
||||||
\\ Style component: desired font to render text with.
|
\\ Style component: desired font to render text with.
|
||||||
},
|
},
|
||||||
|
|
||||||
// e.g. 12 * mach.gfx.px_per_pt // 12pt
|
// e.g. 12 * mach.gfx.px_per_pt // 12pt
|
||||||
.{ .name = .font_size, .type = f32, .description =
|
.font_size = .{ .type = f32, .description =
|
||||||
\\ Style component: font size in pixels
|
\\ Style component: font size in pixels
|
||||||
},
|
},
|
||||||
|
|
||||||
// e.g. mach.gfx.font_weight_normal
|
// e.g. mach.gfx.font_weight_normal
|
||||||
.{ .name = .font_weight, .type = u16, .description =
|
.font_weight = .{ .type = u16, .description =
|
||||||
\\ Style component: font weight
|
\\ Style component: font weight
|
||||||
},
|
},
|
||||||
|
|
||||||
// e.g. false
|
// e.g. false
|
||||||
.{ .name = .italic, .type = bool, .description =
|
.italic = .{ .type = bool, .description =
|
||||||
\\ Style component: italic text
|
\\ Style component: italic text
|
||||||
},
|
},
|
||||||
|
|
||||||
// e.g. vec4(0, 0, 0, 1.0)
|
// e.g. vec4(0, 0, 0, 1.0)
|
||||||
.{ .name = .color, .type = Vec4, .description =
|
.color = .{ .type = Vec4, .description =
|
||||||
\\ Style component: fill color
|
\\ Style component: fill color
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -744,7 +744,7 @@ pub fn ComponentTypesByName(comptime modules: anytype) type {
|
||||||
const BuiltinMC = ComponentTypesM(struct {
|
const BuiltinMC = ComponentTypesM(struct {
|
||||||
pub const name = .builtin;
|
pub const name = .builtin;
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .id, .type = EntityID, .description = "Entity ID" },
|
.id = .{ .type = EntityID, .description = "Entity ID" },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
fields = fields ++ [_]std.builtin.Type.StructField{.{
|
fields = fields ++ [_]std.builtin.Type.StructField{.{
|
||||||
|
|
@ -779,42 +779,33 @@ fn ComponentTypesM(comptime M: anytype) type {
|
||||||
if (!@hasDecl(M, "components")) {
|
if (!@hasDecl(M, "components")) {
|
||||||
return struct {};
|
return struct {};
|
||||||
}
|
}
|
||||||
if (@typeInfo(@TypeOf(M.components)) != .Struct or !@typeInfo(@TypeOf(M.components)).Struct.is_tuple) {
|
if (@typeInfo(@TypeOf(M.components)) != .Struct or @typeInfo(@TypeOf(M.components)).Struct.is_tuple) {
|
||||||
@compileError(error_prefix ++ "expected a tuple of structs, found: " ++ @typeName(@TypeOf(M.components)));
|
@compileError(error_prefix ++ "expected a struct .{}, found: " ++ @typeName(@TypeOf(M.components)));
|
||||||
}
|
}
|
||||||
var fields: []const std.builtin.Type.StructField = &[0]std.builtin.Type.StructField{};
|
var fields: []const std.builtin.Type.StructField = &[0]std.builtin.Type.StructField{};
|
||||||
inline for (M.components, 0..) |component, i| {
|
inline for (@typeInfo(@TypeOf(M.components)).Struct.fields) |field| {
|
||||||
const Component = @TypeOf(component);
|
const Component = field.type;
|
||||||
if (@typeInfo(Component) != .Struct) @compileError(std.fmt.comptimePrint(
|
if (@typeInfo(Component) != .Struct) @compileError(std.fmt.comptimePrint(
|
||||||
error_prefix ++ "expected a tuple of structs, found tuple element ({}): {s}",
|
error_prefix ++ "expected .{s} = .{{}}, found type: {s}",
|
||||||
.{ i, @typeName(Component) },
|
.{ field.name, @typeName(Component) },
|
||||||
));
|
|
||||||
|
|
||||||
// Verify .name = .foo component name field
|
|
||||||
const name_tag = if (@hasField(Component, "name")) component.name else @compileError(std.fmt.comptimePrint(
|
|
||||||
error_prefix ++ "tuple element ({}) missing field `.name = .foo` (component name)",
|
|
||||||
.{i},
|
|
||||||
));
|
|
||||||
if (@typeInfo(@TypeOf(name_tag)) != .EnumLiteral) @compileError(std.fmt.comptimePrint(
|
|
||||||
error_prefix ++ "tuple element ({}) expected field `.name = .foo`, found: {s}",
|
|
||||||
.{ i, @typeName(@TypeOf(name_tag)) },
|
|
||||||
));
|
));
|
||||||
|
const component = @field(M.components, field.name);
|
||||||
|
|
||||||
// Verify .type = Foo, field
|
// Verify .type = Foo, field
|
||||||
if (!@hasField(Component, "type")) @compileError(std.fmt.comptimePrint(
|
if (!@hasField(Component, "type")) @compileError(std.fmt.comptimePrint(
|
||||||
error_prefix ++ "tuple element ({}) missing field `.type = Foo`",
|
error_prefix ++ ".{s} missing field `.type = T`",
|
||||||
.{i},
|
.{field.name},
|
||||||
));
|
));
|
||||||
if (@typeInfo(@TypeOf(component.type)) != .Type) @compileError(std.fmt.comptimePrint(
|
if (@typeInfo(@TypeOf(component.type)) != .Type) @compileError(std.fmt.comptimePrint(
|
||||||
error_prefix ++ "tuple element ({}) expected field `.type = Foo`, found: {s}",
|
error_prefix ++ ".{s} expected field `.type = T`, found: {s}",
|
||||||
.{ i, @typeName(@TypeOf(component.type)) },
|
.{ field.name, @typeName(@TypeOf(component.type)) },
|
||||||
));
|
));
|
||||||
|
|
||||||
const description = blk: {
|
const description = blk: {
|
||||||
if (@hasField(Component, "description")) {
|
if (@hasField(Component, "description")) {
|
||||||
if (!isString(@TypeOf(component.description))) @compileError(std.fmt.comptimePrint(
|
if (!isString(@TypeOf(component.description))) @compileError(std.fmt.comptimePrint(
|
||||||
error_prefix ++ "tuple element ({}) expected (optional) field `.description = \"foo\"`, found: {s}",
|
error_prefix ++ ".{s} expected (optional) field `.description = \"foo\"`, found: {s}",
|
||||||
.{ i, @typeName(@TypeOf(component.description)) },
|
.{ field.name, @typeName(@TypeOf(component.description)) },
|
||||||
));
|
));
|
||||||
break :blk component.description;
|
break :blk component.description;
|
||||||
} else break :blk null;
|
} else break :blk null;
|
||||||
|
|
@ -826,7 +817,7 @@ fn ComponentTypesM(comptime M: anytype) type {
|
||||||
};
|
};
|
||||||
const ns_component = NSComponent{ .type = component.type, .description = description };
|
const ns_component = NSComponent{ .type = component.type, .description = description };
|
||||||
fields = fields ++ [_]std.builtin.Type.StructField{.{
|
fields = fields ++ [_]std.builtin.Type.StructField{.{
|
||||||
.name = @tagName(name_tag),
|
.name = field.name,
|
||||||
.type = NSComponent,
|
.type = NSComponent,
|
||||||
.default_value = &ns_component,
|
.default_value = &ns_component,
|
||||||
.is_comptime = true,
|
.is_comptime = true,
|
||||||
|
|
@ -888,7 +879,7 @@ test ModuleInterface {
|
||||||
|
|
||||||
/// Physics module components
|
/// Physics module components
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .location, .type = @Vector(3, f32), .description = "A location component" },
|
.location = .{ .type = @Vector(3, f32), .description = "A location component" },
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
|
|
@ -909,7 +900,7 @@ test Modules {
|
||||||
|
|
||||||
/// Physics module components
|
/// Physics module components
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
.{ .name = .location, .type = @Vector(3, f32), .description = "A location component" },
|
.location = .{ .type = @Vector(3, f32), .description = "A location component" },
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
|
|
@ -925,9 +916,6 @@ test Modules {
|
||||||
.tick = .{ .handler = tick },
|
.tick = .{ .handler = tick },
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Renderer module components
|
|
||||||
pub const components = .{};
|
|
||||||
|
|
||||||
fn tick() !void {}
|
fn tick() !void {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -950,7 +938,6 @@ test Modules {
|
||||||
test "event name" {
|
test "event name" {
|
||||||
const Physics = ModuleInterface(struct {
|
const Physics = ModuleInterface(struct {
|
||||||
pub const name = .engine_physics;
|
pub const name = .engine_physics;
|
||||||
pub const components = .{};
|
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
.foo = .{ .handler = foo },
|
.foo = .{ .handler = foo },
|
||||||
.bar = .{ .handler = bar },
|
.bar = .{ .handler = bar },
|
||||||
|
|
@ -968,7 +955,6 @@ test "event name" {
|
||||||
|
|
||||||
const Renderer = ModuleInterface(struct {
|
const Renderer = ModuleInterface(struct {
|
||||||
pub const name = .engine_renderer;
|
pub const name = .engine_renderer;
|
||||||
pub const components = .{};
|
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
.foo_unused = .{ .handler = fn (f32, i32) void },
|
.foo_unused = .{ .handler = fn (f32, i32) void },
|
||||||
.bar_unused = .{ .handler = fn (i32, f32) void },
|
.bar_unused = .{ .handler = fn (i32, f32) void },
|
||||||
|
|
@ -1162,7 +1148,6 @@ test "event name calling" {
|
||||||
};
|
};
|
||||||
const Physics = ModuleInterface(struct {
|
const Physics = ModuleInterface(struct {
|
||||||
pub const name = .engine_physics;
|
pub const name = .engine_physics;
|
||||||
pub const components = .{};
|
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
.tick = .{ .handler = tick },
|
.tick = .{ .handler = tick },
|
||||||
};
|
};
|
||||||
|
|
@ -1185,7 +1170,6 @@ test "event name calling" {
|
||||||
});
|
});
|
||||||
const Renderer = ModuleInterface(struct {
|
const Renderer = ModuleInterface(struct {
|
||||||
pub const name = .engine_renderer;
|
pub const name = .engine_renderer;
|
||||||
pub const components = .{};
|
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
.tick = .{ .handler = tick },
|
.tick = .{ .handler = tick },
|
||||||
};
|
};
|
||||||
|
|
@ -1295,7 +1279,6 @@ test "dispatch" {
|
||||||
});
|
});
|
||||||
const Renderer = ModuleInterface(struct {
|
const Renderer = ModuleInterface(struct {
|
||||||
pub const name = .engine_renderer;
|
pub const name = .engine_renderer;
|
||||||
pub const components = .{};
|
|
||||||
pub const global_events = .{
|
pub const global_events = .{
|
||||||
.tick = .{ .handler = tick },
|
.tick = .{ .handler = tick },
|
||||||
.frame_done = .{ .handler = fn (i32) void },
|
.frame_done = .{ .handler = fn (i32) void },
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue