added topbar, and a boatload of modules among other things - ecs container pointers are now updated across dll boundaries

This commit is contained in:
Peter Li 2025-05-23 15:04:02 -07:00
parent cddf5b0cc2
commit fefbc7436b
24 changed files with 614 additions and 147 deletions

View File

@ -139,6 +139,11 @@ pub fn getSessionStamp() i64 {
return gEngine.sessionStamp; return gEngine.sessionStamp;
} }
// a struct can be used like a list of types in this way
pub const ComponentList = struct {
pub const Scene = scene.Scene;
};
pub fn start_module(map: *SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { pub fn start_module(map: *SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void {
staticsInitialized = true; staticsInitialized = true;
@ -190,9 +195,11 @@ pub fn start_module(map: *SpecVariantMap, args: anytype, allocator: std.mem.Allo
try algorithm.string_pool.setup(allocator); try algorithm.string_pool.setup(allocator);
_ = try gEngine.createObject(script_bindings.ScriptTicks, .{ .can_tick = true }); _ = try gEngine.createObject(script_bindings.ScriptTicks, .{ .can_tick = true });
_ = try inputs.initInputStack(); _ = try inputs.initInputStack();
// components define
try ecs.defineComponentList(ComponentList, allocator);
return; return;
} }
@ -203,11 +210,19 @@ pub fn setupFromModule(__args: ModuleLoaderArgs) !void {
algorithm.names.gRegistry = __args.nameRegistry; algorithm.names.gRegistry = __args.nameRegistry;
logging.setupLoggingFromModule(); logging.setupLoggingFromModule();
staticsInitialized = true; staticsInitialized = true;
// walk through and patch all ecs containers
ecs.patchComponentList(ComponentList);
if (getEngineObject(SceneSystem)) |system| {
scene.Scene.SceneObjectContainer = system.sceneObjectContainer;
}
} }
pub fn shutdown_module(_: std.mem.Allocator) void { pub fn shutdown_module(_: std.mem.Allocator) void {
MemoryTracker.MTPrintStatsDelta(); MemoryTracker.MTPrintStatsDelta();
ecs.undefineComponentList(ComponentList);
logging.shutdownLogging(); logging.shutdownLogging();
debug_draw.shutdownDrawInterface(); debug_draw.shutdownDrawInterface();
@ -368,3 +383,31 @@ pub fn modulePreamble(p_allocator: *anyopaque, p_a: ?*anyopaque) !std.mem.Alloca
try setupFromModule(args); try setupFromModule(args);
return allocator; return allocator;
} }
// a wrapper around a struct
// which adds slack up to a specific size
//
// engine objects must be allocated with this if they support hot patching
//
// if pub const Slack is a decl in the struct- EngineObjectVTable will generate with a
// fields remapping list.
pub fn SlackStruct(comptime T: type, comptime SlackSize: usize) type {
return struct {
inner: T,
slack: [SlackSize - @sizeOf(T)]u8 = undefined,
pub fn create(allocator: std.mem.Allocator) !*T {
return (try allocator.create(@This())).getInner();
}
pub fn getInner(self: *@This()) *T {
return &self.inner;
}
pub fn fromPtr(inner: *T) *@This() {
const p: *anyopaque = inner;
return @as(*@This(), @ptrCast(@alignCast(p)));
}
};
}

View File

@ -208,6 +208,10 @@ pub const EcsRegistry = struct {
var containerName = _containerName; var containerName = _containerName;
const newid = self.containers.items.len; const newid = self.containers.items.len;
if (self.containersByName.contains(containerName.handle())) {
try core.assertf(false, "container already exists??", .{});
}
try self.containers.append(self.allocator, ref); try self.containers.append(self.allocator, ref);
try self.containerNames.append(self.allocator, containerName); try self.containerNames.append(self.allocator, containerName);
try self.containersByName.put(self.allocator, containerName.handle(), @intCast(newid)); try self.containersByName.put(self.allocator, containerName.handle(), @intCast(newid));
@ -283,13 +287,47 @@ pub const EcsRegistry = struct {
} }
}; };
pub fn defineComponentList(comptime ComponentList: type, allocator: std.mem.Allocator) !void {
const typeInfo = @typeInfo(ComponentList).@"struct";
inline for (typeInfo.decls) |decl| {
core.engine_logs("defining component" ++ decl.name);
try defineComponent(@field(ComponentList, decl.name), allocator);
}
}
pub fn undefineComponentList(comptime ComponentList: type) void {
const typeInfo = @typeInfo(ComponentList).@"struct";
inline for (typeInfo.decls) |decl| {
undefineComponent(@field(ComponentList, decl.name));
}
}
// this doesn't do any behaviour patching right now,
// only BaseContainer pointers
pub fn patchComponentList(comptime ComponentList: type) void {
const typeInfo = @typeInfo(ComponentList).@"struct";
if (core.getEngineObject(EcsRegistry)) |registry| {
inline for (typeInfo.decls) |decl| {
const T = @field(ComponentList, decl.name);
var name = core.MakeName(T.ComponentName);
if (registry.containersByName.get(name.handle())) |offset| {
core.engine_log("Patching component {s}", .{name.utf8()});
const ref = registry.containers.items[offset];
T.BaseContainer = @ptrCast(@alignCast(ref.ptr));
}
}
}
}
pub fn defineComponent(comptime Component: type, allocator: std.mem.Allocator) !void { pub fn defineComponent(comptime Component: type, allocator: std.mem.Allocator) !void {
const ContainerType = @TypeOf(Component.BaseContainer.*); const ContainerType = @TypeOf(Component.BaseContainer.*);
Component.BaseContainer = try ContainerType.create(allocator); Component.BaseContainer = try ContainerType.create(allocator);
core.engine_log("Component container created " ++ @typeName(Component) ++ " @{x}", .{@intFromPtr(Component.BaseContainer)}); core.engine_log("Component container created " ++ @typeName(Component) ++ " @{x}", .{@intFromPtr(Component.BaseContainer)});
const container = makeEcsContainerRef(Component.BaseContainer); const container = makeEcsContainerRef(Component.BaseContainer);
try registerEcsContainer(container, core.MakeName(@typeName(Component))); try registerEcsContainer(container, core.MakeName(Component.ComponentName));
try script.registerComponent(Component, container); try script.registerComponent(Component, container);
} }

