mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 22:28:24 +02:00
Port rendering of scroll indicator
This commit is contained in:
@@ -25,6 +25,7 @@ in vec4 cursor_color_premult;
|
|||||||
in vec3 decoration_fg;
|
in vec3 decoration_fg;
|
||||||
in float colored_sprite;
|
in float colored_sprite;
|
||||||
in float cell_has_default_bg;
|
in float cell_has_default_bg;
|
||||||
|
in vec2 layer_pos;
|
||||||
|
|
||||||
out vec4 output_color;
|
out vec4 output_color;
|
||||||
|
|
||||||
@@ -91,9 +92,7 @@ vec4 adjust_foreground_contrast_with_background(vec4 text_fg, vec3 bg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec4 layer_color(sampler2D s) {
|
vec4 layer_color(sampler2D s) {
|
||||||
// we need to clamp the co-ordinates as the blank texture has size 1x1
|
return texture(s, layer_pos);
|
||||||
ivec2 pos = clamp(ivec2(gl_FragCoord.xy), ivec2(0), textureSize(s, 0)-1);
|
|
||||||
return texelFetch(s, pos, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_LAYERS
|
#ifdef HAS_LAYERS
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ out vec3 decoration_fg;
|
|||||||
out float colored_sprite;
|
out float colored_sprite;
|
||||||
out float effective_text_alpha;
|
out float effective_text_alpha;
|
||||||
out float cell_has_default_bg;
|
out float cell_has_default_bg;
|
||||||
|
out vec2 layer_pos; // position to sample layer texture at
|
||||||
|
|
||||||
|
|
||||||
// Utility functions {{{
|
// Utility functions {{{
|
||||||
@@ -167,10 +168,12 @@ CellData set_vertex_position() {
|
|||||||
/* The position of this vertex, at a corner of the cell */
|
/* The position of this vertex, at a corner of the cell */
|
||||||
float left = -1.0 + column * dx;
|
float left = -1.0 + column * dx;
|
||||||
float top = 1.0 - row * dy;
|
float top = 1.0 - row * dy;
|
||||||
vec2 xpos = vec2(left, left + dx);
|
|
||||||
vec2 ypos = vec2(top, top - dy);
|
|
||||||
uvec2 pos = cell_pos_map[gl_VertexID];
|
uvec2 pos = cell_pos_map[gl_VertexID];
|
||||||
gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1);
|
gl_Position = vec4(vec2(left, left + dx)[pos.x], vec2(top, top - dy)[pos.y], 0, 1);
|
||||||
|
// The position used to sample the layer textures
|
||||||
|
dx /= 2.0; dy /= 2.0;
|
||||||
|
left = 0 + column * dx; top = 1.0 - row * dy;
|
||||||
|
layer_pos = vec2(vec2(left, left + dx)[pos.x], vec2(top, top - dy)[pos.y]);
|
||||||
// The character sprite being rendered
|
// The character sprite being rendered
|
||||||
sprite_pos = to_sprite_pos(pos, sprite_idx[0] & SPRITE_INDEX_MASK);
|
sprite_pos = to_sprite_pos(pos, sprite_idx[0] & SPRITE_INDEX_MASK);
|
||||||
colored_sprite = float((sprite_idx[0] & SPRITE_COLORED_MASK) >> SPRITE_COLORED_SHIFT);
|
colored_sprite = float((sprite_idx[0] & SPRITE_COLORED_MASK) >> SPRITE_COLORED_SHIFT);
|
||||||
|
|||||||
@@ -102,8 +102,17 @@ typedef struct {
|
|||||||
color_type cursor_bg;
|
color_type cursor_bg;
|
||||||
struct {
|
struct {
|
||||||
struct { float intensity; color_type color; } visual_bell;
|
struct { float intensity; color_type color; } visual_bell;
|
||||||
struct { float frac, alpha; color_type color; unsigned cell_height; } scroll_bar;
|
struct { float frac, alpha; color_type color; unsigned cell_height, cell_width; } scroll_bar;
|
||||||
} ui_layer;
|
} ui_layer;
|
||||||
|
struct {
|
||||||
|
int x;
|
||||||
|
} over_fg_layer;
|
||||||
|
struct {
|
||||||
|
int x;
|
||||||
|
} under_fg_layer;
|
||||||
|
struct {
|
||||||
|
int x;
|
||||||
|
} under_bg_layer;
|
||||||
} last_rendered;
|
} last_rendered;
|
||||||
bool is_dirty, scroll_changed, reload_all_gpu_data;
|
bool is_dirty, scroll_changed, reload_all_gpu_data;
|
||||||
Cursor *cursor;
|
Cursor *cursor;
|
||||||
|
|||||||
101
kitty/shaders.c
101
kitty/shaders.c
@@ -13,6 +13,7 @@
|
|||||||
#include "window_logo.h"
|
#include "window_logo.h"
|
||||||
#include "srgb_gamma.h"
|
#include "srgb_gamma.h"
|
||||||
#include "uniforms_generated.h"
|
#include "uniforms_generated.h"
|
||||||
|
#include "png-reader.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: for shader refactoring
|
* TODO: for shader refactoring
|
||||||
@@ -684,8 +685,7 @@ get_visual_bell_intensity(Screen *screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef struct UIRenderData {
|
typedef struct UIRenderData {
|
||||||
unsigned screen_width, screen_height, cell_width, cell_height;
|
unsigned screen_width, screen_height, cell_width, cell_height, screen_left, screen_top;
|
||||||
|
|
||||||
} UIRenderData;
|
} UIRenderData;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -708,6 +708,37 @@ draw_visual_bell_flash(GLfloat intensity, const color_type flash) {
|
|||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
draw_scroll_indicator(color_type bar_color, GLfloat alpha, float frac, UIRenderData ui) {
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
BLEND_PREMULT;
|
||||||
|
bind_program(TINT_PROGRAM);
|
||||||
|
#define C(shift) srgb_color((bar_color >> shift) & 0xFF) * alpha
|
||||||
|
glUniform4f(tint_program_layout.uniforms.tint_color, C(16), C(8), C(0), alpha);
|
||||||
|
#undef C
|
||||||
|
float bar_width = 0.5f * gl_size(ui.cell_width, ui.screen_width);
|
||||||
|
float bar_height = gl_size(ui.cell_height, ui.screen_height);
|
||||||
|
float bottom = -1.f + MAX(0, 2.f - bar_height) * frac;
|
||||||
|
glUniform4f(tint_program_layout.uniforms.edges, 1.f - bar_width, bottom + bar_height, 1.f, bottom);
|
||||||
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
save_texture_as_png(GLuint texture_id, unsigned width, unsigned height, const char *filename) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||||
|
size_t sz = width * height * sizeof(uint32_t);
|
||||||
|
uint32_t* data = malloc(sz);
|
||||||
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
|
const char *png = png_from_32bit_rgba(data, width, height, &sz, true);
|
||||||
|
if (!sz) fatal("Failed to save PNG to %s with error: %s", filename, png);
|
||||||
|
free(data);
|
||||||
|
FILE* file = fopen(filename, "wb");
|
||||||
|
fwrite(png, 1, sz, file);
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
update_ui_layer(Screen *screen, UIRenderData ui, bool visual_bell_drawn, bool scrollback_indicator_drawn) {
|
update_ui_layer(Screen *screen, UIRenderData ui, bool visual_bell_drawn, bool scrollback_indicator_drawn) {
|
||||||
@@ -719,9 +750,10 @@ update_ui_layer(Screen *screen, UIRenderData ui, bool visual_bell_drawn, bool sc
|
|||||||
flash = !IS_SPECIAL_COLOR(highlight_bg) ? COLOR(visual_bell_color, highlight_bg) : COLOR(visual_bell_color, default_fg);
|
flash = !IS_SPECIAL_COLOR(highlight_bg) ? COLOR(visual_bell_color, highlight_bg) : COLOR(visual_bell_color, default_fg);
|
||||||
#undef COLOR
|
#undef COLOR
|
||||||
}
|
}
|
||||||
bool visual_bell_needs_redraw = intensity != last_ui.visual_bell.intensity || flash != last_ui.visual_bell.color;
|
#define lvb last_ui.visual_bell
|
||||||
last_ui.visual_bell.intensity = intensity;
|
bool visual_bell_needs_redraw = intensity != lvb.intensity || flash != lvb.color;
|
||||||
last_ui.visual_bell.color = flash;
|
lvb.intensity = intensity;
|
||||||
|
lvb.color = flash;
|
||||||
color_type bar_color = 0;
|
color_type bar_color = 0;
|
||||||
GLfloat bar_alpha = OPT(scrollback_indicator_opacity);
|
GLfloat bar_alpha = OPT(scrollback_indicator_opacity);
|
||||||
float bar_frac = 0;
|
float bar_frac = 0;
|
||||||
@@ -729,18 +761,23 @@ update_ui_layer(Screen *screen, UIRenderData ui, bool visual_bell_drawn, bool sc
|
|||||||
bar_color = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg).rgb;
|
bar_color = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg).rgb;
|
||||||
bar_frac = (float)screen->scrolled_by / (float)screen->historybuf->count;
|
bar_frac = (float)screen->scrolled_by / (float)screen->historybuf->count;
|
||||||
}
|
}
|
||||||
bool scrollbar_needs_redraw = (last_ui.scroll_bar.frac != bar_frac || last_ui.scroll_bar.color != bar_color ||
|
|
||||||
last_ui.scroll_bar.cell_height != ui.cell_height || last_ui.scroll_bar.alpha != bar_alpha);
|
#define lsb last_ui.scroll_bar
|
||||||
last_ui.scroll_bar.alpha = bar_alpha;
|
bool scrollbar_needs_redraw = (lsb.frac != bar_frac || lsb.color != bar_color ||
|
||||||
last_ui.scroll_bar.cell_height = ui.cell_height;
|
lsb.cell_height != ui.cell_height || lsb.alpha != bar_alpha || lsb.cell_width != ui.cell_width);
|
||||||
last_ui.scroll_bar.color = bar_color;
|
lsb.alpha = bar_alpha; lsb.cell_height = ui.cell_height; lsb.cell_width = ui.cell_width; lsb.color = bar_color;
|
||||||
last_ui.scroll_bar.frac = bar_frac;
|
lsb.frac = bar_frac;
|
||||||
|
|
||||||
if (!scrollbar_needs_redraw && !visual_bell_needs_redraw) return false;
|
if (!scrollbar_needs_redraw && !visual_bell_needs_redraw) return false;
|
||||||
blank_canvas(0, 0); // clear the framebuffer
|
blank_canvas(0, 0); // clear the framebuffer
|
||||||
save_viewport_using_bottom_left_origin(0, 0, ui.screen_width, ui.screen_height);
|
save_viewport_using_bottom_left_origin(0, 0, ui.screen_width, ui.screen_height);
|
||||||
if (visual_bell_drawn && intensity > 0) draw_visual_bell_flash(last_ui.visual_bell.intensity, last_ui.visual_bell.color);
|
if (visual_bell_drawn && intensity > 0) draw_visual_bell_flash(lvb.intensity, lvb.color);
|
||||||
|
if (scrollback_indicator_drawn) draw_scroll_indicator(bar_color, bar_alpha, bar_frac, ui);
|
||||||
restore_viewport();
|
restore_viewport();
|
||||||
|
if (0) save_texture_as_png(screen->textures.ui.id, ui.screen_width, ui.screen_height, "/tmp/ui.png");
|
||||||
return true;
|
return true;
|
||||||
|
#undef lsb
|
||||||
|
#undef lvb
|
||||||
#undef last_ui
|
#undef last_ui
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,7 +792,7 @@ draw_cells_with_layers(
|
|||||||
|
|
||||||
#define USE_BLANK(which) { if (screen->textures.which.id) { free_texture(&screen->textures.which.id); } glBindTexture(GL_TEXTURE_2D, blank_texture); }
|
#define USE_BLANK(which) { if (screen->textures.which.id) { free_texture(&screen->textures.which.id); } glBindTexture(GL_TEXTURE_2D, blank_texture); }
|
||||||
#define ENSURE_TEXTURE(which) \
|
#define ENSURE_TEXTURE(which) \
|
||||||
has_layers = true; \
|
has_layers = true; bool texture_reset = false; \
|
||||||
if (screen->textures.which.width != ui.screen_width || screen->textures.which.height != ui.screen_height) { \
|
if (screen->textures.which.width != ui.screen_width || screen->textures.which.height != ui.screen_height) { \
|
||||||
if (screen->textures.which.id) free_texture(&screen->textures.which.id); \
|
if (screen->textures.which.id) free_texture(&screen->textures.which.id); \
|
||||||
if (screen->textures.which.framebuffer_id) free_framebuffer(&screen->textures.which.framebuffer_id); \
|
if (screen->textures.which.framebuffer_id) free_framebuffer(&screen->textures.which.framebuffer_id); \
|
||||||
@@ -773,6 +810,7 @@ draw_cells_with_layers(
|
|||||||
glBindFramebuffer(GL_FRAMEBUFFER, screen->textures.which.framebuffer_id); \
|
glBindFramebuffer(GL_FRAMEBUFFER, screen->textures.which.framebuffer_id); \
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->textures.which.id, 0); \
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->textures.which.id, 0); \
|
||||||
check_framebuffer_status_or_die(); \
|
check_framebuffer_status_or_die(); \
|
||||||
|
texture_reset = true; \
|
||||||
} \
|
} \
|
||||||
glBindTexture(GL_TEXTURE_2D, screen->textures.which.id); \
|
glBindTexture(GL_TEXTURE_2D, screen->textures.which.id); \
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, screen->textures.which.framebuffer_id); \
|
glBindFramebuffer(GL_FRAMEBUFFER, screen->textures.which.framebuffer_id); \
|
||||||
@@ -780,17 +818,20 @@ draw_cells_with_layers(
|
|||||||
glActiveTexture(GL_TEXTURE0 + UNDER_BG_LAYER_UNIT);
|
glActiveTexture(GL_TEXTURE0 + UNDER_BG_LAYER_UNIT);
|
||||||
if (grd.num_of_below_refs || has_background_image) {
|
if (grd.num_of_below_refs || has_background_image) {
|
||||||
ENSURE_TEXTURE(under_bg);
|
ENSURE_TEXTURE(under_bg);
|
||||||
|
if (texture_reset) zero_at_ptr(&screen->last_rendered.under_bg_layer);
|
||||||
has_under_bg = 1.;
|
has_under_bg = 1.;
|
||||||
} else USE_BLANK(under_bg);
|
} else USE_BLANK(under_bg);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + UNDER_FG_LAYER_UNIT);
|
glActiveTexture(GL_TEXTURE0 + UNDER_FG_LAYER_UNIT);
|
||||||
if (grd.num_of_below_refs || wl) {
|
if (grd.num_of_below_refs || wl) {
|
||||||
ENSURE_TEXTURE(under_fg);
|
ENSURE_TEXTURE(under_fg);
|
||||||
|
if (texture_reset) zero_at_ptr(&screen->last_rendered.under_fg_layer);
|
||||||
} else USE_BLANK(under_fg);
|
} else USE_BLANK(under_fg);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + OVER_FG_LAYER_UNIT);
|
glActiveTexture(GL_TEXTURE0 + OVER_FG_LAYER_UNIT);
|
||||||
if (grd.num_of_positive_refs) {
|
if (grd.num_of_positive_refs) {
|
||||||
ENSURE_TEXTURE(over_fg);
|
ENSURE_TEXTURE(over_fg);
|
||||||
|
if (texture_reset) zero_at_ptr(&screen->last_rendered.over_fg_layer);
|
||||||
} else USE_BLANK(over_fg);
|
} else USE_BLANK(over_fg);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + UI_LAYER_UNIT);
|
glActiveTexture(GL_TEXTURE0 + UI_LAYER_UNIT);
|
||||||
@@ -798,6 +839,7 @@ draw_cells_with_layers(
|
|||||||
bool scrollback_indicator_drawn = !(OPT(scrollback_indicator_opacity) <= 0 || screen->linebuf != screen->main_linebuf || !screen->scrolled_by);
|
bool scrollback_indicator_drawn = !(OPT(scrollback_indicator_opacity) <= 0 || screen->linebuf != screen->main_linebuf || !screen->scrolled_by);
|
||||||
if (visual_bell_drawn || scrollback_indicator_drawn) {
|
if (visual_bell_drawn || scrollback_indicator_drawn) {
|
||||||
ENSURE_TEXTURE(ui);
|
ENSURE_TEXTURE(ui);
|
||||||
|
if (texture_reset) zero_at_ptr(&screen->last_rendered.ui_layer);
|
||||||
update_ui_layer(screen, ui, visual_bell_drawn, scrollback_indicator_drawn);
|
update_ui_layer(screen, ui, visual_bell_drawn, scrollback_indicator_drawn);
|
||||||
} else USE_BLANK(ui);
|
} else USE_BLANK(ui);
|
||||||
#undef ENSURE_TEXTURE
|
#undef ENSURE_TEXTURE
|
||||||
@@ -823,30 +865,6 @@ draw_cells_with_layers(
|
|||||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
draw_scroll_indicator(bool premult, Screen *screen, const CellRenderData *crd) {
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
if (premult) { BLEND_PREMULT } else { BLEND_ONTO_OPAQUE }
|
|
||||||
bind_program(TINT_PROGRAM);
|
|
||||||
const color_type bar_color = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg).rgb;
|
|
||||||
GLfloat alpha = OPT(scrollback_indicator_opacity);
|
|
||||||
float frac = (float)screen->scrolled_by / (float)screen->historybuf->count;
|
|
||||||
const GLfloat bar_height = crd->gl.dy;
|
|
||||||
GLfloat bottom = (crd->gl.ystart - crd->gl.height);
|
|
||||||
bottom += MAX(0, crd->gl.height - bar_height) * frac;
|
|
||||||
#define C(shift) srgb_color((bar_color >> shift) & 0xFF) * premult_factor
|
|
||||||
GLfloat premult_factor = premult ? alpha : 1.0f;
|
|
||||||
glUniform4f(tint_program_layout.uniforms.tint_color, C(16), C(8), C(0), alpha);
|
|
||||||
#undef C
|
|
||||||
GLfloat width = 0.5f * crd->gl.dx;
|
|
||||||
GLfloat left = (GLfloat)(crd->gl.xstart + (screen->columns * crd->gl.dx - width));
|
|
||||||
glUniform4f(tint_program_layout.uniforms.edges, left, bottom, left + width, bottom + bar_height);
|
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static float prev_inactive_text_alpha = -1;
|
static float prev_inactive_text_alpha = -1;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1071,10 +1089,13 @@ draw_cells(bool for_final_output, const WindowRenderData *srd, OSWindow *os_wind
|
|||||||
has_underlying_image |= grd.num_of_below_refs > 0 || grd.num_of_negative_refs > 0;
|
has_underlying_image |= grd.num_of_below_refs > 0 || grd.num_of_negative_refs > 0;
|
||||||
(void)has_underlying_image;
|
(void)has_underlying_image;
|
||||||
bool is_semi_transparent = os_window->is_semi_transparent && min_bg_opacity < 1.;
|
bool is_semi_transparent = os_window->is_semi_transparent && min_bg_opacity < 1.;
|
||||||
UIRenderData ui = {srd->geometry.right - srd->geometry.left, srd->geometry.bottom - srd->geometry.top, os_window->fonts_data->fcm.cell_width, os_window->fonts_data->fcm.cell_height};
|
UIRenderData ui = {
|
||||||
save_viewport_using_top_left_origin(srd->geometry.left, srd->geometry.top, ui.screen_width, ui.screen_height);
|
srd->geometry.right - srd->geometry.left, srd->geometry.bottom - srd->geometry.top,
|
||||||
|
os_window->fonts_data->fcm.cell_width, os_window->fonts_data->fcm.cell_height,
|
||||||
|
srd->geometry.left, srd->geometry.top,
|
||||||
|
};
|
||||||
|
save_viewport_using_top_left_origin(ui.screen_left, ui.screen_top, ui.screen_width, ui.screen_height);
|
||||||
draw_cells_with_layers(for_final_output, os_window, screen, ui, is_semi_transparent, grd, wl);
|
draw_cells_with_layers(for_final_output, os_window, screen, ui, is_semi_transparent, grd, wl);
|
||||||
draw_scroll_indicator(is_semi_transparent, screen, &crd);
|
|
||||||
if (window && screen->display_window_char) draw_window_number(os_window, screen, &crd, window);
|
if (window && screen->display_window_char) draw_window_number(os_window, screen, &crd, window);
|
||||||
if (OPT(show_hyperlink_targets) && window && screen->current_hyperlink_under_mouse.id && !is_mouse_hidden(os_window)) draw_hyperlink_target(os_window, screen, &crd, window);
|
if (OPT(show_hyperlink_targets) && window && screen->current_hyperlink_under_mouse.id && !is_mouse_hidden(os_window)) draw_hyperlink_target(os_window, screen, &crd, window);
|
||||||
free(scaled_render_data);
|
free(scaled_render_data);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
uniform vec4 tint_color;
|
uniform vec4 tint_color;
|
||||||
out vec4 color; // must be in linear space
|
out vec4 color; // must be in linear space and pre-multiplied
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
color = tint_color;
|
color = tint_color;
|
||||||
|
|||||||
Reference in New Issue
Block a user