From 75566a8510297f511a5981bb6c04a31f33e346bd Mon Sep 17 00:00:00 2001 From: kayomn Date: Thu, 30 May 2024 22:43:45 +0100 Subject: [PATCH] Add texture UV support to 2D drawing --- src/main.zig | 33 ++++++++++-- src/ona/gfx/Device.zig | 93 ++++++++++++++++++++++++++++++-- src/ona/gfx/Queue.zig | 17 +++--- src/ona/gfx/shaders/draw_2d.glsl | 31 +++++++---- 4 files changed, 150 insertions(+), 24 deletions(-) diff --git a/src/main.zig b/src/main.zig index 6b0c867..9462235 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6,6 +6,10 @@ const ona = @import("ona"); const Actors = struct { instances: coral.stack.Sequential(ona.gfx.Queue.Instance2D) = .{.allocator = coral.heap.allocator}, + body_texture: ona.gfx.Queue.Handle = .none, +}; + +const Player = struct { move_x: ona.act.Axis = .{.keys = .{.a, .d}}, move_y: ona.act.Axis = .{.keys = .{.w, .s}}, }; @@ -17,14 +21,31 @@ pub fn main() !void { }); } -fn load(display: coral.ReadBlocking(ona.gfx.Display), actors: coral.Write(Actors)) !void { +fn load(display: coral.ReadBlocking(ona.gfx.Display), actors: coral.Write(Actors), gfx: ona.gfx.Queue) !void { display.res.resize(1280, 720); try actors.res.instances.push_many(800, .{ .origin = .{75, 75}, .xbasis = .{100, 0}, .ybasis = .{0, 100}, - .color = ona.gfx.color.compress(ona.gfx.color.rgb(1, 0, 0)), + }); + + const crap = [_]u32{ + 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000, + 0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000, + 0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, + }; + + actors.res.body_texture = try gfx.buffer.open(.{ + .resource = .{ + .texture = .{ + .data = coral.io.bytes_of(&crap), + .width = 4, + .access = .static, + .format = .bgra8888, + }, + }, }); } @@ -36,18 +57,20 @@ fn render(gfx: ona.gfx.Queue, actors: coral.Write(Actors)) !void { try gfx.buffer.draw_2d(.{ .mesh_2d = gfx.primitives.quad_mesh, .instances = actors.res.instances.values, + .texture = actors.res.body_texture, }); } -fn update(actors: coral.Write(Actors), mapping: coral.Read(ona.act.Mapping)) !void { +fn update(player: coral.Read(Player), actors: coral.Write(Actors), mapping: coral.Read(ona.act.Mapping)) !void { actors.res.instances.values[0].origin += .{ - mapping.res.axis_strength(actors.res.move_x), - mapping.res.axis_strength(actors.res.move_y), + mapping.res.axis_strength(player.res.move_x), + mapping.res.axis_strength(player.res.move_y), }; } fn setup(world: *coral.World, events: ona.App.Events) !void { try world.set_resource(.none, Actors{}); + try world.set_resource(.none, Player{}); try world.on_event(events.load, coral.system_fn(load), .{.label = "load"}); try world.on_event(events.update, coral.system_fn(update), .{.label = "update"}); diff --git a/src/ona/gfx/Device.zig b/src/ona/gfx/Device.zig index 19ba0dc..1bef10c 100644 --- a/src/ona/gfx/Device.zig +++ b/src/ona/gfx/Device.zig @@ -19,6 +19,7 @@ const AtomicBool = std.atomic.Value(bool); const RenderWork = struct { pipeline_2d: sokol.gfx.Pipeline, + instance_2d_sampler: sokol.gfx.Sampler, instance_2d_buffers: coral.stack.Sequential(sokol.gfx.Buffer), resources: coral.stack.Sequential(Resource), @@ -28,6 +29,10 @@ const RenderWork = struct { vertex_buffer: sokol.gfx.Buffer, index_buffer: sokol.gfx.Buffer, }, + + texture: struct { + image: sokol.gfx.Image, + }, }; const buffer_indices = .{ @@ -50,6 +55,10 @@ const RenderWork = struct { sokol.gfx.destroyBuffer(mesh_2d.vertex_buffer); sokol.gfx.destroyBuffer(mesh_2d.index_buffer); }, + + .texture => |texture| { + sokol.gfx.destroyImage(texture.image); + } } } @@ -72,6 +81,11 @@ const RenderWork = struct { .buffer_index = buffer_indices.mesh, }; + attrs[draw_2d.ATTR_vs_mesh_uv] = .{ + .format = .FLOAT2, + .buffer_index = buffer_indices.mesh, + }; + attrs[draw_2d.ATTR_vs_instance_xbasis] = .{ .format = .FLOAT2, .buffer_index = buffer_indices.instance, @@ -97,6 +111,11 @@ const RenderWork = struct { .buffer_index = buffer_indices.instance, }; + attrs[draw_2d.ATTR_vs_instance_rect] = .{ + .format = .FLOAT4, + .buffer_index = buffer_indices.instance, + }; + break: get attrs; }, @@ -113,6 +132,10 @@ const RenderWork = struct { .index_type = .UINT16, }), + .instance_2d_sampler = sokol.gfx.makeSampler(.{ + .label = "instance 2D sampler", + }), + .instance_2d_buffers = .{.allocator = coral.heap.allocator}, .resources = .{.allocator = allocator}, }; @@ -130,7 +153,7 @@ const RenderWork = struct { for (commands) |command| { const mesh_2d = &self.resources.values[command.mesh_2d.index().?].mesh_2d; - + const texture = &self.resources.values[command.texture.index().?].texture; const instance_size = @sizeOf(Queue.Instance2D); const full_instance_buffer_count = command.instances.len / max_instances; @@ -160,6 +183,24 @@ const RenderWork = struct { }, .index_buffer = mesh_2d.index_buffer, + + .fs = .{ + .images = get: { + var images = [_]sokol.gfx.Image{.{}} ** 12; + + images[0] = texture.image; + + break: get images; + }, + + .samplers = get: { + var samplers = [_]sokol.gfx.Sampler{.{}} ** 8; + + samplers[0] = self.instance_2d_sampler; + + break: get samplers; + }, + }, }); sokol.gfx.updateBuffer(self.instance_2d_buffers.values[instance_2d_buffers_used], .{ @@ -194,6 +235,24 @@ const RenderWork = struct { break: get_buffers buffers; }, + .fs = .{ + .images = get: { + var images = [_]sokol.gfx.Image{.{}} ** 12; + + images[0] = texture.image; + + break: get images; + }, + + .samplers = get: { + var samplers = [_]sokol.gfx.Sampler{.{}} ** 8; + + samplers[0] = self.instance_2d_sampler; + + break: get samplers; + }, + }, + .index_buffer = mesh_2d.index_buffer, }); @@ -208,11 +267,34 @@ const RenderWork = struct { } } - fn process_queue(self: *RenderWork, buffer: *const Queue.Buffer, target: Queue.Target) std.mem.Allocator.Error!void { - for (buffer.open_commands.values) |command| { + fn process_open_commands(self: *RenderWork, commands: []const Queue.Buffer.OpenCommand) std.mem.Allocator.Error!void { + for (commands) |command| { switch (command.resource) { - .texture => { + .texture => |texture| { + const stride = texture.width * texture.format.byte_size(); + const image = sokol.gfx.makeImage(.{ + .width = texture.width, + .height = @intCast(texture.data.len / stride), + + .data = .{ + .subimage = get: { + var subimage = [_][16]sokol.gfx.Range{.{.{}} ** 16} ** 6; + + subimage[0][0] = sokol.gfx.asRange(texture.data); + + break: get subimage; + }, + }, + }); + + errdefer sokol.gfx.destroyImage(image); + + try self.resources.push(.{ + .texture = .{ + .image = image, + }, + }); }, .mesh_2d => |mesh_2d| { @@ -245,7 +327,10 @@ const RenderWork = struct { }, } } + } + fn process_queue(self: *RenderWork, buffer: *const Queue.Buffer, target: Queue.Target) std.mem.Allocator.Error!void { + try self.process_open_commands(buffer.open_commands.values); try self.process_draw_2d_commands(buffer.draw_2d_commands.values, target); } }; diff --git a/src/ona/gfx/Queue.zig b/src/ona/gfx/Queue.zig index 98ecb3f..958cf22 100644 --- a/src/ona/gfx/Queue.zig +++ b/src/ona/gfx/Queue.zig @@ -22,6 +22,7 @@ pub const Buffer = struct { pub const Draw2DCommand = struct { instances: []const Instance2D, + texture: Handle, mesh_2d: Handle, }; @@ -40,8 +41,8 @@ pub const Buffer = struct { }; pub const Texture = struct { + data: []const coral.io.Byte, width: u16, - height: u16, format: Format, access: Access, @@ -97,6 +98,7 @@ pub const Buffer = struct { pub fn draw_2d(self: *Buffer, command: Draw2DCommand) std.mem.Allocator.Error!void { try self.draw_2d_commands.push(.{ .instances = try self.arena.allocator().dupe(Instance2D, command.instances), + .texture = command.texture, .mesh_2d = command.mesh_2d, }); } @@ -124,8 +126,8 @@ pub const Buffer = struct { .resource = switch (command.resource) { .texture => |texture| .{ .texture = .{ + .data = try arena_allocator.dupe(coral.io.Byte, texture.data), .width = texture.width, - .height = texture.height, .format = texture.format, .access = texture.access, }, @@ -167,6 +169,8 @@ pub const Instance2D = extern struct { origin: Point2D = @splat(0), color: color.Compressed = color.compress(color.white), depth: f32 = 0, + texture_offset: Point2D = @splat(0), + texture_size: Point2D = @splat(1), }; const Node = struct { @@ -235,6 +239,7 @@ pub const Target = struct { pub const Vertex2D = struct { xy: Point2D, + uv: Point2D, }; pub fn bind(context: coral.system.BindContext) std.mem.Allocator.Error!State { @@ -275,10 +280,10 @@ pub fn bind(context: coral.system.BindContext) std.mem.Allocator.Error!State { .indices = &.{0, 1, 2, 0, 2, 3}, .vertices = &.{ - .{.xy = .{-half_extent, half_extent}},// .uv = .{0, 1}}, - .{.xy = .{half_extent, half_extent}},// .uv = .{1, 1}}, - .{.xy = .{half_extent, -half_extent}},// .uv = .{1, 0}}, - .{.xy = .{-half_extent, -half_extent}},// .uv = .{0, 0}}, + .{.xy = .{-half_extent, half_extent}, .uv = .{0, 1}}, + .{.xy = .{half_extent, half_extent}, .uv = .{1, 1}}, + .{.xy = .{half_extent, -half_extent}, .uv = .{1, 0}}, + .{.xy = .{-half_extent, -half_extent}, .uv = .{0, 0}}, }, }, }, diff --git a/src/ona/gfx/shaders/draw_2d.glsl b/src/ona/gfx/shaders/draw_2d.glsl index dca424a..08c7164 100644 --- a/src/ona/gfx/shaders/draw_2d.glsl +++ b/src/ona/gfx/shaders/draw_2d.glsl @@ -3,41 +3,54 @@ @vs vs in vec2 mesh_xy; +in vec2 mesh_uv; in vec2 instance_xbasis; in vec2 instance_ybasis; in vec2 instance_origin; in vec4 instance_color; in float instance_depth; +in vec4 instance_rect; uniform Screen { vec2 screen_size; }; out vec4 color; +out vec2 uv; void main() { // Calculate the world position of the vertex - const vec2 world_position = instance_origin + mesh_xy.x * instance_xbasis + mesh_xy.y * instance_ybasis; + const vec2 world_position = instance_origin + mesh_xy.x * instance_xbasis + mesh_xy.y * instance_ybasis; - // Convert world position to normalized device coordinates (NDC) - // Assuming the screen coordinates range from (0, 0) to (screen_size.x, screen_size.y) - const vec2 ndc_position = (vec2(world_position.x, -world_position.y) / screen_size) * 2.0 - vec2(1.0, -1.0); + // Convert world position to normalized device coordinates (NDC) + // Assuming the screen coordinates range from (0, 0) to (screen_size.x, screen_size.y) + const vec2 ndc_position = (vec2(world_position.x, -world_position.y) / screen_size) * 2.0 - vec2(1.0, -1.0); - // Set the position of the vertex in clip space - gl_Position = vec4(ndc_position, instance_depth, 1.0); + // Set the position of the vertex in clip space + gl_Position = vec4(ndc_position, instance_depth, 1.0); + color = instance_color; - // Set the output color - color = instance_color; + // Calculate the width and height from left, top, right, bottom configuration + const vec2 rect_pos = instance_rect.xy; // left, top + const vec2 rect_size = instance_rect.zw - instance_rect.xy; // right - left, bottom - top + + // Calculate the adjusted UV coordinates using the instance_rect + uv = rect_pos + (mesh_uv * rect_size); } @end @fs fs +uniform texture2D tex; +uniform sampler smp; + in vec4 color; +in vec2 uv; + out vec4 texel; void main() { - texel = color; + texel = texture(sampler2D(tex, smp), uv) * color; } @end