Make visual bell flash much more gentle

Right now visual bell makes background flash sharply with bright white
(when configured with darkish color theme). This causes eye strain,
especially prominent in unlit environments.

This change makes background bounce smoothly between regular bg color
and highlight (selection) bg color for the configured visual bell
duration. Intensity is animated with cubic easing functions. It
currently peaks at 20% of the duration, this is hardcoded.

Mark functions computing intensity and easing as inline

Do smarter blending of visual bell flash

Blend highlight color with pegtop's softlight mode over both background
and half as much over foreground. This should help with flash visibility
in light themed and inverted colors contexts.

Blend flash in BACKGROUND pass also

Revert "Do smarter blending of visual bell flash"

This reverts commit 9a269d55c7d04334b1c4891c42914423517dfad6.

Revert "Blend flash in BACKGROUND pass also"

This reverts commit 756332cb9d7576b08db78406e37349aa6d1df156.

Revert "Make visual bell flash much more gentle"

This reverts commit cbfe5d59ada2da690e14c7532a7468b0c307c462.

Render flash overlay in a separate drawcall

Trigger frequent repaints to make for smooth animation

Attenuate flash a bit more
This commit is contained in:
Andrew Mayorov 2020-08-26 01:02:27 +03:00 committed by Kovid Goyal
parent 477a652b44
commit aff6fdfa84
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 60 additions and 7 deletions

View File

@ -615,7 +615,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
} }
static void static void
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) { render_os_window(OSWindow *os_window, unsigned int active_window_id, color_type active_window_bg, unsigned int num_visible_windows, bool all_windows_have_same_bg) {
// ensure all pixels are cleared to background color at least once in every buffer // ensure all pixels are cleared to background color at least once in every buffer
if (os_window->clear_count++ < 3) blank_os_window(os_window); if (os_window->clear_count++ < 3) blank_os_window(os_window);
Tab *tab = os_window->tabs + os_window->active_tab; Tab *tab = os_window->tabs + os_window->active_tab;
@ -637,8 +637,7 @@ render_os_window(OSWindow *os_window, monotonic_t now, unsigned int active_windo
bool is_active_window = i == tab->active_window; bool is_active_window = i == tab->active_window;
draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx * x_ratio, WD.dy * y_ratio, WD.screen, os_window, is_active_window, true); draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx * x_ratio, WD.dy * y_ratio, WD.screen, os_window, is_active_window, true);
if (WD.screen->start_visual_bell_at != 0) { if (WD.screen->start_visual_bell_at != 0) {
monotonic_t bell_left = OPT(visual_bell_duration) - (now - WD.screen->start_visual_bell_at); set_maximum_wait(OPT(repaint_delay));
set_maximum_wait(bell_left);
} }
w->cursor_visible_at_last_render = WD.screen->cursor_render_info.is_visible; w->last_cursor_x = WD.screen->cursor_render_info.x; w->last_cursor_y = WD.screen->cursor_render_info.y; w->last_cursor_shape = WD.screen->cursor_render_info.shape; w->cursor_visible_at_last_render = WD.screen->cursor_render_info.is_visible; w->last_cursor_x = WD.screen->cursor_render_info.x; w->last_cursor_y = WD.screen->cursor_render_info.y; w->last_cursor_shape = WD.screen->cursor_render_info.shape;
} }
@ -726,7 +725,7 @@ render(monotonic_t now, bool input_read) {
if (prepare_to_render_os_window(w, now, &active_window_id, &active_window_bg, &num_visible_windows, &all_windows_have_same_bg, scan_for_animated_images)) needs_render = true; if (prepare_to_render_os_window(w, now, &active_window_id, &active_window_bg, &num_visible_windows, &all_windows_have_same_bg, scan_for_animated_images)) needs_render = true;
if (w->last_active_window_id != active_window_id || w->last_active_tab != w->active_tab || w->focused_at_last_render != w->is_focused) needs_render = true; if (w->last_active_window_id != active_window_id || w->last_active_tab != w->active_tab || w->focused_at_last_render != w->is_focused) needs_render = true;
if (w->render_calls < 3 && w->bgimage && w->bgimage->texture_id) needs_render = true; if (w->render_calls < 3 && w->bgimage && w->bgimage->texture_id) needs_render = true;
if (needs_render) render_os_window(w, now, active_window_id, active_window_bg, num_visible_windows, all_windows_have_same_bg); if (needs_render) render_os_window(w, active_window_id, active_window_bg, num_visible_windows, all_windows_have_same_bg);
if (w->is_focused) change_menubar_title(w->window_title); if (w->is_focused) change_menubar_title(w->window_title);
} }
last_render_at = now; last_render_at = now;

