diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2018-09-11 01:16:50 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2018-09-11 01:23:23 -0700 |
commit | bd4b32fa1028a0a4340ed77080059961968c17fd (patch) | |
tree | 668372f57fca84757f50838f88a8369dfa066513 /src | |
parent | b263b3e4b295c42a36970435eb7df5373bce6c89 (diff) |
libstage: remove everything dimensional
Having the stage manage the rendering dimensions for nodes
seemed like a good idea at the time.
This commit removes all that so there's no more coupling to
SDL or dimensional types. Now the stage really is nothing
more than a thin drawing list abstraction. The layers can be
used for ordering the drawing, which is the only semi-dimensional
thing remaining.
The stage_fit() helper remains for now out of convenience, but
it's really out of place in this library.
Diffstat (limited to 'src')
-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 |