From b155b4b79fc24a2c85883e1c2feef3b674091429 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 15 Jun 2024 11:05:22 +0900 Subject: [PATCH] Add a parameter to gfx_draw_glyph() for controlling blending behavior This adds a new parameter `blend` to `gfx_draw_glyph()`. When `blend` is true, the function performs normal alpha blending (same as `gfx_draw_glyph_to_pmap()`). If `blend` is false, the resulting pixel color will be the text color and the alpha value will be copied from the glyph texture. However, if the alpha value is less than 0.01, the pixel will not be written. If you are drawing on a transparent texture (which will later be blended into another texture), `blend` should be false. If you are drawing on top of an image, `blend` should be true. `gfx_draw_glyph()` used to fill transparent pixels with text color, but this step is no longer needed and has been removed. --- include/gfx/font.h | 2 +- include/gfx/gfx.h | 2 +- shaders/blend_rmap_color.f.glsl | 8 +++++--- shaders/dilate.f.glsl | 4 +++- src/draw.c | 28 +++++++++++----------------- src/hll/CharSpriteManager.c | 2 +- src/hll/Gpx2Plus.c | 2 +- src/hll/SengokuRanceFont.c | 2 +- src/hll/StoatSpriteEngine.c | 4 ++-- src/hll/vmDrawMsg.c | 6 +++--- src/parts/construction.c | 4 ++-- src/parts/text.c | 2 +- src/sprite.c | 10 ++-------- src/text.c | 17 ++++++++++++----- 14 files changed, 46 insertions(+), 47 deletions(-) diff --git a/include/gfx/font.h b/include/gfx/font.h index 65ab5af..993b038 100644 --- a/include/gfx/font.h +++ b/include/gfx/font.h @@ -132,7 +132,7 @@ int gfx_get_font_space(void); SDL_Color gfx_get_font_color(void); void gfx_set_font_name(const char *name); -int gfx_render_text(Texture *dst, float x, int y, char *msg, struct text_style *ts); +int gfx_render_text(Texture *dst, float x, int y, char *msg, struct text_style *ts, bool blend); void gfx_draw_text_to_amap(Texture *dst, int x, int y, char *text); void gfx_draw_text_to_pmap(Texture *dst, int x, int y, char *text); float gfx_size_char(struct text_style *ts, const char *ch); diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h index e897d18..966c632 100644 --- a/include/gfx/gfx.h +++ b/include/gfx/gfx.h @@ -170,7 +170,7 @@ void gfx_copy_stretch_with_alpha_map(Texture *dst, int dx, int dy, int dw, int d void gfx_copy_grayscale(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h); void gfx_draw_line(Texture *dst, int x0, int y0, int x1, int y1, int r, int g, int b); void gfx_draw_line_to_amap(Texture *dst, int x0, int y0, int x1, int y1, int a); -void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width); +void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width, bool blend); void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, SDL_Color color, float scale_x); void gfx_draw_glyph_to_amap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, float scale_x); diff --git a/shaders/blend_rmap_color.f.glsl b/shaders/blend_rmap_color.f.glsl index f10b608..9621af7 100644 --- a/shaders/blend_rmap_color.f.glsl +++ b/shaders/blend_rmap_color.f.glsl @@ -15,12 +15,14 @@ */ uniform sampler2D tex; -uniform vec4 color; +uniform vec4 color; // .a is the discard threshold in vec2 tex_coord; out vec4 frag_color; void main() { - vec4 texel = texture(tex, tex_coord); - frag_color = vec4(color.rgb, texel.r * color.a); + vec4 texel = texture(tex, tex_coord); + if (texel.r < color.a) + discard; + frag_color = vec4(color.rgb, texel.r); } diff --git a/shaders/dilate.f.glsl b/shaders/dilate.f.glsl index 4497bdc..9993dfe 100644 --- a/shaders/dilate.f.glsl +++ b/shaders/dilate.f.glsl @@ -16,7 +16,7 @@ uniform sampler2D tex; uniform float threshold; -uniform vec4 color; +uniform vec4 color; // .a is the discard threshold in vec2 tex_coord; out vec4 frag_color; @@ -43,5 +43,7 @@ void main() { } } + if (a_out < color.a) + discard; frag_color = vec4(color.rgb, min(a_out, 1.0)); } diff --git a/src/draw.c b/src/draw.c index ecfbf45..f0cb753 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1118,29 +1118,23 @@ void gfx_draw_line_to_amap(Texture *dst, int x0, int y0, int x1, int y1, int a) } // XXX: Not an actual DrawGraph function; used for rendering text -void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width) +void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width, bool blend) { + if (blend) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } else { + glBlendFunc(GL_ONE, GL_ZERO); + glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); + } + dx = roundf(dx); - - glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ONE); - struct copy_data fill_data = COPY_DATA(dx, dy, dx, dy, glyph->w * scale_x, glyph->h); - fill_data.r = color.r / 255.0; - fill_data.g = color.g / 255.0; - fill_data.b = color.b / 255.0; - fill_data.a = 0.0; - fill_data.threshold = 0.001; - run_copy_shader(&fill_amap_under_border_shader.s, dst, dst, &fill_data); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); - struct copy_data data = STRETCH_DATA( dx, dy, glyph->w * scale_x, glyph->h, 0, 0, glyph->w, glyph->h); data.r = color.r / 255.0; data.g = color.g / 255.0; data.b = color.b / 255.0; - data.a = 1.0; + data.a = 0.01; // discard threshold if (bold_width < 0.01) { run_copy_shader(&blend_rmap_color_shader.s, dst, glyph, &data); @@ -1160,7 +1154,7 @@ void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, Rect data.r = color.r / 255.0; data.g = color.g / 255.0; data.b = color.b / 255.0; - data.a = 1.0; + data.a = 0.01; // discard threshold glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); run_copy_shader(&blend_rmap_color_shader.s, dst, glyph, &data); restore_blend_mode(); @@ -1174,7 +1168,7 @@ void gfx_draw_glyph_to_amap(Texture *dst, float dx, int dy, Texture *glyph, Rect data.r = 1.0; data.g = 1.0; data.b = 1.0; - data.a = 1.0; + data.a = 0.0; // discard threshold glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ZERO); run_copy_shader(&blend_rmap_color_shader.s, dst, glyph, &data); restore_blend_mode(); diff --git a/src/hll/CharSpriteManager.c b/src/hll/CharSpriteManager.c index 219523b..4f77854 100644 --- a/src/hll/CharSpriteManager.c +++ b/src/hll/CharSpriteManager.c @@ -181,7 +181,7 @@ static void charsprite_render(struct charsprite *cs) sprite_init_color(&cs->sp, w, h, 0, 0, 0, 0); sprite_get_texture(&cs->sp); // XXX: force initialization of texture - gfx_render_text(&cs->sp.texture, 0.0f, 0, ch, &cs->ts); + gfx_render_text(&cs->sp.texture, 0.0f, 0, ch, &cs->ts, false); sprite_dirty(&cs->sp); } diff --git a/src/hll/Gpx2Plus.c b/src/hll/Gpx2Plus.c index 2a3458c..31cd3f6 100644 --- a/src/hll/Gpx2Plus.c +++ b/src/hll/Gpx2Plus.c @@ -529,7 +529,7 @@ static void Gpx2Plus_MsgDraw(int surface, int x, int y) skiplen = strlen(s); } pos.y += line_height - ts.size; // bottom align - pos.x += gfx_render_text(dst, pos.x, pos.y, s, &ts); + pos.x += gfx_render_text(dst, pos.x, pos.y, s, &ts, true); pos.y -= line_height - ts.size; if (lb) *lb = '<'; diff --git a/src/hll/SengokuRanceFont.c b/src/hll/SengokuRanceFont.c index 71dd02b..581ecc0 100644 --- a/src/hll/SengokuRanceFont.c +++ b/src/hll/SengokuRanceFont.c @@ -343,7 +343,7 @@ static float sp_text_draw(struct sact_sprite *sp, struct sr_text_properties *tp, tp->last_char = last_char; sprite_dirty(sp); - return gfx_render_text(tex, x ,y, text->text, &tp->ts); + return gfx_render_text(tex, x ,y, text->text, &tp->ts, false); } static void SengokuRanceFont_SP_TextDraw(int sp_no, struct string *text) diff --git a/src/hll/StoatSpriteEngine.c b/src/hll/StoatSpriteEngine.c index 6ccc647..d11d8f1 100644 --- a/src/hll/StoatSpriteEngine.c +++ b/src/hll/StoatSpriteEngine.c @@ -120,7 +120,7 @@ bool StoatSpriteEngine_SP_SetTextSprite(int sp_no, struct string *text) w /= 2; struct sact_sprite *sp = sact_create_sprite(sp_no, w, h, 0, 0, 0, 0); sprite_get_texture(sp); // XXX: force initialization of texture - gfx_render_text(&sp->texture, 0.0f, 0, s, &text_sprite_ts); + gfx_render_text(&sp->texture, 0.0f, 0, s, &text_sprite_ts, false); sprite_dirty(sp); return true; } @@ -457,7 +457,7 @@ static bool StoatSpriteEngine_MultiSprite_SetText(int type, int n, struct string int h = ms->ts.size; sprite_init_color(&ms->sp, w, h, 0, 0, 0, 0); sprite_get_texture(&ms->sp); // XXX: force initialization of texture - gfx_render_text(&ms->sp.texture, 0.0f, 0, text->text, &ms->ts); + gfx_render_text(&ms->sp.texture, 0.0f, 0, text->text, &ms->ts, false); sprite_dirty(&ms->sp); ms->cg = 1; diff --git a/src/hll/vmDrawMsg.c b/src/hll/vmDrawMsg.c index e03922a..cebf738 100644 --- a/src/hll/vmDrawMsg.c +++ b/src/hll/vmDrawMsg.c @@ -161,17 +161,17 @@ static int vmDrawMsg_Draw(int handle) struct vm_surface *sf = vm_surface_get(dm->surfaces[SURFACE_DROP_SHADOW]); int x = dm->pos.x + dm->style.drop_shadow; int y = dm->pos.y + dm->style.drop_shadow; - gfx_render_text(&sf->texture, x, y, s, &ts); + gfx_render_text(&sf->texture, x, y, s, &ts, false); } if (dm->style.bold) { struct text_style ts = dm->style.ts; ts.bold_width = dm->style.bold; ts.color = dm->style.bold_color; struct vm_surface *sf = vm_surface_get(dm->surfaces[SURFACE_BOLD]); - gfx_render_text(&sf->texture, dm->pos.x, dm->pos.y, s, &ts); + gfx_render_text(&sf->texture, dm->pos.x, dm->pos.y, s, &ts, false); } struct vm_surface *sf = vm_surface_get(dm->surfaces[SURFACE_TEXT]); - dm->pos.x += gfx_render_text(&sf->texture, dm->pos.x, dm->pos.y, s, &dm->style.ts); + dm->pos.x += gfx_render_text(&sf->texture, dm->pos.x, dm->pos.y, s, &dm->style.ts, false); if (lb) *lb = '<'; } else if (sscanf(s, "%n", &a1, &a2, &a3, &skiplen) == 3) { diff --git a/src/parts/construction.c b/src/parts/construction.c index fa58d9d..61772ed 100644 --- a/src/parts/construction.c +++ b/src/parts/construction.c @@ -352,7 +352,7 @@ static void build_copy_cut_cg(struct parts_construction_process *cproc, struct p static void build_draw_text(struct parts_construction_process *cproc, struct parts_cp_text *op) { - gfx_render_text(&cproc->common.texture, op->x, op->y, op->text->text, &op->style); + gfx_render_text(&cproc->common.texture, op->x, op->y, op->text->text, &op->style, true); } static void build_copy_text(struct parts_construction_process *cproc, struct parts_cp_text *op) @@ -361,7 +361,7 @@ static void build_copy_text(struct parts_construction_process *cproc, struct par int h = ceilf(op->style.size + op->style.edge_up + op->style.edge_down); gfx_fill_with_alpha(&cproc->common.texture, op->x, op->y, w, h, op->style.edge_color.r, op->style.edge_color.g, op->style.edge_color.b, 0); - gfx_render_text(&cproc->common.texture, op->x, op->y, op->text->text, &op->style); + gfx_render_text(&cproc->common.texture, op->x, op->y, op->text->text, &op->style, false); } bool parts_build_construction_process(struct parts *parts, diff --git a/src/parts/text.c b/src/parts/text.c index 425d50c..617b39b 100644 --- a/src/parts/text.c +++ b/src/parts/text.c @@ -83,7 +83,7 @@ static const char *parts_text_append_char(struct parts_text *t, const char *str) int width = text_style_width(&t->ts, ch->ch); int height = text_style_height(&t->ts); gfx_init_texture_rgba(&ch->t, width, height, (SDL_Color){0,0,0,0}); - ch->advance = gfx_render_text(&ch->t, 0, 0, ch->ch, &t->ts); + ch->advance = gfx_render_text(&ch->t, 0, 0, ch->ch, &t->ts, false); line->width += width; line->height = max(line->height, height); diff --git a/src/sprite.c b/src/sprite.c index 7946242..d71b598 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -372,17 +372,11 @@ void sprite_set_text_pos(struct sact_sprite *sp, int x, int y) void sprite_text_draw(struct sact_sprite *sp, struct string *text, struct text_style *ts) { if (!sp->text.texture.handle) { - SDL_Color c; - if (text_style_has_edge(ts)) - c = ts->edge_color; - else - c = ts->color; - c.a = 0; - gfx_init_texture_rgba(&sp->text.texture, sp->rect.w, sp->rect.h, c); + gfx_init_texture_rgba(&sp->text.texture, sp->rect.w, sp->rect.h, COLOR(0, 0, 0, 0)); } ts->font_spacing = sp->text.char_space; - sp->text.pos.x += gfx_render_text(&sp->text.texture, sp->text.pos.x, sp->text.pos.y, text->text, ts); + sp->text.pos.x += gfx_render_text(&sp->text.texture, sp->text.pos.x, sp->text.pos.y, text->text, ts, false); if (sp->text.current_line_height < ts->size) sp->text.current_line_height = ts->size; sprite_dirty(sp); diff --git a/src/text.c b/src/text.c index 0a1e9cc..cdbab65 100644 --- a/src/text.c +++ b/src/text.c @@ -201,6 +201,7 @@ float gfx_get_actual_font_size_round_down(unsigned face, float size) } enum text_render_mode { + RENDER_COPY, RENDER_BLENDED, RENDER_PMAP, RENDER_AMAP, @@ -237,10 +238,14 @@ static int render_text(Texture *dst, char *msg, struct text_render_metrics *tm) // render glyph Texture *t = &glyph->t[tm->weight]; - if (tm->mode == RENDER_BLENDED) { + if (tm->mode == RENDER_COPY) { float x = pos_x - glyph->rect.x; int y = pos_y - glyph->rect.y; - gfx_draw_glyph(dst, x, y, t, tm->color, config.text_x_scale, tm->edge_width); + gfx_draw_glyph(dst, x, y, t, tm->color, config.text_x_scale, tm->edge_width, false); + } else if (tm->mode == RENDER_BLENDED) { + float x = pos_x - glyph->rect.x; + int y = pos_y - glyph->rect.y; + gfx_draw_glyph(dst, x, y, t, tm->color, config.text_x_scale, tm->edge_width, true); } else if (tm->mode == RENDER_PMAP) { gfx_draw_glyph_to_pmap(dst, pos_x, pos_y, t, glyph->rect, tm->color, config.text_x_scale); } else if (tm->mode == RENDER_AMAP) { @@ -271,11 +276,12 @@ static enum font_weight int_to_font_weight(int weight) return (weight % 1000) < 551 ? FONT_WEIGHT_BOLD : FONT_WEIGHT_HEAVY; } -int gfx_render_text(Texture *dst, float x, int y, char *msg, struct text_style *ts) +int gfx_render_text(Texture *dst, float x, int y, char *msg, struct text_style *ts, bool blend) { enum font_weight weight = int_to_font_weight(ts->weight); struct font_size *font_size = text_style_font_size(ts); float edge_width = text_style_edge_width(ts); + enum text_render_mode mode = blend ? RENDER_BLENDED : RENDER_COPY; if (edge_width > 0.01f) { struct text_render_metrics metrics = { .x = x, @@ -287,10 +293,11 @@ int gfx_render_text(Texture *dst, float x, int y, char *msg, struct text_style * .space_scale_x = ts->space_scale_x, .font_spacing = ts->font_spacing, .edge_spacing = gfx_text_advance_edges ? edge_width : 0.0, - .mode = RENDER_BLENDED, + .mode = mode, .font_size = font_size, }; render_text(dst, msg, &metrics); + mode = RENDER_BLENDED; // core text is blended on top of the edge } struct text_render_metrics metrics = { .x = x, @@ -302,7 +309,7 @@ int gfx_render_text(Texture *dst, float x, int y, char *msg, struct text_style * .space_scale_x = ts->space_scale_x, .font_spacing = ts->font_spacing, .edge_spacing = gfx_text_advance_edges ? edge_width : 0.0, - .mode = RENDER_BLENDED, + .mode = mode, .font_size = font_size, }; return render_text(dst, msg, &metrics);