From 59ccd86a5dfd7d6c2a00d6af55bbe9ca30db993c Mon Sep 17 00:00:00 2001 From: sergeypdev Date: Fri, 23 Feb 2024 22:04:46 +0400 Subject: [PATCH] Basic scene graph with inherited transforms --- src/game.zig | 13 ++++++----- src/globals.zig | 47 +++++++++++++++++++++++++++++++++++++--- tools/asset_compiler.zig | 1 + tools/types.zig | 3 +++ 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/game.zig b/src/game.zig index 3fce972..9c29d1a 100644 --- a/src/game.zig +++ b/src/game.zig @@ -142,7 +142,7 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { gl.viewport(0, 0, globals.g_init.width, globals.g_init.height); - _ = globals.g_mem.world.addEntity(.{ + const light1 = globals.g_mem.world.addEntity(.{ .transform = .{ .pos = Vec3.new(1.8, 1, 0) }, .flags = .{ .point_light = true, .rotate = true }, .point_light = .{ .color_intensity = Vec4.new(1.0, 0.3, 0.1, 100.0), .radius = 0.1 }, @@ -150,7 +150,8 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { }); _ = globals.g_mem.world.addEntity(.{ - .transform = .{ .pos = Vec3.new(-2, 1, 0) }, + .transform = .{ .pos = Vec3.new(-2, 0, 0) }, + .parent = light1, .flags = .{ .point_light = true, .rotate = true }, .point_light = .{ .color_intensity = Vec4.new(0.2, 0.5, 1.0, 100.0), @@ -371,11 +372,11 @@ export fn game_update() bool { ent.rotate.rate * gmem.delta_time, ent.rotate.axis, ).mulByVec4(Vec4.new(old_pos.x(), old_pos.y(), old_pos.z(), 1)); - ent.transform.pos = Vec3.new(new_pos.x(), new_pos.y(), new_pos.z()); + ent.transform.setPos(Vec3.new(new_pos.x(), new_pos.y(), new_pos.z())); } if (ent.flags.point_light) { - const pos = ent.transform.pos; + const pos = ent.globalMatrix(&gmem.world).extractTranslation(); var pos4 = Vec4.new(pos.x(), pos.y(), pos.z(), 1.0); pos4 = gmem.render.camera.view_mat.mulByVec4(pos4); @@ -400,13 +401,13 @@ export fn game_update() bool { gmem.render.draw(.{ .mesh = ent.mesh.handle, .material = ent.mesh.material, - .transform = ent.transform.matrix(), + .transform = ent.globalMatrix(&gmem.world).*, }); } else if (ent.flags.point_light) { gmem.render.draw(.{ .mesh = a.Meshes.sphere, .material = .{ .albedo = ent.point_light.color() }, - .transform = ent.transform.matrix(), + .transform = ent.globalMatrix(&gmem.world).*, }); } } diff --git a/src/globals.zig b/src/globals.zig index 9ca2cb9..055f0e7 100644 --- a/src/globals.zig +++ b/src/globals.zig @@ -44,9 +44,25 @@ pub const Entity = struct { rot: Quat = Quat.identity(), scale: Vec3 = Vec3.one(), - pub fn matrix(self: *Transform) Mat4 { - // TODO: cache - return Mat4.recompose(self.pos, self.rot, self.scale); + _local_dirty: bool = true, + _local: Mat4 = Mat4.identity(), + + _global_dirty: bool = true, + _global: Mat4 = Mat4.identity(), + + pub fn dirty(self: *Transform) void { + self._local_dirty = true; + self._global_dirty = true; + } + + pub fn setPos(self: *Transform, new_pos: Vec3) void { + self.pos = new_pos; + self.dirty(); + } + + pub fn translate(self: *Transform, by: Vec3) void { + self.pos = self.pos.add(by); + self.dirty(); } }; @@ -75,10 +91,35 @@ pub const Entity = struct { next: ?*Entity = null, flags: Flags = .{}, + parent: ?EntityHandle = null, transform: Transform = .{}, mesh: Mesh = .{}, point_light: PointLight = .{}, rotate: Rotate = .{}, + + pub fn localMatrix(self: *Entity) *const Mat4 { + if (self.transform._local_dirty) { + self.transform._local = Mat4.recompose(self.transform.pos, self.transform.rot, self.transform.scale); + self.transform._local_dirty = false; + } + return &self.transform._local; + } + + pub fn globalMatrix(self: *Entity, world: *World) *const Mat4 { + // TODO: think how to reduce pointer chasing + if (self.parent) |parent_ent| { + if (world.getEntity(parent_ent)) |parent| { + if (parent.transform._global_dirty or self.transform._global_dirty) { + self.transform._global = parent.globalMatrix(world).mul(self.localMatrix().*); + self.transform._global_dirty = false; + } + + return &self.transform._global; + } + } + + return self.localMatrix(); + } }; pub const EntityHandle = packed struct { diff --git a/tools/asset_compiler.zig b/tools/asset_compiler.zig index fea2ed3..314f741 100644 --- a/tools/asset_compiler.zig +++ b/tools/asset_compiler.zig @@ -69,6 +69,7 @@ pub fn main() !void { .Shader => try std.fs.Dir.copyFile(std.fs.cwd(), abs_input, output_dir, std.fs.path.basename(rel_input), .{}), .ShaderProgram => try processShaderProgram(allocator, abs_input, output_dir), .Texture => try processTexture(allocator, abs_input, output_dir, false), + .Scene => return error.NotImplemented, } const out_writer = std.io.getStdOut().writer(); diff --git a/tools/types.zig b/tools/types.zig index 61dae94..d62d79a 100644 --- a/tools/types.zig +++ b/tools/types.zig @@ -1,6 +1,7 @@ const std = @import("std"); pub const AssetType = enum { + Scene, Mesh, Shader, ShaderProgram, @@ -8,6 +9,7 @@ pub const AssetType = enum { pub fn pluralName(self: AssetType) []const u8 { return switch (self) { + .Scene => "Scenes", .Mesh => "Meshes", .Shader => "Shaders", .ShaderProgram => "ShaderPrograms", @@ -17,6 +19,7 @@ pub const AssetType = enum { pub fn ext(self: AssetType) []const u8 { return switch (self) { + .Scene => "scn", .Mesh => "mesh", .Shader => "glsl", .ShaderProgram => "prog",