View File

@ -163,7 +163,7 @@ pub const Engine = struct {
self.createObjectLock = true; self.createObjectLock = true;
defer self.createObjectLock = false; defer self.createObjectLock = false;
const newIndex = self.engineObjects.items.len; const newIndex = self.engineObjects.items.len;
const newObjectPtr = try vtable.init_func(self.allocator); const newObjectPtr = try vtable.init_func(self.allocator); // call this thing with the special allocator that adds vtable. slackSize to it.
const newObjectRef = EngineObjectRef{ const newObjectRef = EngineObjectRef{
.ptr = @as(*anyopaque, @ptrCast(newObjectPtr)), .ptr = @as(*anyopaque, @ptrCast(newObjectPtr)),

View File

@ -42,6 +42,45 @@ pub const EngineDataEventError = error{
OutOfMemory, OutOfMemory,
}; };
pub const FieldInfo = struct {
name: []const u8,
size: u32,
offset: u32,
alignment: u32,
};
pub fn PatchStruct(comptime T: type, p: *T, old: []const FieldInfo) void {
const t = @typeInfo(T).@"struct";
var new: T = .{};
inline for (t.fields) |field| {
var oldField: ?FieldInfo = null;
for (old) |oldFieldSearch| {
if (std.mem.eql(u8, field.name, oldFieldSearch.name)) {
oldField = oldFieldSearch;
break;
}
}
if (oldField) |of| {
var src: []const u8 = undefined;
src.ptr = @ptrCast(p);
src.ptr += of.offset;
src.len = @sizeOf(@TypeOf(@field(p, field.name)));
var dest: []u8 = undefined;
dest.ptr = @ptrCast(&@field(new, field.name));
dest.len = @sizeOf(@TypeOf(@field(new, field.name)));
std.mem.copyForwards(u8, dest, src);
}
}
p.* = new;
}
pub const EngineObjectVTable = struct { pub const EngineObjectVTable = struct {
typeName: []const u8, typeName: []const u8,
typeSize: usize, typeSize: usize,
@ -60,6 +99,37 @@ pub const EngineObjectVTable = struct {
readyToExit_func: ?*const fn (*anyopaque) bool = null, readyToExit_func: ?*const fn (*anyopaque) bool = null,
prepare_func: ?*const fn (*anyopaque) EngineDataEventError!void = null, prepare_func: ?*const fn (*anyopaque) EngineDataEventError!void = null,
fieldListHash: ?usize = null,
fieldList: ?[]const FieldInfo = null,
slackSize: ?usize = null,
fn fieldInfoCompare(_: void, a: FieldInfo, b: FieldInfo) bool {
return a.offset < b.offset;
}
pub fn addFieldList(self: *@This(), comptime TargetType: type) void {
if (!@hasDecl(TargetType, "Slack")) {
return;
}
self.slackSize = @sizeOf(TargetType.Slack);
const typeinfo = @typeInfo(TargetType).@"struct";
const fieldList = blk: {
comptime var f: []const FieldInfo = &.{};
inline for (typeinfo.fields) |field| {
f = f ++ .{FieldInfo{
.name = field.name,
.offset = @intCast(@offsetOf(TargetType, field.name)),
.size = @intCast(@sizeOf(field.type)),
.alignment = @alignOf(field.type),
}};
}
break :blk f;
};
self.fieldList = fieldList;
}
pub fn from(comptime TargetType: type, comptime engineObjectName: ?[]const u8) EngineObjectVTable { pub fn from(comptime TargetType: type, comptime engineObjectName: ?[]const u8) EngineObjectVTable {
var self = EngineObjectVTable{ var self = EngineObjectVTable{
@ -68,6 +138,7 @@ pub const EngineObjectVTable = struct {
.typeAlign = @alignOf(TargetType), .typeAlign = @alignOf(TargetType),
.init_func = undefined, .init_func = undefined,
}; };
self.addFieldList(TargetType);
if (engineObjectName) |eon| { if (engineObjectName) |eon| {
self.singletonName = eon; self.singletonName = eon;

View File

@ -25,6 +25,8 @@ pub const LoadedModule = struct {
lastLoad: i64 = 0, lastLoad: i64 = 0,
lastModification: i64 = 0, lastModification: i64 = 0,
pdbPath: ?[]const u8 = null,
startOnLoad: bool = true, startOnLoad: bool = true,
started: bool = false, started: bool = false,
initialLoad: bool = true, initialLoad: bool = true,
@ -51,6 +53,11 @@ pub const LoadedModule = struct {
try std.fs.cwd().copyFile(self.baseModulePath, std.fs.cwd(), stagedPath, .{}); try std.fs.cwd().copyFile(self.baseModulePath, std.fs.cwd(), stagedPath, .{});
if (self.pdbPath) |pdbPath| {
const stagedPdbPath = try std.fmt.allocPrint(allocator, "{s}/{s}.pdb", .{ stagingDirectoryPath, self.moduleName });
try std.fs.cwd().copyFile(pdbPath, std.fs.cwd(), stagedPdbPath, .{});
}
self.stagedPaths.append(allocator, stagedPath) catch unreachable; self.stagedPaths.append(allocator, stagedPath) catch unreachable;
} }
@ -139,6 +146,10 @@ pub const ModuleLoader = struct {
.lastModification = std.time.microTimestamp(), .lastModification = std.time.microTimestamp(),
}; };
if (@import("builtin").os.tag == .windows) {
loaded.pdbPath = try std.fmt.allocPrint(self.arena.allocator(), "zig-out/modules/{s}.pdb", .{libFileName[0 .. libFileName.len - 4]});
}
try core.fs().addFileChangedCallback(libFileName, dllChangedCallback, loaded); try core.fs().addFileChangedCallback(libFileName, dllChangedCallback, loaded);
try self.loadedModules.append(self.arena.allocator(), loaded); try self.loadedModules.append(self.arena.allocator(), loaded);

View File

@ -10,6 +10,31 @@ const LogBufferSize = 1 * 1024 * 1024; // 1Mb buffer log
var gLoggerSys: ?*LoggerSys = null; var gLoggerSys: ?*LoggerSys = null;
pub const LogBuffer = struct {
lock: std.Thread.Mutex = .{},
buffer: std.ArrayList(u8),
pub fn init(allocator: std.mem.Allocator) @This() {
return .{
.buffer = std.ArrayList(u8).init(allocator),
};
}
pub fn lockWriter(self: *@This()) std.ArrayList(u8).Writer {
self.lock.lock();
return self.buffer.writer();
}
pub fn unlock(self: *@This()) void {
self.lock.unlock();
}
pub fn deinit(self: *@This()) void {
self.lock.lock();
self.buffer.deinit();
}
};
pub fn printRaw(comptime fmt: []const u8, args: anytype) void { pub fn printRaw(comptime fmt: []const u8, args: anytype) void {
if (zero_logging) { if (zero_logging) {
return; return;
@ -42,9 +67,13 @@ pub fn printInner(comptime fmt: []const u8, args: anytype) void {
} }
} }
// new logging API
pub fn logDisplay(comptime prefix: []const u8, comptime fmt: []const u8, args: anytype) void {
printInner("[" ++ prefix ++ "]: " ++ fmt ++ "\n", args);
}
pub fn game_log(comptime fmt: []const u8, args: anytype) void { pub fn game_log(comptime fmt: []const u8, args: anytype) void {
printInner("[GAME ]: " ++ fmt ++ "\n", args); printInner("[GAME ]: " ++ fmt ++ "\n", args);
printInner("[SCRIPT ]: " ++ fmt ++ "\n", args);
} }
pub fn game_logs(comptime fmt: []const u8) void { pub fn game_logs(comptime fmt: []const u8) void {
@ -168,6 +197,8 @@ pub const LoggerSys = struct {
lock: std.Thread.Mutex = .{}, lock: std.Thread.Mutex = .{},
flushing: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), flushing: std.atomic.Value(bool) = std.atomic.Value(bool).init(false),
sessionBuffer: ?*LogBuffer = null, // disabled in release modes
pub fn flush(self: *@This()) !void { pub fn flush(self: *@This()) !void {
var z = tracy.ZoneN(@src(), "Trying to flush"); var z = tracy.ZoneN(@src(), "Trying to flush");
defer z.End(); defer z.End();
@ -235,6 +266,11 @@ pub const LoggerSys = struct {
pub fn print(self: *@This(), comptime fmt: []const u8, args: anytype) !void { pub fn print(self: *@This(), comptime fmt: []const u8, args: anytype) !void {
self.lock.lock(); self.lock.lock();
try self.writeOutBuffer.writer().print(fmt, args); try self.writeOutBuffer.writer().print(fmt, args);
if (self.sessionBuffer != null) {
try self.sessionBuffer.?.lockWriter().print(fmt, args);
self.sessionBuffer.?.unlock();
}
self.lock.unlock(); self.lock.unlock();
if (self.writeOutBuffer.items.len > LogBufferSize) { if (self.writeOutBuffer.items.len > LogBufferSize) {

View File

@ -281,6 +281,7 @@ pub const SceneSystem = struct {
dynamicObjects: ArrayListUnmanaged(core.ObjectHandle) = .{}, dynamicObjects: ArrayListUnmanaged(core.ObjectHandle) = .{},
childrenArena: std.heap.ArenaAllocator, childrenArena: std.heap.ArenaAllocator,
tickCount: u32 = 0, tickCount: u32 = 0,
sceneObjectContainer: *SceneObjectSet = undefined,
pub const Field = SceneObjectSet.Field; pub const Field = SceneObjectSet.Field;
pub const FieldType = SceneObjectSet.FieldType; pub const FieldType = SceneObjectSet.FieldType;
@ -365,8 +366,10 @@ pub const SceneSystem = struct {
.childrenArena = std.heap.ArenaAllocator.init(allocator), .childrenArena = std.heap.ArenaAllocator.init(allocator),
}; };
core.EngineObject(@This()).gInstance = self; core.EngineObject(@This()).gInstance = self;
try core.defineComponent(Scene, allocator); // try core.defineComponent(Scene, allocator);
Scene.SceneObjectContainer = try SceneObjectSet.create(allocator); Scene.SceneObjectContainer = try SceneObjectSet.create(allocator);
self.sceneObjectContainer = Scene.SceneObjectContainer;
return self; return self;
} }
@ -388,7 +391,7 @@ pub const SceneSystem = struct {
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
self.dynamicObjects.deinit(self.allocator); self.dynamicObjects.deinit(self.allocator);
self.childrenArena.deinit(); self.childrenArena.deinit();
core.undefineComponent(Scene); // core.undefineComponent(Scene);
Scene.SceneObjectContainer.destroy(); Scene.SceneObjectContainer.destroy();
self.allocator.destroy(self); self.allocator.destroy(self);
} }

View File

@ -16,6 +16,8 @@ pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.me
const gimgui = try core.createObject(Impl, .{}); const gimgui = try core.createObject(Impl, .{});
try gimgui.setup(); try gimgui.setup();
_ = try core.createObject(utils.TopBar, .{});
} }
pub fn setupFromModule() void { pub fn setupFromModule() void {

View File

@ -0,0 +1,92 @@
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "game.ExternGameObject");
pub const Slack = core.SlackStruct(@This(), 256);
allocator: std.mem.Allocator,
arena: std.heap.ArenaAllocator,
windowsMenu: std.ArrayListUnmanaged(*MenuEntry) = .{},
entriesByName: std.AutoHashMapUnmanaged(u32, *MenuEntry) = .{},
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try Slack.create(allocator);
self.* = .{
.allocator = allocator,
.arena = std.heap.ArenaAllocator.init(allocator),
};
try self.addWindowsMenu(.{
.name = "sample window",
.open = false,
.ctx = self,
.windowFunction = windowOpen,
});
return self;
}
pub fn addMenuObject(self: *@This(), ptr: anytype, comptime name: []const u8) !void {
const T = @TypeOf(ptr.*);
try self.addWindowsMenu(.{
.name = name,
.ctx = ptr,
.windowFunction = T.windowOpen,
});
}
pub fn windowOpen(entry: *MenuEntry, dt: f64) void {
_ = dt;
if (ig.begin("sample window", &entry.open, .{})) {}
ig.end();
}
pub fn addWindowsMenu(self: *@This(), entry: MenuEntry) !void {
const new = try self.arena.allocator().create(MenuEntry);
new.* = entry;
var name = core.MakeName(entry.name);
if (self.entriesByName.getEntry(name.handle())) |e| {
core.logDisplay("TopBar", "{s} already registered, updating menu entry instead", .{entry.name});
e.value_ptr.*.* = entry;
} else {
try self.windowsMenu.append(self.arena.allocator(), new);
try self.entriesByName.put(self.arena.allocator(), name.handle(), new);
}
}
pub fn tick(self: *@This(), dt: f64) void {
ig.showDemoWindow(null);
if (ig.beginMainMenuBar()) {
if (ig.beginMenu("Windows..", true)) {
for (self.windowsMenu.items) |entry| {
if (ig.menuItem_Bool(entry.name.ptr, null, entry.open, true)) {
entry.open = !entry.open;
}
}
ig.endMenu();
}
ig.endMainMenuBar();
for (self.windowsMenu.items) |entry| {
if (entry.open) {
entry.windowFunction(entry, dt);
}
}
}
}
pub fn destroy(self: *@This()) void {
self.arena.deinit();
self.allocator.destroy(Slack.fromPtr(self));
}
pub const MenuEntry = struct {
name: []const u8,
open: bool = false,
ctx: ?*anyopaque,
windowFunction: *const fn (*MenuEntry, f64) void,
};
const ig = @import("../imgui.zig").api;
const std = @import("std");
const core = @import("core");

View File

@ -0,0 +1,46 @@
buffer: core.LogBuffer,
allocator: std.mem.Allocator,
lastLength: usize = 0,
pub fn init(allocator: std.mem.Allocator) @This() {
return .{
.allocator = allocator,
.buffer = core.LogBuffer.init(allocator),
};
}
pub fn setup(self: *@This()) void {
if (core.getLogger()) |logger| {
logger.sessionBuffer = &self.buffer;
}
if (core.getEngineObject(imgui.utils.TopBar)) |topBar| {
topBar.addMenuObject(self, "Console") catch {};
}
}
pub fn windowOpen(entry: *imgui.utils.MenuEntry, dt: f64) void {
_ = dt;
const self: *@This() = @ptrCast(@alignCast(entry.ctx));
self.buffer.lock.lock();
defer self.buffer.lock.unlock();
if (ig.begin("Console Output", &entry.open, .{})) {
ig.textSlice(self.buffer.buffer.items);
if (self.lastLength != self.buffer.buffer.items.len)
ig.setScrollHereY(1.0);
}
ig.end();
self.lastLength = self.buffer.buffer.items.len;
}
pub fn deinit(self: *@This()) void {
self.buffer.deinit();
}
const imgui = @import("../imgui.zig");
const ig = imgui.api;
const std = @import("std");
const core = @import("core");

View File

@ -79,5 +79,42 @@ pub inline fn displayStruct(s: anytype, comptime depth: u32, comptime maxDepth:
} }
} }
var staticText: [2048]u8 = undefined;
pub fn hexText(bytes: []const u8) void {
var stream = std.io.fixedBufferStream(&staticText);
var writer = stream.writer();
var b = bytes;
if (b.len > 2040)
b.len = 2040;
core.xxdWrite(writer, bytes, .{}) catch return;
const offset = writer.context.getPos() catch return;
const text = staticText[0..offset];
ig.textSlice(text);
}
pub fn structHexView(ptr: anytype) void {
const T = @typeInfo(@TypeOf(ptr)).pointer.child;
if (ig.begin("struct debugger hexview: " ++ @typeName(T), null, .{})) {
const typeInfo = @typeInfo(T).@"struct";
if (@hasDecl(T, "Slack")) {
ig.textf("size: {d}/{d} bytes", .{ @sizeOf(T), @sizeOf(T.Slack) });
}
inline for (typeInfo.fields) |field| {
const offset = @offsetOf(T, field.name);
ig.textf("+{d}(0x{x}) size: {d}> {s} ", .{ offset, offset, @sizeOf(field.type), field.name });
hexText(&std.mem.toBytes(@field(ptr, field.name)));
ig.separator();
}
}
ig.end();
}
const ig = @import("../imgui.zig").api; const ig = @import("../imgui.zig").api;
const std = @import("std"); const std = @import("std");
const core = @import("core");

View File

@ -1 +1,15 @@
pub const structDebugWindow = @import("structDebugger.zig").structDebugWindow; pub const structDebugger = @import("structDebugger.zig");
pub const structDebugWindow = structDebugger.structDebugWindow;
pub const structHexView = structDebugger.structHexView;
pub const ConsoleWindow = @import("consoleWindow.zig");
pub const TopBar = @import("TopBar.zig");
pub const MenuEntry = TopBar.MenuEntry;
pub fn addMenuFunc(ctx: ?*anyopaque, name: []const u8, func: *const fn (*MenuEntry, f64) void) void {
if (core.getEngineObject(TopBar)) |topbar| {
topbar.addWindowsMenu(.{ .name = name, .ctx = ctx, .windowFunction = func }) catch {};
}
}
const core = @import("core");

View File

@ -36,6 +36,11 @@ pub const PrimitiveType = enum {
sphere, sphere,
}; };
pub const ComponentList = struct {
pub const _PhysicsCharacter = PhysicsCharacter;
pub const _PhysicsCollider = PhysicsCollider;
};
// low level helpers - old api // low level helpers - old api
pub fn addPrimitiveBody(primitive: PrimitiveType, settings: BodyCreationSettings, activationMode: Activation) !BodyId { pub fn addPrimitiveBody(primitive: PrimitiveType, settings: BodyCreationSettings, activationMode: Activation) !BodyId {
const interface = context().system.getBodyInterfaceMut(); const interface = context().system.getBodyInterfaceMut();
@ -78,11 +83,18 @@ pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.me
_ = args; _ = args;
_ = spec; _ = spec;
core.engine_logs("starting physics");
try core.defineComponentList(ComponentList, allocator);
try zphysics.init(allocator, .{}); try zphysics.init(allocator, .{});
_ = try core.createObject(runtime.PhysicsRuntime, .{ .can_tick = true }); _ = try core.createObject(runtime.PhysicsRuntime, .{ .can_tick = true });
} }
pub fn setupFromModule() void {
core.ecs.patchComponentList(ComponentList);
}
pub fn shutdown_module(allocator: std.mem.Allocator) void { pub fn shutdown_module(allocator: std.mem.Allocator) void {
core.undefineComponentList(ComponentList);
_ = allocator; _ = allocator;
zphysics.deinit(); zphysics.deinit();
} }

View File

@ -172,8 +172,8 @@ pub const PhysicsRuntime = struct {
self.system = system; self.system = system;
try core.defineComponent(PhysicsCharacter, self.allocator); //try core.defineComponent(PhysicsCharacter, self.allocator);
try core.defineComponent(PhysicsCollider, self.allocator); // try core.defineComponent(PhysicsCollider, self.allocator);
return self; return self;
} }
@ -227,8 +227,8 @@ pub const PhysicsRuntime = struct {
physChar.deinit(); physChar.deinit();
} }
self.idToEntity.deinit(self.allocator); self.idToEntity.deinit(self.allocator);
core.undefineComponent(PhysicsCharacter); // core.undefineComponent(PhysicsCharacter);
core.undefineComponent(PhysicsCollider); // core.undefineComponent(PhysicsCollider);
self.shapes.deinit(self.allocator); self.shapes.deinit(self.allocator);
self.system.destroy(); self.system.destroy();
allocator.destroy(self); allocator.destroy(self);

View File

@ -56,11 +56,25 @@ pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.me
rendAllocator = allocator; rendAllocator = allocator;
try renderer.createInstance(); try renderer.createInstance();
try renderer.start(); try renderer.start();
try core.defineComponentList(ComponentList, allocator);
}
pub const ComponentList = struct {
pub const _MeshComponent = MeshComponent;
pub const _CameraComponent = CameraComponent;
};
pub fn setupFromModule() void {
if (core.getEngineObject(renderer.Renderer)) |r| {
rendAllocator = r.allocator;
}
core.ecs.patchComponentList(ComponentList);
} }
pub fn shutdown_module(allocator: std.mem.Allocator) void { pub fn shutdown_module(allocator: std.mem.Allocator) void {
core.undefineComponent(MeshComponent); core.undefineComponentList(ComponentList);
core.undefineComponent(CameraComponent);
_ = allocator; _ = allocator;
renderer.shutdown(); renderer.shutdown();
} }

View File

@ -20,8 +20,6 @@ pub const MeshPool = struct {
pub fn create(device: *gpu.GPUDevice, allocator: std.mem.Allocator, settings: MeshPoolCreationSettings) !*@This() { pub fn create(device: *gpu.GPUDevice, allocator: std.mem.Allocator, settings: MeshPoolCreationSettings) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
gMeshPool = self;
self.* = .{ self.* = .{
.allocator = allocator, .allocator = allocator,
.indexSpans = try core.MergedSpans.init(allocator, settings.indexCount), .indexSpans = try core.MergedSpans.init(allocator, settings.indexCount),
@ -185,19 +183,17 @@ pub const MeshPool = struct {
}; };
/// === renderer interface implementation === /// === renderer interface implementation ===
var gMeshPool: *MeshPool = undefined;
pub fn getMesh(name: []const u8) ?rend.IndexedMesh { pub fn getMesh(name: []const u8) ?rend.IndexedMesh {
var n = core.MakeName(name); var n = core.MakeName(name);
return getMeshByName(&n); return getMeshByName(&n);
} }
pub fn getMeshByName(name: *core.Name) ?rend.IndexedMesh { pub fn getMeshByName(name: *core.Name) ?rend.IndexedMesh {
return gMeshPool.installedMeshes.get(name.handle()); return rend.context().meshPool.installedMeshes.get(name.handle());
} }
pub fn pushMeshUpdate(meshUpdate: rend.MeshUpdate) !void { pub fn pushMeshUpdate(meshUpdate: rend.MeshUpdate) !void {
try gMeshPool.pushMeshUpdate(meshUpdate); try rend.context().meshPool.pushMeshUpdate(meshUpdate);
} }
const MeshAssetLoader = @import("MeshAssetLoader.zig"); const MeshAssetLoader = @import("MeshAssetLoader.zig");

View File

@ -96,9 +96,6 @@ pub const Renderer = struct {
.allocator = allocator, .allocator = allocator,
}; };
try core.defineComponent(rend.MeshComponent, allocator);
try core.defineComponent(rend.CameraComponent, allocator);
self.hdrTextureFormat = .textureformatR16g16b16a16Float; self.hdrTextureFormat = .textureformatR16g16b16a16Float;
return self; return self;
} }

View File

@ -1,5 +1,4 @@
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
windowOpen: bool = true,
lastUpdateFrame: u64 = 0, lastUpdateFrame: u64 = 0,
arena: std.heap.ArenaAllocator, arena: std.heap.ArenaAllocator,
@ -13,6 +12,10 @@ pub fn create(allocator: std.mem.Allocator) !*@This() {
.arena = std.heap.ArenaAllocator.init(allocator), .arena = std.heap.ArenaAllocator.init(allocator),
}; };
if (core.getEngineObject(igutils.TopBar)) |topbar| {
topbar.addMenuObject(self, "Engine Object Browser") catch {};
}
return self; return self;
} }
@ -42,19 +45,29 @@ pub fn maybeUpdate(self: *@This()) !void {
} }
} }
pub fn tick(self: *@This()) void { pub fn windowOpen(entry: *igutils.MenuEntry, dt: f64) void {
if (self.windowOpen) { _ = dt;
if (ig.begin("EngineTool", &self.windowOpen, .{})) { const self: *@This() = @ptrCast(@alignCast(entry.ctx));
self.maybeUpdate() catch {
ig.textSlice("Unable to update engine tools list"); if (ig.begin("EngineTool", &entry.open, .{})) {
return; self.maybeUpdate() catch {
}; ig.textSlice("Unable to update engine tools list");
for (self.strings.items) |slice| { return;
ig.textSlice(slice); };
for (self.strings.items) |slice| {
ig.textSlice(slice);
}
if (core.getEngineObject(core.EcsRegistry)) |ecsReg| {
ig.separator();
for (ecsReg.containerNames.items, 0..) |*name, i| {
_ = i;
ig.textf("{s}", .{name.utf8()});
} }
} }
ig.end();
} }
ig.end();
} }
pub fn destroy(self: *@This()) void { pub fn destroy(self: *@This()) void {
@ -67,3 +80,4 @@ const backlog = @import("Backlog");
const core = backlog.core; const core = backlog.core;
const rend = backlog.rend; const rend = backlog.rend;
const ig = backlog.imgui.api; const ig = backlog.imgui.api;
const igutils = backlog.imgui.utils;

View File

@ -1,17 +1,28 @@
dtAverage: f64 = 0.0, dtAverage: f64 = 0.0,
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), null); pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "extras.RendererDebug");
pub fn create(allocator: std.mem.Allocator) !*@This() { pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
self.* = .{ .allocator = allocator }; self.* = .{ .allocator = allocator };
self.setup();
return self; return self;
} }
pub fn tick(self: *@This(), dt: f64) void { // setups are a non-failable functions that get reran after patchStruct() is called
pub fn setup(self: *@This()) void {
if (core.getEngineObject(igu.TopBar)) |topbar| {
topbar.addMenuObject(self, "Renderer Debug") catch {};
}
}
pub fn windowOpen(entry: *igu.MenuEntry, dt: f64) void {
const self: *@This() = @ptrCast(@alignCast(entry.ctx));
core.rollingAverage(&self.dtAverage, dt, 50); core.rollingAverage(&self.dtAverage, dt, 50);
if (ig.begin("renderer debug", null, .{})) { if (ig.begin("renderer debug", null, .{})) {
@ -43,4 +54,5 @@ const backlog = @import("Backlog");
const core = backlog.core; const core = backlog.core;
const rend = backlog.rend; const rend = backlog.rend;
const ig = backlog.imgui.api; const ig = backlog.imgui.api;
const igu = backlog.imgui.utils;
const std = @import("std"); const std = @import("std");

View File

@ -8,9 +8,13 @@ fn debugShowKeys(binding: anytype) void {
ig.textFmt("{s} ({s}) keysDown count: {d}", .{ binding.data.name.utf8(), @typeName(@TypeOf(binding)), binding.data.keysDown.count() }) catch return; ig.textFmt("{s} ({s}) keysDown count: {d}", .{ binding.data.name.utf8(), @typeName(@TypeOf(binding)), binding.data.keysDown.count() }) catch return;
} }
pub fn tick() void { pub fn windowOpen(entry: *igutils.MenuEntry, dt: f64) void {
const self: *@This() = @ptrCast(@alignCast(entry.ctx));
_ = dt;
_ = self;
const stack = core.inputs.getInputStack(); const stack = core.inputs.getInputStack();
if (ig.begin("input stack", null, .{})) { if (ig.begin("input stack", &entry.open, .{})) {
for (stack.active.bindingStack.items) |binding| { for (stack.active.bindingStack.items) |binding| {
switch (binding) { switch (binding) {
.action => |b| { .action => |b| {
@ -33,3 +37,4 @@ const backlog = @import("Backlog");
const core = backlog.core; const core = backlog.core;
const rend = backlog.rend; const rend = backlog.rend;
const ig = backlog.imgui.api; const ig = backlog.imgui.api;
const igutils = backlog.imgui.utils;

View File

@ -15,6 +15,8 @@ pub const Options = struct {
absoluteSpawnposition: bool = false, // if set, won't move the object to where the spawn rotation and position is absoluteSpawnposition: bool = false, // if set, won't move the object to where the spawn rotation and position is
}; };
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "extras.objectSpawner");
pub fn create(allocator: std.mem.Allocator) !*@This() { pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
self.* = .{ self.* = .{

View File

@ -31,7 +31,7 @@ pub fn build(b: *std.Build) void {
}); });
blbuild.addExtraModule(sampleGameExtern.root_module, "gameExtras"); blbuild.addExtraModule(sampleGameExtern.root_module, "gameExtras");
blbuild.addExtraModule(sampleGameExtern.root_module, "bsp");
sampleGameExtern.root_module.addImport("backlog", blbuild.nw_mod); sampleGameExtern.root_module.addImport("backlog", blbuild.nw_mod);
const installExtern = b.addInstallArtifact(sampleGameExtern, .{ const installExtern = b.addInstallArtifact(sampleGameExtern, .{

View File

@ -3,6 +3,8 @@ pub export fn startup(p_allocator: *anyopaque, p_a: ?*anyopaque) bool {
_ = allocator; _ = allocator;
imgui.setupFromModule(); imgui.setupFromModule();
platform.setupFromModule(); platform.setupFromModule();
rend.setupFromModule();
backlog.physics.setupFromModule();
// TODO backlog.setupFromModule // TODO backlog.setupFromModule
start_module(core.startup_getArgs(p_a.?)) catch return false; start_module(core.startup_getArgs(p_a.?)) catch return false;
@ -20,44 +22,96 @@ pub export fn subtract(a: i32, b: i32) i32 {
var gAllocator: std.mem.Allocator = undefined; var gAllocator: std.mem.Allocator = undefined;
pub fn log(comptime fmt: []const u8, args: anytype) void {
core.engine_log("[ExternGame]: " ++ fmt, args);
}
fn start_module(args: core.ModuleLoaderArgs) !void { fn start_module(args: core.ModuleLoaderArgs) !void {
if (args.firstLoad) { if (args.firstLoad) {
_ = core.createObject(ExternGameObject, .{}) catch {}; _ = core.createObject(ExternGameObject, .{}) catch {};
return; return;
} }
log("extern game reloaded ", .{}); core.logDisplay("externGame", "extern game reloaded ", .{});
log("hello mother fucker", .{}); core.logDisplay("externGame", "hello mother fucker", .{});
log("accessing old object at {x} same object? {d}", .{ @intFromPtr(core.EngineObject(ExternGameObject).get()), @sizeOf(ExternGameObject) }); core.logDisplay("externGame", "accessing old object at {x} same object? {d}", .{ @intFromPtr(core.EngineObject(ExternGameObject).get()), @sizeOf(ExternGameObject) });
log("gonna try something dumb- lets patch the vtable of that old object with my vtable's values", .{}); // getting rid of dumb comment
//log("gonna try something dumb- lets patch the vtable of that old object with my vtable's values", .{});
const ref = core.getEngineObjectRef(ExternGameObject).?; const ref = core.getEngineObjectRef(ExternGameObject).?;
ref.vtable.tick_func = ExternGameObject.NeonObjectTable.tick_func; ref.vtable.tick_func = ExternGameObject.NeonObjectTable.tick_func;
core.PatchStruct(ExternGameObject, @ptrCast(@alignCast(ref.ptr)), ref.vtable.fieldList.?);
} }
pub const ExternGameObject = struct { pub const ExternGameObject = struct {
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "game.ExternGameObject"); pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "game.ExternGameObject");
pub const Slack = core.SlackStruct(@This(), 512);
allocator: std.mem.Allocator, allocator: std.mem.Allocator = undefined,
consoleWindow: imgui.utils.ConsoleWindow = undefined,
tbMap: ?*bsp.maploader.TBMap = null,
//lmao: bool = false,
//lmao2: bool = true,
a: bool = false,
// lib: bool = false,
//s: u32 = 0x42,
pub fn loadMap2(self: *@This()) !void {
if (self.tbMap) |tbMap| {
core.engine_log("killing the map", .{});
tbMap.destroy();
}
self.tbMap = try bsp.maploader.LoadTrenchbroomMap(self.allocator, .{
.rotation = core.Rotation.eulerX(core.radians(-90.0)),
.mapName = "bsp/testmap.map",
});
core.engine_log("map loaded", .{});
}
pub fn create(allocator: std.mem.Allocator) !*@This() { pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try Slack.create(allocator);
self.* = .{ .allocator = allocator }; self.* = .{
.allocator = allocator,
.consoleWindow = imgui.utils.ConsoleWindow.init(allocator),
};
imgui.utils.addMenuFunc(self, "Input Stack Viewer", extras.inputDebugger.windowOpen);
self.consoleWindow.setup();
return self; return self;
} }
pub fn tick(self: *@This(), dt: f64) void { pub fn tick(self: *@This(), dt: f64) void {
_ = dt;
_ = self;
const rctx = rend.context(); const rctx = rend.context();
imgui.utils.structDebugWindow(rctx); _ = dt;
if (ig.begin("meh", null, .{})) {
// if (ig.checkbox("move lights ", null)) {}
ig.textFmt("info: - WASD to move, mouse to look,\n- Q and E to go up and down", .{}) catch return;
ig.textFmt("- shift to slow down camera speed", .{}) catch return;
ig.textFmt("- T to enable/disable mouse cursor", .{}) catch return;
ig.textFmt("- f2 to route all inputs to the doom player", .{}) catch return;
ig.textFmt("- movingLight checkbox makes the light stop moving with you", .{}) catch return;
if (ig.smallButton("reload map")) {
self.loadMap2() catch unreachable;
}
if (ig.smallButton("destroy map")) {
if (self.tbMap) |tbMap| {
core.engine_log("killing the map", .{});
tbMap.destroy();
self.tbMap = null;
}
}
}
ig.end();
//_ = self;
_ = rctx;
// imgui.utils.structHexView(self);
// imgui.utils.structHexView(rctx.activeCamera.?);
// if (ig.begin("external game object", null, .{})) { // if (ig.begin("external game object", null, .{})) {
// ig.textf("sup", .{}); // ig.textf("sup", .{});
@ -89,7 +143,7 @@ pub const ExternGameObject = struct {
} }
pub fn destroy(self: *@This()) void { pub fn destroy(self: *@This()) void {
self.allocator.destroy(self); self.allocator.destroy(Slack.fromPtr(self));
} }
}; };
@ -102,3 +156,5 @@ const imgui = backlog.imgui;
const rend = backlog.rend; const rend = backlog.rend;
const ig = imgui.api; const ig = imgui.api;
const platform = backlog.platform; const platform = backlog.platform;
const extras = @import("gameExtras");
const bsp = @import("bsp");

View File

@ -24,8 +24,6 @@ videoFullbright: bool = false,
moveLight: bool = true, moveLight: bool = true,
rendererDebugger: *extras.RendererDebug = undefined,
tbMap: ?*bsp.maploader.TBMap = null, tbMap: ?*bsp.maploader.TBMap = null,
// addFunc: ?*const fn (i32, i32) callconv(.C) i32 = undefined, // addFunc: ?*const fn (i32, i32) callconv(.C) i32 = undefined,
@ -150,40 +148,6 @@ pub const DamagedHelmet = struct {
} }
}; };
pub fn loadMap2(self: *@This()) !void {
if (self.tbMap) |tbMap| {
core.engine_log("killing the map", .{});
tbMap.destroy();
}
self.tbMap = try bsp.maploader.LoadTrenchbroomMap(self.allocator, .{
.rotation = core.Rotation.eulerX(core.radians(-90.0)),
.mapName = "bsp/testmap.map",
});
core.engine_log("map loaded", .{});
}
pub fn loadMap(self: *@This()) void {
self.tbMap = bsp.maploader.LoadTrenchbroomMap(self.allocator, .{
.rotation = core.Rotation.eulerX(core.radians(-90.0)),
.mapName = "bsp/testmap.map",
}) catch |err| {
core.engine_log("unable to load map, error: {any}", .{err});
self.tbMap = null;
return;
};
core.engine_log("map loaded", .{});
}
fn moduleChangedCallback(pathChanged: []const u8, ctx: ?*anyopaque) void {
const self: *@This() = @ptrCast(@alignCast(ctx));
core.engine_log("moduleChanged {s}", .{pathChanged});
var name = core.MakeName(pathChanged);
self.modules.put(self.allocator, name.handle(), name.utf8()) catch {};
}
pub fn prepare(self: *@This()) !void { pub fn prepare(self: *@This()) !void {
core.engine_log(">>>>>>> game prepare", .{}); core.engine_log(">>>>>>> game prepare", .{});
var z = core.tracy.ZoneN(@src(), "PREPARING GAME"); var z = core.tracy.ZoneN(@src(), "PREPARING GAME");
@ -201,9 +165,11 @@ pub fn prepare(self: *@This()) !void {
// try self.tryLoadExtern("externGame"); // try self.tryLoadExtern("externGame");
self.rendererDebugger = try extras.RendererDebug.create(self.allocator); //try core.createObject(extras.RendererDebug, .{}); // self.rendererDebugger = try extras.RendererDebug.create(self.allocator); //try core.createObject(extras.RendererDebug, .{});
_ = try core.createObject(extras.RendererDebug, .{});
self.objectSpawner = try extras.ObjectSpawner.create(self.allocator); //self.objectSpawner = try extras.ObjectSpawner.create(self.allocator);
self.objectSpawner = try core.createObject(extras.ObjectSpawner, .{});
try self.objectSpawner.addSpawnFunction("fox", FoxObject); try self.objectSpawner.addSpawnFunction("fox", FoxObject);
try self.objectSpawner.addSpawnFunction("doomplayer", DoomPlayer.DoomCanvas); try self.objectSpawner.addSpawnFunction("doomplayer", DoomPlayer.DoomCanvas);
try self.objectSpawner.addSpawnFunction("empire", @import("empire.zig")); try self.objectSpawner.addSpawnFunction("empire", @import("empire.zig"));
@ -464,78 +430,78 @@ pub fn tick(self: *@This(), dt: f64) void {
// show a window with the current camera's position // show a window with the current camera's position
if (!self.mouseLook) { if (!self.mouseLook) {
self.engineTool.tick(); // self.engineTool.tick();
self.objectSpawner.windowOpen = !self.mouseLook; self.objectSpawner.windowOpen = !self.mouseLook;
self.objectSpawner.tick(dt); // self.objectSpawner.tick(dt);
extras.inputDebugger.tick(); // self.rendererDebugger.tick(dt);
self.rendererDebugger.tick(dt); // if (ig.begin("meh", null, .{})) {
if (ig.begin("meh", null, .{})) { // ig.textFmt("x:{d:.03} y:{d:.03} z:{d:.03}", .{ pos.x, pos.y, pos.z }) catch return;
ig.textFmt("x:{d:.03} y:{d:.03} z:{d:.03}", .{ pos.x, pos.y, pos.z }) catch return; // // if (ig.checkbox("video fullbright", &self.videoFullbright)) {
// if (ig.checkbox("video fullbright", &self.videoFullbright)) { // // //if (self.videoplayerObject.fetch(rend.MeshComponent)) |mesh| {
// //if (self.videoplayerObject.fetch(rend.MeshComponent)) |mesh| { // // // mesh.textureMode.fullbright = self.videoFullbright;
// // mesh.textureMode.fullbright = self.videoFullbright; // // //}
// //} // // }
// }
if (ig.checkbox("move lights ", &self.moveLight)) {} // if (ig.checkbox("move lights ", &self.moveLight)) {}
ig.textFmt("info: - WASD to move, mouse to look,\n- Q and E to go up and down", .{}) catch return; // ig.textFmt("info: - WASD to move, mouse to look,\n- Q and E to go up and down", .{}) catch return;
ig.textFmt("- shift to slow down camera speed", .{}) catch return; // ig.textFmt("- shift to slow down camera speed", .{}) catch return;
ig.textFmt("- T to enable/disable mouse cursor", .{}) catch return; // ig.textFmt("- T to enable/disable mouse cursor", .{}) catch return;
ig.textFmt("- f2 to route all inputs to the doom player", .{}) catch return; // ig.textFmt("- f2 to route all inputs to the doom player", .{}) catch return;
ig.textFmt("- movingLight checkbox makes the light stop moving with you", .{}) catch return; // ig.textFmt("- movingLight checkbox makes the light stop moving with you", .{}) catch return;
//ig.textf("1 + 2 = {d}", .{self.addFunc.?(1, 2)}); // //ig.textf("1 + 2 = {d}", .{self.addFunc.?(1, 2)});
{ // {
ig.textf("modules dirty: ", .{}); // ig.textf("modules dirty: ", .{});
var i = self.modules.iterator(); // var i = self.modules.iterator();
while (i.next()) |n| { // while (i.next()) |n| {
ig.textf("{s} pending reload", .{n.value_ptr.*}); // ig.textf("{s} pending reload", .{n.value_ptr.*});
} // }
} // }
if (ig.smallButton("reload map")) {
self.loadMap2() catch unreachable;
}
if (ig.smallButton("destroy map")) { // if (ig.smallButton("reload map")) {
if (self.tbMap) |tbMap| { // self.loadMap2() catch unreachable;
core.engine_log("killing the map", .{}); // }
tbMap.destroy();
self.tbMap = null;
}
}
}
ig.end();
if (ig.begin("mesh components", null, .{})) { // if (ig.smallButton("destroy map")) {
for (rend.MeshComponent.BaseContainer.dense.items) |*v| { // if (self.tbMap) |tbMap| {
ig.textFmt("mesh: {s}", .{v.value.meshName.utf8()}) catch unreachable; // core.engine_log("killing the map", .{});
} // tbMap.destroy();
} // self.tbMap = null;
ig.end(); // }
// }
// }
// ig.end();
if (ig.begin("scene components", null, .{})) { // if (ig.begin("mesh components", null, .{})) {
for (core.Scene.BaseContainer.dense.items) |*v| { // for (rend.MeshComponent.BaseContainer.dense.items) |*v| {
ig.textFmt("scene entity: {d}", .{v.value.handle.index}) catch unreachable; // ig.textFmt("mesh: {s}", .{v.value.meshName.utf8()}) catch unreachable;
} // }
// }
// ig.end();
ig.textf("window at 0x{x}", .{@intFromPtr(backlog.platform.context().window)}); // if (ig.begin("scene components", null, .{})) {
if (ig.smallButton("click to show sdl messagebox")) { // for (core.Scene.BaseContainer.dense.items) |*v| {
// _ = backlog.platform.windowing.sdl3.c.SDL_ShowSimpleMessageBox(0, "lmao", "you lmaoed your last uwu", backlog.platform.context().window); // ig.textFmt("scene entity: {d}", .{v.value.handle.index}) catch unreachable;
} // }
}
ig.end(); // ig.textf("window at 0x{x}", .{@intFromPtr(backlog.platform.context().window)});
// if (ig.smallButton("click to show sdl messagebox")) {
// // _ = backlog.platform.windowing.sdl3.c.SDL_ShowSimpleMessageBox(0, "lmao", "you lmaoed your last uwu", backlog.platform.context().window);
// }
// }
// ig.end();
} }
} }
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
self.modules.deinit(self.allocator); self.modules.deinit(self.allocator);
self.rendererDebugger.destroy(); // self.rendererDebugger.destroy();
DoomPlayer.DoomCanvas.cleanupDoom(); DoomPlayer.DoomCanvas.cleanupDoom();
self.fpcamera.destroy(); self.fpcamera.destroy();
self.objectSpawner.destroy(); // self.objectSpawner.destroy();
// self.videoplayer.destroy(); // self.videoplayer.destroy();
self.allocator.destroy(self); self.allocator.destroy(self);
} }