scrap current asset manager

This commit is contained in:
Rokas Puzonas 2026-03-22 15:13:56 +02:00
parent 9becd7d56b
commit 7954a8915a
7 changed files with 18 additions and 831 deletions

View File

@ -1,172 +0,0 @@
const std = @import("std");
const Lib = @import("engine_lib");
const AssetBundle = @This();
fonts: std.ArrayList(Font),
sounds: std.ArrayList(Sound),
textures: std.ArrayList(Texture),
data: std.ArrayList(u8),
const DataSegment = extern struct {
offset: u64,
len: u64,
};
const Font = extern struct {
asset_id: Lib.Asset.Id,
info: Lib.Font.Info,
data: DataSegment
};
const Sound = extern struct {
asset_id: Lib.Asset.Id,
info: Lib.Sound.Info,
data: DataSegment
};
const Texture = extern struct {
asset_id: Lib.Asset.Id,
info: Lib.Texture.Info,
data: DataSegment
};
const Header = extern struct {
magic: Magic,
fonts_len: u32,
sounds_len: u32,
textures_len: u32,
data_len: u32,
pub const Magic = enum(u32) {
v1 = 0x961C8C65,
_,
};
};
const endianness: std.builtin.Endian = .little;
pub fn init() AssetBundle {
return AssetBundle{
.fonts = .empty,
.sounds = .empty,
.textures = .empty,
.data = .empty,
};
}
pub fn deinit(self: *AssetBundle, gpa: std.mem.Allocator) void {
self.sounds.deinit(gpa);
self.textures.deinit(gpa);
self.fonts.deinit(gpa);
self.data.deinit(gpa);
}
pub fn getData(self: AssetBundle, data: DataSegment) []const u8 {
return self.data.items[data.offset..][0..data.len];
}
fn insertData(
self: *AssetBundle,
gpa: std.mem.Allocator,
data: []const u8
) !DataSegment {
const data_offset = self.data.items.len;
try self.data.appendSlice(gpa, data);
return DataSegment{
.offset = data_offset,
.len = data.len
};
}
pub fn appendSound(
self: *AssetBundle,
gpa: std.mem.Allocator,
id: Lib.Asset.Id,
data: []const u8,
info: Lib.Sound.Info,
) !void {
try self.sounds.append(gpa, Sound{
.asset_id = id,
.data = try self.insertData(gpa, data),
.info = info
});
}
pub fn appendFont(
self: *AssetBundle,
gpa: std.mem.Allocator,
id: Lib.Asset.Id,
data: []const u8,
info: Lib.Font.Info,
) !void {
try self.fonts.append(gpa, Font{
.asset_id = id,
.data = try self.insertData(gpa, data),
.info = info
});
}
pub fn appendTexture(
self: *AssetBundle,
gpa: std.mem.Allocator,
id: Lib.Asset.Id,
data: []const u8,
info: Lib.Texture.Info
) !void {
try self.textures.append(gpa, Texture{
.asset_id = id,
.info = info,
.data = try self.insertData(gpa, data)
});
}
pub fn write(self: AssetBundle, writer: *std.Io.Writer) !void {
try writer.writeStruct(Header{
.magic = .v1,
.fonts_len = @intCast(self.fonts.items.len),
.sounds_len = @intCast(self.sounds.items.len),
.textures_len = @intCast(self.textures.items.len),
.data_len = @intCast(self.data.items.len)
}, endianness);
try writer.writeSliceEndian(Font, self.fonts.items, endianness);
try writer.writeSliceEndian(Sound, self.sounds.items, endianness);
try writer.writeSliceEndian(Texture, self.textures.items, endianness);
try writer.writeAll(self.data.items);
}
pub fn read(self: *AssetBundle, gpa: std.mem.Allocator, reader: *std.Io.Reader) !void {
const header = try reader.takeStruct(Header, endianness);
if (header.magic != .v1) {
return error.InvalidMagic;
}
try self.fonts.ensureTotalCapacity(gpa, header.fonts_len);
try self.sounds.ensureTotalCapacity(gpa, header.sounds_len);
try self.textures.ensureTotalCapacity(gpa, header.textures_len);
try self.data.ensureTotalCapacity(gpa, header.data_len);
self.fonts.clearRetainingCapacity();
self.sounds.clearRetainingCapacity();
self.textures.clearRetainingCapacity();
self.data.clearRetainingCapacity();
try reader.readSliceEndian(
Font,
self.fonts.addManyAsSliceAssumeCapacity(header.fonts_len),
endianness
);
try reader.readSliceEndian(
Sound,
self.sounds.addManyAsSliceAssumeCapacity(header.sounds_len),
endianness
);
try reader.readSliceEndian(
Texture,
self.textures.addManyAsSliceAssumeCapacity(header.textures_len),
endianness
);
try reader.readSliceAll(self.data.addManyAsSliceAssumeCapacity(header.data_len));
}

