diff --git a/assets/cubyz/shaders/graphics/graph.vs b/assets/cubyz/shaders/graphics/graph.vs index 847228790..1a9d27cb3 100644 --- a/assets/cubyz/shaders/graphics/graph.vs +++ b/assets/cubyz/shaders/graphics/graph.vs @@ -7,7 +7,7 @@ uniform vec2 screen; uniform int points; uniform int offset; -layout(std430, binding = 4) buffer _data +layout(std430, binding = 5) buffer _data { float data[]; }; diff --git a/src/graphics.zig b/src/graphics.zig index 9ddd00c1f..ce60628ee 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -380,6 +380,12 @@ pub const draw = struct { pub fn text(_text: []const u8, x: f32, y: f32, fontSize: f32, alignment: TextBuffer.Alignment) !void { try TextRendering.renderText(_text, x, y, fontSize, .{.color = @truncate(u24, @bitCast(u32, color))}, alignment); } + + pub fn print(comptime format: []const u8, args: anytype, x: f32, y: f32, fontSize: f32, alignment: TextBuffer.Alignment) !void { + const string = try std.fmt.allocPrint(main.threadAllocator, format, args); + defer main.threadAllocator.free(string); + try text(string, x, y ,fontSize, alignment); + } }; pub const TextBuffer = struct { diff --git a/src/gui/gui.zig b/src/gui/gui.zig index 21026d7f8..9f84d9763 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -241,6 +241,26 @@ pub fn openWindow(id: []const u8) Allocator.Error!void { std.log.warn("Could not find window with id {s}.", .{id}); } +pub fn toggleWindow(id: []const u8) Allocator.Error!void { + defer updateWindowPositions(); + for(windowList.items) |window| { + if(std.mem.eql(u8, window.id, id)) { + for(openWindows.items, 0..) |_openWindow, i| { + if(_openWindow == window) { + _ = openWindows.swapRemove(i); + selectedWindow = null; + return; + } + } + try openWindows.append(window); + try window.onOpenFn(); + selectedWindow = null; + return; + } + } + std.log.warn("Could not find window with id {s}.", .{id}); +} + pub fn openHud() Allocator.Error!void { for(windowList.items) |window| { if(window.isHud) { diff --git a/src/gui/windows/_windowlist.zig b/src/gui/windows/_windowlist.zig index 2ef39a705..3d45cd0e4 100644 --- a/src/gui/windows/_windowlist.zig +++ b/src/gui/windows/_windowlist.zig @@ -4,6 +4,7 @@ pub const chat = @import("chat.zig"); pub const controls = @import("controls.zig"); pub const creative = @import("creative.zig"); pub const crosshair = @import("crosshair.zig"); +pub const debug = @import("debug.zig"); pub const graphics = @import("graphics.zig"); pub const healthbar = @import("healthbar.zig"); pub const hotbar = @import("hotbar.zig"); @@ -11,6 +12,7 @@ pub const inventory = @import("inventory.zig"); pub const inventory_crafting = @import("inventory_crafting.zig"); pub const main = @import("main.zig"); pub const multiplayer = @import("multiplayer.zig"); +pub const performance_graph = @import("performance_graph.zig"); pub const settings = @import("settings.zig"); pub const sound = @import("sound.zig"); pub const workbench = @import("workbench.zig"); \ No newline at end of file diff --git a/src/gui/windows/debug.zig b/src/gui/windows/debug.zig new file mode 100644 index 000000000..1093a6437 --- /dev/null +++ b/src/gui/windows/debug.zig @@ -0,0 +1,51 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; + +const main = @import("root"); +const graphics = main.graphics; +const draw = graphics.draw; +const Texture = graphics.Texture; +const Vec2f = main.vec.Vec2f; + +const gui = @import("../gui.zig"); +const GuiWindow = gui.GuiWindow; +const GuiComponent = gui.GuiComponent; + +pub var window = GuiWindow { + .contentSize = Vec2f{128, 16}, + .title = "Debug", + .id = "cubyz:debug", + .isHud = false, + .showTitleBar = false, + .hasBackground = false, +}; + +fn flawedRender() !void { + draw.setColor(0xffffffff); + var y: f32 = 0; + try draw.print(" fps: {d:.0} Hz{s}", .{1.0/main.lastFrameTime.load(.Monotonic), if(main.settings.vsync) @as([]const u8, " (vsync)") else ""}, 0, y, 8, .left); + y += 8; + try draw.print(" frameTime: {d:.1} ms", .{main.lastFrameTime.load(.Monotonic)*1000.0}, 0, y, 8, .left); + y += 8; + try draw.print("window size: {}×{}", .{main.Window.width, main.Window.height}, 0, y, 8, .left); + y += 8; + if (main.game.world != null) { + try draw.print("Pos: {d:.1}", .{main.game.Player.getPosBlocking()}, 0, y, 8, .left); + y += 8; + try draw.print("Game Time: {}", .{main.game.world.?.gameTime.load(.Monotonic)}, 0, y, 8, .left); + y += 8; + try draw.print("Queue size: {}", .{main.threadPool.loadList.size}, 0, y, 8, .left); + y += 8; + // TODO: biome + y += 8; + // TODO: packet loss + y += 8; + // TODO: Protocl statistics(maybe?) + } +} + +pub fn render() Allocator.Error!void { + flawedRender() catch |err| { + std.log.err("Encountered error while drawing debug window: {s}", .{@errorName(err)}); + }; +} \ No newline at end of file diff --git a/src/gui/windows/performance_graph.zig b/src/gui/windows/performance_graph.zig new file mode 100644 index 000000000..cb982931e --- /dev/null +++ b/src/gui/windows/performance_graph.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; + +const main = @import("root"); +const graphics = main.graphics; +const draw = graphics.draw; +const Texture = graphics.Texture; +const Vec2f = main.vec.Vec2f; + +const gui = @import("../gui.zig"); +const GuiWindow = gui.GuiWindow; +const GuiComponent = gui.GuiComponent; + +pub var window = GuiWindow { + .contentSize = Vec2f{128, 64}, + .title = "Performance Graph", + .id = "cubyz:performance_graph", + .isHud = false, + .showTitleBar = false, + .hasBackground = false, +}; + +var lastFrameTime: [2048]f32 = undefined; +var index: u31 = 0; +var ssbo: graphics.SSBO = undefined; +var shader: graphics.Shader = undefined; +const border: f32 = 8; + +var uniforms: struct { + start: c_int, + dimension: c_int, + screen: c_int, + points: c_int, + offset: c_int, + lineColor: c_int, +} = undefined; + +pub fn init() !void { + ssbo = graphics.SSBO.init(); + shader = try graphics.Shader.initAndGetUniforms("assets/cubyz/shaders/graphics/graph.vs", "assets/cubyz/shaders/graphics/graph.fs", &uniforms); +} + +pub fn deinit() void { + ssbo.deinit(); +} + +fn flawedRender() !void { + lastFrameTime[index] = @floatCast(f32, main.lastFrameTime.load(.Monotonic)*1000.0); + index = (index + 1)%@intCast(u31, lastFrameTime.len); + draw.setColor(0xffffffff); + try draw.text("32 ms", 0, 16, 8, .left); + try draw.text("16 ms", 0, 32, 8, .left); + try draw.text("00 ms", 0, 48, 8, .left); + draw.setColor(0x80ffffff); + draw.line(.{border, 24}, .{window.contentSize[0] - border, 24}); + draw.line(.{border, 40}, .{window.contentSize[0] - border, 40}); + draw.line(.{border, 56}, .{window.contentSize[0] - border, 56}); + draw.setColor(0xffffffff); + shader.bind(); + graphics.c.glUniform1i(uniforms.points, lastFrameTime.len); + graphics.c.glUniform1i(uniforms.offset, index); + graphics.c.glUniform3f(uniforms.lineColor, 1, 1, 1); + var pos = Vec2f{border, border}; + var dim = window.contentSize - @splat(2, 2*border); + pos *= @splat(2, draw.setScale(1)); + pos += draw.setTranslation(.{0, 0}); + dim *= @splat(2, draw.setScale(1)); + pos = @floor(pos); + dim = @ceil(dim); + pos[1] += dim[1]; + + graphics.c.glUniform2f(uniforms.screen, @intToFloat(f32, main.Window.width), @intToFloat(f32, main.Window.height)); + graphics.c.glUniform2f(uniforms.start, pos[0], pos[1]); + graphics.c.glUniform2f(uniforms.dimension, dim[0], draw.setScale(1)); + ssbo.bufferData(f32, &lastFrameTime); + ssbo.bind(5); + graphics.c.glDrawArrays(graphics.c.GL_LINE_STRIP, 0, lastFrameTime.len); +} + +pub fn render() Allocator.Error!void { + flawedRender() catch |err| { + std.log.err("Encountered error while drawing debug window: {s}", .{@errorName(err)}); + }; +} \ No newline at end of file diff --git a/src/main.zig b/src/main.zig index fe7dfb5da..b928fda06 100644 --- a/src/main.zig +++ b/src/main.zig @@ -188,6 +188,16 @@ fn takeBackgroundImageFn() void { std.log.err("Got error while recording the background image: {s}", .{@errorName(err)}); }; } +fn toggleDebugOverlay() void { + gui.toggleWindow("cubyz:debug") catch |err| { + std.log.err("Got error while opening the debug overlay: {s}", .{@errorName(err)}); + }; +} +fn togglePerformanceOverlay() void { + gui.toggleWindow("cubyz:performance_graph") catch |err| { + std.log.err("Got error while opening the performance_graph overlay: {s}", .{@errorName(err)}); + }; +} pub var keyboard: struct { // Gameplay: forward: Key = Key{.key = c.GLFW_KEY_W}, @@ -221,6 +231,10 @@ pub var keyboard: struct { textPaste: Key = Key{.key = c.GLFW_KEY_V, .repeatAction = &gui.textCallbacks.paste}, textCut: Key = Key{.key = c.GLFW_KEY_X, .repeatAction = &gui.textCallbacks.cut}, textNewline: Key = Key{.key = c.GLFW_KEY_ENTER, .repeatAction = &gui.textCallbacks.newline}, + + // debug: + debugOverlay: Key = Key{.key = c.GLFW_KEY_F3, .releaseAction = &toggleDebugOverlay}, + performanceOverlay: Key = Key{.key = c.GLFW_KEY_F4, .releaseAction = &togglePerformanceOverlay}, } = .{}; pub const Window = struct { @@ -464,6 +478,8 @@ pub const Window = struct { } }; +pub var lastFrameTime = std.atomic.Atomic(f64).init(0); + pub fn main() !void { seed = @bitCast(u64, std.time.milliTimestamp()); var gpa = std.heap.GeneralPurposeAllocator(.{.thread_safe=false}){}; @@ -539,7 +555,7 @@ pub fn main() !void { c.glEnable(c.GL_BLEND); c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA); Window.GLFWCallbacks.framebufferSize(undefined, Window.width, Window.height); - var lastTime = std.time.milliTimestamp(); + var lastTime = std.time.nanoTimestamp(); while(c.glfwWindowShouldClose(Window.window) == 0) { { // Check opengl errors: @@ -552,8 +568,9 @@ pub fn main() !void { Window.handleEvents(); c.glClearColor(0.5, 1, 1, 1); c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_STENCIL_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT); - var newTime = std.time.milliTimestamp(); - var deltaTime = @intToFloat(f64, newTime -% lastTime)/1000.0; + var newTime = std.time.nanoTimestamp(); + var deltaTime = @intToFloat(f64, newTime -% lastTime)/1e9; + lastFrameTime.store(deltaTime, .Monotonic); lastTime = newTime; if(game.world != null) { // Update the game try game.update(deltaTime);