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;