summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2018-09-11 01:16:50 -0700
committerVito Caputo <vcaputo@pengaru.com>2018-09-11 01:23:23 -0700
commitbd4b32fa1028a0a4340ed77080059961968c17fd (patch)
tree668372f57fca84757f50838f88a8369dfa066513
parentb263b3e4b295c42a36970435eb7df5373bce6c89 (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.
-rw-r--r--src/stage.c348
-rw-r--r--src/stage.h34
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
© All Rights Reserved