diff --git a/build.zig b/build.zig index f9d9810..490af7b 100644 --- a/build.zig +++ b/build.zig @@ -12,77 +12,61 @@ const Project = struct { optimize: std.builtin.OptimizeMode, imports: ImportList, - pub fn demos_step(self: *const Project, b: *std.Build) *std.Build.Step { - const Demos = struct { - step: std.Build.Step, - project: *const Project, + pub fn find_demos(self: Project, step: *std.Build.Step) void { + const absolute_path = step.owner.path("demos/").getPath(step.owner); - const Self = @This(); + var dir = std.fs.openDirAbsolute(absolute_path, .{.iterate = true}) catch |open_error| { + std.log.warn("failed to open demos directory at {s} with error {s}, skipping...", .{ + absolute_path, + @errorName(open_error), + }); - fn make(step: *std.Build.Step, _: std.Progress.Node) anyerror!void { - const demos: *const Self = @fieldParentPtr("step", step); - const absolute_path = step.owner.path("demos/").getPath(step.owner); - var dir = try std.fs.openDirAbsolute(absolute_path, .{.iterate = true}); + return; + }; - defer { - dir.close(); - } + defer { + dir.close(); + } - var entries = try dir.walk(step.owner.allocator); + var entries = dir.walk(step.owner.allocator) catch @panic("OOM"); - defer { - entries.deinit(); - } + defer { + entries.deinit(); + } - while (try entries.next()) |entry| { - if (entry.kind != .file or !std.mem.endsWith(u8, entry.path, ".zig")) { - continue; - } - - const source_path = step.owner.pathJoin(&.{"demos", entry.basename}); - var path_buffer = [_:0]u8{0} ** 255; - - const demo = step.owner.addExecutable(.{ - .name = try std.fmt.bufPrint(&path_buffer, "{s}.out", .{std.fs.path.stem(entry.basename)}), - .root_source_file = step.owner.path(source_path), - .target = demos.project.target, - .optimize = demos.project.optimize, - }); - - for (demos.project.imports.items) |import| { - demo.root_module.addImport(import.name, import.module); - } - - step.owner.installArtifact(demo); - } - - step.state = .success; + while (entries.next() catch @panic("I/O failure")) |entry| { + if (entry.kind != .file or !std.mem.endsWith(u8, entry.path, ".zig")) { + continue; } - }; - const demos = b.allocator.create(Demos) catch { - @panic("OOM"); - }; + const source_path = step.owner.pathJoin(&.{"demos", entry.basename}); + var path_buffer = [_:0]u8{0} ** 255; - demos.* = .{ - .step = std.Build.Step.init(.{ - .id = .custom, - .name = "demos", - .makeFn = Demos.make, - .owner = b, - }), + const demo = step.owner.addExecutable(.{ + .name = std.fmt.bufPrint(&path_buffer, "{s}.out", .{std.fs.path.stem(entry.basename)}) catch { + @panic("a demo file name is too long"); + }, - .project = self, - }; + .root_source_file = step.owner.path(source_path), + .target = self.target, + .optimize = self.optimize, + }); - return &demos.step; + for (self.imports.items) |import| { + demo.root_module.addImport(import.name, import.module); + } + + step.dependOn(&step.owner.addInstallArtifact(demo, .{ + .dest_dir = .{ + .override = .{.custom = "../demos"}, + }, + }).step); + } } - pub fn find_tests(self: Project, b: *std.Build) !void { - const tests = b.step("tests", "Build and run tests"); - + pub fn find_tests(self: Project, step: *std.Build.Step) void { for (self.imports.items) |import| { - tests.dependOn(&b.addRunArtifact(b.addTest(.{ + step.dependOn(&step.owner.addRunArtifact(step.owner.addTest(.{ .root_source_file = import.module.root_source_file.?, .target = self.target, .optimize = self.optimize, @@ -177,11 +161,7 @@ const Project = struct { }; pub fn build(b: *std.Build) !void { - const project = b.allocator.create(Project) catch { - @panic("OOM"); - }; - - project.* = .{ + var project = Project{ .imports = ImportList.init(b.allocator), .target = b.standardTargetOptions(.{}), .optimize = b.standardOptimizeOption(.{}), @@ -274,7 +254,6 @@ pub fn build(b: *std.Build) !void { gfx_module.link_libc = true; - b.step("demos", "Build demos").dependOn(project.demos_step(b)); - - try project.find_tests(b); + project.find_demos(b.step("demos", "Build demos")); + project.find_tests(b.step("tests", "Build and run tests")); } diff --git a/demos/effects.zig b/demos/effects.zig index 6412815..8b9114a 100644 --- a/demos/effects.zig +++ b/demos/effects.zig @@ -50,15 +50,14 @@ fn render(commands: gfx.Commands, effects: ona.Write(Effects), app: ona.Read(ona const display_width: f32 = @floatFromInt(display.state.width); const display_height: f32 = @floatFromInt(display.state.height); - const display_transform = gfx.Transform2D{ - .origin = .{display_width / 2, display_height / 2}, - .xbasis = .{display_width, 0}, - .ybasis = .{0, display_height}, - }; + const display_transform = gfx.transform_2d(.{ + .translation = .{display_width / 2, display_height / 2}, + }); try commands.draw_texture(.{ .texture = .default, .transform = display_transform, + .resolution = .{display.state.width, display.state.height}, }); try commands.set_effect(.{ @@ -72,7 +71,6 @@ fn render(commands: gfx.Commands, effects: ona.Write(Effects), app: ona.Read(ona }); try commands.set_target(.{ - .texture = null, .clear_color = null, .clear_depth = null, .clear_stencil = null, diff --git a/demos/inputs.zig b/demos/inputs.zig index b421a4e..de9b1c6 100644 --- a/demos/inputs.zig +++ b/demos/inputs.zig @@ -48,7 +48,7 @@ fn update(visuals: ona.Write(Visuals), events: ona.Receive(hid.Event), display: const random = visuals.state.random.random(); const width: f32 = @floatFromInt(display.state.width); const height: f32 = @floatFromInt(display.state.height); - const icon_scale = .{64, 64}; + const icon_scale = .{8, 8}; for (events.messages()) |event| { switch (event) { @@ -56,7 +56,7 @@ fn update(visuals: ona.Write(Visuals), events: ona.Receive(hid.Event), display: try visuals.state.spawned_keyboards.push_grow(.{ .lifetime_seconds = 2.5 + (5 * random.float(f32)), - .transform = gfx.Transform2D.from_simplified(.{ + .transform = gfx.transform_2d(.{ .translation = .{width * random.float(f32), height}, .rotation = std.math.pi * random.float(f32), .scale = icon_scale, @@ -68,7 +68,7 @@ fn update(visuals: ona.Write(Visuals), events: ona.Receive(hid.Event), display: try visuals.state.spawned_mouses.push_grow(.{ .lifetime_seconds = 2.5 + (5 * random.float(f32)), - .transform = gfx.Transform2D.from_simplified(.{ + .transform = gfx.transform_2d(.{ .translation = visuals.state.mouse_position, .rotation = std.math.pi * random.float(f32), .scale = icon_scale, diff --git a/src/gfx/gfx.zig b/src/gfx/gfx.zig index be09af3..3c8f17c 100644 --- a/src/gfx/gfx.zig +++ b/src/gfx/gfx.zig @@ -178,6 +178,7 @@ pub const Commands = struct { pub const DrawTextureCommand = struct { texture: Texture, transform: Transform2D, + resolution: ?@Vector(2, u16) = null, }; pub const SetEffectCommand = struct { @@ -357,13 +358,34 @@ pub const Transform2D = extern struct { pub const Vector = @Vector(2, f32); - pub fn from_simplified(simplified: Simplified) Transform2D { - const rotation_skew = simplified.rotation + simplified.skew; + pub fn scaled(self: Transform2D, scale: Vector) Transform2D { + var transform = self; + const scale_x, const scale_y = scale; + + transform.xbasis *= @splat(scale_x); + transform.ybasis *= @splat(scale_y); + + return transform; + } + + pub fn transformed(self: Transform2D, other: Transform2D) Transform2D { + const xbasis_x, const xbasis_y = other.xbasis; + const ybasis_x, const ybasis_y = other.ybasis; + const origin_x, const origin_y = other.origin; return .{ - .xbasis = simplified.scale * Vector{std.math.cos(simplified.rotation), std.math.sin(simplified.rotation)}, - .ybasis = simplified.scale * Vector{-std.math.sin(rotation_skew), std.math.cos(rotation_skew)}, - .origin = simplified.translation, + .xbasis = + (self.xbasis * @as(Vector, @splat(xbasis_x))) + + (self.ybasis * @as(Vector, @splat(xbasis_y))), + + .ybasis = + (self.xbasis * @as(Vector, @splat(ybasis_x))) + + (self.ybasis * @as(Vector, @splat(ybasis_y))), + + .origin = + (self.xbasis * @as(Vector, @splat(origin_x))) + + (self.ybasis * @as(Vector, @splat(origin_y))) + + self.origin, }; } @@ -586,3 +608,21 @@ pub fn synchronize(exclusive: ona.Exclusive(&.{Assets, Display})) !void { assets.frame_rendered.set(); } } + +pub fn transform_2d(simplified: Transform2D.Simplified) Transform2D { + const rotation_skew = simplified.rotation + simplified.skew; + + return .{ + .xbasis = simplified.scale * Transform2D.Vector{ + std.math.cos(simplified.rotation), + std.math.sin(simplified.rotation), + }, + + .ybasis = simplified.scale * Transform2D.Vector{ + -std.math.sin(rotation_skew), + std.math.cos(rotation_skew), + }, + + .origin = simplified.translation, + }; +} diff --git a/src/gfx/rendering.zig b/src/gfx/rendering.zig index c8f1d49..ee0890a 100644 --- a/src/gfx/rendering.zig +++ b/src/gfx/rendering.zig @@ -96,8 +96,13 @@ const Frame = struct { try self.texture_batch_buffers.push_grow(instance_buffer); } + const texture = resources.get_texture(command.texture).?; + _ = sokol.gfx.appendBuffer(self.texture_batch_buffers.get().?.*, sokol.gfx.asRange(&DrawTexture{ - .transform = command.transform, + .transform = command.transform.scaled(@floatFromInt(command.resolution orelse .{ + texture.width, + texture.height, + })), })); self.drawn_count += 1; diff --git a/src/gfx/shaders/2d_default.vert b/src/gfx/shaders/2d_default.vert index d5045cb..5d782fb 100644 --- a/src/gfx/shaders/2d_default.vert +++ b/src/gfx/shaders/2d_default.vert @@ -8,7 +8,7 @@ layout (location = 3) in vec2 instance_ybasis; layout (location = 4) in vec2 instance_origin; layout (location = 5) in vec4 instance_tint; layout (location = 6) in float instance_depth; -layout (location = 7) in vec4 instance_rect; +layout (location = 7) in vec4 instance_clip; layout (location = 0) out vec4 color; layout (location = 1) out vec2 uv; @@ -20,10 +20,10 @@ layout (binding = 0) uniform View { void main() { const vec2 world_position = instance_origin + mesh_xy.x * instance_xbasis + mesh_xy.y * instance_ybasis; const vec2 projected_position = (projection_matrix * vec4(world_position, 0, 1)).xy; - const vec2 rect_size = instance_rect.zw - instance_rect.xy; + const vec2 rect_size = instance_clip.zw - instance_clip.xy; const vec4 screen_position = vec4(projected_position, instance_depth, 1.0); gl_Position = screen_position; color = instance_tint; - uv = instance_rect.xy + (mesh_uv * rect_size); + uv = instance_clip.xy + (mesh_uv * rect_size); }