From 1fb81d22654d78e20791e284bd40daae87f79cd6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 21 Nov 2017 14:19:49 +0530 Subject: [PATCH] Fix incorrect blending of foreground and background colors when negative z-index images are present Also optimize the blending calculation a bit by using the mix() function and just adding the text and strike alphas. --- kitty/cell_fragment.glsl | 30 +++++++++++++++++++----------- kitty/shaders.c | 2 +- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/kitty/cell_fragment.glsl b/kitty/cell_fragment.glsl index f42a2adf1..02a1ac1fc 100644 --- a/kitty/cell_fragment.glsl +++ b/kitty/cell_fragment.glsl @@ -15,8 +15,13 @@ in vec4 special_bg; out vec4 final_color; -vec3 blend(float alpha, vec3 over, vec3 under) { - return over + (1 - alpha) * under; +vec4 alpha_blend(vec3 over, float over_alpha, vec3 under, float under_alpha) { + // Alpha blend two colors returning the resulting color pre-multiplied by its alpha + // and its alpha. + // See https://en.wikipedia.org/wiki/Alpha_compositing + float alpha = mix(under_alpha, 1.0f, over_alpha); + vec3 combined_color = mix(under * under_alpha, over, over_alpha); + return vec4(combined_color, alpha); } void main() { @@ -24,17 +29,19 @@ void main() { float text_alpha = texture(sprites, sprite_pos).r; float underline_alpha = texture(sprites, underline_pos).r; float strike_alpha = texture(sprites, strike_pos).r; - vec3 underline = underline_alpha * decoration_fg; - vec3 strike = strike_alpha * foreground; - vec3 fg = text_alpha * foreground; - vec3 decoration = blend(underline_alpha, underline, strike); - vec3 combined_fg = blend(text_alpha, fg, decoration); - float combined_alpha = max(max(underline_alpha, strike_alpha), text_alpha); + // Since strike and text are the same color, we simply add the alpha values + float combined_alpha = min(text_alpha + strike_alpha, 1.0f); + // Underline color might be different, so alpha blend + vec4 fg = alpha_blend(decoration_fg, underline_alpha, foreground, combined_alpha); #ifdef ALL - final_color = vec4(blend(combined_alpha, combined_fg, background), 1); + // since background alpha is 1.0 and fg color is pre-multiplied by its alpha, + // we can simplify the alpha blend equation + final_color = vec4(fg.rgb + (1.0f - fg.a) * background, 1.0f); #else - final_color = vec4(combined_fg, combined_alpha); + // FOREGROUND + // fg is pre-multipled so divide it by alpha + final_color = vec4(fg.rgb / fg.a, fg.a); #endif #else @@ -42,7 +49,8 @@ void main() { #ifdef SPECIAL final_color = special_bg; #else - final_color = vec4(background, 1); + // BACKGROUND + final_color = vec4(background, 1.0f); #endif #endif diff --git a/kitty/shaders.c b/kitty/shaders.c index ae8608f16..df1187099 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -317,7 +317,7 @@ draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) { glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); bind_program(CELL_FOREGROUND_PROGRAM); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); if (screen->grman->num_of_positive_refs) draw_graphics(vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs, screen->grman->num_of_positive_refs);