summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2018-05-24 01:06:33 -0700
committerVito Caputo <vcaputo@pengaru.com>2018-05-24 01:10:12 -0700
commit21c0f72b53a594f41c464c17afbc5f500fc91f25 (patch)
tree622fcb05572a9a03abbbf8605b627c3c69bfc91b
parent635e2e8f2b0007a52121c0240d445d0fcf82a231 (diff)
libstage: rewrite aabb_to_rect() for less error
There was too much fractional math happening at once resulting in artifacts like nodes sharing the same position jiggling relative to eachother as they moved. Instead compute the various values discretely, flooring their values. This also integrates the node origin, which previously was ignored. A clamp has also been added to prevent zero-size nodes in rect w or h when their AABB dimensions are non-zero.
-rw-r--r--src/stage.c50
1 files changed, 39 insertions, 11 deletions
diff --git a/src/stage.c b/src/stage.c
index 35d6835..c52e5b1 100644
--- a/src/stage.c
+++ b/src/stage.c
@@ -369,18 +369,46 @@ void stage_get_position(stage_t *stage, v2f_t *res_position)
*res_position = stage->position;
}
-
-static void aabb_to_rect(const aabb_t *aabb, const v2f_t *pos, const SDL_Rect *stage_rect, SDL_Rect *res_rect)
+/* translate an aabb having origin origin at pos position into a dest rect witin stage_rect */
+static void aabb_to_rect(const v2f_t *stage_pos, const aabb_t *aabb, const v2f_t *aabb_origin, const v2f_t *aabb_pos, const SDL_Rect *stage_rect, SDL_Rect *res_rect)
{
- float half_w = ((float)stage_rect->w) * .5f, half_h = ((float)stage_rect->h) * .5f; /* FIXME silly to recompute this repeatedly... */
+ float aabb_w = (aabb->max.x - aabb->min.x);
+ float aabb_h = (aabb->max.y - aabb->min.y);
+
+ /* res dimensions are simply aabb dimensions scaled by stage dimensions */
+ res_rect->w = floorf(aabb_w * .5f * (float)stage_rect->w);
+ res_rect->h = floorf(aabb_h * .5f * (float)stage_rect->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);
+
+ /* apply stage_pos (scaled relative to stage_rect) */
+ res_rect->x += floorf(stage_pos->x * .5f * (float)stage_rect->w);
+ res_rect->y += -floorf(stage_pos->y * .5f * (float)stage_rect->h);
- res_rect->x = stage_rect->x;
- res_rect->y = stage_rect->y;
- res_rect->x += ((float)aabb->min.x + pos->x) * half_w + half_w;
- res_rect->y += stage_rect->h - (((float)aabb->max.y + pos->y) * half_h + half_h);
+ /* apply aabb_pos (scaled relative to stage_rect) */
+ res_rect->x += floorf(aabb_pos->x * .5f * (float)stage_rect->w);
+ res_rect->y += -floorf(aabb_pos->y * .5f * (float)stage_rect->h);
+
+ /* apply aabb_origin (scaled relative to scaled aabb_w) (this probably needs to be inverted) */
+ res_rect->x += floorf(aabb_origin->x * .5f * (float)res_rect->w);
+ res_rect->y += -floorf(aabb_origin->y * .5f * (float)res_rect->h);
+
+ /* apply aabb (scaled relative to stage_rect) */
+ res_rect->x += floorf(aabb->min.x * .5f * (float)stage_rect->w);
+ res_rect->y += -floorf(aabb->max.y * .5f * (float)stage_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;
- res_rect->w = (aabb->max.x - aabb->min.x) * half_w;
- res_rect->h = (aabb->max.y - aabb->min.y) * half_h;
+ if (res_rect->h == 0 && aabb_h > 0.f)
+ res_rect->h = 1;
}
@@ -395,7 +423,7 @@ static void render_nodes(const stage_t *stage, const list_head_t *head, SDL_Rend
continue;
/* scale the node's aabb stage coordinates to destination renderer coordinates */
- aabb_to_rect(&node->aabb, &node->position, dest_rect, &node_rect);
+ aabb_to_rect(&stage->position, &node->aabb, &node->origin, &node->position, dest_rect, &node_rect);
/* if we have a cached texture, see if the dimensions changed */
if (node->cached.texture &&
@@ -503,7 +531,7 @@ stage_node_t * stage_node_lookup_cartesian(const stage_t *stage, int x, int y)
if (!node->active)
continue;
- aabb_to_rect(&node->aabb, &node->position, &rect, &node_rect);
+ aabb_to_rect(&stage->position, &node->aabb, &node->origin, &node->position, &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;
© All Rights Reserved