commit 934256ec9323c4aa9fbe8ede50bbfc6769bbf328
parent 7bd3c8e0800954a0cec321760031df35651aec23
Author: William Casarin <jb55@jb55.com>
Date: Tue, 7 Aug 2018 00:25:19 -0700
the grid sucks
Diffstat:
M | Makefile | | | 2 | +- |
M | grid.c | | | 27 | +++++++++++++++------------ |
M | grid.h | | | 5 | +++++ |
M | ln.c | | | 1 | + |
M | ln.h | | | 7 | +------ |
M | main.c | | | 4 | +++- |
M | render.c | | | 27 | +++++++++++++++++++++++++++ |
M | update.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;