Compare commits

..

1 commit

Author SHA1 Message Date
Lorenzo Torres
e99779fcbc first steps towards porting to 0.16 2026-04-17 13:54:38 +02:00
9 changed files with 65 additions and 61 deletions

View file

@ -25,6 +25,10 @@ pub fn build(b: *std.Build) void {
.link_libc = true, .link_libc = true,
}); });
rendering.addIncludePath(b.path("ext")); rendering.addIncludePath(b.path("ext"));
if (target.result.os.tag == .macos) {
rendering.addSystemIncludePath(.{ .cwd_relative = "/usr/local/include" });
rendering.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" });
}
rendering.addCSourceFile(.{ .file = b.path("ext/stb_image.c") }); rendering.addCSourceFile(.{ .file = b.path("ext/stb_image.c") });
rendering.addImport("math", math); rendering.addImport("math", math);
@ -45,8 +49,12 @@ pub fn build(b: *std.Build) void {
.optimize = optimize, .optimize = optimize,
}), }),
}); });
sideros.addIncludePath(b.path("ext")); sideros.root_module.addIncludePath(b.path("ext"));
sideros.addIncludePath(b.path("src")); sideros.root_module.addIncludePath(b.path("src"));
if (target.result.os.tag == .macos) {
sideros.root_module.addSystemIncludePath(.{ .cwd_relative = "/usr/local/include" });
sideros.root_module.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" });
}
sideros.root_module.addImport("mods", mods); sideros.root_module.addImport("mods", mods);
sideros.root_module.addImport("ecs", ecs); sideros.root_module.addImport("ecs", ecs);
@ -71,18 +79,18 @@ pub fn build(b: *std.Build) void {
}), }),
}); });
exe.root_module.addIncludePath(b.path("src")); exe.root_module.addIncludePath(b.path("src"));
exe.linkLibrary(sideros); exe.root_module.linkLibrary(sideros);
exe.linkLibC(); exe.root_module.link_libc = true;
exe.linkSystemLibrary("vulkan"); exe.root_module.linkSystemLibrary("vulkan", .{ .needed = true });
if (wayland) { if (wayland) {
exe.root_module.addIncludePath(b.path("ext")); exe.root_module.addIncludePath(b.path("ext"));
exe.linkSystemLibrary("wayland-client"); exe.root_module.linkSystemLibrary("wayland-client", .{});
exe.linkSystemLibrary("xkbcommon"); exe.root_module.linkSystemLibrary("xkbcommon", .{});
exe.root_module.addCSourceFile(.{ .file = b.path("ext/xdg-shell.c") }); exe.root_module.addCSourceFile(.{ .file = b.path("ext/xdg-shell.c") });
} else { } else {
exe.linkSystemLibrary("xcb"); exe.root_module.linkSystemLibrary("xcb", .{});
exe.linkSystemLibrary("xcb-keysyms"); exe.root_module.linkSystemLibrary("xcb-keysyms", .{});
exe.linkSystemLibrary("xcb-icccm"); exe.root_module.linkSystemLibrary("xcb-icccm", .{});
} }
b.installArtifact(exe); b.installArtifact(exe);
@ -106,14 +114,14 @@ pub fn build(b: *std.Build) void {
}), }),
}); });
exe.root_module.addIncludePath(b.path("src")); exe.root_module.addIncludePath(b.path("src"));
exe.linkSystemLibrary("vulkan"); exe.root_module.linkSystemLibrary("vulkan", .{});
exe.root_module.addSystemIncludePath(.{ .cwd_relative = "/usr/local/include" }); exe.root_module.addSystemIncludePath(.{ .cwd_relative = "/usr/local/include" });
exe.root_module.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" }); exe.root_module.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" });
exe.root_module.addCSourceFile(.{.file = b.path("src/window.m")}); exe.root_module.addCSourceFile(.{.file = b.path("src/window.m")});
exe.root_module.linkFramework("Cocoa", .{}); exe.root_module.linkFramework("Cocoa", .{});
exe.root_module.linkFramework("Metal", .{}); exe.root_module.linkFramework("Metal", .{});
exe.root_module.linkFramework("QuartzCore", .{}); exe.root_module.linkFramework("QuartzCore", .{});
exe.linkLibrary(sideros); exe.root_module.linkLibrary(sideros);
b.installArtifact(exe); b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe); const run_cmd = b.addRunArtifact(exe);
@ -156,13 +164,10 @@ pub fn build(b: *std.Build) void {
} }
fn compileAllShaders(b: *std.Build, module: *std.Build.Module) void { fn compileAllShaders(b: *std.Build, module: *std.Build.Module) void {
const shaders_dir = if (@hasDecl(@TypeOf(b.build_root.handle), "openIterableDir")) const shaders_dir = b.build_root.handle.openDir(b.graph.io, "assets/shaders", .{ .iterate = true }) catch @panic("Failed to open shaders directory");
b.build_root.handle.openIterableDir("assets/shaders", .{}) catch @panic("Failed to open shaders directory")
else
b.build_root.handle.openDir("assets/shaders", .{ .iterate = true }) catch @panic("Failed to open shaders directory");
var file_it = shaders_dir.iterate(); var file_it = shaders_dir.iterate();
while (file_it.next() catch @panic("Failed to iterate shader directory")) |entry| { while (file_it.next(b.graph.io) catch @panic("Failed to iterate shader directory")) |entry| {
if (entry.kind == .file) { if (entry.kind == .file) {
const ext = std.fs.path.extension(entry.name); const ext = std.fs.path.extension(entry.name);
const basename = std.fs.path.basename(entry.name); const basename = std.fs.path.basename(entry.name);

View file

@ -33,27 +33,20 @@ pub const Pool = struct {
allocator: Allocator, allocator: Allocator,
system_groups: std.ArrayList(SystemGroup), system_groups: std.ArrayList(SystemGroup),
sync_groups: std.ArrayList(SyncGroup), sync_groups: std.ArrayList(SyncGroup),
thread_pool: *std.Thread.Pool, threaded_io: std.Io.Threaded,
wait_group: std.Thread.WaitGroup,
mutex: std.Thread.Mutex,
pub fn init(allocator: Allocator, resources: *Resources) !@This() { pub fn init(allocator: Allocator, resources: *Resources) !@This() {
var pool = @This(){ const pool = @This(){
.humans = .{}, .humans = .{},
.resources = resources, .resources = resources,
.system_groups = std.ArrayList(SystemGroup).empty, .system_groups = std.ArrayList(SystemGroup).empty,
.sync_groups = std.ArrayList(SystemGroup).empty, .sync_groups = std.ArrayList(SystemGroup).empty,
.thread_pool = try allocator.create(std.Thread.Pool), .threaded_io = .init(allocator, .{
.wait_group = .{}, .concurrent_limit = .limited(4),
.mutex = .{}, }),
.allocator = allocator, .allocator = allocator,
}; };
try pool.thread_pool.init(.{
.allocator = allocator,
.n_jobs = 4,
});
return pool; return pool;
} }
@ -70,28 +63,37 @@ pub const Pool = struct {
self.system_groups.deinit(self.allocator); self.system_groups.deinit(self.allocator);
self.sync_groups.deinit(self.allocator); self.sync_groups.deinit(self.allocator);
self.thread_pool.deinit(); self.threaded_io.deinit();
self.allocator.destroy(self.thread_pool);
} }
pub fn tick(self: *@This()) void { pub fn tick(self: *@This()) void {
const io = self.threaded_io.io();
var group: std.Io.Group = .init;
for (0..self.system_groups.items.len) |i| { for (0..self.system_groups.items.len) |i| {
self.thread_pool.spawnWg(&self.wait_group, struct { group.concurrent(io, struct {
fn run(pool: *Pool, index: usize) void { fn run(pool: *Pool, index: usize) std.Io.Cancelable!void {
const group = pool.system_groups.items[index]; const system_group = pool.system_groups.items[index];
for (group) |system| { for (system_group) |system| {
// TODO: system errors should be correctly handled // TODO: system errors should be correctly handled
system(pool) catch unreachable; system(pool) catch unreachable;
} }
} }
}.run, .{ self, i }); }.run, .{ self, i }) catch {
const system_group = self.system_groups.items[i];
for (system_group) |system| {
system(self) catch unreachable;
}
};
} }
for (0..self.sync_groups.items.len) |i| { for (0..self.sync_groups.items.len) |i| {
const group = self.sync_groups.items[i]; const system_group = self.sync_groups.items[i];
for (group) |system| { for (system_group) |system| {
system(self) catch unreachable; system(self) catch unreachable;
} }
} }
group.await(io) catch unreachable;
} }
fn getEntities(self: *@This(), T: type) *std.MultiArrayList(T) { fn getEntities(self: *@This(), T: type) *std.MultiArrayList(T) {

View file

@ -149,18 +149,18 @@ fn vulkan_cleanup(gameInit: sideros.GameInit) void {
//c.vkDestroyInstance(gameInit.instance, null); //c.vkDestroyInstance(gameInit.instance, null);
} }
pub fn main() !void { pub fn main(init: std.process.Init) !void {
create_window(); create_window();
const layer = get_metal_layer(); const layer = get_metal_layer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; var gpa: std.heap.DebugAllocator(.{}) = .init;
const allocator = gpa.allocator(); const allocator = gpa.allocator();
defer if (gpa.deinit() != .ok) @panic("Memory leaked"); defer if (gpa.deinit() != .ok) @panic("Memory leaked");
const gameInit = try vulkan_init(allocator, layer); const gameInit = try vulkan_init(allocator, layer);
defer vulkan_cleanup(gameInit); defer vulkan_cleanup(gameInit);
sideros.sideros_init(gameInit); sideros.sideros_init(init.io, gameInit);
while (!is_window_closed()) { while (!is_window_closed()) {
poll_cocoa_events(); poll_cocoa_events();

View file

@ -27,12 +27,9 @@ const DIndex = packed struct {
x: u32, x: u32,
y: u32, y: u32,
}; };
comptime {
// TODO: is this too big? we could do with 32 bits and a bit more indirection /// This intentionally remains tagless; the opcode determines how to interpret it.
std.debug.assert(@sizeOf(Index) == 8); const Index = union {
}
/// packed union has no tag
const Index = packed union {
u32: u32, u32: u32,
i32: i32, i32: i32,
u64: u64, u64: u64,

View file

@ -61,8 +61,8 @@ pub const Builder = struct {
}; };
} }
pub fn addMesh(self: *Builder, path: []const u8) !Mesh { pub fn addMesh(self: *Builder, io: std.Io, path: []const u8) !Mesh {
const gltf_data = try gltf.parseFile(self.allocator, path); const gltf_data = try gltf.parseFile(self.allocator, io, path);
const vertex_buffer = try createVertexBuffer(self.allocator, self.device, gltf_data); const vertex_buffer = try createVertexBuffer(self.allocator, self.device, gltf_data);
const index_buffer = try createIndexBuffer(self.allocator, self.device, gltf_data); const index_buffer = try createIndexBuffer(self.allocator, self.device, gltf_data);

View file

@ -20,10 +20,10 @@ terrain_pipeline: vk.TerrainPipeline,
current_frame: u32, current_frame: u32,
mesh: Mesh, mesh: Mesh,
transforms: std.ArrayList(math.Transform), transforms: std.ArrayList(math.Transform),
previous_time: std.time.Instant, previous_time: std.Io.Timestamp,
current_image: usize, current_image: usize,
pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Self { pub fn init(allocator: Allocator, io: std.Io, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Self {
const instance: vk.Instance = .{ .handle = instance_handle }; const instance: vk.Instance = .{ .handle = instance_handle };
const surface: vk.Surface = .{ .handle = surface_handle }; const surface: vk.Surface = .{ .handle = surface_handle };
var physical_device = try vk.PhysicalDevice.pick(allocator, instance); var physical_device = try vk.PhysicalDevice.pick(allocator, instance);
@ -48,7 +48,7 @@ pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_hand
_ = try pipeline_builder.addTexture(texture, diffuse); _ = try pipeline_builder.addTexture(texture, diffuse);
_ = try pipeline_builder.addTexture(texture, diffuse); _ = try pipeline_builder.addTexture(texture, diffuse);
const mesh = try pipeline_builder.addMesh("assets/models/cube.glb"); const mesh = try pipeline_builder.addMesh(io, "assets/models/cube.glb");
var graphics_pipeline = try pipeline_builder.build(swapchain, render_pass, vertex_shader, fragment_shader); var graphics_pipeline = try pipeline_builder.build(swapchain, render_pass, vertex_shader, fragment_shader);
const terrain_vertex_shader = try device.initShader("terrain_vert"); const terrain_vertex_shader = try device.initShader("terrain_vert");
@ -96,7 +96,7 @@ pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_hand
.terrain_pipeline = terrain_pipeline, .terrain_pipeline = terrain_pipeline,
.current_frame = 0, .current_frame = 0,
.transforms = transforms, .transforms = transforms,
.previous_time = try std.time.Instant.now(), .previous_time = std.Io.Timestamp.now(std.Io.Threaded.global_single_threaded.io(), .awake),
.mesh = mesh, .mesh = mesh,
.current_image = undefined, .current_image = undefined,
}; };

View file

@ -161,8 +161,8 @@ pub const Model = struct {
}; };
}; };
pub fn parseFile(allocator: Allocator, name: []const u8) !struct { vertices: [][3]f32, normals: [][3]f32, uvs: [][2]f32, indices: []u16 } { pub fn parseFile(allocator: Allocator, io: std.Io, name: []const u8) !struct { vertices: [][3]f32, normals: [][3]f32, uvs: [][2]f32, indices: []u16 } {
const file = try std.fs.cwd().openFile(name, .{}); const file = try std.Io.Dir.cwd().openFile(name, io, .{});
const all = try file.readToEndAlloc(allocator, 1_000_000); const all = try file.readToEndAlloc(allocator, 1_000_000);
defer allocator.free(all); defer allocator.free(all);
const json_chunk = std.mem.bytesAsValue(Model.Chunk, all[Model.Header.offset..]); const json_chunk = std.mem.bytesAsValue(Model.Chunk, all[Model.Header.offset..]);

View file

@ -12,7 +12,7 @@ const std = @import("std");
const systems = @import("systems.zig"); const systems = @import("systems.zig");
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; var gpa: std.heap.DebugAllocator(.{}) = .{};
const allocator = gpa.allocator(); const allocator = gpa.allocator();
var pool: ecs.Pool = undefined; var pool: ecs.Pool = undefined;
var renderer: Renderer = undefined; var renderer: Renderer = undefined;
@ -26,7 +26,7 @@ const ModInfo = struct {
runtime: *mods.Runtime, runtime: *mods.Runtime,
modIdx: u32, modIdx: u32,
}; };
var loadedMods: std.ArrayListUnmanaged(ModInfo) = .{}; var loadedMods: std.ArrayListUnmanaged(ModInfo) = .empty;
fn openOrCreateDir(fs: std.fs.Dir, path: []const u8) !std.fs.Dir { fn openOrCreateDir(fs: std.fs.Dir, path: []const u8) !std.fs.Dir {
var dir: std.fs.Dir = undefined; var dir: std.fs.Dir = undefined;
@ -133,7 +133,7 @@ fn init_mods() void {
} }
} }
export fn sideros_init(init: api.GameInit) callconv(.c) void { fn sideros_init(io: std.Io, init: api.GameInit) void {
resources = .{ resources = .{
.camera = &camera, .camera = &camera,
.renderer = undefined, .renderer = undefined,
@ -145,7 +145,7 @@ export fn sideros_init(init: api.GameInit) callconv(.c) void {
ecs.hooks.addHook(.scroll, systems.zoomCamera) catch @panic("TODO handle this"); ecs.hooks.addHook(.scroll, systems.zoomCamera) catch @panic("TODO handle this");
pool = ecs.Pool.init(allocator, &resources) catch @panic("TODO: Gracefully handle error"); pool = ecs.Pool.init(allocator, &resources) catch @panic("TODO: Gracefully handle error");
// TODO(ernesto): I think this @ptrCast are unavoidable but maybe not? // TODO(ernesto): I think this @ptrCast are unavoidable but maybe not?
renderer = Renderer.init(allocator, @ptrCast(init.instance), @ptrCast(init.surface)) catch |err| std.debug.panic("TODO: Gracefully handle error: {}\n", .{err}); renderer = Renderer.init(allocator, io, @ptrCast(init.instance), @ptrCast(init.surface)) catch |err| std.debug.panic("TODO: Gracefully handle error: {}\n", .{err});
resources.terrain = rendering.Terrain.init(allocator, renderer.device, .{ resources.terrain = rendering.Terrain.init(allocator, renderer.device, .{
.octaves = 8, .octaves = 8,

View file

@ -8,8 +8,8 @@ pub fn render(pool: *ecs.Pool) anyerror!void {
const camera = pool.resources.camera; const camera = pool.resources.camera;
const terrain = pool.resources.terrain; const terrain = pool.resources.terrain;
const now = try std.time.Instant.now(); const now = std.Io.Timestamp.now(pool.threaded_io.io(), .awake);
const delta_time: f32 = @as(f32, @floatFromInt(now.since(renderer.previous_time))) / @as(f32, 1_000_000_000.0); const delta_time: f32 = @as(f32, @floatFromInt(renderer.previous_time.durationTo(now).toNanoseconds())) / @as(f32, 1_000_000_000.0);
pool.resources.delta_time = delta_time; pool.resources.delta_time = delta_time;
renderer.previous_time = now; renderer.previous_time = now;