From ccbf7344b53597e6011acd6bdc2febca1944c7f8 Mon Sep 17 00:00:00 2001 From: Marto Date: Tue, 28 Apr 2026 22:11:35 +0200 Subject: [PATCH] Basic drawing --- src/constants.zig | 13 ++++++++++ src/infrastructure/node.zig | 22 +++++++++++++++++ src/infrastructure/node_manager.zig | 37 +++++++++++++++++++++++++++-- src/infrastructure/road_manager.zig | 24 +++++++++++++++++++ src/main.zig | 1 + src/simulator.zig | 27 ++++++++++++++++++++- 6 files changed, 121 insertions(+), 3 deletions(-) diff --git a/src/constants.zig b/src/constants.zig index a27c27d..969c55d 100644 --- a/src/constants.zig +++ b/src/constants.zig @@ -1,12 +1,25 @@ const clr = @import("raylib").Color; +/// Screen Width pub const WIDTH = 2560; +/// Screen Height pub const HEIGHT = 1440; +/// Base node radius pub const NODE_RADIUS = 20; + +/// The radius around node center where no new node gets created but rather it snaps onto existing one +pub const NODE_SNAP_RADIUS = 3 * NODE_RADIUS; +/// Regular (finished) node colour pub const NODE_COLOUR = clr.brown; +/// Temporary node colour - currently being pulled from pub const NODE_TEMP_COLOUR = clr.orange; +/// The colour of the node being at the cursor pub const NODE_CURSOR_COLOUR = clr.blue; +/// Road (line) size pub const ROAD_SIZE = 20; +/// Regular road colour pub const ROAD_COLOUR = clr.black; +/// Colour of the road that is highlighted +pub const ROAD_HIGHLIGHTED_COLOUR = clr.green; diff --git a/src/infrastructure/node.zig b/src/infrastructure/node.zig index 4292e65..716a166 100644 --- a/src/infrastructure/node.zig +++ b/src/infrastructure/node.zig @@ -1,21 +1,43 @@ +const std = @import("std"); const rl = @import("raylib"); const c = @import("../constants.zig"); +const Road = @import("road.zig").Road; pub const Node = struct { id: usize, pos: rl.Vector2, + roads: std.ArrayList(*Road), pub fn init(new_id: usize, new_pos: rl.Vector2) Node { return .{ .id = new_id, .pos = new_pos, + .roads = .empty, }; } + pub fn deinit(self: *Node, allocator: std.mem.Allocator) void { + self.roads.deinit(allocator); + } + pub fn draw(self: *const Node, direct_colour: ?rl.Color) void { const colour = if (direct_colour) |clr| clr else c.NODE_COLOUR; rl.drawCircleV(self.pos, c.NODE_RADIUS, colour); } + + pub fn posWithinRadius(self: *const Node, pos: rl.Vector2) bool { + return rl.checkCollisionPointCircle(pos, self.pos, c.NODE_SNAP_RADIUS); + } + + + pub fn referenceRoad(self: *Node, allocator: std.mem.Allocator, road_to_add: *Road) !void { + // Note the road_to_add pointer must be one from the roads list as otherwise the pointer is dangling one + for (self.roads.items) |road| { + if (road.*.id == road_to_add.*.id) return error.RoadAlreadyReferenced; + } + + try self.roads.append(allocator, road_to_add); + } }; \ No newline at end of file diff --git a/src/infrastructure/node_manager.zig b/src/infrastructure/node_manager.zig index c0a6687..6f4939f 100644 --- a/src/infrastructure/node_manager.zig +++ b/src/infrastructure/node_manager.zig @@ -6,28 +6,33 @@ const Node = @import("node.zig").Node; const Road = @import("road.zig").Road; pub const NodeManager = struct { + next_id: usize, nodes: std.ArrayList(Node), temp_node: ?*Node, pub fn init() NodeManager { return .{ + .next_id = 0, .nodes = .empty, .temp_node = null, }; } pub fn deinit(self: *NodeManager, allocator: std.mem.Allocator) void { + for (self.nodes.items) |*node| { + node.deinit(allocator); + } self.nodes.deinit(allocator); } pub fn draw(self: *const NodeManager, pos: Vector2) void { for (self.nodes.items) |node| { - node.draw(); + node.draw(null); } if (self.temp_node) |node| { // Temporary node that points at the cursor - const cur_node = Node.init(0, pos); + var cur_node = Node.init(0, pos); // Temporary road that is to be drawn as one in the making const road: Road = .init(0, node, &cur_node); road.draw(); @@ -36,4 +41,32 @@ pub const NodeManager = struct { cur_node.draw(c.NODE_CURSOR_COLOUR); } } + + pub fn getSelectedNode(self: *NodeManager, allocator: std.mem.Allocator, pos: Vector2) !*Node { + for (self.nodes.items) |*node| { + if (node.posWithinRadius(pos)) return node; + } + + // No node is within that position, so we must create a new one + const node: Node = .init(self.getNextID(), pos); + try self.nodes.append(allocator, node); + + return &self.nodes.items[self.nodes.items.len - 1]; + } + + fn getNextID(self: *NodeManager) usize { + const id = self.next_id; + self.next_id += 1; + + return id; + } + + pub fn clear(self: *NodeManager, allocator: std.mem.Allocator) void { + self.temp_node = null; + for (self.nodes.items) |*node| { + node.deinit(allocator); + } + self.nodes.clearRetainingCapacity(); + self.next_id = 0; + } }; \ No newline at end of file diff --git a/src/infrastructure/road_manager.zig b/src/infrastructure/road_manager.zig index 1784cfc..065a9af 100644 --- a/src/infrastructure/road_manager.zig +++ b/src/infrastructure/road_manager.zig @@ -1,11 +1,14 @@ const std = @import("std"); const Road = @import("road.zig").Road; +const Node = @import("node.zig").Node; pub const RoadManager = struct { + next_id: usize, roads: std.ArrayList(Road), pub fn init() RoadManager { return .{ + .next_id = 0, .roads = .empty, }; } @@ -19,4 +22,25 @@ pub const RoadManager = struct { road.draw(); } } + + pub fn addRoad(self: *RoadManager, allocator: std.mem.Allocator, start: *Node, end: *Node) !void { + const road: Road = .init(self.getNextID(), start, end); + try self.roads.append(allocator, road); + + const ref = &self.roads.items[self.roads.items.len - 1]; + try ref.*.nodes[0].referenceRoad(allocator, ref); + try ref.*.nodes[1].referenceRoad(allocator, ref); + } + + fn getNextID(self: *RoadManager) usize { + const id = self.next_id; + self.next_id += 1; + + return id; + } + + pub fn clear(self: *RoadManager) void { + self.roads.clearRetainingCapacity(); + self.next_id = 0; + } }; \ No newline at end of file diff --git a/src/main.zig b/src/main.zig index 9501ef4..593f732 100644 --- a/src/main.zig +++ b/src/main.zig @@ -10,6 +10,7 @@ pub fn main(init: std.process.Init) !void { defer rl.closeWindow(); var sim: Simulator = .init(allocator); + defer sim.deinit(); while (!rl.windowShouldClose()) { rl.beginDrawing(); diff --git a/src/simulator.zig b/src/simulator.zig index 7a1b427..af517f0 100644 --- a/src/simulator.zig +++ b/src/simulator.zig @@ -30,14 +30,39 @@ pub const Simulator = struct { } pub fn handleInput(self: *Simulator, pos: rl.Vector2) void { + self.handleKeyboardInput(); self.handleMouseInput(pos); } + fn handleKeyboardInput(self: *Simulator) void { + if (rl.isKeyReleased(.c)) self.clear(); + } + fn handleMouseInput(self: *Simulator, pos: rl.Vector2) void { if (rl.isMouseButtonReleased(.left)) self.leftClickEvent(pos); } fn leftClickEvent(self: *Simulator, pos: rl.Vector2) void { - // TODO + const cur_node = self.node_man.getSelectedNode(self.allocator, pos) catch |err| { + std.debug.panic("Failed to append the newly created node at pos ({d}, {d}) to node list: {}\n", .{ + pos.x, pos.y, err + }); + }; + + if (self.node_man.temp_node) |temp| { + self.road_man.addRoad(self.allocator, temp, cur_node) catch |err| { + std.debug.panic("Failed to add a new road or assigning its nodes: {}\n", .{err}); + }; + + self.node_man.temp_node = null; + return; + } + + self.node_man.temp_node = cur_node; + } + + fn clear(self: *Simulator) void { + self.road_man.clear(); + self.node_man.clear(self.allocator); } }; \ No newline at end of file