View File

@ -1512,12 +1512,43 @@ screen_use_latin1(Screen *self, bool on) {
bool bool
screen_invert_colors(Screen *self) { screen_invert_colors(Screen *self) {
bool inverted = false; bool inverted = false;
if (self->modes.mDECSCNM) inverted = true;
return inverted;
}
static inline float
ease_out_cubic(float phase) {
return 1.0f - powf(1.0f - phase, 3.0f);
}
static inline float
ease_in_out_cubic(float phase) {
return phase < 0.5f ?
4.0f * powf(phase, 3.0f) :
1.0f - powf(-2.0f * phase + 2.0f, 3.0f) / 2.0f;
}
static inline float
visual_bell_intensity(float phase) {
float peak = 0.2f;
float fade = 1.0f - peak;
if (phase < peak)
return ease_out_cubic(phase / peak);
else
return ease_in_out_cubic((1.0f - phase) / fade);
}
float
screen_visual_bell_intensity(Screen *self) {
if (self->start_visual_bell_at > 0) { if (self->start_visual_bell_at > 0) {
if (monotonic() - self->start_visual_bell_at <= OPT(visual_bell_duration)) inverted = true; monotonic_t progress = monotonic() - self->start_visual_bell_at;
monotonic_t duration = OPT(visual_bell_duration);
if (progress <= duration) {
return visual_bell_intensity((float)progress / duration);
}
else self->start_visual_bell_at = 0; else self->start_visual_bell_at = 0;
} }
if (self->modes.mDECSCNM) inverted = inverted ? false : true; return 0.0f;
return inverted;
} }
void void

View File

@ -207,6 +207,7 @@ void screen_apply_selection(Screen *self, void *address, size_t size);
bool screen_is_selection_dirty(Screen *self); bool screen_is_selection_dirty(Screen *self);
bool screen_has_selection(Screen*); bool screen_has_selection(Screen*);
bool screen_invert_colors(Screen *self); bool screen_invert_colors(Screen *self);
float screen_visual_bell_intensity(Screen *self);
void screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE, bool cursor_has_moved); void screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE, bool cursor_has_moved);
bool screen_is_cursor_visible(Screen *self); bool screen_is_cursor_visible(Screen *self);
bool screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end); bool screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end);

View File

@ -458,6 +458,23 @@ draw_tint(bool premult, Screen *screen, GLfloat xstart, GLfloat ystart, GLfloat
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
} }
void
draw_visual_bell_flash(GLfloat intensity, GLfloat xstart, GLfloat ystart, GLfloat w, GLfloat h, Screen *screen) {
glEnable(GL_BLEND);
// BLEND_PREMULT
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
bind_program(TINT_PROGRAM);
// TODO config option worth?
GLfloat attenuation = 0.4f;
color_type flash = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg);
#define C(shift) ((((GLfloat)((flash >> shift) & 0xFF)) / 255.0f) * intensity * attenuation)
glUniform4f(tint_program_layout.tint_color_location, C(16), C(8), C(0), intensity * attenuation);
#undef C
glUniform4f(tint_program_layout.edges_location, xstart, ystart - h, xstart + w, ystart);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisable(GL_BLEND);
}
static void static void
draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *w, GLfloat xstart, GLfloat ystart, GLfloat width, GLfloat height) { 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); glEnable(GL_BLEND);
@ -650,6 +667,11 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL
vao_idx, gvao_idx, screen, os_window, xstart, ystart, w, h); vao_idx, gvao_idx, screen, os_window, xstart, ystart, w, h);
else draw_cells_simple(vao_idx, gvao_idx, screen); else draw_cells_simple(vao_idx, gvao_idx, screen);
} }
float intensity = screen_visual_bell_intensity(screen);
if (intensity > 0.0f) {
draw_visual_bell_flash((GLfloat)intensity, xstart, ystart, w, h, screen);
}
} }
// }}} // }}}