fix font
This commit is contained in:
@@ -246,12 +246,10 @@ clay.image = function image(path, ...configs)
|
||||
clay.text = function text(str, ...configs)
|
||||
{
|
||||
var config = rectify_configs(configs);
|
||||
config.size ??= [0,0];
|
||||
config.size ??= [0,0]
|
||||
config.font = graphics.get_font(config.font)
|
||||
config.text = str
|
||||
var tsize = config.font.text_size(str, 0, config.size[0], config.text_break, config.text_align);
|
||||
log.console(json.encode(config))
|
||||
log.console(json.encode(tsize))
|
||||
tsize.x = Math.ceil(tsize.x)
|
||||
tsize.y = Math.ceil(tsize.y)
|
||||
config.size = config.size.map((x,i) => Math.max(x, tsize[i]));
|
||||
|
||||
@@ -723,7 +723,6 @@ cmd_fns.draw_text = function(cmd)
|
||||
cmd.pos.width ??= size[0]
|
||||
cmd.pos.height ??= size[1]
|
||||
|
||||
log.console(json.encode(cmd))
|
||||
var mesh = font.make_text_buffer(
|
||||
cmd.text,
|
||||
cmd.pos,
|
||||
|
||||
216
source/font.c
216
source/font.c
@@ -14,6 +14,9 @@
|
||||
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
typedef struct { const char *start, *end; float width; } line_t;
|
||||
typedef struct { line_t *lines; float max_width; } layout_lines;
|
||||
|
||||
struct sFont *use_font;
|
||||
|
||||
void font_free(JSRuntime *rt, font *f)
|
||||
@@ -75,9 +78,9 @@ struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) {
|
||||
|
||||
rect quad;
|
||||
quad.x = glyph.xoff;
|
||||
quad.w = glyph.xoff2-glyph.xoff;
|
||||
quad.y = -glyph.yoff2;
|
||||
quad.h = glyph.yoff2-glyph.yoff;
|
||||
quad.y = -glyph.yoff2; // Top of glyph relative to baseline
|
||||
quad.w = glyph.xoff2 - glyph.xoff;
|
||||
quad.h = glyph.yoff2 - glyph.yoff; // Height from baseline
|
||||
newfont->Characters[c].quad = quad;
|
||||
newfont->Characters[c].advance = glyph.xadvance;
|
||||
}
|
||||
@@ -87,6 +90,82 @@ struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) {
|
||||
return newfont;
|
||||
}
|
||||
|
||||
layout_lines layout_text_lines(const char *text, font *f,
|
||||
float letter_spacing,
|
||||
float wrap,
|
||||
TEXT_BREAK break_at)
|
||||
{
|
||||
layout_lines out = {0};
|
||||
int break_at_word = (break_at == WORD);
|
||||
|
||||
const char *line_start = text;
|
||||
const char *word_start = text;
|
||||
float line_width = 0;
|
||||
float word_width = 0;
|
||||
|
||||
float max_width = 0;
|
||||
|
||||
for (const char *p = text; *p; p++) {
|
||||
if (*p == '\n') {
|
||||
line_t L = { line_start, p, line_width };
|
||||
arrput(out.lines, L);
|
||||
if (line_width > max_width) max_width = line_width;
|
||||
|
||||
line_start = p + 1;
|
||||
word_start = p + 1;
|
||||
line_width = 0;
|
||||
word_width = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned char ch = (unsigned char)*p;
|
||||
float char_w = f->Characters[ch].advance + letter_spacing;
|
||||
|
||||
if (wrap > 0 && line_width + char_w > wrap) {
|
||||
const char *break_pt = p;
|
||||
float break_w = line_width;
|
||||
|
||||
if (break_at_word && *p != ' ' && word_width > 0 && word_start > line_start) {
|
||||
break_pt = word_start;
|
||||
break_w = line_width - word_width;
|
||||
}
|
||||
|
||||
line_t L = { line_start, break_pt, break_w };
|
||||
arrput(out.lines, L);
|
||||
if (break_w > max_width) max_width = break_w;
|
||||
|
||||
line_start = break_pt;
|
||||
if (break_at_word && *line_start == ' ') line_start++;
|
||||
|
||||
p = line_start - 1;
|
||||
word_start = line_start;
|
||||
line_width = 0;
|
||||
word_width = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
line_width += char_w;
|
||||
|
||||
if (break_at_word) {
|
||||
if (*p == ' ') {
|
||||
word_width = 0;
|
||||
word_start = p + 1;
|
||||
} else {
|
||||
word_width += char_w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (line_start < text + strlen(text)) {
|
||||
line_t L = { line_start, text + strlen(text), line_width };
|
||||
arrput(out.lines, L);
|
||||
if (line_width > max_width) max_width = line_width;
|
||||
}
|
||||
|
||||
out.max_width = max_width;
|
||||
return out;
|
||||
}
|
||||
|
||||
void sdrawCharacter(struct text_vert **buffer, stbtt_packedchar c, HMM_Vec2 cursor, float scale, struct rgba color) {
|
||||
struct text_vert vert;
|
||||
|
||||
@@ -164,69 +243,21 @@ const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
|
||||
// text is a string, font f, wrap is how long a line is before wrapping. -1 to not wrap
|
||||
HMM_Vec2 measure_text(const char *text, font *f, float letter_spacing, float wrap, TEXT_BREAK break_at, TEXT_ALIGN align)
|
||||
{
|
||||
int break_at_word = (break_at == WORD);
|
||||
layout_lines lay = layout_text_lines(text, f, letter_spacing, wrap, break_at);
|
||||
|
||||
float lh = f->line_height;
|
||||
float height = lh;
|
||||
float max_width = 0, line_width = 0;
|
||||
int line_count = 1; // Start with 1 line
|
||||
int line_count = arrlen(lay.lines);
|
||||
float height = line_count > 0 ? line_count * lh : 0;
|
||||
|
||||
const char *word_start = text;
|
||||
float word_width = 0;
|
||||
|
||||
for (const char *p = text; *p; ) {
|
||||
if (*p == '\n') {
|
||||
if (line_width > max_width) max_width = line_width;
|
||||
line_width = 0;
|
||||
height += lh;
|
||||
line_count++;
|
||||
word_start = p + 1;
|
||||
word_width = 0;
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned char ch = (unsigned char)*p;
|
||||
float adv = f->Characters[ch].advance;
|
||||
/* add letter spacing unless this will be end-of-line char; unknown yet, so include it here;
|
||||
wrap logic below uses same width */
|
||||
float char_w = adv + letter_spacing;
|
||||
|
||||
if (wrap > 0 && line_width + char_w > wrap) {
|
||||
if (break_at_word && *p != ' ' && word_width > 0 && word_width <= wrap) {
|
||||
line_width -= word_width;
|
||||
p = word_start;
|
||||
} else {
|
||||
if (line_width > max_width) max_width = line_width;
|
||||
line_width = 0;
|
||||
height += lh;
|
||||
line_count++;
|
||||
word_start = p;
|
||||
word_width = 0;
|
||||
/* if not word-breaking or current is space, consume it here */
|
||||
if (!break_at_word || *p == ' ') { p++; }
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
|
||||
line_width += char_w;
|
||||
|
||||
if (break_at_word) {
|
||||
if (*p == ' ') {
|
||||
word_width = 0;
|
||||
word_start = p + 1;
|
||||
} else {
|
||||
word_width += char_w;
|
||||
}
|
||||
}
|
||||
float width = lay.max_width;
|
||||
if (wrap > 0 && align != LEFT && align != JUSTIFY) {
|
||||
// For RIGHT or CENTER we might shift lines visually, but width is still max(line.width, wrap ? min(wrap, ...) ).
|
||||
// Usually you'd report max(wrap, width) or just wrap, depending on how you want containers to size.
|
||||
}
|
||||
|
||||
if (line_width > max_width) max_width = line_width;
|
||||
HMM_Vec2 dim = { width, height };
|
||||
|
||||
printf("measure_text: Number of lines: %d\n", line_count);
|
||||
|
||||
HMM_Vec2 dim = { max_width, height };
|
||||
arrfree(lay.lines);
|
||||
return dim;
|
||||
}
|
||||
|
||||
@@ -236,69 +267,10 @@ struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, colorf col
|
||||
float letter_spacing)
|
||||
{
|
||||
text_vert *buffer = NULL;
|
||||
int break_at_word = (break_at == WORD);
|
||||
float lh = f->line_height;
|
||||
|
||||
typedef struct { const char *start, *end; float width; } line_t;
|
||||
line_t *lines = NULL;
|
||||
|
||||
const char *line_start = text, *word_start = text;
|
||||
float line_width = 0, word_width = 0;
|
||||
|
||||
for (const char *p = text; *p; p++) {
|
||||
if (*p == '\n') {
|
||||
line_t L = { line_start, p, line_width };
|
||||
arrput(lines, L);
|
||||
line_start = p + 1;
|
||||
word_start = p + 1;
|
||||
line_width = 0;
|
||||
word_width = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned char ch = (unsigned char)*p;
|
||||
float adv = f->Characters[ch].advance;
|
||||
float char_w = adv + letter_spacing;
|
||||
|
||||
if (wrap > 0 && line_width + char_w > wrap) {
|
||||
const char *break_pt = p;
|
||||
float break_w = line_width;
|
||||
|
||||
if (break_at_word && *p != ' ' && word_width > 0 && word_start > line_start) {
|
||||
break_pt = word_start;
|
||||
break_w = line_width - word_width;
|
||||
}
|
||||
|
||||
line_t L = { line_start, break_pt, break_w };
|
||||
arrput(lines, L);
|
||||
|
||||
line_start = break_pt;
|
||||
if (break_at_word && *line_start == ' ') line_start++;
|
||||
p = line_start - 1;
|
||||
word_start = line_start;
|
||||
line_width = 0;
|
||||
word_width = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
line_width += char_w;
|
||||
|
||||
if (break_at_word) {
|
||||
if (*p == ' ') {
|
||||
word_width = 0;
|
||||
word_start = p + 1;
|
||||
} else {
|
||||
word_width += char_w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (line_start < text + strlen(text)) {
|
||||
line_t L = { line_start, text + strlen(text), line_width };
|
||||
arrput(lines, L);
|
||||
}
|
||||
|
||||
printf("renderText: Number of lines: %d\n", arrlen(lines));
|
||||
layout_lines lay = layout_text_lines(text, f, letter_spacing, wrap, break_at);
|
||||
line_t *lines = lay.lines;
|
||||
|
||||
HMM_Vec2 cursor = pos;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user