add initSpritesheet() and deinitSpritesheet()
This commit is contained in:
parent
c09ff2aad0
commit
ed560d3da1
@ -54,8 +54,6 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
||||
.rect = Rect.init(1, 0, 1, 1).multiply(tile_size)
|
||||
});
|
||||
|
||||
try Gfx.packSprites();
|
||||
|
||||
self.* = App{
|
||||
.bg = .black,
|
||||
.player_pos = .init(100, 100),
|
||||
|
||||
121
src/graphics.zig
121
src/graphics.zig
@ -28,6 +28,7 @@ const State = struct {
|
||||
|
||||
default_sprite: Sprite.Id,
|
||||
error_sprite: Sprite.Id,
|
||||
default_spritesheet: Spritesheet.Id,
|
||||
default_sampler: sg.Sampler,
|
||||
|
||||
quads_buffer: [2048]Quad,
|
||||
@ -38,9 +39,9 @@ const State = struct {
|
||||
textures_buffer: [Texture.max_textures]Texture.SlotMap.Slot,
|
||||
textures: Texture.SlotMap,
|
||||
|
||||
spritesheet_texture: Texture.Id,
|
||||
spritesheet_size: Vec2,
|
||||
spritesheet_stale: bool,
|
||||
spritesheets_buffer: [Spritesheet.max_spritesheets]Spritesheet.SlotMap.Slot,
|
||||
spritesheets: Spritesheet.SlotMap,
|
||||
|
||||
sprites_buffer: [Sprite.max_sprites]Sprite.SlotMap.Slot,
|
||||
sprites: Sprite.SlotMap,
|
||||
};
|
||||
@ -137,11 +138,11 @@ pub fn init(gpa: std.mem.Allocator, logger: sg.Logger) !void {
|
||||
.textures = .init(.initBuffer(&self.textures_buffer)),
|
||||
.default_sprite = undefined,
|
||||
.error_sprite = undefined,
|
||||
.spritesheet_stale = false,
|
||||
.sprites_buffer = undefined,
|
||||
.sprites = .init(.initBuffer(&self.sprites_buffer)),
|
||||
.spritesheet_texture = undefined,
|
||||
.spritesheet_size = .init(0, 0)
|
||||
.default_spritesheet = undefined,
|
||||
.spritesheets_buffer = undefined,
|
||||
.spritesheets = .init(.initBuffer(&self.spritesheets_buffer))
|
||||
};
|
||||
|
||||
{
|
||||
@ -195,7 +196,7 @@ pub fn init(gpa: std.mem.Allocator, logger: sg.Logger) !void {
|
||||
});
|
||||
}
|
||||
|
||||
self.spritesheet_texture = try initTexture();
|
||||
self.default_spritesheet = try initSpritesheet();
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
@ -257,7 +258,8 @@ pub fn beginFrame() void {
|
||||
.swapchain = sglue.swapchain()
|
||||
});
|
||||
|
||||
const spritesheet_texture = self.textures.getAssumeExists(self.spritesheet_texture);
|
||||
const default_spritesheet = self.spritesheets.getAssumeExists(self.default_spritesheet);
|
||||
const spritesheet_texture = self.textures.getAssumeExists(default_spritesheet.texture);
|
||||
self.bindings.views[shd.VIEW_tex] = spritesheet_texture.view;
|
||||
self.bindings.samplers[shd.SMP_smp] = self.default_sampler;
|
||||
}
|
||||
@ -432,9 +434,12 @@ pub fn draw(opts: DrawOptions) void {
|
||||
var texture = opts.texture;
|
||||
if (!self.textures.exists(texture)) {
|
||||
if (getSpriteUVRect(self.error_sprite)) |error_uv| {
|
||||
texture = self.spritesheet_texture;
|
||||
quad.setUVRect(error_uv);
|
||||
quad.setColor(.white);
|
||||
|
||||
const sprite = self.sprites.getAssumeExists(self.error_sprite);
|
||||
const spritesheet = self.spritesheets.getAssumeExists(sprite.spritesheet);
|
||||
texture = spritesheet.texture;
|
||||
} else {
|
||||
log.err("Failed to draw error texture", .{});
|
||||
return;
|
||||
@ -462,6 +467,7 @@ pub fn initSprite() !Sprite.Id {
|
||||
|
||||
const sprite = self.sprites.getAssumeExists(id);
|
||||
sprite.* = .{
|
||||
.spritesheet = self.default_spritesheet,
|
||||
.data = null,
|
||||
.position = null
|
||||
};
|
||||
@ -477,7 +483,11 @@ pub fn deinitSprite(id: Sprite.Id) void {
|
||||
data.deinit(self.gpa);
|
||||
}
|
||||
self.sprites.removeAssumeExists(id);
|
||||
self.spritesheet_stale = true;
|
||||
|
||||
|
||||
if (self.spritesheets.get(sprite.spritesheet)) |spritesheet| {
|
||||
spritesheet.stale = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,11 +532,21 @@ pub fn setSprite(id: Sprite.Id, opts: SetSpriteOptions) void {
|
||||
|
||||
sprite.data = sprite_data;
|
||||
sprite.position = null;
|
||||
self.spritesheet_stale = true;
|
||||
if (self.spritesheets.get(sprite.spritesheet)) |spritesheet| {
|
||||
spritesheet.stale = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn packSprites() !void {
|
||||
pub fn packSprites(id: Spritesheet.Id) !void {
|
||||
const self = &g_state;
|
||||
const spritesheet = self.spritesheets.get(id) orelse {
|
||||
log.warn("Attempt to pack spritesheet that doesn't exist: {}", .{id});
|
||||
return;
|
||||
};
|
||||
|
||||
if (!spritesheet.stale) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Add a smarter startegy for picking the initial texture size.
|
||||
// One idea is to calculate the sum area of all sprites and pick a atlas size based on that.
|
||||
@ -564,8 +584,8 @@ pub fn packSprites() !void {
|
||||
continue;
|
||||
}
|
||||
|
||||
const spritesheet = try ImageData.initRGBA8(self.gpa, texture_size, texture_size);
|
||||
defer spritesheet.deinit(self.gpa);
|
||||
const image_data = try ImageData.initRGBA8(self.gpa, texture_size, texture_size);
|
||||
defer image_data.deinit(self.gpa);
|
||||
|
||||
{
|
||||
var i: usize = 0;
|
||||
@ -578,7 +598,7 @@ pub fn packSprites() !void {
|
||||
const x: u32 = @intCast(rects[i].x);
|
||||
const y: u32 = @intCast(rects[i].y);
|
||||
sprite.position = .initFromInt(u32, x, y);
|
||||
spritesheet.copyFrom(
|
||||
image_data.copyFrom(
|
||||
sprite_data,
|
||||
x,
|
||||
y,
|
||||
@ -590,10 +610,10 @@ pub fn packSprites() !void {
|
||||
}
|
||||
}
|
||||
|
||||
setTexture(self.spritesheet_texture, spritesheet);
|
||||
setTexture(spritesheet.texture, image_data);
|
||||
|
||||
self.spritesheet_size = .initFromInt(u32, texture_size, texture_size);
|
||||
self.spritesheet_stale = false;
|
||||
spritesheet.size = .initFromInt(u32, texture_size, texture_size);
|
||||
spritesheet.stale = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -613,18 +633,19 @@ pub fn getSpriteUVRect(id: Sprite.Id) ?Rect {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (self.spritesheet_stale) {
|
||||
packSprites() catch |e| {
|
||||
const spritesheet = self.spritesheets.get(sprite.spritesheet) orelse return null;
|
||||
|
||||
packSprites(sprite.spritesheet) catch |e| {
|
||||
log.warn("Failed to pack sprites: {}", .{e});
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
assert(sprite.position != null);
|
||||
|
||||
const sprite_size = Vec2.initFromInt(u32, sprite.data.?.width, sprite.data.?.height);
|
||||
return Rect{
|
||||
.pos = sprite.position.?.divide(self.spritesheet_size),
|
||||
.size = sprite_size.divide(self.spritesheet_size),
|
||||
.pos = sprite.position.?.divide(spritesheet.size),
|
||||
.size = sprite_size.divide(spritesheet.size),
|
||||
};
|
||||
}
|
||||
|
||||
@ -635,19 +656,58 @@ pub fn drawSprite(id: Sprite.Id, pos: Vec2, size: Vec2, color: Color) void {
|
||||
quad.setColor(color);
|
||||
quad.setRect(.{ .pos = pos, .size = size });
|
||||
|
||||
var texture: ?Texture.Id = null;
|
||||
if (getSpriteUVRect(id)) |sprite_uv| {
|
||||
quad.setUVRect(sprite_uv);
|
||||
} else if (getSpriteUVRect(self.error_sprite)) |error_uv| {
|
||||
if (self.sprites.get(id)) |sprite| {
|
||||
if (self.spritesheets.get(sprite.spritesheet)) |spritesheet| {
|
||||
texture = spritesheet.texture;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (texture == null) {
|
||||
if (getSpriteUVRect(self.error_sprite)) |error_uv| {
|
||||
quad.setUVRect(error_uv);
|
||||
quad.setColor(.white);
|
||||
|
||||
const sprite = self.sprites.getAssumeExists(self.error_sprite);
|
||||
const spritesheet = self.spritesheets.getAssumeExists(sprite.spritesheet);
|
||||
texture = spritesheet.texture;
|
||||
}
|
||||
}
|
||||
|
||||
if (texture == null) {
|
||||
log.warn("Failed to draw sprite", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
draw(.{
|
||||
.texture = self.spritesheet_texture,
|
||||
.texture = texture.?,
|
||||
.quad = quad
|
||||
});
|
||||
}
|
||||
|
||||
pub fn initSpritesheet() !Spritesheet.Id {
|
||||
// TODO: self.spritesheet_texture = try initTexture();
|
||||
const self = &g_state;
|
||||
const id = try self.spritesheets.insertBounded();
|
||||
|
||||
const spritesheet = self.spritesheets.getAssumeExists(id);
|
||||
spritesheet.* = .{
|
||||
.texture = try initTexture(),
|
||||
.size = .init(0, 0),
|
||||
.stale = false,
|
||||
};
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
pub fn deinitSpritesheet(id: Spritesheet.Id) void {
|
||||
_ = id; // autofix
|
||||
}
|
||||
|
||||
pub const ImageData = struct {
|
||||
const Pixels = union(enum) {
|
||||
none,
|
||||
@ -755,6 +815,7 @@ pub const Texture = struct {
|
||||
};
|
||||
|
||||
pub const Sprite = struct {
|
||||
spritesheet: Spritesheet.Id,
|
||||
data: ?ImageData,
|
||||
position: ?Vec2,
|
||||
|
||||
@ -763,6 +824,16 @@ pub const Sprite = struct {
|
||||
pub const Id = SlotMap.Id;
|
||||
};
|
||||
|
||||
pub const Spritesheet = struct {
|
||||
texture: Texture.Id,
|
||||
size: Vec2,
|
||||
stale: bool,
|
||||
|
||||
const max_spritesheets = 64;
|
||||
const SlotMap = SlotMapType(std.math.IntFittingRange(0, max_spritesheets-1), u8, Spritesheet);
|
||||
pub const Id = SlotMap.Id;
|
||||
};
|
||||
|
||||
pub const Vertex = extern struct {
|
||||
position: Vec2,
|
||||
texcoord: Vec2,
|
||||
|
||||
@ -51,7 +51,7 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
|
||||
index: Index,
|
||||
|
||||
pub fn format(self: Id, writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||
try writer.print("Id{{ {}, {} }}", .{ self.index, self.generation });
|
||||
try writer.print("Id({s}){{ {}, {} }}", .{ @typeName(Value), self.index, self.generation });
|
||||
}
|
||||
};
|
||||
|
||||
@ -173,9 +173,16 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
|
||||
return slot.used and slot.generation == id.generation;
|
||||
}
|
||||
|
||||
pub fn get(self: *Self, id: Id) ?*Value {
|
||||
if (self.exists(id)) {
|
||||
return &self.slots.items[id.index].value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn getAssumeExists(self: *Self, id: Id) *Value {
|
||||
assert(self.exists(id));
|
||||
return &self.slots.items[id.index].value;
|
||||
return self.get(id).?;
|
||||
}
|
||||
|
||||
pub fn removeAssumeExists(self: *Self, id: Id) void {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user