abg

Animated background for X11
git clone git://git.laack.co/abg.git
Log | Files | Refs | README

commit 8902403ef922e56940d622e0d146739edb339a85
parent edc5f44246df080f7ded88bf50bb9e15ecf1ea5e
Author: Andrew Laack <andrew@laack.co>
Date:   Mon, 14 Sep 2026 21:22:00 -0500

Refactored c++ approach with raylib

Diffstat:
Mbackground/Makefile | 4+---
Dbackground/draw.c | 31-------------------------------
Dbackground/draw.h | 4----
Dbackground/edge.c | 27---------------------------
Abackground/edge.cpp | 16++++++++++++++++
Dbackground/edge.h | 11-----------
Abackground/edge.hpp | 17+++++++++++++++++
Abackground/graph.cpp | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abackground/graph.hpp | 21+++++++++++++++++++++
Dbackground/main.c | 30------------------------------
Abackground/main.cpp | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abackground/old/Makefile | 4++++
Abackground/old/draw.c | 38++++++++++++++++++++++++++++++++++++++
Abackground/old/draw.h | 4++++
Abackground/old/edge.cpp | 28++++++++++++++++++++++++++++
Abackground/old/edge.hpp | 21+++++++++++++++++++++
Abackground/old/main.cpp | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rbackground/util.c -> background/old/util.c | 0
Rbackground/util.h -> background/old/util.h | 0
Abackground/old/vert.c | 33+++++++++++++++++++++++++++++++++
Abackground/old/vert.h | 14++++++++++++++
Abackground/utils.cpp | 20++++++++++++++++++++
Abackground/utils.hpp | 9+++++++++
Dbackground/vert.c | 26--------------------------
Dbackground/vert.h | 8--------
Abackground/vertex.cpp | 21+++++++++++++++++++++
Abackground/vertex.hpp | 14++++++++++++++
27 files changed, 602 insertions(+), 140 deletions(-)

