aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--README.md2
-rw-r--r--build.zig53
-rw-r--r--build.zig.zon18
-rw-r--r--src/imgui.zig4
-rw-r--r--src/main.zig50
-rw-r--r--src/particle.zig34
-rw-r--r--src/quad.zig24
-rw-r--r--src/rules.zig42
m---------vendor/rlImGui0
m---------vendor/zgui0
11 files changed, 127 insertions, 103 deletions
diff --git a/.gitmodules b/.gitmodules
index 9ce7459..a277ea8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "vendor/zgui"]
path = vendor/zgui
url = https://github.com/zig-gamedev/zgui.git
+[submodule "rlimgui"]
+ path = vendor/rlImGui
+ url = https://github.com/raylib-extras/rlImGui.git
diff --git a/README.md b/README.md
index 3605b0f..320e1b0 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Particle Simulator
This is a simple particle simulator written in zig using [Raylib](https://www.raylib.com)
## Dependencies
-- slightly modified rlImgui bindings (commented out 3 random lines)
+- slightly modified rlImgui bindings (commented out lines 295-298)
- zgui
- raylib
## Running
diff --git a/build.zig b/build.zig
index ac39671..a333a8a 100644
--- a/build.zig
+++ b/build.zig
@@ -4,35 +4,42 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseFast });
- const exe = b.addExecutable(.{
- .name = "particle-sim",
- .root_source_file = b.path("src/main.zig"),
- .target = target,
- .optimize = optimize,
- });
- exe.linkLibCpp();
- const raylib_zig = b.dependency("raylib-zig", .{
+ const raylib_zig = b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
});
- const raylib = raylib_zig.module("raylib");
const raylib_artifact = raylib_zig.artifact("raylib");
- exe.linkLibrary(raylib_artifact);
- exe.root_module.addImport("raylib", raylib);
const zgui = b.dependency("zgui", .{
.shared = false,
.with_implot = true,
});
- exe.root_module.addImport("zgui", zgui.module("root"));
- exe.linkLibrary(zgui.artifact("imgui"));
- exe.addIncludePath(b.path("vendor/zgui/libs/imgui"));
const rlimgui = b.dependency("rlimgui", .{
.target = target,
.optimize = optimize,
});
+
+ const exe = b.addExecutable(.{
+ .name = "particle-sim",
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("src/main.zig"),
+ .link_libcpp = true,
+ .imports = &.{
+ .{ .name = "raylib", .module = raylib_zig.module("raylib") },
+ .{ .name = "zgui", .module = zgui.module("root") },
+ },
+ .target = target,
+ .optimize = optimize,
+ }),
+ });
+ // exe.linkLibCpp();
+ exe.linkLibrary(raylib_artifact);
+ exe.linkLibrary(zgui.artifact("imgui"));
+ exe.addIncludePath(zgui.path("libs/imgui"));
+
+
exe.root_module.addCSourceFile(.{
.file = rlimgui.path("rlImGui.cpp"),
.flags = &.{
@@ -54,14 +61,14 @@ pub fn build(b: *std.Build) !void {
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
- const exe_unit_tests = b.addTest(.{
- .root_source_file = b.path("src/quad.zig"),
- .target = target,
- .optimize = optimize,
- });
-
- const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
+ // const exe_unit_tests = b.addTest(.{
+ // .root_source_file = b.path("src/quad.zig"),
+ // .target = target,
+ // .optimize = optimize,
+ // });
- const test_step = b.step("test", "Run unit tests");
- test_step.dependOn(&run_exe_unit_tests.step);
+ // const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
+ //
+ // const test_step = b.step("test", "Run unit tests");
+ // test_step.dependOn(&run_exe_unit_tests.step);
}
diff --git a/build.zig.zon b/build.zig.zon
index 61aaa5e..5b59387 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -1,13 +1,17 @@
.{
- .name = "particle-sim",
- .version = "0.2.1",
+ .name = .particle_sim,
+ .fingerprint = 0x88cd171d5a7354dc,
+ .version = "0.3.0",
.paths = .{ "src", "vendor" },
.dependencies = .{
- .@"raylib-zig" = .{
- .url = "https://github.com/Not-Nik/raylib-zig/archive/devel.tar.gz",
- .hash = "1220fc554f109a45a77ee5c58b4a847936dc0b24dcbed818b65a02de1b58500041dc",
- },
.rlimgui = .{ .path = "vendor/rlImGui" },
- .zgui = .{ .path = "vendor/zgui" },
+ .raylib_zig = .{
+ .url = "git+https://github.com/raylib-zig/raylib-zig?ref=devel#163b1ef2e993fe7cc7c76bb3213d98612f4b7676",
+ .hash = "raylib_zig-5.6.0-dev-KE8REGNJBQDSjjyCmf4ATVQtk_OaBpY0B7kBxwSOPEGZ",
+ },
+ .zgui = .{
+ .url = "git+https://github.com/nic-gaffney/zgui#d90f353a733ab34f1c62e42c01ee87993075fa7e",
+ .hash = "zgui-0.6.0-dev--L6sZBrubQAfBA0cnGPYocwjKh_ass7FrUkTadgicanG",
+ },
},
}
diff --git a/src/imgui.zig b/src/imgui.zig
index 688e935..f086f2a 100644
--- a/src/imgui.zig
+++ b/src/imgui.zig
@@ -30,13 +30,13 @@ pub fn update(alloc: std.mem.Allocator, buf: [:0]u8) !void {
}
if (z.collapsingHeader("Radius", .{ .default_open = true })) {
for (&cfg.radius, 0..) |*r, i| {
- const str = rul.colorToStringZ(i);
+ const str = rul.colorToStringZ(i, "", " Radius");
_ = z.sliderInt(str, .{ .v = r, .min = cfg.minDistance, .max = 500 });
}
}
if (z.collapsingHeader("Speed", .{ .default_open = true })) {
for (&cfg.speed, 0..) |*s, i| {
- const str = rul.colorToStringZ(i);
+ const str = rul.colorToStringZ(i, "", " Speed");
_ = z.sliderInt(str, .{ .v = s, .min = 1, .max = 1000 });
}
}
diff --git a/src/main.zig b/src/main.zig
index f7ec0a0..4d21dae 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -17,18 +17,18 @@ pub fn main() !void {
cfg.rules = rules.ruleMatrix(true, true);
rules.printRules(cfg.rules);
- var gpa = std.heap.GeneralPurposeAllocator(.{
- // .safety = true,
- // .thread_safe = true,
- // .verbose_log = false,
- }){};
- defer {
- const leaked = gpa.deinit();
- if (leaked == .leak) {
- std.debug.print("LEAKY PROGRAM\n", .{});
- }
- }
- const allocator = gpa.allocator();
+ const allocator = std.heap.smp_allocator;
+ // defer {
+ // const leaked = smp.deinit();
+ // if (leaked == .leak) {
+ // std.debug.print("LEAKY PROGRAM\n", .{});
+ // }
+ // }
+ // gpa.setRequestedMemoryLimit(8000000);
+ // const allocator = smp.allocator();
+ // var buffer: [80000000]u8 = undefined;
+ // var fbuffer = std.heap.FixedBufferAllocator.init(&buffer);
+ // const allocator = fbuffer.threadSafeAllocator();
rl.initWindow(cfg.screenWidth, cfg.screenHeight, "Particle Simulator");
defer rl.closeWindow();
@@ -49,18 +49,20 @@ pub fn main() !void {
var particles = try part.initParticles(allocator, cfg.initialParticles);
defer particles.deinit();
var quadTree: quad.Quad(part.particle, cfg.quadSplitLimit) = undefined;
+ // defer quadTree.deinit();
const buf = try allocator.allocSentinel(u8, 128, 0);
std.mem.copyForwards(u8, buf, "Absolute File Path" ++ .{0});
defer allocator.free(buf);
const pool = try allocator.alloc(std.Thread, cfg.numThreads);
+ var particleArrs: [cfg.numThreads]std.ArrayList(part.particle) = undefined;
+ for (0..cfg.numThreads) |i|
+ particleArrs[i] = try std.ArrayList(part.particle).initCapacity(allocator, comptime @divFloor(cfg.particleMax, cfg.numThreads) + cfg.numThreads);
defer allocator.free(pool);
- var frameCounter: u32 = 0;
while (!rl.windowShouldClose()) {
if (particles.items.len < cfg.particleCount) {
for (0..@intCast(cfg.particleCount - @as(i32, @intCast(particles.items.len)))) |_| {
- //std.debug.print("without this print statement it breaks on arm idk why {d}\n", .{cfg.particleCount});
_ = cfg.particleCount;
try particles.append(part.createParticle());
}
@@ -70,22 +72,28 @@ pub fn main() !void {
particles.shrinkRetainingCapacity(@intCast(cfg.particleCount));
}
- quadTree = quad.Quad(part.particle, cfg.quadSplitLimit).init(allocator,
- .{ .x = 0, .y = 0 }, .{ .x = rl.getScreenWidth(), .y = rl.getScreenHeight()});
- defer quadTree.deinit();
+
+ quadTree = try quad.Quad(part.particle, cfg.quadSplitLimit).init(allocator,
+ .{ .x = 0, .y = 0 },
+ .{ .x = rl.getScreenWidth(), .y = rl.getScreenHeight()});
+ // defer quadTree.deinit();
for (particles.items) |p| try quadTree.insert(.{ .pos = p.pos, .data = p});
rl.beginDrawing();
defer rl.endDrawing();
- if (rl.isKeyPressed(rl.KeyboardKey.key_q)) break;
+ if (rl.isKeyPressed(rl.KeyboardKey.q)) {
+ quadTree.deinit();
+ break;
+ }
rl.clearBackground(rl.getColor(0x1E1E2EFF));
- for (pool, 0..) |*thread, i|
- thread.* = try std.Thread.spawn(.{}, part.updateVelocities, .{ particles, quadTree, i });
+ for (pool, 0..) |*thread, i| {
+ thread.* = try std.Thread.spawn(.{}, part.updateVelocities, .{ particles, quadTree, i, &particleArrs[i] });
+ }
for (pool) |thread|
thread.join();
- frameCounter += 1;
+ quadTree.deinit();
part.updatePosition(&particles);
diff --git a/src/particle.zig b/src/particle.zig
index d33e7ce..14748dc 100644
--- a/src/particle.zig
+++ b/src/particle.zig
@@ -9,9 +9,10 @@ pub const particle = struct {
xvel: f32,
yvel: f32,
};
-/// Initialize a MultiArrayList of size amnt with particles created by createParticle
-pub fn initParticles(allocator: std.mem.Allocator, amnt: u32) !std.ArrayList(particle) {
- var particles = std.ArrayList(particle).init(allocator);
+
+/// Initialize an array_list.Managed of size amnt with particles created by createParticle
+pub fn initParticles(allocator: std.mem.Allocator, amnt: u32) !std.array_list.Managed(particle) {
+ var particles = std.array_list.Managed(particle).init(allocator);
try particles.ensureTotalCapacity(cfg.particleMax);
for (0..amnt) |_|
try particles.append(createParticle());
@@ -21,38 +22,38 @@ pub fn initParticles(allocator: std.mem.Allocator, amnt: u32) !std.ArrayList(par
/// Applies forces from the ruleset to each particle
pub fn updateVelocities(
- particles: std.ArrayList(particle),
+ particles: std.array_list.Managed(particle),
qtree: quad.Quad(particle, cfg.quadSplitLimit),
threadidx: u64,
+ particlesInRange: *std.ArrayList(particle),
) !void {
const rules = cfg.rules;
- var particlesInRange = std.ArrayList(particle).init(qtree.allocator);
- defer particlesInRange.deinit();
var i = threadidx;
while (i < particles.items.len) : (i += cfg.numThreads) {
var p: *particle = &(particles.items[i]);
defer particlesInRange.clearRetainingCapacity();
const radius = cfg.radius[p.colorId];
- try qtree.radiusSearchWrapping(p.pos, @intCast(radius), &particlesInRange, rl.getScreenWidth(), rl.getScreenHeight());
+ try qtree.radiusSearchWrapping(p.pos, @intCast(radius), particlesInRange, rl.getScreenWidth(), rl.getScreenHeight());
var forceX: f32 = 0.0;
var forceY: f32 = 0.0;
const floatRadius = @as(f32, @floatFromInt(radius));
const floattMinDistance = @as(f32, @floatFromInt(cfg.minDistance));
for (particlesInRange.items) |p2| {
if (p.pos.x == p2.pos.x and p.pos.y == p2.pos.y) continue;
+ // distance calculations
const distance_x: f32 = @floatFromInt(p.pos.x - p2.pos.x);
const distance_y: f32 = @floatFromInt(p.pos.y - p2.pos.y);
var distance = @sqrt(distance_x * distance_x + distance_y * distance_y);
if (distance == 0) distance = 0.01;
+ // force calculations
const f = -force(distance, floatRadius, rules[p.colorId][p2.colorId]);
forceX += (distance_x / distance) * f;
forceY += (distance_y / distance) * f;
}
+ // update velocity
forceX = forceX * floattMinDistance / floatRadius;
- // forceX = std.math.clamp(forceX, -10.0, 10.0);
forceY = forceY * floattMinDistance / floatRadius;
- // forceY = std.math.clamp(forceY, -10.0, 10.0);
- p.xvel *= cfg.friction ;
+ p.xvel *= cfg.friction;
p.xvel += forceX;
p.yvel *= cfg.friction;
p.yvel += forceY;
@@ -60,18 +61,15 @@ pub fn updateVelocities(
}
/// Applies the particles velocity and updates position
-pub fn updatePosition(particles: *std.ArrayList(particle)) void {
+pub fn updatePosition(particles: *std.array_list.Managed(particle)) void {
for (particles.items) |*p| {
- const maxVel: f32 = 4096.0;
- const posYplusVel: f32 = @as(f32, @floatFromInt(p.pos.y)) + std.math.clamp(p.yvel, -maxVel, maxVel);
- const posXplusVel: f32 = @as(f32, @floatFromInt(p.pos.x)) + std.math.clamp(p.xvel, -maxVel, maxVel);
- p.pos.y = @mod(@as(i32, @intFromFloat(posYplusVel)), rl.getScreenHeight());
- p.pos.x = @mod(@as(i32, @intFromFloat(posXplusVel)), rl.getScreenWidth());
+ p.pos.y = @mod(@as(i32, @intFromFloat(@round(@as(f32, @floatFromInt(p.pos.y)) + (@as(f32, @floatFromInt(cfg.speed[p.colorId])) / 1000.0) * p.yvel))), rl.getScreenHeight());
+ p.pos.x = @mod(@as(i32, @intFromFloat(@round(@as(f32, @floatFromInt(p.pos.x)) + (@as(f32, @floatFromInt(cfg.speed[p.colorId])) / 1000.0) * p.xvel))), rl.getScreenWidth());
}
}
/// Draw the particles onto the screen using raylib
-pub fn draw(particles: std.ArrayList(particle)) void {
+pub fn draw(particles: std.array_list.Managed(particle)) void {
for (particles.items) |p|
rl.drawRectangle(p.pos.x, p.pos.y, 5, 5, cfg.colors[p.colorId]);
}
@@ -88,7 +86,7 @@ fn force(distance: f32, radius: f32, attraction: f32) f32 {
pub fn createParticle() particle {
const seed = @as(u64, @truncate(@as(u128, @bitCast(std.time.nanoTimestamp()))));
- var prng = std.rand.DefaultPrng.init(seed);
+ var prng = std.Random.DefaultPrng.init(seed);
const x = prng.random().uintLessThan(u32, @intCast(rl.getScreenWidth()));
const y = prng.random().uintLessThan(u32, @intCast(rl.getScreenHeight()));
const color = prng.random().uintLessThan(u32, cfg.colorAmnt);
diff --git a/src/quad.zig b/src/quad.zig
index 0d4174e..db24589 100644
--- a/src/quad.zig
+++ b/src/quad.zig
@@ -16,17 +16,17 @@ pub fn Node(T: type) type {
pub fn Quad(T: type, comptime splitLimit: usize) type {
return struct {
allocator: std.mem.Allocator,
- nodes: ?std.BoundedArray(Node(T), splitLimit),
+ nodes: ?std.ArrayList(Node(T)),
topLeft: Point,
bottomRight: Point,
children: [4]?*Quad(T, splitLimit),
const Self = @This();
- pub fn init(allocator: std.mem.Allocator, tl: Point, br: Point) Quad(T, splitLimit) {
+ pub fn init(allocator: std.mem.Allocator, tl: Point, br: Point) !Self {
return Quad(T, splitLimit){
.allocator = allocator,
- .nodes = std.BoundedArray(Node(T), splitLimit).init(0) catch unreachable,
+ .nodes = try std.ArrayList(Node(T)).initCapacity(allocator, splitLimit),
.topLeft = tl,
.bottomRight = br,
.children = [4]?*Quad(T, splitLimit){ null, null, null, null },
@@ -89,8 +89,8 @@ pub fn Quad(T: type, comptime splitLimit: usize) type {
3 => self.bottomRight,
else => unreachable,
};
- self.children[quadrant] = try self.allocator.create(Quad(T, splitLimit));
- self.children[quadrant].?.* = Quad(T, splitLimit).init(self.allocator, tl, br);
+ self.children[quadrant] = try self.allocator.create(Self);
+ self.children[quadrant].?.* = try Self.init(self.allocator, tl, br);
}
fn split(self: *Quad(T, splitLimit)) !void {
@@ -98,7 +98,7 @@ pub fn Quad(T: type, comptime splitLimit: usize) type {
for (0..4) |i|
if (self.children[i] == null)
try self.createChild(i);
- const nodesToRedistribute = self.nodes.?.slice();
+ const nodesToRedistribute = self.nodes.?.items;
for (nodesToRedistribute) |node| {
const quadrant = self.getQuadrant(node.pos);
try self.children[quadrant].?.insert(node);
@@ -116,7 +116,7 @@ pub fn Quad(T: type, comptime splitLimit: usize) type {
return;
}
if (self.nodes) |*nodes| {
- nodes.append(node) catch {
+ nodes.appendBounded(node) catch {
try self.split();
const quadrant = self.getQuadrant(node.pos);
try self.children[quadrant].?.insert(node);
@@ -128,7 +128,7 @@ pub fn Quad(T: type, comptime splitLimit: usize) type {
if (!self.inBoundry(p)) return null;
if (self.nodes) |nodes| {
- for (nodes.slice()) |node|
+ for (nodes.items) |node|
if (node.pos.x == p.x and node.pos.y == p.y)
return node;
return null;
@@ -144,9 +144,9 @@ pub fn Quad(T: type, comptime splitLimit: usize) type {
if (!self.intersectsCircle(center, radius)) return;
if (self.nodes) |nodes| {
- for (nodes.slice()) |node|
+ for (nodes.items) |node|
if (locationInRadius(center, node.pos, radius)) {
- try results.append(node.data);
+ try results.appendBounded(node.data);
};
return;
}
@@ -245,7 +245,9 @@ pub fn Quad(T: type, comptime splitLimit: usize) type {
return self.inRadius(center, radius) or self.inBoundry(center);
}
- pub fn deinit(self: *Quad(T, splitLimit)) void {
+ pub fn deinit(self: *Self) void {
+ if (self.nodes) |*n|
+ n.deinit(self.allocator);
for (self.children) |child| {
if (child) |c| {
c.deinit();
diff --git a/src/rules.zig b/src/rules.zig
index 4e513eb..fac1999 100644
--- a/src/rules.zig
+++ b/src/rules.zig
@@ -4,7 +4,7 @@ const std = @import("std");
/// Generate the set of rules the particles will abide by
pub fn ruleMatrix(radius: bool, speed: bool) [cfg.colorAmnt][cfg.colorAmnt]f32 {
const seed = @as(u64, @truncate(@as(u128, @bitCast(std.time.nanoTimestamp()))));
- var prng = std.rand.DefaultPrng.init(seed);
+ var prng = std.Random.DefaultPrng.init(seed);
var rules: [cfg.colorAmnt][cfg.colorAmnt]f32 = undefined;
for (0..cfg.colorAmnt) |i| {
for (0..cfg.colorAmnt) |j| {
@@ -39,36 +39,37 @@ pub fn printRules(rules: [cfg.colorAmnt][cfg.colorAmnt]f32) void {
/// Loads rules from a csv
pub fn loadRules(allocator: std.mem.Allocator, absolutePath: [:0]u8) !void {
+ var buffer: [256]u8 = undefined;
const file = try std.fs.openFileAbsoluteZ(absolutePath, .{ .mode = .read_only });
defer file.close();
- var reader = file.reader();
+ var reader = file.reader(&buffer).interface;
for (&cfg.rules) |*row| {
for (row) |*col| {
- const buf = try reader.readUntilDelimiterAlloc(allocator, ',', 16);
+ const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
col.* = try std.fmt.parseFloat(f32, buf);
}
- try reader.skipBytes(1, .{});
+ reader.toss(1);
}
for (&cfg.speed) |*s| {
- const buf = try reader.readUntilDelimiterAlloc(allocator, ',', 16);
+ const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
s.* = try std.fmt.parseInt(i32, buf, 10);
}
- try reader.skipBytes(1, .{});
+ reader.toss(1);
for (&cfg.radius) |*r| {
- const buf = try reader.readUntilDelimiterAlloc(allocator, ',', 16);
+ const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
r.* = try std.fmt.parseInt(i32, buf, 10);
}
- try reader.skipBytes(1, .{});
+ reader.toss(1);
{
- const buf = try reader.readUntilDelimiterAlloc(allocator, ',', 16);
+ const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
cfg.minDistance = try std.fmt.parseInt(i32, buf, 10);
}
{
- const buf = try reader.readUntilDelimiterAlloc(allocator, ',', 16);
+ const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
cfg.friction = try std.fmt.parseFloat(f32, buf);
}
@@ -76,9 +77,10 @@ pub fn loadRules(allocator: std.mem.Allocator, absolutePath: [:0]u8) !void {
/// Save rules to a csv
pub fn saveRules(absolutePath: [:0]u8) !void {
+ var buffer: [256]u8 = undefined;
const file = try std.fs.createFileAbsoluteZ(absolutePath, .{ .read = true });
defer file.close();
- var writer = file.writer();
+ var writer = file.writer(&buffer).interface;
for (cfg.rules) |row| {
for (row) |col| {
try writer.print("{d:.3},", .{col});
@@ -112,16 +114,16 @@ pub inline fn colorToString(c: usize) []const u8 {
};
}
-pub inline fn colorToStringZ(c: usize) [:0]const u8 {
+pub inline fn colorToStringZ(c: usize, comptime prepend: []const u8, comptime append: []const u8) [:0]const u8 {
return switch (c) {
- 0 => "Red",
- 1 => "Green",
- 2 => "Blue",
- 3 => "Yellow",
- 4 => "Magenta",
- 5 => "Brown",
- 6 => "Orange",
- 7 => "Gray",
+ 0 => prepend ++ "Red" ++ append,
+ 1 => prepend ++ "Green" ++ append,
+ 2 => prepend ++ "Blue" ++ append,
+ 3 => prepend ++ "Yellow" ++ append,
+ 4 => prepend ++ "Magenta" ++ append,
+ 5 => prepend ++ "Brown" ++ append,
+ 6 => prepend ++ "Orange" ++ append,
+ 7 => prepend ++ "Gray" ++ append,
else => " ",
};
}
diff --git a/vendor/rlImGui b/vendor/rlImGui
new file mode 160000
+Subproject 4d8a61842903978bc42adf3347cd34f4e6524ef
diff --git a/vendor/zgui b/vendor/zgui
deleted file mode 160000
-Subproject 7fa8081c208885b85e3fdfc043cd9d9cb955912