mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-07-10 01:41:16 +00:00
add cursor trail
This commit is contained in:
parent
b07d4059d3
commit
c3eb48fc8a
9 changed files with 129 additions and 3 deletions
|
|
@ -705,6 +705,63 @@ change_menubar_title(PyObject *title UNUSED) {
|
|||
#endif
|
||||
}
|
||||
|
||||
inline static float
|
||||
norm(float x, float y) {
|
||||
return sqrtf(x * x + y * y);
|
||||
}
|
||||
|
||||
static bool
|
||||
update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now) {
|
||||
#define WD w->render_data
|
||||
// the trail corners move towards the cursor corner at a speed proportional to their distance from the cursor corner.
|
||||
// equivalent to exponential ease out animation.
|
||||
static const int ci[4][2] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
|
||||
float cursor_edge_x[2], cursor_edge_y[2];
|
||||
cursor_edge_x[0] = WD.xstart + WD.screen->cursor_render_info.x * WD.dx;
|
||||
cursor_edge_x[1] = cursor_edge_x[0] + WD.dx;
|
||||
cursor_edge_y[0] = WD.ystart - WD.screen->cursor_render_info.y * WD.dy;
|
||||
cursor_edge_y[1] = cursor_edge_y[0] - WD.dy;
|
||||
|
||||
// todo - make these configurable
|
||||
// the decay time for the trail to reach 1/1024 of its distance from the cursor corner
|
||||
float decay_fast = 0.10f;
|
||||
float decay_slow = 0.40f;
|
||||
|
||||
if (OPT(input_delay) < now - WD.screen->cursor->updated_at && ct->updated_at < now) {
|
||||
float cursor_center_x = (cursor_edge_x[0] + cursor_edge_x[1]) * 0.5f;
|
||||
float cursor_center_y = (cursor_edge_y[0] + cursor_edge_y[1]) * 0.5f;
|
||||
float cursor_diag_2 = norm(cursor_edge_x[1] - cursor_edge_x[0], cursor_edge_y[1] - cursor_edge_y[0]) * 0.5;
|
||||
float dt = monotonic_t_to_s_double(now - ct->updated_at);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
float dx = cursor_edge_x[ci[i][0]] - ct->corner_x[i];
|
||||
float dy = cursor_edge_y[ci[i][1]] - ct->corner_y[i];
|
||||
float dist = norm(dx, dy);
|
||||
if (dist == 0) {
|
||||
continue;
|
||||
}
|
||||
float dot = (dx * (cursor_edge_x[ci[i][0]] - cursor_center_x) +
|
||||
dy * (cursor_edge_y[ci[i][1]] - cursor_center_y)) /
|
||||
cursor_diag_2 / dist;
|
||||
|
||||
float decay_seconds = decay_slow + (decay_fast - decay_slow) * (1.0f + dot) * 0.5f;
|
||||
float step = 1.0f - 1.0f / exp2f(10.0f * dt / decay_seconds);
|
||||
|
||||
ct->corner_x[i] += dx * step;
|
||||
ct->corner_y[i] += dy * step;
|
||||
}
|
||||
}
|
||||
ct->updated_at = now;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
float dx = cursor_edge_x[ci[i][0]] - ct->corner_x[i];
|
||||
float dy = cursor_edge_y[ci[i][1]] - ct->corner_y[i];
|
||||
if (dx * dx + dy * dy >= 1e-6) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows, bool *all_windows_have_same_bg, bool scan_for_animated_images) {
|
||||
#define TD os_window->tab_bar_render_data
|
||||
|
|
@ -728,7 +785,6 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
|
|||
color_type first_window_bg = 0;
|
||||
for (unsigned int i = 0; i < tab->num_windows; i++) {
|
||||
Window *w = tab->windows + i;
|
||||
#define WD w->render_data
|
||||
if (w->visible && WD.screen) {
|
||||
screen_check_pause_rendering(WD.screen, now);
|
||||
*num_visible_windows += 1;
|
||||
|
|
@ -751,6 +807,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
|
|||
WD.screen->cursor_render_info.is_focused = os_window->is_focused;
|
||||
set_os_window_title_from_window(w, os_window);
|
||||
*active_window_bg = window_bg;
|
||||
if (true && update_cursor_trail(&tab->cursor_trail, w, now)) needs_render = true;
|
||||
} else {
|
||||
if (WD.screen->cursor_render_info.render_even_when_unfocused) {
|
||||
if (collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window)) needs_render = true;
|
||||
|
|
@ -808,6 +865,7 @@ render_prepared_os_window(OSWindow *os_window, unsigned int active_window_id, co
|
|||
w->cursor_opacity_at_last_render = WD.screen->cursor_render_info.opacity; w->last_cursor_shape = WD.screen->cursor_render_info.shape;
|
||||
}
|
||||
}
|
||||
if (true) draw_trail(&tab->cursor_trail);
|
||||
if (os_window->live_resize.in_progress) draw_resizing_text(os_window);
|
||||
swap_window_buffers(os_window);
|
||||
os_window->last_active_tab = os_window->active_tab; os_window->last_num_tabs = os_window->num_tabs; os_window->last_active_window_id = active_window_id;
|
||||
|
|
|
|||
|
|
@ -297,6 +297,7 @@ typedef struct {
|
|||
PyObject_HEAD
|
||||
|
||||
bool bold, italic, reverse, strikethrough, dim, non_blinking;
|
||||
monotonic_t updated_at;
|
||||
unsigned int x, y;
|
||||
uint8_t decoration;
|
||||
CursorShape shape;
|
||||
|
|
|
|||
|
|
@ -296,6 +296,7 @@ FC_WIDTH_NORMAL: int
|
|||
FC_SLANT_ROMAN: int
|
||||
FC_SLANT_ITALIC: int
|
||||
BORDERS_PROGRAM: int
|
||||
TRAIL_PROGRAM: int
|
||||
PRESS: int
|
||||
RELEASE: int
|
||||
DRAG: int
|
||||
|
|
@ -540,6 +541,8 @@ def add_borders_rect(
|
|||
def init_borders_program() -> None:
|
||||
pass
|
||||
|
||||
def init_trail_program() -> None:
|
||||
pass
|
||||
|
||||
def os_window_has_background_image(os_window_id: int) -> bool:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -1765,6 +1765,7 @@ screen_cursor_position(Screen *self, unsigned int line, unsigned int column) {
|
|||
line += self->margin_top;
|
||||
line = MAX(self->margin_top, MIN(line, self->margin_bottom));
|
||||
}
|
||||
self->cursor->updated_at = monotonic();
|
||||
self->cursor->x = column; self->cursor->y = line;
|
||||
screen_ensure_bounds(self, false, in_margins);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
#define BLEND_ONTO_OPAQUE_WITH_OPAQUE_OUTPUT glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); // blending onto opaque colors with final color having alpha 1
|
||||
#define BLEND_PREMULT glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // blending of pre-multiplied colors
|
||||
|
||||
enum { CELL_PROGRAM, CELL_BG_PROGRAM, CELL_SPECIAL_PROGRAM, CELL_FG_PROGRAM, BORDERS_PROGRAM, GRAPHICS_PROGRAM, GRAPHICS_PREMULT_PROGRAM, GRAPHICS_ALPHA_MASK_PROGRAM, BGIMAGE_PROGRAM, TINT_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, BGIMAGE_PROGRAM, TINT_PROGRAM, TRAIL_PROGRAM, NUM_PROGRAMS };
|
||||
enum { SPRITE_MAP_UNIT, GRAPHICS_UNIT, BGIMAGE_UNIT };
|
||||
|
||||
// Sprites {{{
|
||||
|
|
@ -1133,6 +1133,41 @@ draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_bu
|
|||
|
||||
// }}}
|
||||
|
||||
// Cursor Trail {{{
|
||||
typedef struct {
|
||||
TrailUniforms uniforms;
|
||||
} TrailProgramLayout;
|
||||
static TrailProgramLayout trail_program_layout;
|
||||
|
||||
static void
|
||||
init_trail_program(void) {
|
||||
get_uniform_locations_trail(TRAIL_PROGRAM, &trail_program_layout.uniforms);
|
||||
}
|
||||
|
||||
void
|
||||
draw_trail(CursorTrail *trail) {
|
||||
glEnable(GL_BLEND);
|
||||
// BLEND_PREMULT
|
||||
/*glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);*/
|
||||
BLEND_ONTO_OPAQUE;
|
||||
|
||||
bind_program(TRAIL_PROGRAM);
|
||||
|
||||
glUniform4fv(trail_program_layout.uniforms.x_coords, 1, trail->corner_x);
|
||||
glUniform4fv(trail_program_layout.uniforms.y_coords, 1, trail->corner_y);
|
||||
|
||||
// todo - get cursor color from opt
|
||||
float trail_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
glUniform4fv(trail_program_layout.uniforms.trail_color, 1, trail_color);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
unbind_program();
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// Python API {{{
|
||||
|
||||
static bool
|
||||
|
|
@ -1205,6 +1240,8 @@ NO_ARG(init_borders_program)
|
|||
|
||||
NO_ARG(init_cell_program)
|
||||
|
||||
NO_ARG(init_trail_program)
|
||||
|
||||
static PyObject*
|
||||
sprite_map_set_limits(PyObject UNUSED *self, PyObject *args) {
|
||||
unsigned int w, h;
|
||||
|
|
@ -1229,6 +1266,7 @@ static PyMethodDef module_methods[] = {
|
|||
MW(unbind_program, METH_NOARGS),
|
||||
MW(init_borders_program, METH_NOARGS),
|
||||
MW(init_cell_program, METH_NOARGS),
|
||||
MW(init_trail_program, METH_NOARGS),
|
||||
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
|
@ -1241,7 +1279,7 @@ finalize(void) {
|
|||
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(BGIMAGE_PROGRAM); C(TINT_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(BGIMAGE_PROGRAM); C(TINT_PROGRAM); C(TRAIL_PROGRAM);
|
||||
C(GLSL_VERSION);
|
||||
C(GL_VERSION);
|
||||
C(GL_VENDOR);
|
||||
|
|
|
|||
|
|
@ -27,9 +27,11 @@ from .fast_data_types import (
|
|||
REVERSE,
|
||||
STRIKETHROUGH,
|
||||
TINT_PROGRAM,
|
||||
TRAIL_PROGRAM,
|
||||
compile_program,
|
||||
get_options,
|
||||
init_cell_program,
|
||||
init_trail_program,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -201,5 +203,8 @@ class LoadShaderPrograms:
|
|||
program_for('tint').compile(TINT_PROGRAM, allow_recompile)
|
||||
init_cell_program()
|
||||
|
||||
program_for('trail').compile(TRAIL_PROGRAM, allow_recompile)
|
||||
init_trail_program()
|
||||
|
||||
|
||||
load_shader_programs = LoadShaderPrograms()
|
||||
|
|
|
|||
|
|
@ -212,11 +212,18 @@ typedef struct {
|
|||
ssize_t vao_idx;
|
||||
} BorderRects;
|
||||
|
||||
typedef struct {
|
||||
monotonic_t updated_at;
|
||||
float corner_x[4];
|
||||
float corner_y[4];
|
||||
} CursorTrail;
|
||||
|
||||
typedef struct {
|
||||
id_type id;
|
||||
unsigned int active_window, num_windows, capacity;
|
||||
Window *windows;
|
||||
BorderRects border_rects;
|
||||
CursorTrail cursor_trail;
|
||||
} Tab;
|
||||
|
||||
enum RENDER_STATE { RENDER_FRAME_NOT_REQUESTED, RENDER_FRAME_REQUESTED, RENDER_FRAME_READY };
|
||||
|
|
@ -352,6 +359,7 @@ ssize_t create_border_vao(void);
|
|||
bool send_cell_data_to_gpu(ssize_t, float, float, float, float, Screen *, OSWindow *);
|
||||
void draw_cells(ssize_t, const WindowRenderData*, OSWindow *, bool, bool, bool, Window*);
|
||||
void draw_centered_alpha_mask(OSWindow *w, size_t screen_width, size_t screen_height, size_t width, size_t height, uint8_t *canvas, float);
|
||||
void draw_trail(CursorTrail *trail);
|
||||
void update_surface_size(int, int, uint32_t);
|
||||
void free_texture(uint32_t*);
|
||||
void free_framebuffer(uint32_t*);
|
||||
|
|
|
|||
6
kitty/trail_fragment.glsl
Normal file
6
kitty/trail_fragment.glsl
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
uniform vec4 trail_color;
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = trail_color;
|
||||
}
|
||||
6
kitty/trail_vertex.glsl
Normal file
6
kitty/trail_vertex.glsl
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
uniform vec4 x_coords;
|
||||
uniform vec4 y_coords;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(x_coords[gl_VertexID], y_coords[gl_VertexID], -1.0, 1.0);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue