move debug related code to separate struct
This commit is contained in:
parent
7954a8915a
commit
39c311e225
@ -21,7 +21,7 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.has_tracy = b.option(bool, "tracy", "Tracy integration"),
|
.has_tracy = b.option(bool, "tracy", "Tracy integration"),
|
||||||
.win32_has_console = b.option(bool, "console", "Show console (Window only)"),
|
.win32_has_console = b.option(bool, "console", "Show console (Window only)"),
|
||||||
.win32_png_icon = b.path("src/assets/icon.png"),
|
.win32_png_icon = b.path("src/assets/icon.png"),
|
||||||
.code_hot_reload = b.option(bool, "code-hot-reload", "Dynamically load game code at runtime"),
|
.code_dynamic_linking = b.option(bool, "code-hot-reload", "Dynamically load game code at runtime"),
|
||||||
.asset_hot_reload = b.option(bool, "asset-hot-reload", "Load assets at runtime"),
|
.asset_hot_reload = b.option(bool, "asset-hot-reload", "Load assets at runtime"),
|
||||||
.asset_dir = b.path("src/assets/"),
|
.asset_dir = b.path("src/assets/"),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -14,8 +14,8 @@ const InitOptions = struct {
|
|||||||
|
|
||||||
dep_engine: *std.Build.Dependency,
|
dep_engine: *std.Build.Dependency,
|
||||||
|
|
||||||
statically_linked: ?bool = null,
|
code_static_linking: ?bool = null,
|
||||||
code_hot_reload: ?bool = null,
|
code_dynamic_linking: ?bool = null,
|
||||||
has_imgui: ?bool = null,
|
has_imgui: ?bool = null,
|
||||||
has_tracy: ?bool = null,
|
has_tracy: ?bool = null,
|
||||||
win32_has_console: ?bool = null,
|
win32_has_console: ?bool = null,
|
||||||
@ -31,22 +31,22 @@ pub fn init(outer_builder: *std.Build, opts: InitOptions) void {
|
|||||||
const isDebug = (opts.optimize == .Debug);
|
const isDebug = (opts.optimize == .Debug);
|
||||||
|
|
||||||
var has_tracy = false;
|
var has_tracy = false;
|
||||||
var code_hot_reload = false;
|
var code_dynamic_linking = false;
|
||||||
var asset_hot_reload = false;
|
var asset_hot_reload = false;
|
||||||
if (!isWasm) {
|
if (!isWasm) {
|
||||||
code_hot_reload = opts.code_hot_reload orelse isDebug;
|
code_dynamic_linking = opts.code_dynamic_linking orelse isDebug;
|
||||||
has_tracy = opts.has_tracy orelse isDebug;
|
has_tracy = opts.has_tracy orelse isDebug;
|
||||||
asset_hot_reload = opts.asset_hot_reload orelse isDebug;
|
asset_hot_reload = opts.asset_hot_reload orelse isDebug;
|
||||||
}
|
}
|
||||||
|
|
||||||
const has_imgui = opts.has_imgui orelse isDebug;
|
const has_imgui = opts.has_imgui orelse isDebug;
|
||||||
const statically_linked = opts.statically_linked orelse true;
|
const code_static_linking = opts.code_static_linking orelse true;
|
||||||
|
|
||||||
var build_options = b.addOptions();
|
var build_options = b.addOptions();
|
||||||
build_options.addOption(bool, "has_imgui", has_imgui);
|
build_options.addOption(bool, "has_imgui", has_imgui);
|
||||||
build_options.addOption(bool, "has_tracy", has_tracy);
|
build_options.addOption(bool, "has_tracy", has_tracy);
|
||||||
build_options.addOption(bool, "code_hot_reload", code_hot_reload);
|
build_options.addOption(bool, "code_dynamic_linking", code_dynamic_linking);
|
||||||
build_options.addOption(bool, "statically_linked", statically_linked);
|
build_options.addOption(bool, "code_static_linking", code_static_linking);
|
||||||
build_options.addOption(bool, "asset_hot_reload", asset_hot_reload);
|
build_options.addOption(bool, "asset_hot_reload", asset_hot_reload);
|
||||||
if (asset_hot_reload) {
|
if (asset_hot_reload) {
|
||||||
build_options.addOptionPath("asset_dir", opts.asset_dir);
|
build_options.addOptionPath("asset_dir", opts.asset_dir);
|
||||||
@ -69,7 +69,7 @@ pub fn init(outer_builder: *std.Build, opts: InitOptions) void {
|
|||||||
.has_imgui = has_imgui
|
.has_imgui = has_imgui
|
||||||
});
|
});
|
||||||
engine_module.root_module.addImport("engine_lib", engine_lib);
|
engine_module.root_module.addImport("engine_lib", engine_lib);
|
||||||
if (statically_linked) {
|
if (code_static_linking) {
|
||||||
engine_module.root_module.addImport("game", opts.root_module);
|
engine_module.root_module.addImport("game", opts.root_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ pub fn init(outer_builder: *std.Build, opts: InitOptions) void {
|
|||||||
if (outer_builder.args) |args| {
|
if (outer_builder.args) |args| {
|
||||||
run_cmd.addArgs(args);
|
run_cmd.addArgs(args);
|
||||||
}
|
}
|
||||||
if (code_hot_reload) {
|
if (code_dynamic_linking) {
|
||||||
opts.root_module.resolved_target = opts.target;
|
opts.root_module.resolved_target = opts.target;
|
||||||
opts.root_module.optimize = opts.optimize;
|
opts.root_module.optimize = opts.optimize;
|
||||||
const game_lib = b.addLibrary(.{
|
const game_lib = b.addLibrary(.{
|
||||||
|
|||||||
66
engine/src/engine/debug_system.zig
Normal file
66
engine/src/engine/debug_system.zig
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Environment = @import("./environment.zig");
|
||||||
|
const GameLinking = @import("./game_linking.zig");
|
||||||
|
const Input = @import("./input.zig");
|
||||||
|
|
||||||
|
const DebugSystem = @This();
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
|
is_mouse_inside_imgui: bool,
|
||||||
|
|
||||||
|
show_debug: bool,
|
||||||
|
restart_game: bool,
|
||||||
|
recording: ?Recording,
|
||||||
|
|
||||||
|
play_recording: bool,
|
||||||
|
recording_tick: u64,
|
||||||
|
|
||||||
|
dynamic_linking: ?GameLinking.Dynamic,
|
||||||
|
|
||||||
|
const Recording = struct {
|
||||||
|
arena: std.heap.ArenaAllocator,
|
||||||
|
|
||||||
|
initial: Environment.Init,
|
||||||
|
ticks: std.ArrayList(Environment.Tick),
|
||||||
|
|
||||||
|
pub fn init(gpa: std.mem.Allocator, initial: Environment.Init) Recording {
|
||||||
|
return Recording{
|
||||||
|
.arena = .init(gpa),
|
||||||
|
.ticks = .empty,
|
||||||
|
.initial = initial
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendTick(self: *Recording, tick: Environment.Tick) !void {
|
||||||
|
const arena = self.arena.allocator();
|
||||||
|
|
||||||
|
try self.ticks.append(arena, .{
|
||||||
|
.dt_ns = tick.dt_ns,
|
||||||
|
.events = try arena.dupe(Input.Event, tick.events)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: Recording) void {
|
||||||
|
self.arena.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) DebugSystem {
|
||||||
|
return DebugSystem{
|
||||||
|
.allocator = allocator,
|
||||||
|
.is_mouse_inside_imgui = false,
|
||||||
|
.show_debug = false,
|
||||||
|
.restart_game = false,
|
||||||
|
.recording = null,
|
||||||
|
.play_recording = false,
|
||||||
|
.recording_tick = 0,
|
||||||
|
.dynamic_linking = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *DebugSystem) void {
|
||||||
|
if (self.dynamic_linking) |*dynamic| {
|
||||||
|
dynamic.deinit(self.allocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
205
engine/src/engine/environment.zig
Normal file
205
engine/src/engine/environment.zig
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const log = std.log.scoped(.engine);
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
|
const Input = @import("./input.zig");
|
||||||
|
|
||||||
|
const ScreenScalar = @import("./screen_scaler.zig");
|
||||||
|
|
||||||
|
pub const Lib = @import("engine_lib");
|
||||||
|
const GameCallbacks = Lib.Callbacks;
|
||||||
|
|
||||||
|
const Math = Lib.Math;
|
||||||
|
const Vec2 = Math.Vec2;
|
||||||
|
const rgb = Math.rgb;
|
||||||
|
const Vec4 = Math.Vec4;
|
||||||
|
|
||||||
|
const Environment = @This();
|
||||||
|
|
||||||
|
gpa: std.mem.Allocator,
|
||||||
|
|
||||||
|
callbacks: GameCallbacks,
|
||||||
|
state: ?GameCallbacks.State,
|
||||||
|
frame: ?Lib.Frame,
|
||||||
|
|
||||||
|
mouse_position: ?Vec2,
|
||||||
|
started_at: std.time.Instant,
|
||||||
|
last_frame_at: Lib.Nanoseconds,
|
||||||
|
|
||||||
|
pub const Init = struct {
|
||||||
|
screen_size: Vec2,
|
||||||
|
seed: u64
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Tick = struct {
|
||||||
|
dt_ns: u64,
|
||||||
|
events: []Input.Event,
|
||||||
|
};
|
||||||
|
|
||||||
|
const TickResult = struct {
|
||||||
|
audio: []Lib.AudioCommand,
|
||||||
|
graphics: []Lib.GraphicsCommand,
|
||||||
|
clear_color: Vec4,
|
||||||
|
cursor_hidden: bool
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(gpa: std.mem.Allocator, callbacks: GameCallbacks) Environment {
|
||||||
|
return Environment{
|
||||||
|
.gpa = gpa,
|
||||||
|
.mouse_position = null,
|
||||||
|
.started_at = std.time.Instant.now() catch @panic("Instant.now() unsupported"),
|
||||||
|
.last_frame_at = 0,
|
||||||
|
.state = null,
|
||||||
|
.frame = null,
|
||||||
|
.callbacks = callbacks
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Environment) void {
|
||||||
|
if (self.frame) |*frame| {
|
||||||
|
frame.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn processEvent(self: *Environment, event: Input.Event) void {
|
||||||
|
assert(self.frame != null);
|
||||||
|
const frame = &self.frame.?;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
.key_pressed => |opts| {
|
||||||
|
if (!opts.repeat) {
|
||||||
|
frame.keyboard.press(opts.code, frame.time_ns);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.key_released => |key_code| {
|
||||||
|
frame.keyboard.release(key_code);
|
||||||
|
},
|
||||||
|
.mouse_leave => {
|
||||||
|
frame.keyboard.releaseAll();
|
||||||
|
|
||||||
|
assert(self.mouse_position != null);
|
||||||
|
self.mouse_position = null;
|
||||||
|
frame.mouse_button = .empty;
|
||||||
|
},
|
||||||
|
.mouse_enter => |pos| {
|
||||||
|
assert(self.mouse_position == null);
|
||||||
|
self.mouse_position = pos;
|
||||||
|
},
|
||||||
|
.mouse_move => |pos| {
|
||||||
|
assert(self.mouse_position != null);
|
||||||
|
self.mouse_position = pos;
|
||||||
|
},
|
||||||
|
.mouse_pressed => |opts| {
|
||||||
|
assert(self.mouse_position != null);
|
||||||
|
self.mouse_position = opts.position;
|
||||||
|
frame.mouse_button.press(opts.button, frame.time_ns);
|
||||||
|
},
|
||||||
|
.mouse_released => |opts| {
|
||||||
|
assert(self.mouse_position != null);
|
||||||
|
self.mouse_position = opts.position;
|
||||||
|
frame.mouse_button.release(opts.button);
|
||||||
|
},
|
||||||
|
.window_resize => |opts| {
|
||||||
|
frame.screen_size = .initFromInt(u32, opts.width, opts.height);
|
||||||
|
},
|
||||||
|
else => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stateInit(self: *Environment, initial: Init) void {
|
||||||
|
assert(self.frame == null);
|
||||||
|
const opts = Lib.Init{
|
||||||
|
.gpa = self.gpa,
|
||||||
|
.seed = initial.seed,
|
||||||
|
};
|
||||||
|
self.state = self.callbacks.init(&opts);
|
||||||
|
|
||||||
|
self.frame = .init(self.gpa, initial.screen_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stateDeinit(self: *Environment) void {
|
||||||
|
assert(self.state != null);
|
||||||
|
self.callbacks.deinit(self.state.?);
|
||||||
|
self.state = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stateTick(self: *Environment, opts: Environment.Tick) !TickResult {
|
||||||
|
assert(self.frame != null);
|
||||||
|
const frame = &self.frame.?;
|
||||||
|
|
||||||
|
_ = frame.arena.reset(.retain_capacity);
|
||||||
|
const arena = frame.arena.allocator();
|
||||||
|
|
||||||
|
const audio_commands_capacity = frame.audio_commands.capacity;
|
||||||
|
frame.audio_commands = .empty;
|
||||||
|
try frame.audio_commands.ensureTotalCapacity(arena, audio_commands_capacity);
|
||||||
|
|
||||||
|
const graphics_commands_capacity = frame.graphics_commands.capacity;
|
||||||
|
frame.graphics_commands = .empty;
|
||||||
|
try frame.graphics_commands.ensureTotalCapacity(arena, graphics_commands_capacity);
|
||||||
|
|
||||||
|
frame.dt_ns = opts.dt_ns;
|
||||||
|
frame.time_ns += opts.dt_ns;
|
||||||
|
|
||||||
|
for (opts.events) |event| {
|
||||||
|
if (self.mouse_position == null) {
|
||||||
|
if (event == .mouse_leave) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const enter_position = switch(event) {
|
||||||
|
.mouse_pressed => |e_opts| e_opts.position,
|
||||||
|
.mouse_released => |e_opts| e_opts.position,
|
||||||
|
.mouse_move => |pos| pos,
|
||||||
|
else => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (enter_position) |pos| {
|
||||||
|
self.processEvent(.{ .mouse_enter = pos });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (event == .mouse_enter) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.processEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.mouse_position = self.mouse_position;
|
||||||
|
|
||||||
|
var maybe_screen_scaler: ?ScreenScalar = null;
|
||||||
|
if (frame.canvas_size) |canvas_size| {
|
||||||
|
const screen_scaler = ScreenScalar.init(frame.screen_size, canvas_size);
|
||||||
|
maybe_screen_scaler = screen_scaler;
|
||||||
|
screen_scaler.push(frame);
|
||||||
|
|
||||||
|
if (frame.mouse_position) |mouse_position| {
|
||||||
|
frame.mouse_position = mouse_position.sub(screen_scaler.translation).divideScalar(screen_scaler.scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(self.state != null);
|
||||||
|
self.callbacks.tick(self.state.?, frame);
|
||||||
|
|
||||||
|
if (maybe_screen_scaler) |screen_scaler| {
|
||||||
|
screen_scaler.pop(frame, frame.clear_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.keyboard.pressed = .initEmpty();
|
||||||
|
frame.keyboard.released = .initEmpty();
|
||||||
|
frame.mouse_button.pressed = .initEmpty();
|
||||||
|
frame.mouse_button.released = .initEmpty();
|
||||||
|
|
||||||
|
return TickResult{
|
||||||
|
.graphics = frame.graphics_commands.items,
|
||||||
|
.audio = frame.audio_commands.items,
|
||||||
|
.clear_color = frame.clear_color,
|
||||||
|
.cursor_hidden = frame.hide_cursor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stateDebug(self: *Environment, imgui_ctx: *Lib.ImGui) void {
|
||||||
|
assert(self.state != null);
|
||||||
|
self.callbacks.debug(self.state.?, imgui_ctx);
|
||||||
|
}
|
||||||
@ -8,13 +8,7 @@ const build_options = Lib.build_options;
|
|||||||
|
|
||||||
const GameLinking = @This();
|
const GameLinking = @This();
|
||||||
|
|
||||||
kind: union(enum) {
|
pub const Dynamic = struct {
|
||||||
static,
|
|
||||||
dynamic: KindDynamic,
|
|
||||||
},
|
|
||||||
callbacks: GameCallbacks,
|
|
||||||
|
|
||||||
const KindDynamic = struct {
|
|
||||||
fan_fd: std.os.linux.fd_t,
|
fan_fd: std.os.linux.fd_t,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
dir_path: [:0]const u8,
|
dir_path: [:0]const u8,
|
||||||
@ -39,7 +33,7 @@ const KindDynamic = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(gpa: std.mem.Allocator, path: []const u8) !KindDynamic {
|
pub fn init(gpa: std.mem.Allocator, path: []const u8) !Dynamic {
|
||||||
const dir_path_z = try gpa.dupeZ(u8, std.fs.path.dirname(path) orelse ".");
|
const dir_path_z = try gpa.dupeZ(u8, std.fs.path.dirname(path) orelse ".");
|
||||||
errdefer gpa.free(dir_path_z);
|
errdefer gpa.free(dir_path_z);
|
||||||
|
|
||||||
@ -77,7 +71,7 @@ const KindDynamic = struct {
|
|||||||
|
|
||||||
const lib = try std.DynLib.open(path);
|
const lib = try std.DynLib.open(path);
|
||||||
|
|
||||||
return KindDynamic{
|
return Dynamic{
|
||||||
.fan_fd = fan_fd,
|
.fan_fd = fan_fd,
|
||||||
.dir_path = dir_path_z,
|
.dir_path = dir_path_z,
|
||||||
.path = path_dupe,
|
.path = path_dupe,
|
||||||
@ -88,18 +82,18 @@ const KindDynamic = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: *KindDynamic, gpa: std.mem.Allocator) void {
|
pub fn deinit(self: *Dynamic, gpa: std.mem.Allocator) void {
|
||||||
self.lib.close();
|
self.lib.close();
|
||||||
gpa.free(self.dir_path);
|
gpa.free(self.dir_path);
|
||||||
gpa.free(self.path);
|
gpa.free(self.path);
|
||||||
std.posix.close(self.fan_fd);
|
std.posix.close(self.fan_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getCallbacks(self: *KindDynamic) !GameCallbacks {
|
pub fn getCallbacks(self: *Dynamic) !GameCallbacks {
|
||||||
return getCallbacksFromLibrary(&self.lib);
|
return getCallbacksFromLibrary(&self.lib);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn checkForChanges(self: *KindDynamic) !?GameCallbacks {
|
pub fn checkForChanges(self: *Dynamic) !bool {
|
||||||
const fanotify = std.os.linux.fanotify;
|
const fanotify = std.os.linux.fanotify;
|
||||||
const M = fanotify.event_metadata;
|
const M = fanotify.event_metadata;
|
||||||
const fan_fd = self.fan_fd;
|
const fan_fd = self.fan_fd;
|
||||||
@ -187,6 +181,8 @@ const KindDynamic = struct {
|
|||||||
|
|
||||||
var new_lib = try std.DynLib.open(tmp_path);
|
var new_lib = try std.DynLib.open(tmp_path);
|
||||||
const new_callbacks = try getCallbacksFromLibrary(&new_lib);
|
const new_callbacks = try getCallbacksFromLibrary(&new_lib);
|
||||||
|
// TODO:
|
||||||
|
_ = new_callbacks; // autofix
|
||||||
|
|
||||||
try tmp_dir.deleteFile(tmp_filename);
|
try tmp_dir.deleteFile(tmp_filename);
|
||||||
|
|
||||||
@ -196,69 +192,20 @@ const KindDynamic = struct {
|
|||||||
self.reload_index += 1;
|
self.reload_index += 1;
|
||||||
self.ignore_next_event = true;
|
self.ignore_next_event = true;
|
||||||
|
|
||||||
return new_callbacks;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const KindStatic = struct {
|
pub fn getStatic() ?GameCallbacks {
|
||||||
fn getCallbacks() GameCallbacks {
|
const game = @import("game");
|
||||||
const game = @import("game");
|
return GameCallbacks{
|
||||||
return GameCallbacks{
|
.init = game.init,
|
||||||
.init = game.init,
|
.deinit = game.deinit,
|
||||||
.deinit = game.deinit,
|
.tick = game.tick,
|
||||||
.tick = game.tick,
|
.debug = if (build_options.has_imgui) game.debug else {},
|
||||||
.debug = if (build_options.has_imgui) game.debug else {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn initDynamic(gpa: std.mem.Allocator, path: []const u8) !GameLinking {
|
|
||||||
if (!build_options.code_hot_reload) {
|
|
||||||
return error.NotSupported;
|
|
||||||
}
|
|
||||||
|
|
||||||
var dynamic = try KindDynamic.init(gpa, path);
|
|
||||||
errdefer dynamic.deinit(gpa);
|
|
||||||
|
|
||||||
const callbacks = try dynamic.getCallbacks();
|
|
||||||
|
|
||||||
return GameLinking{
|
|
||||||
.kind = .{ .dynamic = dynamic },
|
|
||||||
.callbacks = callbacks
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initStatic() !GameLinking {
|
|
||||||
if (!build_options.statically_linked) {
|
|
||||||
return error.NotStaticallyLinked;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GameLinking{
|
|
||||||
.kind = .static,
|
|
||||||
.callbacks = KindStatic.getCallbacks()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *GameLinking, gpa: std.mem.Allocator) void {
|
|
||||||
if (build_options.code_hot_reload and self.kind == .dynamic) {
|
|
||||||
self.kind.dynamic.deinit(gpa);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check(self: *GameLinking) !void {
|
|
||||||
if (self.kind == .static) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!build_options.code_hot_reload) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (try self.kind.dynamic.checkForChanges()) |new_callbacks| {
|
|
||||||
self.callbacks = new_callbacks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -28,227 +28,11 @@ pub const Vec2 = Math.Vec2;
|
|||||||
const rgb = Math.rgb;
|
const rgb = Math.rgb;
|
||||||
const Vec4 = Math.Vec4;
|
const Vec4 = Math.Vec4;
|
||||||
|
|
||||||
|
const DebugSystem = @import("./debug_system.zig");
|
||||||
|
|
||||||
const GameLinking = @import("game_linking.zig");
|
const GameLinking = @import("game_linking.zig");
|
||||||
|
|
||||||
const GameState = struct {
|
const Environment = @import("environment.zig");
|
||||||
gpa: std.mem.Allocator,
|
|
||||||
|
|
||||||
state: ?GameCallbacks.State,
|
|
||||||
frame: ?Lib.Frame,
|
|
||||||
|
|
||||||
mouse_position: ?Vec2,
|
|
||||||
started_at: std.time.Instant,
|
|
||||||
last_frame_at: Lib.Nanoseconds,
|
|
||||||
|
|
||||||
const Init = struct {
|
|
||||||
screen_size: Vec2,
|
|
||||||
seed: u64
|
|
||||||
};
|
|
||||||
|
|
||||||
const Tick = struct {
|
|
||||||
dt_ns: u64,
|
|
||||||
events: []Input.Event,
|
|
||||||
};
|
|
||||||
|
|
||||||
const TickResult = struct {
|
|
||||||
audio: []Lib.AudioCommand,
|
|
||||||
graphics: []Lib.GraphicsCommand,
|
|
||||||
clear_color: Vec4,
|
|
||||||
cursor_hidden: bool
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn init(gpa: std.mem.Allocator) GameState {
|
|
||||||
return GameState{
|
|
||||||
.gpa = gpa,
|
|
||||||
.mouse_position = null,
|
|
||||||
.started_at = std.time.Instant.now() catch @panic("Instant.now() unsupported"),
|
|
||||||
.last_frame_at = 0,
|
|
||||||
.state = null,
|
|
||||||
.frame = null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *GameState) void {
|
|
||||||
if (self.frame) |*frame| {
|
|
||||||
frame.deinit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn processEvent(self: *GameState, event: Input.Event) void {
|
|
||||||
assert(self.frame != null);
|
|
||||||
const frame = &self.frame.?;
|
|
||||||
|
|
||||||
switch (event) {
|
|
||||||
.key_pressed => |opts| {
|
|
||||||
if (!opts.repeat) {
|
|
||||||
frame.keyboard.press(opts.code, frame.time_ns);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.key_released => |key_code| {
|
|
||||||
frame.keyboard.release(key_code);
|
|
||||||
},
|
|
||||||
.mouse_leave => {
|
|
||||||
frame.keyboard.releaseAll();
|
|
||||||
|
|
||||||
assert(self.mouse_position != null);
|
|
||||||
self.mouse_position = null;
|
|
||||||
frame.mouse_button = .empty;
|
|
||||||
},
|
|
||||||
.mouse_enter => |pos| {
|
|
||||||
assert(self.mouse_position == null);
|
|
||||||
self.mouse_position = pos;
|
|
||||||
},
|
|
||||||
.mouse_move => |pos| {
|
|
||||||
assert(self.mouse_position != null);
|
|
||||||
self.mouse_position = pos;
|
|
||||||
},
|
|
||||||
.mouse_pressed => |opts| {
|
|
||||||
assert(self.mouse_position != null);
|
|
||||||
self.mouse_position = opts.position;
|
|
||||||
frame.mouse_button.press(opts.button, frame.time_ns);
|
|
||||||
},
|
|
||||||
.mouse_released => |opts| {
|
|
||||||
assert(self.mouse_position != null);
|
|
||||||
self.mouse_position = opts.position;
|
|
||||||
frame.mouse_button.release(opts.button);
|
|
||||||
},
|
|
||||||
.window_resize => |opts| {
|
|
||||||
frame.screen_size = .initFromInt(u32, opts.width, opts.height);
|
|
||||||
},
|
|
||||||
else => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn runGameInit(
|
|
||||||
self: *GameState,
|
|
||||||
init_fn: GameCallbacks.InitFn,
|
|
||||||
initial: Init,
|
|
||||||
) void {
|
|
||||||
assert(self.frame == null);
|
|
||||||
const opts = Lib.Init{
|
|
||||||
.gpa = self.gpa,
|
|
||||||
.seed = initial.seed,
|
|
||||||
};
|
|
||||||
self.state = init_fn(&opts);
|
|
||||||
|
|
||||||
self.frame = .init(self.gpa, initial.screen_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn runGameDeinit(self: *GameState, deinit_fn: GameCallbacks.DeinitFn) void {
|
|
||||||
assert(self.state != null);
|
|
||||||
deinit_fn(self.state.?);
|
|
||||||
self.state = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick(self: *GameState, tick_fn: GameCallbacks.TickFn, opts: GameState.Tick) !TickResult {
|
|
||||||
assert(self.frame != null);
|
|
||||||
const frame = &self.frame.?;
|
|
||||||
|
|
||||||
_ = frame.arena.reset(.retain_capacity);
|
|
||||||
const arena = frame.arena.allocator();
|
|
||||||
|
|
||||||
const audio_commands_capacity = frame.audio_commands.capacity;
|
|
||||||
frame.audio_commands = .empty;
|
|
||||||
try frame.audio_commands.ensureTotalCapacity(arena, audio_commands_capacity);
|
|
||||||
|
|
||||||
const graphics_commands_capacity = frame.graphics_commands.capacity;
|
|
||||||
frame.graphics_commands = .empty;
|
|
||||||
try frame.graphics_commands.ensureTotalCapacity(arena, graphics_commands_capacity);
|
|
||||||
|
|
||||||
frame.dt_ns = opts.dt_ns;
|
|
||||||
frame.time_ns += opts.dt_ns;
|
|
||||||
|
|
||||||
for (opts.events) |event| {
|
|
||||||
if (self.mouse_position == null) {
|
|
||||||
if (event == .mouse_leave) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const enter_position = switch(event) {
|
|
||||||
.mouse_pressed => |e_opts| e_opts.position,
|
|
||||||
.mouse_released => |e_opts| e_opts.position,
|
|
||||||
.mouse_move => |pos| pos,
|
|
||||||
else => null
|
|
||||||
};
|
|
||||||
|
|
||||||
if (enter_position) |pos| {
|
|
||||||
self.processEvent(.{ .mouse_enter = pos });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (event == .mouse_enter) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.processEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
frame.mouse_position = self.mouse_position;
|
|
||||||
|
|
||||||
var maybe_screen_scaler: ?ScreenScalar = null;
|
|
||||||
if (frame.canvas_size) |canvas_size| {
|
|
||||||
const screen_scaler = ScreenScalar.init(frame.screen_size, canvas_size);
|
|
||||||
maybe_screen_scaler = screen_scaler;
|
|
||||||
screen_scaler.push(frame);
|
|
||||||
|
|
||||||
if (frame.mouse_position) |mouse_position| {
|
|
||||||
frame.mouse_position = mouse_position.sub(screen_scaler.translation).divideScalar(screen_scaler.scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(self.state != null);
|
|
||||||
tick_fn(self.state.?, frame);
|
|
||||||
|
|
||||||
if (maybe_screen_scaler) |screen_scaler| {
|
|
||||||
screen_scaler.pop(frame, frame.clear_color);
|
|
||||||
}
|
|
||||||
|
|
||||||
frame.keyboard.pressed = .initEmpty();
|
|
||||||
frame.keyboard.released = .initEmpty();
|
|
||||||
frame.mouse_button.pressed = .initEmpty();
|
|
||||||
frame.mouse_button.released = .initEmpty();
|
|
||||||
|
|
||||||
return TickResult{
|
|
||||||
.graphics = frame.graphics_commands.items,
|
|
||||||
.audio = frame.audio_commands.items,
|
|
||||||
.clear_color = frame.clear_color,
|
|
||||||
.cursor_hidden = frame.hide_cursor
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn runGameDebug(self: *GameState, debug_fn: GameCallbacks.DebugFn, imgui_ctx: *Lib.ImGui) void {
|
|
||||||
assert(self.state != null);
|
|
||||||
debug_fn(self.state.?, imgui_ctx);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Recording = struct {
|
|
||||||
arena: std.heap.ArenaAllocator,
|
|
||||||
|
|
||||||
initial: GameState.Init,
|
|
||||||
ticks: std.ArrayList(GameState.Tick),
|
|
||||||
|
|
||||||
pub fn init(gpa: std.mem.Allocator, initial: GameState.Init) Recording {
|
|
||||||
return Recording{
|
|
||||||
.arena = .init(gpa),
|
|
||||||
.ticks = .empty,
|
|
||||||
.initial = initial
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn appendTick(self: *Recording, tick: GameState.Tick) !void {
|
|
||||||
const arena = self.arena.allocator();
|
|
||||||
|
|
||||||
try self.ticks.append(arena, .{
|
|
||||||
.dt_ns = tick.dt_ns,
|
|
||||||
.events = try arena.dupe(Input.Event, tick.events)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: Recording) void {
|
|
||||||
self.arena.deinit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Engine = @This();
|
const Engine = @This();
|
||||||
|
|
||||||
@ -256,46 +40,49 @@ allocator: std.mem.Allocator,
|
|||||||
graphics: Graphics,
|
graphics: Graphics,
|
||||||
audio: Audio,
|
audio: Audio,
|
||||||
|
|
||||||
game_linking: GameLinking,
|
seed: u64,
|
||||||
game_state: GameState,
|
// game_linking: GameLinking,
|
||||||
|
environment: Environment,
|
||||||
|
|
||||||
queued_events: std.ArrayList(Input.Event),
|
queued_events: std.ArrayList(Input.Event),
|
||||||
is_mouse_inside: bool,
|
is_mouse_inside: bool,
|
||||||
|
|
||||||
seed: u64,
|
debug: DebugSystem,
|
||||||
|
|
||||||
show_debug: bool,
|
|
||||||
restart_game: bool,
|
|
||||||
recording: ?Recording,
|
|
||||||
|
|
||||||
play_recording: bool,
|
|
||||||
recording_tick: u64,
|
|
||||||
|
|
||||||
pub const RunOptions = struct {
|
pub const RunOptions = struct {
|
||||||
pub const AssetLoading = union(enum) {
|
|
||||||
bundle_bytes: []const u8,
|
|
||||||
bundle_path: []const u8,
|
|
||||||
dir_path: []const u8
|
|
||||||
};
|
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
game_library_path: ?[]const u8 = null,
|
game_library_path: ?[]const u8 = null,
|
||||||
do_recording: bool = (builtin.mode == .Debug),
|
do_recording: bool = (builtin.mode == .Debug),
|
||||||
screen_width: u32 = 640,
|
screen_width: u32 = 640,
|
||||||
screen_height: u32 = 480,
|
screen_height: u32 = 480,
|
||||||
|
|
||||||
asset_loading: AssetLoading
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn run(self: *Engine, opts: RunOptions) !void {
|
pub fn run(self: *Engine, opts: RunOptions) !void {
|
||||||
var game_linking: GameLinking = undefined;
|
// var game_linking: GameLinking = undefined;
|
||||||
if (opts.game_library_path) |game_library_path| {
|
// if (opts.game_library_path) |game_library_path| {
|
||||||
game_linking = try .initDynamic(opts.allocator, game_library_path);
|
// game_linking = try .initDynamic(opts.allocator, game_library_path);
|
||||||
} else {
|
// } else {
|
||||||
game_linking = try .initStatic();
|
// game_linking = try .initStatic();
|
||||||
|
// }
|
||||||
|
|
||||||
|
var debug_system = DebugSystem.init(opts.allocator);
|
||||||
|
|
||||||
|
var maybe_callbacks: ?GameCallbacks = null;
|
||||||
|
if (build_options.code_static_linking) {
|
||||||
|
maybe_callbacks = GameLinking.getStatic();
|
||||||
|
}
|
||||||
|
if (build_options.code_dynamic_linking and opts.game_library_path != null) {
|
||||||
|
var dynamic = try GameLinking.Dynamic.init(opts.allocator, opts.game_library_path.?);
|
||||||
|
maybe_callbacks = try dynamic.getCallbacks();
|
||||||
|
debug_system.dynamic_linking = dynamic;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initial = GameState.Init{
|
if (maybe_callbacks == null) {
|
||||||
|
return error.NotLinked;
|
||||||
|
}
|
||||||
|
const callbacks = maybe_callbacks.?;
|
||||||
|
|
||||||
|
const initial = Environment.Init{
|
||||||
.seed = @bitCast(std.time.milliTimestamp()),
|
.seed = @bitCast(std.time.milliTimestamp()),
|
||||||
.screen_size = .initFromInt(u32, opts.screen_width, opts.screen_height)
|
.screen_size = .initFromInt(u32, opts.screen_width, opts.screen_height)
|
||||||
};
|
};
|
||||||
@ -314,23 +101,19 @@ pub fn run(self: *Engine, opts: RunOptions) !void {
|
|||||||
.allocator = opts.allocator,
|
.allocator = opts.allocator,
|
||||||
.logger = .{ .func = sokolLogCallback },
|
.logger = .{ .func = sokolLogCallback },
|
||||||
}),
|
}),
|
||||||
.game_state = .init(opts.allocator),
|
.environment = .init(opts.allocator, callbacks),
|
||||||
.game_linking = game_linking,
|
|
||||||
.show_debug = false,
|
|
||||||
.restart_game = false,
|
|
||||||
.recording = null,
|
|
||||||
.queued_events = .empty,
|
.queued_events = .empty,
|
||||||
.is_mouse_inside = false,
|
|
||||||
.play_recording = false,
|
|
||||||
.recording_tick = 0,
|
|
||||||
.seed = initial.seed,
|
.seed = initial.seed,
|
||||||
|
.is_mouse_inside = false,
|
||||||
|
.debug = debug_system
|
||||||
};
|
};
|
||||||
|
|
||||||
self.game_state.runGameInit(game_linking.callbacks.init, initial);
|
self.environment.stateInit(initial);
|
||||||
|
|
||||||
if (opts.do_recording) {
|
// TODO:
|
||||||
self.recording = .init(opts.allocator, initial);
|
// if (opts.do_recording) {
|
||||||
}
|
// self.recording = .init(opts.allocator, initial);
|
||||||
|
// }
|
||||||
|
|
||||||
tracy.setThreadName("Main");
|
tracy.setThreadName("Main");
|
||||||
|
|
||||||
@ -412,16 +195,19 @@ fn sokolCleanup(self: *Engine) void {
|
|||||||
const zone = tracy.initZone(@src(), .{ });
|
const zone = tracy.initZone(@src(), .{ });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
|
|
||||||
if (self.recording) |recording| {
|
// TODO:
|
||||||
recording.deinit();
|
// if (self.recording) |recording| {
|
||||||
}
|
// recording.deinit();
|
||||||
|
// }
|
||||||
|
|
||||||
self.queued_events.deinit(self.allocator);
|
self.queued_events.deinit(self.allocator);
|
||||||
self.game_state.runGameDeinit(self.game_linking.callbacks.deinit);
|
self.environment.stateDeinit();
|
||||||
self.game_state.deinit();
|
self.environment.deinit();
|
||||||
self.audio.deinit();
|
self.audio.deinit();
|
||||||
self.graphics.deinit(self.allocator);
|
self.graphics.deinit(self.allocator);
|
||||||
self.game_linking.deinit(self.allocator);
|
self.debug.deinit();
|
||||||
|
// TODO:
|
||||||
|
// self.game_linking.deinit(self.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sokolFrame(self: *Engine) !void {
|
fn sokolFrame(self: *Engine) !void {
|
||||||
@ -430,38 +216,44 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
const zone = tracy.initZone(@src(), .{ });
|
const zone = tracy.initZone(@src(), .{ });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
|
|
||||||
try self.game_linking.check();
|
if (self.debug.dynamic_linking) |*dynamic| {
|
||||||
|
if (try dynamic.checkForChanges()) {
|
||||||
const now = std.time.Instant.now() catch @panic("Instant.now() unsupported");
|
self.environment.callbacks = try dynamic.getCallbacks();
|
||||||
const time_passed = now.since(self.game_state.started_at);
|
|
||||||
const dt_ns = time_passed - self.game_state.last_frame_at;
|
|
||||||
self.game_state.last_frame_at = time_passed;
|
|
||||||
|
|
||||||
if (self.play_recording) {
|
|
||||||
assert(self.recording != null);
|
|
||||||
if (self.recording_tick >= self.recording.?.ticks.items.len) {
|
|
||||||
self.play_recording = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tick: GameState.Tick = undefined;
|
const now = std.time.Instant.now() catch @panic("Instant.now() unsupported");
|
||||||
if (self.play_recording) {
|
const time_passed = now.since(self.environment.started_at);
|
||||||
assert(self.recording != null);
|
const dt_ns = time_passed - self.environment.last_frame_at;
|
||||||
const ticks = self.recording.?.ticks.items;
|
self.environment.last_frame_at = time_passed;
|
||||||
tick = ticks[self.recording_tick];
|
|
||||||
self.recording_tick += 1;
|
// TODO:
|
||||||
} else {
|
// if (self.play_recording) {
|
||||||
tick = GameState.Tick{
|
// assert(self.recording != null);
|
||||||
|
// if (self.recording_tick >= self.recording.?.ticks.items.len) {
|
||||||
|
// self.play_recording = false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
var tick: Environment.Tick = undefined;
|
||||||
|
// if (self.play_recording) {
|
||||||
|
// assert(self.recording != null);
|
||||||
|
// const ticks = self.recording.?.ticks.items;
|
||||||
|
// tick = ticks[self.recording_tick];
|
||||||
|
// self.recording_tick += 1;
|
||||||
|
// } else {
|
||||||
|
tick = Environment.Tick{
|
||||||
.dt_ns = dt_ns,
|
.dt_ns = dt_ns,
|
||||||
.events = self.queued_events.items
|
.events = self.queued_events.items
|
||||||
};
|
};
|
||||||
|
//
|
||||||
|
// if (self.recording) |*recording| {
|
||||||
|
// try recording.appendTick(tick);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if (self.recording) |*recording| {
|
const tick_result = try self.environment.stateTick(tick);
|
||||||
try recording.appendTick(tick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tick_result = try self.game_state.tick(self.game_linking.callbacks.tick, tick);
|
|
||||||
|
|
||||||
self.queued_events.clearRetainingCapacity();
|
self.queued_events.clearRetainingCapacity();
|
||||||
|
|
||||||
@ -474,9 +266,10 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
|
|
||||||
self.graphics.drawCommands(tick_result.graphics);
|
self.graphics.drawCommands(tick_result.graphics);
|
||||||
|
|
||||||
if (self.show_debug and build_options.has_imgui) {
|
// TODO:
|
||||||
try self.showDebugWindow();
|
// if (self.show_debug and build_options.has_imgui) {
|
||||||
}
|
// try self.showDebugWindow();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
for (tick_result.audio) |command| {
|
for (tick_result.audio) |command| {
|
||||||
@ -484,25 +277,27 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.restart_game) {
|
// TODO:
|
||||||
self.restart_game = false;
|
// if (self.restart_game) {
|
||||||
|
// self.restart_game = false;
|
||||||
const initial = GameState.Init{
|
//
|
||||||
.seed = self.seed,
|
// const initial = Environment.Init{
|
||||||
.screen_size = .init(sapp.widthf(), sapp.heightf())
|
// .seed = self.seed,
|
||||||
};
|
// .screen_size = .init(sapp.widthf(), sapp.heightf())
|
||||||
|
// };
|
||||||
self.game_state.runGameDeinit(self.game_linking.callbacks.deinit);
|
//
|
||||||
self.game_state.deinit();
|
// self.environment.runGameDeinit(self.game_linking.callbacks.deinit);
|
||||||
|
// self.environment.deinit();
|
||||||
self.game_state = .init(self.allocator);
|
//
|
||||||
self.game_state.runGameInit(self.game_linking.callbacks.init, initial);
|
// self.environment = .init(self.allocator);
|
||||||
|
// self.environment.runGameInit(self.game_linking.callbacks.init, initial);
|
||||||
if (self.recording) |recording| {
|
//
|
||||||
recording.deinit();
|
// // TODO:
|
||||||
self.recording = .init(self.allocator, initial);
|
// // if (self.recording) |recording| {
|
||||||
}
|
// // recording.deinit();
|
||||||
}
|
// // self.recording = .init(self.allocator, initial);
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn showDebugWindow(self: *Engine) !void {
|
fn showDebugWindow(self: *Engine) !void {
|
||||||
@ -524,7 +319,7 @@ fn showDebugWindow(self: *Engine) !void {
|
|||||||
var imgui_ctx = Lib.ImGui.init(self.allocator);
|
var imgui_ctx = Lib.ImGui.init(self.allocator);
|
||||||
defer imgui_ctx.deinit();
|
defer imgui_ctx.deinit();
|
||||||
|
|
||||||
self.game_state.runGameDebug(self.game_linking.callbacks.debug, &imgui_ctx);
|
self.environment.runGameDebug(self.game_linking.callbacks.debug, &imgui_ctx);
|
||||||
for (imgui_ctx.commands.items) |cmd| {
|
for (imgui_ctx.commands.items) |cmd| {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
.text => |str| imgui.text(str)
|
.text => |str| imgui.text(str)
|
||||||
@ -535,31 +330,34 @@ fn showDebugWindow(self: *Engine) !void {
|
|||||||
if (imgui.beginTabItem("Engine")) {
|
if (imgui.beginTabItem("Engine")) {
|
||||||
defer imgui.endTabItem();
|
defer imgui.endTabItem();
|
||||||
|
|
||||||
if (imgui.button("Restart")) {
|
// TODO:
|
||||||
self.restart_game = true;
|
// if (imgui.button("Restart")) {
|
||||||
}
|
// self.restart_game = true;
|
||||||
|
// }
|
||||||
|
|
||||||
if (self.recording) |recording| {
|
// TODO:
|
||||||
imgui.beginDisabled(self.play_recording);
|
// if (self.recording) |recording| {
|
||||||
defer imgui.endDisabled();
|
// imgui.beginDisabled(self.play_recording);
|
||||||
|
// defer imgui.endDisabled();
|
||||||
|
//
|
||||||
|
// if (imgui.button("Replay")) {
|
||||||
|
// self.environment.runGameDeinit(self.game_linking.callbacks.deinit);
|
||||||
|
// self.environment.deinit();
|
||||||
|
//
|
||||||
|
// self.environment = .init(self.allocator);
|
||||||
|
// self.environment.runGameInit(self.game_linking.callbacks.init, recording.initial);
|
||||||
|
//
|
||||||
|
// self.play_recording = true;
|
||||||
|
// self.recording_tick = 0;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if (imgui.button("Replay")) {
|
// TODO:
|
||||||
self.game_state.runGameDeinit(self.game_linking.callbacks.deinit);
|
// if (self.game_linking.kind == .dynamic) {
|
||||||
self.game_state.deinit();
|
// imgui.textFmt("Linking: dynamic (from {s})", .{ self.game_linking.kind.dynamic.path });
|
||||||
|
// } else {
|
||||||
self.game_state = .init(self.allocator);
|
// imgui.textFmt("Linking: static", .{ });
|
||||||
self.game_state.runGameInit(self.game_linking.callbacks.init, recording.initial);
|
// }
|
||||||
|
|
||||||
self.play_recording = true;
|
|
||||||
self.recording_tick = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.game_linking.kind == .dynamic) {
|
|
||||||
imgui.textFmt("Linking: dynamic (from {s})", .{ self.game_linking.kind.dynamic.path });
|
|
||||||
} else {
|
|
||||||
imgui.textFmt("Linking: static", .{ });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (build_options.asset_hot_reload) {
|
if (build_options.asset_hot_reload) {
|
||||||
imgui.textFmt("Asset loading: runtime (from {s})", .{build_options.asset_dir});
|
imgui.textFmt("Asset loading: runtime (from {s})", .{build_options.asset_dir});
|
||||||
@ -569,7 +367,7 @@ fn showDebugWindow(self: *Engine) !void {
|
|||||||
|
|
||||||
imgui.textFmt("Seed: 0x{x:08}", .{ self.seed });
|
imgui.textFmt("Seed: 0x{x:08}", .{ self.seed });
|
||||||
|
|
||||||
const time_ms: f64 = @floatFromInt(@divFloor(self.game_state.last_frame_at, std.time.ns_per_ms));
|
const time_ms: f64 = @floatFromInt(@divFloor(self.environment.last_frame_at, std.time.ns_per_ms));
|
||||||
imgui.textFmt("Time: {:.2}", .{ time_ms / 1000 });
|
imgui.textFmt("Time: {:.2}", .{ time_ms / 1000 });
|
||||||
|
|
||||||
// imgui.textFmt("Draw commands: {}\n", .{
|
// imgui.textFmt("Draw commands: {}\n", .{
|
||||||
@ -602,19 +400,23 @@ fn sokolEvent(self: *Engine, e_ptr: [*c]const sapp.Event) !bool {
|
|||||||
|
|
||||||
if (debug_keybinds and e.type == .KEY_DOWN) {
|
if (debug_keybinds and e.type == .KEY_DOWN) {
|
||||||
if (e.key_code == .F4) {
|
if (e.key_code == .F4) {
|
||||||
self.show_debug = !self.show_debug;
|
// TODO:
|
||||||
|
// self.show_debug = !self.show_debug;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.key_code == .F5) {
|
if (e.key_code == .F5) {
|
||||||
self.restart_game = true;
|
// TODO:
|
||||||
|
// self.restart_game = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.play_recording) {
|
|
||||||
return false;
|
// TODO:
|
||||||
}
|
// if (self.play_recording) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
blk: switch (e.type) {
|
blk: switch (e.type) {
|
||||||
.MOUSE_DOWN => {
|
.MOUSE_DOWN => {
|
||||||
|
|||||||
@ -29,16 +29,16 @@ pub fn main() !void {
|
|||||||
var game_library_path: ?[]const u8 = null;
|
var game_library_path: ?[]const u8 = null;
|
||||||
defer if (game_library_path) |str| allocator.free(str);
|
defer if (game_library_path) |str| allocator.free(str);
|
||||||
|
|
||||||
var asset_loading: Engine.RunOptions.AssetLoading = undefined;
|
// var asset_loading: Engine.RunOptions.AssetLoading = undefined;
|
||||||
if (!build_options.asset_hot_reload) {
|
// if (!build_options.asset_hot_reload) {
|
||||||
asset_loading = .{
|
// asset_loading = .{
|
||||||
.bundle_bytes = @embedFile("asset_bundle")
|
// .bundle_bytes = @embedFile("asset_bundle")
|
||||||
};
|
// };
|
||||||
} else {
|
// } else {
|
||||||
asset_loading = .{
|
// asset_loading = .{
|
||||||
.dir_path = build_options.asset_dir
|
// .dir_path = build_options.asset_dir
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!isWasm) {
|
if (!isWasm) {
|
||||||
var cli: CLI = undefined;
|
var cli: CLI = undefined;
|
||||||
@ -51,7 +51,7 @@ pub fn main() !void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var opt_game_lib_path: ?CLI.Option.Id = null;
|
var opt_game_lib_path: ?CLI.Option.Id = null;
|
||||||
if (build_options.code_hot_reload) {
|
if (build_options.code_dynamic_linking) {
|
||||||
opt_game_lib_path = try cli.addOption(.{
|
opt_game_lib_path = try cli.addOption(.{
|
||||||
.long_name = "game-lib-path",
|
.long_name = "game-lib-path",
|
||||||
.description = "Load game code from dynamic library",
|
.description = "Load game code from dynamic library",
|
||||||
@ -103,7 +103,7 @@ pub fn main() !void {
|
|||||||
try engine.run(.{
|
try engine.run(.{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.game_library_path = game_library_path,
|
.game_library_path = game_library_path,
|
||||||
.asset_loading = asset_loading
|
// .asset_loading = asset_loading
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user