lnvis

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

main.c (7344B)


      1 #include "gl.h"
      2 
      3 #include <stdio.h>
      4 #include <time.h>
      5 #include <assert.h>
      6 #ifdef NANOVG_GLEW
      7 #include <GL/glew.h>
      8 #endif
      9 #define GLFW_INCLUDE_GLEXT
     10 #include <GLFW/glfw3.h>
     11 #include "nanovg/nanovg.h"
     12 #define NANOVG_GL2_IMPLEMENTATION
     13 #include "nanovg/nanovg_gl.h"
     14 
     15 #include "defs.h"
     16 #include "perf.h"
     17 #include "demo.h"
     18 #include "render.h"
     19 #include "update.h"
     20 #include "ln.h"
     21 #include "json.h"
     22 #include "options.h"
     23 
     24 void errorcb(int error, const char *desc)
     25 {
     26 	printf("GLFW error %d: %s\n", error, desc);
     27 }
     28 
     29 int premult = 0;
     30 
     31 static void key(GLFWwindow *window, int key, int scancode, int action, int mods)
     32 {
     33 	NVG_NOTUSED(scancode);
     34 	NVG_NOTUSED(mods);
     35 	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
     36 		glfwSetWindowShouldClose(window, GL_TRUE);
     37 	/* if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) */
     38 	/* 	blowup = !blowup; */
     39 	if (key == GLFW_KEY_P && action == GLFW_PRESS)
     40 		premult = !premult;
     41 }
     42 
     43 static struct ln ln;
     44 static double mx, my;
     45 static int mdown = 0;
     46 static int rmdown = 0;
     47 static int mclicked = 0;
     48 static int rmclicked = 0;
     49 
     50 static const union color dark_color = {
     51 	.rgba = { 0x28 / 255.0, 0x2c / 255.0, 0x34 / 255.0, 1.0f }
     52 };
     53 
     54 static const union color light_color = {
     55 	.rgba = { 1.0, 1.0, 1.0, 1.0f }
     56 };
     57 
     58 
     59 void mouse_pos(GLFWwindow *win, double x, double y)
     60 {
     61 	(void)win;
     62 	mx = x;
     63 	my = y;
     64 }
     65 
     66 void mouse_click(GLFWwindow *win, int button, int action, int mods)
     67 {
     68 	(void)win;
     69 	(void)button;
     70 	(void)action;
     71 	(void)mods;
     72 
     73 	mclicked = action == 1 && button == 0;
     74 	rmclicked = action == 1 && button == 1;
     75 
     76 	if (button == 0)
     77 		mdown = action;
     78 	if (button == 1)
     79 		rmdown = action;
     80 }
     81 
     82 
     83 void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
     84 {
     85 	(void)mods;
     86 	(void)scancode;
     87 	(void)window;
     88 
     89 	if (action == GLFW_PRESS) {
     90 		switch (key) {
     91 		case GLFW_KEY_A:
     92 			ln.display_flags ^= DISP_ALIASES;
     93 			break;
     94 		case GLFW_KEY_F:
     95 			ln.display_flags ^= DISP_FPS;
     96 			break;
     97 		case GLFW_KEY_S:
     98 			ln.display_flags ^= DISP_STROKE_NODES;
     99 			break;
    100 		case GLFW_KEY_G:
    101 			ln.display_flags ^= DISP_GRID;
    102 			break;
    103 		case GLFW_KEY_B:
    104 			ln.display_flags ^= DISP_BEZIER;
    105 			break;
    106 		case GLFW_KEY_T:
    107 			if (ln.display_flags & DISP_DARK)
    108 				memcpy(&ln.clear_color, &light_color, sizeof(ln.clear_color));
    109 			else
    110 				memcpy(&ln.clear_color, &dark_color, sizeof(ln.clear_color));
    111 			ln.display_flags ^= DISP_DARK;
    112 			break;
    113 		}
    114 	}
    115 }
    116 
    117 static struct node *find_node(const char *pubkey, struct node *nodes, int node_count)
    118 {
    119 	// TODO: hash table
    120 	for (int i = 0; i < node_count; i++) {
    121 		if (streq(pubkey, nodes[i].id))
    122 			return &nodes[i];
    123 		/* printf("%s != %s\n", pubkey, nodes[i].id); */
    124 	}
    125 
    126 	return NULL;
    127 }
    128 
    129 
    130 static void connect_node_channels(struct node *nodes, int node_count,
    131 				  struct channel *channels, int channel_count)
    132 {
    133 	struct channel *chan = NULL;
    134 
    135 	for (int i = 0; i < channel_count; i++) {
    136 		chan = &channels[i];
    137 
    138 		chan->nodes[0] = find_node(chan->source, nodes, node_count);
    139 		chan->nodes[1] = find_node(chan->destination, nodes, node_count);
    140 
    141 		assert(chan->nodes[0]);
    142 		assert(chan->nodes[1]);
    143 	}
    144 }
    145 
    146 void read_json(struct ln *ln, struct options *options)
    147 {
    148 	FILE *channels_fd = fopen(options->channels, "r");
    149 	FILE *nodes_fd = fopen(options->nodes, "r");
    150 
    151 	int channel_count = 0;
    152 	int node_count = 0;
    153 	struct channel *channels;
    154 	struct node *nodes;
    155 
    156 	int res = parse_clightning_nodes(nodes_fd, &node_count, &nodes);
    157 	fclose(nodes_fd);
    158 
    159 	if (res != 0) {
    160 		printf("parse_clightning_nodes res %d\n", res);
    161 		exit(1);
    162 	}
    163 
    164 	res = parse_clightning_channels(channels_fd, &channel_count, &channels);
    165 	fclose(channels_fd);
    166 
    167 	if (res != 0) {
    168 		printf("parse_clightning_channels res %d\n", res);
    169 		exit(1);
    170 	}
    171 
    172 	printf("parsed %d nodes, %d channels\n", node_count, channel_count);
    173 
    174 	connect_node_channels(nodes, node_count, channels, channel_count);
    175 	ln->channels = channels;
    176 	ln->channel_count = channel_count;
    177 	ln->nodes = nodes;
    178 	ln->node_count = node_count;
    179 }
    180 
    181 int main(int argc, const char *argv[])
    182 {
    183 	GLFWwindow *window;
    184 	int first = 1;
    185 	DemoData data;
    186 	NVGcontext *vg = NULL;
    187 	PerfGraph fps;
    188 	double prevt = 0;
    189 	struct options options;
    190 
    191 	srand(0);
    192 	// ln collision grid subdivision
    193 	// cells = grid_div * grid_div
    194 	static const int grid_div = 20;
    195 	static const int dark_theme = 1;
    196 
    197 	u64 flags = DISP_DARK
    198 		  | DISP_ALIASES
    199 		  | DISP_GRID
    200 		  | DISP_STROKE_NODES
    201 		  ;
    202 
    203 	parse_options(argc, argv, &options);
    204 
    205 	read_json(&ln, &options);
    206 
    207 	ln.display_flags = flags;
    208 
    209 	if (dark_theme)
    210 		memcpy(&ln.clear_color, &dark_color, sizeof(ln.clear_color));
    211 	else
    212 		memcpy(&ln.clear_color, &light_color, sizeof(ln.clear_color));
    213 
    214 	if (!glfwInit()) {
    215 		printf("Failed to init GLFW.");
    216 		return -1;
    217 	}
    218 
    219 	initGraph(&fps, GRAPH_RENDER_FPS, "Frame Time");
    220 
    221 	glfwSetErrorCallback(errorcb);
    222 
    223 	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    224 	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    225 #ifdef DEMO_MSAA
    226 	glfwWindowHint(GLFW_SAMPLES, 4);
    227 #endif
    228 
    229 	window = glfwCreateWindow(1000, 600, "Lightning Network Vis", NULL, NULL);
    230 	//	window = glfwCreateWindow(1000, 600, "NanoVG", glfwGetPrimaryMonitor(), NULL);
    231 	if (!window) {
    232 		glfwTerminate();
    233 		return -1;
    234 	}
    235 
    236 	glfwSetKeyCallback(window, key);
    237 
    238 	glfwMakeContextCurrent(window);
    239 #ifdef NANOVG_GLEW
    240 	if (glewInit() != GLEW_OK) {
    241 		printf("Could not init glew.\n");
    242 		return -1;
    243 	}
    244 #endif
    245 
    246 #ifdef DEMO_MSAA
    247 	vg = nvgCreateGL2(NVG_STENCIL_STROKES | NVG_DEBUG);
    248 #else
    249 	vg = nvgCreateGL2(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG);
    250 #endif
    251 	if (vg == NULL) {
    252 		printf("Could not init nanovg.\n");
    253 		return -1;
    254 	}
    255 
    256 	ln.vg = vg;
    257 
    258 	init_ln(&ln, grid_div);
    259 
    260 	if (loadDemoData(vg, &data) == -1)
    261 		return -1;
    262 
    263 	glfwSwapInterval(1);
    264 
    265 	glfwSetTime(0);
    266 	prevt = glfwGetTime();
    267 
    268 	glfwSetKeyCallback(window, key_callback);
    269 	glfwSetMouseButtonCallback(window, mouse_click);
    270 	glfwSetCursorPosCallback(window, mouse_pos);
    271 
    272 	while (!glfwWindowShouldClose(window)) {
    273 		if (ln.clicked)
    274 			ln.clicked = 0;
    275 		if (ln.right_clicked)
    276 			ln.right_clicked = 0;
    277 		double t, dt;
    278 		int winWidth, winHeight;
    279 		int fbWidth, fbHeight;
    280 		float pxRatio;
    281 
    282 		t = glfwGetTime();
    283 		dt = t - prevt;
    284 		prevt = t;
    285 		updateGraph(&fps, dt);
    286 
    287 		ln.clicked = mclicked;
    288 		mclicked = 0;
    289 
    290 		ln.right_clicked = rmclicked;
    291 		rmclicked = 0;
    292 
    293 		ln.mx = mx;
    294 		ln.my = my;
    295 		ln.mdown = mdown;
    296 
    297 		glfwGetCursorPos(window, &mx, &my);
    298 		glfwGetWindowSize(window, &winWidth, &winHeight);
    299 
    300 		ln.window_height = winHeight;
    301 		ln.window_width = winWidth;
    302 
    303 		if (first) {
    304 			/* random_network(winWidth, winHeight, 3, 500, &ln); */
    305 			init_network(winWidth, winHeight, &ln);
    306 			filter_network(options.filter, NULL, &ln);
    307 			first = 0;
    308 		}
    309 
    310 		glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
    311 
    312 		// Calculate pixel ration for hi-dpi devices.
    313 		pxRatio = (float)fbWidth / (float)winWidth;
    314 
    315 		// Update and render
    316 		glViewport(0, 0, fbWidth, fbHeight);
    317 
    318 		glClearColor(ln.clear_color.r,
    319 			     ln.clear_color.g,
    320 			     ln.clear_color.b,
    321 			     ln.clear_color.a);
    322 
    323 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
    324 			GL_STENCIL_BUFFER_BIT);
    325 
    326 		nvgBeginFrame(vg, winWidth, winHeight, pxRatio);
    327 
    328 		/* renderDemo(vg, mx, my, winWidth, winHeight, t, 1, &data); */
    329 		update(&ln, dt);
    330 		render_ln(&ln);
    331 
    332 		if (ln.display_flags & DISP_FPS)
    333 			renderGraph(vg, 5, 5, &fps);
    334 
    335 		nvgEndFrame(vg);
    336 
    337 		glfwSwapBuffers(window);
    338 		glfwPollEvents();
    339 	}
    340 
    341 	free_ln(&ln);
    342 	freeDemoData(vg, &data);
    343 
    344 	nvgDeleteGL2(vg);
    345 
    346 	glfwTerminate();
    347 	return 0;
    348 }