diff --git a/src/credits.c b/src/credits.c index 335ed634..37ad462c 100644 --- a/src/credits.c +++ b/src/credits.c @@ -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, diff --git a/src/dialog.c b/src/dialog.c index cf54a429..62bb855f 100644 --- a/src/dialog.c +++ b/src/dialog.c @@ -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, }); diff --git a/src/portrait.c b/src/portrait.c index fdcd47a1..2163b992 100644 --- a/src/portrait.c +++ b/src/portrait.c @@ -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); diff --git a/src/renderer/common/sprite_batch.c b/src/renderer/common/sprite_batch.c index 76cc1846..38270947 100644 --- a/src/renderer/common/sprite_batch.c +++ b/src/renderer/common/sprite_batch.c @@ -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) { diff --git a/src/resource/sprite.c b/src/resource/sprite.c index a0314b22..02cef1bc 100644 --- a/src/resource/sprite.c +++ b/src/resource/sprite.c @@ -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 }, diff --git a/src/resource/sprite.h b/src/resource/sprite.h index 6e8f083e..ccefcd5a 100644 --- a/src/resource/sprite.h +++ b/src/resource/sprite.h @@ -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);