diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | buffer.c | 2 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | node.c | 1 | ||||
-rw-r--r-- | text.c | 20 | ||||
-rw-r--r-- | text.h | 8 | ||||
-rw-r--r-- | ui.c | 1 |
7 files changed, 29 insertions, 7 deletions
@@ -318,7 +318,7 @@ Then, open windows\_installer\\ted\\ted.sln, and build. <tr><td>2.3.2</td> <td>Misc bugfixes</td> <td>2023 Jun 17</td></tr> <tr><td>2.3.3</td> <td>JS highlighting improvments, fix TODO highlighting for single-line comments</td> <td>2023 Jul 6</td></tr> <tr><td>2.3.4</td> <td>Unicode bugfix, `:copy-path`</td> <td>2023 Jul 14</td></tr> -<tr><td>2.4</td> <td>Font overhaul — allow multiple fonts, and variable-width fonts.</td> <td>2023 Jul 18</td></tr> +<tr><td>2.4</td> <td>Font overhaul — allow multiple fonts, and variable-width fonts.</td> <td>2023 Jul 19</td></tr> </table> ## License @@ -3021,6 +3021,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { rgba_u32_to_floats(colors[line == cursor_line ? COLOR_CURSOR_LINE_NUMBER : COLOR_LINE_NUMBERS], text_state.color); text_state.x = x; text_state.y = y; + text_state_break_kerning(&text_state); text_utf8_with_state(font, &text_state, str); y += char_height; if (y > y2) break; @@ -3196,6 +3197,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { } // next line + text_state_break_kerning(&text_state); text_state.x = render_start_x; if (text_state.y > text_state.max_y) { buffer->last_line_on_screen = line_idx; @@ -1,6 +1,4 @@ /* -TODO: -- kerning FUTURE FEATURES: - autodetect indentation (tabs vs spaces) - font setting & support for multiple fonts to cover more characters @@ -324,6 +324,7 @@ void node_frame(Ted *ted, Node *node, Rect r) { rgba_u32_to_floats(colors[COLOR_TEXT], text_state.color); text_state.x = tab_rect.pos.x; text_state.y = tab_rect.pos.y; + text_state_break_kerning(&text_state); text_utf8_with_state(font, &text_state, tab_title); if (i == node->active_tab) { @@ -66,7 +66,8 @@ const TextRenderState text_render_state_default = { .min_x = -FLT_MAX, .max_x = +FLT_MAX, .min_y = -FLT_MAX, .max_y = +FLT_MAX, .color = {1, 0, 1, 1}, - .x_largest = -FLT_MAX, .y_largest = -FLT_MAX + .x_largest = -FLT_MAX, .y_largest = -FLT_MAX, + .prev_char = 0, }; static char text_err[200]; @@ -388,12 +389,18 @@ top: goto ret; } + if (!font->force_monospace && state->prev_char && state->prev_char != '\n') { + // kerning + state->x += (float)stbtt_GetCodepointKernAdvance(&font->stb_info, (int)state->prev_char, (int)c) + * stbtt_ScaleForPixelHeight(&font->stb_info, font->char_height); + } + { float x, y; x = (float)(state->x - floor(state->x)); y = (float)(state->y - floor(state->y)); y += char_height * 0.75f; - stbtt_GetPackedQuad(&info.data, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, 0, &x, &y, &q, 1); + stbtt_GetPackedQuad(&info.data, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, 0, &x, &y, &q, 0); y -= char_height * 0.75f; q.x0 += (float)floor(state->x); @@ -411,8 +418,8 @@ top: float s0 = q.s0, t0 = q.t0; float s1 = q.s1, t1 = q.t1; - float x0 = q.x0, y0 = q.y0; - float x1 = q.x1, y1 = q.y1; + float x0 = roundf(q.x0), y0 = roundf(q.y0); + float x1 = roundf(q.x1), y1 = roundf(q.y1); const float min_x = state->min_x, max_x = state->max_x; const float min_y = state->min_y, max_y = state->max_y; @@ -460,6 +467,7 @@ top: state->x_largest = state->x; if (state->y > state->y_largest) state->y_largest = state->y; + state->prev_char = c; } void text_utf8_with_state(Font *font, TextRenderState *state, const char *str) { @@ -553,6 +561,10 @@ static void font_free_textures(Font *font) { arr_clear(font->textures); } +void text_state_break_kerning(TextRenderState *state) { + state->prev_char = 0; +} + void text_font_change_size(Font *font, float new_size) { font_free_textures(font); font_free_char_info(font); @@ -41,6 +41,9 @@ typedef struct { /// largest y achieved (for computing size) double y_largest; + /// previous character rendered, or 0 if this is the first + char32_t prev_char; + /// used for forwards-compatibility char _reserved[64]; } TextRenderState; @@ -98,6 +101,11 @@ void text_utf8_anchored(Font *font, const char *text, double x, double y, u32 co void text_char_with_state(Font *font, TextRenderState *state, char32_t c); /// Draw some UTF-8 text with a \ref TextRenderState. void text_utf8_with_state(Font *font, TextRenderState *state, const char *str); +/// Used to indicate that the next character drawn should not +/// kern with the previous character. +/// +/// Use this when you go to the next line or something. +void text_state_break_kerning(TextRenderState *state); /// Free memory used by font. /// /// Does NOT free the font's fallback. @@ -160,6 +160,7 @@ void selector_render(Ted *ted, Selector *s) { // draw name rgba_u32_to_floats(entry->color, text_state.color); + text_state_break_kerning(&text_state); text_utf8_with_state(font, &text_state, entry->name); if (entry->detail) { |