summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2019-05-09 19:40:42 -0700
committerVito Caputo <vcaputo@pengaru.com>2019-05-10 14:18:28 -0700
commit277ead61dc5ff6bba1035acf7b6e194e6de739ad (patch)
tree7cc093ff4aed45085e10b1412939c254e6a1dfd9
parent049d14269ac518135a278132efe2ac01f92482e6 (diff)
libstage: deprecate stage_node_*, go heirarchical
Now stage_t is the only type, and a tree of stages may be constructed by supplying a parent to stage_new(). Essentially stage_t swallowed stage_node_t. The heirarchy is handy for grouping stages logically, and alpha is computed statefully during the recursive render. So alpha of grouped stages may be varied at a single parent. The active flag is also honored recursively for a similar effect; toggle subtrees in a single place. Container stages may be created by omitting object/render/free attributes. These are handy for the aforementioned group alpha/active controls.
-rw-r--r--src/stage.c268
-rw-r--r--src/stage.h34
2 files changed, 139 insertions, 163 deletions
diff --git a/src/stage.c b/src/stage.c
index d97cadf..806b633 100644
--- a/src/stage.c
+++ b/src/stage.c
@@ -22,191 +22,181 @@
#include "stage.h"
-struct stage_node_t {
- dll_t nodes;
- char name[STAGE_NODE_NAME_MAX];
- float alpha; /* alpha for the texture when composited */
- unsigned active:1; /* node is active */
- unsigned locked:1; /* node is locked */
-
- stage_render_func_t render; /* render object into a texture */
+struct stage_t {
+ stage_t *parent; /* NULL when root stage */
+ dll_t layer; /* node on parent->layers[layer] when parent != NULL */
+ dll_t layers[STAGE_LAYERS_MAX];
+ char name[STAGE_NAME_MAX];
+ float alpha; /* alpha for the stage */
+ unsigned active:1; /* stage is active */
+ unsigned locked:1; /* stage is locked */
+
+ stage_render_func_t render; /* render object */
stage_free_func_t free; /* free object */
void *object; /* object */
};
-struct stage_t {
- dll_t layers[STAGE_LAYERS_MAX];
- float alpha; /* alpha to apply to all nodes */
-};
-
-
-/* minimally initialize a node to carry an object */
-static void node_init(stage_node_t *node, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func)
+/* minimally initialize a stage to carry an object */
+static void _stage_set_object(stage_t *stage, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func)
{
- strncpy(node->name, name, sizeof(node->name));
- node->render = render_func;
- node->free = free_func;
- node->object = object;
+ strncpy(stage->name, name, sizeof(stage->name));
+ stage->render = render_func;
+ stage->free = free_func;
+ stage->object = object;
}
-/* allocate a node, no list manipulation occurs, this purely creates a node in isolation and assigns its associated name, object and functions */
-static stage_node_t * node_new(const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func)
+/* allocate a stage, this purely creates a stage in isolation and assigns its associated name, object and functions */
+static stage_t * _stage_new(const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func)
{
- stage_node_t *node;
+ stage_t *stage;
- node = calloc(1, sizeof(stage_node_t));
- if (!node)
+ stage = calloc(1, sizeof(stage_t));
+ if (!stage)
return NULL;
- node_init(node, name, object, render_func, free_func);
+ dll_init(&stage->layer);
+ for (int i = 0; i < STAGE_LAYERS_MAX; i++)
+ dll_init(&stage->layers[i]);
- return node;
+ _stage_set_object(stage, name, object, render_func, free_func);
+
+ return stage;
}
-/* free a node, no list manipulation occurs, this is purely cleanup of the node and its associated texture and object */
-static void node_free(stage_t *stage, stage_node_t *node)
+/* free a stage, no list manipulation occurs, this is purely cleanup of the stage and its object */
+static void _stage_free(stage_t *stage)
{
- if (node->free)
- node->free(stage, node, node->object);
+ if (stage->free)
+ stage->free(stage, stage->object);
- free(node);
+ free(stage);
}
-/* returns a new node installed at the specified layer */
-stage_node_t * stage_node_new(stage_t *stage, int layer, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func)
+/* returns a new stage, attached at the specified layer under parent if supplied */
+/* layer has no effect when parent == NULL */
+stage_t * stage_new(stage_t *parent, int layer, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func)
{
- stage_node_t *node;
+ stage_t *stage;
- node = node_new(name, object, render_func, free_func);
- if (!node)
+ stage = _stage_new(name, object, render_func, free_func);
+ if (!stage)
return NULL;
- (void) dll_add_pre(&node->nodes, &stage->layers[layer]);
+ if (parent) {
+ stage->parent = parent;
+ (void) dll_add_pre(&parent->layers[layer], &stage->layer);
+ }
- return node;
+ return stage;
}
-/* replace a given node's object only - retain render/free hooks and everything else, invalidates cache - DOES NOT FREE OLD OBJECT */
-void stage_node_set_object(const stage_t *stage, stage_node_t *node, void *object)
+/* replace a given stage's object only - retain render/free hooks and everything else, invalidates cache - DOES NOT FREE OLD OBJECT */
+void stage_set_object(stage_t *stage, void *object)
{
- node->object = object;
+ stage->object = object;
}
-void stage_node_get_object(const stage_t *stage, stage_node_t *node, void **res_object)
+void stage_get_object(const stage_t *stage, void **res_object)
{
- *res_object = node->object;
+ *res_object = stage->object;
}
-/* replaces a given node's object-related properties but otherwise keeping the existing state */
-void stage_node_replace(const stage_t *stage, stage_node_t *node, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func)
+/* replaces a given stage's object-related properties but otherwise keeping the existing state */
+void stage_replace(stage_t *stage, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func)
{
- if (node->free)
- node->free(stage, node, node->object);
+ if (stage->free)
+ stage->free(stage, stage->object);
- node_init(node, name, object, render_func, free_func);
+ _stage_set_object(stage, name, object, render_func, free_func);
}
-/* frees a given node removing it from the stage */
-stage_node_t * stage_node_free(stage_t *stage, stage_node_t *node)
+static void _stage_free_all(stage_t *stage, int force);
+
+
+/* recursively free the layers of this stage, but not the stage itself */
+static void _stage_free_layers(stage_t *stage, int force)
{
- if (node) {
- (void) dll_del(&node->nodes);
- node_free(stage, node);
- }
+ for (int i = 0; i < STAGE_LAYERS_MAX; i++) {
+ stage_t *s, *_s;
- return NULL;
+ DLL_FOR_EACH_ENTRY_SAFE(&stage->layers[i], s, _s, stage_t, layer)
+ _stage_free_all(s, force);
+ }
}
-/* set the alpha on a node */
-void stage_node_set_alpha(const stage_t *stage, stage_node_t *node, float alpha)
+/* free the stage recursively, skipping locked stages if !force */
+static void _stage_free_all(stage_t *stage, int force)
{
- /* TODO: this should probably mark something dirty for when we stop always recomposing everything */
- node->alpha = alpha;
+ if (stage->locked && !force)
+ return;
+
+ _stage_free_layers(stage, force);
+ dll_del(&stage->layer);
+ _stage_free(stage);
}
-/* set a node's active state (participates in rendering) */
-void stage_node_set_active(const stage_t *stage, stage_node_t *node, int active)
+/* frees a given stage and all its descendants, removing from its
+ * parent if not root.
+ */
+stage_t * stage_free(stage_t *stage)
{
- node->active = active;
+ if (stage)
+ _stage_free_all(stage, 1);
+
+ return NULL;
}
-/* set a node's locked state (doesn't get freed by clears) */
-void stage_node_set_locked(const stage_t *stage, stage_node_t *node, int locked)
+/* set the alpha on a stage */
+void stage_set_alpha(stage_t *stage, float alpha)
{
- node->locked = locked;
+ stage->alpha = alpha;
}
-/* set a node's layer */
-void stage_node_set_layer(stage_t *stage, stage_node_t *node, int layer)
+/* set a stage's active state (participates in rendering) */
+void stage_set_active(stage_t *stage, int active)
{
- /* TODO: assert layer sanity */
- (void) dll_del(&node->nodes);
- (void) dll_add_pre(&node->nodes, &stage->layers[layer]);
+ stage->active = active;
}
-/* create a new stage with the given aspect ratio */
-stage_t * stage_new(void)
+/* set a stage's locked state (doesn't get freed by clears) */
+void stage_set_locked(stage_t *stage, int locked)
{
- stage_t *stage;
- int i;
-
- stage = calloc(1, sizeof(stage_t));
- if (!stage)
- return NULL;
-
- for (i = 0; i < STAGE_LAYERS_MAX; i++)
- (void) dll_init(&stage->layers[i]);
-
- return stage;
+ stage->locked = locked;
}
-static void _stage_clear(stage_t *stage, int force)
+/* set a stage's layer (must not be root stage) */
+/* TODO: maybe support supplying a parent here for switching parents? */
+void stage_set_layer(stage_t *stage, int layer)
{
- stage_node_t *node, *_node;
- int i;
-
- for (i = 0; i < STAGE_LAYERS_MAX; i++) {
- DLL_FOR_EACH_ENTRY_SAFE(&stage->layers[i], node, _node, stage_node_t, nodes) {
- if (force || !node->locked)
- stage_node_free(stage, node);
- }
+ /* TODO: assert parent, and layer sanity */
+ if (stage->parent) {
+ (void) dll_del(&stage->layer);
+ (void) dll_add_pre(&stage->parent->layers[layer], &stage->layer);
}
}
+
/* free everything in the stage, but keep the stage around */
/* probably good hygiene to clear everything when there's no intention of
- * reusing nodes at the start of a new context, in case something is left
+ * reusing stages at the start of a new context, in case something is left
* around unintentionally. */
void stage_clear(stage_t *stage)
{
- _stage_clear(stage, 0);
-}
-
-
-/* free the supplied stage and all associated textures and objects */
-stage_t * stage_free(stage_t *stage)
-{
-
- if (stage) {
- _stage_clear(stage, 1);
- free(stage);
- }
-
- return NULL;
+ _stage_free_layers(stage, 0);
}
@@ -232,58 +222,50 @@ void stage_fit(float aspect_ratio, int width, int height, int *res_width, int *r
}
-/* set the global alpha factor for the stage, the individual node alphas are multiplied by this value @ render time. */
-void stage_set_alpha(stage_t *stage, float alpha)
-{
- stage->alpha = alpha;
-}
-
-
-/* get the global alpha factor for the stage */
-void stage_get_alpha(stage_t *stage, float *res_alpha)
+static void _render_stage(const stage_t *stage, float alpha)
{
- *res_alpha = stage->alpha;
-}
+ float a = alpha * stage->alpha;
+ if (stage->render)
+ stage->render(stage, stage->object, a);
-static void render_nodes(const stage_t *stage, const dll_t *nodes)
-{
- stage_node_t *node;
+ for (int i = 0; i < STAGE_LAYERS_MAX; i++) {
+ stage_t *s;
- DLL_FOR_EACH_ENTRY(nodes, node, stage_node_t, nodes) {
- if (!node->active)
- continue;
+ DLL_FOR_EACH_ENTRY(&stage->layers[i], s, stage_t, layer) {
+ if (!s->active)
+ continue;
- node->render(stage, node, node->object, stage->alpha * node->alpha);
+ _render_stage(s, a);
+ }
}
}
-/* render the supplied stage into the supplied renderer */
-/* the aspect_ratio of the stage will be enforced in filling the logical size
- * of the renderer. Unless the aspect ratio matches precisely, stage_render()
- * will center the rendering and leave blank borders on the edges left empty.
- * The renderer may be sized precisely by first calling stage_fit().
- */
+/* recursively render the supplied stage tree, skipping inactive branches */
void stage_render(const stage_t *stage)
{
- int i;
+ if (!stage->active)
+ return;
- for (i = 0; i < STAGE_LAYERS_MAX; i++)
- render_nodes(stage, &stage->layers[i]);
+ _render_stage(stage, 1.f);
}
-/* lookup a node from a name */
-stage_node_t * stage_node_lookup_name(const stage_t *stage, const char *name)
+/* lookup a stage from a name, returns first match */
+stage_t * stage_lookup_name(stage_t *stage, const char *name)
{
- stage_node_t *node;
- int i;
+ if (!strncmp(stage->name, name, sizeof(stage->name)))
+ return stage;
+
+ /* FIXME: this should probably search layers in descending order */
+ for (int i = 0; i < STAGE_LAYERS_MAX; i++) {
+ stage_t *s;
- for (i = 0; i < STAGE_LAYERS_MAX; i++) {
- DLL_FOR_EACH_ENTRY(&stage->layers[i], node, stage_node_t, nodes) {
- if (!strncmp(node->name, name, sizeof(node->name)))
- return node;
+ DLL_FOR_EACH_ENTRY(&stage->layers[i], s, stage_t, layer) {
+ s = stage_lookup_name(s, name);
+ if (s)
+ return s;
}
}
diff --git a/src/stage.h b/src/stage.h
index 942174a..8357206 100644
--- a/src/stage.h
+++ b/src/stage.h
@@ -17,32 +17,26 @@
#ifndef _STAGE_H
#define _STAGE_H
-#define STAGE_NODE_NAME_MAX 16
+#define STAGE_NAME_MAX 16
#define STAGE_LAYERS_MAX 10
typedef struct stage_t stage_t;
-typedef struct stage_node_t stage_node_t;
-typedef void (*stage_render_func_t)(const stage_t *stage, const stage_node_t *node, void *object, float alpha);
-typedef void (*stage_free_func_t)(const stage_t *stage, const stage_node_t *node, void *object);
+typedef void (*stage_render_func_t)(const stage_t *stage, void *object, float alpha);
+typedef void (*stage_free_func_t)(const stage_t *stage, void *object);
-stage_t * stage_new(void);
-void stage_clear(stage_t *stage);
+stage_t * stage_new(stage_t *parent, int layer, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func);
stage_t * stage_free(stage_t *stage);
-void stage_fit(float aspect_ratio, int width, int height, int *res_width, int *res_height);
-void stage_set_alpha(stage_t *stage, float alpha);
-void stage_get_alpha(stage_t *stage, float *res_alpha);
void stage_render(const stage_t *stage);
-stage_node_t * stage_node_new(stage_t *stage, int layer, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func);
-
-void stage_node_set_object(const stage_t *stage, stage_node_t *node, void *object);
-void stage_node_get_object(const stage_t *stage, stage_node_t *node, void **res_object);
-void stage_node_replace(const stage_t *stage, stage_node_t *node, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func);
-stage_node_t * stage_node_free(stage_t *stage, stage_node_t *node);
-void stage_node_set_alpha(const stage_t *stage, stage_node_t *node, float alpha);
-void stage_node_set_active(const stage_t *stage, stage_node_t *node, int active);
-void stage_node_set_locked(const stage_t *stage, stage_node_t *node, int locked);
-void stage_node_set_layer(stage_t *stage, stage_node_t *node, int layer);
-stage_node_t * stage_node_lookup_name(const stage_t *stage, const char *name);
+void stage_clear(stage_t *stage);
+void stage_set_alpha(stage_t *stage, float alpha);
+void stage_get_alpha(const stage_t *stage, float *res_alpha);
+void stage_set_active(stage_t *stage, int active);
+void stage_set_locked(stage_t *stage, int locked);
+void stage_set_object(stage_t *stage, void *object);
+void stage_get_object(const stage_t *stage, void **res_object);
+void stage_replace(stage_t *stage, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func);
+void stage_set_layer(stage_t *stage, int layer);
+stage_t * stage_lookup_name(stage_t *stage, const char *name);
#endif
© All Rights Reserved