summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--buffer.c2
-rw-r--r--main.c2
-rw-r--r--node.c1
-rw-r--r--text.c20
-rw-r--r--text.h8
-rw-r--r--ui.c1
7 files changed, 29 insertions, 7 deletions
diff --git a/README.md b/README.md
index 13f454e..bcb85b8 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/buffer.c b/buffer.c
index 0dd397d..b98717d 100644
--- a/buffer.c
+++ b/buffer.c
@@ -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;
diff --git a/main.c b/main.c
index 2985f3c..0f9b0e7 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,4 @@
/*
-TODO:
-- kerning
FUTURE FEATURES:
- autodetect indentation (tabs vs spaces)
- font setting & support for multiple fonts to cover more characters
diff --git a/node.c b/node.c
index 29f08b9..43e83fc 100644
--- a/node.c
+++ b/node.c
@@ -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) {
diff --git a/text.c b/text.c
index 29d1831..70941de 100644
--- a/text.c
+++ b/text.c
@@ -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);
diff --git a/text.h b/text.h
index 8d317e8..ff07e79 100644
--- a/text.h
+++ b/text.h
@@ -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.
diff --git a/ui.c b/ui.c
index 0c398b3..abcfad7 100644
--- a/ui.c
+++ b/ui.c
@@ -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) {