lnvis

nanovg lightning network visualizer
git clone git://jb55.com/lnvis
Log | Files | Refs | README | LICENSE

commit 934256ec9323c4aa9fbe8ede50bbfc6769bbf328
parent 7bd3c8e0800954a0cec321760031df35651aec23
Author: William Casarin <jb55@jb55.com>
Date:   Tue,  7 Aug 2018 00:25:19 -0700

the grid sucks

Diffstat:
MMakefile | 2+-
Mgrid.c | 27+++++++++++++++------------
Mgrid.h | 5+++++
Mln.c | 1+
Mln.h | 7+------
Mmain.c | 4+++-
Mrender.c | 27+++++++++++++++++++++++++++
Mupdate.c | 109++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
8 files changed, 125 insertions(+), 57 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ BIN = lnvis PREFIX ?= /usr/local -CFLAGS = -Ideps -ggdb -Os -Wall -Werror -Wextra -std=c99 \ +CFLAGS = -Ideps -ggdb -Os -Wall -Wextra -std=c99 \ -Wno-implicit-fallthrough LDFLAGS = -lglfw -lGL diff --git a/grid.c b/grid.c @@ -16,13 +16,15 @@ static void remove_node_from_cell(struct cell *cell, struct node *node) { // shortcut: reduce node count if it's the last node if (i == cell->node_count-1) { cell->node_count--; + assert(cell->node_count < CELL_MAX_ELEMS); return; } else { - assert(i + 1 < CELL_MAX_ELEMS); - memmove(n, n + 1, - sizeof(*cell->nodes) * (cell->node_count - 1)); + assert(i + 1 <= CELL_MAX_ELEMS); + int msize = sizeof(struct node *) * (cell->node_count - i - 1); + memmove(n, n + 1, msize); cell->node_count--; + assert(cell->node_count < CELL_MAX_ELEMS); return; } } @@ -32,7 +34,7 @@ static void remove_node_from_cell(struct cell *cell, struct node *node) { void update_grid_move_nodes(struct ln *ln) { struct node *n = NULL; - struct cell *new_cell, *old_cell; + struct cell *new_cell; for (u32 i = 0; i < ln->node_count; i++) { n = &ln->nodes[i]; @@ -44,23 +46,23 @@ void update_grid_move_nodes(struct ln *ln) { if (gx > ln->grid_div || gy > ln->grid_div) continue; - // we've moved to a new cell - if (gx != n->grid_x || gy != n->grid_y) { - new_cell = &ln->grid[gy * ln->grid_div + gx]; + new_cell = &ln->grid[gy * ln->grid_div + gx]; + // we've moved to a new cell + if (n->cell != new_cell) { // can't move to new cell :[ if (new_cell->node_count == CELL_MAX_ELEMS) continue; - old_cell = &ln->grid[n->grid_y * ln->grid_div + n->grid_x]; - // remove from old cell - remove_node_from_cell(old_cell, n); + if (n->cell) + remove_node_from_cell(n->cell, n); // add to new cell - n->grid_x = gx; - n->grid_y = gy; + n->cell = new_cell; + /* printf("adding to cell (%d, %d) elems %d\n", */ + /* gx, gy, new_cell->node_count+1); */ new_cell->nodes[new_cell->node_count++] = n; } } @@ -68,3 +70,4 @@ void update_grid_move_nodes(struct ln *ln) { + diff --git a/grid.h b/grid.h @@ -5,6 +5,11 @@ #include "ln.h" +struct cell { + struct node *nodes[CELL_MAX_ELEMS]; + int node_count; +}; + void update_grid_move_nodes(struct ln *ln); diff --git a/ln.c b/ln.c @@ -1,5 +1,6 @@ #include "ln.h" +#include "grid.h" #include <stdlib.h> #include <string.h> #include <stdio.h> diff --git a/ln.h b/ln.h @@ -18,7 +18,7 @@ struct node { }; } color; - int grid_x, grid_y; + struct cell *cell; double x, y; double vx, vy; double ax, ay; @@ -74,11 +74,6 @@ struct channel { u32 last_update; }; -struct cell { - struct node *nodes[CELL_MAX_ELEMS]; - int node_count; -}; - struct ln { NVGcontext *vg; diff --git a/main.c b/main.c @@ -1,6 +1,7 @@ #include "gl.h" #include <stdio.h> +#include <time.h> #ifdef NANOVG_GLEW #include <GL/glew.h> #endif @@ -71,6 +72,7 @@ int main() PerfGraph fps; double prevt = 0; + srand(time(0)); // ln collision grid subdivision // cells = grid_div * grid_div int grid_div = 20; @@ -160,7 +162,7 @@ int main() ln.window_width = winWidth; if (first) { - random_network(winWidth, winHeight, 3, 50, &ln); + random_network(winWidth, winHeight, 3, 200, &ln); printf("channels %d\n", ln.channel_count); first = 0; } diff --git a/render.c b/render.c @@ -41,6 +41,31 @@ void draw_channel(NVGcontext *vg, struct channel *channel) nvgRestore(vg); } + +void draw_grid(NVGcontext *vg, int ww, int wh, int grid_div) { + + for (int x = 0; x < grid_div; ++x) { + double px = ww / grid_div * x; + //int py = wh / grid_div * y; + + nvgBeginPath(vg); + nvgMoveTo(vg, px, 0); + nvgLineTo(vg, px, wh); + nvgStroke(vg); + } + + for (int y = 0; y < grid_div; ++y) { + double py = wh / grid_div * y; + //int py = wh / grid_div * y; + + nvgBeginPath(vg); + nvgMoveTo(vg, 0, py); + nvgLineTo(vg, ww, py); + nvgStroke(vg); + } +} + + void draw_node(NVGcontext *vg, struct node *node) { const float r = node->size; @@ -93,6 +118,8 @@ void render_ln(struct ln *ln) u32 i; NVGcontext *vg = ln->vg; + draw_grid(vg, ln->window_width, ln->window_height, ln->grid_div); + // render channels first for (i = 0; i < ln->channel_count; i++) draw_channel(vg, &ln->channels[i]); diff --git a/update.c b/update.c @@ -25,7 +25,53 @@ struct node *hit_node(struct ln *ln) { } -void force_graph(struct ln *ln, double dt) { +void repel_nodes(struct node *n1, struct node *n2, double dt) { + double dx = n2->x - n1->x; + double dy = n2->y - n1->y; + + double d = sqrt(dx*dx + dy*dy); + + static const double mindist = 100.0; + if (d < mindist) { + + // normalized vector between two nodes + double nx = dx / d; + double ny = dy / d; + + // get the distance past the minimum distance along + // the vector between the two nodes + double nnx = (d - mindist) * nx; + double nny = (d - mindist) * ny; + + if (isnan(nnx) || isnan(nny)) + return; + + // normalize by frame time + double mx = nnx * dt; + double my = nny * dt; + + // correct for the distance by accelerating the node away + // from the other node + n1->vx += mx; + n1->vy += my; + + // do the same in the opposite direction for the other node + n2->vx -= mx; + n2->vy -= my; + } + else { + const double scale = 1.0; + + n1->vx += dx * scale * dt; + n1->vy += dy * scale * dt; + + n2->vx += -dx * scale * dt; + n2->vy += -dy * scale * dt; + } +} + + +static void force_graph(struct ln *ln, double dt) { u32 i; // channel constraints @@ -35,53 +81,40 @@ void force_graph(struct ln *ln, double dt) { struct node *n1 = channel->nodes[0]; struct node *n2 = channel->nodes[1]; - double dx = n2->x - n1->x; - double dy = n2->y - n1->y; - - double d = sqrt(dx*dx + dy*dy); - - static const double mindist = 100.0; - if (d < mindist) { - - // normalized vector between two nodes - double nx = dx / d; - double ny = dy / d; + repel_nodes(n1, n2, dt); + } +} - // get the distance past the minimum distance along - // the vector between the two nodes - double nnx = (d - mindist) * nx; - double nny = (d - mindist) * ny; - if (isnan(nnx) || isnan(nny)) - continue; +static void repel_nearby(struct node *node, double dt) +{ + struct node *n = NULL; + struct cell *cell = node->cell; - // normalize by frame time - double mx = nnx * dt; - double my = nny * dt; + // might happen the first iteration? + if (cell == NULL) + return; - // correct for the distance by accelerating the node away - // from the other node - n1->vx += mx; - n1->vy += my; + // we're the only one in this cell, there's nothing to repel + if (cell->node_count == 1) + return; - // do the same in the opposite direction for the other node - n2->vx -= mx; - n2->vy -= my; - } - else { - const double scale = 1.0; + for (int i = 0; i < cell->node_count; ++i) { + n = cell->nodes[i]; - n1->vx += dx * scale * dt; - n1->vy += dy * scale * dt; + // dont repel against ourselves + if (n == node) + continue; - n2->vx += -dx * scale * dt; - n2->vy += -dy * scale * dt; - } + assert(n); + assert(node); + repel_nodes(n, node, dt); } } -void physics(struct ln *ln, double dt) { +static void physics(struct ln *ln, double dt) +{ static const double friction_coeff = 0.03; static const double friction = 1.0 - friction_coeff; @@ -89,6 +122,8 @@ void physics(struct ln *ln, double dt) { for (u32 i = 0; i < ln->node_count; i++) { struct node *node = &ln->nodes[i]; + repel_nearby(node, dt); + // semi-implicit euler node->ax *= friction; node->ay *= friction;