Compare commits

...
25 Commits
Author SHA1 Message Date
Patrick Jakobsen 12fe6abc25 Updated README 2023-10-19 15:16:07 +02:00
Patrick Jakobsen dd406fe7b4 Fixed borked font bitmap allocation size 2023-10-03 18:49:29 +02:00
Patrick Jakobsen 5be35aa3de Fixed issues cropping up from building -O3 2023-10-03 12:21:35 +02:00
Patrick Jakobsen 5e070521bc Can click button inside scrollable 2023-10-01 16:00:10 +02:00
Patrick Jakobsen f06ac04ea9 . 2023-10-01 14:26:45 +02:00
Patrick Jakobsen 80f5e9056a . 2023-10-01 14:26:25 +02:00
Patrick Jakobsen 4cdc17489e Implemented the top layer 2023-10-01 14:22:50 +02:00
Patrick Jakobsen 51174824b2 A fix for dirtiness 2023-10-01 12:34:21 +02:00
Patrick Jakobsen fe179f2eee Cleanup 2023-10-01 12:00:04 +02:00
Patrick Jakobsen 591a53e627 Scrollable region 2023-10-01 11:35:02 +02:00
Patrick Jakobsen 44d375af29 Fixed gui_push_parent and gui_pop_parent using wrong subtree 2023-10-01 09:17:09 +02:00
Patrick Jakobsen 861e774dee Disabled a debugging printing 2023-09-28 15:44:38 +02:00
Patrick Jakobsen dc39f583f4 Subtrees get dirtied when their clipnodes do 2023-09-28 15:43:47 +02:00
Patrick Jakobsen b2b8e68046 Started on clipping 2023-09-28 13:37:27 +02:00
Patrick Jakobsen e3940cc986 Added inline function for reference validity 2023-09-28 13:37:06 +02:00
Patrick Jakobsen ebbf17cb42 gui nodes now end up where they are supposed to 2023-09-28 13:03:25 +02:00
Patrick Jakobsen 592b26fc10 revised print_node_tree 2023-09-28 11:56:01 +02:00
Patrick Jakobsen 2db1602172 Fixed errorneous dirty-redraw of siblings 2023-09-28 11:39:05 +02:00
Patrick Jakobsen 9477dc3115 Added TODO about revising the dirty system 2023-09-28 11:03:54 +02:00
Patrick Jakobsen d947cc9eeb Recursive subtree layouting and drawing 2023-09-28 10:55:04 +02:00
Patrick Jakobsen e12892f688 test_gui__subtree doesn't crash, but also doesn't work 2023-09-28 10:08:17 +02:00
Patrick Jakobsen 0cb37f5596 Got some input working again 2023-09-28 09:58:25 +02:00
Patrick Jakobsen eeb0430300 WIP GUI_Layer, at partial working state 2023-09-26 16:29:00 +02:00
Patrick Jakobsen c32e0cee2c Introduced a level of indirection for the rdic freelist 2023-09-26 13:37:09 +02:00
Patrick Jakobsen 0473625a82 updated rdic_test for new references_equal name 2023-09-26 13:25:33 +02:00
5 changed files with 1129 additions and 247 deletions

No files matched your search

