302 lines
9.2 KiB
Zig
302 lines
9.2 KiB
Zig
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "main");
|
|
|
|
const GameContext = @This();
|
|
|
|
allocator: std.mem.Allocator,
|
|
|
|
commandQueue: core.RingQueue(Task),
|
|
activeCommand: ?*sys.SubprocessTask = null,
|
|
|
|
showInstructions: bool = false,
|
|
dockingInitialized: bool = false,
|
|
|
|
animationStore: *AnimationStore = undefined,
|
|
|
|
const Task = union(enum(u8)) {
|
|
subprocess: *sys.SubprocessTask,
|
|
func: *const fn (*GameContext) void,
|
|
};
|
|
|
|
pub fn init(allocator: std.mem.Allocator) !*@This() {
|
|
const self = try allocator.create(@This());
|
|
self.* = .{
|
|
.allocator = allocator,
|
|
.commandQueue = try core.RingQueue(Task).init(self.allocator, 4096),
|
|
};
|
|
|
|
return self;
|
|
}
|
|
|
|
pub fn prepare(self: *@This()) !void {
|
|
core.engine_log("program ready", .{});
|
|
try assets.initCooking();
|
|
|
|
if (core.getEngineObject(imgui.utils.TopBar)) |topbar| {
|
|
topbar.menuOpen = true;
|
|
}
|
|
|
|
self.animationStore = try AnimationStore.create(self.allocator);
|
|
}
|
|
|
|
pub fn tick(self: *@This(), dt: f64) void {
|
|
_ = dt;
|
|
|
|
std.Thread.sleep(10 * 1000 * 1000);
|
|
|
|
self.tickTasks() catch {};
|
|
self.animationStore.tick();
|
|
|
|
if (self.activeCommand != null or self.commandQueue.count() > 0) {
|
|
//ig.setNextWindowPos(.{ .x = 20, .y = 20 }, .{}, .{});
|
|
|
|
// if (ig.begin("tasks", null, .{
|
|
// .always_auto_resize = true,
|
|
// .no_title_bar = true,
|
|
// .no_move = true,
|
|
// .no_resize = true,
|
|
// .no_collapse = true,
|
|
// })) {}
|
|
|
|
// ig.end();
|
|
}
|
|
|
|
// Initialize docking layout on first run
|
|
if (!self.dockingInitialized) {
|
|
// Get the main viewport dockspace ID (created by dockSpaceOverViewport)
|
|
const main_dockspace_id = ig.getID_Str("##DockSpaceViewport_11111111");
|
|
|
|
// Dock our toolbox window to the center of the main dockspace
|
|
ig.dockBuilderDockWindow("Toolbox Window", main_dockspace_id);
|
|
|
|
ig.dockBuilderFinish(main_dockspace_id);
|
|
self.dockingInitialized = true;
|
|
}
|
|
|
|
// Create a docked window
|
|
if (ig.begin("Toolbox Window", null, .{})) {
|
|
if (ig.button("Compile Shaders", .{})) {
|
|
start_CompileShaders() catch {};
|
|
}
|
|
|
|
if (ig.button("Launch TrenchBroom", .{})) {
|
|
start_TrenchBroom() catch {};
|
|
}
|
|
|
|
ig.separator();
|
|
ig.textf("animation store", .{});
|
|
|
|
self.animationStore.tickDisplay();
|
|
|
|
if (self.activeCommand != null or self.commandQueue.count() > 0) {
|
|
ig.textf("outstanding tasks: {d}", .{self.commandQueue.count() + 1});
|
|
|
|
if (self.activeCommand) |cmd| {
|
|
ig.textf("current command: ", .{});
|
|
|
|
for (cmd.argsOwned.items) |arg| {
|
|
ig.textf("{s}", .{arg});
|
|
ig.sameLine(0, 4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ig.end();
|
|
}
|
|
|
|
fn findRootDir(allocator: std.mem.Allocator) ![]u8 {
|
|
var current_dir = std.fs.cwd();
|
|
|
|
// Start from current directory and walk up
|
|
var path_components = std.ArrayList([]const u8){};
|
|
defer path_components.deinit(allocator);
|
|
|
|
// Try current directory first
|
|
current_dir.access("content.txt", .{}) catch {
|
|
// content.txt not found, need to walk up
|
|
var temp_dir = current_dir;
|
|
|
|
while (true) {
|
|
// Try to go up one directory
|
|
const parent_dir = temp_dir.openDir("..", .{}) catch return error.RootNotFound;
|
|
temp_dir = parent_dir;
|
|
|
|
// Check if content.txt exists in parent directory
|
|
temp_dir.access("content.txt", .{}) catch {
|
|
continue;
|
|
};
|
|
|
|
// Found content.txt, get the absolute path
|
|
return try temp_dir.realpathAlloc(allocator, ".");
|
|
}
|
|
};
|
|
|
|
// content.txt found in current directory
|
|
return try current_dir.realpathAlloc(allocator, ".");
|
|
}
|
|
|
|
fn start_CompileShaders() !void {
|
|
const self = core.getEngineObject(@This()) orelse return;
|
|
|
|
const root_dir = findRootDir(self.allocator) catch {
|
|
core.engine_log("Could not find BacklogEngine root directory (content.txt not found)", .{});
|
|
return;
|
|
};
|
|
defer self.allocator.free(root_dir);
|
|
core.engine_log("Found root directory: {s}", .{root_dir});
|
|
|
|
const compile_shaders_dir = try std.fs.path.join(self.allocator, &.{ root_dir, "tools", "compileShaders" });
|
|
defer self.allocator.free(compile_shaders_dir);
|
|
|
|
var compile_shaders_name = core.MakeName(compile_shaders_dir);
|
|
|
|
core.engine_log("CompileShaders directory: {s}", .{compile_shaders_dir});
|
|
|
|
const exe_path = try std.fs.path.join(self.allocator, &.{ compile_shaders_dir, "zig-out", "bin", "compileShaders.exe" });
|
|
defer self.allocator.free(exe_path);
|
|
core.engine_log("Looking for executable at: {s}", .{exe_path});
|
|
|
|
// Check if compileShaders.exe exists
|
|
if (std.fs.cwd().access(exe_path, .{})) |_| {
|
|
// File exists, run it directly
|
|
core.engine_log("CompileShaders executable found, running directly", .{});
|
|
try self.commandQueue.pushLocked(.{ .subprocess = try sys.runCommand(
|
|
self.allocator,
|
|
&.{"zig-out/bin/compileShaders.exe"},
|
|
compile_shaders_name.utf8(),
|
|
) });
|
|
} else |_| {
|
|
// File doesn't exist, build it first
|
|
core.engine_log("CompileShaders executable not found, building first", .{});
|
|
try self.commandQueue.pushLocked(.{ .subprocess = try sys.runCommand(
|
|
self.allocator,
|
|
&.{ "zig", "build", "install" },
|
|
compile_shaders_name.utf8(),
|
|
) });
|
|
|
|
// Then run it
|
|
core.engine_log("Queuing compileShaders execution after build", .{});
|
|
try self.commandQueue.pushLocked(.{ .subprocess = try sys.runCommand(
|
|
self.allocator,
|
|
&.{"zig-out/bin/compileShaders.exe"},
|
|
compile_shaders_name.utf8(),
|
|
) });
|
|
}
|
|
}
|
|
|
|
pub fn launchDetachedProcess(allocator: std.mem.Allocator, argv: []const []const u8, cwd: ?[]const u8) !void {
|
|
var child = std.process.Child.init(argv, allocator);
|
|
child.cwd = cwd;
|
|
child.stdin_behavior = .Ignore;
|
|
child.stdout_behavior = .Ignore;
|
|
child.stderr_behavior = .Ignore;
|
|
|
|
try child.spawn();
|
|
}
|
|
|
|
fn start_TrenchBroom() !void {
|
|
const self = core.getEngineObject(@This()) orelse return;
|
|
|
|
const root_dir = findRootDir(self.allocator) catch {
|
|
core.engine_log("Could not find BacklogEngine root directory (content.txt not found)", .{});
|
|
return;
|
|
};
|
|
defer self.allocator.free(root_dir);
|
|
|
|
const trenchbroom_dir = try std.fs.path.join(self.allocator, &.{ root_dir, "tools", "trenchbroom" });
|
|
defer self.allocator.free(trenchbroom_dir);
|
|
|
|
var trenchbroom_name = core.MakeName(trenchbroom_dir);
|
|
|
|
core.engine_log("Launching TrenchBroom from: {s}", .{trenchbroom_dir});
|
|
|
|
try launchDetachedProcess(
|
|
self.allocator,
|
|
&.{"TrenchBroom.exe"},
|
|
trenchbroom_name.utf8(),
|
|
);
|
|
}
|
|
|
|
fn tickTasks(self: *@This()) !void {
|
|
if (self.activeCommand == null) {
|
|
if (self.commandQueue.popFromLocked()) |task| {
|
|
switch (task) {
|
|
.subprocess => |t| {
|
|
self.activeCommand = t;
|
|
// core.engine_log("starting task {any}", .{t.args});
|
|
try t.run();
|
|
},
|
|
.func => |f| {
|
|
f(self);
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
if (self.activeCommand) |active| {
|
|
if (active.checkComplete()) {
|
|
active.destroy();
|
|
core.engine_logs("task complete");
|
|
self.activeCommand = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn loadFileAllocFromCwd(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8) ![]u8 {
|
|
var file = try dir.openFile(path, .{});
|
|
defer file.close();
|
|
const filesize = (try file.stat()).size + 1; // add null byte
|
|
const buffer: []u8 = try allocator.alloc(u8, filesize);
|
|
errdefer allocator.free(buffer);
|
|
try file.reader().readNoEof(buffer[0 .. buffer.len - 1]);
|
|
buffer[buffer.len - 1] = 0;
|
|
return buffer;
|
|
}
|
|
|
|
fn displayInstructions(self: *@This()) void {
|
|
self.showInstructions = true;
|
|
}
|
|
|
|
pub fn deinit(self: *@This()) void {
|
|
self.animationStore.destroy();
|
|
self.allocator.destroy(self);
|
|
}
|
|
|
|
fn copyRecursiveDir(
|
|
allocator: std.mem.Allocator,
|
|
src_dir: *std.fs.Dir,
|
|
dest_dir: *std.fs.Dir,
|
|
) !void {
|
|
var walker = try src_dir.walk(allocator);
|
|
defer walker.deinit();
|
|
|
|
while (try walker.next()) |entry| {
|
|
switch (entry.kind) {
|
|
.file => {
|
|
try entry.dir.copyFile(entry.basename, dest_dir.*, entry.path, .{});
|
|
},
|
|
.directory => {
|
|
try dest_dir.makeDir(entry.path);
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn main() anyerror!void {
|
|
var spec = try api.getSpec("New Project Dialogue");
|
|
try spec.put("useGPA", .{ .boolean = false });
|
|
try spec.put("configName", .{ .string = "toolbox" });
|
|
_ = api.startEngine(&NeonObjectTable, &spec);
|
|
}
|
|
|
|
const AnimationStore = @import("toolbox/animationStore.zig");
|
|
|
|
const builtin = @import("builtin");
|
|
const std = @import("std");
|
|
const api = @import("backlog");
|
|
const imgui = api.imgui;
|
|
const assets = api.assets;
|
|
const ig = api.imgui.api;
|
|
const core = api.core;
|
|
const sys = api.sys;
|