Add texture UV support to 2D drawing
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		
							parent
							
								
									1ffb316a11
								
							
						
					
					
						commit
						75566a8510
					
				
							
								
								
									
										33
									
								
								src/main.zig
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								src/main.zig
									
									
									
									
									
								
							| @ -6,6 +6,10 @@ const ona = @import("ona"); | |||||||
| 
 | 
 | ||||||
| const Actors = struct { | const Actors = struct { | ||||||
| 	instances: coral.stack.Sequential(ona.gfx.Queue.Instance2D) = .{.allocator = coral.heap.allocator}, | 	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_x: ona.act.Axis = .{.keys = .{.a, .d}}, | ||||||
| 	move_y: ona.act.Axis = .{.keys = .{.w, .s}}, | 	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); | 	display.res.resize(1280, 720); | ||||||
| 
 | 
 | ||||||
| 	try actors.res.instances.push_many(800, .{ | 	try actors.res.instances.push_many(800, .{ | ||||||
| 		.origin = .{75, 75}, | 		.origin = .{75, 75}, | ||||||
| 		.xbasis = .{100, 0}, | 		.xbasis = .{100, 0}, | ||||||
| 		.ybasis = .{0, 100}, | 		.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(.{ | 	try gfx.buffer.draw_2d(.{ | ||||||
| 		.mesh_2d = gfx.primitives.quad_mesh, | 		.mesh_2d = gfx.primitives.quad_mesh, | ||||||
| 		.instances = actors.res.instances.values, | 		.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 += .{ | 	actors.res.instances.values[0].origin += .{ | ||||||
| 		mapping.res.axis_strength(actors.res.move_x), | 		mapping.res.axis_strength(player.res.move_x), | ||||||
| 		mapping.res.axis_strength(actors.res.move_y), | 		mapping.res.axis_strength(player.res.move_y), | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn setup(world: *coral.World, events: ona.App.Events) !void { | fn setup(world: *coral.World, events: ona.App.Events) !void { | ||||||
| 	try world.set_resource(.none, Actors{}); | 	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.load, coral.system_fn(load), .{.label = "load"}); | ||||||
| 	try world.on_event(events.update, coral.system_fn(update), .{.label = "update"}); | 	try world.on_event(events.update, coral.system_fn(update), .{.label = "update"}); | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ const AtomicBool = std.atomic.Value(bool); | |||||||
| 
 | 
 | ||||||
| const RenderWork = struct { | const RenderWork = struct { | ||||||
| 	pipeline_2d: sokol.gfx.Pipeline, | 	pipeline_2d: sokol.gfx.Pipeline, | ||||||
|  | 	instance_2d_sampler: sokol.gfx.Sampler, | ||||||
| 	instance_2d_buffers: coral.stack.Sequential(sokol.gfx.Buffer), | 	instance_2d_buffers: coral.stack.Sequential(sokol.gfx.Buffer), | ||||||
| 	resources: coral.stack.Sequential(Resource), | 	resources: coral.stack.Sequential(Resource), | ||||||
| 
 | 
 | ||||||
| @ -28,6 +29,10 @@ const RenderWork = struct { | |||||||
| 			vertex_buffer: sokol.gfx.Buffer, | 			vertex_buffer: sokol.gfx.Buffer, | ||||||
| 			index_buffer: sokol.gfx.Buffer, | 			index_buffer: sokol.gfx.Buffer, | ||||||
| 		}, | 		}, | ||||||
|  | 
 | ||||||
|  | 		texture: struct { | ||||||
|  | 			image: sokol.gfx.Image, | ||||||
|  | 		}, | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	const buffer_indices = .{ | 	const buffer_indices = .{ | ||||||
| @ -50,6 +55,10 @@ const RenderWork = struct { | |||||||
| 					sokol.gfx.destroyBuffer(mesh_2d.vertex_buffer); | 					sokol.gfx.destroyBuffer(mesh_2d.vertex_buffer); | ||||||
| 					sokol.gfx.destroyBuffer(mesh_2d.index_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, | 							.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] = .{ | 						attrs[draw_2d.ATTR_vs_instance_xbasis] = .{ | ||||||
| 							.format = .FLOAT2, | 							.format = .FLOAT2, | ||||||
| 							.buffer_index = buffer_indices.instance, | 							.buffer_index = buffer_indices.instance, | ||||||
| @ -97,6 +111,11 @@ const RenderWork = struct { | |||||||
| 							.buffer_index = buffer_indices.instance, | 							.buffer_index = buffer_indices.instance, | ||||||
| 						}; | 						}; | ||||||
| 
 | 
 | ||||||
|  | 						attrs[draw_2d.ATTR_vs_instance_rect] = .{ | ||||||
|  | 							.format = .FLOAT4, | ||||||
|  | 							.buffer_index = buffer_indices.instance, | ||||||
|  | 						}; | ||||||
|  | 
 | ||||||
| 						break: get attrs; | 						break: get attrs; | ||||||
| 					}, | 					}, | ||||||
| 
 | 
 | ||||||
| @ -113,6 +132,10 @@ const RenderWork = struct { | |||||||
| 				.index_type = .UINT16, | 				.index_type = .UINT16, | ||||||
| 			}), | 			}), | ||||||
| 
 | 
 | ||||||
|  | 			.instance_2d_sampler = sokol.gfx.makeSampler(.{ | ||||||
|  | 				.label = "instance 2D sampler", | ||||||
|  | 			}), | ||||||
|  | 
 | ||||||
| 			.instance_2d_buffers = .{.allocator = coral.heap.allocator}, | 			.instance_2d_buffers = .{.allocator = coral.heap.allocator}, | ||||||
| 			.resources = .{.allocator = allocator}, | 			.resources = .{.allocator = allocator}, | ||||||
| 		}; | 		}; | ||||||
| @ -130,7 +153,7 @@ const RenderWork = struct { | |||||||
| 
 | 
 | ||||||
| 		for (commands) |command| { | 		for (commands) |command| { | ||||||
| 			const mesh_2d = &self.resources.values[command.mesh_2d.index().?].mesh_2d; | 			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 instance_size = @sizeOf(Queue.Instance2D); | ||||||
| 			const full_instance_buffer_count = command.instances.len / max_instances; | 			const full_instance_buffer_count = command.instances.len / max_instances; | ||||||
| 
 | 
 | ||||||
| @ -160,6 +183,24 @@ const RenderWork = struct { | |||||||
| 					}, | 					}, | ||||||
| 
 | 
 | ||||||
| 					.index_buffer = mesh_2d.index_buffer, | 					.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], .{ | 				sokol.gfx.updateBuffer(self.instance_2d_buffers.values[instance_2d_buffers_used], .{ | ||||||
| @ -194,6 +235,24 @@ const RenderWork = struct { | |||||||
| 					break: get_buffers buffers; | 					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, | 				.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 { | 	fn process_open_commands(self: *RenderWork, commands: []const Queue.Buffer.OpenCommand) std.mem.Allocator.Error!void { | ||||||
| 		for (buffer.open_commands.values) |command| { | 		for (commands) |command| { | ||||||
| 			switch (command.resource) { | 			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| { | 				.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); | 		try self.process_draw_2d_commands(buffer.draw_2d_commands.values, target); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ pub const Buffer = struct { | |||||||
| 
 | 
 | ||||||
| 	pub const Draw2DCommand = struct { | 	pub const Draw2DCommand = struct { | ||||||
| 		instances: []const Instance2D, | 		instances: []const Instance2D, | ||||||
|  | 		texture: Handle, | ||||||
| 		mesh_2d: Handle, | 		mesh_2d: Handle, | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| @ -40,8 +41,8 @@ pub const Buffer = struct { | |||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		pub const Texture = struct { | 		pub const Texture = struct { | ||||||
|  | 			data: []const coral.io.Byte, | ||||||
| 			width: u16, | 			width: u16, | ||||||
| 			height: u16, |  | ||||||
| 			format: Format, | 			format: Format, | ||||||
| 			access: Access, | 			access: Access, | ||||||
| 
 | 
 | ||||||
| @ -97,6 +98,7 @@ pub const Buffer = struct { | |||||||
| 	pub fn draw_2d(self: *Buffer, command: Draw2DCommand) std.mem.Allocator.Error!void { | 	pub fn draw_2d(self: *Buffer, command: Draw2DCommand) std.mem.Allocator.Error!void { | ||||||
| 		try self.draw_2d_commands.push(.{ | 		try self.draw_2d_commands.push(.{ | ||||||
| 			.instances = try self.arena.allocator().dupe(Instance2D, command.instances), | 			.instances = try self.arena.allocator().dupe(Instance2D, command.instances), | ||||||
|  | 			.texture = command.texture, | ||||||
| 			.mesh_2d = command.mesh_2d, | 			.mesh_2d = command.mesh_2d, | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| @ -124,8 +126,8 @@ pub const Buffer = struct { | |||||||
| 			.resource = switch (command.resource) { | 			.resource = switch (command.resource) { | ||||||
| 				.texture => |texture| .{ | 				.texture => |texture| .{ | ||||||
| 					.texture = .{ | 					.texture = .{ | ||||||
|  | 						.data = try arena_allocator.dupe(coral.io.Byte, texture.data), | ||||||
| 						.width = texture.width, | 						.width = texture.width, | ||||||
| 						.height = texture.height, |  | ||||||
| 						.format = texture.format, | 						.format = texture.format, | ||||||
| 						.access = texture.access, | 						.access = texture.access, | ||||||
| 					}, | 					}, | ||||||
| @ -167,6 +169,8 @@ pub const Instance2D = extern struct { | |||||||
| 	origin: Point2D = @splat(0), | 	origin: Point2D = @splat(0), | ||||||
| 	color: color.Compressed = color.compress(color.white), | 	color: color.Compressed = color.compress(color.white), | ||||||
| 	depth: f32 = 0, | 	depth: f32 = 0, | ||||||
|  | 	texture_offset: Point2D = @splat(0), | ||||||
|  | 	texture_size: Point2D = @splat(1), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const Node = struct { | const Node = struct { | ||||||
| @ -235,6 +239,7 @@ pub const Target = struct { | |||||||
| 
 | 
 | ||||||
| pub const Vertex2D = struct { | pub const Vertex2D = struct { | ||||||
| 	xy: Point2D, | 	xy: Point2D, | ||||||
|  | 	uv: Point2D, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| pub fn bind(context: coral.system.BindContext) std.mem.Allocator.Error!State { | 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}, | 							.indices = &.{0, 1, 2, 0, 2, 3}, | ||||||
| 
 | 
 | ||||||
| 							.vertices = &.{ | 							.vertices = &.{ | ||||||
| 								.{.xy = .{-half_extent, half_extent}},// .uv = .{0, 1}}, | 								.{.xy = .{-half_extent, half_extent}, .uv = .{0, 1}}, | ||||||
| 								.{.xy = .{half_extent, half_extent}},// .uv = .{1, 1}}, | 								.{.xy = .{half_extent, half_extent}, .uv = .{1, 1}}, | ||||||
| 								.{.xy = .{half_extent, -half_extent}},// .uv = .{1, 0}}, | 								.{.xy = .{half_extent, -half_extent}, .uv = .{1, 0}}, | ||||||
| 								.{.xy = .{-half_extent, -half_extent}},//  .uv = .{0, 0}}, | 								.{.xy = .{-half_extent, -half_extent},  .uv = .{0, 0}}, | ||||||
| 							}, | 							}, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
|  | |||||||
| @ -3,18 +3,21 @@ | |||||||
| 
 | 
 | ||||||
| @vs vs | @vs vs | ||||||
| in vec2 mesh_xy; | in vec2 mesh_xy; | ||||||
|  | in vec2 mesh_uv; | ||||||
| 
 | 
 | ||||||
| in vec2 instance_xbasis; | in vec2 instance_xbasis; | ||||||
| in vec2 instance_ybasis; | in vec2 instance_ybasis; | ||||||
| in vec2 instance_origin; | in vec2 instance_origin; | ||||||
| in vec4 instance_color; | in vec4 instance_color; | ||||||
| in float instance_depth; | in float instance_depth; | ||||||
|  | in vec4 instance_rect; | ||||||
| 
 | 
 | ||||||
| uniform Screen { | uniform Screen { | ||||||
| 	vec2 screen_size; | 	vec2 screen_size; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| out vec4 color; | out vec4 color; | ||||||
|  | out vec2 uv; | ||||||
| 
 | 
 | ||||||
| void main() { | void main() { | ||||||
| 	// Calculate the world position of the vertex | 	// Calculate the world position of the vertex | ||||||
| @ -26,18 +29,28 @@ void main() { | |||||||
| 
 | 
 | ||||||
| 	// Set the position of the vertex in clip space | 	// Set the position of the vertex in clip space | ||||||
| 	gl_Position = vec4(ndc_position, instance_depth, 1.0); | 	gl_Position = vec4(ndc_position, instance_depth, 1.0); | ||||||
| 
 |  | ||||||
|     // Set the output color |  | ||||||
| 	color = instance_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 | @end | ||||||
| 
 | 
 | ||||||
| @fs fs | @fs fs | ||||||
|  | uniform texture2D tex; | ||||||
|  | uniform sampler smp; | ||||||
|  | 
 | ||||||
| in vec4 color; | in vec4 color; | ||||||
|  | in vec2 uv; | ||||||
|  | 
 | ||||||
| out vec4 texel; | out vec4 texel; | ||||||
| 
 | 
 | ||||||
| void main() { | void main() { | ||||||
| 	texel = color; | 	texel = texture(sampler2D(tex, smp), uv) * color; | ||||||
| } | } | ||||||
| @end | @end | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user