View File

@ -35,7 +35,6 @@ const KindDynamic = struct {
.init = try ensureLookup(lib, GameCallbacks.InitFn, "init"),
.tick = try ensureLookup(lib, GameCallbacks.TickFn, "tick"),
.deinit = try ensureLookup(lib, GameCallbacks.DeinitFn, "deinit"),
.loadAssets = if (build_options.asset_hot_reload) try ensureLookup(lib, GameCallbacks.LoadAssetsFn, "loadAssets") else {},
.debug = if (build_options.has_imgui) try ensureLookup(lib, GameCallbacks.DebugFn, "debug") else {},
};
}
@ -212,7 +211,6 @@ const KindStatic = struct {
.init = game.init,
.deinit = game.deinit,
.tick = game.tick,
.loadAssets = if (build_options.asset_hot_reload) game.loadAssets else {},
.debug = if (build_options.has_imgui) game.debug else {},
};
}

View File

@ -19,7 +19,6 @@ const STBImage = @import("stb_image");
const Gfx = Graphics;
pub const Lib = @import("engine_lib");
pub const AssetBundle = @import("./asset_bundle.zig");
const build_options = Lib.build_options;
const debug_keybinds = (builtin.mode == .Debug);
@ -124,18 +123,15 @@ const GameState = struct {
self: *GameState,
init_fn: GameCallbacks.InitFn,
initial: Init,
asset_registry: Lib.Asset.Registry
) void {
assert(self.frame == null);
const opts = Lib.Init{
.gpa = self.gpa,
.seed = initial.seed,
.assets = asset_registry
};
self.state = init_fn(&opts);
self.frame = .init(self.gpa, initial.screen_size);
self.frame.?.assets = asset_registry;
}
fn runGameDeinit(self: *GameState, deinit_fn: GameCallbacks.DeinitFn) void {
@ -254,157 +250,12 @@ const Recording = struct {
}
};
const AssetManager = struct {
const LoadAsset = union(enum) {
font: struct {
id: Lib.Font.Id,
path: []const u8
},
sound: struct {
id: Lib.Sound.Id,
path: []const u8
},
texture: struct {
id: Lib.Texture.Id,
path: []const u8
},
pub fn clone(self: LoadAsset, arena: std.mem.Allocator) !LoadAsset {
return switch (self) {
.font => |opts| LoadAsset{
.font = .{
.id = opts.id,
.path = try arena.dupe(u8, opts.path)
}
},
.sound => |opts| LoadAsset{
.sound = .{
.id = opts.id,
.path = try arena.dupe(u8, opts.path)
}
},
.texture => |opts| LoadAsset{
.texture = .{
.id = opts.id,
.path = try arena.dupe(u8, opts.path)
}
}
};
}
};
gpa: std.mem.Allocator,
assets: std.ArrayList(Lib.Asset),
textures: std.ArrayList(Lib.Texture),
dir: ?std.fs.Dir,
queued_loads_arena: std.heap.ArenaAllocator,
queued_loads: std.ArrayList(LoadAsset),
pub fn init(gpa: std.mem.Allocator) AssetManager {
return AssetManager{
.gpa = gpa,
.assets = .empty,
.textures = .empty,
.dir = null,
.queued_loads_arena = .init(gpa),
.queued_loads = .empty
};
}
pub fn deinit(self: *AssetManager) void {
self.queued_loads_arena.deinit();
self.assets.deinit(self.gpa);
self.textures.deinit(self.gpa);
}
pub fn initRegistry(self: AssetManager) Lib.Asset.Registry {
return Lib.Asset.Registry{
.assets = self.assets.items,
.textures = self.textures.items
};
}
pub fn enqueueLoad(self: *AssetManager, load: LoadAsset) !void {
const arena = self.queued_loads_arena.allocator();
try self.queued_loads.append(arena, try load.clone(arena));
}
pub fn performQueuedLoads(self: *AssetManager, graphics: *Graphics, audio: *Audio) !void {
if (self.dir == null) {
if (self.queued_loads.items.len > 0) {
return error.MissingAssetDirectory;
}
return;
}
const dir = self.dir.?;
for (self.queued_loads.items) |queued_load| {
switch (queued_load) {
.font => |opts| {
const font_data = try readFileAll(self.gpa, dir, opts.path);
defer self.gpa.free(font_data);
try graphics.setFontData(opts.id, font_data);
},
.sound => |opts| {
const sound_data = try readFileAll(self.gpa, dir, opts.path);
defer self.gpa.free(sound_data);
try audio.setSoundData(opts.id, .{
.data = sound_data,
.format = .vorbis
});
},
.texture => |opts| {
const image_data = try readFileAll(self.gpa, dir, opts.path);
defer self.gpa.free(image_data);
const image = try STBImage.load(image_data);
defer image.deinit();
// TODO: Assert that loaded data matches precomputed texture info
try graphics.setTextureData(opts.id, .{
.width = image.width,
.height = image.height,
.rgba = image.rgba8_pixels,
});
}
}
}
_ = self.queued_loads_arena.reset(.free_all);
self.queued_loads = .empty;
}
fn hasTexture(self: AssetManager, texture_id: Lib.Texture.Id) bool {
for (self.textures.items) |texture| {
if (texture.id == texture_id) {
return true;
}
}
return false;
}
pub fn assertAssetsLoaded(self: AssetManager) void {
for (self.assets.items) |asset| {
switch (asset.kind) {
.texture => |texture_id| {
assert(self.hasTexture(texture_id));
},
else => {} // TODO:
}
}
}
};
const Engine = @This();
allocator: std.mem.Allocator,
graphics: Graphics,
audio: Audio,
asset_bundle: ?AssetBundle = null,
asset_manager: AssetManager,
game_linking: GameLinking,
game_state: GameState,
@ -473,123 +324,9 @@ pub fn run(self: *Engine, opts: RunOptions) !void {
.play_recording = false,
.recording_tick = 0,
.seed = initial.seed,
.asset_manager = .init(opts.allocator),
.asset_bundle = null,
};
switch (opts.asset_loading) {
.bundle_bytes => |bundle_bytes| {
var asset_bundle = AssetBundle.init();
errdefer asset_bundle.deinit(opts.allocator);
var reader = std.Io.Reader.fixed(bundle_bytes);
asset_bundle.read(opts.allocator, &reader) catch |e| {
log.err("Failed to load asset bundle: {}", .{e});
return error.FailedToLoadAssetBundle;
};
for (asset_bundle.fonts.items) |font| {
const font_id = try self.graphics.addFont();
try self.asset_manager.assets.append(self.allocator, .{
.id = font.asset_id,
.kind = .{ .font = font_id }
});
}
for (asset_bundle.textures.items) |texture| {
const texture_id = try self.graphics.addTexture();
try self.asset_manager.assets.append(self.allocator, .{
.id = texture.asset_id,
.kind = .{ .texture = texture_id }
});
try self.asset_manager.textures.append(self.asset_manager.gpa, .{
.id = texture_id,
.info = texture.info
});
}
for (asset_bundle.sounds.items) |sound| {
const sound_id = try self.audio.addSound();
try self.asset_manager.assets.append(self.allocator, .{
.id = sound.asset_id,
.kind = .{ .sound = sound_id }
});
}
self.asset_bundle = asset_bundle;
},
.dir_path => |asset_dir_path| {
if (!build_options.asset_hot_reload) {
return error.RuntimeAssetLoadingDisabled;
}
const dir = try std.fs.cwd().openDir(asset_dir_path, .{ .iterate = true });
var loader: Lib.Asset.Loader = .init(opts.allocator, dir);
defer loader.deinit();
game_linking.callbacks.loadAssets(&loader);
for (loader.assets.items) |asset_desc| {
switch (asset_desc.kind) {
.font => |path| {
const font_id = try self.graphics.addFont();
try self.asset_manager.assets.append(self.allocator, .{
.id = asset_desc.id,
.kind = .{ .font = font_id }
});
try self.asset_manager.enqueueLoad(.{
.font = .{
.id = font_id,
.path = path
}
});
},
.texture => |texture| {
const texture_id = try self.graphics.addTexture();
try self.asset_manager.assets.append(self.allocator, .{
.id = asset_desc.id,
.kind = .{ .texture = texture_id }
});
try self.asset_manager.enqueueLoad(.{
.texture = .{
.id = texture_id,
.path = texture.path
}
});
try self.asset_manager.textures.append(self.asset_manager.gpa, .{
.id = texture_id,
.info = texture.info
});
},
.sound => |path| {
const sound_id = try self.audio.addSound();
try self.asset_manager.assets.append(self.allocator, .{
.id = asset_desc.id,
.kind = .{ .sound = sound_id }
});
try self.asset_manager.enqueueLoad(.{
.sound = .{
.id = sound_id,
.path = path
}
});
},
}
}
self.asset_manager.dir = dir;
},
.bundle_path => {
// TODO:
unreachable;
},
}
self.game_state.runGameInit(game_linking.callbacks.init, initial, self.asset_manager.initRegistry());
self.game_state.runGameInit(game_linking.callbacks.init, initial);
if (opts.do_recording) {
self.recording = .init(opts.allocator, initial);
@ -669,45 +406,6 @@ fn sokolInit(self: *Engine) !void {
try self.graphics.setupSokol();
self.audio.setupSokol();
try self.asset_manager.performQueuedLoads(&self.graphics, &self.audio);
if (self.asset_bundle) |*asset_bundle| {
const registry = self.asset_manager.initRegistry();
for (asset_bundle.fonts.items) |font| {
const font_id = registry.getFont(font.asset_id);
assert(font_id != Lib.Font.Id.nil);
try self.graphics.setFontData(font_id, asset_bundle.getData(font.data));
}
for (asset_bundle.textures.items) |texture| {
const texture_id = registry.getTexture(texture.asset_id);
assert(texture_id != Lib.Texture.Id.nil);
const image = try STBImage.load(asset_bundle.getData(texture.data));
defer image.deinit();
try self.graphics.setTextureData(texture_id, .{
.width = image.width,
.height = image.height,
.rgba = image.rgba8_pixels
});
}
for (asset_bundle.sounds.items) |sound| {
const sound_id = registry.getSound(sound.asset_id);
assert(sound_id != Lib.Sound.Id.nil);
try self.audio.setSoundData(sound_id, .{
.data = asset_bundle.getData(sound.data),
.format = .vorbis
});
}
asset_bundle.deinit(self.allocator);
self.asset_bundle = null;
}
self.asset_manager.assertAssetsLoaded();
}
fn sokolCleanup(self: *Engine) void {
@ -724,7 +422,6 @@ fn sokolCleanup(self: *Engine) void {
self.audio.deinit();
self.graphics.deinit(self.allocator);
self.game_linking.deinit(self.allocator);
self.asset_manager.deinit();
}
fn sokolFrame(self: *Engine) !void {
@ -799,7 +496,7 @@ fn sokolFrame(self: *Engine) !void {
self.game_state.deinit();
self.game_state = .init(self.allocator);
self.game_state.runGameInit(self.game_linking.callbacks.init, initial, self.asset_manager.initRegistry());
self.game_state.runGameInit(self.game_linking.callbacks.init, initial);
if (self.recording) |recording| {
recording.deinit();
@ -851,7 +548,7 @@ fn showDebugWindow(self: *Engine) !void {
self.game_state.deinit();
self.game_state = .init(self.allocator);
self.game_state.runGameInit(self.game_linking.callbacks.init, recording.initial, self.asset_manager.initRegistry());
self.game_state.runGameInit(self.game_linking.callbacks.init, recording.initial);
self.play_recording = true;
self.recording_tick = 0;

View File

@ -1,207 +0,0 @@
const std = @import("std");
const log = std.log.scoped(.engine);
const STBImage = @import("stb_image");
const Font = @import("./font.zig");
const Sound = @import("./sound.zig");
const Texture = @import("./texture.zig");
const Asset = @This();
id: Id,
kind: union(Type) {
font: Font.Id,
sound: Sound.Id,
texture: Texture.Id,
},
pub const Id = u32;
pub const Type = enum {
font,
sound,
texture
};
pub const Loader = struct {
const Descriptor = struct {
const KindTexture = struct {
path: []const u8,
info: Texture.Info
};
id: Id,
kind: union(Type) {
font: []const u8,
sound: []const u8,
texture: KindTexture
}
};
arena: std.heap.ArenaAllocator,
dir: std.fs.Dir,
assets: std.ArrayList(Descriptor),
add_failed: bool,
pub fn init(gpa: std.mem.Allocator, dir: std.fs.Dir) Loader {
return Loader{
.arena = .init(gpa),
.dir = dir,
.assets = .empty,
.add_failed = false
};
}
pub fn deinit(self: *Loader) void {
self.arena.deinit();
self.* = undefined;
}
fn readFile(self: *Loader, gpa: std.mem.Allocator, path: []const u8) ![]u8 {
const f = try self.dir.openFile(path, .{});
defer f.close();
var wa: std.Io.Writer.Allocating = .init(gpa);
defer wa.deinit();
var buffer: [4 * 4096]u8 = undefined;
var reader = f.reader(&buffer);
_ = try reader.interface.stream(&wa.writer, .unlimited);
return try wa.toOwnedSlice();
}
pub fn addFont(self: *Loader, id: Asset.Id, path: []const u8) void {
const allocator = self.arena.allocator();
const path_dupe = allocator.dupe(u8, path) catch |e| {
log.err("Failed to duplicate path: {}", .{e});
return;
};
self.assets.append(allocator, Descriptor{
.id = id,
.kind = .{ .font = path_dupe }
}) catch |e| {
log.err("Failed add sound: {}", .{e});
};
}
pub fn addSound(self: *Loader, id: Asset.Id, path: []const u8) void {
const allocator = self.arena.allocator();
const path_dupe = allocator.dupe(u8, path) catch |e| {
log.err("Failed to duplicate path: {}", .{e});
return;
};
self.assets.append(allocator, Descriptor{
.id = id,
.kind = .{ .sound = path_dupe }
}) catch |e| {
log.err("Failed add sound: {}", .{e});
};
}
fn addTextureFallible(self: *Loader, id: Asset.Id, path: []const u8) !void {
const allocator = self.arena.allocator();
var image_info: Texture.Info = undefined;
{
const file_contents = try self.readFile(allocator, path);
defer allocator.free(file_contents);
const image = try STBImage.load(file_contents);
defer image.deinit();
image_info = .{
.width = image.width,
.height = image.height,
.format = .png
};
}
const path_dupe = allocator.dupe(u8, path) catch |e| {
log.err("Failed to duplicate path: {}", .{e});
return;
};
const texture = Descriptor.KindTexture{
.path = path_dupe,
.info = image_info
};
self.assets.append(allocator, Descriptor{
.id = id,
.kind = .{ .texture = texture }
}) catch |e| {
log.err("Failed add sound: {}", .{e});
};
}
pub fn addTexture(self: *Loader, id: Asset.Id, path: []const u8) void {
self.addTextureFallible(id, path) catch |e| {
log.err("Failed to add texture: {}", .{e});
self.add_failed = true;
};
}
};
pub const Registry = struct {
assets: []const Asset,
textures: []const Texture,
pub const empty = Registry{
.assets = &.{},
.textures = &.{}
};
pub fn getAsset(self: Registry, id: Asset.Id) ?Asset {
// TODO: Make this O(1)?
for (self.assets) |asset| {
if (asset.id == id) {
return asset;
}
}
return null;
}
pub fn getSound(self: Registry, id: Asset.Id) Sound.Id {
const asset = self.getAsset(id) orelse return Sound.Id.nil;
if (asset.kind != .sound) {
return Sound.Id.nil;
}
return asset.kind.sound;
}
pub fn getFont(self: Registry, id: Asset.Id) Font.Id {
const asset = self.getAsset(id) orelse return Font.Id.nil;
if (asset.kind != .font) {
return Font.Id.nil;
}
return asset.kind.font;
}
pub fn getTexture(self: Registry, id: Asset.Id) Texture.Id {
const asset = self.getAsset(id) orelse return Texture.Id.nil;
if (asset.kind != .texture) {
return Texture.Id.nil;
}
return asset.kind.texture;
}
pub fn getTextureInfo(self: Registry, id: Texture.Id) Texture.Info {
if (id == .nil) {
log.warn("Failed to access .nil texture info", .{});
return .nil;
}
// TODO: Make this O(1)?
for (self.textures) |texture| {
if (texture.id == id) {
return texture.info;
}
}
log.warn("Failed to find texture info, id={}", .{id});
return .nil;
}
};

View File

@ -146,7 +146,6 @@ pub const MouseButton = enum {
pub const Texture = @import("./texture.zig");
pub const Font = @import("./font.zig");
pub const Sound = @import("./sound.zig");
pub const Asset = @import("./asset.zig");
pub const Sprite = struct {
texture: Texture.Id,
@ -289,8 +288,6 @@ pub const Frame = struct {
screen_size: Vec2,
clear_color: Vec4,
assets: Asset.Registry,
pub fn init(
gpa: std.mem.Allocator,
screen_size: Vec2
@ -309,7 +306,6 @@ pub const Frame = struct {
.audio_commands = .empty,
.hide_cursor = false,
.screen_size = screen_size,
.assets = .empty
};
}
@ -477,8 +473,6 @@ pub const Frame = struct {
pub const Init = struct {
gpa: std.mem.Allocator,
seed: u64,
assets: Asset.Registry,
};
pub const Callbacks = struct {
@ -488,12 +482,10 @@ pub const Callbacks = struct {
pub const TickFn = *const fn(state: State, frame: *Frame) callconv(.c) void;
pub const DeinitFn = *const fn(state: State) callconv(.c) void;
pub const DebugFn = *const fn(state: State, imgui: *ImGui) callconv(.c) void;
pub const LoadAssetsFn = *const fn(assets: *Asset.Loader) callconv(.c) void;
init: InitFn,
tick: TickFn,
deinit: DeinitFn,
loadAssets: if (build_options.asset_hot_reload) LoadAssetsFn else void,
debug: if (build_options.has_imgui) DebugFn else void
};
@ -501,8 +493,7 @@ pub fn exportCallbacksIfNeeded(
comptime init: Callbacks.InitFn,
comptime tick: Callbacks.TickFn,
comptime deinit: Callbacks.DeinitFn,
comptime debug: Callbacks.DebugFn,
comptime assets: Callbacks.LoadAssetsFn,
comptime debug: Callbacks.DebugFn
) void {
const builtin = @import("builtin");
if (builtin.output_mode != .Lib) {
@ -512,9 +503,6 @@ pub fn exportCallbacksIfNeeded(
@export(init, .{ .name = "init", .linkage = .strong });
@export(tick, .{ .name = "tick", .linkage = .strong });
@export(deinit, .{ .name = "deinit", .linkage = .strong });
if (build_options.asset_hot_reload) {
@export(assets, .{ .name = "loadAssets", .linkage = .strong });
}
if (build_options.has_imgui) {
@export(debug, .{ .name = "debug", .linkage = .strong });
}

View File

@ -1,84 +0,0 @@
const std = @import("std");
const Game = @import("game");
const Engine = @import("engine");
const Lib = Engine.Lib;
const AssetBundle = Engine.AssetBundle;
fn readFileAll(gpa: std.mem.Allocator, dir: std.fs.Dir, sub_path: []const u8) ![]u8 {
const f = try dir.openFile(sub_path, .{});
defer f.close();
var wa: std.Io.Writer.Allocating = .init(gpa);
defer wa.deinit();
var buffer: [4 * 4096]u8 = undefined;
var reader = f.reader(&buffer);
_ = try reader.interface.stream(&wa.writer, .unlimited);
return try wa.toOwnedSlice();
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
defer _ = gpa.deinit();
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
if (args.len != 3) {
std.debug.print("Usage: ./asset-bundler <asset-dir> <output>", .{});
std.process.exit(1);
}
const cwd = std.fs.cwd();
const asset_dir_path = args[1];
const output_path = args[2];
const asset_dir = try cwd.openDir(asset_dir_path, .{ .iterate = true });
var loader: Lib.Asset.Loader = .init(allocator, asset_dir);
defer loader.deinit();
Game.loadAssets(&loader);
var bundle = AssetBundle.init();
defer bundle.deinit(allocator);
for (loader.assets.items) |asset_desc| {
const id = asset_desc.id;
switch (asset_desc.kind) {
.font => |path| {
const font_data = try readFileAll(allocator, asset_dir, path);
defer allocator.free(font_data);
// TODO:
try bundle.appendFont(allocator, id, font_data, .{ .format = .ttf });
},
.sound => |path| {
const sound_data = try readFileAll(allocator, asset_dir, path);
defer allocator.free(sound_data);
try bundle.appendSound(allocator, id, sound_data, .{
// TODO:
.format = .vorbis,
.playback_style = .decode_once
});
},
.texture => |opts| {
const texture_data = try readFileAll(allocator, asset_dir, opts.path);
defer allocator.free(texture_data);
try bundle.appendTexture(allocator, id, texture_data, opts.info);
}
}
}
const output_file = try std.fs.cwd().createFile(output_path, .{ });
defer output_file.close();
var buffer: [4096 * 4]u8 = undefined;
var writer = output_file.writer(&buffer);
try bundle.write(&writer.interface);
try writer.interface.flush();
}

View File

@ -9,20 +9,6 @@ const rgb = Engine.Math.rgb;
const Game = @This();
const FontName = enum {
regular,
bold,
italic,
};
const AssetId = enum {
font_regular,
font_bold,
font_italic,
sound_wood,
texture_icon,
};
const State = struct {
gpa: Allocator,
player: Vec2,
@ -40,25 +26,6 @@ pub fn init(opts: *const Engine.Init) callconv(.c) *anyopaque {
return state;
}
fn getFont(assets: Engine.Asset.Registry, font_name: FontName) FontId {
const asset_id = switch (font_name) {
.regular => AssetId.font_regular,
.bold => AssetId.font_bold,
.italic => AssetId.font_italic,
};
return assets.getFont(@intFromEnum(asset_id));
}
pub fn loadAssets(assets: *Engine.Asset.Loader) callconv(.c) void {
assets.addFont(@intFromEnum(AssetId.font_regular), "roboto-font/Roboto-Regular.ttf");
assets.addFont(@intFromEnum(AssetId.font_bold), "roboto-font/Roboto-Bold.ttf");
assets.addFont(@intFromEnum(AssetId.font_italic), "roboto-font/Roboto-Italic.ttf");
assets.addSound(@intFromEnum(AssetId.sound_wood), "wood01.ogg");
assets.addTexture(@intFromEnum(AssetId.texture_icon), "icon.png");
}
pub fn deinit(state_ptr: *anyopaque) callconv(.c) void {
const state: *State = @alignCast(@ptrCast(state_ptr));
const gpa = state.gpa;
@ -89,10 +56,10 @@ pub fn tick(state_ptr: *anyopaque, frame: *Engine.Frame) callconv(.c) void {
dir = dir.normalized();
if (dir.x != 0 or dir.y != 0) {
frame.playAudio(.{
.id = frame.assets.getSound(@intFromEnum(AssetId.sound_wood)),
.volume = 0.1
});
// frame.playAudio(.{
// .id = frame.assets.getSound(@intFromEnum(AssetId.sound_wood)),
// .volume = 0.1
// });
}
state.player = state.player.add(dir.multiplyScalar(50 * dt));
@ -102,7 +69,7 @@ pub fn tick(state_ptr: *anyopaque, frame: *Engine.Frame) callconv(.c) void {
.color = rgb(20, 20, 20)
});
const icon = frame.assets.getTexture(@intFromEnum(AssetId.texture_icon));
// const icon = frame.assets.getTexture(@intFromEnum(AssetId.texture_icon));
const size = Vec2.init(20, 20);
frame.drawRectangle(.{
@ -111,10 +78,10 @@ pub fn tick(state_ptr: *anyopaque, frame: *Engine.Frame) callconv(.c) void {
.size = size
},
.color = rgb(200, 2, 200),
.sprite = .{
.texture = icon,
.uv = .unit
}
// .sprite = .{
// .texture = icon,
// .uv = .unit
// }
});
if (dir.x != 0 or dir.y != 0) {
frame.drawRectanglOutline(state.player.sub(size.divideScalar(2)), size, rgb(20, 20, 20), 3);
@ -131,10 +98,10 @@ pub fn tick(state_ptr: *anyopaque, frame: *Engine.Frame) callconv(.c) void {
});
}
frame.drawText(state.player, "Player", .{
.font = getFont(frame.assets, .regular),
.size = 10
});
// frame.drawText(state.player, "Player", .{
// .font = getFont(frame.assets, .regular),
// .size = 10
// });
}
pub fn debug(state_ptr: *anyopaque, imgui: *Engine.ImGui) callconv(.c) void {
@ -144,5 +111,5 @@ pub fn debug(state_ptr: *anyopaque, imgui: *Engine.ImGui) callconv(.c) void {
}
comptime {
Engine.exportCallbacksIfNeeded(init, tick, deinit, debug, loadAssets);
Engine.exportCallbacksIfNeeded(init, tick, deinit, debug);
}