demo: Add node editor example

This commit is contained in:
Rob Loach 2024-09-05 11:27:30 -04:00
parent 862405f8be
commit 8e0e80b516
No known key found for this signature in database
GPG Key ID: 627C60834A74A21A
4 changed files with 62 additions and 36 deletions

View File

@ -1,6 +1,6 @@
/* /*
A basic node-based UI built with Nuklear. A basic node-based UI built with Nuklear.
Builds on the node editor example included in Nuklear v1.00, with the aim of Builds on the node editor example included in Nuklear v1.00, with the aim of
being used as a prototype for implementing a functioning node editor. being used as a prototype for implementing a functioning node editor.
Features: Features:
@ -176,7 +176,7 @@ node_editor_delete_link(struct node_link *link)
} }
struct node* struct node*
node_editor_add(struct node_editor *editor, size_t nodeSize, const char *name, struct nk_rect bounds, node_editor_add(struct node_editor *editor, size_t nodeSize, const char *name, struct nk_rect bounds,
int in_count, int out_count) int in_count, int out_count)
{ {
int i; int i;
@ -208,7 +208,7 @@ int in_count, int out_count)
} }
node->bounds = bounds; node->bounds = bounds;
node->input_count = in_count; node->input_count = in_count;
node->output_count = out_count; node->output_count = out_count;
@ -224,7 +224,7 @@ int in_count, int out_count)
node->outputs[i].type = fValue; /* default connector type */ node->outputs[i].type = fValue; /* default connector type */
} }
/* default connector spacing */ /* default connector spacing */
node->slot_spacing.in_top = node->slot_spacing.in_space = node->bounds.h / (float)((node->input_count) + 1); node->slot_spacing.in_top = node->slot_spacing.in_space = node->bounds.h / (float)((node->input_count) + 1);
node->slot_spacing.out_top = node->slot_spacing.out_space = node->bounds.h / (float)((node->output_count) + 1); node->slot_spacing.out_top = node->slot_spacing.out_space = node->bounds.h / (float)((node->output_count) + 1);
@ -235,7 +235,7 @@ int in_count, int out_count)
} }
void * void *
node_editor_eval_connected(struct node* node, int inputSlot) node_editor_eval_connected(struct node* node, int inputSlot)
{ {
NK_ASSERT(node->inputs[inputSlot].is_connected); NK_ASSERT(node->inputs[inputSlot].is_connected);
return node->inputs[inputSlot].connected_node->eval_func(node->inputs[inputSlot].connected_node, node->inputs[inputSlot].connected_slot); return node->inputs[inputSlot].connected_node->eval_func(node->inputs[inputSlot].connected_node, node->inputs[inputSlot].connected_slot);
@ -265,7 +265,7 @@ node_editor_link(struct node_editor *editor, struct node *in_node, int in_slot,
in_node->outputs[in_slot].is_connected = nk_true; in_node->outputs[in_slot].is_connected = nk_true;
out_node->inputs[out_slot].connected_node = in_node; out_node->inputs[out_slot].connected_node = in_node;
out_node->inputs[out_slot].connected_slot = in_slot; out_node->inputs[out_slot].connected_slot = in_slot;
link->input_node = in_node; link->input_node = in_node;
link->input_slot = in_slot; link->input_slot = in_slot;
link->output_node = out_node; link->output_node = out_node;
@ -279,15 +279,37 @@ node_editor_link(struct node_editor *editor, struct node *in_node, int in_slot,
static void static void
node_editor_init(struct node_editor *editor) node_editor_init(struct node_editor *editor)
{ {
struct nk_vec2 output_node_position = {500, 300}; struct nk_vec2 color_node_position = {40, 10};
struct nk_vec2 color_node_position = {200, 200}; struct nk_vec2 color2_node_position = {40, 260};
struct nk_vec2 blend_node_position = {300, 140};
struct nk_vec2 output_node_position = {540, 154};
struct node_type_color *color1;
struct node_type_color *color2;
struct node *blend;
memset(editor, 0, sizeof(*editor)); memset(editor, 0, sizeof(*editor));
editor->begin = NULL; editor->begin = NULL;
editor->end = NULL; editor->end = NULL;
/* Create the nodes */
editor->output_node = node_output_create(editor, output_node_position); editor->output_node = node_output_create(editor, output_node_position);
node_color_create(editor, color_node_position); color1 = node_color_create(editor, color_node_position);
node_editor_link(editor, editor->node_buf[1], 0, editor->output_node, 0); color2 = node_color_create(editor, color2_node_position);
blend = (struct node *)node_blend_create(editor, blend_node_position);
/* Set the color values */
color1->input_val[0] = 1.0f;
color1->input_val[1] = 0.0f;
color1->input_val[2] = 0.0f;
color2->input_val[0] = 0.0f;
color2->input_val[1] = 0.0f;
color2->input_val[2] = 1.0f;
/* Link the nodes */
node_editor_link(editor, (struct node*)color1, 0, blend, 0);
node_editor_link(editor, (struct node*)color2, 0, blend, 1);
node_editor_link(editor, blend, 0, editor->output_node, 0);
editor->show_grid = nk_true; editor->show_grid = nk_true;
} }
@ -330,13 +352,13 @@ node_editor(struct nk_context *ctx)
} }
/* execute each node as a movable group */ /* execute each node as a movable group */
/* (loop through nodes) */ /* (loop through nodes) */
while (it) { while (it) {
/* Output node window should not have a close button */ /* Output node window should not have a close button */
nk_flags nodePanel_flags = NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE; nk_flags nodePanel_flags = NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE;
if (it != editor->output_node) if (it != editor->output_node)
nodePanel_flags |= NK_WINDOW_CLOSABLE; nodePanel_flags |= NK_WINDOW_CLOSABLE;
/* calculate scrolled node window position and size */ /* calculate scrolled node window position and size */
nk_layout_space_push(ctx, nk_rect(it->bounds.x - editor->scrolling.x, nk_layout_space_push(ctx, nk_rect(it->bounds.x - editor->scrolling.x,
it->bounds.y - editor->scrolling.y, it->bounds.w, it->bounds.h)); it->bounds.y - editor->scrolling.y, it->bounds.w, it->bounds.h));
@ -356,7 +378,7 @@ node_editor(struct nk_context *ctx)
} }
if ((nodePanel->flags & NK_WINDOW_HIDDEN)) /* Node close button has been clicked */ if ((nodePanel->flags & NK_WINDOW_HIDDEN)) /* Node close button has been clicked */
{ {
/* Delete node */ /* Delete node */
struct node_link *link_remove; struct node_link *link_remove;
node_editor_pop(editor, it); node_editor_pop(editor, it);
@ -383,16 +405,16 @@ node_editor(struct nk_context *ctx)
else { else {
/* ================= NODE CONTENT ===================== */ /* ================= NODE CONTENT ===================== */
it->display_func(ctx, it); it->display_func(ctx, it);
/* ==================================================== */ /* ==================================================== */
} }
nk_group_end(ctx); nk_group_end(ctx);
} }
if (!(nodePanel->flags & NK_WINDOW_HIDDEN)) if (!(nodePanel->flags & NK_WINDOW_HIDDEN))
{ {
/* node connector and linking */ /* node connector and linking */
struct nk_rect bounds; struct nk_rect bounds;
@ -416,7 +438,7 @@ node_editor(struct nk_context *ctx)
/* start linking process */ /* start linking process */
/* (set linking active) */ /* (set linking active) */
if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) { if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) {
editor->linking.active = nk_true; editor->linking.active = nk_true;
editor->linking.node = it; editor->linking.node = it;
editor->linking.input_id = it->ID; editor->linking.input_id = it->ID;
editor->linking.input_slot = n; editor->linking.input_slot = n;
@ -450,7 +472,7 @@ node_editor(struct nk_context *ctx)
editor->linking.active == nk_false && editor->linking.active == nk_false &&
it->inputs[n].is_connected == nk_true) { it->inputs[n].is_connected == nk_true) {
struct node_link *node_relink = node_editor_find_link_by_output(editor, it, n); struct node_link *node_relink = node_editor_find_link_by_output(editor, it, n);
editor->linking.active = nk_true; editor->linking.active = nk_true;
editor->linking.node = node_relink->input_node; editor->linking.node = node_relink->input_node;
editor->linking.input_id = node_relink->input_node->ID; editor->linking.input_id = node_relink->input_node->ID;
editor->linking.input_slot = node_relink->input_slot; editor->linking.input_slot = node_relink->input_slot;
@ -460,12 +482,12 @@ node_editor(struct nk_context *ctx)
/* (Create link) */ /* (Create link) */
if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) && if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) &&
nk_input_is_mouse_hovering_rect(in, circle) && nk_input_is_mouse_hovering_rect(in, circle) &&
editor->linking.active && editor->linking.active &&
editor->linking.node != it && editor->linking.node != it &&
it->inputs[n].type == editor->linking.node->outputs[editor->linking.input_slot].type && it->inputs[n].type == editor->linking.node->outputs[editor->linking.input_slot].type &&
it->inputs[n].is_connected != nk_true) { it->inputs[n].is_connected != nk_true) {
editor->linking.active = nk_false; editor->linking.active = nk_false;
node_editor_link(editor, editor->linking.node, node_editor_link(editor, editor->linking.node,
editor->linking.input_slot, it, n); editor->linking.input_slot, it, n);
} }

