add nil ids to slotmap

This commit is contained in:
Rokas Puzonas 2026-08-10 01:54:38 +03:00
parent 69ae88c37d
commit 3cfd12d8ba
5 changed files with 134 additions and 141 deletions

View File

@ -62,7 +62,7 @@ const Tilesheet = struct {
pub fn init(gpa: Allocator, image: Gfx.ImageData, width: u32, height: u32, tile_size: Vec2) !Tilesheet { pub fn init(gpa: Allocator, image: Gfx.ImageData, width: u32, height: u32, tile_size: Vec2) !Tilesheet {
const sprites = try gpa.alloc(Gfx.Sprite.Id, width * height); const sprites = try gpa.alloc(Gfx.Sprite.Id, width * height);
errdefer gpa.free(sprites); errdefer gpa.free(sprites);
@memset(sprites, Gfx.getNilSprite()); @memset(sprites, .nil);
return Tilesheet{ return Tilesheet{
.sprites = sprites, .sprites = sprites,
@ -82,11 +82,11 @@ const Tilesheet = struct {
pub fn get(self: Tilesheet, x: u32, y: u32) Gfx.Sprite.Id { pub fn get(self: Tilesheet, x: u32, y: u32) Gfx.Sprite.Id {
if (x >= self.width or y >= self.height) { if (x >= self.width or y >= self.height) {
log.warn("Attempt to get tile which is out of bounds", .{}); log.warn("Attempt to get tile which is out of bounds", .{});
return Gfx.getNilSprite(); return .nil;
} }
const sprite_index = y * self.width + x; const sprite_index = y * self.width + x;
if (self.sprites[sprite_index] == Gfx.getNilSprite()) { if (self.sprites[sprite_index] == Gfx.Sprite.Id.nil) {
const sprite = Gfx.initSprite(.{ .padding = 1 }); const sprite = Gfx.initSprite(.{ .padding = 1 });
Gfx.setSprite(sprite, .{ Gfx.setSprite(sprite, .{
.image = self.image, .image = self.image,

82
src/platform/audio.zig Normal file
View File

@ -0,0 +1,82 @@
const std = @import("std");
const log = std.log.scoped(.audio);
const sokol = @import("sokol");
const sapp = sokol.app;
const saudio = sokol.audio;
const tracy = @import("tracy");
const SlotMapType = @import("./slot_map.zig").SlotMapType;
const State = struct {
sounds: Sound.SlotMap
};
var g_state: State = undefined;
pub const InitOptions = struct {
logger: saudio.Logger = .{},
buffer_frames: u32 = 2048,
max_sounds: usize = 128,
};
pub const Sound = struct {
cb: Callback,
userdata: *anyopaque,
volume: f32 = 1,
pub const Callback = *const fn(sound: *Sound, samples: *std.ArrayList(f32)) void;
const SlotMap = SlotMapType(u8, u16, Sound);
pub const Id = SlotMap.Id;
};
pub fn init(gpa: std.mem.Allocator, opts: InitOptions) !void {
const channels = 1; // TODO: Stereo audio
const self = &g_state;
const sounds_buffer = try gpa.alloc(Sound.SlotMap.Slot, opts.max_sounds);
errdefer gpa.free(sounds_buffer);
self.* = State{
.sounds = .init(sounds_buffer)
};
saudio.setup(.{
.stream_userdata_cb = sokolStreamCallback,
.logger = opts.logger,
.num_channels = channels,
.buffer_frames = @intCast(opts.buffer_frames),
});
const sample_rate: f32 = @floatFromInt(saudio.sampleRate());
const max_latency_s: f32 = @as(f32, @floatFromInt(opts.buffer_frames)) / sample_rate;
const max_latency_ns: i64 = @intFromFloat(max_latency_s * std.time.ns_per_s);
log.debug("Init:", .{});
log.debug("- sample_rate: {}", .{saudio.sampleRate()});
log.debug("- channels: {}", .{saudio.channels()});
log.debug("- buffer_frames: {}", .{saudio.bufferFrames()});
log.debug("- max_latency: {f}", .{std.Io.Duration.fromNanoseconds(max_latency_ns)});
}
pub fn deinit(gpa: std.mem.Allocator) void {
var self = &g_state;
saudio.shutdown();
gpa.free(self.sounds.slots.allocatedSlice());
}
pub fn addSound() Sound.Id {
}
pub fn removeSound() void {
}
fn sokolStreamCallback(buffer: [*c]f32, num_frames: i32, num_channels: i32, user_data: ?*anyopaque) callconv(.c) void {
_ = buffer; // autofix
_ = num_frames; // autofix
_ = num_channels; // autofix
_ = user_data; // autofix
}

View File

@ -49,19 +49,15 @@ const State = struct {
textures_buffer: [Texture.max_textures]Texture.SlotMap.Slot, textures_buffer: [Texture.max_textures]Texture.SlotMap.Slot,
textures: Texture.SlotMap, textures: Texture.SlotMap,
nil_texture: Texture.Id,
spritesheets_buffer: [Spritesheet.max_spritesheets]Spritesheet.SlotMap.Slot, spritesheets_buffer: [Spritesheet.max_spritesheets]Spritesheet.SlotMap.Slot,
spritesheets: Spritesheet.SlotMap, spritesheets: Spritesheet.SlotMap,
nil_spritesheet: Spritesheet.Id,
sprites_buffer: [Sprite.max_sprites]Sprite.SlotMap.Slot, sprites_buffer: [Sprite.max_sprites]Sprite.SlotMap.Slot,
sprites: Sprite.SlotMap, sprites: Sprite.SlotMap,
nil_sprite: Sprite.Id,
fonts_buffer: [Font.max_fonts]Font.SlotMap.Slot, fonts_buffer: [Font.max_fonts]Font.SlotMap.Slot,
fonts: Font.SlotMap, fonts: Font.SlotMap,
nil_font: Font.Id,
}; };
var g_state: State = undefined; var g_state: State = undefined;
@ -173,67 +169,17 @@ pub fn init(gpa: std.mem.Allocator, logger: sg.Logger) !void {
.textures_buffer = undefined, .textures_buffer = undefined,
.textures = .init(&self.textures_buffer), .textures = .init(&self.textures_buffer),
.nil_texture = undefined,
.sprites_buffer = undefined, .sprites_buffer = undefined,
.sprites = .init(&self.sprites_buffer), .sprites = .init(&self.sprites_buffer),
.nil_sprite = undefined,
.spritesheets_buffer = undefined, .spritesheets_buffer = undefined,
.spritesheets = .init(&self.spritesheets_buffer), .spritesheets = .init(&self.spritesheets_buffer),
.nil_spritesheet = undefined,
.fonts_buffer = undefined, .fonts_buffer = undefined,
.fonts = .init(&self.fonts_buffer), .fonts = .init(&self.fonts_buffer),
.nil_font = undefined,
}; };
self.nil_texture = self.textures.insertAssumeCapacity();
{
const nil_texture = self.textures.getAssumeExists(self.nil_texture);
nil_texture.* = Texture{
.dynamic = false,
.updated_at = null,
.image = .{ .id = sg.invalid_id },
.view = .{ .id = sg.invalid_id },
};
}
self.nil_spritesheet = self.spritesheets.insertAssumeCapacity();
{
const nil_spritesheet = self.spritesheets.getAssumeExists(self.nil_spritesheet);
nil_spritesheet.* = Spritesheet{
.texture = self.nil_texture,
.format = .rgba8,
.size = .init(0, 0),
.needs_repack = false,
.needs_texture_rebuild = false,
.nodes = undefined,
.packer = null,
};
}
self.nil_sprite = self.sprites.insertAssumeCapacity();
{
const nil_sprite = self.sprites.getAssumeExists(self.nil_sprite);
nil_sprite.* = Sprite{
.spritesheet = self.nil_spritesheet,
.data = .none,
.position = null,
.padding = 0
};
}
self.nil_font = self.fonts.insertAssumeCapacity();
{
const nil_font = self.fonts.getAssumeExists(self.nil_font);
nil_font.* = Font{
.spritesheet = self.nil_spritesheet,
.stb = null,
.cache = .init(),
};
}
self.default_spritesheet = initSpritesheet(.{}); self.default_spritesheet = initSpritesheet(.{});
self.default_font_spritesheet = initSpritesheet(.{ .format = .r8 }); self.default_font_spritesheet = initSpritesheet(.{ .format = .r8 });
@ -612,13 +558,13 @@ pub fn initTexture(opts: TextureOptions) Texture.Id {
const self = &g_state; const self = &g_state;
const id = self.textures.insertUndefined() catch { const id = self.textures.insertUndefined() catch {
log.warn("Failed to create texture, limit reached! limit: {}", .{self.textures.slots.capacity}); log.warn("Failed to create texture, limit reached! limit: {}", .{self.textures.slots.capacity});
return self.nil_texture; return .nil;
}; };
const view = sg.allocView(); const view = sg.allocView();
if (sg.queryViewState(view) != .ALLOC) { if (sg.queryViewState(view) != .ALLOC) {
log.warn("Failed to alloc texture view", .{}); log.warn("Failed to alloc texture view", .{});
return self.nil_texture; return .nil;
} }
const texture = self.textures.getAssumeExists(id); const texture = self.textures.getAssumeExists(id);
@ -665,10 +611,6 @@ pub fn deinitTexture(id: Texture.Id) void {
pub fn setTexture(id: Texture.Id, texture_data: ImageData) void { pub fn setTexture(id: Texture.Id, texture_data: ImageData) void {
const self = &g_state; const self = &g_state;
if (id == self.nil_texture) {
return;
}
const texture = self.textures.get(id) orelse { const texture = self.textures.get(id) orelse {
log.warn("Attempt to set texture that doesn't exist: {}", .{id}); log.warn("Attempt to set texture that doesn't exist: {}", .{id});
return; return;
@ -808,8 +750,7 @@ pub fn draw(opts: DrawOptions) void {
var quad = opts.quad; var quad = opts.quad;
var view: sg.View = .{ .id = sg.invalid_id }; var view: sg.View = .{ .id = sg.invalid_id };
if (opts.texture != self.nil_texture and self.textures.exists(opts.texture)) { if (self.textures.get(opts.texture)) |texture| {
const texture = self.textures.getAssumeExists(opts.texture);
view = texture.view; view = texture.view;
} }
@ -862,17 +803,11 @@ const SpriteOptions = struct {
padding: u32 = 0, padding: u32 = 0,
}; };
// TODO: I don't like this getter, maybe nil_sprite should be a public global variable.
pub fn getNilSprite() Sprite.Id {
const self = &g_state;
return self.nil_sprite;
}
pub fn initSprite(opts: SpriteOptions) Sprite.Id { pub fn initSprite(opts: SpriteOptions) Sprite.Id {
const self = &g_state; const self = &g_state;
const id = self.sprites.insertUndefined() catch { const id = self.sprites.insertUndefined() catch {
log.warn("Failed to create sprite, limit reached! limit: {}", .{self.sprites.slots.capacity}); log.warn("Failed to create sprite, limit reached! limit: {}", .{self.sprites.slots.capacity});
return self.nil_sprite; return .nil;
}; };
const sprite = self.sprites.getAssumeExists(id); const sprite = self.sprites.getAssumeExists(id);
@ -888,10 +823,6 @@ pub fn initSprite(opts: SpriteOptions) Sprite.Id {
pub fn deinitSprite(id: Sprite.Id) void { pub fn deinitSprite(id: Sprite.Id) void {
const self = &g_state; const self = &g_state;
if (id == self.nil_sprite) {
return;
}
if (self.sprites.exists(id)) { if (self.sprites.exists(id)) {
const sprite = self.sprites.getAssumeExists(id); const sprite = self.sprites.getAssumeExists(id);
if (sprite.data) |data| { if (sprite.data) |data| {
@ -912,10 +843,6 @@ const SetSpriteOptions = struct {
pub fn setSprite(id: Sprite.Id, opts: SetSpriteOptions) void { pub fn setSprite(id: Sprite.Id, opts: SetSpriteOptions) void {
const self = &g_state; const self = &g_state;
if (id == self.nil_sprite) {
return;
}
const sprite = self.sprites.get(id) orelse { const sprite = self.sprites.get(id) orelse {
log.warn("Attempt to set sprite that doesn't exist: {}", .{id}); log.warn("Attempt to set sprite that doesn't exist: {}", .{id});
return; return;
@ -1048,10 +975,6 @@ fn repackSpritesheet(id: Spritesheet.Id) void {
fn repackSpritesheetIfNeeded(id: Spritesheet.Id) void { fn repackSpritesheetIfNeeded(id: Spritesheet.Id) void {
const self = &g_state; const self = &g_state;
if (id == self.nil_spritesheet) {
return;
}
const spritesheet = self.spritesheets.get(id) orelse { const spritesheet = self.spritesheets.get(id) orelse {
log.warn("Attempt to pack spritesheet that doesn't exist: {f}", .{id}); log.warn("Attempt to pack spritesheet that doesn't exist: {f}", .{id});
return; return;
@ -1066,10 +989,6 @@ fn repackSpritesheetIfNeeded(id: Spritesheet.Id) void {
fn rebuildSpritesheetTextureIfNeeded(id: Spritesheet.Id) void { fn rebuildSpritesheetTextureIfNeeded(id: Spritesheet.Id) void {
const self = &g_state; const self = &g_state;
if (id == self.nil_spritesheet) {
return;
}
const spritesheet = self.spritesheets.get(id) orelse return; const spritesheet = self.spritesheets.get(id) orelse return;
if (!spritesheet.needs_texture_rebuild) { if (!spritesheet.needs_texture_rebuild) {
return; return;
@ -1156,10 +1075,6 @@ fn ensureSpritePacked(id: Sprite.Id) bool {
pub fn getSpriteUVRect(id: Sprite.Id) ?Rect { pub fn getSpriteUVRect(id: Sprite.Id) ?Rect {
const self = &g_state; const self = &g_state;
if (id == self.nil_sprite) {
return null;
}
const sprite = self.sprites.get(id) orelse return null; const sprite = self.sprites.get(id) orelse return null;
const sprite_data = sprite.data orelse return null; const sprite_data = sprite.data orelse return null;
@ -1195,18 +1110,16 @@ pub fn drawSpriteQuad(id: Sprite.Id, points: Quad, color: Color) void {
quad.vertices[3].position = points.positions[3]; quad.vertices[3].position = points.positions[3];
var texture: ?Texture.Id = null; var texture: ?Texture.Id = null;
if (id != self.nil_sprite) { if (getSpriteUVRect(id)) |sprite_uv| {
if (getSpriteUVRect(id)) |sprite_uv| { quad.setUVRect(sprite_uv);
quad.setUVRect(sprite_uv);
const sprite = self.sprites.getAssumeExists(id); const sprite = self.sprites.getAssumeExists(id);
const spritesheet = self.spritesheets.getAssumeExists(sprite.spritesheet); const spritesheet = self.spritesheets.getAssumeExists(sprite.spritesheet);
texture = spritesheet.texture; texture = spritesheet.texture;
}
} }
draw(.{ draw(.{
.texture = texture orelse self.nil_texture, .texture = texture orelse .nil,
.quad = quad .quad = quad
}); });
} }
@ -1224,7 +1137,7 @@ pub fn initSpritesheet(opts: SpriteSheetOptions) Spritesheet.Id {
const self = &g_state; const self = &g_state;
const id = self.spritesheets.insertUndefined() catch { const id = self.spritesheets.insertUndefined() catch {
log.warn("Failed to create spritesheet, limit reached! limit: {}", .{self.spritesheets.slots.capacity}); log.warn("Failed to create spritesheet, limit reached! limit: {}", .{self.spritesheets.slots.capacity});
return self.nil_spritesheet; return .nil;
}; };
const spritesheet = self.spritesheets.getAssumeExists(id); const spritesheet = self.spritesheets.getAssumeExists(id);
@ -1243,10 +1156,6 @@ pub fn initSpritesheet(opts: SpriteSheetOptions) Spritesheet.Id {
pub fn deinitSpritesheet(id: Spritesheet.Id) void { pub fn deinitSpritesheet(id: Spritesheet.Id) void {
const self = &g_state; const self = &g_state;
if (id == self.nil_spritesheet) {
return;
}
if (self.spritesheets.get(id)) { if (self.spritesheets.get(id)) {
const spritesheet = self.spritesheets.getAssumeExists(id); const spritesheet = self.spritesheets.getAssumeExists(id);
deinitTexture(spritesheet.texture); deinitTexture(spritesheet.texture);
@ -1258,7 +1167,7 @@ pub fn initFont() Font.Id {
const self = &g_state; const self = &g_state;
const id = self.fonts.insertUndefined() catch { const id = self.fonts.insertUndefined() catch {
log.warn("Failed to create font, limit reached! limit: {}", .{self.fonts.slots.capacity}); log.warn("Failed to create font, limit reached! limit: {}", .{self.fonts.slots.capacity});
return self.nil_font; return .nil;
}; };
const font = self.fonts.getAssumeExists(id); const font = self.fonts.getAssumeExists(id);
@ -1273,10 +1182,6 @@ pub fn initFont() Font.Id {
pub fn deinitFont(id: Font.Id) void { pub fn deinitFont(id: Font.Id) void {
const self = &g_state; const self = &g_state;
if (id == self.nil_font) {
return;
}
if (self.fonts.get(id)) |font| { if (self.fonts.get(id)) |font| {
font.cache.deinit(); font.cache.deinit();
self.fonts.removeAssumeExists(id); self.fonts.removeAssumeExists(id);
@ -1285,10 +1190,6 @@ pub fn deinitFont(id: Font.Id) void {
pub fn setFont(id: Font.Id, ttf_data: [:0]const u8) void { pub fn setFont(id: Font.Id, ttf_data: [:0]const u8) void {
const self = &g_state; const self = &g_state;
if (id == self.nil_font) {
return;
}
const font = self.fonts.get(id) orelse { const font = self.fonts.get(id) orelse {
log.warn("Attempt to set font that doesn't exist: {}", .{id}); log.warn("Attempt to set font that doesn't exist: {}", .{id});
return; return;
@ -1312,17 +1213,9 @@ pub fn setFont(id: Font.Id, ttf_data: [:0]const u8) void {
font.cache = .init(); font.cache = .init();
} }
fn getFont(id: Font.Id) ?*Font {
const self = &g_state;
if (id == self.nil_font) {
return null;
}
return self.fonts.get(id);
}
pub fn getGlyphIndex(id: Font.Id, codepoint: u21) ?GlyphIndex { pub fn getGlyphIndex(id: Font.Id, codepoint: u21) ?GlyphIndex {
const font = getFont(id) orelse return null; const self = &g_state;
const font = self.fonts.get(id) orelse return null;
const stb_font = font.stb orelse return null; const stb_font = font.stb orelse return null;
if (stb_font.findGlyphIndex(codepoint)) |index| { if (stb_font.findGlyphIndex(codepoint)) |index| {
@ -1334,14 +1227,16 @@ pub fn getGlyphIndex(id: Font.Id, codepoint: u21) ?GlyphIndex {
} }
pub fn getFontPixelScale(id: Font.Id, height: f32) f32 { pub fn getFontPixelScale(id: Font.Id, height: f32) f32 {
const font = getFont(id) orelse return 0; const self = &g_state;
const font = self.fonts.get(id) orelse return 0;
const stb_font = font.stb orelse return 0; const stb_font = font.stb orelse return 0;
return stb_font.scaleForPixelHeight(height); return stb_font.scaleForPixelHeight(height);
} }
pub fn getFontAscent(id: Font.Id, height: f32) f32 { pub fn getFontAscent(id: Font.Id, height: f32) f32 {
const font = getFont(id) orelse return 0; const self = &g_state;
const font = self.fonts.get(id) orelse return 0;
const stb_font = font.stb orelse return 0; const stb_font = font.stb orelse return 0;
const vmetrics = stb_font.getFontVMetrics(); const vmetrics = stb_font.getFontVMetrics();
@ -1351,7 +1246,7 @@ pub fn getFontAscent(id: Font.Id, height: f32) f32 {
pub fn getGlyph(id: Font.Id, index: GlyphIndex, scale_x: f32, scale_y: f32) ?*Font.Glyph { pub fn getGlyph(id: Font.Id, index: GlyphIndex, scale_x: f32, scale_y: f32) ?*Font.Glyph {
const self = &g_state; const self = &g_state;
const font = getFont(id) orelse return null; const font = self.fonts.get(id) orelse return null;
const stb_font = font.stb orelse return null; const stb_font = font.stb orelse return null;
// TODO: Allow specifying a different scale for x and y // TODO: Allow specifying a different scale for x and y
@ -1374,7 +1269,7 @@ pub fn getGlyph(id: Font.Id, index: GlyphIndex, scale_x: f32, scale_y: f32) ?*Fo
const box_width: u32 = @intCast(glyph.box.x1 - glyph.box.x0); const box_width: u32 = @intCast(glyph.box.x1 - glyph.box.x0);
const box_height: u32 = @intCast(glyph.box.y1 - glyph.box.y0); const box_height: u32 = @intCast(glyph.box.y1 - glyph.box.y0);
if (box_width > 0 and box_height > 0) { if (box_width > 0 and box_height > 0) {
assert(glyph.sprite == self.nil_sprite); assert(glyph.sprite == Sprite.Id.nil);
glyph.sprite = initSprite(.{ .spritesheet = font.spritesheet, .padding = 1 }); glyph.sprite = initSprite(.{ .spritesheet = font.spritesheet, .padding = 1 });
assert(box_width < Font.Glyph.max_width); assert(box_width < Font.Glyph.max_width);
@ -1395,7 +1290,7 @@ pub fn getGlyph(id: Font.Id, index: GlyphIndex, scale_x: f32, scale_y: f32) ?*Fo
); );
setSprite(glyph.sprite, .{ .image = bitmap }); setSprite(glyph.sprite, .{ .image = bitmap });
} else { } else {
glyph.sprite = self.nil_sprite; glyph.sprite = .nil;
} }
} }
glyph.used_this_frame = true; glyph.used_this_frame = true;
@ -1431,7 +1326,7 @@ pub const TextRunLayout = struct {
pub fn next(self: *TextRunLayout, glyph_index: GlyphIndex) ?GlyphRect { pub fn next(self: *TextRunLayout, glyph_index: GlyphIndex) ?GlyphRect {
const glyph = getGlyph(self.font, glyph_index, self.scale_x, self.scale_y) orelse return null; const glyph = getGlyph(self.font, glyph_index, self.scale_x, self.scale_y) orelse return null;
const font = getFont(self.font) orelse return null; const font = g_state.fonts.get(self.font) orelse return null;
const stb_font = font.stb orelse return null; const stb_font = font.stb orelse return null;
if (self.prev_glyph) |prev_glyph| { if (self.prev_glyph) |prev_glyph| {
@ -1494,8 +1389,6 @@ pub const DrawTextOptions = struct {
}; };
pub fn drawText(id: Font.Id, opts: DrawTextOptions) void { pub fn drawText(id: Font.Id, opts: DrawTextOptions) void {
const self = &g_state;
var layout = TextRunLayout.init(id, opts.height); var layout = TextRunLayout.init(id, opts.height);
var pos = opts.pos; var pos = opts.pos;
@ -1513,9 +1406,6 @@ pub fn drawText(id: Font.Id, opts: DrawTextOptions) void {
while (iter.nextCodepoint()) |codepoint| { while (iter.nextCodepoint()) |codepoint| {
const glyph_index = getGlyphIndex(id, codepoint) orelse continue; const glyph_index = getGlyphIndex(id, codepoint) orelse continue;
const glyph_layout = layout.next(glyph_index) orelse continue; const glyph_layout = layout.next(glyph_index) orelse continue;
if (glyph_layout.sprite == self.nil_sprite) {
continue;
}
drawSprite( drawSprite(
glyph_layout.sprite, glyph_layout.sprite,
@ -1619,9 +1509,6 @@ pub const TextBuilder = struct {
pub fn draw(self: *TextBuilder, pos: Vec2) void { pub fn draw(self: *TextBuilder, pos: Vec2) void {
for (self.glyphs.items) |glyph| { for (self.glyphs.items) |glyph| {
if (glyph.sprite == g_state.nil_sprite) {
continue;
}
drawSprite(glyph.sprite, glyph.rect.pos.add(pos), glyph.rect.size, glyph.color); drawSprite(glyph.sprite, glyph.rect.pos.add(pos), glyph.rect.size, glyph.color);
} }
} }
@ -2276,7 +2163,7 @@ pub const Font = struct {
.x1 = 0, .x1 = 0,
.y1 = 0, .y1 = 0,
}, },
.sprite = g_state.nil_sprite, .sprite = .nil,
.used_this_frame = false .used_this_frame = false
}; };
} }

View File

@ -26,6 +26,7 @@ const shd = @import("shader");
pub const ImGUI = @import("./imgui.zig"); pub const ImGUI = @import("./imgui.zig");
pub const Gfx = @import("./graphics.zig"); pub const Gfx = @import("./graphics.zig");
pub const Input = @import("./input.zig"); pub const Input = @import("./input.zig");
pub const Audio = @import("./audio.zig");
const EmbeddedAssets = @import("embedded_assets"); const EmbeddedAssets = @import("embedded_assets");
@ -66,6 +67,9 @@ fn PlatformType(App: type) type {
try Gfx.init(self.gpa, .{ try Gfx.init(self.gpa, .{
.func = sokolLogCallback .func = sokolLogCallback
}); });
try Audio.init(self.gpa, .{
.logger = .{ .func = sokolLogCallback }
});
ImGUI.init(.{ ImGUI.init(.{
.func = sokolLogCallback .func = sokolLogCallback
}); });
@ -445,6 +449,7 @@ fn PlatformType(App: type) type {
ImGUI.deinit(); ImGUI.deinit();
Gfx.deinit(); Gfx.deinit();
Audio.deinit(self.gpa);
} }
}; };
} }

View File

@ -50,8 +50,17 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
generation: Generation, generation: Generation,
index: Index, index: Index,
pub const nil = Id{
.generation = std.math.maxInt(Generation),
.index = std.math.maxInt(Index),
};
pub fn format(self: Id, writer: *std.Io.Writer) std.Io.Writer.Error!void { pub fn format(self: Id, writer: *std.Io.Writer) std.Io.Writer.Error!void {
try writer.print("Id({s}){{ {}, {} }}", .{ @typeName(Value), self.index, self.generation }); if (self == Id.nil) {
try writer.print("Id({s}){{ nil }}", .{ @typeName(Value) });
} else {
try writer.print("Id({s}){{ {}, {} }}", .{ @typeName(Value), self.index, self.generation });
}
} }
}; };
@ -129,10 +138,12 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
assert(!slot.used); assert(!slot.used);
slot.used = true; slot.used = true;
return Id{ const result = Id{
.index = @intCast(index), .index = @intCast(index),
.generation = slot.generation .generation = slot.generation
}; };
assert(result != Id.nil);
return result;
} }
pub fn insertUndefined(self: *Self) Allocator.Error!Id { pub fn insertUndefined(self: *Self) Allocator.Error!Id {
@ -178,6 +189,14 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
slot.used = false; slot.used = false;
slot.generation +%= 1; slot.generation +%= 1;
self.insertHole(id.index); self.insertHole(id.index);
const next_id = Id{
.generation = id.generation,
.index = id.index,
};
if (next_id == Id.nil) {
slot.generation +%= 1;
}
} }
pub fn remove(self: *Self, id: Id) bool { pub fn remove(self: *Self, id: Id) bool {