allocator: std.mem.Allocator, gltfs: std.StringHashMapUnmanaged(GltfData) = .{}, stringArena: std.heap.ArenaAllocator, filesToProcess: std.ArrayListUnmanaged(FileToProcess) = .{}, animations: std.ArrayListUnmanaged(AnimationData) = .{}, browser: *AnimationDataBrowser, const AnimationDataBrowser = extras.browser.Browser(AnimationData); pub const AnimationData = struct { name: []const u8, pub fn fileName(self: *@This()) []const u8 { return self.name; } pub fn getModTime(self: *@This()) []const u8 { _ = self; return "0"; } }; pub const FileToProcess = struct { path: []const u8, }; pub const GltfAnimationData = struct { name: []const u8, }; pub const GltfData = struct { filePath: []u8, animations: std.ArrayListUnmanaged(GltfAnimationData) = .{}, }; pub fn create(allocator: std.mem.Allocator) !*@This() { const self = try allocator.create(@This()); self.* = .{ .allocator = allocator, .stringArena = std.heap.ArenaAllocator.init(allocator), .browser = try AnimationDataBrowser.create(allocator), }; self.browser.sameWindow = true; self.browser.setList(&self.animations.items); try self.setupCallbacks(); try self.initialLoad(); return self; } pub fn setupCallbacks(self: *@This()) !void { platform.watchPath("content/"); try core.fs().addAnyWatchCallback(fileChangedCallback, self); } pub fn scanAll(self: *@This(), dir_path: []const u8) !void { var dir = try std.fs.cwd().openDir(dir_path, .{ .iterate = true }); defer dir.close(); var it = dir.iterate(); while (try it.next()) |entry| { const full_path = try std.fs.path.join(self.allocator, &.{ dir_path, entry.name }); defer self.allocator.free(full_path); if (entry.kind == .directory) { if (std.mem.eql(u8, entry.name, "_shaders")) { continue; } try self.scanAll(full_path); // Recursive call for subdirectories } else if (entry.kind == .file) { // core.engine_log("processing file: {s}", .{entry.name}); var pathAsName = core.MakeName(full_path); try self.filesToProcess.append(self.allocator, .{ .path = pathAsName.utf8() }); } } } pub fn initialLoad(self: *@This()) !void { try self.scanAll("content/"); } pub fn fileChangedCallback(path: []const u8, ctx: ?*anyopaque) void { const self: *@This() = @ptrCast(@alignCast(ctx.?)); // core.engine_log("file change seen {s}", .{path}); // var name = core.MakeName(path); self.filesToProcess.append(self.allocator, .{ .path = name.utf8() }) catch {}; // self.updatePath(path) catch return; } fn salloc(self: *@This()) std.mem.Allocator { return self.stringArena.allocator(); } pub fn updatePath(self: *@This(), path: []const u8) !void { core.engine_log("updating Path: {s}", .{path}); if (std.mem.endsWith(u8, path, ".ozz")) {} if (std.mem.endsWith(u8, path, ".gltf")) { // 1. check if there is a .cook file // if there is a .cook file // then dont load, no further actions needed const pathstr = try std.fmt.allocPrint(self.salloc(), "{s}.cook", .{path[0 .. path.len - 5]}); defer self.salloc().free(pathstr); core.engine_log("checking path: {s}", .{pathstr}); if (!core.fs().fileExists(pathstr)) { const dir = try std.fs.cwd().openDir(p2.getDir(pathstr), .{ .iterate = true }); try cook.generateAllCookFiles(self.allocator, dir); } try self.animations.append(self.allocator, .{ .name = path }); //var name = core.MakeName(pathstr); // if there is a cook file // var mapping = try core.fs().loadFile(path); // zgltf.init(self.allocator); // core.fs().unmap(mapping); } } pub fn tickDisplay(self: *@This()) void { self.browser.tickDisplay(); } pub fn tick(self: *@This()) void { const start = core.getEngineTime(); while (self.filesToProcess.pop()) |pop| { const now = core.getEngineTime(); if (now - start > 0.050) { break; } self.updatePath(pop.path) catch unreachable; } } pub fn destroy(self: *@This()) void { self.browser.destroy(); self.allocator.destroy(self); } const std = @import("std"); const api = @import("backlog"); const imgui = api.imgui; const ig = api.imgui.api; const p2 = core.algorithm; const core = api.core; const sys = api.sys; const zgltf = core.zgltf; const assets = api.assets; const cook = assets.cook; const platform = api.platform; const extras = @import("gameExtras");