diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a15f174cb38..85c1a58a9ef 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,9 +6,14 @@ kitty is a feature full, cross-platform, *fast*, GPU based terminal emulator. version 0.6.0 [future] ------------------------ +- Support background transparency via the background_opacity option. Provided + that your OS/window manager supports transparency, you can now have kitty + render pixels that have only the default background color as + semi-transparent. + - Support multiple top level (OS) windows. These windows all share the sprite texture cache on the GPU, further reducing overall resource usage. Use - the shortcut `ctrl+shift+n` to open anew top-level window. + the shortcut `ctrl+shift+n` to open a new top-level window. - Add support for a *daemon* mode using the `--single-instance` command line option. With this option you can have only a single kitty instance running. diff --git a/kitty/cell_fragment.glsl b/kitty/cell_fragment.glsl index f1b07b9c7ec..89d183bbcc3 100644 --- a/kitty/cell_fragment.glsl +++ b/kitty/cell_fragment.glsl @@ -62,19 +62,36 @@ vec4 calculate_foreground() { #endif void main() { -#if defined(BACKGROUND) || defined(SPECIAL) -#if defined(TRANSPARENT) || defined(SPECIAL) +#ifdef BACKGROUND +#ifdef TRANSPARENT final_color = vec4(background.rgb * bg_alpha, bg_alpha); #else final_color = vec4(background.rgb, 1.0f); #endif +#endif -#else +#ifdef SPECIAL +#ifdef TRANSPARENT + final_color = vec4(background.rgb * bg_alpha, bg_alpha); +#else + final_color = vec4(background.rgb, bg_alpha); +#endif +#endif + +#if defined(FOREGROUND) || defined(SIMPLE) + // FOREGROUND or SIMPLE vec4 fg = calculate_foreground(); // pre-multiplied foreground + #ifdef FOREGROUND + // FOREGROUND +#ifdef TRANSPARENT final_color = fg; #else + final_color = vec4(fg.rgb / fg.a, fg.a); +#endif +#else + // SIMPLE #ifdef TRANSPARENT final_color = alpha_blend_premul(fg.rgb, fg.a, background * bg_alpha, bg_alpha); final_color = vec4(final_color.rgb / final_color.a, final_color.a); diff --git a/kitty/shaders.c b/kitty/shaders.c index ba37b4b4489..68061bc09de 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -303,20 +303,43 @@ draw_graphics(int program, ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *d bind_vertex_array(vao_idx); } +#define BLEND_ONTO_OPAQUE glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // blending onto opaque colors +#define BLEND_PREMULT glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // blending of pre-multiplied colors + static void -draw_all_cells(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) { +draw_cells_simple(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) { bind_program(CELL_PROGRAM); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); if (screen->grman->count) { glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // blending onto opaque colors + BLEND_ONTO_OPAQUE; draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->count); glDisable(GL_BLEND); } } static void -draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *os_window) { +draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) { + bind_program(CELL_BG_PROGRAM); + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); + glEnable(GL_BLEND); + BLEND_ONTO_OPAQUE; + + if (screen->grman->num_of_negative_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_negative_refs); + + bind_program(CELL_SPECIAL_PROGRAM); + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); + + bind_program(CELL_FG_PROGRAM); + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); + + if (screen->grman->num_of_positive_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs, screen->grman->num_of_positive_refs); + + glDisable(GL_BLEND); +} + +static void +draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *os_window) { if (!os_window->offscreen_texture_id) { glGenTextures(1, &os_window->offscreen_texture_id); glBindTexture(GL_TEXTURE_2D, os_window->offscreen_texture_id); @@ -334,7 +357,7 @@ draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWind bind_program(CELL_BG_PROGRAM); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // blending of pre-multiplied colors + BLEND_PREMULT; if (screen->grman->num_of_negative_refs) draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_negative_refs); @@ -390,9 +413,13 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL glUniform1i(glGetUniformLocation(program_id(CELL_FG_PROGRAM), "sprites"), SPRITE_MAP_UNIT); cell_constants_set = true; } - bool needs_complex_rendering = screen->grman->num_of_negative_refs || (screen->grman->num_of_positive_refs && os_window->is_semi_transparent); - if (needs_complex_rendering) draw_cells_interleaved(vao_idx, gvao_idx, screen, os_window); - else draw_all_cells(vao_idx, gvao_idx, screen); + if (os_window->is_semi_transparent) { + if (screen->grman->count) draw_cells_interleaved_premult(vao_idx, gvao_idx, screen, os_window); + else draw_cells_simple(vao_idx, gvao_idx, screen); + } else { + if (screen->grman->num_of_negative_refs) draw_cells_interleaved(vao_idx, gvao_idx, screen); + else draw_cells_simple(vao_idx, gvao_idx, screen); + } } // }}}