vrshoot
diff libs/drawtext/font.c @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/drawtext/font.c Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,697 @@ 1.4 +/* 1.5 +libdrawtext - a simple library for fast text rendering in OpenGL 1.6 +Copyright (C) 2011 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU Lesser General Public License as published by 1.10 +the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU Lesser General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU Lesser General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 +#ifndef NO_FREETYPE 1.22 +#define USE_FREETYPE 1.23 +#endif 1.24 + 1.25 +#include <stdio.h> 1.26 +#include <stdlib.h> 1.27 +#include <string.h> 1.28 +#include <math.h> 1.29 +#include <limits.h> 1.30 +#include <ctype.h> 1.31 +#include <float.h> 1.32 +#include <errno.h> 1.33 +#ifdef USE_FREETYPE 1.34 +#include <ft2build.h> 1.35 +#include FT_FREETYPE_H 1.36 +#endif 1.37 +#include "drawtext.h" 1.38 +#include "drawtext_impl.h" 1.39 + 1.40 +#define FTSZ_TO_PIXELS(x) ((x) / 64) 1.41 +#define MAX_IMG_WIDTH 4096 1.42 + 1.43 + 1.44 +#ifdef USE_FREETYPE 1.45 +static int init_freetype(void); 1.46 +static void cleanup(void); 1.47 + 1.48 +static void calc_best_size(int total_width, int max_glyph_height, int padding, int pow2, int *imgw, int *imgh); 1.49 +static int next_pow2(int x); 1.50 + 1.51 +static FT_Library ft; 1.52 + 1.53 + 1.54 +static int init_done; 1.55 + 1.56 +static int init_freetype(void) 1.57 +{ 1.58 + if(!init_done) { 1.59 + if(FT_Init_FreeType(&ft) != 0) { 1.60 + return -1; 1.61 + } 1.62 + atexit(cleanup); 1.63 + init_done = 1; 1.64 + } 1.65 + return 0; 1.66 +} 1.67 + 1.68 +static void cleanup(void) 1.69 +{ 1.70 + if(init_done) { 1.71 + FT_Done_FreeType(ft); 1.72 + } 1.73 +} 1.74 + 1.75 +struct dtx_font *dtx_open_font(const char *fname, int sz) 1.76 +{ 1.77 + struct dtx_font *fnt; 1.78 + 1.79 + init_freetype(); 1.80 + 1.81 + if(!(fnt = calloc(1, sizeof *fnt))) { 1.82 + fperror("failed to allocate font structure"); 1.83 + return 0; 1.84 + } 1.85 + 1.86 + if(FT_New_Face(ft, fname, 0, (FT_Face*)&fnt->face) != 0) { 1.87 + fprintf(stderr, "failed to open font file: %s\n", fname); 1.88 + return 0; 1.89 + } 1.90 + 1.91 + /* pre-create the extended ASCII range glyphmap */ 1.92 + if(sz) { 1.93 + dtx_prepare_range(fnt, sz, 0, 256); 1.94 + 1.95 + if(!dtx_font) { 1.96 + dtx_use_font(fnt, sz); 1.97 + } 1.98 + } 1.99 + 1.100 + return fnt; 1.101 +} 1.102 + 1.103 +void dtx_close_font(struct dtx_font *fnt) 1.104 +{ 1.105 + if(!fnt) return; 1.106 + 1.107 + FT_Done_Face(fnt->face); 1.108 + 1.109 + /* destroy the glyphmaps */ 1.110 + while(fnt->gmaps) { 1.111 + void *tmp = fnt->gmaps; 1.112 + fnt->gmaps = fnt->gmaps->next; 1.113 + dtx_free_glyphmap(tmp); 1.114 + } 1.115 + 1.116 + free(fnt); 1.117 +} 1.118 + 1.119 +void dtx_prepare(struct dtx_font *fnt, int sz) 1.120 +{ 1.121 + dtx_get_font_glyphmap_range(fnt, sz, 0, 256); 1.122 +} 1.123 + 1.124 +void dtx_prepare_range(struct dtx_font *fnt, int sz, int cstart, int cend) 1.125 +{ 1.126 + dtx_get_font_glyphmap_range(fnt, sz, cstart, cend); 1.127 +} 1.128 + 1.129 +struct dtx_glyphmap *dtx_get_font_glyphmap(struct dtx_font *fnt, int sz, int code) 1.130 +{ 1.131 + struct dtx_glyphmap *gm; 1.132 + 1.133 + /* check to see if the last we've given out fits the bill */ 1.134 + if(fnt->last_gmap && code >= fnt->last_gmap->cstart && code < fnt->last_gmap->cend && fnt->last_gmap->ptsize == sz) { 1.135 + return fnt->last_gmap; 1.136 + } 1.137 + 1.138 + /* otherwise search for the appropriate glyphmap */ 1.139 + gm = fnt->gmaps; 1.140 + while(gm) { 1.141 + if(code >= gm->cstart && code < gm->cend && sz == gm->ptsize) { 1.142 + fnt->last_gmap = gm; 1.143 + return gm; 1.144 + } 1.145 + gm = gm->next; 1.146 + } 1.147 + return 0; 1.148 +} 1.149 + 1.150 +struct dtx_glyphmap *dtx_get_font_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend) 1.151 +{ 1.152 + struct dtx_glyphmap *gm; 1.153 + 1.154 + /* search the available glyphmaps to see if we've got one that includes 1.155 + * the requested range 1.156 + */ 1.157 + gm = fnt->gmaps; 1.158 + while(gm) { 1.159 + if(gm->cstart <= cstart && gm->cend >= cend && gm->ptsize == sz) { 1.160 + return gm; 1.161 + } 1.162 + gm = gm->next; 1.163 + } 1.164 + 1.165 + /* not found, create one and add it to the list */ 1.166 + if(!(gm = dtx_create_glyphmap_range(fnt, sz, cstart, cend))) { 1.167 + return 0; 1.168 + } 1.169 + return gm; 1.170 +} 1.171 + 1.172 +struct dtx_glyphmap *dtx_create_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend) 1.173 +{ 1.174 + FT_Face face = fnt->face; 1.175 + struct dtx_glyphmap *gmap; 1.176 + int i, j; 1.177 + int gx, gy; 1.178 + int padding = 4; 1.179 + int total_width = padding; 1.180 + int max_height = 0; 1.181 + 1.182 + FT_Set_Char_Size(fnt->face, 0, sz * 64, 72, 72); 1.183 + 1.184 + if(!(gmap = calloc(1, sizeof *gmap))) { 1.185 + return 0; 1.186 + } 1.187 + 1.188 + gmap->ptsize = sz; 1.189 + gmap->cstart = cstart; 1.190 + gmap->cend = cend; 1.191 + gmap->crange = cend - cstart; 1.192 + gmap->line_advance = FTSZ_TO_PIXELS((float)face->size->metrics.height); 1.193 + gmap->baseline = -FTSZ_TO_PIXELS((float)face->size->metrics.descender); 1.194 + 1.195 + if(!(gmap->glyphs = malloc(gmap->crange * sizeof *gmap->glyphs))) { 1.196 + free(gmap); 1.197 + return 0; 1.198 + } 1.199 + 1.200 + for(i=0; i<gmap->crange; i++) { 1.201 + int h; 1.202 + 1.203 + FT_Load_Char(face, i + cstart, 0); 1.204 + h = FTSZ_TO_PIXELS(face->glyph->metrics.height); 1.205 + 1.206 + if(h > max_height) { 1.207 + max_height = h; 1.208 + } 1.209 + total_width += FTSZ_TO_PIXELS(face->glyph->metrics.width) + padding; 1.210 + } 1.211 + 1.212 + calc_best_size(total_width, max_height, padding, 1, &gmap->xsz, &gmap->ysz); 1.213 + 1.214 + if(!(gmap->pixels = malloc(gmap->xsz * gmap->ysz))) { 1.215 + free(gmap->glyphs); 1.216 + free(gmap); 1.217 + return 0; 1.218 + } 1.219 + memset(gmap->pixels, 0, gmap->xsz * gmap->ysz); 1.220 + 1.221 + gx = padding; 1.222 + gy = padding; 1.223 + 1.224 + for(i=0; i<gmap->crange; i++) { 1.225 + float gwidth, gheight; 1.226 + unsigned char *src, *dst; 1.227 + FT_GlyphSlot glyph; 1.228 + 1.229 + FT_Load_Char(face, i + cstart, FT_LOAD_RENDER); 1.230 + glyph = face->glyph; 1.231 + gwidth = FTSZ_TO_PIXELS((float)glyph->metrics.width); 1.232 + gheight = FTSZ_TO_PIXELS((float)glyph->metrics.height); 1.233 + 1.234 + if(gx > gmap->xsz - gwidth - padding) { 1.235 + gx = padding; 1.236 + gy += max_height + padding; 1.237 + } 1.238 + 1.239 + src = glyph->bitmap.buffer; 1.240 + dst = gmap->pixels + gy * gmap->xsz + gx; 1.241 + 1.242 + for(j=0; j<glyph->bitmap.rows; j++) { 1.243 + memcpy(dst, src, glyph->bitmap.width); 1.244 + dst += gmap->xsz; 1.245 + src += glyph->bitmap.pitch; 1.246 + } 1.247 + 1.248 + gmap->glyphs[i].code = i; 1.249 + gmap->glyphs[i].x = gx - 1; 1.250 + gmap->glyphs[i].y = gy - 1; 1.251 + gmap->glyphs[i].width = gwidth + 2; 1.252 + gmap->glyphs[i].height = gheight + 2; 1.253 + gmap->glyphs[i].orig_x = -FTSZ_TO_PIXELS((float)glyph->metrics.horiBearingX) + 1; 1.254 + gmap->glyphs[i].orig_y = FTSZ_TO_PIXELS((float)glyph->metrics.height - glyph->metrics.horiBearingY) + 1; 1.255 + gmap->glyphs[i].advance = FTSZ_TO_PIXELS((float)glyph->metrics.horiAdvance); 1.256 + /* also precalc normalized */ 1.257 + gmap->glyphs[i].nx = (float)gmap->glyphs[i].x / (float)gmap->xsz; 1.258 + gmap->glyphs[i].ny = (float)gmap->glyphs[i].y / (float)gmap->ysz; 1.259 + gmap->glyphs[i].nwidth = (float)gmap->glyphs[i].width / (float)gmap->xsz; 1.260 + gmap->glyphs[i].nheight = (float)gmap->glyphs[i].height / (float)gmap->ysz; 1.261 + 1.262 + gx += gwidth + padding; 1.263 + } 1.264 + 1.265 + /* add it to the glyphmaps list of the font */ 1.266 + gmap->next = fnt->gmaps; 1.267 + fnt->gmaps = gmap; 1.268 + 1.269 + return gmap; 1.270 +} 1.271 +#endif /* USE_FREETYPE */ 1.272 + 1.273 +void dtx_free_glyphmap(struct dtx_glyphmap *gmap) 1.274 +{ 1.275 + if(gmap) { 1.276 + free(gmap->pixels); 1.277 + free(gmap->glyphs); 1.278 + free(gmap); 1.279 + } 1.280 +} 1.281 + 1.282 +unsigned char *dtx_get_glyphmap_pixels(struct dtx_glyphmap *gmap) 1.283 +{ 1.284 + return gmap->pixels; 1.285 +} 1.286 + 1.287 +int dtx_get_glyphmap_width(struct dtx_glyphmap *gmap) 1.288 +{ 1.289 + return gmap->xsz; 1.290 +} 1.291 + 1.292 +int dtx_get_glyphmap_height(struct dtx_glyphmap *gmap) 1.293 +{ 1.294 + return gmap->ysz; 1.295 +} 1.296 + 1.297 +struct dtx_glyphmap *dtx_load_glyphmap(const char *fname) 1.298 +{ 1.299 + FILE *fp; 1.300 + struct dtx_glyphmap *gmap; 1.301 + 1.302 + if(!(fp = fopen(fname, "r"))) { 1.303 + return 0; 1.304 + } 1.305 + gmap = dtx_load_glyphmap_stream(fp); 1.306 + fclose(fp); 1.307 + return gmap; 1.308 +} 1.309 + 1.310 +struct dtx_glyphmap *dtx_load_glyphmap_stream(FILE *fp) 1.311 +{ 1.312 + char buf[512]; 1.313 + int hdr_lines = 0; 1.314 + struct dtx_glyphmap *gmap; 1.315 + struct glyph *glyphs = 0; 1.316 + int min_code = INT_MAX; 1.317 + int max_code = INT_MIN; 1.318 + int i, max_pixval, num_pixels; 1.319 + 1.320 + if(!(gmap = calloc(1, sizeof *gmap))) { 1.321 + fperror("failed to allocate glyphmap"); 1.322 + return 0; 1.323 + } 1.324 + 1.325 + while(hdr_lines < 3) { 1.326 + char *line = buf; 1.327 + if(!fgets(buf, sizeof buf, fp)) { 1.328 + fperror("unexpected end of file"); 1.329 + goto err; 1.330 + } 1.331 + 1.332 + while(isspace(*line)) { 1.333 + line++; 1.334 + } 1.335 + 1.336 + if(line[0] == '#') { 1.337 + struct glyph *g; 1.338 + int c; 1.339 + float x, y, xsz, ysz, res; 1.340 + 1.341 + res = sscanf(line + 1, "%d: %fx%f+%f+%f\n", &c, &xsz, &ysz, &x, &y); 1.342 + if(res != 5) { 1.343 + fprintf(stderr, "%s: invalid glyph info line\n", __FUNCTION__); 1.344 + goto err; 1.345 + } 1.346 + 1.347 + if(!(g = malloc(sizeof *g))) { 1.348 + fperror("failed to allocate glyph"); 1.349 + goto err; 1.350 + } 1.351 + g->code = c; 1.352 + g->x = x; 1.353 + g->y = y; 1.354 + g->width = xsz; 1.355 + g->height = ysz; 1.356 + g->next = glyphs; 1.357 + glyphs = g; 1.358 + 1.359 + if(c < min_code) { 1.360 + min_code = c; 1.361 + } 1.362 + if(c > max_code) { 1.363 + max_code = c; 1.364 + } 1.365 + } else { 1.366 + switch(hdr_lines) { 1.367 + case 0: 1.368 + if(0[line] != 'P' || 1[line] != '6') { 1.369 + fprintf(stderr, "%s: invalid file format (magic)\n", __FUNCTION__); 1.370 + goto err; 1.371 + } 1.372 + break; 1.373 + 1.374 + case 1: 1.375 + if(sscanf(line, "%d %d", &gmap->xsz, &gmap->ysz) != 2) { 1.376 + fprintf(stderr, "%s: invalid file format (dim)\n", __FUNCTION__); 1.377 + goto err; 1.378 + } 1.379 + break; 1.380 + 1.381 + case 2: 1.382 + { 1.383 + char *endp; 1.384 + max_pixval = strtol(line, &endp, 10); 1.385 + if(endp == line) { 1.386 + fprintf(stderr, "%s: invalid file format (maxval)\n", __FUNCTION__); 1.387 + goto err; 1.388 + } 1.389 + } 1.390 + break; 1.391 + 1.392 + default: 1.393 + break; /* can't happen */ 1.394 + } 1.395 + hdr_lines++; 1.396 + } 1.397 + } 1.398 + 1.399 + num_pixels = gmap->xsz * gmap->ysz; 1.400 + if(!(gmap->pixels = malloc(num_pixels))) { 1.401 + fperror("failed to allocate pixels"); 1.402 + goto err; 1.403 + } 1.404 + 1.405 + for(i=0; i<num_pixels; i++) { 1.406 + long c = fgetc(fp); 1.407 + if(c == -1) { 1.408 + fprintf(stderr, "unexpected end of file while reading pixels\n"); 1.409 + goto err; 1.410 + } 1.411 + gmap->pixels[i] = 255 * c / max_pixval; 1.412 + fseek(fp, 2, SEEK_CUR); 1.413 + } 1.414 + 1.415 + gmap->cstart = min_code; 1.416 + gmap->cend = max_code + 1; 1.417 + gmap->crange = gmap->cend - gmap->cstart; 1.418 + 1.419 + if(!(gmap->glyphs = calloc(gmap->crange, sizeof *gmap->glyphs))) { 1.420 + fperror("failed to allocate glyph info"); 1.421 + goto err; 1.422 + } 1.423 + 1.424 + while(glyphs) { 1.425 + struct glyph *g = glyphs; 1.426 + glyphs = glyphs->next; 1.427 + 1.428 + gmap->glyphs[g->code - gmap->cstart] = *g; 1.429 + free(g); 1.430 + } 1.431 + return gmap; 1.432 + 1.433 +err: 1.434 + dtx_free_glyphmap(gmap); 1.435 + while(glyphs) { 1.436 + void *tmp = glyphs; 1.437 + glyphs = glyphs->next; 1.438 + free(tmp); 1.439 + } 1.440 + return 0; 1.441 +} 1.442 + 1.443 +int dtx_save_glyphmap(const char *fname, const struct dtx_glyphmap *gmap) 1.444 +{ 1.445 + FILE *fp; 1.446 + int res; 1.447 + 1.448 + if(!(fp = fopen(fname, "wb"))) { 1.449 + fprintf(stderr, "%s: failed to open file: %s: %s\n", __FUNCTION__, fname, strerror(errno)); 1.450 + return -1; 1.451 + } 1.452 + res = dtx_save_glyphmap_stream(fp, gmap); 1.453 + fclose(fp); 1.454 + return res; 1.455 +} 1.456 + 1.457 +int dtx_save_glyphmap_stream(FILE *fp, const struct dtx_glyphmap *gmap) 1.458 +{ 1.459 + int i, num_pixels; 1.460 + struct glyph *g = gmap->glyphs; 1.461 + 1.462 + fprintf(fp, "P6\n%d %d\n", gmap->xsz, gmap->ysz); 1.463 + for(i=0; i<gmap->crange; i++) { 1.464 + fprintf(fp, "# %d: %fx%f+%f+%f\n", g->code, g->width, g->height, g->x, g->y); 1.465 + g++; 1.466 + } 1.467 + fprintf(fp, "255\n"); 1.468 + 1.469 + num_pixels = gmap->xsz * gmap->ysz; 1.470 + for(i=0; i<num_pixels; i++) { 1.471 + int c = gmap->pixels[i]; 1.472 + fputc(c, fp); 1.473 + fputc(c, fp); 1.474 + fputc(c, fp); 1.475 + } 1.476 + return 0; 1.477 +} 1.478 + 1.479 + 1.480 +void dtx_use_font(struct dtx_font *fnt, int sz) 1.481 +{ 1.482 + dtx_gl_init(); 1.483 + 1.484 + dtx_font = fnt; 1.485 + dtx_font_sz = sz; 1.486 +} 1.487 + 1.488 +float dtx_line_height(void) 1.489 +{ 1.490 + struct dtx_glyphmap *gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, '\n'); 1.491 + 1.492 + return gmap->line_advance; 1.493 +} 1.494 + 1.495 +float dtx_baseline(void) 1.496 +{ 1.497 + struct dtx_glyphmap *gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, '\n'); 1.498 + 1.499 + return gmap->baseline; 1.500 +} 1.501 + 1.502 +void dtx_glyph_box(int code, struct dtx_box *box) 1.503 +{ 1.504 + int cidx; 1.505 + struct dtx_glyphmap *gmap; 1.506 + gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code); 1.507 + 1.508 + cidx = code - gmap->cstart; 1.509 + 1.510 + box->x = gmap->glyphs[cidx].orig_x; 1.511 + box->y = gmap->glyphs[cidx].orig_y; 1.512 + box->width = gmap->glyphs[cidx].width; 1.513 + box->height = gmap->glyphs[cidx].height; 1.514 +} 1.515 + 1.516 +float dtx_glyph_width(int code) 1.517 +{ 1.518 + struct dtx_box box; 1.519 + dtx_glyph_box(code, &box); 1.520 + return box.width; 1.521 +} 1.522 + 1.523 +float dtx_glyph_height(int code) 1.524 +{ 1.525 + struct dtx_box box; 1.526 + dtx_glyph_box(code, &box); 1.527 + return box.height; 1.528 +} 1.529 + 1.530 +void dtx_string_box(const char *str, struct dtx_box *box) 1.531 +{ 1.532 + int code; 1.533 + float pos_x = 0.0f, pos_y = 0.0f; 1.534 + struct glyph *g = 0; 1.535 + float x0, y0, x1, y1; 1.536 + 1.537 + x0 = y0 = FLT_MAX; 1.538 + x1 = y1 = -FLT_MAX; 1.539 + 1.540 + while(*str) { 1.541 + float px, py; 1.542 + struct dtx_glyphmap *gmap; 1.543 + 1.544 + code = dtx_utf8_char_code(str); 1.545 + str = dtx_utf8_next_char((char*)str); 1.546 + 1.547 + px = pos_x; 1.548 + py = pos_y; 1.549 + 1.550 + if((gmap = dtx_proc_char(code, &pos_x, &pos_y))) { 1.551 + g = gmap->glyphs + code - gmap->cstart; 1.552 + 1.553 + if(px + g->orig_x < x0) { 1.554 + x0 = px + g->orig_x; 1.555 + } 1.556 + if(py - g->orig_y < y0) { 1.557 + y0 = py - g->orig_y; 1.558 + } 1.559 + if(px + g->orig_x + g->width > x1) { 1.560 + x1 = px + g->orig_x + g->width; 1.561 + } 1.562 + if(py - g->orig_y + g->height > y1) { 1.563 + y1 = py - g->orig_y + g->height; 1.564 + } 1.565 + } 1.566 + } 1.567 + 1.568 + box->x = x0; 1.569 + box->y = y0; 1.570 + box->width = x1 - x0; 1.571 + box->height = y1 - y0; 1.572 +} 1.573 + 1.574 +float dtx_string_width(const char *str) 1.575 +{ 1.576 + struct dtx_box box; 1.577 + 1.578 + dtx_string_box(str, &box); 1.579 + return box.width; 1.580 +} 1.581 + 1.582 +float dtx_string_height(const char *str) 1.583 +{ 1.584 + struct dtx_box box; 1.585 + 1.586 + dtx_string_box(str, &box); 1.587 + return box.height; 1.588 +} 1.589 + 1.590 +float dtx_char_pos(const char *str, int n) 1.591 +{ 1.592 + int i; 1.593 + float pos = 0.0; 1.594 + struct dtx_glyphmap *gmap; 1.595 + 1.596 + for(i=0; i<n; i++) { 1.597 + int code = dtx_utf8_char_code(str); 1.598 + str = dtx_utf8_next_char((char*)str); 1.599 + 1.600 + gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code); 1.601 + pos += gmap->glyphs[i].advance; 1.602 + } 1.603 + return pos; 1.604 +} 1.605 + 1.606 +int dtx_char_at_pt(const char *str, float pt) 1.607 +{ 1.608 + int i; 1.609 + float prev_pos = 0.0f, pos = 0.0f; 1.610 + struct dtx_glyphmap *gmap; 1.611 + 1.612 + for(i=0; *str; i++) { 1.613 + int code = dtx_utf8_char_code(str); 1.614 + str = dtx_utf8_next_char((char*)str); 1.615 + 1.616 + gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code); 1.617 + pos += gmap->glyphs[i].advance; 1.618 + 1.619 + if(fabs(pt - prev_pos) < fabs(pt - pos)) { 1.620 + break; 1.621 + } 1.622 + prev_pos = pos; 1.623 + } 1.624 + return i; 1.625 +} 1.626 + 1.627 +struct dtx_glyphmap *dtx_proc_char(int code, float *xpos, float *ypos) 1.628 +{ 1.629 + struct dtx_glyphmap *gmap; 1.630 + gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code); 1.631 + 1.632 + switch(code) { 1.633 + case '\n': 1.634 + *xpos = 0.0; 1.635 + if(gmap) { 1.636 + *ypos -= gmap->line_advance; 1.637 + } 1.638 + return 0; 1.639 + 1.640 + case '\t': 1.641 + if(gmap) { 1.642 + *xpos = (fmod(*xpos, 4.0) + 4.0) * gmap->glyphs[0].advance; 1.643 + } 1.644 + return 0; 1.645 + 1.646 + case '\r': 1.647 + *xpos = 0.0; 1.648 + return 0; 1.649 + 1.650 + default: 1.651 + break; 1.652 + } 1.653 + 1.654 + if(gmap) { 1.655 + *xpos += gmap->glyphs[code - gmap->cstart].advance; 1.656 + } 1.657 + return gmap; 1.658 +} 1.659 + 1.660 +static void calc_best_size(int total_width, int max_glyph_height, int padding, int pow2, int *imgw, int *imgh) 1.661 +{ 1.662 + int xsz, ysz, num_rows; 1.663 + float aspect; 1.664 + 1.665 + for(xsz=2; xsz<=MAX_IMG_WIDTH; xsz *= 2) { 1.666 + num_rows = total_width / xsz + 1; 1.667 + 1.668 + /* take into account the one extra padding for each row after the first */ 1.669 + num_rows = (total_width + padding * (num_rows - 1)) / xsz + 1; 1.670 + 1.671 + ysz = num_rows * (max_glyph_height + padding) + padding; 1.672 + if(pow2) { 1.673 + ysz = next_pow2(ysz); 1.674 + } 1.675 + aspect = (float)xsz / (float)ysz; 1.676 + 1.677 + if(aspect >= 1.0) { 1.678 + break; 1.679 + } 1.680 + } 1.681 + 1.682 + if(xsz > MAX_IMG_WIDTH) { 1.683 + xsz = MAX_IMG_WIDTH; 1.684 + } 1.685 + 1.686 + *imgw = xsz; 1.687 + *imgh = ysz; 1.688 +} 1.689 + 1.690 + 1.691 +static int next_pow2(int x) 1.692 +{ 1.693 + x--; 1.694 + x = (x >> 1) | x; 1.695 + x = (x >> 2) | x; 1.696 + x = (x >> 4) | x; 1.697 + x = (x >> 8) | x; 1.698 + x = (x >> 16) | x; 1.699 + return x + 1; 1.700 +}