Made Renderer a separate module

This commit is contained in:
Lorenzo Torres 2025-03-27 21:42:46 +01:00
parent 09691ec4d9
commit 1730f1e298
14 changed files with 292 additions and 260 deletions

View file

@ -55,17 +55,28 @@ pub fn build(b: *std.Build) void {
}, .flags = &[_][]const u8{ "-D_GLFW_X11", "-Wall", "-Wextra" } });
glfw.linkLibC();
const sideros = b.addModule("sideros", .{
.root_source_file = b.path("src/sideros.zig"),
.target = target,
.optimize = optimize,
});
const mods = b.addModule("mods", .{
.root_source_file = b.path("src/mods/mods.zig"),
.target = target,
.optimize = optimize,
});
mods.addImport("sideros", sideros);
const ecs = b.addModule("ecs", .{
.root_source_file = b.path("src/ecs/ecs.zig"),
const renderer = b.addModule("renderer", .{
.root_source_file = b.path("src/renderer/Renderer.zig"),
.target = target,
.optimize = optimize,
});
renderer.addImport("sideros", sideros);
renderer.addIncludePath(b.path("ext/glfw/include"));
compileAllShaders(b, renderer);
const exe = b.addExecutable(.{
.root_source_file = b.path("src/main.zig"),
@ -74,11 +85,10 @@ pub fn build(b: *std.Build) void {
.name = "sideros",
});
exe.root_module.addImport("mods", mods);
exe.root_module.addImport("ecs", ecs);
exe.addIncludePath(b.path("ext/glfw/include"));
exe.root_module.addImport("sideros", sideros);
exe.root_module.addImport("renderer", renderer);
exe.linkSystemLibrary("vulkan");
compileAllShaders(b, exe);
exe.linkLibrary(glfw);
exe.linkLibC();
@ -127,7 +137,7 @@ pub fn build(b: *std.Build) void {
test_step.dependOn(&run_exe_unit_tests.step);
}
fn compileAllShaders(b: *std.Build, exe: *std.Build.Step.Compile) void {
fn compileAllShaders(b: *std.Build, module: *std.Build.Module) void {
const shaders_dir = if (@hasDecl(@TypeOf(b.build_root.handle), "openIterableDir"))
b.build_root.handle.openIterableDir("assets/shaders", .{}) catch @panic("Failed to open shaders directory")
else
@ -140,15 +150,15 @@ fn compileAllShaders(b: *std.Build, exe: *std.Build.Step.Compile) void {
const basename = std.fs.path.basename(entry.name);
const name = basename[0 .. basename.len - ext.len];
if (std.mem.eql(u8, ext, ".vert")) {
addShader(b, exe, name, .vertex);
addShader(b, module, name, .vertex);
} else if (std.mem.eql(u8, ext, ".frag")) {
addShader(b, exe, name, .fragment);
addShader(b, module, name, .fragment);
}
}
}
}
fn addShader(b: *std.Build, exe: *std.Build.Step.Compile, name: []const u8, stage: ShaderStage) void {
fn addShader(b: *std.Build, module: *std.Build.Module, name: []const u8, stage: ShaderStage) void {
const mod_name = std.fmt.allocPrint(b.allocator, "{s}_{s}", .{ name, if (stage == .vertex) "vert" else "frag" }) catch @panic("");
const source = std.fmt.allocPrint(b.allocator, "assets/shaders/{s}.{s}", .{ name, if (stage == .vertex) "vert" else "frag" }) catch @panic("");
const outpath = std.fmt.allocPrint(b.allocator, "assets/shaders/{s}_{s}.spv", .{ name, if (stage == .vertex) "vert" else "frag" }) catch @panic("");
@ -158,5 +168,5 @@ fn addShader(b: *std.Build, exe: *std.Build.Step.Compile, name: []const u8, stag
const output = shader_compilation.addOutputFileArg(outpath);
shader_compilation.addFileArg(b.path(source));
exe.root_module.addAnonymousImport(mod_name, .{ .root_source_file = output });
module.addAnonymousImport(mod_name, .{ .root_source_file = output });
}

View file

@ -2,5 +2,6 @@ pub const components = @import("components.zig");
const entities = @import("entities.zig");
pub const Pool = entities.Pool;
pub const Resources = entities.Resources;
pub const System = *const fn (*Pool) void;
pub const SystemGroup = []const System;

View file

@ -2,15 +2,21 @@ const std = @import("std");
const Allocator = std.mem.Allocator;
const components = @import("components.zig");
const sparse = @import("sparse.zig");
const Renderer = @import("renderer");
pub const System = *const fn (*Pool) void;
pub const SystemGroup = []const System;
pub const Resources = struct {
window: Renderer.Window,
renderer: Renderer,
};
pub const Pool = struct {
// Components
position: sparse.SparseSet(components.Position),
speed: sparse.SparseSet(components.Speed),
resources: Resources,
system_groups: std.ArrayList(SystemGroup),
thread_pool: *std.Thread.Pool,
wait_group: std.Thread.WaitGroup,
@ -20,11 +26,11 @@ pub const Pool = struct {
component_flags: std.AutoHashMap(usize, usize),
pub fn init(allocator: Allocator) !@This() {
pub fn init(allocator: Allocator, resources: Resources) !@This() {
var pool = @This(){
.position = sparse.SparseSet(components.Position).init(allocator),
.speed = sparse.SparseSet(components.Speed).init(allocator),
.resources = resources,
.system_groups = std.ArrayList(SystemGroup).init(allocator),
.thread_pool = try allocator.create(std.Thread.Pool),
.wait_group = .{},

View file

@ -1,13 +1,10 @@
const std = @import("std");
const c = @import("c.zig");
const window = @import("rendering/window.zig");
const config = @import("config");
const Renderer = @import("rendering/renderer_vulkan.zig");
const math = @import("math.zig");
const math = @import("sideros").math;
const mods = @import("mods");
const ecs = @import("ecs");
const gltf = @import("rendering/gltf.zig");
const ecs = @import("ecs/ecs.zig");
pub const Renderer = @import("renderer");
fn testSystem2(pool: *ecs.Pool) void {
for (pool.getQuery(ecs.components.Position), 0..) |position, i| {
@ -23,52 +20,47 @@ pub fn main() !void {
const allocator = gpa.allocator();
defer if (gpa.deinit() != .ok) @panic("Leaked memory");
var global_runtime = mods.GlobalRuntime.init(allocator);
defer global_runtime.deinit();
try global_runtime.addFunction("debug", mods.Wasm.debug);
//var global_runtime = mods.GlobalRuntime.init(allocator);
//defer global_runtime.deinit();
//try global_runtime.addFunction("debug", mods.Wasm.debug);
const file = try std.fs.cwd().openFile("assets/core.wasm", .{});
const all = try file.readToEndAlloc(allocator, 1_000_000); // 1 MB
var parser = mods.Parser{
.bytes = all,
.byte_idx = 0,
.allocator = allocator,
};
const module = parser.parseModule() catch |err| {
std.debug.print("[ERROR]: error at byte {x}(0x{x})\n", .{ parser.byte_idx, parser.bytes[parser.byte_idx] });
return err;
};
var runtime = try mods.Runtime.init(allocator, module, &global_runtime);
defer runtime.deinit(allocator);
//const file = try std.fs.cwd().openFile("assets/core.wasm", .{});
//const all = try file.readToEndAlloc(allocator, 1_000_000); // 1 MB
//var parser = mods.Parser{
// .bytes = all,
// .byte_idx = 0,
// .allocator = allocator,
//};
//const module = parser.parseModule() catch |err| {
// std.debug.print("[ERROR]: error at byte {x}(0x{x})\n", .{ parser.byte_idx, parser.bytes[parser.byte_idx] });
// return err;
//};
//var runtime = try mods.Runtime.init(allocator, module, &global_runtime);
//defer runtime.deinit(allocator);
var parameters = [_]usize{};
try runtime.callExternal(allocator, "preinit", &parameters);
const w = try window.Window.create(800, 600, "sideros");
//var parameters = [_]usize{};
//try runtime.callExternal(allocator, "preinit", &parameters);
const w = try Renderer.Window.create(800, 600, "sideros");
defer w.destroy();
// var pool = try ecs.Pool.init(allocator);
// defer pool.deinit(allocator);
//try pool.addSystemGroup(&[_]entities.System{
// testSystem,
//});
// try pool.addSystemGroup(&[_]ecs.System{
// testSystem2,
// });
// for (0..1000) |_| {
// const entity = try pool.createEntity();
// try pool.addComponent(entity, ecs.components.Position{ .x = 1.0, .y = 0.5, .z = 3.0 });
// try pool.addComponent(entity, ecs.components.Speed{ .speed = 5.0 });
// }
// TODO(luccie-cmd): Renderer.create shouldn't return an error
// var r = try Renderer.create(allocator, w);
// defer r.destroy();
var r = try Renderer.create(allocator, w);
defer r.destroy();
// while (!w.shouldClose()) {
// c.glfwPollEvents();
// try r.tick();
// pool.tick();
// }
const resources = ecs.Resources{
.window = w,
.renderer = r,
};
var pool = try ecs.Pool.init(allocator, resources);
defer pool.deinit(allocator);
try pool.addSystemGroup(&[_]ecs.System{
testSystem2,
});
while (!w.shouldClose()) {
try r.tick();
pool.tick();
}
}

21
src/renderer/Camera.zig Normal file
View file

@ -0,0 +1,21 @@
const std = @import("std");
const ecs = @import("ecs");
const math = @import("../math.zig");
const Camera = @This();
const UP = @Vector(3, f32){ 0.0, 1.0, 0.0 };
pub const Uniform = struct {
proj: math.Matrix,
view: math.Matrix,
model: math.Matrix,
};
uniform: Uniform,
position: @Vector(3, f32),
target: @Vector(3, f32),
direction: @Vector(3, f32),
right: @Vector(3, f32),
up: @Vector(3, f32),
fn input(pool: *ecs.Pool) void {
}

119
src/renderer/Mesh.zig Normal file
View file

@ -0,0 +1,119 @@
const c = @import("c.zig");
const std = @import("std");
const vk = @import("vulkan.zig");
const gltf = @import("gltf.zig");
const Allocator = std.mem.Allocator;
const Mesh = @This();
pub const Vertex = struct {
position: [3]f32,
pub fn create(x: f32, y: f32, z: f32) Vertex {
return Vertex{
.position = .{ x, y, z },
};
}
pub fn bindingDescription() c.VkVertexInputBindingDescription {
const binding_description: c.VkVertexInputBindingDescription = .{
.binding = 0,
.stride = @sizeOf(Vertex),
.inputRate = c.VK_VERTEX_INPUT_RATE_VERTEX,
};
return binding_description;
}
pub fn attributeDescription() c.VkVertexInputAttributeDescription {
const attribute_description: c.VkVertexInputAttributeDescription = .{
.location = 0,
.binding = 0,
.format = c.VK_FORMAT_R32G32B32_SFLOAT,
.offset = 0,
};
return attribute_description;
}
};
vertex_buffer: vk.Buffer,
index_buffer: vk.Buffer,
pub fn createVertexBuffer(allocator: Allocator, device: anytype) !vk.Buffer {
const gltf_data = try gltf.parseFile(allocator, "assets/models/block.glb");
const vertices = gltf_data.vertices;
var data: [*c]?*anyopaque = null;
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf(Vertex) * vertices.len);
try vk.mapError(c.vkMapMemory(
device.handle,
buffer.memory,
0,
buffer.size,
0,
@ptrCast(&data),
));
if (data) |ptr| {
const gpu_vertices: [*]Vertex = @ptrCast(@alignCast(ptr));
@memcpy(gpu_vertices, @as([]Vertex, @ptrCast(vertices[0..])));
}
c.vkUnmapMemory(device.handle, buffer.memory);
const vertex_buffer = try device.createBuffer(vk.BufferUsage{ .vertex_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(Vertex) * vertices.len);
try buffer.copyTo(device, vertex_buffer);
buffer.destroy(device.handle);
return vertex_buffer;
}
pub fn createIndexBuffer(allocator: Allocator, device: anytype) !vk.Buffer {
const gltf_data = try gltf.parseFile(allocator, "assets/models/block.glb");
const indices = gltf_data.indices;
//const indices = [_]u16{ 0, 1, 2, 3, 0, 2 };
var data: [*c]?*anyopaque = null;
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf(u16) * indices.len);
try vk.mapError(c.vkMapMemory(
device.handle,
buffer.memory,
0,
buffer.size,
0,
@ptrCast(&data),
));
if (data) |ptr| {
const gpu_indices: [*]u16 = @ptrCast(@alignCast(ptr));
@memcpy(gpu_indices, indices[0..]);
}
c.vkUnmapMemory(device.handle, buffer.memory);
const index_buffer = try device.createBuffer(vk.BufferUsage{ .index_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(u16) * indices.len);
try buffer.copyTo(device, index_buffer);
buffer.destroy(device.handle);
return index_buffer;
}
pub fn create(allocator: Allocator, device: anytype) !Mesh {
const vertex_buffer = try Mesh.createVertexBuffer(allocator, device);
const index_buffer = try Mesh.createIndexBuffer(allocator, device);
return Mesh{
.vertex_buffer = vertex_buffer,
.index_buffer = index_buffer,
};
}

View file

@ -1,8 +1,8 @@
const c = @import("../c.zig");
const c = @import("c.zig");
const std = @import("std");
const vk = @import("vulkan.zig");
const window = @import("window.zig");
const mesh = @import("mesh.zig");
pub const Window = @import("Window.zig");
pub const Mesh = @import("Mesh.zig");
const Allocator = std.mem.Allocator;
const Renderer = @This();
@ -18,7 +18,7 @@ current_frame: u32,
vertex_buffer: vk.Buffer,
index_buffer: vk.Buffer,
pub fn create(allocator: Allocator, w: window.Window) !Renderer {
pub fn create(allocator: Allocator, w: Window) !Renderer {
const instance = try vk.Instance.create(allocator);
const surface = try vk.Surface.create(instance, w);
@ -44,7 +44,7 @@ pub fn create(allocator: Allocator, w: window.Window) !Renderer {
// renderer.render(some_other_thing);
// ...
// renderer.submit()
const triangle = try mesh.Mesh.create(allocator, device);
const triangle = try Mesh.create(allocator, device);
return Renderer{
.instance = instance,

64
src/renderer/Window.zig Normal file
View file

@ -0,0 +1,64 @@
const c = @import("c.zig");
const std = @import("std");
const Window = @This();
pub const Error = error{
platform_unavailable,
platform_error,
};
pub fn getExtensions() [][*c]const u8 {
var extension_count: u32 = undefined;
const raw: [*c][*c]const u8 = c.glfwGetRequiredInstanceExtensions(&extension_count);
const extensions = raw[0..extension_count];
return extensions;
}
title: []const u8,
width: usize,
height: usize,
raw: *c.GLFWwindow,
pub fn create(width: usize, height: usize, title: []const u8) !Window {
if (c.glfwInit() != c.GLFW_TRUE) {
const status = c.glfwGetError(null);
return switch (status) {
c.GLFW_PLATFORM_UNAVAILABLE => Error.platform_unavailable,
c.GLFW_PLATFORM_ERROR => Error.platform_error,
else => unreachable,
};
}
c.glfwWindowHint(c.GLFW_RESIZABLE, c.GLFW_FALSE);
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API);
const raw = c.glfwCreateWindow(@intCast(width), @intCast(height), title.ptr, null, null);
c.glfwShowWindow(raw);
return Window{
.title = title,
.width = width,
.height = height,
.raw = raw.?,
};
}
pub fn shouldClose(self: Window) bool {
return c.glfwWindowShouldClose(self.raw) == c.GLFW_TRUE;
}
pub fn size(self: Window) struct { usize, usize } {
var width: u32 = undefined;
var height: u32 = undefined;
c.glfwGetFramebufferSize(self.raw, @ptrCast(&width), @ptrCast(&height));
return .{ @intCast(width), @intCast(height) };
}
pub fn destroy(self: Window) void {
c.glfwDestroyWindow(self.raw);
c.glfwTerminate();
}

View file

@ -1,5 +1,5 @@
const std = @import("std");
const mesh = @import("mesh.zig");
const Mesh = @import("Mesh.zig");
const Allocator = std.mem.Allocator;
pub const Model = struct {
@ -106,7 +106,7 @@ pub const Model = struct {
scenes: ?[]Scene = null,
nodes: ?[]Node = null,
materials: ?[]Material = null,
meshes: ?[]Mesh = null,
meshes: ?[]Model.Mesh = null,
accessors: ?[]Accessor = null,
bufferViews: ?[]BufferView = null,
buffers: ?[]Buffer = null,

View file

@ -1,8 +1,9 @@
const std = @import("std");
const c = @import("../c.zig");
const window = @import("./window.zig");
const mesh = @import("./mesh.zig");
const math = @import("../math.zig");
const c = @import("c.zig");
const Window = @import("Window.zig");
const Mesh = @import("Mesh.zig");
const sideros = @import("sideros");
const math = sideros.math;
const Allocator = std.mem.Allocator;
const builtin = @import("builtin");
@ -71,7 +72,7 @@ pub const Instance = struct {
handle: c.VkInstance,
pub fn create(allocator: Allocator) !Instance {
const extensions = window.getExtensions();
const extensions = Window.getExtensions();
// Querry avaliable extensions size
var avaliableExtensionsCount: u32 = 0;
@ -323,8 +324,8 @@ pub fn GraphicsPipeline(comptime n: usize) type {
// TODO: shouldn't this be closer to usage?
const shader_stage_infos: []const c.VkPipelineShaderStageCreateInfo = &.{ vertex_shader_stage_info, fragment_shader_stage_info };
const vertex_attributes: []const c.VkVertexInputAttributeDescription = &.{mesh.Vertex.attributeDescription()};
const vertex_bindings: []const c.VkVertexInputBindingDescription = &.{mesh.Vertex.bindingDescription()};
const vertex_attributes: []const c.VkVertexInputAttributeDescription = &.{Mesh.Vertex.attributeDescription()};
const vertex_bindings: []const c.VkVertexInputBindingDescription = &.{Mesh.Vertex.bindingDescription()};
const vertex_input_info: c.VkPipelineVertexInputStateCreateInfo = .{
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
@ -613,7 +614,7 @@ pub fn Swapchain(comptime n: usize) type {
}
// TODO: Allow to recreate so Window can be resized
pub fn create(allocator: Allocator, surface: Surface, device: Device(n), physical_device: PhysicalDevice, w: window.Window, render_pass: RenderPass(n)) !Self {
pub fn create(allocator: Allocator, surface: Surface, device: Device(n), physical_device: PhysicalDevice, w: Window, render_pass: RenderPass(n)) !Self {
const present_modes = try surface.presentModes(allocator, physical_device);
defer allocator.free(present_modes);
const capabilities = try surface.capabilities(physical_device);
@ -765,7 +766,7 @@ pub fn Swapchain(comptime n: usize) type {
pub const Surface = struct {
handle: c.VkSurfaceKHR,
pub fn create(instance: Instance, w: window.Window) !Surface {
pub fn create(instance: Instance, w: Window) !Surface {
var handle: c.VkSurfaceKHR = undefined;
try mapError(c.glfwCreateWindowSurface(instance.handle, w.raw, null, &handle));
return Surface{

View file

@ -1,119 +0,0 @@
const c = @import("../c.zig");
const std = @import("std");
const vk = @import("vulkan.zig");
const gltf = @import("gltf.zig");
const Allocator = std.mem.Allocator;
pub const Vertex = struct {
position: [3]f32,
pub fn create(x: f32, y: f32, z: f32) Vertex {
return Vertex{
.position = .{ x, y, z },
};
}
pub fn bindingDescription() c.VkVertexInputBindingDescription {
const binding_description: c.VkVertexInputBindingDescription = .{
.binding = 0,
.stride = @sizeOf(Vertex),
.inputRate = c.VK_VERTEX_INPUT_RATE_VERTEX,
};
return binding_description;
}
pub fn attributeDescription() c.VkVertexInputAttributeDescription {
const attribute_description: c.VkVertexInputAttributeDescription = .{
.location = 0,
.binding = 0,
.format = c.VK_FORMAT_R32G32B32_SFLOAT,
.offset = 0,
};
return attribute_description;
}
};
pub const Mesh = struct {
vertex_buffer: vk.Buffer,
index_buffer: vk.Buffer,
pub fn createVertexBuffer(allocator: Allocator, device: anytype) !vk.Buffer {
const gltf_data = try gltf.parseFile(allocator, "assets/models/block.glb");
const vertices = gltf_data.vertices;
var data: [*c]?*anyopaque = null;
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf(Vertex) * vertices.len);
try vk.mapError(c.vkMapMemory(
device.handle,
buffer.memory,
0,
buffer.size,
0,
@ptrCast(&data),
));
if (data) |ptr| {
const gpu_vertices: [*]Vertex = @ptrCast(@alignCast(ptr));
@memcpy(gpu_vertices, @as([]Vertex, @ptrCast(vertices[0..])));
}
c.vkUnmapMemory(device.handle, buffer.memory);
const vertex_buffer = try device.createBuffer(vk.BufferUsage{ .vertex_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(Vertex) * vertices.len);
try buffer.copyTo(device, vertex_buffer);
buffer.destroy(device.handle);
return vertex_buffer;
}
pub fn createIndexBuffer(allocator: Allocator, device: anytype) !vk.Buffer {
const gltf_data = try gltf.parseFile(allocator, "assets/models/block.glb");
const indices = gltf_data.indices;
//const indices = [_]u16{ 0, 1, 2, 3, 0, 2 };
var data: [*c]?*anyopaque = null;
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf(u16) * indices.len);
try vk.mapError(c.vkMapMemory(
device.handle,
buffer.memory,
0,
buffer.size,
0,
@ptrCast(&data),
));
if (data) |ptr| {
const gpu_indices: [*]u16 = @ptrCast(@alignCast(ptr));
@memcpy(gpu_indices, indices[0..]);
}
c.vkUnmapMemory(device.handle, buffer.memory);
const index_buffer = try device.createBuffer(vk.BufferUsage{ .index_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(u16) * indices.len);
try buffer.copyTo(device, index_buffer);
buffer.destroy(device.handle);
return index_buffer;
}
pub fn create(allocator: Allocator, device: anytype) !Mesh {
const vertex_buffer = try Mesh.createVertexBuffer(allocator, device);
const index_buffer = try Mesh.createIndexBuffer(allocator, device);
return Mesh{
.vertex_buffer = vertex_buffer,
.index_buffer = index_buffer,
};
}
};

View file

@ -1,64 +0,0 @@
const c = @import("../c.zig");
const std = @import("std");
pub const Error = error{
platform_unavailable,
platform_error,
};
pub fn getExtensions() [][*c]const u8 {
var extension_count: u32 = undefined;
const raw: [*c][*c]const u8 = c.glfwGetRequiredInstanceExtensions(&extension_count);
const extensions = raw[0..extension_count];
return extensions;
}
pub const Window = struct {
title: []const u8,
width: usize,
height: usize,
raw: *c.GLFWwindow,
pub fn create(width: usize, height: usize, title: []const u8) !Window {
if (c.glfwInit() != c.GLFW_TRUE) {
const status = c.glfwGetError(null);
return switch (status) {
c.GLFW_PLATFORM_UNAVAILABLE => Error.platform_unavailable,
c.GLFW_PLATFORM_ERROR => Error.platform_error,
else => unreachable,
};
}
c.glfwWindowHint(c.GLFW_RESIZABLE, c.GLFW_FALSE);
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API);
const raw = c.glfwCreateWindow(@intCast(width), @intCast(height), title.ptr, null, null);
c.glfwShowWindow(raw);
return Window{
.title = title,
.width = width,
.height = height,
.raw = raw.?,
};
}
pub fn shouldClose(self: Window) bool {
return c.glfwWindowShouldClose(self.raw) == c.GLFW_TRUE;
}
pub fn size(self: Window) struct { usize, usize } {
var width: u32 = undefined;
var height: u32 = undefined;
c.glfwGetFramebufferSize(self.raw, @ptrCast(&width), @ptrCast(&height));
return .{ @intCast(width), @intCast(height) };
}
pub fn destroy(self: Window) void {
c.glfwDestroyWindow(self.raw);
c.glfwTerminate();
}
};

1
src/sideros.zig Normal file
View file

@ -0,0 +1 @@
pub const math = @import("math.zig");