From fe3e51a00d85b0703b983aa2c06b8eb43add6d23 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 21 Aug 2017 16:39:34 +0530 Subject: [PATCH] Move the GLSL shaders into their own files --- kitty/boss.py | 3 +- kitty/cell_fragment.glsl | 26 +++++++ kitty/cell_vertex.glsl | 63 +++++++++++++++++ kitty/char_grid.py | 138 ++----------------------------------- kitty/cursor_fragment.glsl | 6 ++ kitty/cursor_vertex.glsl | 16 +++++ kitty/shaders.py | 9 +++ setup.py | 2 +- 8 files changed, 130 insertions(+), 133 deletions(-) create mode 100644 kitty/cell_fragment.glsl create mode 100644 kitty/cell_vertex.glsl create mode 100644 kitty/cursor_fragment.glsl create mode 100644 kitty/cursor_vertex.glsl diff --git a/kitty/boss.py b/kitty/boss.py index ca609423b..c71c5cc74 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -26,7 +26,7 @@ from .fast_data_types import ( ) from .fonts.render import set_font_family from .borders import BordersProgram -from .char_grid import cursor_shader, cell_shader +from .char_grid import load_shader_programs from .constants import is_key_pressed from .keys import interpret_text_event, interpret_key_event, get_shortcut, get_sent_data from .session import create_session @@ -100,6 +100,7 @@ class Boss(Thread): glfw_window.window_focus_callback = self.on_focus self.tab_manager = TabManager(opts, args, startup_session) self.sprites = Sprites() + cell_shader, cursor_shader = load_shader_programs() self.cell_program = ShaderProgram(*cell_shader) self.cursor_program = ShaderProgram(*cursor_shader) self.borders_program = BordersProgram() diff --git a/kitty/cell_fragment.glsl b/kitty/cell_fragment.glsl new file mode 100644 index 000000000..9decc0451 --- /dev/null +++ b/kitty/cell_fragment.glsl @@ -0,0 +1,26 @@ +uniform sampler2DArray sprites; +in vec3 sprite_pos; +in vec3 underline_pos; +in vec3 strike_pos; +in vec3 foreground; +in vec3 background; +in vec3 decoration_fg; +out vec4 final_color; + +vec3 blend(float alpha, vec3 over, vec3 under) { + return over + (1 - alpha) * under; +} + +void main() { + float text_alpha = texture(sprites, sprite_pos).r; + float underline_alpha = texture(sprites, underline_pos).r; + float strike_alpha = texture(sprites, strike_pos).r; + vec3 underline = underline_alpha * decoration_fg; + vec3 strike = strike_alpha * foreground; + vec3 fg = text_alpha * foreground; + vec3 decoration = blend(underline_alpha, underline, strike); + vec3 combined_fg = blend(text_alpha, fg, decoration); + float combined_alpha = max(max(underline_alpha, strike_alpha), text_alpha); + final_color = vec4(blend(combined_alpha, combined_fg, background), 1); +} + diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl new file mode 100644 index 000000000..d7845141d --- /dev/null +++ b/kitty/cell_vertex.glsl @@ -0,0 +1,63 @@ +uniform uvec2 dimensions; // xnum, ynum +uniform vec4 steps; // xstart, ystart, dx, dy +uniform vec2 sprite_layout; // dx, dy +uniform usamplerBuffer sprite_map; // gl_InstanceID -> x, y, z +uniform ivec2 color_indices; // which color to use as fg and which as bg +out vec3 sprite_pos; +out vec3 underline_pos; +out vec3 strike_pos; +out vec3 foreground; +out vec3 background; +out vec3 decoration_fg; + +const uvec2 pos_map[] = uvec2[4]( + uvec2(1, 0), // right, top + uvec2(1, 1), // right, bottom + uvec2(0, 1), // left, bottom + uvec2(0, 0) // left, top +); + +const uint BYTE_MASK = uint(255); +const uint ZERO = uint(0); +const uint SMASK = uint(3); + +vec3 to_color(uint c) { + uint r, g, b; + r = (c >> 16) & BYTE_MASK; + g = (c >> 8) & BYTE_MASK; + b = c & BYTE_MASK; + return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0); +} + +vec3 to_sprite_pos(uvec2 pos, uint x, uint y, uint z) { + vec2 s_xpos = vec2(x, float(x) + 1.0) * sprite_layout[0]; + vec2 s_ypos = vec2(y, float(y) + 1.0) * sprite_layout[1]; + return vec3(s_xpos[pos[0]], s_ypos[pos[1]], z); +} + +void main() { + uint instance_id = uint(gl_InstanceID); + uint r = instance_id / dimensions[0]; + uint c = instance_id - r * dimensions[0]; + float left = steps[0] + c * steps[2]; + float top = steps[1] - r * steps[3]; + vec2 xpos = vec2(left, left + steps[2]); + vec2 ypos = vec2(top, top - steps[3]); + uvec2 pos = pos_map[gl_VertexID]; + gl_Position = vec4(xpos[pos[0]], ypos[pos[1]], 0, 1); + + int sprite_id = gl_InstanceID * STRIDE; + uint x = texelFetch(sprite_map, sprite_id).r; + uint y = texelFetch(sprite_map, sprite_id + 1).r; + uint z = texelFetch(sprite_map, sprite_id + 2).r; + sprite_pos = to_sprite_pos(pos, x, y, z); + sprite_id += 3; + uint fg = texelFetch(sprite_map, sprite_id + color_indices[0]).r; + uint bg = texelFetch(sprite_map, sprite_id + color_indices[1]).r; + uint decoration = texelFetch(sprite_map, sprite_id + 2).r; + foreground = to_color(fg); + background = to_color(bg); + decoration_fg = to_color(decoration); + underline_pos = to_sprite_pos(pos, (decoration >> 24) & SMASK, ZERO, ZERO); + strike_pos = to_sprite_pos(pos, (decoration >> 26) & SMASK, ZERO, ZERO); +} diff --git a/kitty/char_grid.py b/kitty/char_grid.py index e8e14773f..7cb14c869 100644 --- a/kitty/char_grid.py +++ b/kitty/char_grid.py @@ -20,6 +20,7 @@ from .fast_data_types import ( glUniform4f, glUniform2i ) from .rgb import to_color +from .shaders import load_shaders from .utils import ( color_as_int, color_from_int, get_logical_dpi, open_url, safe_print, set_primary_selection @@ -32,137 +33,12 @@ class DynamicColor(Enum): default_fg, default_bg, cursor_color, highlight_fg, highlight_bg = range(1, 6) -if DATA_CELL_SIZE % 3: - raise ValueError('Incorrect data cell size, must be a multiple of 3') - - -# cell shader {{{ - -cell_shader = ( - '''\ -uniform uvec2 dimensions; // xnum, ynum -uniform vec4 steps; // xstart, ystart, dx, dy -uniform vec2 sprite_layout; // dx, dy -uniform usamplerBuffer sprite_map; // gl_InstanceID -> x, y, z -uniform ivec2 color_indices; // which color to use as fg and which as bg -out vec3 sprite_pos; -out vec3 underline_pos; -out vec3 strike_pos; -out vec3 foreground; -out vec3 background; -out vec3 decoration_fg; - -const uvec2 pos_map[] = uvec2[4]( - uvec2(1, 0), // right, top - uvec2(1, 1), // right, bottom - uvec2(0, 1), // left, bottom - uvec2(0, 0) // left, top -); - -const uint BYTE_MASK = uint(255); -const uint ZERO = uint(0); -const uint SMASK = uint(3); - -vec3 to_color(uint c) { - uint r, g, b; - r = (c >> 16) & BYTE_MASK; - g = (c >> 8) & BYTE_MASK; - b = c & BYTE_MASK; - return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0); -} - -vec3 to_sprite_pos(uvec2 pos, uint x, uint y, uint z) { - vec2 s_xpos = vec2(x, float(x) + 1.0) * sprite_layout[0]; - vec2 s_ypos = vec2(y, float(y) + 1.0) * sprite_layout[1]; - return vec3(s_xpos[pos[0]], s_ypos[pos[1]], z); -} - -void main() { - uint instance_id = uint(gl_InstanceID); - uint r = instance_id / dimensions[0]; - uint c = instance_id - r * dimensions[0]; - float left = steps[0] + c * steps[2]; - float top = steps[1] - r * steps[3]; - vec2 xpos = vec2(left, left + steps[2]); - vec2 ypos = vec2(top, top - steps[3]); - uvec2 pos = pos_map[gl_VertexID]; - gl_Position = vec4(xpos[pos[0]], ypos[pos[1]], 0, 1); - - int sprite_id = gl_InstanceID * STRIDE; - uint x = texelFetch(sprite_map, sprite_id).r; - uint y = texelFetch(sprite_map, sprite_id + 1).r; - uint z = texelFetch(sprite_map, sprite_id + 2).r; - sprite_pos = to_sprite_pos(pos, x, y, z); - sprite_id += 3; - uint fg = texelFetch(sprite_map, sprite_id + color_indices[0]).r; - uint bg = texelFetch(sprite_map, sprite_id + color_indices[1]).r; - uint decoration = texelFetch(sprite_map, sprite_id + 2).r; - foreground = to_color(fg); - background = to_color(bg); - decoration_fg = to_color(decoration); - underline_pos = to_sprite_pos(pos, (decoration >> 24) & SMASK, ZERO, ZERO); - strike_pos = to_sprite_pos(pos, (decoration >> 26) & SMASK, ZERO, ZERO); -} -'''.replace('STRIDE', str(DATA_CELL_SIZE)), - - '''\ -uniform sampler2DArray sprites; -in vec3 sprite_pos; -in vec3 underline_pos; -in vec3 strike_pos; -in vec3 foreground; -in vec3 background; -in vec3 decoration_fg; -out vec4 final_color; - -vec3 blend(float alpha, vec3 over, vec3 under) { - return over + (1 - alpha) * under; -} - -void main() { - float text_alpha = texture(sprites, sprite_pos).r; - float underline_alpha = texture(sprites, underline_pos).r; - float strike_alpha = texture(sprites, strike_pos).r; - vec3 underline = underline_alpha * decoration_fg; - vec3 strike = strike_alpha * foreground; - vec3 fg = text_alpha * foreground; - vec3 decoration = blend(underline_alpha, underline, strike); - vec3 combined_fg = blend(text_alpha, fg, decoration); - float combined_alpha = max(max(underline_alpha, strike_alpha), text_alpha); - final_color = vec4(blend(combined_alpha, combined_fg, background), 1); -} -''') -# }}} - -# cursor shader {{{ - -cursor_shader = ( - '''\ -uniform vec2 xpos; -uniform vec2 ypos; - -const uvec2 pos_map[] = uvec2[4]( - uvec2(1, 0), // right, top - uvec2(1, 1), // right, bottom - uvec2(0, 1), // left, bottom - uvec2(0, 0) // left, top -); - -void main() { - uvec2 pos = pos_map[gl_VertexID]; - gl_Position = vec4(xpos[pos[0]], ypos[pos[1]], 0, 1); -} -''', - - '''\ -uniform vec4 color; -out vec4 final_color; - -void main() { - final_color = color; -} -''') -# }}} +def load_shader_programs(): + vert, frag = load_shaders('cell') + vert = vert.replace('STRIDE', str(DATA_CELL_SIZE)) + cell = vert, frag + cursor = load_shaders('cursor') + return cell, cursor class Selection: # {{{ diff --git a/kitty/cursor_fragment.glsl b/kitty/cursor_fragment.glsl new file mode 100644 index 000000000..007e3cf62 --- /dev/null +++ b/kitty/cursor_fragment.glsl @@ -0,0 +1,6 @@ +uniform vec4 color; +out vec4 final_color; + +void main() { + final_color = color; +} diff --git a/kitty/cursor_vertex.glsl b/kitty/cursor_vertex.glsl new file mode 100644 index 000000000..a71a404b5 --- /dev/null +++ b/kitty/cursor_vertex.glsl @@ -0,0 +1,16 @@ +uniform vec2 xpos; +uniform vec2 ypos; + +const uvec2 pos_map[] = uvec2[4]( + uvec2(1, 0), // right, top + uvec2(1, 1), // right, bottom + uvec2(0, 1), // left, bottom + uvec2(0, 0) // left, top +); + +void main() { + uvec2 pos = pos_map[gl_VertexID]; + gl_Position = vec4(xpos[pos[0]], ypos[pos[1]], 0, 1); +} + + diff --git a/kitty/shaders.py b/kitty/shaders.py index 9ff66a973..9a1b1e10c 100644 --- a/kitty/shaders.py +++ b/kitty/shaders.py @@ -2,6 +2,7 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2016, Kovid Goyal +import os import sys from ctypes import addressof, sizeof from functools import lru_cache @@ -33,6 +34,14 @@ GL_VERSION = (3, 3) VERSION = GL_VERSION[0] * 100 + GL_VERSION[1] * 10 ITALIC_MASK = 1 << ITALIC BOLD_MASK = 1 << BOLD +BASE = os.path.dirname(os.path.abspath(__file__)) + + +@lru_cache() +def load_shaders(name): + vert = open(os.path.join(BASE, '{}_vertex.glsl'.format(name))).read() + frag = open(os.path.join(BASE, '{}_fragment.glsl'.format(name))).read() + return vert, frag class Sprites: diff --git a/setup.py b/setup.py index e61b35b59..1e82f70fe 100755 --- a/setup.py +++ b/setup.py @@ -319,7 +319,7 @@ def package(args, for_bundle=False): # {{{ def src_ignore(parent, entries): return [ x for x in entries - if '.' in x and x.rpartition('.')[2] not in ('py', 'so', 'conf') + if '.' in x and x.rpartition('.')[2] not in ('py', 'so', 'conf', 'glsl') ] shutil.copytree('kitty', os.path.join(libdir, 'kitty'), ignore=src_ignore)