diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index 9dadda930..88dfa3bcb 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -3,10 +3,11 @@ uniform uvec2 dimensions; // xnum, ynum uniform vec4 steps; // xstart, ystart, dx, dy uniform vec2 sprite_layout; // dx, dy uniform ivec2 color_indices; // which color to use as fg and which as bg -uniform uvec2 default_colors; // The default foreground and background colors +uniform uvec4 default_colors; // The default colors uniform uint color_table[256]; // The color table in uvec3 sprite_coords; in uvec3 colors; +in float is_selected; out vec3 sprite_pos; out vec3 underline_pos; out vec3 strike_pos; @@ -56,6 +57,10 @@ vec3 to_sprite_pos(uvec2 pos, uint x, uint y, uint z) { return vec3(s_xpos[pos.x], s_ypos[pos.y], z); } +vec3 apply_selection(vec3 color, uint which) { + return is_selected * color_to_vec(which) + (1.0 - is_selected) * color; +} + void main() { uint instance_id = uint(gl_InstanceID); uint r = instance_id / dimensions[0]; @@ -71,9 +76,9 @@ void main() { uint fg = colors[color_indices[0]]; uint bg = colors[color_indices[1]]; uint decoration = colors[2]; - foreground = to_color(fg, default_colors[color_indices[0]]); - background = to_color(bg, default_colors[color_indices[1]]); - decoration_fg = to_color(decoration, default_colors[0]); + foreground = apply_selection(to_color(fg, default_colors[color_indices[0]]), default_colors[2]); + background = apply_selection(to_color(bg, default_colors[color_indices[1]]), default_colors[3]); + decoration_fg = to_color(decoration, default_colors[color_indices[0]]); underline_pos = to_sprite_pos(pos, (sprite_coords.z >> 24) & SMASK, ZERO, ZERO); strike_pos = to_sprite_pos(pos, (sprite_coords.z >> 26) & SMASK, ZERO, ZERO); } diff --git a/kitty/char_grid.py b/kitty/char_grid.py index f46c3ef1c..fa5c111e4 100644 --- a/kitty/char_grid.py +++ b/kitty/char_grid.py @@ -11,13 +11,13 @@ from threading import Lock from .config import build_ansi_color_table, defaults from .constants import ( - GLuint, ScreenGeometry, cell_size, get_boss, viewport_size + GLfloat, GLuint, ScreenGeometry, cell_size, get_boss, viewport_size ) from .fast_data_types import ( CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, DATA_CELL_SIZE, GL_BLEND, - GL_LINE_LOOP, GL_TRIANGLE_FAN, GL_UNSIGNED_INT, glDisable, glDrawArrays, - glDrawArraysInstanced, glEnable, glUniform1i, glUniform2f, glUniform2i, - glUniform2ui, glUniform4f, glUniform1uiv + GL_FLOAT, GL_LINE_LOOP, GL_TRIANGLE_FAN, GL_UNSIGNED_INT, glDisable, + glDrawArrays, glDrawArraysInstanced, glEnable, glUniform1i, glUniform1uiv, + glUniform2f, glUniform2i, glUniform2ui, glUniform4f, glUniform4ui ) from .rgb import to_color from .shaders import ShaderProgram, load_shaders @@ -36,11 +36,13 @@ class DynamicColor(Enum): class CellProgram(ShaderProgram): def create_sprite_map(self): - stride = DATA_CELL_SIZE * sizeof(GLuint) - size = DATA_CELL_SIZE // 2 with self.array_object_creator() as add_attribute: + stride = DATA_CELL_SIZE * sizeof(GLuint) + size = DATA_CELL_SIZE // 2 add_attribute('sprite_coords', size=size, dtype=GL_UNSIGNED_INT, stride=stride, divisor=1) add_attribute('colors', size=size, dtype=GL_UNSIGNED_INT, stride=stride, offset=stride // 2, divisor=1) + add_attribute.newbuf() + add_attribute('is_selected', size=1, dtype=GL_FLOAT, stride=sizeof(GLfloat), divisor=1) return add_attribute.vao_id @@ -124,7 +126,7 @@ def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell def render_cells(vao_id, sg, cell_program, sprites, color_profile, invert_colors=False): ul = cell_program.uniform_location glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum) - glUniform2ui(ul('default_colors'), color_profile.default_fg, color_profile.default_bg) + glUniform4ui(ul('default_colors'), color_profile.default_fg, color_profile.default_bg, color_profile.highlight_fg, color_profile.highlight_bg) glUniform1uiv(ul('color_table'), 256, color_profile.color_table_address()) glUniform2i(ul('color_indices'), 1 if invert_colors else 0, 0 if invert_colors else 1) glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy) @@ -142,7 +144,7 @@ class CharGrid: self.buffer_lock = Lock() self.vao_id = None self.current_selection = Selection() - self.last_rendered_selection = self.current_selection.limits(0, screen.lines, screen.columns) + self.last_rendered_selection = None self.render_buf_is_dirty = True self.render_data = None self.scrolled_by = 0 @@ -156,7 +158,7 @@ class CharGrid: self.opts = opts self.default_cursor = self.current_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0) self.opts = opts - self.sprite_map_type = self.main_sprite_map = self.scroll_sprite_map = self.render_buf = None + self.main_sprite_map = self.scroll_sprite_map = self.render_buf = None def escape(chars): return ''.join(frozenset(chars)).replace('\\', r'\\').replace(']', r'\]').replace('-', r'\-') @@ -177,12 +179,12 @@ class CharGrid: def resize(self, window_geometry): self.update_position(window_geometry) - self.sprite_map_type = (GLuint * (self.screen_geometry.ynum * self.screen_geometry.xnum * DATA_CELL_SIZE)) - self.main_sprite_map = self.sprite_map_type() - self.scroll_sprite_map = self.sprite_map_type() + rt = (GLuint * (self.screen_geometry.ynum * self.screen_geometry.xnum * DATA_CELL_SIZE)) + self.main_sprite_map = rt() + self.scroll_sprite_map = rt() with self.buffer_lock: - self.render_buf = self.sprite_map_type() - self.selection_buf = self.sprite_map_type() + self.render_buf = rt() + self.selection_buf = (GLfloat * (self.screen_geometry.ynum * self.screen_geometry.xnum))() self.render_buf_is_dirty = True self.current_selection.clear() @@ -360,19 +362,15 @@ class CharGrid: return if self.vao_id is None: self.vao_id = cell_program.create_sprite_map() - buf = self.render_buf start, end = sel = self.current_selection.limits(self.scrolled_by, self.screen.lines, self.screen.columns) - if start != end: - buf = self.selection_buf - if self.render_buf_is_dirty or sel != self.last_rendered_selection: - memmove(buf, self.render_buf, sizeof(type(buf))) - fg = self.screen.color_profile.highlight_fg - bg = self.screen.color_profile.highlight_bg - self.screen.apply_selection(addressof(buf), start[0], start[1], end[0], end[1], fg, bg) - if self.render_buf_is_dirty or self.last_rendered_selection != sel: - cell_program.send_vertex_data(self.vao_id, buf) - self.render_buf_is_dirty = False + selection_changed = sel != self.last_rendered_selection + if selection_changed: + self.screen.apply_selection(addressof(self.selection_buf), start[0], start[1], end[0], end[1], len(self.selection_buf)) + cell_program.send_vertex_data(self.vao_id, self.selection_buf, bufnum=1) self.last_rendered_selection = sel + if self.render_buf_is_dirty: + cell_program.send_vertex_data(self.vao_id, self.render_buf) + self.render_buf_is_dirty = False return sg def render_cells(self, sg, cell_program, sprites, invert_colors=False): diff --git a/kitty/gl.h b/kitty/gl.h index 918bdbf5d..e5c908ee0 100644 --- a/kitty/gl.h +++ b/kitty/gl.h @@ -84,6 +84,16 @@ Uniform2ui(PyObject UNUSED *self, PyObject *args) { Py_RETURN_NONE; } +static PyObject* +Uniform4ui(PyObject UNUSED *self, PyObject *args) { + int location; + unsigned int a, b, c, d; + if (!PyArg_ParseTuple(args, "iIIII", &location, &a, &b, &c, &d)) return NULL; + glUniform4ui(location, a, b, c, d); + CHECK_ERROR; + Py_RETURN_NONE; +} + static PyObject* Uniform1uiv(PyObject UNUSED *self, PyObject *args) { int location; @@ -784,6 +794,7 @@ int add_module_gl_constants(PyObject *module) { METH(GetProgramiv, METH_VARARGS) \ METH(GetShaderiv, METH_VARARGS) \ METH(Uniform2ui, METH_VARARGS) \ + METH(Uniform4ui, METH_VARARGS) \ METH(Uniform1uiv, METH_VARARGS) \ METH(Uniform2i, METH_VARARGS) \ METH(Uniform1i, METH_VARARGS) \ diff --git a/kitty/screen.c b/kitty/screen.c index fbd100a42..88ff7d3fd 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1208,16 +1208,15 @@ set_scroll_cell_data(Screen *self, PyObject *args) { static PyObject* apply_selection(Screen *self, PyObject *args) { - unsigned int fg, bg, startx, endx, starty, endy; + unsigned int size, startx, endx, starty, endy, i, end; PyObject *l; - if (!PyArg_ParseTuple(args, "O!IIIIII", &PyLong_Type, &l, &startx, &starty, &endx, &endy, &fg, &bg)) return NULL; + if (!PyArg_ParseTuple(args, "O!IIIII", &PyLong_Type, &l, &startx, &starty, &endx, &endy, &size)) return NULL; if (startx >= self->columns || starty >= self->lines || endx >= self->columns || endy >= self->lines) { Py_RETURN_NONE; } - unsigned int *data = PyLong_AsVoidPtr(l), offset; - for(unsigned int i = starty * self->columns + startx; i <= endy * self->columns + endx; i++) { - offset = DATA_CELL_SIZE * i; - data[offset + 3] = fg; - data[offset + 4] = bg; - } + float *data = PyLong_AsVoidPtr(l); + memset(data, 0, size * sizeof(float)); + end = endy * self->columns + endx; + i = starty * self->columns + startx; + if (i != end) { for(; i <= end; i++) data[i] = 1; } Py_RETURN_NONE; }