From 73c048205e900f5e76910c4932abece0f38c38ee Mon Sep 17 00:00:00 2001 From: bfeld Date: Wed, 15 Nov 2023 20:19:26 +0100 Subject: [PATCH] Clean up hot shader reload thread on exit --- src/gfx_hsr.zig | 9 +- src/gfx_impl.zig | 111 ---------- src/gfx_rw.zig | 5 - src/graphics.zig | 543 ----------------------------------------------- src/input.zig | 34 +-- src/main.zig | 83 ++++---- src/rw_gui.zig | 176 --------------- src/sim.zig | 390 ---------------------------------- 8 files changed, 71 insertions(+), 1280 deletions(-) delete mode 100644 src/gfx_impl.zig delete mode 100644 src/graphics.zig delete mode 100644 src/rw_gui.zig delete mode 100644 src/sim.zig diff --git a/src/gfx_hsr.zig b/src/gfx_hsr.zig index 3db4d1e..cbfc7f1 100644 --- a/src/gfx_hsr.zig +++ b/src/gfx_hsr.zig @@ -27,18 +27,24 @@ pub fn init() void { } +pub fn rmWatch() void { + const r = lnx.inotify_rm_watch(fd, wd); + _ = r; +} + pub fn readEvent() void { log_gfx_hsr.debug("Watching directory for hot shader reload", .{}); const event_size = (@sizeOf(lnx.inotify_event) + std.os.PATH_MAX) * 10; var buf: [event_size]u8 = undefined; - while (true) { + while (is_running) { const len = lnx.read(fd, &buf, event_size); _ = len; log_gfx_hsr.debug("Shader file(s) modified", .{}); is_reload_triggered.value = true; } + log_gfx_hsr.debug("Stopping file watch", .{}); } //-----------------------------------------------------------------------------// @@ -48,6 +54,7 @@ pub fn readEvent() void { const log_gfx_hsr = std.log.scoped(.gfx_hsr); pub var is_reload_triggered = std.atomic.Atomic(bool).init(false); +pub var is_running: bool = true; var fd: i32 = 0; var wd: i32 = 0; diff --git a/src/gfx_impl.zig b/src/gfx_impl.zig deleted file mode 100644 index 53e9166..0000000 --- a/src/gfx_impl.zig +++ /dev/null @@ -1,111 +0,0 @@ -// This helper consists of a few specialised calls to a graphics -// API that has to be implemented by the user. - -/// This is the graphics backend -const gfx = @import("graphics.zig"); - -/// Add a quad to a batch of quads. Handling of batches is -/// implementation specific, might also internally draw -/// immediately. However, this function is typically called -/// where a lot of quads are drawn, so draw calls might be -/// relevant. -pub inline fn addBatchQuad(x0: f32, y0: f32, x1: f32, y1: f32) void { - gfx.addQuad(x0, y0, x1, y1); -} - -/// Add a quad to a batch of textured quads. Handling of batches -/// is implementation specific, might also internally draw -/// immediately. However, this function is typically called -/// where a lot of quads are drawn, so draw calls might be -/// relevant. -pub inline fn addBatchQuadTextured(x0: f32, y0: f32, x1: f32, y1: f32, - u_0: f32, v0: f32, u_1: f32, v1: f32) void { - gfx.addQuadTextured(x0, y0, x1, y1, u_0, v0, u_1, v1); -} - -/// Immediately draw a line. Internal handling is implementation -/// specific and may also happen within a batch, though this is -/// typically called for a few single line -pub inline fn addImmediateLine(x0: f32, y0: f32, x1: f32, y1: f32) void { - gfx.drawLine(x0, y0, x1, y1); -} - -/// Immediately draw a quad. Internal handling is implementation -/// specific and may also happen within a batch, though this is -/// typically called for a few single quads -pub inline fn addImmediateQuad(x0: f32, y0: f32, x1: f32, y1: f32) void { - gfx.drawQuad(x0, y0, x1, y1); -} - -/// Immediately draw a textured quad. Internal handling is implementation -/// specific and may also happen within a batch, though this is -/// typically called for a few single quads -pub inline fn addImmediateQuadTextured(x0: f32, y0: f32, x1: f32, y1: f32, - u_0: f32, v0: f32, u_1: f32, v1: f32) void { - gfx.drawQuadTextured(x0, y0, x1, y1, u_0, v0, u_1, v1); -} - -/// Begin with a batch of quads. This function might be relevant for -/// e.g. immediate mode of OpenGL, but may as well be left empty if -/// batches are implemented differently, using core profile, VBOs -/// or other methods -pub inline fn beginBatchQuads() void { - gfx.startBatchQuads(); -} - -/// Begin with a batch of textured quads. This function might be relevant -/// for e.g. immediate mode of OpenGL, but may as well be left empty if -/// batches are implemented differently, using core profile, VBOs -/// or other methods -pub inline fn beginBatchQuadsTextured() void { - gfx.startBatchQuadsTextured(); -} - -pub inline fn bindTexture(tex_id: u32) void { - gfx.bindTexture(tex_id); -} - -/// End a batch call, see beginBatch-functions for a more detailed explanation -pub inline fn endBatch() void { - gfx.endBatch(); -} - -/// Upload data in the data array as a texture with the given ID. Here, -/// the data is only one channel and to be interpreted as alpha. It is -/// mostly used for font rendering, where the background is interpreted -/// as alpha=0 -pub inline fn createTextureAlpha(w: u32, h: u32, data: []u8, tex_id: u32) void { - gfx.createTexture1C(w, h, data, tex_id); -} - -/// Generate a new texture ID to upload data to -pub inline fn getNewTextureId() u32 { - return gfx.getTextureId(); -} - -/// Height of the window with the graphical context -pub inline fn getWindowHeight() u64 { - return gfx.getWindowHeight(); -} - -/// Width of the window with the graphical context -pub inline fn getWindowWidth() u64 { - return gfx.getWindowWidth(); -} - -/// Release a texture with the given ID -pub inline fn releaseTexture(tex_id: u32) void { - gfx.releaseTexture(tex_id); -} - -/// Set the color (RGBA) for upcoming operations. If using VBAs/VBOs -/// for example, a helper functions and data might be implemented -/// to fill arrays -pub inline fn setColor(r: f32, g: f32, b: f32, a: f32) void { - gfx.setColor4(r, g, b, a); -} - -/// Set the width of lines drawn by the graphics engine -pub inline fn setLineWidth(w: f32) void { - gfx.setLineWidth(w); -} diff --git a/src/gfx_rw.zig b/src/gfx_rw.zig index d296e30..9d1d959 100644 --- a/src/gfx_rw.zig +++ b/src/gfx_rw.zig @@ -41,11 +41,6 @@ pub fn init() !void { } try gfx_core.bindEBOAndBufferData(ebo, buffer_size*6, ebo_buf.items, .Static); ebo_buf.deinit(); - - if (builtin.os.tag == .linux) { - const gfx_hsr= @import("gfx_hsr.zig"); - gfx_hsr.init(); - } } pub fn deinit() void { diff --git a/src/graphics.zig b/src/graphics.zig deleted file mode 100644 index a5d59fb..0000000 --- a/src/graphics.zig +++ /dev/null @@ -1,543 +0,0 @@ -const std = @import("std"); -const c = @import("c.zig").c; -const cfg = @import("config.zig"); -const gfx_core = @import("gfx_core.zig"); -const stats = @import("stats.zig"); - -//-----------------------------------------------------------------------------// -// Error Sets -//-----------------------------------------------------------------------------// - -//-----------------------------------------------------------------------------// -// Init / DeInit -//-----------------------------------------------------------------------------// - -/// Initialise glfw, create a window and setup opengl -pub fn init() !void { - - - vbo = try gfx_core.createVBO(); - vao = try gfx_core.createVAO(); - try initShaders(); - try allocMemory(); - - // var value_quads = quads.getPtr(1); - // if (value_quads) |val| { - // for (&val.i_verts) |*v| { - // v.* = 0; - // } - // for (&val.i_cols) |*v| { - // v.* = 0; - // } - // for (&val.n) |*v| { - // v.* = 0; - // } - // } -} - -pub fn deinit() void { - draw_call_statistics.printStats(); - quad_statistics.printStats(); - quad_tex_statistics.printStats(); - - - freeMemory(); - - const leaked = gpa.deinit(); - if (leaked == .leak) log_gfx.err("Memory leaked in GeneralPurposeAllocator", .{}); -} - -pub fn initShaders() !void { - log_gfx.info("Preparing shaders", .{}); - - shader_program = try gfx_core.createShaderProgramFromFiles( - "/home/bfeld/projects/rayworld-ng/resource/shader/base.vert", - "/home/bfeld/projects/rayworld-ng/resource/shader/base.frag"); -} - -//-----------------------------------------------------------------------------// -// Getter/Setter -//-----------------------------------------------------------------------------// - -//-----------------------------------------------------------------------------// -// Processing -//-----------------------------------------------------------------------------// - - -pub fn startBatchLine() void { - gfx_core.disableTexturing()(); - // c.glBegin(c.GL_LINES); -} - -pub fn startBatchLineTextured() void { - gfx_core.enableTexturing(); - // c.glBegin(c.GL_LINES); -} - -pub fn startBatchQuads() void { - gfx_core.disableTexturing(); - // c.glBegin(c.GL_QUADS); -} - -pub fn startBatchQuadsTextured() void { - gfx_core.disableTexturing()(); - // c.glBegin(c.GL_QUADS); -} - -pub fn drawCircle(x: f32, y: f32, r: f32) void { - _ = r; - _ = y; - _ = x; - const nr_of_segments = 100.0; - - gfx_core.disableTexturing(); - // c.glBegin(c.GL_LINE_LOOP); - var angle: f32 = 0.0; - const inc = 2.0 * std.math.pi / nr_of_segments; - while (angle < 2.0 * std.math.pi) : (angle += inc) { - // c.glVertex2f(r * @cos(angle) + x, r * @sin(angle) + y); - } - // c.glEnd(); -} - -pub fn drawLine(x0: f32, y0: f32, x1: f32, y1: f32) void { - _ = y1; - _ = x1; - _ = y0; - _ = x0; - gfx_core.disableTexturing(); - // c.glBegin(c.GL_LINES); - // c.glVertex2f(x0, y0); - // c.glVertex2f(x1, y1); - // c.glEnd(); -} - -pub fn drawQuad(x0: f32, y0: f32, x1: f32, y1: f32) void { - _ = y1; - _ = x1; - _ = y0; - _ = x0; - // disableTexturing(); - // c.glBegin(c.GL_QUADS); - // c.glVertex2f(x0, y0); - // c.glVertex2f(x1, y0); - // c.glVertex2f(x1, y1); - // c.glVertex2f(x0, y1); - // c.glEnd(); -} - -pub fn drawQuadTextured(x0: f32, y0: f32, x1: f32, y1: f32, - u_0: f32, v0: f32, u_1: f32, v1: f32) void { - _ = v1; - _ = u_1; - _ = v0; - _ = u_0; - _ = y1; - _ = x1; - _ = y0; - _ = x0; - gfx_core.enableTexturing(); - // c.glBegin(c.GL_QUADS); - // c.glTexCoord2f(u_0, v0); c.glVertex2f(x0, y0); - // c.glTexCoord2f(u_1, v0); c.glVertex2f(x1, y0); - // c.glTexCoord2f(u_1, v1); c.glVertex2f(x1, y1); - // c.glTexCoord2f(u_0, v1); c.glVertex2f(x0, y1); - // c.glEnd(); -} - -pub fn drawTriangle(x0: f32, y0: f32, x1: f32, y1: f32, x2: f32, y2: f32) void { - _ = y2; - _ = x2; - _ = y1; - _ = x1; - _ = y0; - _ = x0; - gfx_core.disableTexturing(); - // c.glBegin(c.GL_TRIANGLES); - // c.glVertex2f(x0, y0); - // c.glVertex2f(x1, y1); - // c.glVertex2f(x2, y2); - // c.glEnd(); -} - -pub fn addLine(x0: f32, y0: f32, x1: f32, y1: f32) void { - _ = y1; - _ = x1; - _ = y0; - _ = x0; - // c.glVertex3f(x0, y0, 1); - // c.glVertex3f(x1, y1, 1); -} - -pub fn addQuad(x0: f32, y0: f32, x1: f32, y1: f32) void { - _ = y1; - _ = x1; - _ = y0; - _ = x0; - // c.glVertex2f(x0, y0); - // c.glVertex2f(x1, y0); - // c.glVertex2f(x1, y1); - // c.glVertex2f(x0, y1); -} - -pub fn addQuadTextured(x0: f32, y0: f32, x1: f32, y1: f32, - u_0: f32, v0: f32, u_1: f32, v1: f32) void { - _ = v1; - _ = u_1; - _ = v0; - _ = u_0; - _ = y1; - _ = x1; - _ = y0; - _ = x0; - // c.glTexCoord2f(u_0, v0); c.glVertex2f(x0, y0); - // c.glTexCoord2f(u_1, v0); c.glVertex2f(x1, y0); - // c.glTexCoord2f(u_1, v1); c.glVertex2f(x1, y1); - // c.glTexCoord2f(u_0, v1); c.glVertex2f(x0, y1); -} - -pub fn addVerticalQuad(x0: f32, x1: f32, y0: f32, y1: f32, r: f32, g: f32, b: f32, a: f32, d0: u8) void { - var value = quads.getPtr(1); - if (value) |v| { - const d = depth_levels - d0 - 1; - const i_v = v.i_verts[d]; - v.verts[d][i_v] = x0; - v.verts[d][i_v + 1] = y0; - v.verts[d][i_v + 2] = x1; - v.verts[d][i_v + 3] = y0; - v.verts[d][i_v + 4] = x1; - v.verts[d][i_v + 5] = y1; - v.verts[d][i_v + 6] = x0; - v.verts[d][i_v + 7] = y1; - const i_c = v.i_cols[d]; - v.cols[d][i_c] = r; - v.cols[d][i_c + 1] = g; - v.cols[d][i_c + 2] = b; - v.cols[d][i_c + 3] = a; - v.cols[d][i_c + 4] = r; - v.cols[d][i_c + 5] = g; - v.cols[d][i_c + 6] = b; - v.cols[d][i_c + 7] = a; - v.cols[d][i_c + 8] = r; - v.cols[d][i_c + 9] = g; - v.cols[d][i_c + 10] = b; - v.cols[d][i_c + 11] = a; - v.cols[d][i_c + 12] = r; - v.cols[d][i_c + 13] = g; - v.cols[d][i_c + 14] = b; - v.cols[d][i_c + 15] = a; - v.i_verts[d] += 8; - v.i_cols[d] += 16; - v.n[d] += 4; - depth_levels_active.set(d); - quad_statistics.inc(); - } -} - -pub fn addVerticalQuadG2G(x0: f32, x1: f32, y0: f32, y1: f32, c0: f32, c1: f32, a: f32, d0: u8) void { - var value = quads.getPtr(1); - if (value) |v| { - const d = depth_levels - d0 - 1; - const i_v = v.i_verts[d]; - v.verts[d][i_v] = x0; - v.verts[d][i_v + 1] = y0; - v.verts[d][i_v + 2] = x1; - v.verts[d][i_v + 3] = y0; - v.verts[d][i_v + 4] = x1; - v.verts[d][i_v + 5] = y1; - v.verts[d][i_v + 6] = x0; - v.verts[d][i_v + 7] = y1; - const i_c = v.i_cols[d]; - v.cols[d][i_c] = c0; - v.cols[d][i_c + 1] = c0; - v.cols[d][i_c + 2] = c0; - v.cols[d][i_c + 3] = a; - v.cols[d][i_c + 4] = c0; - v.cols[d][i_c + 5] = c0; - v.cols[d][i_c + 6] = c0; - v.cols[d][i_c + 7] = a; - v.cols[d][i_c + 8] = c1; - v.cols[d][i_c + 9] = c1; - v.cols[d][i_c + 10] = c1; - v.cols[d][i_c + 11] = a; - v.cols[d][i_c + 12] = c1; - v.cols[d][i_c + 13] = c1; - v.cols[d][i_c + 14] = c1; - v.cols[d][i_c + 15] = a; - v.i_verts[d] += 8; - v.i_cols[d] += 16; - v.n[d] += 4; - depth_levels_active.set(d); - quad_statistics.inc(); - } -} - -pub fn addVerticalQuadY(x0: f32, x1: f32, y0: f32, y1: f32, y2: f32, y3: f32, r: f32, g: f32, b: f32, a: f32, d0: u8) void { - var value = quads.getPtr(1); - if (value) |v| { - const d = depth_levels - d0 - 1; - const i_v = v.i_verts[d]; - v.verts[d][i_v] = x0; - v.verts[d][i_v + 1] = y0; - v.verts[d][i_v + 2] = x1; - v.verts[d][i_v + 3] = y1; - v.verts[d][i_v + 4] = x1; - v.verts[d][i_v + 5] = y2; - v.verts[d][i_v + 6] = x0; - v.verts[d][i_v + 7] = y3; - const i_c = v.i_cols[d]; - v.cols[d][i_c] = r; - v.cols[d][i_c + 1] = g; - v.cols[d][i_c + 2] = b; - v.cols[d][i_c + 3] = a; - v.cols[d][i_c + 4] = r; - v.cols[d][i_c + 5] = g; - v.cols[d][i_c + 6] = b; - v.cols[d][i_c + 7] = a; - v.cols[d][i_c + 8] = r; - v.cols[d][i_c + 9] = g; - v.cols[d][i_c + 10] = b; - v.cols[d][i_c + 11] = a; - v.cols[d][i_c + 12] = r; - v.cols[d][i_c + 13] = g; - v.cols[d][i_c + 14] = b; - v.cols[d][i_c + 15] = a; - v.i_verts[d] += 8; - v.i_cols[d] += 16; - v.n[d] += 4; - depth_levels_active.set(d); - quad_statistics.inc(); - } -} - -pub fn addVerticalTexturedQuad(x0: f32, x1: f32, y0: f32, y1: f32, u_0: f32, u_1: f32, v0: f32, v1: f32, r: f32, g: f32, b: f32, a: f32, d0: u8, t: u32) void { - var value = quads_textured.getPtr(t); - if (value) |v| { - const d = depth_levels - d0 - 1; - const i_v = v.i_verts[d]; - v.verts[d][i_v] = x0; - v.verts[d][i_v + 1] = y0; - v.verts[d][i_v + 2] = x1; - v.verts[d][i_v + 3] = y0; - v.verts[d][i_v + 4] = x1; - v.verts[d][i_v + 5] = y1; - v.verts[d][i_v + 6] = x0; - v.verts[d][i_v + 7] = y1; - const i_c = v.i_cols[d]; - v.cols[d][i_c] = r; - v.cols[d][i_c + 1] = g; - v.cols[d][i_c + 2] = b; - v.cols[d][i_c + 3] = a; - v.cols[d][i_c + 4] = r; - v.cols[d][i_c + 5] = g; - v.cols[d][i_c + 6] = b; - v.cols[d][i_c + 7] = a; - v.cols[d][i_c + 8] = r; - v.cols[d][i_c + 9] = g; - v.cols[d][i_c + 10] = b; - v.cols[d][i_c + 11] = a; - v.cols[d][i_c + 12] = r; - v.cols[d][i_c + 13] = g; - v.cols[d][i_c + 14] = b; - v.cols[d][i_c + 15] = a; - const i_t = v.i_texcs[d]; - v.texcs[d][i_t] = u_0; - v.texcs[d][i_t + 1] = v0; - v.texcs[d][i_t + 2] = u_1; - v.texcs[d][i_t + 3] = v0; - v.texcs[d][i_t + 4] = u_1; - v.texcs[d][i_t + 5] = v1; - v.texcs[d][i_t + 6] = u_0; - v.texcs[d][i_t + 7] = v1; - v.i_verts[d] += 8; - v.i_cols[d] += 16; - v.i_texcs[d] += 8; - v.n[d] += 4; - depth_levels_active.set(d); - quad_tex_statistics.inc(); - } -} - -pub fn addVerticalTexturedQuadY(x0: f32, x1: f32, y0: f32, y1: f32, y2: f32, y3: f32, u_0: f32, u_1: f32, v0: f32, v1: f32, r: f32, g: f32, b: f32, a: f32, d0: u8, t: u32) void { - var value = quads_textured.getPtr(t); - if (value) |v| { - const d = depth_levels - d0 - 1; - const i_v = v.i_verts[d]; - v.verts[d][i_v] = x0; - v.verts[d][i_v + 1] = y0; - v.verts[d][i_v + 2] = x1; - v.verts[d][i_v + 3] = y1; - v.verts[d][i_v + 4] = x1; - v.verts[d][i_v + 5] = y2; - v.verts[d][i_v + 6] = x0; - v.verts[d][i_v + 7] = y3; - const i_c = v.i_cols[d]; - v.cols[d][i_c] = r; - v.cols[d][i_c + 1] = g; - v.cols[d][i_c + 2] = b; - v.cols[d][i_c + 3] = a; - v.cols[d][i_c + 4] = r; - v.cols[d][i_c + 5] = g; - v.cols[d][i_c + 6] = b; - v.cols[d][i_c + 7] = a; - v.cols[d][i_c + 8] = r; - v.cols[d][i_c + 9] = g; - v.cols[d][i_c + 10] = b; - v.cols[d][i_c + 11] = a; - v.cols[d][i_c + 12] = r; - v.cols[d][i_c + 13] = g; - v.cols[d][i_c + 14] = b; - v.cols[d][i_c + 15] = a; - const i_t = v.i_texcs[d]; - v.texcs[d][i_t] = u_0; - v.texcs[d][i_t + 1] = v0; - v.texcs[d][i_t + 2] = u_1; - v.texcs[d][i_t + 3] = v0; - v.texcs[d][i_t + 4] = u_1; - v.texcs[d][i_t + 5] = v1; - v.texcs[d][i_t + 6] = u_0; - v.texcs[d][i_t + 7] = v1; - v.i_verts[d] += 8; - v.i_cols[d] += 16; - v.i_texcs[d] += 8; - v.n[d] += 4; - depth_levels_active.set(d); - quad_tex_statistics.inc(); - } -} - -pub fn endBatch() void { - // c.glEnd(); -} - -pub fn endBatchTextured() void { - // c.glEnd(); -} - -pub fn renderFrame() !void { - var iter = depth_levels_active.iterator(.{}); - while (iter.next()) |d| { - // c.glEnableClientState(c.GL_VERTEX_ARRAY); - // c.glEnableClientState(c.GL_COLOR_ARRAY); - // c.glEnableClientState(c.GL_TEXTURE_COORD_ARRAY); - // c.glEnable(c.GL_TEXTURE_2D); - var iter_quad_tex = quads_textured.iterator(); - while (iter_quad_tex.next()) |v| { - if (v.value_ptr.n[d] > 0) { - // bindTexture(v.key_ptr.*); - // c.glVertexPointer(2, c.GL_FLOAT, 0, @ptrCast(&v.value_ptr.verts[d])); - // c.glColorPointer(4, c.GL_FLOAT, 0, @ptrCast(&v.value_ptr.cols[d])); - // c.glTexCoordPointer(2, c.GL_FLOAT, 0, @ptrCast(&v.value_ptr.texcs[d])); - // c.glDrawArrays(c.GL_QUADS, 0, @intCast(v.value_ptr.n[d])); - // if (!glCheckError()) return GraphicsError.OpenGLFailed; - v.value_ptr.i_verts[d] = 0; - v.value_ptr.i_cols[d] = 0; - v.value_ptr.i_texcs[d] = 0; - v.value_ptr.n[d] = 0; - draw_call_statistics.inc(); - } - } - // c.glDisableClientState(c.GL_TEXTURE_COORD_ARRAY); - // c.glDisable(c.GL_TEXTURE_2D); - var value_quads = quads.getPtr(1); - if (value_quads) |v| { - // c.glVertexPointer(2, c.GL_FLOAT, 0, @ptrCast(&v.verts[d])); - // c.glColorPointer(4, c.GL_FLOAT, 0, @ptrCast(&v.cols[d])); - // c.glDrawArrays(c.GL_QUADS, 0, @intCast(v.n[d])); - // if (!glCheckError()) return GraphicsError.OpenGLFailed; - v.i_verts[d] = 0; - v.i_cols[d] = 0; - v.n[d] = 0; - draw_call_statistics.inc(); - } - // c.glDisableClientState(c.GL_VERTEX_ARRAY); - // c.glDisableClientState(c.GL_COLOR_ARRAY); - // c.glDisableClientState(c.GL_TEXTURE_COORD_ARRAY); - } - const r = std.bit_set.Range{ .start = 0, .end = depth_levels - 1 }; - depth_levels_active.setRangeValue(r, false); - - draw_call_statistics.finishFrame(); - quad_statistics.finishFrame(); - quad_tex_statistics.finishFrame(); - - try gfx_core.useShaderProgram(shader_program); - try gfx_core.bindVAO(vao); - - const verts = [9]f32 { - -0.5, -0.5, 0.0, - 0.5, -0.5, 0.0, - 0.0, 0.5, 0.0, - }; - try gfx_core.bindVBO(vbo); - c.__glewBufferData.?(c.GL_ARRAY_BUFFER, 9*@sizeOf(f32), &verts, c.GL_STATIC_DRAW); - c.__glewVertexAttribPointer.?(0, 3, c.GL_FLOAT, c.GL_FALSE, 3 * @sizeOf(f32), null); - c.__glewEnableVertexAttribArray.?(0); - - c.glDrawArrays(c.GL_TRIANGLES, 0, 3); - -} - -//-----------------------------------------------------------------------------// -// Internal -//-----------------------------------------------------------------------------// - -const log_gfx = std.log.scoped(.gfx); - -var gpa = if (cfg.debug_allocator) std.heap.GeneralPurposeAllocator(.{ .verbose_log = true }){} else std.heap.GeneralPurposeAllocator(.{}){}; -const allocator = gpa.allocator(); - -var frame_time: i64 = @intFromFloat(1.0 / 5.0 * 1.0e9); - -var draw_call_statistics = stats.PerFrameCounter.init("Draw calls"); -var quad_statistics = stats.PerFrameCounter.init("Quads"); -var quad_tex_statistics = stats.PerFrameCounter.init("Quads textured"); - -/// Maximum quad buffer size for rendering -const quads_max = 4096 / cfg.sub_sampling_base * 8; // 4K resolution, minimm width 2px, maximum of 8 lines in each column of a depth layer -/// Maximum depth levels for rendering -const depth_levels = cfg.gfx.depth_levels_max; -/// Active depth levels -var depth_levels_active = std.bit_set.IntegerBitSet(depth_levels).initEmpty(); - -const Quads = struct { - verts: [depth_levels][quads_max * 2 * 4]f32, - cols: [depth_levels][quads_max * 4 * 4]f32, - i_verts: [depth_levels]u32, - i_cols: [depth_levels]u32, - n: [depth_levels]u32, -}; - -const TexturedQuads = struct { - verts: [depth_levels][quads_max * 2 * 4]f32, - cols: [depth_levels][quads_max * 4 * 4]f32, - texcs: [depth_levels][quads_max * 2 * 4]f32, - i_verts: [depth_levels]u32, - i_cols: [depth_levels]u32, - i_texcs: [depth_levels]u32, - n: [depth_levels]u32, -}; - -var quads = std.AutoHashMap(u8, Quads).init(allocator); -var quads_textured = std.AutoHashMap(u32, TexturedQuads).init(allocator); - -fn allocMemory() !void { - quads.put(1, .{ .verts = undefined, .cols = undefined, .i_verts = undefined, .i_cols = undefined, .n = undefined }) catch |e| { - log_gfx.err("Allocation error ", .{}); - return e; - }; -} - -fn freeMemory() void { - quads.deinit(); - quads_textured.deinit(); -} - -var shader_program: u32 = 0; -var vao: u32 = 0; -var vbo: u32 = 0; - -//-----------------------------------------------------------------------------// -// Tests -//-----------------------------------------------------------------------------// - diff --git a/src/input.zig b/src/input.zig index 34de1df..c856782 100644 --- a/src/input.zig +++ b/src/input.zig @@ -3,8 +3,8 @@ const c = @import("c.zig").c; const gfx_core = @import("gfx_core.zig"); const gfx_rw = @import("gfx_rw.zig"); const plr = @import("player.zig"); -const rw_gui = @import("rw_gui.zig"); -const sim = @import("sim.zig"); +// const rw_gui = @import("rw_gui.zig"); +// const sim = @import("sim.zig"); //-----------------------------------------------------------------------------// // Init / DeInit @@ -42,12 +42,12 @@ pub fn processInputs(frequency: f32) void { if (c.glfwGetKey(window, c.GLFW_KEY_S) == c.GLFW_PRESS) plr.move(-6.0 / frequency); if (c.glfwGetKey(window, c.GLFW_KEY_E) == c.GLFW_PRESS) plr.moveUpDown(3.0 / frequency); if (c.glfwGetKey(window, c.GLFW_KEY_C) == c.GLFW_PRESS) plr.moveUpDown(-3.0 / frequency); - if (c.glfwGetKey(window, c.GLFW_KEY_LEFT) == c.GLFW_PRESS) sim.moveMapLeft(); - if (c.glfwGetKey(window, c.GLFW_KEY_RIGHT) == c.GLFW_PRESS) sim.moveMapRight(); - if (c.glfwGetKey(window, c.GLFW_KEY_UP) == c.GLFW_PRESS) sim.moveMapUp(); - if (c.glfwGetKey(window, c.GLFW_KEY_DOWN) == c.GLFW_PRESS) sim.moveMapDown(); - if (c.glfwGetKey(window, c.GLFW_KEY_F3) == c.GLFW_PRESS) sim.zoomOutMap(); - if (c.glfwGetKey(window, c.GLFW_KEY_F4) == c.GLFW_PRESS) sim.zoomInMap(); + // if (c.glfwGetKey(window, c.GLFW_KEY_LEFT) == c.GLFW_PRESS) sim.moveMapLeft(); + // if (c.glfwGetKey(window, c.GLFW_KEY_RIGHT) == c.GLFW_PRESS) sim.moveMapRight(); + // if (c.glfwGetKey(window, c.GLFW_KEY_UP) == c.GLFW_PRESS) sim.moveMapUp(); + // if (c.glfwGetKey(window, c.GLFW_KEY_DOWN) == c.GLFW_PRESS) sim.moveMapDown(); + // if (c.glfwGetKey(window, c.GLFW_KEY_F3) == c.GLFW_PRESS) sim.zoomOutMap(); + // if (c.glfwGetKey(window, c.GLFW_KEY_F4) == c.GLFW_PRESS) sim.zoomInMap(); } } @@ -115,12 +115,12 @@ fn processKeyPressEvent(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action if (key == c.GLFW_KEY_F1 and action == c.GLFW_PRESS) is_f1 = is_f1 != true; if (key == c.GLFW_KEY_F2 and action == c.GLFW_PRESS) is_f2 = is_f2 != true; - if (key == c.GLFW_KEY_F5 and action == c.GLFW_PRESS) sim.timing.decelerate(); - if (key == c.GLFW_KEY_F6 and action == c.GLFW_PRESS) sim.timing.accelerate(); - if (key == c.GLFW_KEY_F7 and action == c.GLFW_PRESS) sim.timing.decreaseFpsTarget(); - if (key == c.GLFW_KEY_F8 and action == c.GLFW_PRESS) sim.timing.increaseFpsTarget(); + // if (key == c.GLFW_KEY_F5 and action == c.GLFW_PRESS) sim.timing.decelerate(); + // if (key == c.GLFW_KEY_F6 and action == c.GLFW_PRESS) sim.timing.accelerate(); + // if (key == c.GLFW_KEY_F7 and action == c.GLFW_PRESS) sim.timing.decreaseFpsTarget(); + // if (key == c.GLFW_KEY_F8 and action == c.GLFW_PRESS) sim.timing.increaseFpsTarget(); if (key == c.GLFW_KEY_E and mods == c.GLFW_MOD_CONTROL and action == c.GLFW_PRESS) { - rw_gui.toggleEditMode(); + // rw_gui.toggleEditMode(); is_edit_mode_enabled = is_edit_mode_enabled != true; if (is_edit_mode_enabled) { _ = c.glfwSetCursorPos(window, @floatFromInt(gfx_core.getWindowWidth()/2), @@ -129,14 +129,14 @@ fn processKeyPressEvent(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action _ = c.glfwSetCursorPos(window, 0.0, 0.0); } } - if (key == c.GLFW_KEY_R and action == c.GLFW_PRESS) { + if (key == c.GLFW_KEY_R and mods == c.GLFW_MOD_CONTROL and action == c.GLFW_PRESS) { gfx_rw.reloadShaders() catch |e| { log_input.err("Unable to reload shaders: {}", .{e}); }; } - if (key == c.GLFW_KEY_H and action == c.GLFW_PRESS) sim.toggleStationHook(); - if (key == c.GLFW_KEY_M and action == c.GLFW_PRESS) sim.toggleMap(); - if (key == c.GLFW_KEY_P and action == c.GLFW_PRESS) sim.togglePause(); + // if (key == c.GLFW_KEY_H and action == c.GLFW_PRESS) sim.toggleStationHook(); + // if (key == c.GLFW_KEY_M and action == c.GLFW_PRESS) sim.toggleMap(); + // if (key == c.GLFW_KEY_P and action == c.GLFW_PRESS) sim.togglePause(); if (key == c.GLFW_KEY_Q and action == c.GLFW_PRESS) c.glfwSetWindowShouldClose(window, c.GLFW_TRUE); } diff --git a/src/main.zig b/src/main.zig index 04f1f69..00783ae 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4,13 +4,13 @@ const c = @import("c.zig").c; const cfg = @import("config.zig"); const gfx_core = @import("gfx_core.zig"); const gfx = @import("gfx_rw.zig"); -const rw_gui = @import("rw_gui.zig"); +// const rw_gui = @import("rw_gui.zig"); const input = @import("input.zig"); const map = @import("map.zig"); const plr = @import("player.zig"); const rc = @import("raycaster.zig"); const stats = @import("stats.zig"); -const sim = @import("sim.zig"); +// const sim = @import("sim.zig"); pub const std_options = struct { pub const log_scope_levels = &[_]std.log.ScopeLevel{ @@ -83,10 +83,11 @@ pub fn main() !void { // if (cfg.multithreading) sim_thread = try std.Thread.spawn(.{}, sim.run, .{}); + var hsr_thread: std.Thread = undefined; if (builtin.os.tag == .linux) { const gfx_hsr= @import("gfx_hsr.zig"); - var hsr_thread: std.Thread = undefined; - if (cfg.multithreading) hsr_thread = try std.Thread.spawn(.{}, gfx_hsr.readEvent, .{}); + gfx_hsr.init(); + hsr_thread = try std.Thread.spawn(.{}, gfx_hsr.readEvent, .{}); } while (gfx_core.isWindowOpen()) { @@ -155,20 +156,27 @@ pub fn main() !void { } } + if (builtin.os.tag == .linux) { + const gfx_hsr = @import("gfx_hsr.zig"); + gfx_hsr.rmWatch(); + @atomicStore(bool, &gfx_hsr.is_running, false, .Unordered); + hsr_thread.join(); + } + // sim.stop(); // if (cfg.multithreading) sim_thread.join(); - showPerformanceStats(prf_fps.getAvgAllMs(), - prf_idle.getAvgAllMs(), - prf_in.getAvgAllMs(), - prf_rc.getAvgAllMs(), - prf_ren.getAvgAllMs(), - prf_ren_scene.getAvgAllMs(), - prf_ren_frame.getAvgAllMs(), - prf_ren_map.getAvgAllMs(), - prf_ren_gui.getAvgAllMs(), - prf_ren_sim.getAvgAllMs(), - sim.getAvgAllMs()); + // showPerformanceStats(prf_fps.getAvgAllMs(), + // prf_idle.getAvgAllMs(), + // prf_in.getAvgAllMs(), + // prf_rc.getAvgAllMs(), + // prf_ren.getAvgAllMs(), + // prf_ren_scene.getAvgAllMs(), + // prf_ren_frame.getAvgAllMs(), + // prf_ren_map.getAvgAllMs(), + // prf_ren_gui.getAvgAllMs(), + // prf_ren_sim.getAvgAllMs(), + // sim.getAvgAllMs()); } @@ -187,28 +195,28 @@ fn printUsage() void { std.debug.print(help_message ++ "\n", .{}); } -inline fn showPerformanceStats(fps: f64, idle: f64, in: f64, rayc: f64, ren: f64, - ren_scene: f64, ren_frame: f64, ren_map: f64, ren_gui: f64, - ren_sim: f64, simulation: f64) void { - - std.log.info( - "\nFrametime: {d:.2}ms\n" ++ - " Idle: {d:.2}ms\n" ++ - " Input: {d:.2}ms\n" ++ - " Raycasting: {d:.2}ms\n" ++ - " Rendering: {d:.2}ms\n" ++ - " Scene: {d:.2}ms\n" ++ - " Frame: {d:.2}ms\n" ++ - " Map: {d:.2}ms\n" ++ - " Gui: {d:.2}ms\n" ++ - " Sim: {d:.2}ms\n" ++ - "Sim-Thread: {d:.2}ms\n" ++ - "(@{d:.0}Hz => {d:.2}ms @{d:.0}Hz)", - .{fps, idle, in, rayc, ren, ren_scene, ren_frame, ren_map, ren_gui, ren_sim, simulation, - sim.timing.getFpsTarget(), simulation*sim.timing.getFpsTarget()/cfg.gfx.fps_target, - cfg.gfx.fps_target} - ); -} +// inline fn showPerformanceStats(fps: f64, idle: f64, in: f64, rayc: f64, ren: f64, +// ren_scene: f64, ren_frame: f64, ren_map: f64, ren_gui: f64, +// ren_sim: f64, simulation: f64) void { + +// std.log.info( +// "\nFrametime: {d:.2}ms\n" ++ +// " Idle: {d:.2}ms\n" ++ +// " Input: {d:.2}ms\n" ++ +// " Raycasting: {d:.2}ms\n" ++ +// " Rendering: {d:.2}ms\n" ++ +// " Scene: {d:.2}ms\n" ++ +// " Frame: {d:.2}ms\n" ++ +// " Map: {d:.2}ms\n" ++ +// " Gui: {d:.2}ms\n" ++ +// " Sim: {d:.2}ms\n" ++ +// "Sim-Thread: {d:.2}ms\n" ++ +// "(@{d:.0}Hz => {d:.2}ms @{d:.0}Hz)", +// .{fps, idle, in, rayc, ren, ren_scene, ren_frame, ren_map, ren_gui, ren_sim, simulation, +// sim.timing.getFpsTarget(), simulation*sim.timing.getFpsTarget()/cfg.gfx.fps_target, +// cfg.gfx.fps_target} +// ); +// } const help_message = "=====================\n" ++ " Welcome to Rayworld \n" ++ @@ -217,6 +225,7 @@ const help_message = "=====================\n" ++ " F1: this help\n" ++ " F2: debug info\n" ++ " CTRL-E: toggle edit mode (preparation for map editor)\n" ++ + " CTRL-R: manually reload shaders\n" ++ " Q: quit\n" ++ "MOVEMENT\n" ++ " Use mouse to turn/look around\n" ++ diff --git a/src/rw_gui.zig b/src/rw_gui.zig deleted file mode 100644 index 0336bff..0000000 --- a/src/rw_gui.zig +++ /dev/null @@ -1,176 +0,0 @@ -const std = @import("std"); -const gui = @import("gui.zig"); -const cfg = @import("config.zig"); -const fnt = @import("font_manager.zig"); -const gfx = @import("graphics.zig"); -const input = @import("input.zig"); -const sim = @import("sim.zig"); - -pub fn init() !void { - - fnt.init(); - try fnt.addFont("anka_b", "resource/AnkaCoder-C87-b.ttf"); - try fnt.addFont("anka_i", "resource/AnkaCoder-C87-i.ttf"); - try fnt.addFont("anka_r", "resource/AnkaCoder-C87-r.ttf"); - try fnt.addFont("anka_bi", "resource/AnkaCoder-C87-bi.ttf"); - try fnt.rasterise("anka_b", 32, gfx.getTextureId()); - - const font_overlay: gui.Overlay = .{.title = .{.text = "Font Idle Timers", - .col = .{0.8, 1.0, 0.8, 0.8}}, - .width = 300, - .height = 32.0 * (@as(f32, @floatFromInt(fnt.getIdByName().count() + 1))), - .is_enabled = false, - .ll_x = 10.0, - .ll_y = 10.0, - .col = .{0.0, 1.0, 0.0, 0.2}, - }; - const text_widget: gui.TextWidget = .{.col = .{0.5, 1.0, 0.5, 0.8}}; - try gui.addOverlay("fnt_ovl", font_overlay); - try gui.addTextWidget("fnt_ovl", "fnt_txt", text_widget); - - const prf_overlay: gui.Overlay = .{.title = .{.text = "Performance Stats", - .col = .{0.8, 1.0, 0.8, 0.8}}, - .width = 400, - .height = 32.0 * 13, - .align_h = .right, - .align_v = .top, - .is_enabled = false, - .ll_x = 330.0, - .ll_y = 10.0, - .col = .{0.0, 1.0, 0.0, 0.2}, - .widget_type = .text, - }; - const prf_widget: gui.TextWidget = .{.col = .{0.5, 1.0, 0.5, 0.8}}; - try gui.addOverlay("prf_ovl", prf_overlay); - try gui.addTextWidget("prf_ovl", "prf_txt", prf_widget); - - const help_overlay: gui.Overlay = .{.title = .{.text = "Help", - .col = .{0.8, 1.0, 0.8, 0.8}}, - .width = 500, - .height = 200, - .resize_mode = .auto, - .align_h = .centered, - .align_v = .centered, - .is_enabled = false, - .col = .{0.0, 1.0, 0.0, 0.2}, - .widget_type = .text, - }; - const help_widget: gui.TextWidget = .{.text = "HelpMessage", - .col = .{0.5, 1.0, 0.5, 0.8}}; - try gui.addOverlay("hlp_ovl", help_overlay); - try gui.addTextWidget("hlp_ovl", "hlp_txt", help_widget); -} - -pub fn deinit() void { - gui.deinit(); - fnt.deinit(); - arena.deinit(); -} - -pub fn setHelpMessage(msg: []const u8) !void { - const hlp_txt = try gui.getTextWidget("hlp_txt"); - hlp_txt.text = msg; -} - -pub fn toggleEditMode() void { - is_edit_mode_enabled = is_edit_mode_enabled != true; - gui.toggleEditMode(); -} - -pub fn updatePerformanceStats(fps: f64, idle: f64, in: f64, rayc: f64, ren: f64, - ren_scene: f64, ren_frame: f64, ren_map: f64, ren_gui: f64, - ren_sim: f64, simulation: f64) !void { - const ovl = try gui.getOverlay("prf_ovl"); - if (ovl.is_enabled) { - const prf_printout = try std.fmt.allocPrint(allocator, - "Frametime: {d:.2}ms\n" ++ - " Idle: {d:.2}ms\n" ++ - " Input: {d:.2}ms\n" ++ - " Raycasting: {d:.2}ms\n" ++ - " Rendering: {d:.2}ms\n" ++ - " Scene: {d:.2}ms\n" ++ - " Frame: {d:.2}ms\n" ++ - " Map: {d:.2}ms\n" ++ - " Gui: {d:.2}ms\n" ++ - " Sim: {d:.2}ms\n" ++ - "Sim-Thread: {d:.2}ms\n" ++ - "(@{d:.0}Hz => {d:.2}ms @{d:.0}Hz)", - .{fps, idle, in, rayc, ren, ren_scene, ren_frame, ren_map, ren_gui, ren_sim, simulation, - sim.timing.getFpsTarget(), simulation*sim.timing.getFpsTarget()/cfg.gfx.fps_target, - cfg.gfx.fps_target} - ); - - const t = try gui.getTextWidget("prf_txt"); - t.text = prf_printout; - } -} - -pub fn process(x: f32, y: f32, mouse_l: bool, mouse_wheel: f32) !void { - try updateFontStats(); - try gui.processOverlays(x, y, mouse_l, mouse_wheel); - - if (is_edit_mode_enabled) { - try fnt.setFont("anka_bi", 48); - gfx.setColor4(1.0, 0.2, 0.2, 0.8); - const t = "EDIT MODE"; - const s = fnt.getTextSizeLine("EDIT MODE") catch {return;}; - try fnt.renderText(t, @as(f32, @floatFromInt(gfx.getWindowWidth()))-s.w-10, 0, 0.0); - gui.drawCursor(x, y); - } - { - const ovl = try gui.getOverlay("hlp_ovl"); - if (input.getF1()) { - ovl.is_enabled = true; - } else { - ovl.is_enabled = false; - } - } - { - const ovl_fnt = try gui.getOverlay("fnt_ovl"); - const ovl_prf = try gui.getOverlay("prf_ovl"); - if (input.getF2()) { - ovl_fnt.is_enabled = true; - ovl_prf.is_enabled = true; - } else { - ovl_fnt.is_enabled = false; - ovl_prf.is_enabled = false; - } - } - - _ = arena.reset(.retain_capacity); -} - -//-----------------------------------------------------------------------------// -// Internal -//-----------------------------------------------------------------------------// - -var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); -const allocator = arena.allocator(); - -var is_edit_mode_enabled: bool = false; - -fn updateFontStats() !void { - const ovl = try gui.getOverlay("fnt_ovl"); - if (ovl.is_enabled) { - const names = fnt.getIdByName(); - const timers = fnt.getTimerById(); - - var iter = names.iterator(); - var timer_printout = std.ArrayList(u8).init(allocator); - - while (iter.next()) |v| { - const name = v.key_ptr.*; - var timer = timers.get(v.value_ptr.*).?; - - const tmp = try std.fmt.allocPrint(allocator, - "{s}: {d:.1}s\n", - .{name, 1.0e-9 * @as(f64, @floatFromInt(timer.read()))}); - try timer_printout.appendSlice(tmp); - allocator.free(tmp); - - } - _ = timer_printout.pop(); // Remove last carriage return - var t = try gui.getTextWidget("fnt_txt"); - t.text = try timer_printout.toOwnedSlice(); - } -} diff --git a/src/sim.zig b/src/sim.zig deleted file mode 100644 index ddabc5f..0000000 --- a/src/sim.zig +++ /dev/null @@ -1,390 +0,0 @@ -const std = @import("std"); -const cfg = @import("config.zig"); -const gfx_core = @import("gfx_core.zig"); -const gfx = @import("graphics.zig"); -const gui = @import("gui.zig"); -const stats = @import("stats.zig"); - -//-----------------------------------------------------------------------------// -// Init / DeInit -//-----------------------------------------------------------------------------// - -pub fn init() !void { - - timing.init(); - - const mass_planet = 1e26; - - // Initialise planet - try objs.append(allocator, .{ - .acc = .{0.0, 0.0}, - .vel = .{0.0, 0.0}, - .pos = .{0.0, 0.0}, - .mass = mass_planet, - .mass_inv = 1.0 / mass_planet, - .radius = 5e6, - }); - - const orbit_radius = 7e6; - // const orbit_velocity = @sqrt(gravitational_constant * mass_planet / orbit_radius); - - switch (cfg.sim.scenario) { - .falling_station => try initFallingStation(mass_planet, orbit_radius), - .breaking_asteriod => try initBreakingAsteriod(mass_planet, orbit_radius), - else => {}, - } - - log_sim.debug("Number of objects: {}", .{objs.len}); -} - -pub fn deinit() void { - objs.deinit(allocator); - - const leaked = gpa.deinit(); - if (leaked == .leak) log_sim.err("Memory leaked in GeneralPurposeAllocator", .{}); -} - -//-----------------------------------------------------------------------------// -// Processing -//-----------------------------------------------------------------------------// - -pub fn createScene() !void { - - if (is_map_displayed) { - const win_w: f32 = @floatFromInt(gfx_core.getWindowWidth()); - const win_h: f32 = @floatFromInt(gfx_core.getWindowHeight()); - - var hook: vec_2d = .{0.0, 0.0}; - var zoom_x2: vec_2d = @splat(cam.zoom); - var win_center: vec_2d = .{win_w * 0.5, win_h * 0.5}; - - if (cam.station_hook) { - hook = objs.items(.pos)[1]; - } - - var map_overlay: gui.Overlay = .{.title = .{.text = "System Map", - .font_size = 64, - .col = .{1.0, 0.8, 0.3, 0.8}}, - .frame = .{10, 64, 10, 10}, - .width = win_w * 0.9, - .height = win_h * 0.9, - .ll_x = win_w * 0.05, - .ll_y = win_h * 0.05, - .col = .{1.0, 0.5, 0.0, 0.3}}; - try gui.drawOverlay(&map_overlay); - - gfx_core.setViewport(@intFromFloat(map_overlay.ll_x + map_overlay.frame[0]), - @intFromFloat(map_overlay.ll_y + map_overlay.frame[3]), - @intFromFloat(map_overlay.width - map_overlay.frame[0] - map_overlay.frame[2]), - @intFromFloat(map_overlay.height - map_overlay.frame[1] - map_overlay.frame[3])); - - gfx.startBatchQuads(); - - gfx.setColor4(1.0, 0.5, 0.0, 0.8); - - var i: usize = 2; - while (i < objs.len) : (i += 1) { - const o = @max(@as(f32, @floatCast(objs.items(.radius)[i])) * cam.zoom, 1.5); - const p = (objs.items(.pos)[i] + cam.p - hook) * zoom_x2 + win_center; - - gfx.addQuad(@floatCast(p[0]-o), @floatCast(p[1]-o), - @floatCast(p[0]+o), @floatCast(p[1]+o)); - } - - gfx.setColor4(1.0, 0.1, 0.0, 0.8); - - // The station - const s_o = @max(@as(f32, @floatCast(objs.items(.radius)[1])) * cam.zoom, 2.0); - const s_p = (objs.items(.pos)[1] + cam.p - hook) * zoom_x2 + win_center; - - gfx.addQuad(@floatCast(s_p[0]-s_o), @floatCast(s_p[1]-s_o), - @floatCast(s_p[0]+s_o), @floatCast(s_p[1]+s_o)); - - gfx.endBatch(); - - // The planet - const c_p = (objs.items(.pos)[0] + cam.p - hook) * zoom_x2 + win_center; - const c_r = cam.zoom * @as(f32, @floatCast(objs.items(.radius)[0])); - gfx.setColor4(1.0, 0.6, 0.0, 0.8); - gfx.setLineWidth(4.0); - gfx.drawCircle(@floatCast(c_p[0]), @floatCast(c_p[1]), c_r); - gfx.setLineWidth(1.0); - - gfx.setViewportFull(); - } -} - - -pub fn run() !void { - var timer = try std.time.Timer.start(); - - log_sim.info("Starting simulation", .{}); - - var perf = try stats.PerFrameTimerBuffered(128).init(); - while (is_running) { - perf.start(); - if (timing.is_paused) { - step(); - } - perf.stop(); - prf_avg_buf_ms = perf.getAvgBufMs(); - const t = timer.read(); - - const t_step = @subWithOverflow(timing.frame_time, t); - if (t_step[1] == 0) std.time.sleep(t_step[0]) - else timing.decreaseFpsTarget(); - - timer.reset(); - } - prf_avg_all_ms = perf.getAvgAllMs(); -} - -pub fn step() void { - const dt: vec_2d = @splat(@as(f64, timing.acceleration/timing.fps_base)); - - var i: usize = 1; - while (i < objs.len) : (i += 1) { - const d = objs.items(.pos)[0]-objs.items(.pos)[i]; - const r_sqr = @reduce(.Add, d*d); // = d[0]*d[0] + d[1]*d[1] - const r = @sqrt(r_sqr); - const r_x2: vec_2d = @splat(r); - const m = objs.items(.mass)[0]; - const a = gravitational_constant * m / r_sqr; - const a_x2: vec_2d = @splat(a); - const e_0 = d / r_x2; - objs.items(.acc)[i] = e_0 * a_x2; - } - // if (cfg.sim.scenario == .falling_station) { - var drag: f64 = -1.0e-5; - objs.items(.acc)[1] += @as(vec_2d, @splat(drag)) * objs.items(.vel)[1]; - // } - - i = 0; - while (i < objs.len) : (i += 1) { - objs.items(.vel)[i] += objs.items(.acc)[i] * dt; - objs.items(.pos)[i] += objs.items(.vel)[i] * dt; - } -} - -pub inline fn getAvgAllMs() f64 { - return prf_avg_all_ms; -} - -pub inline fn getAvgBufMs() f64 { - return prf_avg_buf_ms; -} - -pub fn stop() void { - log_sim.info("Simulation terminating", .{}); - @atomicStore(bool, &is_running, false, .Release); -} - -pub inline fn moveMapLeft() void { - cam.p[0] += 10.0 / cam.zoom * 60.0 / gfx_core.getFPS(); -} - -pub inline fn moveMapRight() void { - cam.p[0] -= 10.0 / cam.zoom * 60.0 / gfx_core.getFPS(); -} - -pub inline fn moveMapUp() void { - cam.p[1] += 10.0 / cam.zoom * 60.0 / gfx_core.getFPS(); -} - -pub inline fn moveMapDown() void { - cam.p[1] -= 10.0 / cam.zoom * 60.0 / gfx_core.getFPS(); -} - -pub inline fn toggleMap() void { - is_map_displayed = is_map_displayed != true; -} - -pub inline fn togglePause() void { - timing.is_paused = timing.is_paused != true; -} - -pub inline fn toggleStationHook() void { - cam.station_hook = cam.station_hook != true; -} - -pub inline fn zoomInMap() void { - cam.zoom *= 1.0 + 0.1 * 60.0 / gfx_core.getFPS(); -} - -pub inline fn zoomOutMap() void { - cam.zoom *= 1.0 - 0.1 * 60.0 / gfx_core.getFPS(); -} - -pub const timing = struct { - - pub inline fn getFpsTarget() f32 { - return fps_target; - } - - pub fn accelerate() void { - if (10.0 * acceleration / fps_base <= 10.0) { - acceleration *= 10.0; - } else { - log_sim.warn("Acceleration too high, keeping {d:.0} for numeric stability.", .{acceleration}); - } - log_sim.info("Simulation rate at {d:.2}x @{d:.0}Hz", .{acceleration, fps_target}); - } - - pub fn decelerate() void { - acceleration *= 0.1; - log_sim.info("Simulation rate at {d:.2}x @{d:.0}Hz", .{acceleration, fps_target}); - } - - pub fn decreaseFpsTarget() void { - if (fps_target > 100.0) { - fps_target -= 100.0; - frame_time = @intFromFloat(1.0/fps_target*1.0e9); - log_sim.info("Simulation rate at {d:.2}x @{d:.0}Hz", .{acceleration, fps_target}); - } - } - - pub fn increaseFpsTarget() void { - fps_target += 100.0; - frame_time = @intFromFloat(1.0/fps_target*1.0e9); - log_sim.info("Simulation rate at {d:.2}x @{d:.0}Hz", .{acceleration, fps_target}); - } - - fn init() void { - fps_target = cfg.sim.fps_target; - acceleration = cfg.sim.acceleration; - if (acceleration / fps_target > 10.0) { - acceleration = 10.0 * fps_target; - log_sim.warn("Acceleration too high, capping at {d:.0} for numeric stability.", .{acceleration}); - } - log_sim.info("Simulation rate at {d:.2}x @{d:.0}Hz", .{acceleration, fps_target}); - } - - var acceleration: f32 = 1.0; - var fps_base: f32 = 100.0; - var fps_target: f32 = 100.0; - var frame_time: u64 = @intFromFloat(1.0/cfg.sim.fps_target*1.0e9); - var is_paused = false; -}; - -//-----------------------------------------------------------------------------// -// Internal -//-----------------------------------------------------------------------------// - -const log_sim = std.log.scoped(.sim); - -var gpa = if (cfg.debug_allocator) std.heap.GeneralPurposeAllocator(.{.verbose_log = true}){} else - std.heap.GeneralPurposeAllocator(.{}){}; -const allocator = gpa.allocator(); - -const gravitational_constant = 6.6743015e-11; - -var is_map_displayed: bool = false; -var is_running: bool = true; -var prf_avg_all_ms: f64 = 0.0; -var prf_avg_buf_ms: f64 = 0.0; - -const Camera = struct { - p: vec_2d, - zoom: f32, - station_hook: bool, -}; -var cam = Camera { - .p = .{0.0, 0.0}, - .zoom = 5.0e-5, - .station_hook = false, -}; - -const vec_2d = @Vector(2, f64); - -const PhysicalObject = struct { - acc: vec_2d, - pos: vec_2d, - vel: vec_2d, - mass: f64, - mass_inv: f64, - radius: f64, -}; - -/// All physically simulated objects. MultiArrayList is internally implemented -/// as a SoA (Struct of Arrays), which should be fine, here. -const Objects = std.MultiArrayList(PhysicalObject); - -var objs = Objects{}; - -fn initFallingStation(mass_planet: f64, orbit_radius: f64) !void { - var r_gen = std.rand.DefaultPrng.init(23); - const prng = r_gen.random(); - - const o_sr = orbit_radius + 2.0e6; - const o_sv = @sqrt(gravitational_constant * mass_planet / o_sr); - var i: u32 = 0; - // Initialise station - try objs.append(allocator, .{ - .acc = .{0.0, 0.0}, - .vel = .{0.0, o_sv}, - .pos = .{o_sr, 0.0}, - .mass = 500e3, // ISS-like ~ 500t - .mass_inv = 1.0 / 500e3, - .radius = 50, // ISS-like ~94m x 73m - }); - - i = 0; - while (i < cfg.sim.number_of_debris) : (i += 1) { - - const o_std = prng.floatNorm(f64) * 350.0e3; - const ang_std = prng.floatNorm(f64) * 0.1; - const o_r = orbit_radius + o_std; - const ang = prng.float(f64) * 2.0 * std.math.pi; - - const o_v = @sqrt(gravitational_constant * mass_planet / o_r); - - // Initialise debris - try objs.append(allocator, .{ - .acc = .{0.0, 0.0}, - .vel = .{-o_v * @cos(ang+ang_std), o_v * @sin(ang+ang_std)}, - .pos = .{o_r * @sin(ang+ang_std), o_r * @cos(ang+ang_std)}, - .mass = 20e3, - .mass_inv = 1.0 / 20e3, - .radius = 5, - }); - } -} - -fn initBreakingAsteriod(mass_planet: f64, orbit_radius: f64) !void { - var r_gen = std.rand.DefaultPrng.init(23); - const prng = r_gen.random(); - - const o_sr = orbit_radius + 1.0e6; - const o_sv = @sqrt(gravitational_constant * mass_planet / o_sr); - var i: u32 = 0; - // Initialise station - try objs.append(allocator, .{ - .acc = .{0.0, 0.0}, - .vel = .{0.0, o_sv}, - .pos = .{-o_sr, 0.0}, - .mass = 500e3, // ISS-like ~ 500t - .mass_inv = 1.0 / 500e3, - .radius = 50, // ISS-like ~94m x 73m - }); - - const o_dr = orbit_radius; - const o_dv = @sqrt(gravitational_constant * mass_planet / o_dr); - i = 0; - while (i < cfg.sim.number_of_debris) : (i += 1) { - - const o_std = prng.floatNorm(f64) * 50.0e3; - const o_r = orbit_radius + o_std; - - // const o_v = @sqrt(gravitational_constant * mass_planet / o_r); - - // Initialise debris - try objs.append(allocator, .{ - .acc = .{0.0, 0.0}, - .vel = .{0.0, o_dv+prng.floatNorm(f64) * 1.0e2}, - .pos = .{o_r, prng.floatNorm(f64) * 25.0e3}, - .mass = 20e3, - .mass_inv = 1.0 / 20e3, - .radius = 5, - }); - } -}