dungeon_crawler
diff prototype/drawtext/font.c @ 24:e122ba214ee1
implementing the command console
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 23 Aug 2012 18:03:11 +0300 |
parents | |
children | 2fc004802739 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/prototype/drawtext/font.c Thu Aug 23 18:03:11 2012 +0300 1.3 @@ -0,0 +1,678 @@ 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 + 1.96 + return fnt; 1.97 +} 1.98 + 1.99 +void dtx_close_font(struct dtx_font *fnt) 1.100 +{ 1.101 + if(!fnt) return; 1.102 + 1.103 + FT_Done_Face(fnt->face); 1.104 + 1.105 + /* destroy the glyphmaps */ 1.106 + while(fnt->gmaps) { 1.107 + void *tmp = fnt->gmaps; 1.108 + fnt->gmaps = fnt->gmaps->next; 1.109 + dtx_free_glyphmap(tmp); 1.110 + } 1.111 + 1.112 + free(fnt); 1.113 +} 1.114 + 1.115 +void dtx_prepare(struct dtx_font *fnt, int sz) 1.116 +{ 1.117 + dtx_get_font_glyphmap_range(fnt, sz, 0, 256); 1.118 +} 1.119 + 1.120 +void dtx_prepare_range(struct dtx_font *fnt, int sz, int cstart, int cend) 1.121 +{ 1.122 + dtx_get_font_glyphmap_range(fnt, sz, cstart, cend); 1.123 +} 1.124 + 1.125 +struct dtx_glyphmap *dtx_get_font_glyphmap(struct dtx_font *fnt, int sz, int code) 1.126 +{ 1.127 + struct dtx_glyphmap *gm; 1.128 + 1.129 + /* check to see if the last we've given out fits the bill */ 1.130 + if(fnt->last_gmap && code >= fnt->last_gmap->cstart && code < fnt->last_gmap->cend && fnt->last_gmap->ptsize == sz) { 1.131 + return fnt->last_gmap; 1.132 + } 1.133 + 1.134 + /* otherwise search for the appropriate glyphmap */ 1.135 + gm = fnt->gmaps; 1.136 + while(gm) { 1.137 + if(code >= gm->cstart && code < gm->cend && sz == gm->ptsize) { 1.138 + fnt->last_gmap = gm; 1.139 + return gm; 1.140 + } 1.141 + gm = gm->next; 1.142 + } 1.143 + return 0; 1.144 +} 1.145 + 1.146 +struct dtx_glyphmap *dtx_get_font_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend) 1.147 +{ 1.148 + struct dtx_glyphmap *gm; 1.149 + 1.150 + /* search the available glyphmaps to see if we've got one that includes 1.151 + * the requested range 1.152 + */ 1.153 + gm = fnt->gmaps; 1.154 + while(gm) { 1.155 + if(gm->cstart <= cstart && gm->cend >= cend && gm->ptsize == sz) { 1.156 + return gm; 1.157 + } 1.158 + gm = gm->next; 1.159 + } 1.160 + 1.161 + /* not found, create one and add it to the list */ 1.162 + if(!(gm = dtx_create_glyphmap_range(fnt, sz, cstart, cend))) { 1.163 + return 0; 1.164 + } 1.165 + return gm; 1.166 +} 1.167 + 1.168 +struct dtx_glyphmap *dtx_create_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend) 1.169 +{ 1.170 + FT_Face face = fnt->face; 1.171 + struct dtx_glyphmap *gmap; 1.172 + int i, j; 1.173 + int gx, gy; 1.174 + int padding = 4; 1.175 + int total_width = padding; 1.176 + int max_height = 0; 1.177 + 1.178 + FT_Set_Char_Size(fnt->face, 0, sz * 64, 72, 72); 1.179 + 1.180 + if(!(gmap = calloc(1, sizeof *gmap))) { 1.181 + return 0; 1.182 + } 1.183 + 1.184 + gmap->ptsize = sz; 1.185 + gmap->cstart = cstart; 1.186 + gmap->cend = cend; 1.187 + gmap->crange = cend - cstart; 1.188 + gmap->line_advance = FTSZ_TO_PIXELS((float)face->size->metrics.height); 1.189 + 1.190 + if(!(gmap->glyphs = malloc(gmap->crange * sizeof *gmap->glyphs))) { 1.191 + free(gmap); 1.192 + return 0; 1.193 + } 1.194 + 1.195 + for(i=0; i<gmap->crange; i++) { 1.196 + int h; 1.197 + 1.198 + FT_Load_Char(face, i + cstart, 0); 1.199 + h = FTSZ_TO_PIXELS(face->glyph->metrics.height); 1.200 + 1.201 + if(h > max_height) { 1.202 + max_height = h; 1.203 + } 1.204 + total_width += FTSZ_TO_PIXELS(face->glyph->metrics.width) + padding; 1.205 + } 1.206 + 1.207 + calc_best_size(total_width, max_height, padding, 1, &gmap->xsz, &gmap->ysz); 1.208 + 1.209 + if(!(gmap->pixels = malloc(gmap->xsz * gmap->ysz))) { 1.210 + free(gmap->glyphs); 1.211 + free(gmap); 1.212 + return 0; 1.213 + } 1.214 + memset(gmap->pixels, 0, gmap->xsz * gmap->ysz); 1.215 + 1.216 + gx = padding; 1.217 + gy = padding; 1.218 + 1.219 + for(i=0; i<gmap->crange; i++) { 1.220 + float gwidth, gheight; 1.221 + unsigned char *src, *dst; 1.222 + FT_GlyphSlot glyph; 1.223 + 1.224 + FT_Load_Char(face, i + cstart, FT_LOAD_RENDER); 1.225 + glyph = face->glyph; 1.226 + gwidth = FTSZ_TO_PIXELS((float)glyph->metrics.width); 1.227 + gheight = FTSZ_TO_PIXELS((float)glyph->metrics.height); 1.228 + 1.229 + if(gx > gmap->xsz - gwidth - padding) { 1.230 + gx = padding; 1.231 + gy += max_height + padding; 1.232 + } 1.233 + 1.234 + src = glyph->bitmap.buffer; 1.235 + dst = gmap->pixels + gy * gmap->xsz + gx; 1.236 + 1.237 + for(j=0; j<glyph->bitmap.rows; j++) { 1.238 + memcpy(dst, src, glyph->bitmap.width); 1.239 + dst += gmap->xsz; 1.240 + src += glyph->bitmap.pitch; 1.241 + } 1.242 + 1.243 + gmap->glyphs[i].code = i; 1.244 + gmap->glyphs[i].x = gx - 1; 1.245 + gmap->glyphs[i].y = gy - 1; 1.246 + gmap->glyphs[i].width = gwidth + 2; 1.247 + gmap->glyphs[i].height = gheight + 2; 1.248 + gmap->glyphs[i].orig_x = -FTSZ_TO_PIXELS((float)glyph->metrics.horiBearingX) + 1; 1.249 + gmap->glyphs[i].orig_y = FTSZ_TO_PIXELS((float)glyph->metrics.height - glyph->metrics.horiBearingY) + 1; 1.250 + gmap->glyphs[i].advance = FTSZ_TO_PIXELS((float)glyph->metrics.horiAdvance); 1.251 + /* also precalc normalized */ 1.252 + gmap->glyphs[i].nx = (float)gmap->glyphs[i].x / (float)gmap->xsz; 1.253 + gmap->glyphs[i].ny = (float)gmap->glyphs[i].y / (float)gmap->ysz; 1.254 + gmap->glyphs[i].nwidth = (float)gmap->glyphs[i].width / (float)gmap->xsz; 1.255 + gmap->glyphs[i].nheight = (float)gmap->glyphs[i].height / (float)gmap->ysz; 1.256 + 1.257 + gx += gwidth + padding; 1.258 + } 1.259 + 1.260 + /* add it to the glyphmaps list of the font */ 1.261 + gmap->next = fnt->gmaps; 1.262 + fnt->gmaps = gmap; 1.263 + 1.264 + return gmap; 1.265 +} 1.266 +#endif /* USE_FREETYPE */ 1.267 + 1.268 +void dtx_free_glyphmap(struct dtx_glyphmap *gmap) 1.269 +{ 1.270 + if(gmap) { 1.271 + free(gmap->pixels); 1.272 + free(gmap->glyphs); 1.273 + free(gmap); 1.274 + } 1.275 +} 1.276 + 1.277 +unsigned char *dtx_get_glyphmap_pixels(struct dtx_glyphmap *gmap) 1.278 +{ 1.279 + return gmap->pixels; 1.280 +} 1.281 + 1.282 +int dtx_get_glyphmap_width(struct dtx_glyphmap *gmap) 1.283 +{ 1.284 + return gmap->xsz; 1.285 +} 1.286 + 1.287 +int dtx_get_glyphmap_height(struct dtx_glyphmap *gmap) 1.288 +{ 1.289 + return gmap->ysz; 1.290 +} 1.291 + 1.292 +struct dtx_glyphmap *dtx_load_glyphmap(const char *fname) 1.293 +{ 1.294 + FILE *fp; 1.295 + struct dtx_glyphmap *gmap; 1.296 + 1.297 + if(!(fp = fopen(fname, "r"))) { 1.298 + return 0; 1.299 + } 1.300 + gmap = dtx_load_glyphmap_stream(fp); 1.301 + fclose(fp); 1.302 + return gmap; 1.303 +} 1.304 + 1.305 +struct dtx_glyphmap *dtx_load_glyphmap_stream(FILE *fp) 1.306 +{ 1.307 + char buf[512]; 1.308 + int hdr_lines = 0; 1.309 + struct dtx_glyphmap *gmap; 1.310 + struct glyph *glyphs = 0; 1.311 + int min_code = INT_MAX; 1.312 + int max_code = INT_MIN; 1.313 + int i, max_pixval, num_pixels; 1.314 + 1.315 + if(!(gmap = calloc(1, sizeof *gmap))) { 1.316 + fperror("failed to allocate glyphmap"); 1.317 + return 0; 1.318 + } 1.319 + 1.320 + while(hdr_lines < 3) { 1.321 + char *line = buf; 1.322 + if(!fgets(buf, sizeof buf, fp)) { 1.323 + fperror("unexpected end of file"); 1.324 + goto err; 1.325 + } 1.326 + 1.327 + while(isspace(*line)) { 1.328 + line++; 1.329 + } 1.330 + 1.331 + if(line[0] == '#') { 1.332 + struct glyph *g; 1.333 + int c; 1.334 + float x, y, xsz, ysz, res; 1.335 + 1.336 + res = sscanf(line + 1, "%d: %fx%f+%f+%f\n", &c, &xsz, &ysz, &x, &y); 1.337 + if(res != 5) { 1.338 + fprintf(stderr, "%s: invalid glyph info line\n", __func__); 1.339 + goto err; 1.340 + } 1.341 + 1.342 + if(!(g = malloc(sizeof *g))) { 1.343 + fperror("failed to allocate glyph"); 1.344 + goto err; 1.345 + } 1.346 + g->code = c; 1.347 + g->x = x; 1.348 + g->y = y; 1.349 + g->width = xsz; 1.350 + g->height = ysz; 1.351 + g->next = glyphs; 1.352 + glyphs = g; 1.353 + 1.354 + if(c < min_code) { 1.355 + min_code = c; 1.356 + } 1.357 + if(c > max_code) { 1.358 + max_code = c; 1.359 + } 1.360 + } else { 1.361 + switch(hdr_lines) { 1.362 + case 0: 1.363 + if(0[line] != 'P' || 1[line] != '6') { 1.364 + fprintf(stderr, "%s: invalid file format (magic)\n", __func__); 1.365 + goto err; 1.366 + } 1.367 + break; 1.368 + 1.369 + case 1: 1.370 + if(sscanf(line, "%d %d", &gmap->xsz, &gmap->ysz) != 2) { 1.371 + fprintf(stderr, "%s: invalid file format (dim)\n", __func__); 1.372 + goto err; 1.373 + } 1.374 + break; 1.375 + 1.376 + case 2: 1.377 + { 1.378 + char *endp; 1.379 + max_pixval = strtol(line, &endp, 10); 1.380 + if(endp == line) { 1.381 + fprintf(stderr, "%s: invalid file format (maxval)\n", __func__); 1.382 + goto err; 1.383 + } 1.384 + } 1.385 + break; 1.386 + 1.387 + default: 1.388 + break; /* can't happen */ 1.389 + } 1.390 + hdr_lines++; 1.391 + } 1.392 + } 1.393 + 1.394 + num_pixels = gmap->xsz * gmap->ysz; 1.395 + if(!(gmap->pixels = malloc(num_pixels))) { 1.396 + fperror("failed to allocate pixels"); 1.397 + goto err; 1.398 + } 1.399 + 1.400 + for(i=0; i<num_pixels; i++) { 1.401 + long c = fgetc(fp); 1.402 + if(c == -1) { 1.403 + fprintf(stderr, "unexpected end of file while reading pixels\n"); 1.404 + goto err; 1.405 + } 1.406 + gmap->pixels[i] = 255 * c / max_pixval; 1.407 + fseek(fp, 2, SEEK_CUR); 1.408 + } 1.409 + 1.410 + gmap->cstart = min_code; 1.411 + gmap->cend = max_code + 1; 1.412 + gmap->crange = gmap->cend - gmap->cstart; 1.413 + 1.414 + if(!(gmap->glyphs = calloc(gmap->crange, sizeof *gmap->glyphs))) { 1.415 + fperror("failed to allocate glyph info"); 1.416 + goto err; 1.417 + } 1.418 + 1.419 + while(glyphs) { 1.420 + struct glyph *g = glyphs; 1.421 + glyphs = glyphs->next; 1.422 + 1.423 + gmap->glyphs[g->code - gmap->cstart] = *g; 1.424 + free(g); 1.425 + } 1.426 + return gmap; 1.427 + 1.428 +err: 1.429 + dtx_free_glyphmap(gmap); 1.430 + while(glyphs) { 1.431 + void *tmp = glyphs; 1.432 + glyphs = glyphs->next; 1.433 + free(tmp); 1.434 + } 1.435 + return 0; 1.436 +} 1.437 + 1.438 +int dtx_save_glyphmap(const char *fname, const struct dtx_glyphmap *gmap) 1.439 +{ 1.440 + FILE *fp; 1.441 + int res; 1.442 + 1.443 + if(!(fp = fopen(fname, "wb"))) { 1.444 + fprintf(stderr, "%s: failed to open file: %s: %s\n", __func__, fname, strerror(errno)); 1.445 + return -1; 1.446 + } 1.447 + res = dtx_save_glyphmap_stream(fp, gmap); 1.448 + fclose(fp); 1.449 + return res; 1.450 +} 1.451 + 1.452 +int dtx_save_glyphmap_stream(FILE *fp, const struct dtx_glyphmap *gmap) 1.453 +{ 1.454 + int i, num_pixels; 1.455 + struct glyph *g = gmap->glyphs; 1.456 + 1.457 + fprintf(fp, "P6\n%d %d\n", gmap->xsz, gmap->ysz); 1.458 + for(i=0; i<gmap->crange; i++) { 1.459 + fprintf(fp, "# %d: %fx%f+%f+%f\n", g->code, g->width, g->height, g->x, g->y); 1.460 + g++; 1.461 + } 1.462 + fprintf(fp, "255\n"); 1.463 + 1.464 + num_pixels = gmap->xsz * gmap->ysz; 1.465 + for(i=0; i<num_pixels; i++) { 1.466 + int c = gmap->pixels[i]; 1.467 + fputc(c, fp); 1.468 + fputc(c, fp); 1.469 + fputc(c, fp); 1.470 + } 1.471 + return 0; 1.472 +} 1.473 + 1.474 + 1.475 +void dtx_use_font(struct dtx_font *fnt, int sz) 1.476 +{ 1.477 + dtx_gl_init(); 1.478 + 1.479 + dtx_font = fnt; 1.480 + dtx_font_sz = sz; 1.481 +} 1.482 + 1.483 +void dtx_glyph_box(int code, struct dtx_box *box) 1.484 +{ 1.485 + int cidx; 1.486 + struct dtx_glyphmap *gmap; 1.487 + gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code); 1.488 + 1.489 + cidx = code - gmap->cstart; 1.490 + 1.491 + box->x = gmap->glyphs[cidx].orig_x; 1.492 + box->y = gmap->glyphs[cidx].orig_y; 1.493 + box->width = gmap->glyphs[cidx].width; 1.494 + box->height = gmap->glyphs[cidx].height; 1.495 +} 1.496 + 1.497 +float dtx_glyph_width(int code) 1.498 +{ 1.499 + struct dtx_box box; 1.500 + dtx_glyph_box(code, &box); 1.501 + return box.width; 1.502 +} 1.503 + 1.504 +float dtx_glyph_height(int code) 1.505 +{ 1.506 + struct dtx_box box; 1.507 + dtx_glyph_box(code, &box); 1.508 + return box.height; 1.509 +} 1.510 + 1.511 +void dtx_string_box(const char *str, struct dtx_box *box) 1.512 +{ 1.513 + int code; 1.514 + float pos_x = 0.0f, pos_y = 0.0f; 1.515 + struct glyph *g = 0; 1.516 + float x0, y0, x1, y1; 1.517 + 1.518 + x0 = y0 = FLT_MAX; 1.519 + x1 = y1 = -FLT_MAX; 1.520 + 1.521 + while(*str) { 1.522 + float px, py; 1.523 + struct dtx_glyphmap *gmap; 1.524 + 1.525 + code = dtx_utf8_char_code(str); 1.526 + str = dtx_utf8_next_char((char*)str); 1.527 + 1.528 + px = pos_x; 1.529 + py = pos_y; 1.530 + 1.531 + if((gmap = dtx_proc_char(code, &pos_x, &pos_y))) { 1.532 + g = gmap->glyphs + code - gmap->cstart; 1.533 + 1.534 + if(px + g->orig_x < x0) { 1.535 + x0 = px + g->orig_x; 1.536 + } 1.537 + if(py - g->orig_y < y0) { 1.538 + y0 = py - g->orig_y; 1.539 + } 1.540 + if(px + g->orig_x + g->width > x1) { 1.541 + x1 = px + g->orig_x + g->width; 1.542 + } 1.543 + if(py - g->orig_y + g->height > y1) { 1.544 + y1 = py - g->orig_y + g->height; 1.545 + } 1.546 + } 1.547 + } 1.548 + 1.549 + box->x = x0; 1.550 + box->y = y0; 1.551 + box->width = x1 - x0; 1.552 + box->height = y1 - y0; 1.553 +} 1.554 + 1.555 +float dtx_string_width(const char *str) 1.556 +{ 1.557 + struct dtx_box box; 1.558 + 1.559 + dtx_string_box(str, &box); 1.560 + return box.width; 1.561 +} 1.562 + 1.563 +float dtx_string_height(const char *str) 1.564 +{ 1.565 + struct dtx_box box; 1.566 + 1.567 + dtx_string_box(str, &box); 1.568 + return box.height; 1.569 +} 1.570 + 1.571 +float dtx_char_pos(const char *str, int n) 1.572 +{ 1.573 + int i; 1.574 + float pos = 0.0; 1.575 + struct dtx_glyphmap *gmap; 1.576 + 1.577 + for(i=0; i<n; i++) { 1.578 + int code = dtx_utf8_char_code(str); 1.579 + str = dtx_utf8_next_char((char*)str); 1.580 + 1.581 + gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code); 1.582 + pos += gmap->glyphs[i].advance; 1.583 + } 1.584 + return pos; 1.585 +} 1.586 + 1.587 +int dtx_char_at_pt(const char *str, float pt) 1.588 +{ 1.589 + int i; 1.590 + float prev_pos = 0.0f, pos = 0.0f; 1.591 + struct dtx_glyphmap *gmap; 1.592 + 1.593 + for(i=0; *str; i++) { 1.594 + int code = dtx_utf8_char_code(str); 1.595 + str = dtx_utf8_next_char((char*)str); 1.596 + 1.597 + gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code); 1.598 + pos += gmap->glyphs[i].advance; 1.599 + 1.600 + if(fabs(pt - prev_pos) < fabs(pt - pos)) { 1.601 + break; 1.602 + } 1.603 + prev_pos = pos; 1.604 + } 1.605 + return i; 1.606 +} 1.607 + 1.608 +struct dtx_glyphmap *dtx_proc_char(int code, float *xpos, float *ypos) 1.609 +{ 1.610 + struct dtx_glyphmap *gmap; 1.611 + gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code); 1.612 + 1.613 + switch(code) { 1.614 + case '\n': 1.615 + *xpos = 0.0; 1.616 + if(gmap) { 1.617 + *ypos -= gmap->line_advance; 1.618 + } 1.619 + return 0; 1.620 + 1.621 + case '\t': 1.622 + if(gmap) { 1.623 + *xpos = (fmod(*xpos, 4.0) + 4.0) * gmap->glyphs[0].advance; 1.624 + } 1.625 + return 0; 1.626 + 1.627 + case '\r': 1.628 + *xpos = 0.0; 1.629 + return 0; 1.630 + 1.631 + default: 1.632 + break; 1.633 + } 1.634 + 1.635 + if(gmap) { 1.636 + *xpos += gmap->glyphs[code - gmap->cstart].advance; 1.637 + } 1.638 + return gmap; 1.639 +} 1.640 + 1.641 +static void calc_best_size(int total_width, int max_glyph_height, int padding, int pow2, int *imgw, int *imgh) 1.642 +{ 1.643 + int xsz, ysz, num_rows; 1.644 + float aspect; 1.645 + 1.646 + for(xsz=2; xsz<=MAX_IMG_WIDTH; xsz *= 2) { 1.647 + num_rows = total_width / xsz + 1; 1.648 + 1.649 + /* take into account the one extra padding for each row after the first */ 1.650 + num_rows = (total_width + padding * (num_rows - 1)) / xsz + 1; 1.651 + 1.652 + ysz = num_rows * (max_glyph_height + padding) + padding; 1.653 + if(pow2) { 1.654 + ysz = next_pow2(ysz); 1.655 + } 1.656 + aspect = (float)xsz / (float)ysz; 1.657 + 1.658 + if(aspect >= 1.0) { 1.659 + break; 1.660 + } 1.661 + } 1.662 + 1.663 + if(xsz > MAX_IMG_WIDTH) { 1.664 + xsz = MAX_IMG_WIDTH; 1.665 + } 1.666 + 1.667 + *imgw = xsz; 1.668 + *imgh = ysz; 1.669 +} 1.670 + 1.671 + 1.672 +static int next_pow2(int x) 1.673 +{ 1.674 + x--; 1.675 + x = (x >> 1) | x; 1.676 + x = (x >> 2) | x; 1.677 + x = (x >> 4) | x; 1.678 + x = (x >> 8) | x; 1.679 + x = (x >> 16) | x; 1.680 + return x + 1; 1.681 +}