From 1c97d66ceacb465d0520f19750e3ac930e0a7adc Mon Sep 17 00:00:00 2001 From: copygirl Date: Fri, 5 Apr 2024 20:10:23 +0200 Subject: [PATCH] Start using ECS by creating a camera entity --- libs/flecs-zig-ble | 1 + src/main.zig | 17 +++++++++++++++++ src/renderer.zig | 40 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 160000 libs/flecs-zig-ble diff --git a/libs/flecs-zig-ble b/libs/flecs-zig-ble new file mode 160000 index 0000000..f48a688 --- /dev/null +++ b/libs/flecs-zig-ble @@ -0,0 +1 @@ +Subproject commit f48a6884caf656b49f416abdd3ce078fc93b1504 diff --git a/src/main.zig b/src/main.zig index 8d87be3..a955604 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4,10 +4,14 @@ const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator(.{}); const core = @import("mach").core; const Renderer = @import("./renderer.zig"); +const flecszigble = @import("flecs-zig-ble"); +const World = flecszigble.World(void); + pub const App = @This(); gpa: GeneralPurposeAllocator, allocator: std.mem.Allocator, +world: *World, random: std.rand.Random, renderer: *Renderer, @@ -31,6 +35,18 @@ pub fn init(app: *App) !void { app.gpa = GeneralPurposeAllocator{}; app.allocator = app.gpa.allocator(); + // Initialize flecs-zig-ble and create a new Flecs world. + // + // Flecs is a library for using Entity Component System (ECS) design + // intuitively and efficiently. Entities can be created and have various + // components – and relationships to other entities – added to them. + // + // This data is stored in an in-memory database, which can be queried + // and modified. For example by using systems, you are able to get + // entities that match a set of components, and modify their values. + flecszigble.init(app.allocator); + app.world = try World.init(); + // Create a pseudo-random number generator, but initialize it with // a constant seed so we always get the same result when launching. var prng = std.rand.DefaultPrng.init(0); @@ -47,6 +63,7 @@ pub fn deinit(app: *App) void { // in the order they were created in `init`. defer core.deinit(); defer _ = app.gpa.deinit(); // TODO: Check for memory leaks? + defer app.world.deinit(); defer app.renderer.deinit(); } diff --git a/src/renderer.zig b/src/renderer.zig index fc41ec6..50d6f68 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -17,6 +17,23 @@ const primitives = @import("./primitives.zig"); const VertexData = primitives.VertexData; const PrimitiveData = primitives.PrimitiveData; +const flecszigble = @import("flecs-zig-ble"); +const Entity = flecszigble.Entity(void); + +const Transform = struct { value: Mat }; +const CameraPerspective = struct { + /// Vertical field of view (in degrees). + field_of_view: f32, + /// The near clip plane distance. Objects closer than this value are + /// "cut off". Should be set to a positive value close to zero, depending + /// on how close rendered objects typically get to the camera. + near_plane: f32, + /// The far clip place distance. Objects further than this value are + /// "cut off" and therefore won't be visible. Should be set to a larger + /// positive value, depending on how far objects can get from the camera. + far_plane: f32, +}; + /// Holds data needed to render an object in a rendering pass. const ObjectData = struct { /// Bind group which associates model-related buffers with parameters @@ -39,6 +56,7 @@ depth_texture_view: ?*gpu.TextureView = null, primitive_data: []PrimitiveData, object_data: []ObjectData, +camera_entity: Entity, pub fn init(app: *App) !*Renderer { // A string buffer used to format objects' labels. @@ -207,6 +225,12 @@ pub fn init(app: *App) !*Renderer { }; } + _ = try app.world.component(Transform); + _ = try app.world.component(CameraPerspective); + + const camera_entity = try app.world.entity(.{ .name = "Camera" }, .{ Transform, CameraPerspective }); + camera_entity.set(CameraPerspective, .{ .field_of_view = 45.0, .near_plane = 0.05, .far_plane = 80.0 }); + const result = try app.allocator.create(Renderer); result.* = .{ .app = app, @@ -215,6 +239,7 @@ pub fn init(app: *App) !*Renderer { .camera_bind_group = camera_bind_group, .primitive_data = primitive_data, .object_data = object_data, + .camera_entity = camera_entity, }; // Initialize the depth texture. @@ -265,12 +290,23 @@ pub fn update(self: *Renderer) void { const camera_pos = vec(x, 2.0, z, 1.0); const view_matrix = zm.lookAtLh(camera_pos, vec(0, 0, 0, 1), vec(0, 1, 0, 1)); + // Setting the transform here doesn't do anything because it's not used + // anywhere. In the future we would want to set the camera transform + // outside of the rendering step, and then get and use it here, instead. + self.camera_entity.set(Transform, .{ .value = view_matrix }); + // TODO: Not sure if this is the proper transform, or actually inverted. + // Set up a projection matrix using the size of the window. // The perspective projection will make things further away appear smaller. const width: f32 = @floatFromInt(core.descriptor.width); const height: f32 = @floatFromInt(core.descriptor.height); - const field_of_view = std.math.degreesToRadians(f32, 45.0); - const proj_matrix = zm.perspectiveFovLh(field_of_view, width / height, 0.05, 80.0); + const perspective = self.camera_entity.get(CameraPerspective).?; + const proj_matrix = zm.perspectiveFovLh( + std.math.degreesToRadians(f32, perspective.field_of_view), + width / height, + perspective.near_plane, + perspective.far_plane, + ); const view_proj_matrix = zm.mul(view_matrix, proj_matrix);