Move the text attributes out of the char type
This means that more text attributes can be added in the future (there are 8 bits available) and there is no need to keep bit twiddling when accessing the chars themselves. Also means less data needs to be sent to the GPU. Cell size does not change since there were currently 2 unused bytes because of alignment.
This commit is contained in:
parent
85ed5c1515
commit
a92b3c605f
@ -9,8 +9,7 @@ uniform uvec4 url_range; // The range for the currently highlighted URL (start_x
|
||||
uniform ColorTable {
|
||||
uint color_table[256]; // The color table
|
||||
};
|
||||
in uint text_attrs;
|
||||
in uvec3 sprite_coords;
|
||||
in uvec4 sprite_coords;
|
||||
in uvec3 colors;
|
||||
in float is_selected;
|
||||
out vec3 sprite_pos;
|
||||
@ -95,7 +94,8 @@ void main() {
|
||||
gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1);
|
||||
|
||||
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & SHORT_MASK);
|
||||
uint reverse = (text_attrs >> 30) & STRIKE_MASK;
|
||||
uint text_attrs = sprite_coords[3];
|
||||
uint reverse = (text_attrs >> 6) & STRIKE_MASK;
|
||||
uint fg = colors[color_indices[reverse]];
|
||||
uint bg = colors[color_indices[ONE - reverse]];
|
||||
uint resolved_fg = as_color(fg, default_colors[color_indices[0]]);
|
||||
@ -103,6 +103,6 @@ void main() {
|
||||
background = apply_selection(to_color(bg, default_colors[color_indices[1]]), default_colors[3]);
|
||||
float in_url = in_range(url_range, c, r);
|
||||
decoration_fg = mix_vecs(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
|
||||
underline_pos = mix_vecs(in_url, to_sprite_pos(pos, TWO, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 26) & DECORATION_MASK, ZERO, ZERO));
|
||||
strike_pos = to_sprite_pos(pos, ((text_attrs >> 31) & STRIKE_MASK) * THREE, ZERO, ZERO);
|
||||
underline_pos = mix_vecs(in_url, to_sprite_pos(pos, TWO, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 2) & DECORATION_MASK, ZERO, ZERO));
|
||||
strike_pos = to_sprite_pos(pos, ((text_attrs >> 7) & STRIKE_MASK) * THREE, ZERO, ZERO);
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ typedef uint32_t color_type;
|
||||
typedef uint32_t combining_type;
|
||||
typedef unsigned int index_type;
|
||||
typedef uint16_t sprite_index;
|
||||
typedef uint16_t attrs_type;
|
||||
typedef enum CursorShapes { NO_CURSOR_SHAPE, CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE, NUM_OF_CURSOR_SHAPES } CursorShape;
|
||||
|
||||
#define ERROR_PREFIX "[PARSE ERROR]"
|
||||
@ -38,15 +39,12 @@ typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
|
||||
|
||||
#define MAX_CHILDREN 256
|
||||
#define BLANK_CHAR 0
|
||||
#define CHAR_MASK 0xFFFFFF
|
||||
#define ATTRS_SHIFT 24
|
||||
#define ATTRS_MASK_WITHOUT_WIDTH 0xFC000000
|
||||
#define ATTRS_MASK_WITHOUT_WIDTH 0xFFC
|
||||
#define WIDTH_MASK 3
|
||||
#define DECORATION_SHIFT 2
|
||||
#define DECORATION_MASK 3
|
||||
#define BOLD_SHIFT 4
|
||||
#define ITALIC_SHIFT 5
|
||||
#define POSCHAR_MASK 0x30FFFFFF
|
||||
#define REVERSE_SHIFT 6
|
||||
#define STRIKE_SHIFT 7
|
||||
#define COL_MASK 0xFFFFFFFF
|
||||
@ -56,14 +54,14 @@ typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
|
||||
#define UTF8_REJECT 1
|
||||
#define UNDERCURL_CODE 6
|
||||
#define DECORATION_FG_CODE 58
|
||||
#define CHAR_IS_BLANK(ch) ((ch & CHAR_MASK) == 32 || (ch & CHAR_MASK) == 0)
|
||||
#define CHAR_IS_BLANK(ch) ((ch) == 32 || (ch) == 0)
|
||||
|
||||
#define FG 1
|
||||
#define BG 2
|
||||
|
||||
#define CURSOR_TO_ATTRS(c, w) \
|
||||
((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \
|
||||
((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | ((c->strikethrough & 1) << STRIKE_SHIFT))) << ATTRS_SHIFT
|
||||
((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | ((c->strikethrough & 1) << STRIKE_SHIFT)))
|
||||
|
||||
#define ATTRS_TO_CURSOR(a, c) \
|
||||
c->decoration = (a >> DECORATION_SHIFT) & 3; c->bold = (a >> BOLD_SHIFT) & 1; c->italic = (a >> ITALIC_SHIFT) & 1; \
|
||||
@ -126,6 +124,7 @@ typedef struct {
|
||||
color_type fg, bg, decoration_fg;
|
||||
combining_type cc;
|
||||
sprite_index sprite_x, sprite_y, sprite_z;
|
||||
attrs_type attrs;
|
||||
} Cell;
|
||||
|
||||
typedef struct {
|
||||
@ -280,8 +279,9 @@ PyTypeObject ChildMonitor_Type;
|
||||
for(index_type __i__ = (at); __i__ < (line)->xnum - (num); __i__++) { \
|
||||
COPY_CELL(line, __i__ + (num), line, __i__) \
|
||||
} \
|
||||
if ((((line)->cells[(at)].ch >> ATTRS_SHIFT) & WIDTH_MASK) != 1) { \
|
||||
(line)->cells[(at)].ch = (1 << ATTRS_SHIFT) | BLANK_CHAR; \
|
||||
if ((((line)->cells[(at)].attrs) & WIDTH_MASK) != 1) { \
|
||||
(line)->cells[(at)].ch = BLANK_CHAR; \
|
||||
(line)->cells[(at)].attrs = BLANK_CHAR ? 1 : 0; \
|
||||
clear_sprite_position((line)->cells[(at)]); \
|
||||
}
|
||||
|
||||
|
||||
@ -116,7 +116,7 @@ line(LineBuf *self, PyObject *y) {
|
||||
|
||||
unsigned int
|
||||
linebuf_char_width_at(LineBuf *self, index_type x, index_type y) {
|
||||
return (lineptr(self, self->line_map[y])[x].ch >> ATTRS_SHIFT) & WIDTH_MASK;
|
||||
return (lineptr(self, self->line_map[y])[x].attrs) & WIDTH_MASK;
|
||||
}
|
||||
|
||||
void
|
||||
@ -453,7 +453,7 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, HistoryBuf *his
|
||||
for (first = self->ynum - 1; true; first--) {
|
||||
Cell *cells = lineptr(self, first);
|
||||
for(i = 0; i < self->xnum; i++) {
|
||||
if ((cells[i].ch & CHAR_MASK) != BLANK_CHAR) { is_empty = false; break; }
|
||||
if ((cells[i].ch) != BLANK_CHAR) { is_empty = false; break; }
|
||||
}
|
||||
if (!is_empty || !first) break;
|
||||
}
|
||||
|
||||
56
kitty/line.c
56
kitty/line.c
@ -27,7 +27,7 @@ unsigned int
|
||||
line_length(Line *self) {
|
||||
index_type last = self->xnum - 1;
|
||||
for (index_type i = 0; i < self->xnum; i++) {
|
||||
if ((self->cells[last - i].ch & CHAR_MASK) != BLANK_CHAR) return self->xnum - i;
|
||||
if ((self->cells[last - i].ch) != BLANK_CHAR) return self->xnum - i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -68,7 +68,7 @@ find_colon_slash(Line *self, index_type x, index_type limit) {
|
||||
limit = MAX(2, limit);
|
||||
if (pos < limit) return 0;
|
||||
do {
|
||||
char_type ch = self->cells[pos].ch & CHAR_MASK;
|
||||
char_type ch = self->cells[pos].ch;
|
||||
if (!is_url_char(ch)) return false;
|
||||
switch(state) {
|
||||
case ANY:
|
||||
@ -92,7 +92,7 @@ prefix_matches(Line *self, index_type at, const char* prefix, index_type prefix_
|
||||
if (prefix_len > at) return false;
|
||||
index_type p, i;
|
||||
for (p = at - prefix_len, i = 0; i < prefix_len && p < self->xnum; i++, p++) {
|
||||
if ((self->cells[p].ch & CHAR_MASK) != (unsigned char)prefix[i]) return false;
|
||||
if ((self->cells[p].ch) != (unsigned char)prefix[i]) return false;
|
||||
}
|
||||
return i == prefix_len;
|
||||
}
|
||||
@ -117,7 +117,7 @@ static inline bool
|
||||
has_url_beyond(Line *self, index_type x) {
|
||||
if (self->xnum <= x + MIN_URL_LEN + 3) return false;
|
||||
for (index_type i = x; i < MIN(x + MIN_URL_LEN + 3, self->xnum); i++) {
|
||||
if (!is_url_char(self->cells[i].ch & CHAR_MASK)) return false;
|
||||
if (!is_url_char(self->cells[i].ch)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -143,9 +143,9 @@ index_type
|
||||
line_url_end_at(Line *self, index_type x) {
|
||||
index_type ans = x;
|
||||
if (x >= self->xnum || self->xnum <= MIN_URL_LEN + 3) return 0;
|
||||
while (ans < self->xnum && is_url_char(self->cells[ans].ch & CHAR_MASK)) ans++;
|
||||
while (ans < self->xnum && is_url_char(self->cells[ans].ch)) ans++;
|
||||
ans--;
|
||||
while (ans > x && can_strip_from_end_of_url(self->cells[ans].ch & CHAR_MASK)) ans--;
|
||||
while (ans > x && can_strip_from_end_of_url(self->cells[ans].ch)) ans--;
|
||||
return ans;
|
||||
}
|
||||
|
||||
@ -167,7 +167,7 @@ static PyObject*
|
||||
text_at(Line* self, Py_ssize_t xval) {
|
||||
#define text_at_doc "[x] -> Return the text in the specified cell"
|
||||
if (xval >= self->xnum) { PyErr_SetString(PyExc_IndexError, "Column number out of bounds"); return NULL; }
|
||||
return line_text_at(self->cells[xval].ch & CHAR_MASK, self->cells[xval].cc);
|
||||
return line_text_at(self->cells[xval].ch, self->cells[xval].cc);
|
||||
}
|
||||
|
||||
PyObject*
|
||||
@ -177,7 +177,7 @@ unicode_in_range(Line *self, index_type start, index_type limit, bool include_cc
|
||||
if (leading_char) buf[n++] = leading_char;
|
||||
char_type previous_width = 0;
|
||||
for(index_type i = start; i < limit && n < sizeof(buf)/sizeof(buf[0]) - 4; i++) {
|
||||
char_type ch = self->cells[i].ch & CHAR_MASK;
|
||||
char_type ch = self->cells[i].ch;
|
||||
if (ch == 0) {
|
||||
if (previous_width == 2) { previous_width = 0; continue; };
|
||||
ch = ' ';
|
||||
@ -192,7 +192,7 @@ unicode_in_range(Line *self, index_type start, index_type limit, bool include_cc
|
||||
if (cc2) buf[n++] = cc2;
|
||||
}
|
||||
}
|
||||
previous_width = (self->cells[i].ch >> ATTRS_SHIFT) & WIDTH_MASK;
|
||||
previous_width = self->cells[i].attrs & WIDTH_MASK;
|
||||
}
|
||||
return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, n);
|
||||
}
|
||||
@ -247,7 +247,7 @@ line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen) {
|
||||
|
||||
WRITE_SGR(0);
|
||||
for (index_type pos=0; pos < limit; pos++) {
|
||||
char_type attrs = self->cells[pos].ch >> ATTRS_SHIFT, ch = self->cells[pos].ch & CHAR_MASK;
|
||||
char_type attrs = self->cells[pos].attrs, ch = self->cells[pos].ch;
|
||||
if (ch == 0) {
|
||||
if (previous_width == 2) { previous_width = 0; continue; }
|
||||
ch = ' ';
|
||||
@ -319,7 +319,7 @@ width(Line *self, PyObject *val) {
|
||||
#define width_doc "width(x) -> the width of the character at x"
|
||||
unsigned long x = PyLong_AsUnsignedLong(val);
|
||||
if (x >= self->xnum) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; }
|
||||
char_type attrs = self->cells[x].ch >> ATTRS_SHIFT;
|
||||
char_type attrs = self->cells[x].attrs;
|
||||
return PyLong_FromUnsignedLong((unsigned long) (attrs & WIDTH_MASK));
|
||||
}
|
||||
|
||||
@ -375,7 +375,8 @@ set_text(Line* self, PyObject *args) {
|
||||
color_type dfg = cursor->decoration_fg & COL_MASK;
|
||||
|
||||
for (index_type i = cursor->x; offset < limit && i < self->xnum; i++, offset++) {
|
||||
self->cells[i].ch = (PyUnicode_READ(kind, buf, offset) & CHAR_MASK) | attrs;
|
||||
self->cells[i].ch = (PyUnicode_READ(kind, buf, offset));
|
||||
self->cells[i].attrs = attrs;
|
||||
self->cells[i].fg = fg;
|
||||
self->cells[i].bg = bg;
|
||||
self->cells[i].decoration_fg = dfg;
|
||||
@ -399,7 +400,7 @@ cursor_from(Line* self, PyObject *args) {
|
||||
ans = alloc_cursor();
|
||||
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
||||
ans->x = x; ans->y = y;
|
||||
char_type attrs = self->cells[x].ch >> ATTRS_SHIFT;
|
||||
char_type attrs = self->cells[x].attrs;
|
||||
ATTRS_TO_CURSOR(attrs, ans);
|
||||
ans->fg = self->cells[x].fg; ans->bg = self->cells[x].bg;
|
||||
ans->decoration_fg = self->cells[x].decoration_fg & COL_MASK;
|
||||
@ -408,12 +409,12 @@ cursor_from(Line* self, PyObject *args) {
|
||||
}
|
||||
|
||||
void
|
||||
line_clear_text(Line *self, unsigned int at, unsigned int num, int ch) {
|
||||
const char_type repl = ((char_type)ch & CHAR_MASK) | ( (ch ? 1 : 0) << ATTRS_SHIFT);
|
||||
line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch) {
|
||||
attrs_type width = ch ? 1 : 0;
|
||||
#define PREFIX \
|
||||
for (index_type i = at; i < MIN(self->xnum, at + num); i++) { \
|
||||
self->cells[i].ch = (self->cells[i].ch & ATTRS_MASK_WITHOUT_WIDTH) | repl; \
|
||||
self->cells[i].cc = 0;
|
||||
self->cells[i].ch = ch; self->cells[i].cc = 0; \
|
||||
self->cells[i].attrs = (self->cells[i].attrs & ATTRS_MASK_WITHOUT_WIDTH) | width;
|
||||
if (CHAR_IS_BLANK(ch)) {
|
||||
PREFIX
|
||||
clear_sprite_position(self->cells[i]); }
|
||||
@ -438,16 +439,17 @@ line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num,
|
||||
char_type attrs = CURSOR_TO_ATTRS(cursor, 1);
|
||||
color_type fg = (cursor->fg & COL_MASK), bg = (cursor->bg & COL_MASK);
|
||||
color_type dfg = cursor->decoration_fg & COL_MASK;
|
||||
if (!clear_char) attrs = ((attrs >> ATTRS_SHIFT) & ~WIDTH_MASK) << ATTRS_SHIFT;
|
||||
if (!clear_char) attrs = attrs & ATTRS_MASK_WITHOUT_WIDTH;
|
||||
|
||||
for (index_type i = at; i < self->xnum && i < at + num; i++) {
|
||||
if (clear_char) {
|
||||
self->cells[i].ch = BLANK_CHAR | attrs;
|
||||
self->cells[i].ch = BLANK_CHAR;
|
||||
self->cells[i].cc = 0;
|
||||
self->cells[i].attrs = attrs;
|
||||
clear_sprite_position(self->cells[i]);
|
||||
} else {
|
||||
char_type w = ((self->cells[i].ch >> ATTRS_SHIFT) & WIDTH_MASK) << ATTRS_SHIFT;
|
||||
self->cells[i].ch = (self->cells[i].ch & CHAR_MASK) | attrs | w;
|
||||
attrs_type w = self->cells[i].attrs & WIDTH_MASK;
|
||||
self->cells[i].attrs = attrs | w;
|
||||
set_sprite_position_at(i);
|
||||
}
|
||||
self->cells[i].fg = fg; self->cells[i].bg = bg;
|
||||
@ -471,9 +473,10 @@ void line_right_shift(Line *self, unsigned int at, unsigned int num) {
|
||||
COPY_SELF_CELL(i - num, i)
|
||||
}
|
||||
// Check if a wide character was split at the right edge
|
||||
char_type w = (self->cells[self->xnum - 1].ch >> ATTRS_SHIFT) & WIDTH_MASK;
|
||||
char_type w = (self->cells[self->xnum - 1].attrs) & WIDTH_MASK;
|
||||
if (w != 1) {
|
||||
self->cells[self->xnum - 1].ch = ((BLANK_CHAR ? 1 : 0) << ATTRS_SHIFT) | BLANK_CHAR;
|
||||
self->cells[self->xnum - 1].ch = BLANK_CHAR;
|
||||
self->cells[self->xnum - 1].attrs = BLANK_CHAR ? 1 : 0;
|
||||
clear_sprite_position(self->cells[self->xnum - 1]);
|
||||
}
|
||||
}
|
||||
@ -508,16 +511,15 @@ left_shift(Line *self, PyObject *args) {
|
||||
|
||||
void
|
||||
line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor, bool is_second) {
|
||||
char_type attrs;
|
||||
if (cursor == NULL) {
|
||||
attrs = (((self->cells[at].ch >> ATTRS_SHIFT) & ~WIDTH_MASK) | (width & WIDTH_MASK)) << ATTRS_SHIFT;
|
||||
self->cells[at].attrs = (self->cells[at].attrs & ATTRS_MASK_WITHOUT_WIDTH) | width;
|
||||
} else {
|
||||
attrs = CURSOR_TO_ATTRS(cursor, width & WIDTH_MASK);
|
||||
self->cells[at].attrs = CURSOR_TO_ATTRS(cursor, width & WIDTH_MASK);
|
||||
self->cells[at].fg = (cursor->fg & COL_MASK);
|
||||
self->cells[at].bg = (cursor->bg & COL_MASK);
|
||||
self->cells[at].decoration_fg = cursor->decoration_fg & COL_MASK;
|
||||
}
|
||||
self->cells[at].ch = (ch & CHAR_MASK) | attrs;
|
||||
self->cells[at].ch = ch;
|
||||
self->cells[at].cc = 0;
|
||||
if (!is_second && CHAR_IS_BLANK(ch)) { clear_sprite_position(self->cells[at]); }
|
||||
else set_sprite_position_at(at);
|
||||
|
||||
@ -22,10 +22,11 @@ update_sprites_in_line(Cell *cells, index_type xnum) {
|
||||
|
||||
static inline void
|
||||
set_attribute_on_line(Cell *cells, uint32_t shift, uint32_t val, index_type xnum) {
|
||||
uint32_t mask = shift == DECORATION_SHIFT ? 3 : 1;
|
||||
uint32_t aval = (val & mask) << (ATTRS_SHIFT + shift);
|
||||
mask = ~(mask << (ATTRS_SHIFT + shift));
|
||||
for (index_type i = 0; i < xnum; i++) cells[i].ch = (cells[i].ch & mask) | aval;
|
||||
// Set a single attribute on all cells in the line
|
||||
attrs_type mask = shift == DECORATION_SHIFT ? 3 : 1;
|
||||
attrs_type aval = (val & mask) << shift;
|
||||
mask = ~(mask << shift);
|
||||
for (index_type i = 0; i < xnum; i++) cells[i].attrs = (cells[i].attrs & mask) | aval;
|
||||
if (shift == BOLD_SHIFT || shift == ITALIC_SHIFT) update_sprites_in_line(cells, xnum);
|
||||
}
|
||||
|
||||
@ -42,21 +43,22 @@ copy_line(const Line *src, Line *dest) {
|
||||
static inline void
|
||||
clear_chars_in_line(Cell *cells, index_type xnum, char_type ch) {
|
||||
// Clear only the char part of each cell, the rest must have been cleared by a memset or similar
|
||||
char_type c = (1 << ATTRS_SHIFT) | ch;
|
||||
for (index_type i = 0; i < xnum; i++) cells[i].ch = c;
|
||||
if (ch) {
|
||||
for (index_type i = 0; i < xnum; i++) { cells[i].ch = ch; cells[i].attrs = 1; }
|
||||
}
|
||||
}
|
||||
|
||||
static inline index_type
|
||||
xlimit_for_line(Line *line) {
|
||||
index_type xlimit = line->xnum;
|
||||
if (BLANK_CHAR == 0) {
|
||||
while (xlimit > 0 && (line->cells[xlimit - 1].ch & CHAR_MASK) == BLANK_CHAR) xlimit--;
|
||||
while (xlimit > 0 && (line->cells[xlimit - 1].ch) == BLANK_CHAR) xlimit--;
|
||||
}
|
||||
return xlimit;
|
||||
}
|
||||
|
||||
PyObject* line_text_at(char_type, combining_type);
|
||||
void line_clear_text(Line *self, unsigned int at, unsigned int num, int ch);
|
||||
void line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch);
|
||||
void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char);
|
||||
void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, bool);
|
||||
void line_right_shift(Line *, unsigned int , unsigned int );
|
||||
|
||||
@ -59,7 +59,7 @@ rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf
|
||||
src_x_limit = src->xnum;
|
||||
if (!src_line_is_continued) {
|
||||
// Trim trailing blanks since there is a hard line break at the end of this line
|
||||
while(src_x_limit && (src->line->cells[src_x_limit - 1].ch & CHAR_MASK) == BLANK_CHAR) src_x_limit--;
|
||||
while(src_x_limit && (src->line->cells[src_x_limit - 1].ch) == BLANK_CHAR) src_x_limit--;
|
||||
|
||||
}
|
||||
while (src_x < src_x_limit) {
|
||||
|
||||
@ -1366,7 +1366,7 @@ screen_selection_range_for_word(Screen *self, index_type x, index_type y, index_
|
||||
if (y >= self->lines || x >= self->columns) return false;
|
||||
index_type start, end;
|
||||
Line *line = visual_line_(self, y);
|
||||
#define is_ok(x) (is_word_char((line->cells[x].ch) & CHAR_MASK) || is_opt_word_char(line->cells[x].ch & CHAR_MASK))
|
||||
#define is_ok(x) (is_word_char((line->cells[x].ch)) || is_opt_word_char(line->cells[x].ch))
|
||||
if (!is_ok(x)) {
|
||||
start = x; end = x + 1;
|
||||
} else {
|
||||
|
||||
@ -591,8 +591,7 @@ create_cell_vao() {
|
||||
#define A1(name, size, dtype, offset) A(name, size, dtype, (void*)(offsetof(Cell, offset)), sizeof(Cell))
|
||||
|
||||
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
|
||||
A1(text_attrs, 1, GL_UNSIGNED_INT, ch);
|
||||
A1(sprite_coords, 3, GL_UNSIGNED_SHORT, sprite_x);
|
||||
A1(sprite_coords, 4, GL_UNSIGNED_SHORT, sprite_x);
|
||||
A1(colors, 3, GL_UNSIGNED_INT, fg);
|
||||
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
|
||||
A(is_selected, 1, GL_FLOAT, NULL, 0);
|
||||
|
||||
@ -15,6 +15,7 @@ struct SpritePosition {
|
||||
sprite_index x, y, z;
|
||||
char_type ch;
|
||||
combining_type cc;
|
||||
bool bold, italic;
|
||||
bool is_second;
|
||||
bool filled;
|
||||
bool rendered;
|
||||
@ -88,15 +89,15 @@ do_increment(int *error) {
|
||||
}
|
||||
|
||||
SpritePosition*
|
||||
sprite_map_position_for(char_type ch, combining_type cc, bool is_second, int *error) {
|
||||
char_type pos_char = ch & POSCHAR_MASK; // Includes only the char and bold and italic bits
|
||||
unsigned int idx = ((ch >> (ATTRS_SHIFT - 4)) & 0x300) | (ch & 0xFF); // Includes only italic, bold and lowest byte of ch
|
||||
sprite_map_position_for(char_type ch, attrs_type attrs, combining_type cc, bool is_second, int *error) {
|
||||
uint8_t bold_italic = (attrs >> BOLD_SHIFT) & 3;
|
||||
unsigned int idx = (ch & 0xFF) | (bold_italic << 8); // Only bold italic bits and lowest byte of char
|
||||
SpritePosition *s = &(sprite_map.cache[idx]);
|
||||
// Optimize for the common case of an ASCII char already in the cache
|
||||
if (LIKELY(s->ch == pos_char && s->filled && s->cc == cc && s->is_second == is_second)) return s; // Cache hit
|
||||
if (LIKELY(s->ch == ch && s->filled && s->cc == cc && s->is_second == is_second)) return s; // Cache hit
|
||||
while(true) {
|
||||
if (s->filled) {
|
||||
if (s->ch == pos_char && s->cc == cc && s->is_second == is_second) return s; // Cache hit
|
||||
if (s->ch == ch && s->cc == cc && s->is_second == is_second) return s; // Cache hit
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -106,11 +107,13 @@ sprite_map_position_for(char_type ch, combining_type cc, bool is_second, int *er
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
s->ch = pos_char;
|
||||
s->ch = ch;
|
||||
s->cc = cc;
|
||||
s->is_second = is_second;
|
||||
s->filled = true;
|
||||
s->rendered = false;
|
||||
s->bold = bold_italic & 1;
|
||||
s->italic = bold_italic >> 1;
|
||||
s->x = sprite_map.x; s->y = sprite_map.y; s->z = sprite_map.z;
|
||||
do_increment(error);
|
||||
sprite_map.dirty = true;
|
||||
@ -122,10 +125,10 @@ void
|
||||
set_sprite_position(Cell *cell, Cell *previous_cell) {
|
||||
SpritePosition *sp;
|
||||
static int error;
|
||||
if (UNLIKELY(previous_cell != NULL && ((previous_cell->ch >> ATTRS_SHIFT) & WIDTH_MASK) == 2)) {
|
||||
sp = sprite_map_position_for(previous_cell->ch, 0, true, &error);
|
||||
if (UNLIKELY(previous_cell != NULL && ((previous_cell->attrs) & WIDTH_MASK) == 2)) {
|
||||
sp = sprite_map_position_for(previous_cell->ch, previous_cell->attrs, 0, true, &error);
|
||||
} else {
|
||||
sp = sprite_map_position_for(cell->ch, cell->cc, false, &error);
|
||||
sp = sprite_map_position_for(cell->ch, cell->attrs, cell->cc, false, &error);
|
||||
}
|
||||
cell->sprite_x = sp->x;
|
||||
cell->sprite_y = sp->y;
|
||||
@ -178,12 +181,13 @@ sprite_map_current_layout(unsigned int *x, unsigned int *y, unsigned int *z) {
|
||||
|
||||
PyObject*
|
||||
sprite_position_for(PyObject UNUSED *self, PyObject *args) {
|
||||
#define position_for_doc "position_for(ch, cc, is_second) -> x, y, z the sprite position for the specified text"
|
||||
#define sprite_position_for_doc "sprite_position_for(ch, cc, is_second, attrs) -> x, y, z the sprite position for the specified text"
|
||||
unsigned long ch = 0;
|
||||
unsigned long long cc = 0;
|
||||
unsigned int attrs = 1;
|
||||
int is_second = 0, error = 0;
|
||||
if (!PyArg_ParseTuple(args, "|kKp", &ch, &cc, &is_second)) return NULL;
|
||||
SpritePosition *pos = sprite_map_position_for(ch, cc, is_second, &error);
|
||||
if (!PyArg_ParseTuple(args, "|kKpI", &ch, &cc, &is_second, &attrs)) return NULL;
|
||||
SpritePosition *pos = sprite_map_position_for(ch, attrs, cc, is_second, &error);
|
||||
if (pos == NULL) { sprite_map_set_error(error); return NULL; }
|
||||
return Py_BuildValue("III", pos->x, pos->y, pos->z);
|
||||
}
|
||||
@ -197,10 +201,8 @@ render_dirty_sprites(void (*render)(PyObject*, bool, bool, bool, sprite_index, s
|
||||
SpritePosition *sp = &(sprite_map.cache[i]);
|
||||
do {
|
||||
if (sp->filled && !sp->rendered) {
|
||||
PyObject *text = line_text_at(sp->ch & CHAR_MASK, sp->cc);
|
||||
char_type attrs = sp->ch >> ATTRS_SHIFT;
|
||||
bool bold = (attrs >> BOLD_SHIFT) & 1, italic = (attrs >> ITALIC_SHIFT) & 1;
|
||||
render(text, bold, italic, sp->is_second, sp->x, sp->y, sp->z);
|
||||
PyObject *text = line_text_at(sp->ch, sp->cc);
|
||||
render(text, sp->bold, sp->italic, sp->is_second, sp->x, sp->y, sp->z);
|
||||
Py_CLEAR(text);
|
||||
sp->rendered = true;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user