diff options
| -rw-r--r-- | src/stage.c | 348 | ||||
| -rw-r--r-- | src/stage.h | 34 | 
2 files changed, 18 insertions, 364 deletions
| diff --git a/src/stage.c b/src/stage.c index cc8f618..6ded8a5 100644 --- a/src/stage.c +++ b/src/stage.c @@ -14,52 +14,29 @@   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ -#include <SDL.h> +#include <stdlib.h> +#include <string.h>  #include "list.h"  #include "stage.h" -typedef struct v2f_t { -	float	x, y; -} v2f_t; - -typedef struct aabb_t { -	v2f_t	min, max; -} aabb_t; - -typedef struct stage_cached_t { -	int		width, height; -	SDL_Texture	*texture; -} stage_cached_t;  struct stage_node_t {  	list_head_t		nodes;  	char			name[STAGE_NODE_NAME_MAX]; -	stage_cached_t		cached; -	aabb_t			aabb;		/* node coordinates expressed in the space of -1.0...1.0 */ -	stage_map_t		aabb_map; -	v2f_t			position;	/* position of node, optionally used to move aabb as a whole */ -	stage_map_t		position_map; -	v2f_t			origin;		/* origin of node, 0,0 being center of aabb (the default) this determines how position relates to aabb.  -1...1 being aabb.min ... aabb.max */  	float			alpha;		/* alpha for the texture when composited */ -	double			angle;		/* angle for the texture when composited */  	unsigned		active:1;	/* node is active */  	unsigned		locked:1;	/* node is locked */ -	unsigned		statik:1;	/* node is static */  	stage_render_func_t	render;		/* render object into a texture */  	stage_free_func_t	free;		/* free object */  	void			*object;	/* object */  }; +  struct stage_t {  	list_head_t	layers[STAGE_LAYERS_MAX]; -	SDL_Renderer	*renderer;		/* target renderer */ -	float		aspect_ratio;		/* width/height ratio of stage, -1.0...1.0 range of node coordinates map to this ratio. */ -	v2f_t		position;		/* position of the stage (defaults to 0,0) */  	float		alpha;			/* alpha to apply to all nodes */ -	stage_map_t	aabb_map;		/* aabb map for the stage, nodes inherit this setting at create time */ -	stage_map_t	position_map;		/* position map for the stage, nodes inherit this setting at create time */  }; @@ -89,12 +66,11 @@ static stage_node_t * node_new(const char *name, void *object, stage_render_func  /* 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_node_t *node) +static void node_free(stage_t *stage, stage_node_t *node)  {  	if (node->free) -		node->free(node->object); -	if (node->cached.texture) -		SDL_DestroyTexture(node->cached.texture); +		node->free(stage, node, node->object); +  	free(node);  } @@ -108,8 +84,6 @@ stage_node_t * stage_node_new(stage_t *stage, int layer, const char *name, void  	if (!node)  		return NULL; -	node->aabb_map = stage->aabb_map; -	node->position_map = stage->position_map;  	list_add_tail(&node->nodes, &stage->layers[layer]);  	return node; @@ -117,27 +91,12 @@ stage_node_t * stage_node_new(stage_t *stage, int layer, const char *name, void  /* replace a given node's object only - retain render/free hooks and everything else, invalidates cache  - DOES NOT FREE OLD OBJECT */ -/* FIXME: this is being used as a kludge to swap frames in an svg -  - * eliminate this bullshit and add support for animations or at least frames, - * the stage really shouldn't have anything to do with it, we can dick with - * the svg behind its back.  I just don't currently have the helpers for creating - * svg nodes actually giving out the bare svg handle currently, so the stage_node_t - * is all I have to dick with at the moment.  Next time!  This really dicks with - * the resource lifecycle - if the stage frees the node, which object was active - * at the time and which object still needs to be freed because it wasn't in - * the stage when the node was killed?  It's totally shitty, and I'm aware. - */  void stage_node_set_object(const stage_t *stage, stage_node_t *node, void *object)  { -	if (node->cached.texture) { -		SDL_DestroyTexture(node->cached.texture); -		node->cached.texture = NULL; -	} -  	node->object = object;  } -/* FIXME: GROSS fuck me */ +  void stage_node_get_object(const stage_t *stage, stage_node_t *node, void **res_object)  {  	*res_object = node->object; @@ -148,12 +107,7 @@ void stage_node_get_object(const stage_t *stage, stage_node_t *node, void **res_  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)  {  	if (node->free) -		node->free(node->object); - -	if (node->cached.texture) { -		SDL_DestroyTexture(node->cached.texture); -		node->cached.texture = NULL; -	} +		node->free(stage, node, node->object);  	node_init(node, name, object, render_func, free_func);  } @@ -164,7 +118,7 @@ stage_node_t * stage_node_free(stage_t *stage, stage_node_t *node)  {  	if (node) {  		list_del(&node->nodes); -		node_free(node); +		node_free(stage, node);  	}  	return NULL; @@ -179,49 +133,6 @@ void stage_node_set_alpha(const stage_t *stage, stage_node_t *node, float alpha)  } -/* set the aabb for a node */ -void stage_node_set_aabb(const stage_t *stage, stage_node_t *node, const aabb_t *aabb) -{ -	node->aabb = *aabb; -} - - -/* get the aabb for a node */ -void stage_node_get_aabb(const stage_t *stage, const stage_node_t *node, aabb_t *res_aabb) -{ -	*res_aabb = node->aabb; -} - - -/* set the position for a node */ -void stage_node_set_position(const stage_t *stage, stage_node_t *node, v2f_t *position) -{ -	node->position = *position; -} - - -/* get the position for a node */ -void stage_node_get_position(const stage_t *stage, const stage_node_t *node, v2f_t *res_position) -{ -	*res_position = node->position; -} - - -/* set the origin for a node */ -void stage_node_set_origin(const stage_t *stage, stage_node_t *node, v2f_t *origin) -{ -	node->origin = *origin; -} - - -/* get the origin for a node */ -void stage_node_get_origin(const stage_t *stage, const stage_node_t *node, v2f_t *res_origin) -{ - -	*res_origin = node->origin; -} - -  /* set a node's active state (participates in rendering) */  void stage_node_set_active(const stage_t *stage, stage_node_t *node, int active)  { @@ -236,14 +147,6 @@ void stage_node_set_locked(const stage_t *stage, stage_node_t *node, int locked)  } -/* set a node to static (isn't influenced by external position/origin/aabb changes, solely its own positin/origin/aabb) */ -void stage_node_set_static(const stage_t *stage, stage_node_t *node, int statik) -{ -	/* I deliberately spelled statik to avoid language keyword collision */ -	node->statik = statik; -} - -  /* set a node's layer */  void stage_node_set_layer(stage_t *stage, stage_node_t *node, int layer)  { @@ -253,32 +156,8 @@ void stage_node_set_layer(stage_t *stage, stage_node_t *node, int layer)  } -void stage_node_set_angle(const stage_t *stage, stage_node_t *node, double angle) -{ -	node->angle = angle; -} - - -void stage_node_set_aabb_map(const stage_t *stage, stage_node_t *node, stage_map_t map) -{ -	node->aabb_map = map; -} - - -void stage_node_set_position_map(const stage_t *stage, stage_node_t *node, stage_map_t map) -{ -	node->position_map = map; -} - - -void stage_node_get_angle(const stage_t *stage, stage_node_t *node, double *res_angle) -{ -	*res_angle = node->angle; -} - -  /* create a new stage with the given aspect ratio */ -stage_t * stage_new(SDL_Renderer *renderer, float aspect_ratio) +stage_t * stage_new(void)  {  	stage_t	*stage;  	int	i; @@ -290,12 +169,10 @@ stage_t * stage_new(SDL_Renderer *renderer, float aspect_ratio)  	for (i = 0; i < STAGE_LAYERS_MAX; i++)  		INIT_LIST_HEAD(&stage->layers[i]); -	stage->renderer = renderer; -	stage->aspect_ratio = aspect_ratio; -  	return stage;  } +  static void _stage_clear(stage_t *stage, int force)  {  	stage_node_t	*node, *_node; @@ -368,169 +245,19 @@ void stage_get_alpha(stage_t *stage, float *res_alpha)  } -/* set the global position for the stage, all nodes are shifted by this @ render time */ -void stage_set_position(stage_t *stage, v2f_t *position) -{ -	stage->position = *position; -} - - -/* get the global position for the stage */ -void stage_get_position(stage_t *stage, v2f_t *res_position) -{ -	*res_position = stage->position; -} - - -/* set the aabb mapping for the stage */ -void stage_set_aabb_map(stage_t *stage, stage_map_t map) -{ -	stage->aabb_map = map; -} - - -/* set the position mapping for the stage */ -void stage_set_position_map(stage_t *stage, stage_map_t map) -{ -	stage->position_map = map; -} - - -static void map_stage_rect(const stage_t *stage, const SDL_Rect *stage_rect, stage_map_t map, float *res_w, float *res_h) -{ -	switch (map) { -	case STAGE_MAP_FILL: -		*res_w = stage_rect->w; -		*res_h = stage_rect->h; -		break; - -	case STAGE_MAP_MINSQ: -		if (stage_rect->w < stage_rect->h) { -			*res_w = stage_rect->w; -			*res_h = stage_rect->w; -		} else { -			*res_w = stage_rect->h; -			*res_h = stage_rect->h; -		} -		break; - -	case STAGE_MAP_MAXSQ: -		if (stage_rect->w > stage_rect->h) { -			*res_w = stage_rect->w; -			*res_h = stage_rect->w; -		} else { -			*res_w = stage_rect->h; -			*res_h = stage_rect->h; -		} -		break; -	} -} - - -/* translate a node's aabb within the given stage to a rect witin stage_rect, storing result in *res_rect */ -static void node_to_rect(const stage_t *stage, const stage_node_t *node, const SDL_Rect *stage_rect, SDL_Rect *res_rect) -{ -	float	aabb_w = (node->aabb.max.x - node->aabb.min.x); -	float	aabb_h = (node->aabb.max.y - node->aabb.min.y); -	float	stage_w, stage_h; - -	/* center in stage_rect */ -	res_rect->x = stage_rect->x + floorf((float)stage_rect->w * .5f); -	res_rect->y = stage_rect->y + floorf((float)stage_rect->h * .5f); - -	/* compute virtual stage dimensions according to the node's aabb_map setting for aabb calculations */ -	map_stage_rect(stage, stage_rect, node->aabb_map, &stage_w, &stage_h); - -	/* res dimensions are simply aabb dimensions scaled by stage dimensions according to node->aabb_map */ -	res_rect->w = floorf(aabb_w * .5f * stage_w); -	res_rect->h = floorf(aabb_h * .5f * stage_h); - -	/* apply node->aabb (scaled relative to stage_rect) */ -	res_rect->x += floorf(node->aabb.min.x * .5f * stage_w); -	res_rect->y += -floorf(node->aabb.max.y * .5f * stage_h); - -	if (!node->statik) { -		/* apply stage->position (relative to stage_rect) */ -		res_rect->x += floorf(stage->position.x * .5f * (float)stage_rect->w); -		res_rect->y += -floorf(stage->position.y * .5f * (float)stage_rect->h); -	} - -	/* compute virtual stage dimensions according to the node's position_map setting for position calculations */ -	map_stage_rect(stage, stage_rect, node->position_map, &stage_w, &stage_h); - -	res_rect->x += floorf(node->position.x * .5f * (float)stage_w); -	res_rect->y += -floorf(node->position.y * .5f * (float)stage_h); - -	/* apply node->origin (scaled relative to scaled aabb_w) (this probably needs to be inverted) */ -	res_rect->x += floorf(node->origin.x * .5f * (float)res_rect->w); -	res_rect->y += -floorf(node->origin.y * .5f * (float)res_rect->h); - -	/* Prevent producing 0-dimensioned non-zero rects even if it's technicaly incorrect, -	 * what's likely going on is the window has been resized very small.  Rather -	 * than allowing things to become completely invisible in such circumstances, -	 * give them at least a single pixel. -	 */ -	if (res_rect->w == 0 && aabb_w > 0.f) -		res_rect->w = 1; - -	if (res_rect->h == 0 && aabb_h > 0.f) -		res_rect->h = 1; -} - - -static void render_nodes(const stage_t *stage, const list_head_t *head, SDL_Renderer *renderer, SDL_Rect *dest_rect) +static void render_nodes(const stage_t *stage, const list_head_t *head)  {  	stage_node_t	*node;  	list_for_each_entry(node, head, nodes) { -		SDL_Rect	node_rect; -  		if (!node->active)  			continue; -		/* scale the node's aabb stage coordinates to destination renderer coordinates */ -		node_to_rect(stage, node, dest_rect, &node_rect); - -		/* if we have a cached texture, see if the dimensions changed */ -		if (node->cached.texture && -		    (node_rect.w != node->cached.width || -		     node_rect.h != node->cached.height)) { -			SDL_DestroyTexture(node->cached.texture); -			node->cached.texture = NULL; -		} - -		/* Tell the node to draw its cached texture */ -		/* The draw function may either use the existing texture when non-NULL or destroy and create a new one, -		 * whatever is most convenient for it. -		 * If the texture is NULL, a create & render must be performed, and 1 returned. -		 * If the texture is non-NULL, and there's no animation or anything to be done, 0 may simply be returned. -		 * Otherwise, if supplied a non-NULL texture and it's modified, 1 must be returned. -		 */ -		/* XXX: at this time, the return value is ignored (it always composites the stage even when unchanged) */ -		node->render(renderer, node->object, node_rect.w, node_rect.h, &node->cached.texture); -		node->cached.width = node_rect.w; -		node->cached.height = node_rect.h; -		SDL_SetTextureAlphaMod(node->cached.texture, stage->alpha * node->alpha * 255.0f); - -		/* copy the texture to renderer */ -		if (node->angle == 0) -			SDL_RenderCopy(renderer, node->cached.texture, NULL, &node_rect); -		else -			SDL_RenderCopyEx(renderer, node->cached.texture, NULL, &node_rect, node->angle, NULL, SDL_FLIP_NONE); +		node->render(stage, node, node->object, stage->alpha * node->alpha);  	}  } -/* XXX: ANOTHER KLUDGE FIXME */ -/* we shouldn't need to let this out of the stage, but for the mouse aiming - * it was easier this way for now. - */ -void stage_get_output_size(stage_t *stage, int *res_width, int *res_height) -{ -	SDL_GetRendererOutputSize(stage->renderer, res_width, res_height); -} - -  /* 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() @@ -539,20 +266,10 @@ void stage_get_output_size(stage_t *stage, int *res_width, int *res_height)   */  void stage_render(const stage_t *stage)  { -	SDL_Rect	rect; -	int		i, width, height; - -	/* XXX TODO: investigate renderer viewports and scale factors */ -	SDL_GetRendererOutputSize(stage->renderer, &width, &height); - -	stage_fit(stage->aspect_ratio, width, height, &rect.w, &rect.h); -	rect.x = (width - rect.w) / 2; -	rect.y = (height - rect.h) / 2; - -	SDL_RenderClear(stage->renderer);	/* TODO: handle -1 on error */ +	int	i;  	for (i = 0; i < STAGE_LAYERS_MAX; i++) -		render_nodes(stage, &stage->layers[i], stage->renderer, &rect); +		render_nodes(stage, &stage->layers[i]);  } @@ -571,38 +288,3 @@ stage_node_t * stage_node_lookup_name(const stage_t *stage, const char *name)  	return NULL;  } - - -/* lookup a node from a cartesian renderer coordinate */ -stage_node_t * stage_node_lookup_cartesian(const stage_t *stage, int x, int y) -{ -	stage_node_t	*node; -	SDL_Rect	rect; -	int		i, width, height; - -	/* FIXME: copy-pasta with render, factor out */ -	SDL_GetRendererOutputSize(stage->renderer, &width, &height); - -	stage_fit(stage->aspect_ratio, width, height, &rect.w, &rect.h); -	rect.x = (width - rect.w) / 2; -	rect.y = (height - rect.h) / 2; - -	/* this is currently very simple: find the first top-most node -	 * including the specified coordinate. -	 */ -	for (i = STAGE_LAYERS_MAX - 1; i >= 0; i--) { -		list_for_each_entry(node, &stage->layers[i], nodes) { -			SDL_Rect	node_rect; - -			if (!node->active) -				continue; - -			node_to_rect(stage, node, &rect, &node_rect); -			if (x >= node_rect.x && x < node_rect.x + node_rect.w && -			    y >= node_rect.y && y < node_rect.y + node_rect.h) -				return node; -		} -	} - -	return NULL; -} diff --git a/src/stage.h b/src/stage.h index 7299f4a..9f27d68 100644 --- a/src/stage.h +++ b/src/stage.h @@ -17,60 +17,32 @@  #ifndef _STAGE_H  #define _STAGE_H -typedef struct SDL_Renderer SDL_Renderer; -typedef struct SDL_Texture SDL_Texture; -  #define STAGE_NODE_NAME_MAX	16  #define STAGE_LAYERS_MAX	10 -typedef enum stage_map_t { -	STAGE_MAP_FILL,		/* -1,-1...1,1 linearly maps to the AR-constrained stage dimensions, the default */ -	STAGE_MAP_MAXSQ,	/* -1,-1...1,1 linearly maps to a square the size of the maximum axis of the AR-constrained stage dimensions */ -	STAGE_MAP_MINSQ,	/* -1,-1...1,1 linearly maps to a square the size of the minimum axis of the AR-constrained stage dimensions */ -} stage_map_t; - -typedef struct v2f_t v2f_t; -typedef struct aabb_t aabb_t;  typedef struct stage_t stage_t;  typedef struct stage_node_t stage_node_t; -typedef int (*stage_render_func_t)(SDL_Renderer *renderer, void *object, int width, int height, SDL_Texture **texture); -typedef void (*stage_free_func_t)(void *object); +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); -stage_t * stage_new(SDL_Renderer *renderer, float aspect_ratio); +stage_t * stage_new(void);  void stage_clear(stage_t *stage);  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_set_position(stage_t *stage, v2f_t *position); -void stage_get_position(stage_t *stage, v2f_t *res_position); -void stage_set_aabb_map(stage_t *stage, stage_map_t map); -void stage_set_position_map(stage_t *stage, stage_map_t map);  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_get_output_size(stage_t *stage, int *res_width, int *res_height);  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_aabb(const stage_t *stage, stage_node_t *node, const aabb_t *aabb); -void stage_node_get_aabb(const stage_t *stage, const stage_node_t *node, aabb_t *res_aabb); -void stage_node_set_position(const stage_t *stage, stage_node_t *node, v2f_t *position); -void stage_node_get_position(const stage_t *stage, const stage_node_t *node, v2f_t *res_position); -void stage_node_set_origin(const stage_t *stage, stage_node_t *node, v2f_t *origin); -void stage_node_get_origin(const stage_t *stage, const stage_node_t *node, v2f_t *res_origin);  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_static(const stage_t *stage, stage_node_t *node, int stationary);  void stage_node_set_layer(stage_t *stage, stage_node_t *node, int layer); -void stage_node_set_angle(const stage_t *stage, stage_node_t *node, double angle); -void stage_node_get_angle(const stage_t *stage, stage_node_t *node, double *res_angle); -void stage_node_set_aabb_map(const stage_t *stage, stage_node_t *node, stage_map_t fit); -void stage_node_set_position_map(const stage_t *stage, stage_node_t *node, stage_map_t fit);  stage_node_t * stage_node_lookup_name(const stage_t *stage, const char *name); -stage_node_t * stage_node_lookup_cartesian(const stage_t *stage, int x, int y);  #endif | 
