commit f55fbdf3edb180f0aaf1ca4cf4eab0c6f1b057a1
parent f1ad0a3d06dd0b45cc7ae31fea913ba2d7eb42e4
Author: William Casarin <jb55@jb55.com>
Date: Sat, 4 Aug 2018 14:19:28 -0700
progress!
- interactivity
- forces and such
- lines
Diffstat:
M | Makefile | | | 1 | + |
M | defs.h | | | 3 | +++ |
M | deps/nanovg/nanovg.c | | | 5 | ++--- |
M | ln.h | | | 69 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
M | main.c | | | 89 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ |
M | render.c | | | 61 | ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- |
A | update.c | | | 85 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | update.h | | | 9 | +++++++++ |
8 files changed, 302 insertions(+), 20 deletions(-)
diff --git a/Makefile b/Makefile
@@ -9,6 +9,7 @@ LDFLAGS = -lglfw -lGL
SRCS = main.c
+SRCS += update.c
SRCS += render.c
SRCS += perf.c
SRCS += demo.c
diff --git a/defs.h b/defs.h
@@ -13,5 +13,8 @@ typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
+typedef unsigned long long u64;
+typedef signed long long s64;
+
#endif /* LNVIS_DEFS_H */
diff --git a/deps/nanovg/nanovg.c b/deps/nanovg/nanovg.c
@@ -845,9 +845,8 @@ void nvgDeleteImage(NVGcontext* ctx, int image)
ctx->params.renderDeleteTexture(ctx->params.userPtr, image);
}
-NVGpaint nvgLinearGradient(NVGcontext* ctx,
- float sx, float sy, float ex, float ey,
- NVGcolor icol, NVGcolor ocol)
+NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float ey,
+ NVGcolor icol, NVGcolor ocol)
{
NVGpaint p;
float dx, dy, d;
diff --git a/ln.h b/ln.h
@@ -3,10 +3,11 @@
#define LNVIS_LN_H
#include "nanovg/nanovg.h"
+#include "defs.h"
struct node {
const char *alias;
- const char *nodeid;
+ const char *id; // pubkey
union {
float rgba[4];
@@ -14,12 +15,76 @@ struct node {
float r, g, b, a;
};
} color;
+
+ double x, y;
+ double vx, vy;
+ double ax, ay;
+
+ float size;
+};
+
+
+// REMOTE: remote node opened the channel with local
+// LOCAL: local node opened the channel with remote
+enum side {
+ LOCAL,
+ REMOTE,
+ NUM_SIDES
+};
+
+/*
+ * type: 256 (`channel_announcement`)
+ * - [`64`:`node_signature_1`]
+ * - [`64`:`node_signature_2`]
+ * - [`64`:`bitcoin_signature_1`]
+ * - [`64`:`bitcoin_signature_2`]
+ * - [`2`:`len`]
+ * - [`len`:`features`]
+ * - [`32`:`chain_hash`]
+ * - [`8`:`short_channel_id`]
+ * - [`33`:`node_id_1`]
+ * - [`33`:`node_id_2`]
+ * - [`33`:`bitcoin_key_1`]
+ * - [`33`:`bitcoin_key_2`]
+ */
+
+/* type: 258 (`channel_update`)
+ * - [`64`:`signature`]
+ * - [`32`:`chain_hash`]
+ * - [`8`:`short_channel_id`]
+ * - [`4`:`timestamp`]
+ * - [`2`:`flags`]
+ * - [`2`:`cltv_expiry_delta`]
+ * - [`8`:`htlc_minimum_msat`]
+ * - [`4`:`fee_base_msat`]
+ * - [`4`:`fee_proportional_millionths`]
+ */
+
+struct channel {
+ struct node *nodes[2];
+
+ u64 our_msatoshi;
+ /* Statistics for min and max our_msatoshi. */
+ u64 msatoshi_to_us_min;
+ u64 msatoshi_to_us_max;
+
+ u32 last_update;
};
struct ln {
NVGcontext *vg;
+
+ int clicked;
+ int mdown;
+ double mx, my;
+
+ struct node *drag_target;
+
struct node *nodes;
- int node_count;
+ u32 node_count;
+
+ struct channel *channels;
+ u32 channel_count;
};
#endif /* LNVIS_LN_H */
diff --git a/main.c b/main.c
@@ -14,6 +14,7 @@
#include "perf.h"
#include "demo.h"
#include "render.h"
+#include "update.h"
#include "ln.h"
void errorcb(int error, const char *desc)
@@ -35,6 +36,36 @@ static void key(GLFWwindow *window, int key, int scancode, int action, int mods)
premult = !premult;
}
+
+static double rand_0to1() {
+ return (double) rand() / RAND_MAX;
+}
+
+static double mx, my;
+static int mdown = 0;
+static int mclicked = 0;
+
+void mouse_pos(GLFWwindow *win, double x, double y)
+{
+ (void)win;
+ mx = x;
+ my = y;
+}
+
+void mouse_click(GLFWwindow *win, int button, int action, int mods)
+{
+ (void)win;
+ (void)button;
+ (void)action;
+ (void)mods;
+
+ mclicked = action == 1 && button == 0;
+
+ if (button == 0)
+ mdown = action;
+}
+
+
int main()
{
GLFWwindow *window;
@@ -44,14 +75,45 @@ int main()
double prevt = 0;
struct ln ln;
- struct node test_nodes[] = { {
- .alias = "@jb55",
- .color = { { 1.0, 0, 0, 1.0 } },
- } };
+ struct node test_nodes[] = {
+ {
+ .alias = "@jb55",
+ .color = { { 1.0, 0, 0, 1.0 } },
+ },
+ {
+ .alias = "SuperHub",
+ .color = { { 0.0, 1.0, 0.0, 1.0 } },
+ },
+ {
+ .alias = "satoshis.place",
+ .color = { { 0.0, 0.5, 1.0, 1.0 } },
+ },
+ };
+
+ struct channel test_channels[] = {
+ {
+ .nodes = { &test_nodes[0], &test_nodes[1] },
+ },
+ {
+ .nodes = { &test_nodes[1], &test_nodes[2] },
+ }
+ };
ln.nodes = test_nodes;
ln.node_count = ARRAY_SIZE(test_nodes);
+ ln.channels = test_channels;
+ ln.channel_count = ARRAY_SIZE(test_channels);
+
+ for (u32 i = 0; i < ln.node_count; ++i) {
+ struct node *n = &ln.nodes[i];
+ n->x = 100.0 * (i+1);
+ n->y = 100.0 * (i+1);
+ n->vx = 200.0 * rand_0to1();
+ n->vy = 200.0 * rand_0to1();
+ n->size = 20;
+ }
+
if (!glfwInit()) {
printf("Failed to init GLFW.");
return -1;
@@ -95,6 +157,7 @@ int main()
}
ln.vg = vg;
+ ln.clicked = 0;
if (loadDemoData(vg, &data) == -1)
return -1;
@@ -104,8 +167,13 @@ int main()
glfwSetTime(0);
prevt = glfwGetTime();
+ glfwSetMouseButtonCallback(window, mouse_click);
+ glfwSetCursorPosCallback(window, mouse_pos);
+
while (!glfwWindowShouldClose(window)) {
- double mx, my, t, dt;
+ if (ln.clicked)
+ ln.clicked = 0;
+ double t, dt;
int winWidth, winHeight;
int fbWidth, fbHeight;
float pxRatio;
@@ -115,6 +183,13 @@ int main()
prevt = t;
updateGraph(&fps, dt);
+ ln.clicked = mclicked;
+ mclicked = 0;
+
+ ln.mx = mx;
+ ln.my = my;
+ ln.mdown = mdown;
+
glfwGetCursorPos(window, &mx, &my);
glfwGetWindowSize(window, &winWidth, &winHeight);
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
@@ -127,13 +202,15 @@ int main()
if (premult)
glClearColor(0, 0, 0, 0);
else // base16-onedark bg color ;)
- glClearColor(0x28 / 255.0, 0x2c / 255.0, 0x34 / 255.0, 1.0f);
+ glClearColor(0x28 / 255.0, 0x2c / 255.0, 0x34 / 255.0,
+ 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
nvgBeginFrame(vg, winWidth, winHeight, pxRatio);
/* renderDemo(vg, mx, my, winWidth, winHeight, t, 1, &data); */
+ update(&ln, dt);
render_ln(&ln);
renderGraph(vg, 5, 5, &fps);
diff --git a/render.c b/render.c
@@ -3,10 +3,48 @@
#include <stdio.h>
#include "nanovg/nanovg.h"
+void draw_channel(NVGcontext *vg, struct channel *channel)
+{
+ const struct node *n1 = channel->nodes[0];
+ const struct node *n2 = channel->nodes[1];
+ static const float stroke = 2.0f;
+
+ const float sx = n1->x;
+ const float sy = n1->y;
+
+ const float ex = n2->x;
+ const float ey = n2->y;
+
+ NVGcolor n1_color =
+ nvgRGBAf(n1->color.r,
+ n1->color.g,
+ n1->color.b,
+ n1->color.a);
+
+ NVGcolor n2_color =
+ nvgRGBAf(n2->color.r,
+ n2->color.g,
+ n2->color.b,
+ n2->color.a);
+
+ NVGpaint linear_grad =
+ nvgLinearGradient(vg, sx, sy, ex, ey, n1_color, n2_color);
+
+ nvgSave(vg);
+ nvgStrokeWidth(vg, stroke);
+
+ nvgStrokePaint(vg, linear_grad);
+ nvgBeginPath(vg);
+ nvgMoveTo(vg, n1->x, n1->y);
+ nvgLineTo(vg, n2->x, n2->y);
+ nvgStroke(vg);
+ nvgRestore(vg);
+}
+
void draw_node(NVGcontext *vg, struct node *node)
{
- const float r = 20.0;
- const float pos = 500.0;
+ const float r = node->size;
+ /* const float pos = 500.0; */
/* const float h = r; */
/* const float w = r; */
@@ -14,13 +52,8 @@ void draw_node(NVGcontext *vg, struct node *node)
/* const float y = pos; */
/* const float kr = (int)(h * 0.35f); */
/* const float cy = y + (int)(h * 0.5f); */
-
-
NVGpaint bg;
- nvgSave(vg);
- nvgTranslate(vg, pos, pos);
-
NVGcolor node_color =
nvgRGBAf(node->color.r, node->color.g, node->color.b,
node->color.a);
@@ -28,6 +61,9 @@ void draw_node(NVGcontext *vg, struct node *node)
NVGcolor blend =
nvgRGBAf(0, 0, 0, 0.5);
+ nvgSave(vg);
+ nvgTranslate(vg, node->x, node->y);
+
const float light = 2.0f;
bg = nvgRadialGradient(vg, -light, -light, 0, r+2.0, node_color, blend);
nvgBeginPath(vg);
@@ -54,6 +90,13 @@ void draw_node(NVGcontext *vg, struct node *node)
void render_ln(struct ln *ln)
{
- for (int i = 0; i < ln->node_count; i++)
- draw_node(ln->vg, &ln->nodes[i]);
+ u32 i;
+ NVGcontext *vg = ln->vg;
+
+ // render channels first
+ for (i = 0; i < ln->channel_count; i++)
+ draw_channel(vg, &ln->channels[i]);
+
+ for (i = 0; i < ln->node_count; i++)
+ draw_node(vg, &ln->nodes[i]);
}
diff --git a/update.c b/update.c
@@ -0,0 +1,85 @@
+
+#include "ln.h"
+#include <math.h>
+#include <stdio.h>
+
+struct node *hit_node(struct ln *ln) {
+ for (u32 i = 0; i < ln->node_count; ++i)
+ {
+ struct node *n = &ln->nodes[i];
+
+ const double dx = fabs(n->x - ln->mx);
+ const double dy = fabs(n->y - ln->my);
+
+ const double d = sqrt(dx*dx + dy*dy);
+
+ /* printf("%s's dx %f dy %f d %f\n", n->alias, dx, dy, d); */
+
+ if (d <= n->size)
+ return n;
+ }
+
+ return NULL;
+}
+
+// force graph update logic
+void update(struct ln *ln, double dt)
+{
+
+ // click detection
+ if (ln->clicked) {
+ struct node *hit = hit_node(ln);
+
+ if (hit != NULL)
+ printf("hit %s\n", hit->alias);
+
+ ln->drag_target = hit;
+ }
+
+ // stop dragging
+ if (!ln->mdown && ln->drag_target)
+ ln->drag_target = NULL;
+
+ // drag
+ if (ln->mdown && ln->drag_target) {
+ ln->drag_target->x = ln->mx;
+ ln->drag_target->y = ln->my;
+ }
+
+ u32 i;
+ static const double friction = 0.3;
+
+ for (i = 0; i < ln->channel_count; ++i) {
+ struct channel *channel = &ln->channels[i];
+
+ struct node *n1 = channel->nodes[0];
+ struct node *n2 = channel->nodes[1];
+
+ double dx = n2->x - n1->x;
+ double dy = n2->y - n1->y;
+
+ n1->vx += dx * 0.001;
+ n1->vy += dy * 0.001;
+ }
+
+ for (u32 i = 0; i < ln->node_count; i++) {
+ struct node *node = &ln->nodes[i];
+
+ // semi-implicit euler
+
+ // update node position
+ node->vx += node->ax * dt;
+ node->vy += node->ay * dt;
+
+ // forces (testing)
+ if (node->vx > 0.0)
+ node->vx -= friction;
+
+ if (node->vy > 0.0)
+ node->vy -= friction;
+
+ node->x += node->vx * dt;
+ node->y += node->vy * dt;
+
+ }
+}
diff --git a/update.h b/update.h
@@ -0,0 +1,9 @@
+
+#ifndef LNVIS_UPDATE_H
+#define LNVIS_UPDATE_H
+
+#include "ln.h"
+
+void update(struct ln *ln, double dt);
+
+#endif /* LNVIS_UPDATE_H */