+30 -1
View File
@@ -1,2 +1,31 @@
# RDIC # RDIC - Retained Data, Immediate Code
Serious GUI programming has long been dominated by retained mode APIs, where a tree of GUI objects that hold function pointers for callbacks is built and a central "do the GUI thing" procedure is called, which takes care of handling all the GUI functionality and calls the callbacks as necessary.
A competitor to retained mode GUIs is the immediate mode GUI paradigm, which prioritizes locality of GUI element definition and its behavior.
The specification of GUI elements is done by calling procedures that instantiate them every frame that they should appear on the screen.
For instance, a button is achieved by calling some procedure, e.g. `gui_button`, which would return true if the button was clicked on and false otherwise.
There are tradeoffs in choosing one or the other. Retained mode required you to use inversion of control, which to some is a violation of good programming principles.
Immediate mode is in many regards simpler, but has the downside that it forgoes exposing a data structure to the user at all, and has to use clever techniques to identify the same GUI elements across frames.
The RDIC approach combines retained and immediate techniques.
In retained mode it is normal to use handles into a behind-the-scenes data structure, which is used to make state changes requests in order to manipulate the GUI.
RDIC introduces the use of references into an exposed, retained data structure, where you re-use your references across frames, in an immediate style API.
When passing the same, stable reference to e.g. a button call every frame, it is determined that this is in fact the same button across consecutive frames.
RDIC example:
```C
static RDIC_Reference my_button = {0};
if(button(&my_button, "Button Label")) {
printf("Printed if button is clicked.\n");
}
```
The stable data structure in RDIC can be leveraged for features such as accessibility.
One example of how this data structure is used in the example GUI in this repository is conditional redrawing. It stores a "dirty" flag with each node, which is used to skip over non-"dirty" nodes when generating draw commands. This is very useful for the implementation, which draws using only the CPU.
+1 -1
View File
@@ -1 +1 @@
gcc -g -Wall -Wextra $1 -fsanitize=address,undefined gui.c stb_truetype.o -lX11 -lm gcc -g -Wall -Wextra -Wno-stringop-overflow $1 -fsanitize=address,undefined gui.c stb_truetype.o -lX11 -lm
+1040 -214
View File
File diff suppressed because it is too large. Load diff
+21 -9
View File
@@ -27,9 +27,13 @@ typedef struct {
// NOTE(Zelaven): This idea is bad because it assumes that a reference won't be reallocated. Generations are much more reliable. // NOTE(Zelaven): This idea is bad because it assumes that a reference won't be reallocated. Generations are much more reliable.
typedef struct {
RDIC_Node *head;
} RDIC_Freelist;
typedef struct { typedef struct {
RDIC_Node *root; RDIC_Node *root;
RDIC_Node *node_freelist; RDIC_Freelist *freelist;
RDIC_Node *current_parent; RDIC_Node *current_parent;
RDIC_Node *frame_current_node; RDIC_Node *frame_current_node;
@@ -43,6 +47,12 @@ static inline int rdic_node_references_equal(
return (n.node == m.node) && (n.generation == m.generation); return (n.node == m.node) && (n.generation == m.generation);
} }
static inline int rdic_node_reference_valid(
RDIC_Node_Reference n)
{
return (n.node != NULL) && (n.generation == n.node->generation);
}
enum { enum {
RDIC_GET_NODE__NODES_COLLECTED = 1 << 0, RDIC_GET_NODE__NODES_COLLECTED = 1 << 0,
RDIC_GET_NODE__NODE_ALLOCATED = 1 << 1, RDIC_GET_NODE__NODE_ALLOCATED = 1 << 1,
@@ -146,9 +156,9 @@ void rdic_cull_subtrees(
} }
} }
current->sibling = context->node_freelist; current->sibling = context->freelist->head;
current->generation += 1; // Invalidate references. current->generation += 1; // Invalidate references.
context->node_freelist = current; context->freelist->head = current;
current = next; current = next;
} }
@@ -165,17 +175,19 @@ RDIC_Node_Reference rdic_context_start_frame(
RDIC_Node_Reference node_reference = last_root; RDIC_Node_Reference node_reference = last_root;
int need_new_node = (last_root.node == NULL) int need_new_node = (last_root.node == NULL)
|| (last_root.generation != last_root.node->generation); || (last_root.generation != last_root.node->generation);
if(need_new_node && context->node_freelist == NULL) int can_get_node_from_freelist =
(context->freelist == NULL || context->freelist->head == NULL);
if(need_new_node && can_get_node_from_freelist)
{ {
return (RDIC_Node_Reference){0}; return (RDIC_Node_Reference){0};
} }
if(need_new_node) if(need_new_node)
{ {
RDIC_Node_Reference result; RDIC_Node_Reference result;
result.node = context->node_freelist; result.node = context->freelist->head;
result.generation = result.node->generation; result.generation = result.node->generation;
context->node_freelist = context->node_freelist->sibling; context->freelist->head = context->freelist->head->sibling;
RDIC_Node *root = result.node; RDIC_Node *root = result.node;
root->sibling = NULL; root->sibling = NULL;
@@ -260,7 +272,7 @@ RDIC_Node_Reference rdic_get_node(
reference_is_valid reference_is_valid
&& (context->current_parent == node_reference.node->parent); && (context->current_parent == node_reference.node->parent);
if(!reference_is_valid && context->node_freelist == NULL) if(!reference_is_valid && context->freelist->head == NULL)
{ {
if(out_flags != NULL) if(out_flags != NULL)
{ {
@@ -316,9 +328,9 @@ RDIC_Node_Reference rdic_get_node(
{ // Make new node { // Make new node
// NOTE(Zelaven): We guard against empty freelist, so this is safe. // NOTE(Zelaven): We guard against empty freelist, so this is safe.
RDIC_Node_Reference result = {0}; RDIC_Node_Reference result = {0};
result.node = context->node_freelist; result.node = context->freelist->head;
result.generation = result.node->generation; result.generation = result.node->generation;
context->node_freelist = context->node_freelist->sibling; context->freelist->head = context->freelist->head->sibling;
// TODO(Zelaven): Should the various fields be filled out here, or outside? // TODO(Zelaven): Should the various fields be filled out here, or outside?
// What will be the strategy to avoid redundant work? // What will be the strategy to avoid redundant work?
+37 -22
View File
@@ -48,7 +48,8 @@ void init_node_freelist(GUI_Node *nodes, int node_count)
RDIC_Context context = {0};\ RDIC_Context context = {0};\
GUI_Node freelist_nodes[FREELIST_LENGTH] = {0};\ GUI_Node freelist_nodes[FREELIST_LENGTH] = {0};\
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));\ init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));\
context.node_freelist = &freelist_nodes[0].rn;\ RDIC_Freelist freelist = {&freelist_nodes[0].rn};\
context.freelist = &freelist;\
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
@@ -74,7 +75,7 @@ RDIC_Node_Reference test_get_node(
// NOTE(Zelaven): Helpers can be buggy too and could in principle have tests. // NOTE(Zelaven): Helpers can be buggy too and could in principle have tests.
int freelist_contains(RDIC_Context *context, RDIC_Node *node) int freelist_contains(RDIC_Context *context, RDIC_Node *node)
{ {
RDIC_Node *current = context->node_freelist; RDIC_Node *current = context->freelist->head;
int result = 0; int result = 0;
while(!result && current != NULL) while(!result && current != NULL)
{ {
@@ -211,7 +212,8 @@ void test__start_frame__succeed(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[1] = {0}; GUI_Node freelist_nodes[1] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
// Act. // Act.
@@ -229,7 +231,8 @@ void test__finish_frame__succeed(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[1] = {0}; GUI_Node freelist_nodes[1] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
root = rdic_context_start_frame( root = rdic_context_start_frame(
&context, &context,
@@ -253,20 +256,21 @@ void test__get_node_with_empty_freelist__return_null_reference(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[1] = {0}; GUI_Node freelist_nodes[1] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
root = rdic_context_start_frame( root = rdic_context_start_frame(
&context, &context,
root); root);
assert(context.node_freelist == NULL);
// Act. // Act.
RDIC_Node_Reference node = {0}; // Invalid reference -> new node. RDIC_Node_Reference node = {0}; // Invalid reference -> new node.
node = GET_NODE(&context, node); node = GET_NODE(&context, node);
// Assert. // Assert.
// NOTE(Zelaven): We specifically assert that the reference is all 0. // NOTE(Zelaven): We specifically assert that the reference is all 0.
if(context.freelist->head != NULL)
{TEST_ERROR("Freelist not empty.");}
if(node.node != NULL) if(node.node != NULL)
{TEST_ERROR("Non-NULL node despite empty freelist.");} {TEST_ERROR("Non-NULL node despite empty freelist.");}
if(node.generation != 0) if(node.generation != 0)
@@ -279,7 +283,8 @@ void test__get_node_with_empty_freelist_with_nonzero_generation__return_null_ref
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[1] = {0}; GUI_Node freelist_nodes[1] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
root = rdic_context_start_frame( root = rdic_context_start_frame(
&context, &context,
@@ -304,7 +309,8 @@ void test__get_node__succeed(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[2] = {0}; GUI_Node freelist_nodes[2] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
root = rdic_context_start_frame( root = rdic_context_start_frame(
&context, &context,
@@ -329,7 +335,8 @@ void test__get_node_finish_frame__succeed(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[2] = {0}; GUI_Node freelist_nodes[2] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
root = rdic_context_start_frame( root = rdic_context_start_frame(
&context, &context,
@@ -381,7 +388,7 @@ void test__single_node__returned_to_freelist(void)
if(node.node->generation != 1) if(node.node->generation != 1)
{TEST_ERROR("Node submitted to freelist increased generation more than once?");} {TEST_ERROR("Node submitted to freelist increased generation more than once?");}
ASSERT_REFERENCE_INVALID(node, "(Skipped in second frame)"); ASSERT_REFERENCE_INVALID(node, "(Skipped in second frame)");
if(context.node_freelist != node.node) if(context.freelist->head != node.node)
{TEST_ERROR("Node not prepended to freelist.");} {TEST_ERROR("Node not prepended to freelist.");}
@@ -390,7 +397,7 @@ void test__single_node__returned_to_freelist(void)
} }
#define ASSERT_REFERENCES_EQUAL(REF1, REF2)\ #define ASSERT_REFERENCES_EQUAL(REF1, REF2)\
if(!gui_node_references_equal((REF1), (REF2)))\ if(!rdic_node_references_equal((REF1), (REF2)))\
{TEST_ERROR("`"#REF1"` != `"#REF2"`.\n");} {TEST_ERROR("`"#REF1"` != `"#REF2"`.\n");}
void test__single_node__nodes_are_stable(void) void test__single_node__nodes_are_stable(void)
{ {
@@ -398,7 +405,8 @@ void test__single_node__nodes_are_stable(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[2] = {0}; GUI_Node freelist_nodes[2] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
RDIC_Node_Reference node = {0}; RDIC_Node_Reference node = {0};
@@ -456,7 +464,7 @@ void test__single_node_freelist_reuse__succeed(void)
if(node.generation != 1) if(node.generation != 1)
{TEST_ERROR("`node` generation is not 1.");} {TEST_ERROR("`node` generation is not 1.");}
ASSERT_REFERENCE_VALID(node); ASSERT_REFERENCE_VALID(node);
if(context.node_freelist != NULL) if(context.freelist->head != NULL)
{TEST_ERROR("Freelist should be empty.");} {TEST_ERROR("Freelist should be empty.");}
} }
@@ -470,7 +478,8 @@ void test__parent_child_frame__succeed(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[3] = {0}; GUI_Node freelist_nodes[3] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
RDIC_Node_Reference parent_node = {0}; RDIC_Node_Reference parent_node = {0};
RDIC_Node_Reference child_node = {0}; RDIC_Node_Reference child_node = {0};
@@ -499,7 +508,8 @@ void test__parent_child_free_child__child_to_freelist(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[3] = {0}; GUI_Node freelist_nodes[3] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
RDIC_Node_Reference parent_node = {0}; RDIC_Node_Reference parent_node = {0};
RDIC_Node_Reference child_node = {0}; RDIC_Node_Reference child_node = {0};
@@ -530,7 +540,7 @@ void test__parent_child_free_child__child_to_freelist(void)
if(child_node.node->generation != 1) if(child_node.node->generation != 1)
{TEST_ERROR("Node submitted to freelist retained same generation?");} {TEST_ERROR("Node submitted to freelist retained same generation?");}
ASSERT_REFERENCE_INVALID(child_node, "(Skipped in second frame)"); ASSERT_REFERENCE_INVALID(child_node, "(Skipped in second frame)");
if(context.node_freelist != child_node.node) if(context.freelist->head != child_node.node)
{TEST_ERROR("Node not prepended to freelist.");} {TEST_ERROR("Node not prepended to freelist.");}
} }
@@ -540,7 +550,8 @@ void test__parent_child_free_child__parent_to_freelist(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[3] = {0}; GUI_Node freelist_nodes[3] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
RDIC_Node_Reference parent = {0}; RDIC_Node_Reference parent = {0};
RDIC_Node_Reference child = {0}; RDIC_Node_Reference child = {0};
@@ -642,7 +653,8 @@ void test__parent_child_both_reused__succeed(void)
RDIC_Context context = {0};\ RDIC_Context context = {0};\
GUI_Node freelist_nodes[5] = {0};\ GUI_Node freelist_nodes[5] = {0};\
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));\ init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));\
context.node_freelist = &freelist_nodes[0].rn;\ RDIC_Freelist freelist = {&freelist_nodes[0].rn};\
context.freelist = &freelist;\
RDIC_Node_Reference root = {0};\ RDIC_Node_Reference root = {0};\
RDIC_Node_Reference parent = {0};\ RDIC_Node_Reference parent = {0};\
RDIC_Node_Reference child1 = {0};\ RDIC_Node_Reference child1 = {0};\
@@ -816,7 +828,8 @@ void test__exhaust_freelist_larger_tree__no_crash(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[3] = {0}; GUI_Node freelist_nodes[3] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
RDIC_Node_Reference n1 = {0}; RDIC_Node_Reference n1 = {0};
RDIC_Node_Reference n1_1 = {0}; RDIC_Node_Reference n1_1 = {0};
@@ -879,7 +892,8 @@ void test__large_tree_constructed__succeed(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[14] = {0}; GUI_Node freelist_nodes[14] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
RDIC_Node_Reference n1 = {0}; RDIC_Node_Reference n1 = {0};
RDIC_Node_Reference n1_1 = {0}; RDIC_Node_Reference n1_1 = {0};
@@ -954,7 +968,8 @@ void test__culling_that_needs_to_use_stash__succeed(void)
RDIC_Context context = {0}; RDIC_Context context = {0};
GUI_Node freelist_nodes[14] = {0}; GUI_Node freelist_nodes[14] = {0};
init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes)); init_node_freelist(freelist_nodes, ARRAYLENGTH(freelist_nodes));
context.node_freelist = &freelist_nodes[0].rn; RDIC_Freelist freelist = {&freelist_nodes[0].rn};
context.freelist = &freelist;
RDIC_Node_Reference root = {0}; RDIC_Node_Reference root = {0};
RDIC_Node_Reference n1 = {0}; RDIC_Node_Reference n1 = {0};
RDIC_Node_Reference n1_1 = {0}; RDIC_Node_Reference n1_1 = {0};