sprite: handle virtual paddings transparently
Most client code no longer needs to care about paddings at all, aside from some very special cases involving dynamic creation of padded sprites. So far we only have one known example of this in portrait_render(). This should let us optimize most of our sprites with autotrimming in the future. Additionally, support for deprecated offset_{x,y} keys in sprite files has been removed.
This commit is contained in:
parent
8927edae65
commit
0adaf17d5f
6 changed files with 38 additions and 67 deletions
|
@ -348,7 +348,7 @@ static double entry_height(CreditsEntry *e, double *head, double *body) {
|
|||
|
||||
if(e->lines > 0) {
|
||||
if(*(e->data[0]) == '*') {
|
||||
total += *head = sprite_padded_height(res_sprite("kyoukkuri"));
|
||||
total += *head = res_sprite("kyoukkuri")->h;
|
||||
} else {
|
||||
total += *head = font_get_lineskip(res_font("big"));
|
||||
}
|
||||
|
@ -435,7 +435,7 @@ static void credits_draw_entry(CreditsEntry *e) {
|
|||
float t = ((global.frames) % 90) / 59.0;
|
||||
float elevation = yukkuri_jump(t);
|
||||
float squeeze = (elevation - yukkuri_jump(t - 0.03)) * 0.4;
|
||||
float halfheight = sprite_padded_height(yukkuri_spr) * 0.5;
|
||||
float halfheight = yukkuri_spr->h * 0.5;
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = yukkuri_spr,
|
||||
|
|
|
@ -274,9 +274,6 @@ void dialog_draw(Dialog *dialog) {
|
|||
Sprite *portrait = &a->composite;
|
||||
assume(portrait->tex != NULL);
|
||||
|
||||
float portrait_w = sprite_padded_width(portrait);
|
||||
float portrait_h = sprite_padded_height(portrait);
|
||||
|
||||
r_mat_mv_push();
|
||||
|
||||
if(a->side == DIALOG_SIDE_LEFT) {
|
||||
|
@ -302,8 +299,8 @@ void dialog_draw(Dialog *dialog) {
|
|||
r_draw_sprite(&(SpriteParams) {
|
||||
.blend = BLEND_PREMUL_ALPHA,
|
||||
.color = &clr,
|
||||
.pos.x = (dialog_width - portrait_w) / 2 + 32 + a->offset.x,
|
||||
.pos.y = VIEWPORT_H - portrait_h / 2 + a->offset.y,
|
||||
.pos.x = (dialog_width - portrait->w) / 2 + 32 + a->offset.x,
|
||||
.pos.y = VIEWPORT_H - portrait->h / 2 + a->offset.y,
|
||||
.sprite_ptr = portrait,
|
||||
});
|
||||
|
||||
|
|
|
@ -61,8 +61,8 @@ void portrait_render(Sprite *s_base, Sprite *s_face, Sprite *s_out) {
|
|||
|
||||
uint tex_w = imax(itc.w, 1);
|
||||
uint tex_h = imax(itc.h, 1);
|
||||
uint spr_w = s_base->extent.w;
|
||||
uint spr_h = s_base->extent.h;
|
||||
float spr_w = s_base->extent.w;
|
||||
float spr_h = s_base->extent.h;
|
||||
|
||||
Texture *ptex = r_texture_create(&(TextureParams) {
|
||||
.type = TEX_TYPE_RGBA_8,
|
||||
|
@ -82,14 +82,14 @@ void portrait_render(Sprite *s_base, Sprite *s_face, Sprite *s_out) {
|
|||
r_framebuffer(fb);
|
||||
r_framebuffer_clear(fb, CLEAR_COLOR, RGBA(0, 0, 0, 0), 1);
|
||||
|
||||
r_mat_proj_push_ortho(spr_w, spr_h);
|
||||
r_mat_proj_push_ortho(spr_w - s_base->padding.w, spr_h - s_base->padding.h);
|
||||
r_mat_mv_push_identity();
|
||||
|
||||
SpriteParams sp = { 0 };
|
||||
sp.sprite_ptr = s_base;
|
||||
sp.blend = BLEND_NONE;
|
||||
sp.pos.x = spr_w * 0.5f - sprite_padded_offset_x(s_base);
|
||||
sp.pos.y = spr_h * 0.5f - sprite_padded_offset_y(s_base);
|
||||
sp.pos.x = spr_w * 0.5f - s_base->padding.offset.x;
|
||||
sp.pos.y = spr_h * 0.5f - s_base->padding.offset.y;
|
||||
sp.color = RGBA(1, 1, 1, 1);
|
||||
sp.shader_ptr = res_shader("sprite_default"),
|
||||
r_draw_sprite(&sp);
|
||||
|
|
|
@ -181,6 +181,10 @@ static void _r_sprite_batch_compute_attribs(
|
|||
float scale_x = params->scale.x ? params->scale.x : 1;
|
||||
float scale_y = params->scale.y ? params->scale.y : scale_x;
|
||||
|
||||
FloatOffset ofs = spr->padding.offset;
|
||||
FloatExtent imgdims = spr->extent;
|
||||
imgdims.as_cmplx -= spr->padding.extent.as_cmplx;
|
||||
|
||||
if(params->pos.x || params->pos.y) {
|
||||
glm_translate(attribs.mv_transform, (vec3) { params->pos.x, params->pos.y });
|
||||
}
|
||||
|
@ -195,21 +199,18 @@ static void _r_sprite_batch_compute_attribs(
|
|||
}
|
||||
}
|
||||
|
||||
glm_scale(attribs.mv_transform, (vec3) { scale_x * spr->w, scale_y * spr->h, 1 });
|
||||
glm_scale(attribs.mv_transform, (vec3) { scale_x * imgdims.w, scale_y * imgdims.h, 1 });
|
||||
|
||||
float ofs_x = sprite_padded_offset_x(spr);
|
||||
float ofs_y = sprite_padded_offset_y(spr);
|
||||
|
||||
if(ofs_x || ofs_y) {
|
||||
if(ofs.x || ofs.y) {
|
||||
if(params->flip.x) {
|
||||
ofs_x *= -1;
|
||||
ofs.x *= -1;
|
||||
}
|
||||
|
||||
if(params->flip.y) {
|
||||
ofs_y *= -1;
|
||||
ofs.y *= -1;
|
||||
}
|
||||
|
||||
glm_translate(attribs.mv_transform, (vec3) { ofs_x / spr->w, ofs_y / spr->h });
|
||||
glm_translate(attribs.mv_transform, (vec3) { ofs.x / imgdims.w, ofs.y / imgdims.h });
|
||||
}
|
||||
|
||||
if(params->color == NULL) {
|
||||
|
|
|
@ -50,7 +50,6 @@ static void load_sprite_stage1(ResourceLoadState *st) {
|
|||
return;
|
||||
}
|
||||
|
||||
float ofs_x = 0, ofs_y = 0;
|
||||
|
||||
SDL_RWops *rw = res_open_file(st, st->path, VFS_MODE_READ);
|
||||
|
||||
|
@ -62,6 +61,8 @@ static void load_sprite_stage1(ResourceLoadState *st) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct { float top, bottom, left, right; } pad = { };
|
||||
|
||||
bool parsed = parse_keyvalue_stream_with_spec(rw, (KVSpec[]) {
|
||||
{ "texture", .out_str = &state->texture_name },
|
||||
{ "region_x", .out_float = &spr->tex_area.x },
|
||||
|
@ -70,12 +71,10 @@ static void load_sprite_stage1(ResourceLoadState *st) {
|
|||
{ "region_h", .out_float = &spr->tex_area.h },
|
||||
{ "w", .out_float = &spr->w },
|
||||
{ "h", .out_float = &spr->h },
|
||||
{ "offset_x", .out_float = &ofs_x, KVSPEC_DEPRECATED("margin_left; margin_right") },
|
||||
{ "offset_y", .out_float = &ofs_y, KVSPEC_DEPRECATED("margin_top; margin_bottom") },
|
||||
{ "padding_top", .out_float = &spr->padding.top },
|
||||
{ "padding_bottom", .out_float = &spr->padding.bottom },
|
||||
{ "padding_left", .out_float = &spr->padding.left },
|
||||
{ "padding_right", .out_float = &spr->padding.right },
|
||||
{ "padding_top", .out_float = &pad.top },
|
||||
{ "padding_bottom", .out_float = &pad.bottom },
|
||||
{ "padding_left", .out_float = &pad.left },
|
||||
{ "padding_right", .out_float = &pad.right },
|
||||
{ NULL }
|
||||
});
|
||||
|
||||
|
@ -97,10 +96,13 @@ static void load_sprite_stage1(ResourceLoadState *st) {
|
|||
|
||||
res_load_dependency(st, RES_TEXTURE, state->texture_name);
|
||||
|
||||
spr->padding.left += ofs_x;
|
||||
spr->padding.right -= ofs_x;
|
||||
spr->padding.top += ofs_y;
|
||||
spr->padding.bottom -= ofs_y;
|
||||
spr->padding.extent.w = pad.left + pad.right;
|
||||
spr->padding.extent.h = pad.top + pad.bottom;
|
||||
|
||||
spr->padding.offset.x = 0.5f * (pad.left - pad.right);
|
||||
spr->padding.offset.y = 0.5f * (pad.top - pad.bottom);
|
||||
|
||||
spr->extent.as_cmplx += spr->padding.extent.as_cmplx;
|
||||
|
||||
res_load_continue_after_dependencies(st, load_sprite_stage2, state);
|
||||
return;
|
||||
|
@ -154,7 +156,7 @@ Sprite *prefix_get_sprite(const char *name, const char *prefix) {
|
|||
}
|
||||
|
||||
static void begin_draw_sprite(float x, float y, float scale_x, float scale_y, Sprite *spr) {
|
||||
FloatOffset o = sprite_padded_offset(spr);
|
||||
FloatOffset o = spr->padding.offset;
|
||||
|
||||
begin_draw_texture(
|
||||
(FloatRect){ x + o.x * scale_x, y + o.y * scale_y, spr->w * scale_x, spr->h * scale_y },
|
||||
|
|
|
@ -12,50 +12,21 @@
|
|||
#include "resource.h"
|
||||
#include "texture.h"
|
||||
|
||||
typedef struct SpriteMargin {
|
||||
float top, bottom, left, right;
|
||||
} SpriteMargin;
|
||||
|
||||
typedef struct Sprite {
|
||||
Texture *tex;
|
||||
FloatRect tex_area;
|
||||
union {
|
||||
// NOTE: This is stored with padding pre-applied.
|
||||
// To get the area actually occupied by the image, subtract `padding.extent` from the size
|
||||
// and bias the origin by `padding.offset`.
|
||||
// You shouldn't need to worry about it in most cases, unless you're doing some low-level
|
||||
// sprite rendering or want to add virtual paddings to your own Sprite instance.
|
||||
FloatExtent extent;
|
||||
struct { float w, h; };
|
||||
};
|
||||
SpriteMargin padding;
|
||||
FloatRect padding;
|
||||
} Sprite;
|
||||
|
||||
INLINE float sprite_padded_width(const Sprite *restrict spr) {
|
||||
return spr->extent.w + spr->padding.left + spr->padding.right;
|
||||
}
|
||||
|
||||
INLINE float sprite_padded_height(const Sprite *restrict spr) {
|
||||
return spr->extent.h + spr->padding.top + spr->padding.bottom;
|
||||
}
|
||||
|
||||
INLINE FloatExtent sprite_padded_extent(const Sprite *restrict spr) {
|
||||
FloatExtent e;
|
||||
e.w = sprite_padded_width(spr);
|
||||
e.h = sprite_padded_height(spr);
|
||||
return e;
|
||||
}
|
||||
|
||||
INLINE float sprite_padded_offset_x(const Sprite *restrict spr) {
|
||||
return (spr->padding.left - spr->padding.right) * 0.5;
|
||||
}
|
||||
|
||||
INLINE float sprite_padded_offset_y(const Sprite *restrict spr) {
|
||||
return (spr->padding.top - spr->padding.bottom) * 0.5;
|
||||
}
|
||||
|
||||
INLINE FloatOffset sprite_padded_offset(const Sprite *restrict spr) {
|
||||
FloatOffset o;
|
||||
o.x = sprite_padded_offset_x(spr);
|
||||
o.y = sprite_padded_offset_y(spr);
|
||||
return o;
|
||||
}
|
||||
|
||||
FloatRect sprite_denormalized_tex_coords(const Sprite *restrict spr);
|
||||
IntRect sprite_denormalized_int_tex_coords(const Sprite *restrict spr);
|
||||
void sprite_set_denormalized_tex_coords(Sprite *restrict spr, FloatRect tc);
|
||||
|
|
Loading…
Reference in a new issue