diff --git a/background/Makefile b/background/Makefile @@ -1,4 +1,2 @@ -clean: - rm a.out build: - g++ main.c draw.c vert.c edge.c util.c -lraylib + g++ main.cpp graph.cpp edge.cpp utils.cpp vertex.cpp -lraylib diff --git a/background/draw.c b/background/draw.c @@ -1,31 +0,0 @@ -#include "raylib.h" -#include "edge.h" -#include <stdio.h> - -#define VERTEX_SIZE 5 - -void draw_edges(Edge* edges, int length) { - for(int i = 0; i < length; ++i) { - Edge e = edges[i]; - - Vertex v1 = *e.v1; - Vertex v2 = *e.v2; - - // TODO: Convert this to a function. - Vector2 v1_p; - v1_p.x = v1.x; - v1_p.y = v1.y; - Vector2 v2_p; - v2_p.x = (float)v2.x; - v2_p.y = (float)v2.y; - DrawLineEx(v1_p, v2_p, 1,DARKGRAY); - } -} - -void draw_vertices(Vertex* vertices, int length) { - for(int i = 0; i < length; ++i) { - Vertex v = vertices[i]; - DrawCircle(v.x,v.y,VERTEX_SIZE, WHITE); - } -} - diff --git a/background/draw.h b/background/draw.h @@ -1,4 +0,0 @@ -#include "edge.h" - -void draw_vertices(Vertex* vertices, int length); -void draw_edges(Edge* edges, int length); diff --git a/background/edge.c b/background/edge.c @@ -1,27 +0,0 @@ -#include "edge.h" -#include "util.h" -#include <stdlib.h> -#include <stdio.h> - -void print_edge(Edge *e) { - printf("v1.x = %i, v1.y = %i\nv2.x = %i, v2.y = %i", e->v1->x, e->v1->y, e->v2->x, e->v2->y); -} - -Edge gen_edge(int idx1, int idx2, Vertex* vertices) { - Edge e; - e.v1 = &vertices[idx1]; - e.v2 = &vertices[idx2]; - return e; -} - -Edge* gen_edges(Vertex* vertices, int vtCount, int edgeCount) { - Edge* edges = (Edge*)malloc(sizeof(Edge) * edgeCount); - for(int i = 0; i < edgeCount; ++i) { - int idx1 = choose_random(vtCount); - int idx2 = choose_random(vtCount); - Edge e = gen_edge(idx1,idx2, vertices); - edges[i] = e; - } - return edges; - -} diff --git a/background/edge.cpp b/background/edge.cpp @@ -0,0 +1,16 @@ +#include "edge.hpp" + +Edge::Edge(std::size_t v1, std::size_t v2, float length2) + : v1Index(v1), v2Index(v2), length2(length2) {} + +std::string Edge::toString() { + return "(" + std::to_string(this->v1Index) + ", " + std::to_string(this->v2Index) + ")"; +} + +bool Edge::operator<(const Edge& other) const { + return length2 < other.length2; +} + +bool Edge::operator>(const Edge& other) const { + return length2 > other.length2; +} diff --git a/background/edge.h b/background/edge.h @@ -1,11 +0,0 @@ -#include "vert.h" - -typedef struct Edge { - Vertex* v1; - Vertex* v2; - -} Edge; - -Edge gen_edge(int idx1, int idx2, Vertex* vertices); -Edge* gen_edges(Vertex* vertices, int vtCount, int edgeCount); -void print_edge(Edge* e); diff --git a/background/edge.hpp b/background/edge.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include <cstddef> +#include <string> + +class Edge { + public: + // indices of v1 and v2 + Edge(std::size_t v1, std::size_t v2, float length2); + std::size_t v1Index; + std::size_t v2Index; + float length2; + bool traversed = false; + std::string toString(); + bool operator<(const Edge& other) const; + bool operator>(const Edge& other) const; +}; diff --git a/background/graph.cpp b/background/graph.cpp @@ -0,0 +1,119 @@ +#include "graph.hpp" +#include "vertex.hpp" +#include "utils.hpp" +#include <cstddef> +#include <raylib.h> +#include <iostream> + +Graph::Graph(std::size_t edgeCount, std::size_t vertCount, float xMax, float yMax) { + for(std::size_t i = 0; i < vertCount; ++i) { + Vector2 rnd = randomPosition(xMax, yMax); + Vertex v {rnd,5}; + this->vertices.push_back(v); + } + for(std::size_t i = 0; i < edgeCount; ++i) { + std::size_t idx1 = 0; + std::size_t idx2 = 0; + // no self-edges + while (idx1 == idx2) { + idx1 = std::rand() % vertCount; + idx2 = std::rand() % vertCount; + } + + Edge e {idx1, idx2, distanceSquared(vertices[idx1].position, vertices[idx2].position)}; + this->edges[idx1].push_back(e); + this->edges[idx2].push_back(e); + } +} + +std::string Graph::toString() { + + std::string result = "edges: {"; + + for(auto pair: this->edges) { + auto key = pair.first; + for(auto edge: edges[key]) { + result += edge.toString(); + } + } + + result += "}"; + + result += "\nvertices: {"; + + for(auto vertex: this->vertices) { + result += vertex.toString(); + } + + result += "}"; + return result; +} + + +void Graph::render() { + // yes, this will double draw because we track 0 -> 1 and 1 -> 0 + + std::vector<Edge> visited {}; + for(auto pair: this->edges) { + auto edges = this->edges[pair.first]; + for(auto edge: edges) { + std::size_t idx1 = edge.v1Index; + std::size_t idx2 = edge.v2Index; + auto v1 = vertices[idx1].position; + auto v2 = vertices[idx2].position; + if(edge.traversed) { + visited.push_back(edge); + } else { + DrawLineEx(v1, v2, 1,DARKERGRAY); + } + } + } + + // ensure we draw visited over unvisited for better looks + for(auto edge: visited) { + std::size_t idx1 = edge.v1Index; + std::size_t idx2 = edge.v2Index; + auto v1 = vertices[idx1].position; + auto v2 = vertices[idx2].position; + DrawLineEx(v1, v2, 1, WHITE); + } + + for(auto vertex: this->vertices) { + vertex.render(); + } +} + +void Graph::traverseVertexIdx(std::size_t idx) { + this->vertices[idx].visited = true; +} + +std::vector<Edge> Graph::getEdgesOfVertexIdx(std::size_t idx) { + return this->edges[idx]; +} + +void Graph::setEdgeTraversed(Edge e) { + + std::size_t source = e.v1Index; + std::size_t destination = e.v2Index; + + if(source == destination) { + return; + } + + auto& cEdges = edges[source]; + + for(auto& edge : cEdges) { + if(edge.v2Index == destination || edge.v1Index == destination) { + edge.traversed = true; + } + } + + auto& oEdges = edges[destination]; + + for(auto& edge : oEdges) { + if(edge.v2Index == source || edge.v1Index == source) { + edge.traversed = true; + } + } + +} diff --git a/background/graph.hpp b/background/graph.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <string> +#include <unordered_map> +#include <vector> +#include "edge.hpp" +#include "vertex.hpp" + +class Graph { + private: + std::unordered_map<std::size_t, std::vector<Edge>> edges {}; + std::vector<Vertex> vertices {}; + public: + // based on the edgeCount and vertCount, random edges and vertices will be created. + Graph(std::size_t edgeCount, std::size_t vertCount, float xMax, float yMax); + std::string toString(); + void render(); + void traverseVertexIdx(std::size_t idx); + std::vector<Edge> getEdgesOfVertexIdx(std::size_t idx); + void setEdgeTraversed(Edge e); +}; diff --git a/background/main.c b/background/main.c @@ -1,30 +0,0 @@ -#include "raylib.h" -#include <stdlib.h> -#include <time.h> -#include "draw.h" - -#define VERTICES 100 -#define EDGES 1000 - -int main(void) -{ - - srand(time(0)); - InitWindow(5120, 1440, "Raylib background animation window"); - - while (!WindowShouldClose()) - { - Vertex* vertices = gen_vertices(VERTICES); - Edge* edges = gen_edges(vertices, VERTICES, EDGES); - BeginDrawing(); - ClearBackground(BLACK); - draw_edges(edges,EDGES); - draw_vertices(vertices,VERTICES); - EndDrawing(); - free(vertices); - free(edges); - } - - CloseWindow(); - return 0; -} diff --git a/background/main.cpp b/background/main.cpp @@ -0,0 +1,87 @@ +#include "graph.hpp" +#include <unistd.h> +#include <raylib.h> +#include <ctime> +#include <queue> +#include <unordered_set> + +int main() { + srand(clock()); + + std::size_t edgeCount = 2000; + std::size_t vertCount = 200; + + float xMax = 5120; + float yMax = 1440; + + + InitWindow(xMax, yMax, "Raylib animation window"); + + while (!WindowShouldClose()) { + + Graph g = Graph(edgeCount, vertCount, xMax,yMax); + std::unordered_set<std::size_t> visitedIndices {}; + std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> toVisit {}; + std::vector<Edge> edges = g.getEdgesOfVertexIdx(0); + + for(auto edge: edges) { + toVisit.push(edge); + } + + g.traverseVertexIdx(0); + visitedIndices.insert(0); + + + + while (!WindowShouldClose()) { + + BeginDrawing(); + ClearBackground(BLACK); + g.render(); + EndDrawing(); + + bool found = false; + if(toVisit.size() == 0) { + break; + } + while(found == false) { + if(toVisit.size() == 0) { + break; + } + + found = true; + auto current = toVisit.top(); + toVisit.pop(); + + if(visitedIndices.find(current.v2Index) == visitedIndices.end()) { + auto cIdx = current.v2Index; + visitedIndices.insert(current.v2Index); + g.traverseVertexIdx(cIdx); + // TODO: Make this a function. + std::vector<Edge> edges = g.getEdgesOfVertexIdx(cIdx); + for(auto edge: edges) { + toVisit.push(edge); + } + g.setEdgeTraversed(current); + + } else if(visitedIndices.find(current.v1Index) == visitedIndices.end()) { + auto cIdx = current.v1Index; + visitedIndices.insert(current.v1Index); + g.traverseVertexIdx(cIdx); + // TODO: Make this a function. + std::vector<Edge> edges = g.getEdgesOfVertexIdx(cIdx); + for(auto edge: edges) { + toVisit.push(edge); + } + g.setEdgeTraversed(current); + } else { + found = false; + } + + } + + } + + } + +} diff --git a/background/old/Makefile b/background/old/Makefile @@ -0,0 +1,4 @@ +clean: + rm a.out +build: + g++ main.cpp draw.c vert.c edge.cpp util.c -lraylib diff --git a/background/old/draw.c b/background/old/draw.c @@ -0,0 +1,38 @@ +#include "raylib.h" +#include "edge.hpp" + +#define VERTEX_SIZE 5 + +void draw_edges(Edge* edges, int length) { + for(int i = 0; i < length; ++i) { + Edge e = edges[i]; + + Vertex v1 = *e.v1; + Vertex v2 = *e.v2; + + // TODO: Convert this to a function. + Vector2 v1_p; + v1_p.x = v1.x; + v1_p.y = v1.y; + Vector2 v2_p; + v2_p.x = (float)v2.x; + v2_p.y = (float)v2.y; + if(e.traversed == true) { + DrawLineEx(v1_p, v2_p, 1,WHITE); + } else { + DrawLineEx(v1_p, v2_p, 1,DARKGRAY); + } + } +} + +void draw_vertices(Vertex* vertices, int length) { + for(int i = 0; i < length; ++i) { + Vertex v = vertices[i]; + if(v.visited) { + DrawCircle(v.x,v.y,VERTEX_SIZE, WHITE); + } else { + DrawCircle(v.x,v.y,VERTEX_SIZE, GRAY); + } + } +} + diff --git a/background/old/draw.h b/background/old/draw.h @@ -0,0 +1,4 @@ +#include "edge.hpp" + +void draw_vertices(Vertex* vertices, int length); +void draw_edges(Edge* edges, int length); diff --git a/background/old/edge.cpp b/background/old/edge.cpp @@ -0,0 +1,28 @@ +#include "edge.hpp" +#include "util.h" +#include <stdlib.h> +#include <stdio.h> + +void print_edge(Edge *e) { + printf("v1.x = %i, v1.y = %i\nv2.x = %i, v2.y = %i", e->v1->x, e->v1->y, e->v2->x, e->v2->y); +} + +Edge gen_edge(int idx1, int idx2, Vertex* vertices) { + Edge e; + e.v1 = &vertices[idx1]; + e.v2 = &vertices[idx2]; + e.weight = vert_dist(e.v1, e.v2); + return e; +} + +Edge* gen_edges(Vertex* vertices, int vtCount, int edgeCount) { + Edge* edges = (Edge*)malloc(sizeof(Edge) * edgeCount); + for(int i = 0; i < edgeCount; ++i) { + int idx1 = choose_random(vtCount); + int idx2 = choose_random(vtCount); + Edge e = gen_edge(idx1,idx2, vertices); + edges[i] = e; + } + return edges; + +} diff --git a/background/old/edge.hpp b/background/old/edge.hpp @@ -0,0 +1,21 @@ +#ifndef EDGE +#define EDGE + +#include "vert.h" + +typedef struct Edge { + Vertex* v1; + Vertex* v2; + float weight; + bool traversed; + bool operator<(const Edge& other) const { + return weight < other.weight; + } + +} Edge; + +Edge gen_edge(int idx1, int idx2, Vertex* vertices); +Edge* gen_edges(Vertex* vertices, int vtCount, int edgeCount); +void print_edge(Edge* e); + +#endif diff --git a/background/old/main.cpp b/background/old/main.cpp @@ -0,0 +1,135 @@ +#include <algorithm> +#include <thread> +#include <chrono> +#include <ctime> +#include <time.h> +#include <iostream> +#include <cstdint> +#include <raylib.h> +#include <stdlib.h> +#include <time.h> +#include <unordered_map> +#include <unordered_set> +#include <vector> +#include "draw.h" + +#define VERTICES 100 +#define EDGES 1000 + +std::unordered_map<std::uintptr_t, std::vector<Edge*>> getMap(Vertex* verts, Edge* edges, int edgeCount, int vertCount) { + + std::unordered_map<std::uintptr_t, std::vector<Edge*>> res {}; + + for(int i = 0; i < vertCount; ++i) { + Vertex* vert = &verts[i]; + res[std::uintptr_t(vert)] = std::vector<Edge*>{}; + } + + + for (int i = 0; i < edgeCount; ++i) { + Edge& e = edges[i]; + res[std::uintptr_t(e.v1)].push_back(&e); + res[std::uintptr_t(e.v2)].push_back(&e); + } + + return res; +} + +void visit_vertex( + Vertex* v, + const std::vector<Edge*>& edges, + std::vector<Edge*>& visitHeap, + std::unordered_set<std::uintptr_t>& visited +) { + + v->visited = true; + + visited.insert(uintptr_t(v)); + for(Edge* edge: edges) { + visitHeap.push_back(edge); + + auto cmp = [](Edge* a, Edge* b) { + // this makes it a min heap bc < + return a->weight < b->weight; + }; + + std::push_heap(visitHeap.begin(), visitHeap.end(), cmp); + } + return; +} + +// create vertices +// create weighted edge list +// associated edges with both vertices + // undirected graph +// start with arbitrary element + // push edges into an array + // search array for smallest element + // explore +int main(void) +{ + + srand(time(0)); + InitWindow(5120, 1440, "Raylib background animation window"); + + while (!WindowShouldClose()) + { + Vertex* vertices = gen_vertices(VERTICES); + Edge* edges = gen_edges(vertices, VERTICES, EDGES); + auto mp = getMap(vertices,edges,EDGES,VERTICES); + + std::unordered_set<std::uintptr_t> visited {}; + std::vector<Edge*> visitHeap; + + visit_vertex(&vertices[0], mp[uintptr_t(&vertices[0])], visitHeap, visited); + bool done = false; + + while(!done) { + + BeginDrawing(); + ClearBackground(BLACK); + draw_edges(edges,EDGES); + draw_vertices(vertices,VERTICES); + EndDrawing(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + + std::vector<Edge*> currentHeap = visitHeap; + visitHeap.clear(); + + auto cmp = [](Edge* a, Edge* b) { + return a->weight < b->weight; + }; + std::pop_heap(visitHeap.begin(), visitHeap.end(), cmp); + + Edge* vis = visitHeap.back(); + visitHeap.pop_back(); + + if(visited.find(uintptr_t(vis->v1)) == visited.end() && visited.find(uintptr_t(vis->v2)) == visited.end()) { + continue; + } + + if(visited.find(uintptr_t(vis->v1)) != visited.end() && visited.find(uintptr_t(vis->v2)) != visited.end()) { + continue; + } + + + Vertex* visiting = nullptr; + + if(visited.find(uintptr_t(vis->v1)) == visited.end()){ + visited.insert(uintptr_t(vis->v1)); + visiting = vis->v1; + } else { + visited.insert(uintptr_t(vis->v2)); + visiting = vis->v2; + } + vis->traversed = true; + visit_vertex(visiting, mp[uintptr_t(visiting)], visitHeap, visited); + } + + free(vertices); + free(edges); + } + + CloseWindow(); + return 0; +} diff --git a/background/util.c b/background/old/util.c diff --git a/background/util.h b/background/old/util.h diff --git a/background/old/vert.c b/background/old/vert.c @@ -0,0 +1,33 @@ +#include "vert.h" +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +Vertex gen_vertex() { + int y = rand() % 1440; + int x = rand() % 5120; + Vertex v; + v.x = x; + v.y = y; + return v; +} + +void print_vertex(Vertex* v) { + printf("x: %i, y: %i", v->x, v->y); +} + +Vertex* gen_vertices(int vtCount) { + Vertex* vertices = (Vertex*)malloc(sizeof(Vertex) * vtCount); + for(int i = 0; i < vtCount; ++i) { + Vertex v = gen_vertex(); + vertices[i] = v; + } + return vertices; + +} + +float vert_dist(Vertex* v1, Vertex* v2) { + float dx = (float)v1->x - (float)v2->x; + float dy = (float)v1->y - (float)v2->y; + return sqrt(dx*dx + dy*dy); +} diff --git a/background/old/vert.h b/background/old/vert.h @@ -0,0 +1,14 @@ +#ifndef VERT +#define VERT + +typedef struct Vert { + int x; + int y; + bool visited; + +} Vertex; +Vertex gen_vertex(); +Vertex* gen_vertices(int vtCount); +Vertex* choose_random(Vertex* vertices, int length); +float vert_dist(Vertex* v1, Vertex* v2); +#endif diff --git a/background/utils.cpp b/background/utils.cpp @@ -0,0 +1,20 @@ +#include "utils.hpp" +#include <cstdlib> + +float square(float x) { + return x * x; +} + +// call srand before invocation as this is a pure function. +Vector2 randomPosition(float xMax, float yMax) { + float r1 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX) * xMax; + float r2 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX) * yMax; + Vector2 v {r1,r2}; + return v; +} + +float distanceSquared(Vector2 v1, Vector2 v2) { + float xSquare = square(v1.x - v2.x); + float ySquare = square(v1.y - v2.y); + return xSquare + ySquare; +} diff --git a/background/utils.hpp b/background/utils.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include <raylib.h> + +#define DARKERGRAY CLITERAL(Color){ 40, 40, 40, 255 } + +float square(float x); +Vector2 randomPosition(float xMax, float yMax); +float distanceSquared(Vector2 v1, Vector2 v2); diff --git a/background/vert.c b/background/vert.c @@ -1,26 +0,0 @@ -#include "vert.h" -#include <stdlib.h> -#include <stdio.h> - -Vertex gen_vertex() { - int y = rand() % 1440; - int x = rand() % 5120; - Vertex v; - v.x = x; - v.y = y; - return v; -} - -void print_vertex(Vertex* v) { - printf("x: %i, y: %i", v->x, v->y); -} - -Vertex* gen_vertices(int vtCount) { - Vertex* vertices = (Vertex*)malloc(sizeof(Vertex) * vtCount); - for(int i = 0; i < vtCount; ++i) { - Vertex v = gen_vertex(); - vertices[i] = v; - } - return vertices; - -} diff --git a/background/vert.h b/background/vert.h @@ -1,8 +0,0 @@ -typedef struct Vert { - int x; - int y; - -} Vertex; -Vertex gen_vertex(); -Vertex* gen_vertices(int vtCount); -Vertex* choose_random(Vertex* vertices, int length); diff --git a/background/vertex.cpp b/background/vertex.cpp @@ -0,0 +1,21 @@ +#include "vertex.hpp" +#include <string> +#include <raylib.h> + +Vertex::Vertex(Vector2 position, float drawSize) + : position(position), drawSize(drawSize) {} + + +std::string Vertex::toString() { + std::string result = "(" + std::to_string(this->position.x) + ", " + std::to_string(this->position.y) + ")"; + return result; +} + + +void Vertex::render() { + if(visited) { + DrawCircle(position.x, position.y, drawSize, WHITE); + } else { + DrawCircle(position.x, position.y, drawSize, DARKGRAY); + } +} diff --git a/background/vertex.hpp b/background/vertex.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <raylib.h> +#include <string> + +class Vertex { + public: + Vertex(Vector2 position, float drawSize); + Vector2 position; + float drawSize; + std::string toString(); + void render(); + bool visited = false; +};