diff --git a/engine/audio/src/sound_engine.zig b/engine/audio/src/sound_engine.zig index 86d6e69..8e7f044 100644 --- a/engine/audio/src/sound_engine.zig +++ b/engine/audio/src/sound_engine.zig @@ -11,19 +11,19 @@ const tracy = core.tracy; const ma = @import("miniaudio"); pub fn sound_log(comptime fmt: []const u8, args: anytype) void { - core.printInner("[SOUND ]: " ++ fmt ++ "\n", args); + core.printInner(core.defaultHighlight, "[SOUND ]: " ++ fmt ++ "\n", args); } pub fn sound_logs(comptime fmt: []const u8) void { - core.printInner("[SOUND ]: " ++ fmt ++ "\n", .{}); + core.printInner(core.defaultHighlight, "[SOUND ]: " ++ fmt ++ "\n", .{}); } pub fn sound_err(comptime fmt: []const u8, args: anytype) void { - core.printInner("[SOUND ]: ERROR!! " ++ fmt ++ "\n", args); + core.printInner(core.errorHighlight, "[SOUND ]: ERROR!! " ++ fmt ++ "\n", args); } pub fn sound_errs(comptime fmt: []const u8) void { - core.printInner("[SOUND ]: ERROR!!" ++ fmt ++ "\n", .{}); + core.printInner(core.errorHighlight, "[SOUND ]: ERROR!!" ++ fmt ++ "\n", .{}); } pub const SoundLoader = struct { diff --git a/engine/core/src/configVars.zig b/engine/core/src/configVars.zig index f982870..b05284d 100644 --- a/engine/core/src/configVars.zig +++ b/engine/core/src/configVars.zig @@ -215,8 +215,8 @@ pub const Parser = struct { fn printError(self: *@This(), comptime fmt: []const u8, args: anytype) !void { if (core.getLogger()) |logger| { - try logger.print(fmt, args); - try logger.print("[Config ]: Config File Parse Error> {s}:{d} \n", .{ self.fileName, self.lineNumber }); + try logger.print(core.colors.Color.Red, fmt, args); + try logger.print(core.colors.Color.Red, "[Config ]: Config File Parse Error> {s}:{d} \n", .{ self.fileName, self.lineNumber }); } } diff --git a/engine/core/src/core.zig b/engine/core/src/core.zig index bf14b72..e793549 100644 --- a/engine/core/src/core.zig +++ b/engine/core/src/core.zig @@ -16,6 +16,7 @@ pub const ActionBinding = inputs.ActionBinding; pub const IOEvent = inputs.IOEvent; pub const debug_draw = @import("debug_draw.zig"); +pub const debugTextLog = debug_draw.debugTextLog; pub const DebugDrawParams = debug_draw.DebugDrawParams; pub const DebugDrawInterface = debug_draw.DebugDrawInterface; pub const installDebugDrawInterface = debug_draw.installDebugDrawInterface; diff --git a/engine/core/src/debug_draw.zig b/engine/core/src/debug_draw.zig index 24bd972..d56fa77 100644 --- a/engine/core/src/debug_draw.zig +++ b/engine/core/src/debug_draw.zig @@ -7,12 +7,24 @@ pub const DebugDrawParams = struct { rotation: core.Quat = .{ 0, 0, 0, 1 }, }; +pub const DebugLogParamsInner = struct { + slice: []const u8, + duration: f64, + color: core.colors.Color = core.colors.Color.Yellow, +}; + +pub const DebugLogParams = struct { + color: core.colors.Color = core.colors.Color.Yellow, +}; + pub const DebugDrawInterface = struct { debugSphereFn: *const fn (pos: core.Vectorf, radius: f32, DebugDrawParams) void, debugBoxFn: *const fn (pos: core.Vectorf, extents: core.Vectorf, DebugDrawParams) void, debugLineFn: *const fn (start: core.Vectorf, end: core.Vectorf, DebugDrawParams) void, }; +pub const DebugLogDelegate = core.EngineObjectDelegate(*const fn (*anyopaque, DebugLogParamsInner) void); + pub var gDebugDrawInterface: ?*DebugDrawInterface = null; var gDebugDrawAllocator: ?std.mem.Allocator = null; @@ -40,6 +52,11 @@ pub fn debugBox(pos: core.Vectorf, extents: core.Vectorf, params: DebugDrawParam } } +pub fn installDebugLogInterface(ptr: anytype) void { + const interface = DebugLogDelegate.make(ptr, "onDebugLog"); + core.get(core.LoggerSys).debugLogInterface = interface; +} + pub fn installDebugDrawInterface(allocator: std.mem.Allocator, newInterface: DebugDrawInterface) !void { gDebugDrawInterface = try allocator.create(DebugDrawInterface); gDebugDrawAllocator = allocator; @@ -54,3 +71,16 @@ pub fn shutdownDrawInterface() void { gDebugDrawAllocator.?.destroy(interface); } } + +pub fn debugTextLog(slice: []const u8, duration: f64, params: DebugLogParams) void { + if (core.getEngineObject(core.LoggerSys)) |logger| { + if (logger.debugLogInterface) |*interface| { + const p = DebugLogParamsInner{ + .slice = slice, + .duration = duration, + .color = params.color, + }; + interface.call(p); + } + } +} diff --git a/engine/core/src/engineObject.zig b/engine/core/src/engineObject.zig index faa488e..c41a978 100644 --- a/engine/core/src/engineObject.zig +++ b/engine/core/src/engineObject.zig @@ -127,6 +127,18 @@ pub fn EngineObjectDelegate(comptime T: type) type { version: i32 = -1, vtable: *EngineObjectVTable, + pub fn make(ptr: anytype, comptime funcName: []const u8) @This() { + const TargetType = @typeInfo(@TypeOf(ptr)).pointer.child; + const func = @field(TargetType, funcName); + + return .{ + .func = func, + .functionName = funcName, + .target = ptr, + .vtable = &TargetType.NeonObjectTable, + }; + } + pub fn call(self: *@This(), args: anytype) void { //if (!core.BuildOption("static_build")) { todo; disable this vtable check in non-static builds if (self.vtable.version != self.version) { diff --git a/engine/core/src/inputs/inputStack.zig b/engine/core/src/inputs/inputStack.zig index f240849..878b39a 100644 --- a/engine/core/src/inputs/inputStack.zig +++ b/engine/core/src/inputs/inputStack.zig @@ -170,13 +170,26 @@ pub const ActionBinding = struct { return self; } + + pub fn addToLayer(self: *@This(), layer: *BindingLayer) !void { + try layer.addBindingByName(self.data.name, self); + } + + pub fn removeFromLayer(self: *@This(), layer: *BindingLayer) !void { + try layer.removeBindingByName(self.data.name); + } + // pushes this binding to the active layer pub fn activate(self: *@This()) void { - getInputStack().active.addBindingByName(self.data.name, self) catch unreachable; + if (getInputStack().active) |active| { + active.addBindingByName(self.data.name, self) catch unreachable; + } } pub fn deactivate(self: *@This()) void { - getInputStack().active.removeBindingByName(self.data.name); + if (getInputStack().active) |active| { + active.removeBindingByName(self.data.name); + } } pub fn addKey(self: *@This(), key: Key, event: ActionEvent) void { @@ -224,9 +237,19 @@ pub const Axis1dBinding = struct { return self; } + pub fn addToLayer(self: *@This(), layer: *BindingLayer) !void { + try layer.addBindingByName(self.data.name, self); + } + + pub fn removeFromLayer(self: *@This(), layer: *BindingLayer) !void { + try layer.removeBindingByName(self.data.name); + } + // pushes this binding to the active layer pub fn activate(self: *@This()) void { - getInputStack().active.addBindingByName(self.data.name, self) catch unreachable; + if (getInputStack().active) |active| { + active.addBindingByName(self.data.name, self) catch unreachable; + } } pub fn setClamp(self: *@This(), clampValue: ?f32) void { @@ -234,7 +257,9 @@ pub const Axis1dBinding = struct { } pub fn deactivate(self: *@This()) void { - getInputStack().active.removeBindingByName(self.data.name); + if (getInputStack().active) |active| { + active.removeBindingByName(self.data.name); + } } pub fn addKey(self: *@This(), key: Key, magnitude: f32) void { @@ -270,6 +295,14 @@ pub const Axis2dBinding = struct { // func: Axis2dFunc, // }; + pub fn addToLayer(self: *@This(), layer: *BindingLayer) !void { + try layer.addBindingByName(self.data.name, self); + } + + pub fn removeFromLayer(self: *@This(), layer: *BindingLayer) !void { + try layer.removeBindingByName(self.data.name); + } + pub fn create(name: core.Name) !*@This() { const allocator = arenaAlloc(); const self = try allocator.create(@This()); @@ -296,11 +329,15 @@ pub const Axis2dBinding = struct { // pushes this binding to the active layer pub fn activate(self: *@This()) void { - getInputStack().active.addBindingByName(self.data.name, self) catch unreachable; + if (getInputStack().active) |active| { + active.addBindingByName(self.data.name, self) catch unreachable; + } } pub fn deactivate(self: *@This()) void { - getInputStack().active.removeBindingByName(self.data.name); + if (getInputStack().active) |active| { + active.removeBindingByName(self.data.name); + } } pub fn addKey(self: *@This(), key: Key, magnitude: f32, axis: enum { x, y }) void { @@ -581,7 +618,8 @@ pub const BindingLayer = struct { pub const InputStack = struct { allocator: std.mem.Allocator, - active: *BindingLayer, + active: ?*BindingLayer, + bindingStack: std.ArrayListUnmanaged(*BindingLayer) = .{}, arena: std.heap.ArenaAllocator, keysDown: std.AutoHashMapUnmanaged(Key, bool) = .{}, @@ -610,36 +648,49 @@ pub const InputStack = struct { } pub fn updatePreviousInputs(self: *@This()) void { - if (self.active.bindingStack.items.len == 0) { + if (self.active == null) { + return; + } + const active = self.active.?; + + if (active.bindingStack.items.len == 0) { return; } - var i: i32 = @intCast(self.active.bindingStack.items.len - 1); + var i: i32 = @intCast(active.bindingStack.items.len - 1); while (i >= 0) : (i -= 1) { - const binding = &self.active.bindingStack.items[@intCast(i)]; + const binding = &active.bindingStack.items[@intCast(i)]; binding.processHeldKeys(); } } pub fn sendAxisUpdates(self: *@This()) void { - for (self.active.bindingStack.items) |binding| { + if (self.active == null) { + return; + } + const active = self.active.?; + for (active.bindingStack.items) |binding| { binding.sendAxisUpdates(); } } fn routeKeyEvent(self: *@This(), key: Key, event: ActionEvent) void { + if (self.active == null) { + return; + } + const active = self.active.?; // for all bindings in reverse order from this layer, route the input, stop the // route if the input was consumed // core.engine_log(" >> {any} > routeKeyEvent 1", .{key}); - if (self.active.bindingStack.items.len == 0) { + if (active.bindingStack.items.len == 0) { return; } // core.engine_log(" >> {any} > routeKeyEvent 2", .{key}); - var i: i32 = @intCast(self.active.bindingStack.items.len - 1); + var i: i32 = @intCast(active.bindingStack.items.len - 1); // core.engine_log(" >> {any} > routeKeyEvent 2 binding count : {d}", .{ key, i }); while (i >= 0) : (i -= 1) { - const binding = self.active.bindingStack.items[@intCast(i)]; + const binding = active.bindingStack.items[@intCast(i)]; var consumed: bool = false; var routed: bool = false; @@ -662,13 +713,17 @@ pub const InputStack = struct { } fn routeMouseRelative(self: *@This(), move: core.Vector2f) void { - if (self.active.bindingStack.items.len == 0) { + if (self.active == null) { return; } - var i: i32 = @intCast(self.active.bindingStack.items.len - 1); + const active = self.active.?; + if (active.bindingStack.items.len == 0) { + return; + } + var i: i32 = @intCast(active.bindingStack.items.len - 1); // core.engine_log(" >> {any} > routeKeyEvent 2 binding count : {d}", .{ key, i }); while (i >= 0) : (i -= 1) { - const binding = self.active.bindingStack.items[@intCast(i)]; + const binding = active.bindingStack.items[@intCast(i)]; switch (binding) { // only axis2d handles mouse relative right now, @@ -700,7 +755,9 @@ pub const InputStack = struct { pub fn deinit(self: *@This()) void { self.arena.deinit(); - self.active.destroy(); + if (self.active) |active| { + active.destroy(); + } self.allocator.destroy(self); } }; diff --git a/engine/core/src/logging.zig b/engine/core/src/logging.zig index bbbc270..a3591f4 100644 --- a/engine/core/src/logging.zig +++ b/engine/core/src/logging.zig @@ -36,6 +36,9 @@ pub const LogBuffer = struct { } }; +pub const defaultHighlight = core.colors.Color.Yellow; +pub const errorHighlight = core.colors.Color.Red; + pub fn printRaw(comptime fmt: []const u8, args: anytype) void { if (zero_logging) { return; @@ -45,14 +48,14 @@ pub fn printRaw(comptime fmt: []const u8, args: anytype) void { std.debug.print(fmt, args); } else { if (gLoggerSys) |loggerSys| { - loggerSys.print(fmt, args) catch std.debug.print("!> " ++ fmt, args); + loggerSys.print(defaultHighlight, fmt, args) catch std.debug.print("!> " ++ fmt, args); } else { std.debug.print(fmt, args); } } } -pub fn printInner(comptime fmt: []const u8, args: anytype) void { +pub fn printInner(highlight: core.colors.Color, comptime fmt: []const u8, args: anytype) void { if (zero_logging) { return; } @@ -61,7 +64,7 @@ pub fn printInner(comptime fmt: []const u8, args: anytype) void { std.debug.print("> " ++ fmt, args); } else { if (gLoggerSys) |loggerSys| { - loggerSys.print(fmt, args) catch std.debug.print("!> " ++ fmt, args); + loggerSys.print(highlight, fmt, args) catch std.debug.print("!> " ++ fmt, args); } else { std.debug.print("> " ++ fmt, args); } @@ -70,63 +73,63 @@ 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); + printInner(defaultHighlight, "[" ++ prefix ++ "]: " ++ fmt ++ "\n", args); } pub fn game_log(comptime fmt: []const u8, args: anytype) void { - printInner("[GAME ]: " ++ fmt ++ "\n", args); + printInner(defaultHighlight, "[GAME ]: " ++ fmt ++ "\n", args); } pub fn game_logs(comptime fmt: []const u8) void { - printInner("[GAME ]: " ++ fmt ++ "\n", .{}); + printInner(defaultHighlight, "[GAME ]: " ++ fmt ++ "\n", .{}); } pub fn ui_log(comptime fmt: []const u8, args: anytype) void { - printInner("[UI ]: " ++ fmt ++ "\n", args); + printInner(defaultHighlight, "[UI ]: " ++ fmt ++ "\n", args); } pub fn ui_logs(comptime fmt: []const u8) void { - printInner("[UI ]: " ++ fmt ++ "\n", .{}); + printInner(defaultHighlight, "[UI ]: " ++ fmt ++ "\n", .{}); } pub fn console_log(comptime fmt: []const u8, args: anytype) void { - printInner("[CONSOLE ]: " ++ fmt ++ "\n", args); + printInner(defaultHighlight, "[CONSOLE ]: " ++ fmt ++ "\n", args); } pub fn console_logs(comptime fmt: []const u8) void { - printInner("[CONSOLE ]: " ++ fmt ++ "\n"); + printInner(defaultHighlight, "[CONSOLE ]: " ++ fmt ++ "\n"); } pub fn engine_log(comptime fmt: []const u8, args: anytype) void { - printInner("[ENGINE ]: " ++ fmt ++ "\n", args); + printInner(defaultHighlight, "[ENGINE ]: " ++ fmt ++ "\n", args); } pub fn engine_logs(comptime fmt: []const u8) void { - printInner("[ENGINE ]: " ++ fmt ++ "\n", .{}); + printInner(defaultHighlight, "[ENGINE ]: " ++ fmt ++ "\n", .{}); } pub fn engine_err(comptime fmt: []const u8, args: anytype) void { - printInner("[ENGINE ]: ERROR!! " ++ fmt ++ "\n", args); + printInner(errorHighlight, "[ENGINE ]: ERROR!! " ++ fmt ++ "\n", args); } pub fn engine_errs(comptime fmt: []const u8) void { - printInner("[ENGINE ]: ERROR!! " ++ fmt ++ "\n", .{}); + printInner(errorHighlight, "[ENGINE ]: ERROR!! " ++ fmt ++ "\n", .{}); } pub fn test_log(comptime fmt: []const u8, args: anytype) void { - printInner("[TEST ]: " ++ fmt ++ "\n", args); + printInner(defaultHighlight, "[TEST ]: " ++ fmt ++ "\n", args); } pub fn test_logs(comptime fmt: []const u8) void { - printInner("[TEST ]: " ++ fmt ++ "\n", .{}); + printInner(defaultHighlight, "[TEST ]: " ++ fmt ++ "\n", .{}); } pub fn graphics_log(comptime fmt: []const u8, args: anytype) void { - printInner("[GRAPHICS ]: " ++ fmt ++ "\n", args); + printInner(defaultHighlight, "[GRAPHICS ]: " ++ fmt ++ "\n", args); } pub fn graphics_logs(comptime fmt: []const u8) void { - printInner("[GRAPHICS ]: " ++ fmt ++ "\n", .{}); + printInner(defaultHighlight, "[GRAPHICS ]: " ++ fmt ++ "\n", .{}); } pub const FileLog = struct { @@ -198,6 +201,8 @@ pub const LoggerSys = struct { lock: std.Thread.Mutex = .{}, flushing: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), + debugLogInterface: ?core.debug_draw.DebugLogDelegate = null, + sessionBuffer: ?*LogBuffer = null, // disabled in release modes pub fn flush(self: *@This()) !void { @@ -264,14 +269,25 @@ pub const LoggerSys = struct { self.lock.unlock(); } - pub fn print(self: *@This(), comptime fmt: []const u8, args: anytype) !void { + var slice: [4096]u8 = undefined; + pub fn print(self: *@This(), highlight: core.colors.Color, comptime fmt: []const u8, args: anytype) !void { self.lock.lock(); try self.writeOutBuffer.writer().print(fmt, args); self.lock.unlock(); - if (self.sessionBuffer != null and !core.getEngine().isShuttingDown()) { - self.sessionBuffer.?.lockWriter().print(fmt, args) catch {}; - self.sessionBuffer.?.unlock(); + blk: { + if (self.sessionBuffer != null and !core.getEngine().isShuttingDown()) { + self.sessionBuffer.?.lockWriter().print(fmt, args) catch { + self.sessionBuffer.?.unlock(); + break :blk; + }; + self.sessionBuffer.?.unlock(); + + const s = std.fmt.bufPrint(&slice, fmt, args) catch { + break :blk; + }; + core.debugTextLog(s, 3.5, .{ .color = highlight }); + } } if (self.writeOutBuffer.items.len > LogBufferSize) { diff --git a/engine/imgui/src/sgpu/backend_impl.zig b/engine/imgui/src/sgpu/backend_impl.zig index 20cdb20..1f375cf 100644 --- a/engine/imgui/src/sgpu/backend_impl.zig +++ b/engine/imgui/src/sgpu/backend_impl.zig @@ -25,13 +25,21 @@ pub const Impl = struct { return self; } + const ImguiArgs = struct { imguiIni: []const u8 = "imgui.ini" }; + pub fn setup(self: *@This()) !void { core.graphics_log("imgui startup", .{}); self.device = rend.context().device; try rend.registerRendererObject(@This(), self); + const args = try core.ParseArgs(ImguiArgs); + c.Imgui_SDL3_Init(@ptrCast(platform.getInstance().window), @ptrCast(self.device)); + ig.getIO().?.ini_file_name = @ptrCast(args.imguiIni.ptr); + ig.loadIniSettingsFromDisk(@ptrCast(args.imguiIni.ptr)); + try platform.getInstance().addSDLProcessFunction(processSDLEvents); + core.engine_log("using imgui ini: {s}", .{args.imguiIni}); self.context = ig.getCurrentContext().?; self.setupBeginCount(); diff --git a/engine/imgui/src/utils/consoleWindow.zig b/engine/imgui/src/utils/consoleWindow.zig index ad222eb..33ee5e0 100644 --- a/engine/imgui/src/utils/consoleWindow.zig +++ b/engine/imgui/src/utils/consoleWindow.zig @@ -39,8 +39,10 @@ pub fn windowOpen(entry: *imgui.utils.MenuEntry, dt: f64) void { items = self.buffer.buffer.items[if (items.len > 10000) items.len - 10000 else 0..items.len]; ig.textSlice(items); - if (self.lastLength != self.buffer.buffer.items.len) + const b = self.buffer.buffer.items; + if (self.lastLength != b.len and b.len > 0) { ig.setScrollHereY(1.0); + } } ig.end(); diff --git a/engine/net/src/enet/EnetTransport.zig b/engine/net/src/enet/EnetTransport.zig index 378b910..f7b559e 100644 --- a/engine/net/src/enet/EnetTransport.zig +++ b/engine/net/src/enet/EnetTransport.zig @@ -1,7 +1,7 @@ pub var TransportInterfaceVTable = net.TransportInterface.Implement(@This()); pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "net.ENetTransport"); -allocator: std.mem.Allocator, +allocator: std.mem.Allocator = undefined, sessions: std.ArrayListUnmanaged(*net.Session) = .{}, deadSessions: std.ArrayListUnmanaged(*net.Session) = .{}, @@ -59,6 +59,12 @@ const ENetLinkData = struct { }) catch unreachable; } + pub fn sendPacketChannelDebug(self: *@This(), bytes: []const u8, reliable: bool, channel: u8) void { + if (enet.enet_packet_create(bytes.ptr, bytes.len, if (reliable) enet.ENET_PACKET_FLAG_RELIABLE else 0)) |packet| { + _ = enet.enet_peer_send(self.peer, channel, packet); + } + } + // raw access to sendPacket pub fn sendPacket(self: *@This(), bytes: []const u8, reliable: bool) void { if (enet.enet_packet_create(bytes.ptr, bytes.len, if (reliable) enet.ENET_PACKET_FLAG_RELIABLE else 0)) |packet| { @@ -106,12 +112,17 @@ const ENetSessionData = struct { enet.ENET_EVENT_TYPE_RECEIVE => { self.messageCount += 1; const data = @as([*]u8, @ptrCast(event.packet.*.data))[0..event.packet.*.dataLength]; - // core.engine_log("Received message #{}: '{s}' echoing it back", .{ self.messageCount, data }); + core.engine_log("Received message #{d} channel {d}: '{s}' echoing it back", .{ self.messageCount, event.channelID, data }); if (self.findLinkByPeer(event.peer)) |link| { const linkData = getLinkData(link); if (link.linkType == .server) { - linkData.queuePacketData(data, true); + // linkData.queuePacketData(data, true); + if (std.mem.startsWith(u8, data, "cname:")) { + const ipAsString = net.ip2String(net.netAllocator(), event.peer.*.address.host) catch unreachable; + const id = std.fmt.allocPrint(net.netAllocator(), "{s}@{s}", .{ data[6..data.len], ipAsString }) catch unreachable; + link.idString = id; + } } if (link.linkType == .client) { if (!std.mem.startsWith(u8, data, "msg:")) { @@ -143,6 +154,8 @@ const ENetSessionData = struct { net.netAllocator().free(queuedData.bytes); } } + + enet.enet_host_flush(self.host); } }; diff --git a/engine/net/src/netEngine.zig b/engine/net/src/netEngine.zig index 8ddf2f7..1a1d225 100644 --- a/engine/net/src/netEngine.zig +++ b/engine/net/src/netEngine.zig @@ -4,19 +4,19 @@ const std = @import("std"); pub const EnetTransport = @import("enet/EnetTransport.zig"); pub fn net_log(comptime fmt: []const u8, args: anytype) void { - core.printInner("[NET ]: " ++ fmt ++ "\n", args); + core.printInner(core.defaultHighlight, "[NET ]: " ++ fmt ++ "\n", args); } pub fn net_logs(comptime fmt: []const u8) void { - core.printInner("[NET ]: " ++ fmt ++ "\n", .{}); + core.printInner(core.defaultHighlight, "[NET ]: " ++ fmt ++ "\n", .{}); } pub fn net_err(comptime fmt: []const u8, args: anytype) void { - core.printInner("[NET ]: ERROR!! " ++ fmt ++ "\n", args); + core.printInner(core.errorHighlight, "[NET ]: ERROR!! " ++ fmt ++ "\n", args); } pub fn net_errs(comptime fmt: []const u8) void { - core.printInner("[NET ]: ERROR!! " ++ fmt ++ "\n", .{}); + core.printInner(core.errorHighlight, "[NET ]: ERROR!! " ++ fmt ++ "\n", .{}); } pub const TransportRef = core.Reference(net.TransportInterface); diff --git a/engine/papyrus/src/TextEntrySystem.zig b/engine/papyrus/src/TextEntrySystem.zig index b990f3b..b559c3e 100644 --- a/engine/papyrus/src/TextEntrySystem.zig +++ b/engine/papyrus/src/TextEntrySystem.zig @@ -66,7 +66,7 @@ pub fn testHits(self: *@This()) !void { const cursorPos = ctx.currentCursorPosition; self.cursorResults = trg.testHit(cursorPos); if (self.cursorResults) |hr| { - try self.ctx.pushDebugText("text entry hittest found found: line={d} index={d}", .{ hr.line, hr.index }); + try self.ctx.pushDebugText("text entry hittest found found: line={d} index={d}", .{ hr.line, hr.index }, null); self.insertIndex = hr.index; } } diff --git a/engine/papyrus/src/localization.zig b/engine/papyrus/src/localization.zig index 8fe0907..e133369 100644 --- a/engine/papyrus/src/localization.zig +++ b/engine/papyrus/src/localization.zig @@ -87,7 +87,7 @@ pub const LocText = struct { }; } - pub fn fromUtf8Z(text: []const u8) @This() { + pub fn fromUtf8Z(text: [:0]const u8) @This() { for (text, 0..) |ch, i| { if (ch == 0) { var slice: []const u8 = undefined; diff --git a/engine/papyrus/src/papyrus.zig b/engine/papyrus/src/papyrus.zig index d99beb3..e649baf 100644 --- a/engine/papyrus/src/papyrus.zig +++ b/engine/papyrus/src/papyrus.zig @@ -419,13 +419,20 @@ pub const Context = struct { _displayLayout: std.ArrayListUnmanaged(LayoutInfo) = .{}, _horizontalLayout: std.AutoHashMapUnmanaged(NodeHandle, HorizontalLayoutInfo) = .{}, - debugText: std.ArrayList([]u8), - debugTextCount: u32 = 0, + debugText: std.ArrayList(DebugLogTextEntry), + drawDebug: bool = false, + debugEnabled: bool = false, + debugFontSize: f32 = 12, debugMousePick: bool = false, rootNodes: std.ArrayList(NodeHandle), + stringArena: std.heap.ArenaAllocator, const debugTextMax = 32; + const DebugLogTextEntry = struct { + text: []u8, + color: Color, + }; pub fn tick(self: *@This(), deltaTime: f64) !void { self.clearDebugText(); @@ -438,7 +445,7 @@ pub const Context = struct { pub fn tickDebug(self: *@This(), deltaTime: f64) !void { _ = deltaTime; - try self.pushDebugText("mouse Position: {d}, {d}", .{ self.currentCursorPosition.x, self.currentCursorPosition.y }); + try self.pushDebugText("mouse Position: {d}, {d}", .{ self.currentCursorPosition.x, self.currentCursorPosition.y }, null); if (self.debugMousePick) { if (self.mousePick.selected_node) |node| { const n = self.getRead(node); @@ -452,14 +459,14 @@ pub const Context = struct { layout.pos.y, layout.size.x, layout.size.y, - }); + }, null); } } } pub fn create(backingAllocator: std.mem.Allocator, ctx: *PapyrusRuntime) !*@This() { var self = try backingAllocator.create(@This()); - var allocator = backingAllocator; + const allocator = backingAllocator; self.* = .{ .allocator = allocator, @@ -475,16 +482,12 @@ pub const Context = struct { ._layout = .{}, ._layoutNodes = .{}, ._horizontalLayout = .{}, - .debugText = std.ArrayList([]u8).init(allocator), + .debugText = std.ArrayList(DebugLogTextEntry).init(allocator), .mousePick = Layout.init(allocator), .rootNodes = std.ArrayList(NodeHandle).init(allocator), + .stringArena = std.heap.ArenaAllocator.init(allocator), }; - for (0..debugTextMax) |_| { - const textBuffer = try allocator.alloc(u8, 512); - try self.debugText.append(textBuffer); - } - // constructing the root node _ = try self.nodes.new(.{ .text = MakeText("root"), @@ -492,20 +495,35 @@ pub const Context = struct { .nodeType = .{ .Slot = .{} }, }); - try self.pushDebugText("mouse position: {d}, {d}", .{ 0, 0 }); + try self.pushDebugText("mouse position: {d}, {d}", .{ 0, 0 }, null); return self; } - pub fn pushDebugText(self: *@This(), comptime fmt: []const u8, args: anytype) !void { - if (self.debugTextCount < debugTextMax) { - _ = try std.fmt.bufPrintZ(self.debugText.items[self.debugTextCount], fmt, args); - self.debugTextCount += 1; + pub fn pushDebugTextSlice(self: *@This(), slice: []const u8, _color: ?Color) !void { + const color = if (_color == null) Color.Yellow else _color.?; + if (self.debugText.items.len < debugTextMax) { + try self.debugText.append(.{ + .text = self.stringArena.allocator().dupe(slice) catch "", + .color = color, + }); + } + } + + pub fn pushDebugText(self: *@This(), comptime fmt: []const u8, args: anytype, _color: ?Color) !void { + const color = if (_color == null) Color.Yellow else _color.?; + + if (self.debugText.items.len < debugTextMax) { + try self.debugText.append(.{ + .text = std.fmt.allocPrint(self.stringArena.allocator(), fmt, args) catch "", + .color = color, + }); } } pub fn clearDebugText(self: *@This()) void { - self.debugTextCount = 0; + _ = self.stringArena.reset(.retain_capacity); + self.debugText.clearRetainingCapacity(); } pub const destroy = deinit; @@ -536,8 +554,9 @@ pub const Context = struct { // self._layoutPositions.deinit(self.allocator); self._displayLayout.deinit(self.allocator); + self.stringArena.deinit(); for (self.debugText.items) |text| { - self.allocator.free(text); + _ = text; } self.debugText.deinit(); self.allocator.destroy(self); @@ -1191,12 +1210,18 @@ pub const Context = struct { } } - if (self.drawDebug) { - try self.addDebugInfo(drawList); - } + if (self.debugEnabled) { + if (self.drawDebug) { + try self.addDebugInfo(drawList); + } - if (self.debugMousePick) { - try self.mousePick.addMousePickInfo(self, drawList); + if (self.debugMousePick) { + try self.mousePick.addMousePickInfo(self, drawList); + } + + // if (self.debugLogText.items.len) { + // try self.addDebugLogText(drawList); + // } } for (0..drawList.items.len) |i| { @@ -1209,10 +1234,37 @@ pub const Context = struct { } } + // fn addDebugLogText(self: *@This()) !void + // { + // const defaultHeight = 16; + // const sizePerLine: f32 = defaultHeight + 2; + // const yOffsetPerLine: f32 = defaultHeight + 1; + // var yOffset: f32 = sizePerLine * 2; + // const width = defaultHeight / 2 * 120; + + // const fontHandle = self.fontCache.defaultMonoFont.atlas.fontHandle; + // for (self.debugLogText.items)|logTextEntry| + // { + // + // } + + // try drawList.append(.{ + // .node = .{}, + // .primitive = .{ + // .Rect = .{ + // .tl = .{ .x = 30 - 5, .y = yOffset - 5 }, + // .size = .{ .x = width + 5, .y = sizePerLine * @as(f32, @floatFromInt(self.debugTextCount + 2)) }, + // .borderColor = Color.fromRGBA(0x444444ee), + // .backgroundColor = Color.fromRGBA2(0.05, 0.05, 0.08, 0.88), + // }, + // }, + // }); + // } + fn addDebugInfo(self: @This(), drawList: *DrawList) !void { - const defaultHeight = 16; - const sizePerLine: f32 = defaultHeight + 2; + const defaultHeight = self.debugFontSize; const yOffsetPerLine: f32 = defaultHeight + 1; + const sizePerLine: f32 = yOffsetPerLine + (yOffsetPerLine / 4); var yOffset: f32 = sizePerLine * 2; const width = defaultHeight / 2 * 120; @@ -1223,9 +1275,9 @@ pub const Context = struct { .primitive = .{ .Rect = .{ .tl = .{ .x = 30 - 5, .y = yOffset - 5 }, - .size = .{ .x = width + 5, .y = sizePerLine * @as(f32, @floatFromInt(self.debugTextCount + 2)) }, + .size = .{ .x = width + 5, .y = sizePerLine * @as(f32, @floatFromInt(self.debugText.items.len)) + 0.5 }, .borderColor = Color.fromRGBA(0x444444ee), - .backgroundColor = Color.fromRGBA2(0.05, 0.05, 0.08, 0.88), + .backgroundColor = Color.fromRGBA2(0.05, 0.05, 0.08, 0.68), }, }, }); @@ -1251,7 +1303,7 @@ pub const Context = struct { // yOffset += yOffsetPerLine; for (self.debugText.items, 0..) |textData, i| { - if (i >= self.debugTextCount) { + if (i >= self.debugText.items.len) { break; } @@ -1259,11 +1311,11 @@ pub const Context = struct { .node = .{ .index = @intCast(i) }, .primitive = .{ .Text = .{ - .text = LocText.fromUtf8Z(textData), + .text = LocText.fromUtf8(textData.text), .tl = .{ .x = 30, .y = yOffset }, .size = .{ .x = width, .y = 30 }, .renderMode = .NoControl, - .color = Color.Yellow, + .color = textData.color, .textSize = defaultHeight, .fontHandle = fontHandle, .flags = .{ diff --git a/engine/platform/src/windowing.zig b/engine/platform/src/windowing.zig index 0bda2c6..fd88263 100644 --- a/engine/platform/src/windowing.zig +++ b/engine/platform/src/windowing.zig @@ -90,14 +90,59 @@ pub const PlatformInstance = struct { processFuncs: std.ArrayListUnmanaged(*const fn (*sdl3.Event) void) = .{}, + platformRequests: std.ArrayListUnmanaged(PlatformRequest) = .{}, + cursorPos: core.Vector2f = .{}, pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "platform.Instance"); + pub const PlatformRequest = union(enum(u32)) { + setMouseRelativeMode: struct { relativeMode: bool }, + setMousePosition: struct { pos: core.Vector2f }, + setCursorVisible: struct { visible: bool }, + setWindowSize: struct { size: core.Vector2u }, + maximizeWindow: struct {}, + setWindowPosition: struct { pos: core.Vector2u }, + }; + + pub fn pushRequest(self: *@This(), req: PlatformRequest) void { + self.platformRequests.append(self.allocator, req) catch { + core.engine_err("unable to issue request", .{}); + }; + } + + pub fn handlePlatformRequests(self: *@This()) void { + for (self.platformRequests.items) |req| { + switch (req) { + .setMouseRelativeMode => |p| { + self.setMouseRelativeMode(p.relativeMode); + }, + .setMousePosition => |p| { + self.setMousePosition(p.pos); + }, + .setCursorVisible => |p| { + self.setCursorVisible(p.visible); + }, + .setWindowSize => |p| { + self.setWindowSize(p.size); + }, + .maximizeWindow => { + self.maximizeWindow(); + }, + .setWindowPosition => |p| { + self.setWindowPosition(p.pos); + }, + } + } + + self.platformRequests.clearRetainingCapacity(); + } + pub fn deinit(self: *@This()) void { self.allocator.free(self.windowName); self.allocator.free(self.iconPath); self.processFuncs.deinit(self.allocator); + self.platformRequests.deinit(self.allocator); self.allocator.destroy(self); // shutdown } @@ -181,9 +226,10 @@ pub const PlatformInstance = struct { pub fn procEvents(ptr: *anyopaque, frameNumber: u64) core.EngineDataEventError!void { _ = frameNumber; - const self: *@This() = @ptrCast(@alignCast(ptr)); + self.handlePlatformRequests(); + // const self: *@This() = @ptrCast(@alignCast(ptr)); var t1 = tracy.ZoneN(@src(), "Pumping Events"); defer t1.End(); @@ -198,6 +244,7 @@ pub const PlatformInstance = struct { if (event.type == sdl3.events.window_resized) { self.extent.x = @floatFromInt(event.window.data1); self.extent.y = @floatFromInt(event.window.data2); + core.engine_log("engine resized {d}x{d}", self.extent); } for (self.processFuncs.items) |func| { @@ -245,6 +292,22 @@ pub const PlatformInstance = struct { sdl3.hideCursor(); } } + + pub fn setWindowSize(self: *@This(), size: core.Vector2u) void { + if (sdl3.c.SDL_SetWindowSize(self.window, @intCast(size.x), @intCast(size.y))) { + _ = sdl3.c.SDL_SyncWindow(self.window); + } else { + core.engine_log("unable to set window size {s}", .{sdl3.getError()}); + } + } + + pub fn maximizeWindow(self: *@This()) void { + _ = sdl3.c.SDL_MaximizeWindow(self.window); + } + + pub fn setWindowPosition(self: *@This(), pos: core.Vector2u) void { + _ = sdl3.c.SDL_SetWindowPosition(self.window, @intCast(pos.x), @intCast(pos.y)); + } }; pub const IOEvent = core.IOEvent; diff --git a/engine/sys/src/systemProc.zig b/engine/sys/src/systemProc.zig index bfcf7c4..20d2df6 100644 --- a/engine/sys/src/systemProc.zig +++ b/engine/sys/src/systemProc.zig @@ -19,7 +19,6 @@ pub const SubprocessTask = struct { mutex: std.Thread.Mutex = .{}, allocator: std.mem.Allocator, - args: []const []const u8, child: ?std.process.Child = null, completed: bool = false, @@ -30,6 +29,9 @@ pub const SubprocessTask = struct { stdout: std.ArrayListUnmanaged(u8) = .{}, stderr: std.ArrayListUnmanaged(u8) = .{}, + argsOwned: std.ArrayListUnmanaged([]const u8) = .{}, + argsArena: std.heap.ArenaAllocator, + pub fn run(task: *@This()) !void { const L = struct { self: *SubprocessTask, @@ -40,12 +42,8 @@ pub const SubprocessTask = struct { self.stderr = .{}; self.stdout = .{}; core.engine_log("running task", .{}); - for (self.args) |arg| { - core.engine_log("{s}", .{arg}); - } - core.engine_log("cwd = {s}", .{self.workingDir.?}); - self.child = std.process.Child.init(self.args, self.allocator); + self.child = std.process.Child.init(self.argsOwned.items, self.allocator); self.child.?.stdout_behavior = .Inherit; self.child.?.stderr_behavior = .Inherit; self.child.?.cwd = self.workingDir; @@ -67,14 +65,20 @@ pub const SubprocessTask = struct { self.* = .{ .child = null, .allocator = allocator, - .args = argv, + .argsArena = std.heap.ArenaAllocator.init(allocator), }; + for (argv) |a| { + const v = try self.argsArena.allocator().dupe(u8, a); + try self.argsOwned.append(self.allocator, v); + } return self; } pub fn destroy(self: *@This()) void { self.mutex.lock(); + self.argsArena.deinit(); + self.argsOwned.deinit(self.allocator); if (self.child) |*child| { _ = child; core.engine_log("destroying child process", .{}); diff --git a/engine/ui/shaders/text.frag.hlsl b/engine/ui/shaders/text.frag.hlsl index bfe7f82..224e7d1 100644 --- a/engine/ui/shaders/text.frag.hlsl +++ b/engine/ui/shaders/text.frag.hlsl @@ -58,7 +58,7 @@ float4 main( // so 1 + 0.5*4 = 3 is the divisor alpha = (alpha + 0.5 * asum) / 3.0; - textColor = float4(textColor.xyz, alpha);//textColor.* alpha); + textColor = float4(textColor.xyz, alpha * textColor.w);//textColor.* alpha); textColor.xyz = pow(textColor.xyz, 2.2); // gamma correction // Premultiplied alpha output. @@ -68,7 +68,7 @@ float4 main( { float alpha = 1.0; float gray = dot(textColor.xyz, float3(0.2126, 0.7152, 0.0722)); - o = float4(textColor.xyz , pow(tex.x / gray, 1/(2.2)) );//textColor.* alpha); + o = float4(textColor.xyz , pow(tex.x / gray, 1/(2.2)) * textColor.w );//textColor.* alpha); //outFragColor = vec4(1.0, 0.0, 0.0, 1.0); } @@ -78,7 +78,7 @@ float4 main( if(!rect(pixelPosition, position, size)) { } - outFragColor = float4(1.0, 0.0, 0.0, 1.0); + outFragColor = float4(1.0, 0.0, 0.0, textColor.w); return outFragColor + o * 0.00001; #else diff --git a/engine/ui/src/sgpu/papyrusSgpu.zig b/engine/ui/src/sgpu/papyrusSgpu.zig index 28a7971..e35309b 100644 --- a/engine/ui/src/sgpu/papyrusSgpu.zig +++ b/engine/ui/src/sgpu/papyrusSgpu.zig @@ -14,6 +14,7 @@ quadMesh: ?rend.IndexedMesh = null, quadMeshName: core.Name, stringArena: std.heap.ArenaAllocator, +debugStringArena: std.heap.ArenaAllocator, drawList: papyrus.DrawList, first: bool = true, @@ -29,6 +30,14 @@ reloadingShaders: bool = false, lastEventsCount: u64 = 0, +debugTextQueue: core.RingQueue(DebugTextCommand) = undefined, + +const DebugTextCommand = struct { + text: []u8, + color: core.colors.Color, + duration: f32, +}; + const DrawCommand = union(enum(u8)) { rect: struct { ssboIndex: u32, @@ -119,17 +128,36 @@ pub fn create(allocator: std.mem.Allocator) !*@This() { .screenContext = undefined, .runtime = try papyrus.PapyrusRuntime.create(allocator), .stringArena = std.heap.ArenaAllocator.init(allocator), + .debugStringArena = std.heap.ArenaAllocator.init(allocator), .quadMeshName = core.MakeName("m_screenPlane"), .drawList = papyrus.DrawList.init(allocator), + .debugTextQueue = try @TypeOf(self.debugTextQueue).init(allocator, 4096), .screenBuffers = undefined, }; self.screenContext = try self.runtime.addContext(); try self.textRenderers.put(allocator, self.screenContext, try TextRenderer.create(allocator)); + self.screenContext.debugEnabled = true; + + core.debug_draw.installDebugLogInterface(self); return self; } +pub fn onDebugLog(ctx: ?*anyopaque, params: core.debug_draw.DebugLogParamsInner) void { + const self = core.cast(*@This(), ctx.?); + + // std.debug.print("================\n", .{}); + // std.debug.print("{s}", .{params.slice}); + // std.debug.print("==============\n", .{}); + + const s = self.debugStringArena.allocator().dupe(u8, params.slice) catch { + return; + }; + + self.debugTextQueue.pushLocked(.{ .text = s, .duration = @floatCast(params.duration), .color = params.color }) catch {}; +} + pub fn tick(self: *@This(), dt: f64) void { const inputStack = core.getInputStack(); self.screenContext.setCursorLocation(.{ @@ -141,26 +169,64 @@ pub fn tick(self: *@This(), dt: f64) void { core.engine_errs("unable to tick papyrus"); }; - self.screenContext.pushDebugText("fps: {d:.2} ({d:.4}ms)", .{ 1 / core.getEngine().averageFrameTime, core.getEngine().averageFrameTime }) catch {}; + self.screenContext.pushDebugText("fps: {d:.2} ({d:.4}ms)", .{ 1 / core.getEngine().averageFrameTime, core.getEngine().averageFrameTime }, null) catch {}; if (core.MemoryTracker.MTGet()) |tracker| { self.screenContext.pushDebugText("memory used: {d:.4} MiB in {d} allocations {d} events per frame", .{ @as(f64, @floatFromInt(tracker.totalAllocSize)) / 1024 / 1024, tracker.allocationsCount, tracker.eventsCount - self.lastEventsCount, - }) catch {}; + }, null) catch {}; self.screenContext.pushDebugText("untracked allocations: {d:.4} MiB in {d} allocations", .{ @as(f64, @floatFromInt(tracker.untrackedAllocationsSize)) / 1024 / 1024, tracker.untrackedAllocationsCount, - }) catch {}; + }, null) catch {}; self.screenContext.pushDebugText("total {d:.4} MiB", .{ @as(f64, @floatFromInt(tracker.getTotalMemoryUsed())) / 1024 / 1024, - }) catch {}; + }, null) catch {}; self.lastEventsCount = tracker.eventsCount; } + + const fdt: f32 = @floatCast(dt); + + var offset: usize = 0; + self.debugTextQueue.lock(); + defer self.debugTextQueue.unlock(); + + const count = self.debugTextQueue.count(); + + while (offset < count and offset < 32) { + const display = self.debugTextQueue.queue.at(count - offset - 1).?; + + var color = display.color; + if (display.duration < 1.5) { + color.a = display.duration / 1.5; + } + + // in terms of rendering, we gonna just + self.screenContext.pushDebugText("{s}", .{ + display.text, + }, color) catch {}; + + offset += 1; + } + + offset = 0; + + while (offset < count) { + var next = self.debugTextQueue.popFromUnlocked().?; + next.duration -= fdt; + + if (next.duration >= 0) { + self.debugTextQueue.queue.push(next) catch {}; + } else { + self.debugStringArena.allocator().free(next.text); + } + offset += 1; + } } pub fn setup(self: *@This()) !void { @@ -205,10 +271,12 @@ pub fn destroy(self: *@This()) void { next.*.destroy(); } + self.debugTextQueue.deinit(); self.fontTextures.deinit(self.allocator); self.textRenderers.deinit(self.allocator); self.screenContext.destroy(); self.stringArena.deinit(); + self.debugStringArena.deinit(); self.runtime.destroy(); self.drawList.deinit(); self.tempDrawCommand.deinit(self.allocator); @@ -340,8 +408,8 @@ pub fn drawToTarget(self: *@This(), cmd: *gpu.GPUCommandBuffer, ctx: *papyrus.Co const stashedDrawDebug = ctx.drawDebug; if (self.reloadingShaders) { - ctx.pushDebugText("recompiling shaders...", .{}) catch {}; - ctx.pushDebugText("...", .{}) catch {}; + ctx.pushDebugText("recompiling shaders...", .{}, null) catch {}; + ctx.pushDebugText("...", .{}, null) catch {}; } ctx.drawDebug = stashedDrawDebug or self.reloadingShaders; diff --git a/engine/ui/src/sgpu/textRenderer.zig b/engine/ui/src/sgpu/textRenderer.zig index a7a64bf..fb80544 100644 --- a/engine/ui/src/sgpu/textRenderer.zig +++ b/engine/ui/src/sgpu/textRenderer.zig @@ -239,7 +239,7 @@ pub const TextRenderer = struct { .x = baseMetrics.x / @as(f32, @floatFromInt(atlas.atlasSize.x)), .y = baseMetrics.y / @as(f32, @floatFromInt(atlas.atlasSize.y)), }, // uv size - .{ .r = color.r, .g = color.g, .b = color.b }, // color + .{ .r = color.r, .g = color.g, .b = color.b, .a = color.a }, // color // uvSize: core.Vector2f, // color: core.colors.Color, // vertex: *TextBufferList(TextMeshVertex), diff --git a/extras/gameExtras/src/gameExtras.zig b/extras/gameExtras/src/gameExtras.zig index e295fd7..7c7ef6a 100644 --- a/extras/gameExtras/src/gameExtras.zig +++ b/extras/gameExtras/src/gameExtras.zig @@ -12,12 +12,11 @@ pub const ModuleLoader = @import("debuggers/modulesLoader.zig"); pub const browser = @import("debuggers/fileBrowser.zig"); -pub fn setup() !void { - _ = try core.createObject(games.GameList, .{}); -} +pub const GameList = games.GameList; pub const GameModeMessage = games.GameModeMessage; pub const GameModeState = games.GameModeState; +pub const addGame = games.addGame; pub const getGame = games.getGame; pub const beginGame = games.beginGame; pub const endGame = games.endGame; diff --git a/extras/gameExtras/src/gameplay/games.zig b/extras/gameExtras/src/gameplay/games.zig index 694d0be..7910429 100644 --- a/extras/gameExtras/src/gameplay/games.zig +++ b/extras/gameExtras/src/gameplay/games.zig @@ -20,7 +20,7 @@ pub const GameInterface = struct { pub const GameList = struct { pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "extras.GameList"); - allocator: std.mem.Allocator, + allocator: std.mem.Allocator = undefined, games: std.StringHashMapUnmanaged(*GameInterface) = .{}, gamesByTag: std.AutoHashMapUnmanaged(u32, GameInterfaceList) = .{}, @@ -87,16 +87,24 @@ pub const GameList = struct { }; pub fn beginGame(name: []const u8) void { - getGame(name).beginPlay(); + if (getGame(name)) |game| { + game.beginPlay(); + } else { + core.engine_log("unable to begin game {s}", .{name}); + } } pub fn endGame(name: []const u8) void { - getGame(name).endPlay(); + if (getGame(name)) |game| { + game.endPlay(); + } else { + core.engine_log("unable to endPlay game {s}", .{name}); + } } -pub fn getGame(name: []const u8) *GameInterface { +pub fn getGame(name: []const u8) ?*GameInterface { core.engine_log("getting Game {s}", .{name}); - return core.EngineObject(GameList).get().games.get(name).?; + return core.EngineObject(GameList).get().games.get(name); } pub fn addGame(name: []const u8, p: *anyopaque, comptime T: type) !void { diff --git a/lib/p2/src/structures/ring-queue.zig b/lib/p2/src/structures/ring-queue.zig index 53063f9..4410017 100644 --- a/lib/p2/src/structures/ring-queue.zig +++ b/lib/p2/src/structures/ring-queue.zig @@ -27,8 +27,8 @@ pub fn RingQueue(comptime T: type) type { pub fn pushLocked(self: *@This(), newValue: T) RingQueueError!void { self.mutex.lock(); - try self.queue.push(newValue); defer self.mutex.unlock(); + try self.queue.push(newValue); } // only call this if you have locked already diff --git a/lib/packer/src/packerfs.zig b/lib/packer/src/packerfs.zig index 5758b28..0117e1e 100644 --- a/lib/packer/src/packerfs.zig +++ b/lib/packer/src/packerfs.zig @@ -293,7 +293,7 @@ pub const PackerFS = struct { self.lock.lock(); defer self.lock.unlock(); - std.debug.print("loading file: {s}", .{path}); + // std.debug.print("loading file: {s}", .{path}); var pathName = Name.Make(path); if (self.fileHandlesByName.get(pathName.handle())) |fileNameHandle| { // std.debug.print("{s} maps to index {d}\n", .{ path, fileNameHandle }); @@ -308,7 +308,7 @@ pub const PackerFS = struct { for (self.contentPaths.items) |contentPath| { if (try self.loadFileDirect(contentPath, path)) |mapping| { - std.debug.print("loading directly: {s}, {s}", .{ contentPath, path }); + // std.debug.print("loading directly: {s}, {s}", .{ contentPath, path }); return mapping; } } diff --git a/projects/content/_shaders/dxil/text.frag.dxil b/projects/content/_shaders/dxil/text.frag.dxil index a6bc6ed..20db0d8 100644 Binary files a/projects/content/_shaders/dxil/text.frag.dxil and b/projects/content/_shaders/dxil/text.frag.dxil differ diff --git a/projects/content/_shaders/msl/text.frag.msl b/projects/content/_shaders/msl/text.frag.msl index 6fdccbf..68cc8e9 100644 --- a/projects/content/_shaders/msl/text.frag.msl +++ b/projects/content/_shaders/msl/text.frag.msl @@ -16,8 +16,6 @@ struct type_StructuredBuffer_FontInfo FontInfo _m0[1]; }; -constant float _59 = {}; - struct main0_out { float4 out_var_SV_Target0 [[color(0)]]; @@ -80,24 +78,25 @@ fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredB float _110 = float(in.in_var_TEXCOORD0 & 255u) * 0.0039215688593685626983642578125; float _114 = float((in.in_var_TEXCOORD0 >> 8u) & 255u) * 0.0039215688593685626983642578125; float _118 = float((in.in_var_TEXCOORD0 >> 16u) & 255u) * 0.0039215688593685626983642578125; - float4 _181; + float _122 = float((in.in_var_TEXCOORD0 >> 24u) & 255u) * 0.0039215688593685626983642578125; + float4 _187; if (fontBuffer._m0[in.in_var_TEXCOORD3].isSdf == 1u) { - float _124 = _67.x; - float _125 = fwidth(_124); - float _126 = 0.529411792755126953125 - _125; - float _127 = 0.529411792755126953125 + _125; - float2 _133 = (dfdx(in.in_var_TEXCOORD1) + dfdy(in.in_var_TEXCOORD1)) * 0.3540000021457672119140625; - float4 _140 = float4(in.in_var_TEXCOORD1 - _133, in.in_var_TEXCOORD1 + _133); - float4 _171 = float4(_110, _114, _118, (fast::clamp(smoothstep(_126, _127, _124), 0.0, 1.0) + (0.5 * (((fast::clamp(smoothstep(_126, _127, Texture0.sample(Sampler0, _140.xy).x), 0.0, 1.0) + fast::clamp(smoothstep(_126, _127, Texture0.sample(Sampler0, _140.zw).x), 0.0, 1.0)) + fast::clamp(smoothstep(_126, _127, Texture0.sample(Sampler0, _140.xw).x), 0.0, 1.0)) + fast::clamp(smoothstep(_126, _127, Texture0.sample(Sampler0, _140.zy).x), 0.0, 1.0)))) * 0.3333333432674407958984375); - float3 _173 = powr(_171.xyz, float3(2.2000000476837158203125)); - _181 = float4(_173.x, _173.y, _173.z, _171.w); + float _128 = _67.x; + float _129 = fwidth(_128); + float _130 = 0.529411792755126953125 - _129; + float _131 = 0.529411792755126953125 + _129; + float2 _137 = (dfdx(in.in_var_TEXCOORD1) + dfdy(in.in_var_TEXCOORD1)) * 0.3540000021457672119140625; + float4 _144 = float4(in.in_var_TEXCOORD1 - _137, in.in_var_TEXCOORD1 + _137); + float4 _176 = float4(_110, _114, _118, ((fast::clamp(smoothstep(_130, _131, _128), 0.0, 1.0) + (0.5 * (((fast::clamp(smoothstep(_130, _131, Texture0.sample(Sampler0, _144.xy).x), 0.0, 1.0) + fast::clamp(smoothstep(_130, _131, Texture0.sample(Sampler0, _144.zw).x), 0.0, 1.0)) + fast::clamp(smoothstep(_130, _131, Texture0.sample(Sampler0, _144.xw).x), 0.0, 1.0)) + fast::clamp(smoothstep(_130, _131, Texture0.sample(Sampler0, _144.zy).x), 0.0, 1.0)))) * 0.3333333432674407958984375) * _122); + float3 _178 = powr(_176.xyz, float3(2.2000000476837158203125)); + _187 = float4(_178.x, _178.y, _178.z, _176.w); } else { - _181 = float4(_110, _114, _118, powr(_67.x / dot(float4(_110, _114, _118, _59).xyz, float3(0.2125999927520751953125, 0.715200006961822509765625, 0.072200000286102294921875)), 0.4545454680919647216796875)); + _187 = float4(_110, _114, _118, powr(_67.x / dot(float4(_110, _114, _118, _122).xyz, float3(0.2125999927520751953125, 0.715200006961822509765625, 0.072200000286102294921875)), 0.4545454680919647216796875) * _122); } - out.out_var_SV_Target0 = _181; + out.out_var_SV_Target0 = _187; return out; } diff --git a/projects/content/_shaders/spv/text.frag.spv b/projects/content/_shaders/spv/text.frag.spv index 302c6ca..d6e6ee2 100644 Binary files a/projects/content/_shaders/spv/text.frag.spv and b/projects/content/_shaders/spv/text.frag.spv differ diff --git a/projects/sampleGame/externGame/externGame.zig b/projects/sampleGame/externGame/externGame.zig index 325d3c9..86e1fcc 100644 --- a/projects/sampleGame/externGame/externGame.zig +++ b/projects/sampleGame/externGame/externGame.zig @@ -26,10 +26,13 @@ pub export fn subtract(a: i32, b: i32) i32 { var gAllocator: std.mem.Allocator = undefined; pub fn start_module(args: core.ModuleLoaderArgs) !void { + core.PatchOrCreateObject(extras.GameList, .{}); core.PatchOrCreateObject(extras.ModuleLoader, .{}); core.PatchOrCreateObject(extras.ObjectSystemSpawner, .{}); + core.PatchOrCreateObject(net.EnetTransport, .{}); core.PatchOrCreateObject(ExternGameObject, .{}); core.PatchOrCreateObject(imgui.utils.ConsoleWindow, .{}); + core.PatchOrCreateObject(@import("fpgame/fpgame.zig"), .{}); _ = args; core.logDisplay("externGame", "accessing old object at {x} same object? {d}", .{ @intFromPtr(core.EngineObject(ExternGameObject).get()), @sizeOf(ExternGameObject) }); @@ -83,6 +86,12 @@ pub const BoxObject = struct { } }; +pub const ExternGameArgs = struct { + clientTarget: []const u8 = "127.0.0.1", + clientIndex: u32 = 0, + asClient: bool = false, +}; + pub const ExternGameObject = struct { pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "game.ExternGameObject"); pub const Slack = core.SlackStruct(@This(), 1024); @@ -95,10 +104,13 @@ pub const ExternGameObject = struct { session: ?*net.Session = null, clientLink: ?*net.Link = null, + launchAsClient: ?[]const u8 = null, recompiling: bool = false, firstTick: bool = true, + fpcamera: *extras.FpCamera = undefined, + fireInput: ?*core.ActionBinding = null, altFireInput: ?*core.ActionBinding = null, reloadInput: ?*core.ActionBinding = null, @@ -116,10 +128,16 @@ pub const ExternGameObject = struct { spawnedEntities: std.ArrayListUnmanaged(core.Entity) = .{}, + clientIndex: u32 = 0, + autoAddClients: bool = true, + clientsToAdd: u32 = 1, + displayVectorsTest: bool = false, pub fn beginPlay(p: *anyopaque) void { const self = core.cast(*@This(), p); + ui.context().screenContext.drawDebug = true; + self._beginPlay() catch { core.engine_errs("unable to beginplay"); }; @@ -232,6 +250,24 @@ pub const ExternGameObject = struct { self.physicsObjectsWindow = try extras.PhysicsObjectList.create(self.allocator); + const args = try core.ParseArgs(ExternGameArgs); + + if (args.asClient) { + self.launchAsClient = args.clientTarget; + self.clientIndex = args.clientIndex; + core.engine_log("starting up as client connecting to {s}", .{args.clientTarget}); + platform.context().pushRequest(.{ .setWindowSize = .{ .size = .{ .x = 1000, .y = 562 } } }); + platform.context().pushRequest(.{ .setWindowPosition = .{ .pos = .{ .x = 1000 * args.clientIndex, .y = 30 } } }); + + const ctx = ui.getScreen(); + const text = try ctx.addText(.{}, "client"); + ctx.get(text).pos = .{ .x = 0, .y = 10 }; + ctx.get(text).size = .{ .x = 400, .y = 300 }; + + ui.context().screenContext.debugFontSize = 20; + self.connectClient(); + } + try core.registerObject(BoxObject, "Box"); try core.registerObjectAdvanced(BoxObject, "BoxSmoky", "createSmoky"); @@ -263,8 +299,7 @@ pub const ExternGameObject = struct { } } - try extras.games.addGame("ExternGame", self, @This()); - + try extras.addGame("ExternGame", self, @This()); extras.beginGame("ExternGame"); return self; @@ -391,6 +426,7 @@ pub const ExternGameObject = struct { if (platform.context().isCursorEnabled()) { core.engine_logs("moving light"); + core.debugTextLog("moving light", 3.5, .{ .color = core.colors.Color.Green }); const ray = rend.context().activeCamera.?.getNormalRayFromScreen(platform.getCursorPosition()); if (physics.traceLine(ray.start, ray.dir.fmul(10000), .{ .bodyFilter = &self.fireTraceFilter, .getNormalsSlow = true })) |r| { if (r.normal) |n| { @@ -469,6 +505,22 @@ pub const ExternGameObject = struct { ig.textf("lmao", .{}); + if (ig.smallButton("800x450")) { + platform.context().pushRequest(.{ .setWindowSize = .{ .size = .{ .x = 800, .y = 450 } } }); + } + + if (ig.smallButton("1600x900")) { + platform.context().pushRequest(.{ .setWindowSize = .{ .size = .{ .x = 1600, .y = 900 } } }); + } + + if (ig.smallButton("maximize")) { + platform.context().pushRequest(.{ .maximizeWindow = .{} }); + } + + if (ig.smallButton("setMousePos")) { + platform.context().pushRequest(.{ .setMousePosition = .{ .pos = .{ .x = 800, .y = 450 } } }); + } + if (ig.smallButton("reload map")) { self.loadMap2() catch unreachable; } @@ -496,17 +548,61 @@ pub const ExternGameObject = struct { audio.context().setVolume(self.volume / 100); } + _ = ig.checkbox("addClients", &self.autoAddClients); + ig.sameLine(0, 10); + if (self.autoAddClients) { + _ = ig.inputInt("clientCount", @ptrCast(&self.clientsToAdd), 1, 1, .{}); + } + if (ig.smallButton("host")) { - self.session = net.hostSession(&.{"7777"}) catch unreachable; + self.session = blk: { + const s = net.hostSession(&.{"7777"}) catch { + core.engine_err("host server failed", .{}); + break :blk null; + }; + + break :blk s; + }; + + if (self.session) |session| { + _ = session; + + var fmt: [256]u8 = undefined; + var fmt2: [256]u8 = undefined; + for (0..self.clientsToAdd) |i| { + const ci = std.fmt.bufPrint(&fmt, "--clientIndex={d}", .{i}) catch { + core.engine_err("unable to create client {d} out of memory?", .{i}); + break; + }; + + const igIni = std.fmt.bufPrint(&fmt2, "--imguiIni=client{d}.ini", .{i}) catch { + core.engine_err("unable to create client {d} out of memory?", .{i}); + break; + }; + + _ = sys.SubprocessTask.runCommand( + self.allocator, + &.{ "zig-out/bin/sampleGame.exe", "--asClient=True", ci, igIni }, + ".", + ) catch { + core.engine_err("unable to create client {d}", .{i}); + break; + }; + } + } } if (ig.smallButton("connect")) { - self.clientLink = net.connect("127.0.0.1:7777") catch unreachable; + self.connectClient(); } if (self.clientLink) |link| { if (ig.smallButton("sendMessageToServer")) { link.sendMessage("hello from client", true) catch {}; + link.sendMessage("hello from client (unreliable)", false) catch {}; + const linkData = net.EnetTransport.getLinkData(link); + linkData.sendPacketChannelDebug("debug: unreliable over channel 0", false, 0); + linkData.sendPacketChannelDebug("debug: reliable over channel 1", true, 1); } } } @@ -524,8 +620,16 @@ pub const ExternGameObject = struct { self.particleDebugger.particleDebug(); } if (self.session) |session| { - if (session.links.items.len > 0) { - const linkData = net.EnetTransport.getLinkData(session.links.items[0]); + if (ig.begin("host session", null, .{})) { + for (session.links.items) |link| { + const linkData = net.EnetTransport.getLinkData(link); + ig.textf("{s} {d}ms", .{ link.idString, linkData.peer.*.roundTripTime }); + } + } + ig.end(); + + for (session.links.items) |link| { + const linkData = net.EnetTransport.getLinkData(link); if (rend.context().activeCamera) |camera| { linkData.testLinkPosition = camera.entity.fetch(core.Scene).?.getPosition(); } @@ -540,6 +644,21 @@ pub const ExternGameObject = struct { } } + fn connectClient(self: *@This()) void { + self.clientLink = net.connect("127.0.0.1:7777") catch unreachable; + + var fmt: [256]u8 = undefined; + if (self.clientLink) |link| { + const nameMsg = std.fmt.bufPrint(&fmt, "cname:client{d}", .{self.clientIndex}) catch { + core.engine_err("unable to create client message, out of memory?", .{}); + return; + }; + link.sendMessage(nameMsg, true) catch { + core.engine_err("unable to send message?", .{}); + }; + } + } + pub fn destroy(self: *@This()) void { if (self.clientLink) |link| { link.destroy(); diff --git a/projects/sampleGame/main.zig b/projects/sampleGame/main.zig index da43abe..661ee19 100644 --- a/projects/sampleGame/main.zig +++ b/projects/sampleGame/main.zig @@ -251,8 +251,6 @@ pub fn prepare(self: *@This()) !void { defer z.End(); try core.fs().addContentPath("sampleGame"); - try extras.setup(); - try audio.loadBuiltinSounds(); // try core.loadModule("externGame", true); @@ -269,17 +267,21 @@ pub fn prepare(self: *@This()) !void { try rendererDebug.skyboxes.append(rendererDebug.allocator, core.MakeName("t_dark_skybox")); try core.getEngineObject(core.GameObjectSystem).?.registerObject("foxObject", FoxObject); + core.PatchOrCreateObject(extras.games.GameList, .{}); try assets.loadList(assetReferences); // self.videoplayer = try VideoPlayer.create(self.allocator); // try self.videoplayer.startPlayback("LAPWING2.ogv"); // self.videoplayerObject = try self.videoplayer.createVideoPlayerEntity(); + try extras.addGame("Default", self, @This()); + extras.beginGame("Default"); + rend.setSkyboxTexture("t_skybox"); - beginPlay(@ptrCast(self)); + // beginPlay(@ptrCast(self)); } -fn beginPlay(p: ?*anyopaque) void { +pub fn beginPlay(p: ?*anyopaque) void { const self = core.cast(*@This(), p.?); self._beginPlay() catch { core.engine_errs("unable to beginPlay sampleagme"); @@ -363,7 +365,7 @@ fn _beginPlay(self: *@This()) !void { self.updateMouseLook(); } -pub fn game_endPlay(p: ?*anyopaque) void { +pub fn endPlay(p: ?*anyopaque) void { const self = core.cast(*@This(), p.?); _ = self; } diff --git a/projects/tools/newProjectMaker.zig b/projects/tools/newProjectMaker.zig index cbeddc2..6f2900c 100644 --- a/projects/tools/newProjectMaker.zig +++ b/projects/tools/newProjectMaker.zig @@ -62,7 +62,7 @@ pub fn tick(self: *@This(), dt: f64) void { if (self.activeCommand) |cmd| { ig.textf("current command: ", .{}); - for (cmd.args) |arg| { + for (cmd.argsOwned.items) |arg| { ig.textf("{s}", .{arg}); ig.sameLine(0, 4); } diff --git a/projects/tools/toolbox.zig b/projects/tools/toolbox.zig index 0ced155..654a363 100644 --- a/projects/tools/toolbox.zig +++ b/projects/tools/toolbox.zig @@ -93,7 +93,7 @@ pub fn tick(self: *@This(), dt: f64) void { if (self.activeCommand) |cmd| { ig.textf("current command: ", .{}); - for (cmd.args) |arg| { + for (cmd.argsOwned.items) |arg| { ig.textf("{s}", .{arg}); ig.sameLine(0, 4); }