Rendering of underline/strikethrough
This commit is contained in:
parent
e53c3076ef
commit
aca53d4e2b
@ -23,6 +23,9 @@ Size = namedtuple('Size', 'width height')
|
||||
Cursor = namedtuple('Cursor', 'x y hidden shape color blink')
|
||||
ScreenGeometry = namedtuple('ScreenGeometry', 'xstart ystart xnum ynum dx dy')
|
||||
|
||||
if DATA_CELL_SIZE % 3:
|
||||
raise ValueError('Incorrect data cell size, must be a multiple of 3')
|
||||
|
||||
# cell shader {{{
|
||||
|
||||
cell_shader = (
|
||||
@ -32,8 +35,11 @@ uniform vec4 steps; // xstart, ystart, dx, dy
|
||||
uniform vec2 sprite_layout; // dx, dy
|
||||
uniform usamplerBuffer sprite_map; // gl_InstanceID -> x, y, z
|
||||
out vec3 sprite_pos;
|
||||
out vec4 foreground;
|
||||
out vec4 background;
|
||||
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
|
||||
@ -42,12 +48,22 @@ const uvec2 pos_map[] = uvec2[4](
|
||||
uvec2(0, 0) // left, top
|
||||
);
|
||||
|
||||
vec4 to_color(uint c) {
|
||||
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) & uint(255);
|
||||
g = (c >> 8) & uint(255);
|
||||
b = c & uint(255);
|
||||
return vec4(r / 255.0, g / 255.0, b / 255.0, 1);
|
||||
r = (c >> 16) & BYTE_MASK;
|
||||
g = (c >> 8) & BYTE_MASK;
|
||||
b = c & BYTE_MASK;
|
||||
return vec3(r / 255.0, g / 255.0, b / 255.0);
|
||||
}
|
||||
|
||||
vec3 to_sprite_pos(uvec2 pos, uint x, uint y, uint z) {
|
||||
vec2 s_xpos = vec2(x, x + 1.0) * sprite_layout[0];
|
||||
vec2 s_ypos = vec2(y, y + 1.0) * sprite_layout[1];
|
||||
return vec3(s_xpos[pos[0]], s_ypos[pos[1]], z);
|
||||
}
|
||||
|
||||
void main() {
|
||||
@ -61,27 +77,44 @@ void main() {
|
||||
uvec2 pos = pos_map[gl_VertexID];
|
||||
gl_Position = vec4(xpos[pos[0]], ypos[pos[1]], 0, 1);
|
||||
|
||||
int sprite_id = int(instance_id) * 3;
|
||||
int sprite_id = int(instance_id) * STRIDE;
|
||||
uvec4 spos = texelFetch(sprite_map, sprite_id);
|
||||
vec2 s_xpos = vec2(spos[0], spos[0] + 1.0) * sprite_layout[0];
|
||||
vec2 s_ypos = vec2(spos[1], spos[1] + 1.0) * sprite_layout[1];
|
||||
sprite_pos = vec3(s_xpos[pos[0]], s_ypos[pos[1]], spos[2]);
|
||||
uvec4 colors = texelFetch(sprite_map, sprite_id + 1);
|
||||
sprite_pos = to_sprite_pos(pos, spos[0], spos[1], spos[2]);
|
||||
foreground = to_color(colors[0]);
|
||||
background = to_color(colors[1]);
|
||||
uint decoration = colors[2];
|
||||
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 // 3)),
|
||||
|
||||
'''\
|
||||
uniform sampler2DArray sprites;
|
||||
in vec3 sprite_pos;
|
||||
in vec4 foreground;
|
||||
in vec4 background;
|
||||
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 alpha = texture(sprites, sprite_pos).r;
|
||||
final_color = background * (1 - alpha) + foreground * alpha;
|
||||
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);
|
||||
}
|
||||
''')
|
||||
# }}}
|
||||
|
||||
@ -22,13 +22,15 @@ typedef uint32_t decoration_type;
|
||||
typedef uint32_t combining_type;
|
||||
typedef unsigned int index_type;
|
||||
#define CELL_SIZE (sizeof(char_type) + sizeof(color_type) + sizeof(decoration_type) + sizeof(combining_type))
|
||||
#define DATA_CELL_SIZE 9
|
||||
// The data cell size must be a multiple of 3
|
||||
#define DATA_CELL_SIZE 2 * 3
|
||||
|
||||
#define CHAR_MASK 0xFFFFFF
|
||||
#define ATTRS_SHIFT 24
|
||||
#define ATTRS_MASK_WITHOUT_WIDTH 0xFC000000
|
||||
#define WIDTH_MASK 3
|
||||
#define DECORATION_SHIFT 2
|
||||
#define DECORATION_MASK 3
|
||||
#define BOLD_SHIFT 4
|
||||
#define ITALIC_SHIFT 5
|
||||
#define REVERSE_SHIFT 6
|
||||
|
||||
@ -66,6 +66,8 @@ class Renderer:
|
||||
fg, bg = self.color_pairs[i % 3]
|
||||
c.fg = (fg << 8) | 3
|
||||
c.bg = (bg << 8) | 3
|
||||
c.decoration = 2
|
||||
c.strikethrough = True
|
||||
c.x = x
|
||||
line.set_text('%d' % (i % 10), 0, 1, c)
|
||||
self.sprites.backend.update_cell_data(line, 0, sg.xnum - 1, self.color_profile, 0xffffff, 0, ctypes.addressof(data))
|
||||
|
||||
@ -249,7 +249,7 @@ def add_curl(buf, position, thickness):
|
||||
buf[offset + x] = 255
|
||||
|
||||
|
||||
def render_cell(text=' ', bold=False, italic=False, underline=0, strikeout=False):
|
||||
def render_cell(text=' ', bold=False, italic=False, underline=0, strikethrough=False):
|
||||
# TODO: Handle non-normalizable combining chars. Probably need to use
|
||||
# harfbuzz for that
|
||||
text = unicodedata.normalize('NFC', text)[0]
|
||||
@ -272,7 +272,7 @@ def render_cell(text=' ', bold=False, italic=False, underline=0, strikeout=False
|
||||
if underline == 2:
|
||||
t = min(cell_height - underline_position - 1, t)
|
||||
dl(add_curl if underline == 2 else add_line, underline_position, t)
|
||||
if strikeout:
|
||||
if strikethrough:
|
||||
pos = int(0.65 * baseline)
|
||||
dl(add_line, pos, underline_thickness)
|
||||
return first, second
|
||||
@ -315,7 +315,7 @@ def test_rendering(text='\'Ping👁a⧽', sz=144, family='Ubuntu Mono for Kov
|
||||
set_font_family(family, sz)
|
||||
cells = []
|
||||
for c in text:
|
||||
f, s = render_cell(c, underline=2, strikeout=True)
|
||||
f, s = render_cell(c, underline=2, strikethrough=True)
|
||||
cells.append(f)
|
||||
if s is not None:
|
||||
cells.append(s)
|
||||
|
||||
@ -1045,7 +1045,6 @@ set_scroll_cell_data(Screen *self, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args, "O!O!O!kkIO", &SpriteMap_Type, &spm, &ColorProfile_Type, &color_profile, &PyLong_Type, &sp, &default_fg, &default_bg, &scrolled_by, &dp)) return NULL;
|
||||
data = PyLong_AsVoidPtr(dp);
|
||||
src = PyLong_AsVoidPtr(sp);
|
||||
unsigned int line_size = 9 * self->columns;
|
||||
|
||||
scrolled_by = MIN(self->historybuf->count, scrolled_by);
|
||||
|
||||
@ -1056,6 +1055,7 @@ set_scroll_cell_data(Screen *self, PyObject *args) {
|
||||
}
|
||||
if (scrolled_by < self->lines) {
|
||||
// Less than a full screen has been scrolled, copy some lines from the screen buffer to the scroll buffer
|
||||
unsigned int line_size = DATA_CELL_SIZE * self->columns;
|
||||
index_type num_to_copy = self->lines - scrolled_by;
|
||||
index_type offset = line_size * scrolled_by;
|
||||
memcpy(data + offset, src, line_size * num_to_copy * sizeof(unsigned int));
|
||||
|
||||
@ -69,10 +69,8 @@ class Sprites:
|
||||
|
||||
send() # blank
|
||||
send(underline=1)
|
||||
send(strikeout=True)
|
||||
send(underline=1, strikeout=True)
|
||||
send(underline=2)
|
||||
if send(underline=2, strikeout=True) != 5:
|
||||
if send(strikethrough=True) != 3:
|
||||
raise RuntimeError('Available OpenGL texture size is too small')
|
||||
|
||||
@property
|
||||
|
||||
@ -139,7 +139,6 @@ position_for(SpriteMap *self, PyObject *args) {
|
||||
return Py_BuildValue("III", pos->x, pos->y, pos->z);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
update_cell_range_data(SpriteMap *self, Line *line, unsigned int xstart, unsigned int xmax, ColorProfile *color_profile, const uint32_t default_bg, const uint32_t default_fg, unsigned int *data) {
|
||||
SpritePosition *sp;
|
||||
@ -153,13 +152,17 @@ update_cell_range_data(SpriteMap *self, Line *line, unsigned int xstart, unsigne
|
||||
if (previous_width == 2) sp = sprite_position_for(self, previous_ch, 0, true, &err);
|
||||
else sp = sprite_position_for(self, ch, line->combining_chars[i], false, &err);
|
||||
if (sp == NULL) { set_sprite_error(err); return false; }
|
||||
char_type attrs = ch >> ATTRS_SHIFT;
|
||||
unsigned int decoration = (attrs >> DECORATION_SHIFT) & DECORATION_MASK;
|
||||
unsigned int strikethrough = ((attrs >> STRIKE_SHIFT) & 1) ? 3 : 0;
|
||||
data[offset] = sp->x;
|
||||
data[offset+1] = sp->y;
|
||||
data[offset+2] = sp->z;
|
||||
data[offset+3] = to_color(color_profile, line->colors[i] & COL_MASK, default_fg);
|
||||
data[offset+4] = to_color(color_profile, line->colors[i] >> COL_SHIFT, default_bg);
|
||||
data[offset+5] = to_color(color_profile, line->decoration_fg[i] & COL_MASK, default_fg);
|
||||
previous_ch = ch; previous_width = (ch >> ATTRS_SHIFT) & WIDTH_MASK;
|
||||
unsigned int decoration_fg = decoration > 1 ? to_color(color_profile, line->decoration_fg[i] & COL_MASK, data[offset+3]) : data[offset+3];
|
||||
data[offset+5] = (decoration_fg & COL_MASK) | (decoration << 24) | (strikethrough << 26);
|
||||
previous_ch = ch; previous_width = (attrs) & WIDTH_MASK;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user