demo: Add node editor example
This commit is contained in:
parent
862405f8be
commit
8e0e80b516
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue