diff --git a/kitty/config_data.py b/kitty/config_data.py index 3d2c2ab93..6960cf30b 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -864,6 +864,12 @@ Path to a background image. Must be in PNG format.''')) o('background_image_layout', 'tiled', option_type=choices('tiled', 'scaled', 'mirror-tiled'), long_text=_(''' Whether to tile or scale the background image.''')) +o('background_image_tint', 0.5, option_type=unit_float, long_text=_(''' +How much to tint the background image by the background area. The tint is applied +only under the text area, not margin/borders. Makes it easier to read the text. +Tinting is done using the current background color for each window. +''')) + o('background_image_linear', False, long_text=_(''' When background image is scaled, whether linear interpolation should be used.''')) diff --git a/kitty/shaders.c b/kitty/shaders.c index 43cc3d1a3..fc569aa54 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, BGIMAGE_PROGRAM, NUM_PROGRAMS }; +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, BGIMAGE_PROGRAM, TINT_PROGRAM, NUM_PROGRAMS }; enum { SPRITE_MAP_UNIT, GRAPHICS_UNIT, BLIT_UNIT, BGIMAGE_UNIT }; // Sprites {{{ @@ -168,6 +168,10 @@ typedef struct { GLint image_location, tiled_location, sizes_location, opacity_location; } BGImageProgramLayout; static BGImageProgramLayout bgimage_program_layout = {0}; +typedef struct { + GLint tint_color_location, edges_location; +} TintProgramLayout; +static TintProgramLayout tint_program_layout = {0}; static void init_cell_program(void) { @@ -190,6 +194,8 @@ init_cell_program(void) { bgimage_program_layout.opacity_location = get_uniform_location(BGIMAGE_PROGRAM, "opacity"); bgimage_program_layout.sizes_location = get_uniform_location(BGIMAGE_PROGRAM, "sizes"); bgimage_program_layout.tiled_location = get_uniform_location(BGIMAGE_PROGRAM, "tiled"); + tint_program_layout.tint_color_location = get_uniform_location(TINT_PROGRAM, "tint_color"); + tint_program_layout.edges_location = get_uniform_location(TINT_PROGRAM, "edges"); } #define CELL_BUFFERS enum { cell_data_buffer, selection_buffer, uniform_buffer }; @@ -434,15 +440,23 @@ has_bgimage(OSWindow *w) { } static void -draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *w) { +draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *w, GLfloat xstart, GLfloat ystart, GLfloat width, GLfloat height) { glEnable(GL_BLEND); BLEND_ONTO_OPAQUE; - bind_program(CELL_BG_PROGRAM); // draw background for all cells if (!has_bgimage(w)) { + bind_program(CELL_BG_PROGRAM); glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 3); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); + } else if (OPT(background_image_tint) > 0) { + bind_program(TINT_PROGRAM); + color_type window_bg = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.default_bg, screen->color_profile->configured.default_bg); +#define C(shift) ((((GLfloat)((window_bg >> shift) & 0xFF)) / 255.0f)) + glUniform4f(tint_program_layout.tint_color_location, C(16), C(8), C(0), OPT(background_image_tint)); +#undef C + glUniform4f(tint_program_layout.edges_location, xstart, ystart - height, xstart + width, ystart); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } if (screen->grman->num_of_below_refs || has_bgimage(w)) { @@ -610,7 +624,7 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL if (screen->grman->count || has_bgimage(os_window)) 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 || screen->grman->num_of_below_refs || has_bgimage(os_window)) draw_cells_interleaved(vao_idx, gvao_idx, screen, os_window); + if (screen->grman->num_of_negative_refs || screen->grman->num_of_below_refs || has_bgimage(os_window)) draw_cells_interleaved(vao_idx, gvao_idx, screen, os_window, xstart, ystart, w, h); else draw_cells_simple(vao_idx, gvao_idx, screen); } } @@ -779,7 +793,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(BGIMAGE_PROGRAM); + 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(BGIMAGE_PROGRAM); C(TINT_PROGRAM); C(GLSL_VERSION); C(GL_VERSION); C(GL_VENDOR); diff --git a/kitty/state.c b/kitty/state.c index 412de2e46..a30cfc010 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -560,6 +560,7 @@ PYWRAP1(set_options) { S(cursor_stop_blinking_after, parse_s_double_to_monotonic_t); S(background_opacity, PyFloat_AsFloat); S(background_image_layout, bglayout); + S(background_image_tint, PyFloat_AsFloat); S(background_image_linear, PyObject_IsTrue); S(dim_opacity, PyFloat_AsFloat); S(dynamic_background_opacity, PyObject_IsTrue); diff --git a/kitty/state.h b/kitty/state.h index 71fdb4f9a..d3394e1bf 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -42,6 +42,7 @@ typedef struct { char* background_image; BackgroundImageLayout background_image_layout; bool background_image_linear; + float background_image_tint; bool dynamic_background_opacity; float inactive_text_alpha; diff --git a/kitty/tint_fragment.glsl b/kitty/tint_fragment.glsl new file mode 100644 index 000000000..ce3b849af --- /dev/null +++ b/kitty/tint_fragment.glsl @@ -0,0 +1,8 @@ +#version GLSL_VERSION + +uniform vec4 tint_color; +out vec4 color; + +void main() { + color = tint_color; +} diff --git a/kitty/tint_vertex.glsl b/kitty/tint_vertex.glsl new file mode 100644 index 000000000..f8c85ece7 --- /dev/null +++ b/kitty/tint_vertex.glsl @@ -0,0 +1,19 @@ +#version GLSL_VERSION + +uniform vec4 edges; + +void main() { + float left = edges[0]; + float top = edges[1]; + float right = edges[2]; + float bottom = edges[3]; + vec2 pos_map[] = vec2[4]( + vec2(left, top), + vec2(left, bottom), + vec2(right, bottom), + vec2(right, top) + ); + + + gl_Position = vec4(pos_map[gl_VertexID], 0, 1); +} diff --git a/kitty/window.py b/kitty/window.py index 7faf76dc1..23771ca61 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -19,10 +19,10 @@ from .fast_data_types import ( CELL_PROGRAM, CELL_SPECIAL_PROGRAM, CSI, DCS, DECORATION, DIM, GRAPHICS_ALPHA_MASK_PROGRAM, GRAPHICS_PREMULT_PROGRAM, GRAPHICS_PROGRAM, MARK, MARK_MASK, OSC, REVERSE, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, - STRIKETHROUGH, Screen, add_window, cell_size_for_window, compile_program, - get_clipboard_string, init_cell_program, set_clipboard_string, - set_titlebar_color, set_window_render_data, update_window_title, - update_window_visibility, viewport_for_window + STRIKETHROUGH, TINT_PROGRAM, Screen, add_window, cell_size_for_window, + compile_program, get_clipboard_string, init_cell_program, + set_clipboard_string, set_titlebar_color, set_window_render_data, + update_window_title, update_window_visibility, viewport_for_window ) from .keys import defines, extended_key_event, keyboard_mode_name from .rgb import to_color @@ -95,6 +95,8 @@ def load_shader_programs(semi_transparent=False): v, f = load_shaders('bgimage') compile_program(BGIMAGE_PROGRAM, v, f) + v, f = load_shaders('tint') + compile_program(TINT_PROGRAM, v, f) init_cell_program()