From 8020657d8c0a42ce79057b1d9a5db6801c4e4698 Mon Sep 17 00:00:00 2001 From: Fredrick Brennan Date: Sat, 11 Jan 2020 13:29:41 +0800 Subject: [PATCH] Allow drawing images below cells w/background --- docs/graphics-protocol.rst | 6 ++++-- kitty/cell_fragment.glsl | 28 ++++++++++++++++++---------- kitty/cell_vertex.glsl | 11 +++++++++-- kitty/graphics.c | 11 +++++++++-- kitty/graphics.h | 3 ++- kitty/shaders.c | 33 ++++++++++++++++++++++++--------- kitty/window.py | 3 ++- 7 files changed, 68 insertions(+), 27 deletions(-) diff --git a/docs/graphics-protocol.rst b/docs/graphics-protocol.rst index 9cc2aac33..6aca6a5e7 100644 --- a/docs/graphics-protocol.rst +++ b/docs/graphics-protocol.rst @@ -334,7 +334,9 @@ Finally, you can specify the image *z-index*, i.e. the vertical stacking order. placed in the same location with different z-index values will be blended if they are semi-transparent. You can specify z-index values using the ``z`` key. Negative z-index values mean that the images will be drawn under the text. This -allows rendering of text on top of images. +allows rendering of text on top of images. Negative z-index values below +INT32_MIN/2 (-1073741824) will be drawn under cells with non-default background +colors. Deleting images --------------------- @@ -417,7 +419,7 @@ Key Value Default Description ``Y`` Positive integer ``0`` The y-offset within the first cell at which to start displaying the image ``c`` Positive integer ``0`` The number of columns to display the image over ``r`` Positive integer ``0`` The number of rows to display the image over -``z`` Integer ``0`` The *z-index* vertical stacking order of the image +``z`` 32-bit integer ``0`` The *z-index* vertical stacking order of the image **Keys for deleting images** ----------------------------------------------------------- ``d`` Single character. ``a`` What to delete. diff --git a/kitty/cell_fragment.glsl b/kitty/cell_fragment.glsl index aae9222f0..e463dc173 100644 --- a/kitty/cell_fragment.glsl +++ b/kitty/cell_fragment.glsl @@ -2,7 +2,7 @@ #define WHICH_PROGRAM #define NOT_TRANSPARENT -#if defined(SIMPLE) || defined(BACKGROUND) || defined(SPECIAL) +#if defined(SIMPLE) || defined(BACKGROUND) || defined(SPECIAL) || defined(DEFAULTBG) #define NEEDS_BACKROUND #endif @@ -12,6 +12,8 @@ #ifdef NEEDS_BACKROUND in vec3 background; +in vec3 defaultbg; +in float bgfac; #if defined(TRANSPARENT) || defined(SPECIAL) in float bg_alpha; #endif @@ -76,11 +78,13 @@ vec4 blend_onto_opaque_premul(vec3 over, float over_alpha, vec3 under) { * * 2a) Opaque bg with images under text * There are multiple passes, each pass is blended onto the previous using the opaque blend func (alpha, 1- alpha): - * 1) Draw only the background -- expected output is color with alpha 1 - * 2) Draw the images that are supposed to be below text. This happens in the graphics shader - * 3) Draw the special cells (selection/cursor). Output is same as from step 1, with bg_alpha 1 for special cells and 0 otherwise - * 4) Draw the foreground -- expected output is color with alpha which is blended using the opaque blend func - * 5) Draw the images that are supposed to be above text again in the graphics shader + * 1) Draw only the default background + * 2) Draw the images that are supposed to be below both the background and text. This happens in the graphics shader + * 3) Draw the background of cells that don't have the default background + 4) Draw the images that are supposed to be below text but not background, again in graphics shader. + * 5) Draw the special cells (selection/cursor). Output is same as from step 1, with bg_alpha 1 for special cells and 0 otherwise + * 6) Draw the foreground -- expected output is color with alpha which is blended using the opaque blend func + * 7) Draw the images that are supposed to be above text again in the graphics shader * * 2b) Transparent bg with images * First everything is rendered into a framebuffer, and then the framebauffer is blended onto @@ -125,11 +129,15 @@ void main() { #endif #endif -#ifdef BACKGROUND -#ifdef TRANSPARENT - final_color = vec4(background.rgb * bg_alpha, bg_alpha); +#if (defined(DEFAULTBG) || defined(BACKGROUND)) +#if defined(TRANSPARENT) + final_color = vec4(bgfac * background.rgb * bg_alpha, bg_alpha * bgfac); #else - final_color = vec4(background.rgb, 1.0f); +#if defined(DEFAULTBG) + final_color = vec4(bgfac * background.rgb, 1.0f); +#else + final_color = vec4(bgfac * background.rgb, 1.0f * bgfac); +#endif #endif #endif diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index 1187cce3d..7d42c5e1c 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -35,7 +35,7 @@ const uvec2 cell_pos_map[] = uvec2[4]( // }}} -#if defined(SIMPLE) || defined(BACKGROUND) || defined(SPECIAL) +#if defined(SIMPLE) || defined(BACKGROUND) || defined(SPECIAL) || defined(DEFAULTBG) #define NEEDS_BACKROUND #endif @@ -45,6 +45,8 @@ const uvec2 cell_pos_map[] = uvec2[4]( #ifdef NEEDS_BACKROUND out vec3 background; +out vec3 defaultbg; +out float bgfac; #if defined(TRANSPARENT) || defined(SPECIAL) out float bg_alpha; #endif @@ -197,8 +199,13 @@ void main() { // Background {{{ #ifdef NEEDS_BACKROUND -#if defined(BACKGROUND) +#if defined(BACKGROUND) || defined(DEFAULTBG) background = bg; + defaultbg = to_color(colors[2], default_colors[bg_index]); + bgfac = 1-float(equal(background, defaultbg)); +#if defined(DEFAULTBG) + bgfac += 1; +#endif #endif #if defined(TRANSPARENT) diff --git a/kitty/graphics.c b/kitty/graphics.c index f306b8ef0..b1d49515b 100644 --- a/kitty/graphics.c +++ b/kitty/graphics.c @@ -544,7 +544,9 @@ grman_update_layers(GraphicsManager *self, unsigned int scrolled_by, float scree if (!self->layers_dirty) return false; self->layers_dirty = false; size_t i, j; - self->num_of_negative_refs = 0; self->num_of_positive_refs = 0; + self->num_of_below_refs = 0; + self->num_of_negative_refs = 0; + self->num_of_positive_refs = 0; Image *img; ImageRef *ref; ImageRect r; float screen_width = dx * num_cols, screen_height = dy * num_rows; @@ -565,7 +567,12 @@ grman_update_layers(GraphicsManager *self, unsigned int scrolled_by, float scree if (ref->num_cols > 0) r.right = screen_left + (ref->start_column + (int32_t)ref->num_cols) * dx; else r.right = r.left + screen_width * (float)ref->src_width / screen_width_px; - if (ref->z_index < 0) self->num_of_negative_refs++; else self->num_of_positive_refs++; + if (ref->z_index < ((int32_t)INT32_MIN/2)) + self->num_of_below_refs++; + else if (ref->z_index < 0) + self->num_of_negative_refs++; + else + self->num_of_positive_refs++; ensure_space_for(self, render_data, ImageRenderData, self->count + 1, capacity, 64, true); ImageRenderData *rd = self->render_data + self->count; zero_at_ptr(rd); diff --git a/kitty/graphics.h b/kitty/graphics.h index 3a85dbc65..16af6923c 100644 --- a/kitty/graphics.h +++ b/kitty/graphics.h @@ -72,7 +72,8 @@ typedef struct { size_t count, capacity; ImageRenderData *render_data; bool layers_dirty; - size_t num_of_negative_refs, num_of_positive_refs; + // The number of images below MIN_ZINDEX / 2, then the number of refs between MIN_ZINDEX / 2 and -1 inclusive, then the number of refs above 0 inclusive. + size_t num_of_below_refs, num_of_negative_refs, num_of_positive_refs; unsigned int last_scrolled_by; size_t used_storage; } GraphicsManager; diff --git a/kitty/shaders.c b/kitty/shaders.c index a8c8e7b7e..965d9276a 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -9,7 +9,7 @@ #include "gl.h" #include -enum { CELL_PROGRAM, CELL_BG_PROGRAM, CELL_SPECIAL_PROGRAM, CELL_FG_PROGRAM, BORDERS_PROGRAM, GRAPHICS_PROGRAM, GRAPHICS_PREMULT_PROGRAM, GRAPHICS_ALPHA_MASK_PROGRAM, BLIT_PROGRAM, NUM_PROGRAMS }; +enum { CELL_PROGRAM, CELL_BG_PROGRAM, CELL_DEFAULT_BG_PROGRAM, CELL_SPECIAL_PROGRAM, CELL_FG_PROGRAM, BORDERS_PROGRAM, GRAPHICS_PROGRAM, GRAPHICS_PREMULT_PROGRAM, GRAPHICS_ALPHA_MASK_PROGRAM, BLIT_PROGRAM, NUM_PROGRAMS }; enum { SPRITE_MAP_UNIT, GRAPHICS_UNIT, BLIT_UNIT }; // Sprites {{{ @@ -390,12 +390,18 @@ draw_cells_simple(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) { static void 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_DEFAULT_BG_PROGRAM); + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); + + if (screen->grman->num_of_below_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_below_refs); + + bind_program(CELL_BG_PROGRAM); + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); + + if (screen->grman->num_of_negative_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_below_refs, screen->grman->num_of_negative_refs); bind_program(CELL_SPECIAL_PROGRAM); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); @@ -423,13 +429,21 @@ draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen glBindFramebuffer(GL_DRAW_FRAMEBUFFER, offscreen_framebuffer); glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, os_window->offscreen_texture_id, 0); /* if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) fatal("Offscreen framebuffer not complete"); */ - - bind_program(CELL_BG_PROGRAM); + bind_program(CELL_DEFAULT_BG_PROGRAM); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); glEnable(GL_BLEND); 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); + if (screen->grman->num_of_below_refs) { + draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_below_refs); + } + + bind_program(CELL_BG_PROGRAM); + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); + + if (screen->grman->num_of_negative_refs) { + draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_below_refs, screen->grman->num_of_negative_refs); + } bind_program(CELL_SPECIAL_PROGRAM); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); @@ -469,6 +483,7 @@ set_cell_uniforms(float current_inactive_text_alpha, bool force) { S(GRAPHICS_PREMULT_PROGRAM, image, GRAPHICS_UNIT, 1i); S(CELL_PROGRAM, sprites, SPRITE_MAP_UNIT, 1i); S(CELL_FG_PROGRAM, sprites, SPRITE_MAP_UNIT, 1i); S(CELL_PROGRAM, dim_opacity, OPT(dim_opacity), 1f); S(CELL_FG_PROGRAM, dim_opacity, OPT(dim_opacity), 1f); + S(CELL_BG_PROGRAM, defaultbg, OPT(background), 1f); #undef S cell_uniform_data.constants_set = true; } @@ -530,7 +545,7 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL 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); + if (screen->grman->num_of_negative_refs || screen->grman->num_of_below_refs) draw_cells_interleaved(vao_idx, gvao_idx, screen); else draw_cells_simple(vao_idx, gvao_idx, screen); } } @@ -691,7 +706,7 @@ static PyMethodDef module_methods[] = { bool init_shaders(PyObject *module) { #define C(x) if (PyModule_AddIntConstant(module, #x, x) != 0) { PyErr_NoMemory(); return false; } - C(CELL_PROGRAM); C(CELL_BG_PROGRAM); C(CELL_SPECIAL_PROGRAM); C(CELL_FG_PROGRAM); C(BORDERS_PROGRAM); C(GRAPHICS_PROGRAM); C(GRAPHICS_PREMULT_PROGRAM); C(GRAPHICS_ALPHA_MASK_PROGRAM); C(BLIT_PROGRAM); + C(CELL_PROGRAM); C(CELL_BG_PROGRAM); C(CELL_DEFAULT_BG_PROGRAM); C(CELL_SPECIAL_PROGRAM); C(CELL_FG_PROGRAM); C(BORDERS_PROGRAM); C(GRAPHICS_PROGRAM); C(GRAPHICS_PREMULT_PROGRAM); C(GRAPHICS_ALPHA_MASK_PROGRAM); C(BLIT_PROGRAM); C(GLSL_VERSION); C(GL_VERSION); C(GL_VENDOR); diff --git a/kitty/window.py b/kitty/window.py index bfaeaa70a..e75ec64a8 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -15,7 +15,7 @@ from .constants import ( ScreenGeometry, WindowGeometry, appname, get_boss, wakeup ) from .fast_data_types import ( - BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM, CELL_PROGRAM, + BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_DEFAULT_BG_PROGRAM, CELL_FG_PROGRAM, CELL_PROGRAM, CELL_SPECIAL_PROGRAM, CSI, DCS, DECORATION, DIM, GRAPHICS_ALPHA_MASK_PROGRAM, GRAPHICS_PREMULT_PROGRAM, GRAPHICS_PROGRAM, OSC, REVERSE, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, STRIKETHROUGH, Screen, @@ -63,6 +63,7 @@ def load_shader_programs(semi_transparent=False): for which, p in { 'SIMPLE': CELL_PROGRAM, 'BACKGROUND': CELL_BG_PROGRAM, + 'DEFAULTBG': CELL_DEFAULT_BG_PROGRAM, 'SPECIAL': CELL_SPECIAL_PROGRAM, 'FOREGROUND': CELL_FG_PROGRAM, }.items():