all: move standalone libraries to libs/ subdirectory

The root dir of our repository has grown quite a lot the past few months.

I'd like to make it more clear where the bulk of the engine lives (`src/`) and
also make it more clear which Mach libraries are consumable as standalone projects.

As for the name of this directory, `libs` was my first choice but there's a bit of
a convention of that being external libraries in Zig projects _today_, while these
are libraries maintained as part of Mach in this repository - not external ones.

We will name this directory `libs`, and if we have a need for external libraries
we will use `external` or `deps` for that directory name. I considered other names
such as `components`, `systems`, `modules` (which are bad as they overlap with
major ECS / engine concepts), and it seems likely the official Zig package manager
will break the convention of using a `libs` dir anyway.

Performed via:

```sh
mkdir libs/
git mv freetype libs/
git mv basisu libs/
git mv gamemode libs/
git mv glfw libs/
git mv gpu libs/
git mv gpu-dawn libs/
git mv sysaudio libs/
git mv sysjs libs/
git mv ecs libs/
```

git-subtree-dir: glfw
git-subtree-mainline: 0d5b853443
git-subtree-split: 572d1144f11b353abdb64fff828b25a4f0fbb7ca

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>

git mv ecs libs/

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
Stephen Gutekanst 2022-08-26 13:29:04 -07:00 committed by Stephen Gutekanst
parent 79ec61396f
commit 0645429df9
240 changed files with 6 additions and 6 deletions

291
libs/ecs/src/systems.zig Normal file
View file

