diff options
| author | Vito Caputo <vcaputo@pengaru.com> | 2019-05-09 19:40:42 -0700 | 
|---|---|---|
| committer | Vito Caputo <vcaputo@pengaru.com> | 2019-05-10 14:18:28 -0700 | 
| commit | 277ead61dc5ff6bba1035acf7b6e194e6de739ad (patch) | |
| tree | 7cc093ff4aed45085e10b1412939c254e6a1dfd9 | |
| parent | 049d14269ac518135a278132efe2ac01f92482e6 (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.c | 268 | ||||
| -rw-r--r-- | src/stage.h | 34 | 
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 | 
