From e252c5b01e0c42902bedf3537852a74232fed2cf Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Sat, 5 Oct 2024 19:34:38 +0200 Subject: Update graph example --- examples/graph.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 205 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/examples/graph.c b/examples/graph.c index c7b2877..7f9870f 100755 --- a/examples/graph.c +++ b/examples/graph.c @@ -27,6 +27,167 @@ exit $? # */ #include "../graphics.c" +enum { + MAX_NUM_NODES = 1024, + MAX_NUM_EDGES = 1024, +}; + +typedef struct { + b8 enabled; + f64 x; + f64 y; + f64 radius; + b8 hover; +} Node; + +typedef struct { + b8 enabled; + i64 src; + i64 dst; + f64 width; + b8 hover; +} Edge; + +typedef struct { + Node nodes[MAX_NUM_NODES]; + Edge edges[MAX_NUM_EDGES]; +} World; + +World world = {0}; + +b8 check_node_index(i64 node_index) { + return + node_index >= 0 && node_index < MAX_NUM_NODES + && world.nodes[node_index].enabled; +} + +b8 check_edge_index(i64 edge_index) { + return + edge_index >= 0 && edge_index < MAX_NUM_EDGES + && world.edges[edge_index].enabled + && check_node_index(world.edges[edge_index].src) + && check_node_index(world.edges[edge_index].dst); +} + +void draw_node(i64 node_index) { + assert(check_node_index(node_index)); + + Node n = world.nodes[node_index]; + + u32 color = 0; // black color + + if (n.hover) + color = 0x007f00; // green color + + fill_ellipse( + OP_SET, // set pixels + color, + n.x - n.radius, + n.y - n.radius, + n.radius * 2, + n.radius * 2 + ); +} + +void draw_edge(i64 edge_index) { + assert(check_edge_index(edge_index)); + + Edge e = world.edges[edge_index]; + Node n0 = world.nodes[e.src]; + Node n1 = world.nodes[e.dst]; + + u32 color = 0x7f7f7f; // grey color + + if (e.hover) + color = 0x007f00; // green color + + fill_line( + OP_SET, // set pixels + color, + n0.x, + n0.y, + n1.x, + n1.y, + e.width + ); +} + +void draw_graph(void) { + // draw all edges + for (i64 i = 0; i < MAX_NUM_EDGES; ++i) + if (world.edges[i].enabled) + draw_edge(i); + + // draw all nodes + for (i64 i = 0; i < MAX_NUM_NODES; ++i) + if (world.nodes[i].enabled) + draw_node(i); +} + +void update_node(i64 node_index) { + assert(check_node_index(node_index)); + + Node n = world.nodes[node_index]; + + f64 cx = platform.cursor_x - n.x; + f64 cy = platform.cursor_y - n.y; + + world.nodes[node_index].hover = cx * cx + cy * cy <= n.radius * n.radius; +} + +void update_edge(i64 edge_index) { + assert(check_edge_index(edge_index)); + + Edge e = world.edges[edge_index]; + Node n0 = world.nodes[e.src]; + Node n1 = world.nodes[e.dst]; + + f64 cx = platform.cursor_x - n0.x; + f64 cy = platform.cursor_y - n0.y; + + // normalized line direction vector + f64 rx = n1.x - n0.x; + f64 ry = n1.y - n0.y; + f64 r = sqrt(rx * rx + ry * ry); + if (r >= EPSILON) { + rx /= r; + ry /= r; + } + + // tangent + f64 tx = -ry; + f64 ty = rx; + + // distance to the line (dot-product) + f64 d = cx * tx + cy * ty; + + // distance to the tangent line + f64 l = cx * rx + cy * ry; + + world.edges[edge_index].hover = d <= e.width / 2 && d >= -e.width / 2 && l >= 0 && l <= r; +} + +void update_graph(void) { + b8 hover_node = 0; + + // update all nodes + for (i64 i = 0; i < MAX_NUM_NODES; ++i) + if (world.nodes[i].enabled) { + update_node(i); + if (world.nodes[i].hover) + hover_node = 1; + } + + // update all edges + for (i64 i = 0; i < MAX_NUM_EDGES; ++i) + if (world.edges[i].enabled) { + if (hover_node) + world.edges[i].hover = 0; + else + update_edge(i); + } +} + i32 main(i32 argc, c8 **argv) { (void) argc; (void) argv; @@ -37,26 +198,57 @@ i32 main(i32 argc, c8 **argv) { .frame_height = 720, }; - u32 WHITE = u32_from_rgb(1.f, 1.f, 1.f); - u32 BLACK = u32_from_rgb(0.f, 0.f, 0.f); - u32 RED = u32_from_rgb(1.f, 0.f, 0.f); - u32 BLUE = u32_from_rgb(0.f, 0.f, 1.f); - p_init(); - while (!platform.done) { - p_wait_events(); + world.nodes[0] = (Node) { + .enabled = 1, + .x = 100, + .y = 100, + .radius = 50, + }; + + world.nodes[1] = (Node) { + .enabled = 1, + .x = 300, + .y = 100, + .radius = 50, + }; + + world.nodes[2] = (Node) { + .enabled = 1, + .x = 120, + .y = 300, + .radius = 60, + }; - i64 x = platform.frame_width / 2; - i64 y = platform.frame_height / 2; + world.edges[0] = (Edge) { + .enabled = 1, + .src = 0, + .dst = 1, + .width = 30, + }; - fill_rectangle(OP_SET, WHITE, 0, 0, platform.frame_width, platform.frame_height); + world.edges[1] = (Edge) { + .enabled = 1, + .src = 0, + .dst = 2, + .width = 30, + }; - fill_triangle(OP_SET, RED, 100, 100, 200, 100, 150, 200); + world.edges[2] = (Edge) { + .enabled = 1, + .src = 1, + .dst = 2, + .width = 30, + }; + + while (!platform.done) { + p_wait_events(); - fill_line(OP_SET, BLUE, 100, 300, 300, 500, 30); + fill_rectangle(OP_SET, 0xffffff, 0, 0, platform.frame_width, platform.frame_height); - fill_ellipse(OP_SET, BLACK, x - 140, y - 100, 280, 200); + update_graph(); + draw_graph(); p_render_frame(); } -- cgit v1.2.3