@ -0,0 +1,291 @@
const std = @import("std");
const mem = std.mem;
const Allocator = mem.Allocator;
const testing = std.testing;
const math = std.math;
const StructField = std.builtin.Type.StructField;
const EnumField = std.builtin.Type.EnumField;
const UnionField = std.builtin.Type.UnionField;
const Entities = @import("entities.zig").Entities;
/// An ECS module can provide components, systems, and global values.
pub fn Module(comptime Params: anytype) @TypeOf(Params) {
// TODO: validate the type
return Params;
}
/// Describes a set of ECS modules, each of which can provide components, systems, and more.
pub fn Modules(modules: anytype) @TypeOf(modules) {
// TODO: validate the type
return modules;
}
/// Returns a tagged union representing the messages, turning this:
///
/// ```
/// .{ .tick = void, .foo = i32 }
/// ```
///
/// Into `T`:
///
/// ```
/// const T = union(MessagesTag(messages)) {
/// .tick = void,
/// .foo = i32,
/// };
/// ```
pub fn Messages(messages: anytype) type {
var fields: []const UnionField = &[0]UnionField{};
const message_fields = std.meta.fields(@TypeOf(messages));
inline for (message_fields) |message_field| {
const message_type = @field(messages, message_field.name);
fields = fields ++ [_]std.builtin.Type.UnionField{.{
.name = message_field.name,
.field_type = message_type,
.alignment = if (message_type == void) 0 else @alignOf(message_type),
}};
}
// Hack to workaround stage1 compiler bug. https://github.com/ziglang/zig/issues/8114
//
// return @Type(.{
// .Union = .{
// .layout = .Auto,
// .tag_type = MessagesTag(messages),
// .fields = fields,
// .decls = &[_]std.builtin.Type.Declaration{},
// },
// });
//
const Ref = union(enum) { temp };
var info = @typeInfo(Ref);
info.Union.tag_type = MessagesTag(messages);
info.Union.fields = fields;
return @Type(info);
}
/// Returns the tag enum for a tagged union representing the messages, turning this:
///
/// ```
/// .{ .tick = void, .foo = i32 }
/// ```
///
/// Into this:
///
/// ```
/// enum { .tick, .foo };
/// ```
pub fn MessagesTag(messages: anytype) type {
var fields: []const EnumField = &[0]EnumField{};
const message_fields = std.meta.fields(@TypeOf(messages));
inline for (message_fields) |message_field, index| {
fields = fields ++ [_]std.builtin.Type.EnumField{.{
.name = message_field.name,
.value = index,
}};
}
return @Type(.{
.Enum = .{
.layout = .Auto,
.tag_type = std.meta.Int(.unsigned, @floatToInt(u16, math.ceil(math.log2(@intToFloat(f64, message_fields.len))))),
.fields = fields,
.decls = &[_]std.builtin.Type.Declaration{},
.is_exhaustive = true,
},
});
}
/// Returns the namespaced components struct **type**.
//
/// Consult `namespacedComponents` for how a value of this type looks.
fn NamespacedComponents(comptime modules: anytype) type {
var fields: []const StructField = &[0]StructField{};
inline for (std.meta.fields(@TypeOf(modules))) |module_field| {
const module = @field(modules, module_field.name);
if (@hasField(@TypeOf(module), "components")) {
fields = fields ++ [_]std.builtin.Type.StructField{.{
.name = module_field.name,
.field_type = @TypeOf(module.components),
.default_value = null,
.is_comptime = false,
.alignment = @alignOf(@TypeOf(module.components)),
}};
}
}
return @Type(.{
.Struct = .{
.layout = .Auto,
.is_tuple = false,
.fields = fields,
.decls = &[_]std.builtin.Type.Declaration{},
},
});
}
/// Extracts namespaces components from modules like this:
///
/// ```
/// .{
/// .renderer = .{
/// .components = .{
/// .location = Vec3,
/// .rotation = Vec3,
/// },
/// ...
/// },
/// .physics2d = .{
/// .components = .{
/// .location = Vec2
/// .velocity = Vec2,
/// },
/// ...
/// },
/// }
/// ```
///
/// Returning a namespaced components value like this:
///
/// ```
/// .{
/// .renderer = .{
/// .location = Vec3,
/// .rotation = Vec3,
/// },
/// .physics2d = .{
/// .location = Vec2
/// .velocity = Vec2,
/// },
/// }
/// ```
///
fn namespacedComponents(comptime modules: anytype) NamespacedComponents(modules) {
var x: NamespacedComponents(modules) = undefined;
inline for (std.meta.fields(@TypeOf(modules))) |module_field| {
const module = @field(modules, module_field.name);
if (@hasField(@TypeOf(module), "components")) {
@field(x, module_field.name) = module.components;
}
}
return x;
}
/// Extracts namespaced globals from modules like this:
///
/// ```
/// .{
/// .renderer = .{
/// .globals = struct{
/// foo: *Bar,
/// baz: Bam,
/// },
/// ...
/// },
/// .physics2d = .{
/// .globals = struct{
/// foo: *Instance,
/// },
/// ...
/// },
/// }
/// ```
///
/// Into a namespaced global type like this:
///
/// ```
/// struct{
/// renderer: struct{
/// foo: *Bar,
/// baz: Bam,
/// },
/// physics2d: struct{
/// foo: *Instance,
/// },
/// }
/// ```
///
fn NamespacedGlobals(comptime modules: anytype) type {
var fields: []const StructField = &[0]StructField{};
inline for (std.meta.fields(@TypeOf(modules))) |module_field| {
const module = @field(modules, module_field.name);
if (@hasField(@TypeOf(module), "globals")) {
fields = fields ++ [_]std.builtin.Type.StructField{.{
.name = module_field.name,
.field_type = module.globals,
.default_value = null,
.is_comptime = false,
.alignment = @alignOf(module.globals),
}};
}
}
return @Type(.{
.Struct = .{
.layout = .Auto,
.is_tuple = false,
.fields = fields,
.decls = &[_]std.builtin.Type.Declaration{},
},
});
}
pub fn World(comptime modules: anytype) type {
const all_components = namespacedComponents(modules);
return struct {
allocator: Allocator,
entities: Entities(all_components),
globals: NamespacedGlobals(modules),
const Self = @This();
pub fn init(allocator: Allocator) !Self {
return Self{
.allocator = allocator,
.entities = try Entities(all_components).init(allocator),
.globals = undefined,
};
}
pub fn deinit(world: *Self) void {
world.entities.deinit();
}
/// Gets a global value called `.global_tag` from the module named `.module_tag`
pub fn get(world: *Self, module_tag: anytype, global_tag: anytype) @TypeOf(@field(
@field(world.globals, @tagName(module_tag)),
@tagName(global_tag),
)) {
return comptime @field(
@field(world.globals, @tagName(module_tag)),
@tagName(global_tag),
);
}
/// Sets a global value called `.global_tag` in the module named `.module_tag`
pub fn set(
world: *Self,
comptime module_tag: anytype,
comptime global_tag: anytype,
value: @TypeOf(@field(
@field(world.globals, @tagName(module_tag)),
@tagName(global_tag),
)),
) void {
comptime @field(
@field(world.globals, @tagName(module_tag)),
@tagName(global_tag),
) = value;
}
/// Tick sends the global 'tick' message to all modules that are subscribed to it.
pub fn tick(world: *Self) void {
_ = world;
inline for (std.meta.fields(@TypeOf(modules))) |module_field| {
const module = @field(modules, module_field.name);
if (@hasField(@TypeOf(module), "messages")) {
if (@hasField(module.messages, "tick")) module.update(.tick);
}
}
}
};
}