diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index 91129ee9f..b353ce17d 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -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); } diff --git a/kitty/data-types.h b/kitty/data-types.h index 95900d98f..635d3089f 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -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)]); \ } diff --git a/kitty/line-buf.c b/kitty/line-buf.c index 5211b0f16..ff98ca33a 100644 --- a/kitty/line-buf.c +++ b/kitty/line-buf.c @@ -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; } diff --git a/kitty/line.c b/kitty/line.c index 9dfa3f3de..8184deaa0 100644 --- a/kitty/line.c +++ b/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); diff --git a/kitty/lineops.h b/kitty/lineops.h index b522b3718..22e3e285b 100644 --- a/kitty/lineops.h +++ b/kitty/lineops.h @@ -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 ); diff --git a/kitty/rewrap.h b/kitty/rewrap.h index 716a25588..f151a49d8 100644 --- a/kitty/rewrap.h +++ b/kitty/rewrap.h @@ -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) { diff --git a/kitty/screen.c b/kitty/screen.c index 1bad5c864..64cfc0257 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -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 { diff --git a/kitty/shaders.c b/kitty/shaders.c index dc45e50ff..9a35ce25d 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -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); diff --git a/kitty/sprites.c b/kitty/sprites.c index 9283e84ac..95ff15b0d 100644 --- a/kitty/sprites.c +++ b/kitty/sprites.c @@ -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; }