summaryrefslogtreecommitdiff
path: root/examples/graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/graph.c')
-rwxr-xr-xexamples/graph.c218
1 files changed, 205 insertions, 13 deletions
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();
}