Add gfx.Commands.draw_texture (closes #67)
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
13c58bf106
commit
bb1d383ccb
|
@ -13,6 +13,9 @@ const CRT = extern struct {
|
|||
|
||||
const Effects = struct {
|
||||
render_texture: gfx.Texture = .default,
|
||||
image_textures: [2]gfx.Texture = [_]gfx.Texture{.default} ** 2,
|
||||
last_time: f64 = 0,
|
||||
image_index: usize = 0,
|
||||
crt_effect: gfx.Effect = .default,
|
||||
};
|
||||
|
||||
|
@ -31,14 +34,44 @@ fn load(display: ona.Write(gfx.Display), effects: ona.Write(Effects), assets: on
|
|||
});
|
||||
|
||||
effects.state.crt_effect = try assets.state.load_effect_file(ona.files.bundle, "./crt.frag.spv");
|
||||
|
||||
var descs = gfx.Descs.init(ona.heap.allocator);
|
||||
|
||||
defer {
|
||||
descs.deinit();
|
||||
}
|
||||
|
||||
effects.state.image_textures = .{
|
||||
try assets.state.load_texture(try descs.checker_texture(.{
|
||||
.colors = .{gfx.colors.black, gfx.colors.purple},
|
||||
.width = 8,
|
||||
.height = 8,
|
||||
})),
|
||||
|
||||
try assets.state.load_texture(try descs.checker_texture(.{
|
||||
.colors = .{gfx.colors.black, gfx.colors.grey},
|
||||
.width = 8,
|
||||
.height = 8,
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
pub const main = ona.App.setup.
|
||||
with_module(gfx).
|
||||
with_state(Effects{}).
|
||||
with_system(.load, ona.system_fn(load), .{.label = "load effects"}).
|
||||
with_system(.update, ona.system_fn(update), .{.label = "update effects"}).
|
||||
with_system(.render, ona.system_fn(render), .{.label = "render effects"}).build();
|
||||
|
||||
fn update(effects: ona.Write(Effects), app: ona.Read(ona.App)) void {
|
||||
const update_seconds = 5;
|
||||
|
||||
if ((app.state.elapsed_time - effects.state.last_time) > update_seconds) {
|
||||
effects.state.image_index = (effects.state.image_index + 1) % effects.state.image_textures.len;
|
||||
effects.state.last_time = app.state.elapsed_time;
|
||||
}
|
||||
}
|
||||
|
||||
fn render(commands: gfx.Commands, effects: ona.Write(Effects), app: ona.Read(ona.App), display: ona.Write(gfx.Display)) !void {
|
||||
try commands.set_target(.{
|
||||
.texture = effects.state.render_texture,
|
||||
|
@ -55,7 +88,7 @@ fn render(commands: gfx.Commands, effects: ona.Write(Effects), app: ona.Read(ona
|
|||
});
|
||||
|
||||
try commands.draw_texture(.{
|
||||
.texture = .default,
|
||||
.texture = effects.state.image_textures[effects.state.image_index],
|
||||
.transform = display_transform,
|
||||
.resolution = .{display.state.width, display.state.height},
|
||||
});
|
||||
|
|
|
@ -7,29 +7,29 @@ const ona = @import("ona");
|
|||
const std = @import("std");
|
||||
|
||||
const Spawned = struct {
|
||||
visual: struct {
|
||||
color: gfx.Color,
|
||||
transform: gfx.Transform2D,
|
||||
},
|
||||
|
||||
lifetime_seconds: f32,
|
||||
};
|
||||
|
||||
const Visuals = struct {
|
||||
spawned_keyboards: ona.stack.Parallel(Spawned) = .{},
|
||||
spawned_mouses: ona.stack.Parallel(Spawned) = .{},
|
||||
keyboard_icon: gfx.Texture = .default,
|
||||
mouse_icon: gfx.Texture = .default,
|
||||
spawned: ona.stack.Parallel(Spawned) = .{},
|
||||
random: std.Random.Xoroshiro128,
|
||||
mouse_position: @Vector(2, f32) = @splat(0),
|
||||
};
|
||||
|
||||
fn cleanup(visuals: ona.Write(Visuals)) !void {
|
||||
visuals.state.spawned_keyboards.deinit();
|
||||
visuals.state.spawned_mouses.deinit();
|
||||
visuals.state.spawned.deinit();
|
||||
visuals.state.spawned.deinit();
|
||||
}
|
||||
|
||||
fn load(visuals: ona.Write(Visuals)) !void {
|
||||
const initial_spawn_capacity = 1024;
|
||||
|
||||
try visuals.state.spawned_keyboards.grow(initial_spawn_capacity);
|
||||
try visuals.state.spawned_mouses.grow(initial_spawn_capacity);
|
||||
try visuals.state.spawned.grow(initial_spawn_capacity);
|
||||
}
|
||||
|
||||
pub const main = ona.App.setup.
|
||||
|
@ -42,8 +42,7 @@ pub const main = ona.App.setup.
|
|||
with_system(.exit, ona.system_fn(cleanup), .{.label = "clean up visuals"}).build();
|
||||
|
||||
fn update(visuals: ona.Write(Visuals), events: ona.Receive(hid.Event), display: ona.Read(gfx.Display)) !void {
|
||||
update_spawned(&visuals.state.spawned_keyboards);
|
||||
update_spawned(&visuals.state.spawned_mouses);
|
||||
update_spawned(&visuals.state.spawned);
|
||||
|
||||
const random = visuals.state.random.random();
|
||||
const width: f32 = @floatFromInt(display.state.width);
|
||||
|
@ -53,26 +52,34 @@ fn update(visuals: ona.Write(Visuals), events: ona.Receive(hid.Event), display:
|
|||
for (events.messages()) |event| {
|
||||
switch (event) {
|
||||
.key_down => {
|
||||
try visuals.state.spawned_keyboards.push_grow(.{
|
||||
try visuals.state.spawned.push_grow(.{
|
||||
.lifetime_seconds = 2.5 + (5 * random.float(f32)),
|
||||
|
||||
.visual = .{
|
||||
.color = .{random.float(f32), random.float(f32), random.float(f32), random.float(f32)},
|
||||
|
||||
.transform = gfx.transform_2d(.{
|
||||
.translation = .{width * random.float(f32), height},
|
||||
.rotation = std.math.pi * random.float(f32),
|
||||
.scale = icon_scale,
|
||||
}),
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
.mouse_down => {
|
||||
try visuals.state.spawned_mouses.push_grow(.{
|
||||
try visuals.state.spawned.push_grow(.{
|
||||
.lifetime_seconds = 2.5 + (5 * random.float(f32)),
|
||||
|
||||
.visual = .{
|
||||
.color = .{random.float(f32), random.float(f32), random.float(f32), random.float(f32)},
|
||||
|
||||
.transform = gfx.transform_2d(.{
|
||||
.translation = visuals.state.mouse_position,
|
||||
.rotation = std.math.pi * random.float(f32),
|
||||
.scale = icon_scale,
|
||||
}),
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -88,8 +95,8 @@ fn update(visuals: ona.Write(Visuals), events: ona.Receive(hid.Event), display:
|
|||
fn update_spawned(spawned: *ona.stack.Parallel(Spawned)) void {
|
||||
const float_speed = 6;
|
||||
|
||||
for (spawned.values.slice(.transform)) |*transform| {
|
||||
transform.* = transform.translated(.{0, -float_speed});
|
||||
for (spawned.values.slice(.visual)) |*visual| {
|
||||
visual.transform = visual.transform.translated(.{0, -float_speed});
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -113,17 +120,10 @@ fn update_spawned(spawned: *ona.stack.Parallel(Spawned)) void {
|
|||
}
|
||||
|
||||
fn render(visuals: ona.Write(Visuals), commands: gfx.Commands) !void {
|
||||
for (visuals.state.spawned_keyboards.values.slice(.transform)) |transform| {
|
||||
try commands.draw_texture(.{
|
||||
.texture = visuals.state.keyboard_icon,
|
||||
.transform = transform,
|
||||
});
|
||||
}
|
||||
|
||||
for (visuals.state.spawned_mouses.values.slice(.transform)) |transform| {
|
||||
try commands.draw_texture(.{
|
||||
.texture = visuals.state.keyboard_icon,
|
||||
.transform = transform,
|
||||
for (visuals.state.spawned.values.slice(.visual)) |visual| {
|
||||
try commands.draw_rect(.{
|
||||
.transform = visual.transform,
|
||||
.color = visual.color,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -454,35 +454,26 @@ pub fn init() !Self {
|
|||
}
|
||||
|
||||
const assert = struct {
|
||||
fn is_handle(expected: anytype, actual: @TypeOf(expected)) void {
|
||||
std.debug.assert(actual == expected);
|
||||
fn is_default_handle(actual: anytype) void {
|
||||
std.debug.assert(actual == .default);
|
||||
}
|
||||
};
|
||||
|
||||
assert.is_handle(gfx.Effect.default, try pools.create_effect(.{
|
||||
var descs = gfx.Descs.init(ona.heap.allocator);
|
||||
|
||||
defer {
|
||||
descs.deinit();
|
||||
}
|
||||
|
||||
assert.is_default_handle(try pools.create_effect(.{
|
||||
.fragment_spirv_ops = &spirv.to_ops(@embedFile("./shaders/2d_default.frag.spv")),
|
||||
}));
|
||||
|
||||
assert.is_handle(gfx.Texture.default, try pools.create_texture(.{
|
||||
.format = .rgba8,
|
||||
|
||||
.access = .{
|
||||
.static = .{
|
||||
.data = std.mem.asBytes(&[_]u32{
|
||||
0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080,
|
||||
0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000,
|
||||
0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080,
|
||||
0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000,
|
||||
0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080,
|
||||
0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000,
|
||||
0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080,
|
||||
0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000, 0xFF800080, 0xFF000000,
|
||||
}),
|
||||
|
||||
assert.is_default_handle(try pools.create_texture(try descs.solid_texture(.{
|
||||
.width = 8,
|
||||
},
|
||||
},
|
||||
}));
|
||||
.height = 8,
|
||||
.color = gfx.colors.white,
|
||||
})));
|
||||
|
||||
return pools;
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
const gfx = @import("./gfx.zig");
|
||||
|
||||
pub const black = greyscale(0);
|
||||
|
||||
pub fn greyscale(v: f32) gfx.Color {
|
||||
return .{v, v, v, 1};
|
||||
}
|
||||
|
||||
pub fn rgb(r: f32, g: f32, b: f32) gfx.Color {
|
||||
return .{r, g, b, 1};
|
||||
}
|
||||
|
||||
pub const white = greyscale(1);
|
270
src/gfx/gfx.zig
270
src/gfx/gfx.zig
|
@ -1,5 +1,3 @@
|
|||
pub const colors = @import("./colors.zig");
|
||||
|
||||
const hid = @import("hid");
|
||||
|
||||
const ona = @import("ona");
|
||||
|
@ -14,7 +12,6 @@ const std = @import("std");
|
|||
|
||||
pub const Assets = struct {
|
||||
window: *ext.SDL_Window,
|
||||
texture_formats: ona.stack.Sequential(TextureFormat),
|
||||
frame_rendered: std.Thread.ResetEvent = .{},
|
||||
pending_work: WorkQueue = .{},
|
||||
has_worker_thread: ?std.Thread = null,
|
||||
|
@ -72,8 +69,6 @@ pub const Assets = struct {
|
|||
worker_thread.join();
|
||||
}
|
||||
|
||||
self.texture_formats.deinit();
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
|
@ -94,7 +89,6 @@ pub const Assets = struct {
|
|||
}
|
||||
|
||||
return .{
|
||||
.texture_formats = .{.allocator = ona.heap.allocator},
|
||||
.window = window,
|
||||
};
|
||||
}
|
||||
|
@ -143,24 +137,6 @@ pub const Assets = struct {
|
|||
return loaded.get().*;
|
||||
}
|
||||
|
||||
pub fn load_texture_file(self: *Assets, storage: ona.files.Storage, path: []const u8) LoadFileError!Texture {
|
||||
var arena = std.heap.ArenaAllocator.init(ona.heap.allocator);
|
||||
|
||||
defer {
|
||||
arena.deinit();
|
||||
}
|
||||
|
||||
for (self.texture_formats.values) |format| {
|
||||
if (!std.mem.endsWith(u8, path, format.extension)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return self.load_texture(try format.load_file(&arena, storage, path));
|
||||
}
|
||||
|
||||
return error.FormatUnsupported;
|
||||
}
|
||||
|
||||
pub const thread_restriction = .main;
|
||||
};
|
||||
|
||||
|
@ -169,12 +145,18 @@ pub const Color = @Vector(4, f32);
|
|||
pub const Commands = struct {
|
||||
pending: *List,
|
||||
|
||||
const Command = union (enum) {
|
||||
pub const Command = union (enum) {
|
||||
draw_rect: DrawRectCommand,
|
||||
draw_texture: DrawTextureCommand,
|
||||
set_effect: SetEffectCommand,
|
||||
set_target: SetTargetCommand,
|
||||
};
|
||||
|
||||
pub const DrawRectCommand = struct {
|
||||
color: Color,
|
||||
transform: Transform2D,
|
||||
};
|
||||
|
||||
pub const DrawTextureCommand = struct {
|
||||
texture: Texture,
|
||||
transform: Transform2D,
|
||||
|
@ -264,6 +246,10 @@ pub const Commands = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn draw_rect(self: Commands, command: DrawRectCommand) std.mem.Allocator.Error!void {
|
||||
try self.pending.stack.push_grow(.{.draw_rect = command});
|
||||
}
|
||||
|
||||
pub fn draw_texture(self: Commands, command: DrawTextureCommand) std.mem.Allocator.Error!void {
|
||||
try self.pending.stack.push_grow(.{.draw_texture = command});
|
||||
}
|
||||
|
@ -286,6 +272,150 @@ pub const Commands = struct {
|
|||
}
|
||||
};
|
||||
|
||||
pub const Descs = struct {
|
||||
arena: std.heap.ArenaAllocator,
|
||||
|
||||
pub const CheckerTextureDesc = struct {
|
||||
width: u16,
|
||||
height: u16,
|
||||
colors: [2]Color,
|
||||
};
|
||||
|
||||
pub const BmpTextureDesc = struct {
|
||||
storage: ona.files.Storage,
|
||||
path: []const u8,
|
||||
};
|
||||
|
||||
pub const SolidTextureDesc = struct {
|
||||
width: u16,
|
||||
height: u16,
|
||||
color: Color,
|
||||
};
|
||||
|
||||
pub fn bmp_texture(self: *Descs, desc: BmpTextureDesc) (error { OutOfMemory, FormatUnsupported })!Texture.Desc {
|
||||
const header = try desc.storage.read_little(desc.path, 0, extern struct {
|
||||
type: [2]u8 align (1),
|
||||
file_size: u32 align (1),
|
||||
reserved: [2]u16 align (1),
|
||||
image_offset: u32 align (1),
|
||||
header_size: u32 align (1),
|
||||
pixel_width: i32 align (1),
|
||||
pixel_height: i32 align (1),
|
||||
color_planes: u16 align (1),
|
||||
bits_per_pixel: u16 align (1),
|
||||
compression_method: u32 align (1),
|
||||
image_size: u32 align(1),
|
||||
pixels_per_meter_x: i32 align (1),
|
||||
pixels_per_meter_y: i32 align (1),
|
||||
palette_colors_used: u32 align (1),
|
||||
important_colors_used: u32 align (1),
|
||||
}) orelse {
|
||||
return error.FormatUnsupported;
|
||||
};
|
||||
|
||||
if (!std.mem.eql(u8, &header.type, "BM")) {
|
||||
return error.FormatUnsupported;
|
||||
}
|
||||
|
||||
const pixel_width = std.math.cast(u16, header.pixel_width) orelse {
|
||||
return error.FormatUnsupported;
|
||||
};
|
||||
|
||||
const pixels = try self.arena.allocator().alloc(u8, header.image_size);
|
||||
const bytes_per_pixel = header.bits_per_pixel / @bitSizeOf(u8);
|
||||
const alignment = 4;
|
||||
const byte_stride = pixel_width * bytes_per_pixel;
|
||||
const padded_byte_stride = alignment * @divTrunc((byte_stride + alignment - 1), alignment);
|
||||
const byte_padding = ona.scalars.sub(padded_byte_stride, byte_stride) orelse 0;
|
||||
var buffer_offset: usize = 0;
|
||||
var file_offset = @as(usize, header.image_offset);
|
||||
|
||||
switch (header.bits_per_pixel) {
|
||||
32 => {
|
||||
while (buffer_offset < pixels.len) {
|
||||
const line = pixels[buffer_offset .. buffer_offset + byte_stride];
|
||||
|
||||
if (try desc.storage.read(desc.path, line, file_offset) != byte_stride) {
|
||||
return error.FormatUnsupported;
|
||||
}
|
||||
|
||||
for (0 .. pixel_width) |i| {
|
||||
const line_offset = i * 4;
|
||||
const pixel = line[line_offset .. line_offset + 4];
|
||||
|
||||
std.mem.swap(u8, &pixel[0], &pixel[2]);
|
||||
}
|
||||
|
||||
file_offset += line.len + byte_padding;
|
||||
buffer_offset += padded_byte_stride;
|
||||
}
|
||||
},
|
||||
|
||||
else => return error.FormatUnsupported,
|
||||
}
|
||||
|
||||
return .{
|
||||
.format = .rgba8,
|
||||
|
||||
.access = .{
|
||||
.static = .{
|
||||
.width = pixel_width,
|
||||
.data = pixels,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn checker_texture(self: *Descs, desc: CheckerTextureDesc) std.mem.Allocator.Error!Texture.Desc {
|
||||
const color_data = try self.arena.allocator().alloc(u32, desc.width * desc.height);
|
||||
|
||||
for (color_data, 0 .. color_data.len) |*color, i| {
|
||||
const row = i / desc.width;
|
||||
const col = i % desc.width;
|
||||
|
||||
color.* = colors.compress(desc.colors[(col + (row % 2)) % desc.colors.len]);
|
||||
}
|
||||
|
||||
return .{
|
||||
.access = .{
|
||||
.static = .{
|
||||
.data = std.mem.sliceAsBytes(color_data),
|
||||
.width = desc.width,
|
||||
},
|
||||
},
|
||||
|
||||
.format = .rgba8,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Descs) void {
|
||||
self.arena.deinit();
|
||||
}
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) Descs {
|
||||
return .{
|
||||
.arena = std.heap.ArenaAllocator.init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn solid_texture(self: *Descs, desc: SolidTextureDesc) std.mem.Allocator.Error!Texture.Desc {
|
||||
const color_data = try self.arena.allocator().alloc(u32, desc.width * desc.height);
|
||||
|
||||
@memset(color_data, colors.compress(desc.color));
|
||||
|
||||
return .{
|
||||
.access = .{
|
||||
.static = .{
|
||||
.data = std.mem.sliceAsBytes(color_data),
|
||||
.width = desc.width,
|
||||
},
|
||||
},
|
||||
|
||||
.format = .rgba8,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Display = struct {
|
||||
width: u16 = 1280,
|
||||
height: u16 = 720,
|
||||
|
@ -398,79 +528,30 @@ pub const Transform2D = extern struct {
|
|||
}
|
||||
};
|
||||
|
||||
fn load_bmp_texture(arena: *std.heap.ArenaAllocator, storage: ona.files.Storage, path: []const u8) !Texture.Desc {
|
||||
const header = try storage.read_little(path, 0, extern struct {
|
||||
type: [2]u8 align (1),
|
||||
file_size: u32 align (1),
|
||||
reserved: [2]u16 align (1),
|
||||
image_offset: u32 align (1),
|
||||
header_size: u32 align (1),
|
||||
pixel_width: i32 align (1),
|
||||
pixel_height: i32 align (1),
|
||||
color_planes: u16 align (1),
|
||||
bits_per_pixel: u16 align (1),
|
||||
compression_method: u32 align (1),
|
||||
image_size: u32 align(1),
|
||||
pixels_per_meter_x: i32 align (1),
|
||||
pixels_per_meter_y: i32 align (1),
|
||||
palette_colors_used: u32 align (1),
|
||||
important_colors_used: u32 align (1),
|
||||
}) orelse {
|
||||
return error.FormatUnsupported;
|
||||
};
|
||||
pub const colors = struct {
|
||||
pub const black = greyscale(0);
|
||||
|
||||
if (!std.mem.eql(u8, &header.type, "BM")) {
|
||||
return error.FormatUnsupported;
|
||||
pub fn compress(color: Color) u32 {
|
||||
const range: Color = @splat(255);
|
||||
const r, const g, const b, const a = color * range;
|
||||
|
||||
return @bitCast([_]u8{@intFromFloat(r), @intFromFloat(g), @intFromFloat(b), @intFromFloat(a)});
|
||||
}
|
||||
|
||||
const pixel_width = std.math.cast(u16, header.pixel_width) orelse {
|
||||
return error.FormatUnsupported;
|
||||
};
|
||||
pub const grey = greyscale(0.5);
|
||||
|
||||
const pixels = try arena.allocator().alloc(u8, header.image_size);
|
||||
const bytes_per_pixel = header.bits_per_pixel / @bitSizeOf(u8);
|
||||
const alignment = 4;
|
||||
const byte_stride = pixel_width * bytes_per_pixel;
|
||||
const padded_byte_stride = alignment * @divTrunc((byte_stride + alignment - 1), alignment);
|
||||
const byte_padding = ona.scalars.sub(padded_byte_stride, byte_stride) orelse 0;
|
||||
var buffer_offset: usize = 0;
|
||||
var file_offset = @as(usize, header.image_offset);
|
||||
|
||||
switch (header.bits_per_pixel) {
|
||||
32 => {
|
||||
while (buffer_offset < pixels.len) {
|
||||
const line = pixels[buffer_offset .. buffer_offset + byte_stride];
|
||||
|
||||
if (try storage.read(path, line, file_offset) != byte_stride) {
|
||||
return error.FormatUnsupported;
|
||||
pub fn greyscale(v: f32) Color {
|
||||
return .{v, v, v, 1};
|
||||
}
|
||||
|
||||
for (0 .. pixel_width) |i| {
|
||||
const line_offset = i * 4;
|
||||
const pixel = line[line_offset .. line_offset + 4];
|
||||
pub const purple = rgb(0.5, 0, 0.5);
|
||||
|
||||
std.mem.swap(u8, &pixel[0], &pixel[2]);
|
||||
pub fn rgb(r: f32, g: f32, b: f32) Color {
|
||||
return .{r, g, b, 1};
|
||||
}
|
||||
|
||||
file_offset += line.len + byte_padding;
|
||||
buffer_offset += padded_byte_stride;
|
||||
}
|
||||
},
|
||||
|
||||
else => return error.FormatUnsupported,
|
||||
}
|
||||
|
||||
return .{
|
||||
.format = .rgba8,
|
||||
|
||||
.access = .{
|
||||
.static = .{
|
||||
.width = pixel_width,
|
||||
.data = pixels,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
pub const white = greyscale(1);
|
||||
};
|
||||
|
||||
pub fn poll(app: ona.Write(ona.App), events: ona.Send(hid.Event)) !void {
|
||||
var event = @as(ext.SDL_Event, undefined);
|
||||
|
@ -551,17 +632,6 @@ pub fn setup(world: *ona.World, events: ona.App.Events) (error {Unsupported} ||
|
|||
assets.window,
|
||||
});
|
||||
|
||||
const builtin_texture_formats = [_]Assets.TextureFormat{
|
||||
.{
|
||||
.extension = "bmp",
|
||||
.load_file = load_bmp_texture,
|
||||
},
|
||||
};
|
||||
|
||||
for (builtin_texture_formats) |format| {
|
||||
try assets.texture_formats.push_grow(format);
|
||||
}
|
||||
|
||||
try world.set_state(Display{});
|
||||
try world.on_event(events.pre_update, ona.system_fn(poll), .{.label = "poll gfx"});
|
||||
try world.on_event(events.exit, ona.system_fn(stop), .{.label = "stop gfx"});
|
||||
|
|
|
@ -69,14 +69,42 @@ const Frame = struct {
|
|||
});
|
||||
|
||||
return .{
|
||||
.texture_batch_buffers = .{.allocator = ona.heap.allocator},
|
||||
.texture_batch_buffers = .{},
|
||||
.quad_index_buffer = quad_index_buffer,
|
||||
.quad_vertex_buffer = quad_vertex_buffer,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn draw_rect(self: *Frame, resources: *Resources, command: gfx.Commands.DrawRectCommand) !void {
|
||||
if (self.current_source_texture != .default) {
|
||||
self.flush(resources);
|
||||
}
|
||||
|
||||
self.current_source_texture = .default;
|
||||
|
||||
const has_filled_current_buffer = (self.drawn_count % batches_per_buffer) == 0;
|
||||
const buffer_count = self.drawn_count / batches_per_buffer;
|
||||
|
||||
if (has_filled_current_buffer and buffer_count == self.texture_batch_buffers.len()) {
|
||||
const instance_buffer = sokol.gfx.makeBuffer(.{
|
||||
.size = @sizeOf(DrawTexture) * batches_per_buffer,
|
||||
.usage = .STREAM,
|
||||
});
|
||||
|
||||
errdefer sokol.gfx.destroyBuffer(instance_buffer);
|
||||
|
||||
try self.texture_batch_buffers.push_grow(instance_buffer);
|
||||
}
|
||||
|
||||
_ = sokol.gfx.appendBuffer(self.texture_batch_buffers.get().?.*, sokol.gfx.asRange(&DrawTexture{
|
||||
.transform = command.transform,
|
||||
}));
|
||||
|
||||
self.drawn_count += 1;
|
||||
}
|
||||
|
||||
pub fn draw_texture(self: *Frame, resources: *Resources, command: gfx.Commands.DrawTextureCommand) !void {
|
||||
if (command.texture != self.current_source_texture) {
|
||||
if (self.current_source_texture != command.texture) {
|
||||
self.flush(resources);
|
||||
}
|
||||
|
||||
|
@ -377,6 +405,7 @@ pub fn process_work(pending_work: *gfx.Assets.WorkQueue, window: *ext.SDL_Window
|
|||
while (has_command_params) |command_params| : (has_command_params = command_params.has_next) {
|
||||
for (command_params.param.submitted_commands()) |command| {
|
||||
try switch (command) {
|
||||
.draw_rect => |draw_rect| frame.draw_rect(&resources, draw_rect),
|
||||
.draw_texture => |draw_texture| frame.draw_texture(&resources, draw_texture),
|
||||
.set_effect => |set_effect| frame.set_effect(&resources, set_effect),
|
||||
.set_target => |set_target| frame.set_target(&resources, set_target),
|
||||
|
|
Loading…
Reference in New Issue