View File

@ -7,6 +7,7 @@ struct node_type_blend {
static struct nk_colorf *node_blend_eval(struct node *node, int oIndex) { static struct nk_colorf *node_blend_eval(struct node *node, int oIndex) {
struct node_type_blend* blend_node = (struct node_type_blend*)node; struct node_type_blend* blend_node = (struct node_type_blend*)node;
NK_UNUSED(oIndex);
return &blend_node->output_val; return &blend_node->output_val;
} }
@ -35,8 +36,8 @@ static void node_blend_display(struct nk_context *ctx, struct node *node) {
blend_node->blend_val = nk_propertyf(ctx, "#Blend", 0.0f, blend_node->blend_val, 1.0f, 0.01f, 0.01f); blend_node->blend_val = nk_propertyf(ctx, "#Blend", 0.0f, blend_node->blend_val, 1.0f, 0.01f, 0.01f);
blend_amnt = blend_node->blend_val; blend_amnt = blend_node->blend_val;
} }
if(node->inputs[0].is_connected && node->inputs[1].is_connected) { if(node->inputs[0].is_connected && node->inputs[1].is_connected) {
blend_node->output_val.r = blend_node->input_val[0].r * (1.0f-blend_amnt) + blend_node->input_val[1].r * blend_amnt; blend_node->output_val.r = blend_node->input_val[0].r * (1.0f-blend_amnt) + blend_node->input_val[1].r * blend_amnt;
blend_node->output_val.g = blend_node->input_val[0].g * (1.0f-blend_amnt) + blend_node->input_val[1].g * blend_amnt; blend_node->output_val.g = blend_node->input_val[0].g * (1.0f-blend_amnt) + blend_node->input_val[1].g * blend_amnt;
@ -48,7 +49,7 @@ static void node_blend_display(struct nk_context *ctx, struct node *node) {
} }
} }
void node_blend_create(struct node_editor *editor, struct nk_vec2 position) { struct node_type_blend* node_blend_create(struct node_editor *editor, struct nk_vec2 position) {
struct node_type_blend* blend_node = (struct node_type_blend*)node_editor_add(editor, sizeof(struct node_type_blend), "Blend", nk_rect(position.x, position.y, 180, 130), 3, 1); struct node_type_blend* blend_node = (struct node_type_blend*)node_editor_add(editor, sizeof(struct node_type_blend), "Blend", nk_rect(position.x, position.y, 180, 130), 3, 1);
if (blend_node) { if (blend_node) {
const struct nk_colorf blank = {0.0f, 0.0f, 0.0f, 0.0f}; const struct nk_colorf blank = {0.0f, 0.0f, 0.0f, 0.0f};
@ -68,6 +69,7 @@ void node_blend_create(struct node_editor *editor, struct nk_vec2 position) {
blend_node->node.display_func = node_blend_display; blend_node->node.display_func = node_blend_display;
blend_node->node.eval_func = (void*(*)(struct node*, int)) node_blend_eval; blend_node->node.eval_func = (void*(*)(struct node*, int)) node_blend_eval;
} }
return blend_node;
} }

View File

@ -22,8 +22,8 @@ static void node_color_draw(struct nk_context *ctx, struct node *node)
int i; int i;
nk_layout_row_dynamic(ctx, 25, 1); nk_layout_row_dynamic(ctx, 25, 1);
nk_button_color(ctx, nk_rgba_cf(color_node->output_val)); nk_button_color(ctx, nk_rgba_cf(color_node->output_val));
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
if (color_node->node.inputs[i].is_connected) { if (color_node->node.inputs[i].is_connected) {
eval_result = *(float*)node_editor_eval_connected(node, i); eval_result = *(float*)node_editor_eval_connected(node, i);
@ -42,14 +42,14 @@ static void node_color_draw(struct nk_context *ctx, struct node *node)
color_node->output_val.a = color_val[3]; color_node->output_val.a = color_val[3];
} }
void node_color_create(struct node_editor *editor, struct nk_vec2 position) struct node_type_color * node_color_create(struct node_editor *editor, struct nk_vec2 position)
{ {
struct node_type_color *color_node = (struct node_type_color*)node_editor_add(editor, sizeof(struct node_type_color), "Color", nk_rect(position.x, position.y, 180, 190), 4, 1); struct node_type_color *color_node = (struct node_type_color*)node_editor_add(editor, sizeof(struct node_type_color), "Color", nk_rect(position.x, position.y, 180, 190), 4, 1);
if (color_node) if (color_node)
{ {
int i; int i;
const struct nk_colorf white = {1.0f, 1.0f, 1.0f, 1.0f}; const struct nk_colorf white = {1.0f, 1.0f, 1.0f, 1.0f};
color_node->node.slot_spacing.in_top = 72.0f; color_node->node.slot_spacing.in_top = 72.0f;
color_node->node.slot_spacing.in_space = 29.0f; color_node->node.slot_spacing.in_space = 29.0f;
color_node->node.slot_spacing.out_top = 42.0f; color_node->node.slot_spacing.out_top = 42.0f;
@ -58,10 +58,10 @@ void node_color_create(struct node_editor *editor, struct nk_vec2 position)
for (i = 0; i < color_node->node.input_count; i++) for (i = 0; i < color_node->node.input_count; i++)
color_node->node.inputs[i].type = fValue; color_node->node.inputs[i].type = fValue;
color_node->node.outputs[0].type = fColor; color_node->node.outputs[0].type = fColor;
color_node->input_val[0] = color_node->input_val[0] =
color_node->input_val[1] = color_node->input_val[1] =
color_node->input_val[2] = color_node->input_val[2] =
color_node->input_val[3] = 1.0f; color_node->input_val[3] = 1.0f;
color_node->output_val = white; color_node->output_val = white;
@ -69,4 +69,5 @@ void node_color_create(struct node_editor *editor, struct nk_vec2 position)
color_node->node.display_func = node_color_draw; color_node->node.display_func = node_color_draw;
color_node->node.eval_func = (void*(*)(struct node*, int)) node_color_eval; color_node->node.eval_func = (void*(*)(struct node*, int)) node_color_eval;
} }
return color_node;
} }

View File

@ -15,7 +15,7 @@ static void node_float_draw(struct nk_context *ctx, struct node *node) {
float_node->output_val = nk_propertyf(ctx, "#Value:", 0.0f, float_node->output_val, 1.0f, 0.01f, 0.01f); float_node->output_val = nk_propertyf(ctx, "#Value:", 0.0f, float_node->output_val, 1.0f, 0.01f, 0.01f);
} }
void node_float_create(struct node_editor *editor, struct nk_vec2 position) { struct node_type_float *node_float_create(struct node_editor *editor, struct nk_vec2 position) {
struct node_type_float *float_node = (struct node_type_float*)node_editor_add(editor, sizeof(struct node_type_float), "Float", nk_rect(position.x, position.y, 180, 75), 0, 1); struct node_type_float *float_node = (struct node_type_float*)node_editor_add(editor, sizeof(struct node_type_float), "Float", nk_rect(position.x, position.y, 180, 75), 0, 1);
if (float_node) if (float_node)
{ {
@ -23,4 +23,5 @@ void node_float_create(struct node_editor *editor, struct nk_vec2 position) {
float_node->node.display_func = node_float_draw; float_node->node.display_func = node_float_draw;
float_node->node.eval_func = (void*(*)(struct node*, int)) node_float_eval; float_node->node.eval_func = (void*(*)(struct node*, int)) node_float_eval;
} }
return float_node;
} }