├── LICENSE ├── README.md ├── build.sh └── src ├── bitmap.c ├── bitmap.h ├── lib └── stb │ ├── stb_image.c │ ├── stb_image.h │ ├── stb_image_write.c │ ├── stb_image_write.h │ ├── stb_rect_pack.c │ ├── stb_rect_pack.h │ ├── stb_truetype.c │ └── stb_truetype.h ├── limits.h ├── main.c ├── util.c └── util.h /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2016 rxi 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # atlas 2 | A small utility for generating a texture atlas from all the images and truetype 3 | fonts in a directory. 4 | 5 | 6 | ## Basic usage 7 | ```bash 8 | atlas assetdir 9 | ``` 10 | This will pack the images and fonts from `assetdir` and create the file 11 | `out.png`. `out.txt` will also be created, containing a list of all the packed 12 | images and their locations. 13 | 14 | The `-f` argument can be used to specify a custom line format for the text file, 15 | for example, the following might be used for XML: 16 | ```bash 17 | atlas -f "" assetdir 18 | ``` 19 | 20 | Run `atlas --help` for a list of all possible arguments. 21 | 22 | 23 | ## License 24 | This project is free software; you can redistribute it and/or modify it under 25 | the terms of the MIT license. See LICENSE for details. 26 | 27 | The project uses several of the [stb libraries](https://github.com/nothings/stb) 28 | which are in the public domain. 29 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gcc -Wall -Wextra -std=gnu99 -O2 -o atlas\ 4 | src/main.c\ 5 | src/util.c\ 6 | src/bitmap.c\ 7 | src/lib/stb/stb_image.c\ 8 | src/lib/stb/stb_image_write.c\ 9 | src/lib/stb/stb_rect_pack.c\ 10 | src/lib/stb/stb_truetype.c\ 11 | -lm 12 | 13 | strip atlas 14 | -------------------------------------------------------------------------------- /src/bitmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (c) 2016 rxi 3 | ** 4 | ** This project is free software; you can redistribute it and/or modify it 5 | ** under the terms of the MIT license. See LICENSE for details. 6 | **/ 7 | 8 | #include "util.h" 9 | #include "bitmap.h" 10 | 11 | 12 | /* Blits `src` to `dst` at [x,y] with no blending */ 13 | void bitmap_blit(Bitmap *dst, Bitmap *src, int x, int y) { 14 | for (int i = 0; i < src->height; i++) { 15 | int dy = y + i; 16 | if (dy < 0 || dy >= dst->height) continue; 17 | for (int j = 0; j < src->width; j++) { 18 | int dx = x + j; 19 | if (dx < 0 || dx >= dst->width) continue; 20 | dst->data[dx + dy * dst->width] = src->data[i * src->width + j]; 21 | } 22 | } 23 | } 24 | 25 | 26 | /* Blits an 8bit alpha-channel-only buffer to the source, no blending */ 27 | void bitmap_blit8(Bitmap *dst, uint8_t *src, int w, int h, int x, int y) { 28 | for (int i = 0; i < h; i++) { 29 | int dy = y + i; 30 | if (dy < 0 || dy >= dst->height) continue; 31 | for (int j = 0; j < w; j++) { 32 | int dx = x + j; 33 | if (dx < 0 || dx >= dst->width) continue; 34 | dst->data[dx + dy * dst->width] = 0x00ffffff | src[i * w + j] << 24; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/bitmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (c) 2016 rxi 3 | ** 4 | ** This project is free software; you can redistribute it and/or modify it 5 | ** under the terms of the MIT license. See LICENSE for details. 6 | **/ 7 | 8 | #ifndef BITMAP_H 9 | #define BITMAP_H 10 | 11 | #include 12 | 13 | typedef struct { 14 | uint32_t *data; 15 | int width, height; 16 | } Bitmap; 17 | 18 | void bitmap_blit(Bitmap *dst, Bitmap *src, int x, int y); 19 | void bitmap_blit8(Bitmap *dst, uint8_t *src, int w, int h, int x, int y); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/lib/stb/stb_image.c: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #include "stb_image.h" 3 | -------------------------------------------------------------------------------- /src/lib/stb/stb_image_write.c: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_WRITE_IMPLEMENTATION 2 | #include "stb_image_write.h" 3 | -------------------------------------------------------------------------------- /src/lib/stb/stb_image_write.h: -------------------------------------------------------------------------------- 1 | /* stb_image_write - v1.02 - public domain - http://nothings.org/stb/stb_image_write.h 2 | writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015 3 | no warranty implied; use at your own risk 4 | 5 | Before #including, 6 | 7 | #define STB_IMAGE_WRITE_IMPLEMENTATION 8 | 9 | in the file that you want to have the implementation. 10 | 11 | Will probably not work correctly with strict-aliasing optimizations. 12 | 13 | ABOUT: 14 | 15 | This header file is a library for writing images to C stdio. It could be 16 | adapted to write to memory or a general streaming interface; let me know. 17 | 18 | The PNG output is not optimal; it is 20-50% larger than the file 19 | written by a decent optimizing implementation. This library is designed 20 | for source code compactness and simplicity, not optimal image file size 21 | or run-time performance. 22 | 23 | BUILDING: 24 | 25 | You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. 26 | You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace 27 | malloc,realloc,free. 28 | You can define STBIW_MEMMOVE() to replace memmove() 29 | 30 | USAGE: 31 | 32 | There are four functions, one for each image file format: 33 | 34 | int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 35 | int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 36 | int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 37 | int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); 38 | 39 | There are also four equivalent functions that use an arbitrary write function. You are 40 | expected to open/close your file-equivalent before and after calling these: 41 | 42 | int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); 43 | int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 44 | int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 45 | int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); 46 | 47 | where the callback is: 48 | void stbi_write_func(void *context, void *data, int size); 49 | 50 | You can define STBI_WRITE_NO_STDIO to disable the file variant of these 51 | functions, so the library will not use stdio.h at all. However, this will 52 | also disable HDR writing, because it requires stdio for formatted output. 53 | 54 | Each function returns 0 on failure and non-0 on success. 55 | 56 | The functions create an image file defined by the parameters. The image 57 | is a rectangle of pixels stored from left-to-right, top-to-bottom. 58 | Each pixel contains 'comp' channels of data stored interleaved with 8-bits 59 | per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is 60 | monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. 61 | The *data pointer points to the first byte of the top-left-most pixel. 62 | For PNG, "stride_in_bytes" is the distance in bytes from the first byte of 63 | a row of pixels to the first byte of the next row of pixels. 64 | 65 | PNG creates output files with the same number of components as the input. 66 | The BMP format expands Y to RGB in the file format and does not 67 | output alpha. 68 | 69 | PNG supports writing rectangles of data even when the bytes storing rows of 70 | data are not consecutive in memory (e.g. sub-rectangles of a larger image), 71 | by supplying the stride between the beginning of adjacent rows. The other 72 | formats do not. (Thus you cannot write a native-format BMP through the BMP 73 | writer, both because it is in BGR order and because it may have padding 74 | at the end of the line.) 75 | 76 | HDR expects linear float data. Since the format is always 32-bit rgb(e) 77 | data, alpha (if provided) is discarded, and for monochrome data it is 78 | replicated across all three channels. 79 | 80 | TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed 81 | data, set the global variable 'stbi_write_tga_with_rle' to 0. 82 | 83 | CREDITS: 84 | 85 | PNG/BMP/TGA 86 | Sean Barrett 87 | HDR 88 | Baldur Karlsson 89 | TGA monochrome: 90 | Jean-Sebastien Guay 91 | misc enhancements: 92 | Tim Kelsey 93 | TGA RLE 94 | Alan Hickman 95 | initial file IO callback implementation 96 | Emmanuel Julien 97 | bugfixes: 98 | github:Chribba 99 | Guillaume Chereau 100 | github:jry2 101 | github:romigrou 102 | Sergio Gonzalez 103 | Jonas Karlsson 104 | Filip Wasil 105 | Thatcher Ulrich 106 | 107 | LICENSE 108 | 109 | This software is dual-licensed to the public domain and under the following 110 | license: you are granted a perpetual, irrevocable license to copy, modify, 111 | publish, and distribute this file as you see fit. 112 | 113 | */ 114 | 115 | #ifndef INCLUDE_STB_IMAGE_WRITE_H 116 | #define INCLUDE_STB_IMAGE_WRITE_H 117 | 118 | #ifdef __cplusplus 119 | extern "C" { 120 | #endif 121 | 122 | #ifdef STB_IMAGE_WRITE_STATIC 123 | #define STBIWDEF static 124 | #else 125 | #define STBIWDEF extern 126 | extern int stbi_write_tga_with_rle; 127 | #endif 128 | 129 | #ifndef STBI_WRITE_NO_STDIO 130 | STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 131 | STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 132 | STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 133 | STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); 134 | #endif 135 | 136 | typedef void stbi_write_func(void *context, void *data, int size); 137 | 138 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); 139 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 140 | STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 141 | STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif 146 | 147 | #endif//INCLUDE_STB_IMAGE_WRITE_H 148 | 149 | #ifdef STB_IMAGE_WRITE_IMPLEMENTATION 150 | 151 | #ifdef _WIN32 152 | #ifndef _CRT_SECURE_NO_WARNINGS 153 | #define _CRT_SECURE_NO_WARNINGS 154 | #endif 155 | #ifndef _CRT_NONSTDC_NO_DEPRECATE 156 | #define _CRT_NONSTDC_NO_DEPRECATE 157 | #endif 158 | #endif 159 | 160 | #ifndef STBI_WRITE_NO_STDIO 161 | #include 162 | #endif // STBI_WRITE_NO_STDIO 163 | 164 | #include 165 | #include 166 | #include 167 | #include 168 | 169 | #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) 170 | // ok 171 | #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) 172 | // ok 173 | #else 174 | #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." 175 | #endif 176 | 177 | #ifndef STBIW_MALLOC 178 | #define STBIW_MALLOC(sz) malloc(sz) 179 | #define STBIW_REALLOC(p,newsz) realloc(p,newsz) 180 | #define STBIW_FREE(p) free(p) 181 | #endif 182 | 183 | #ifndef STBIW_REALLOC_SIZED 184 | #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) 185 | #endif 186 | 187 | 188 | #ifndef STBIW_MEMMOVE 189 | #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) 190 | #endif 191 | 192 | 193 | #ifndef STBIW_ASSERT 194 | #include 195 | #define STBIW_ASSERT(x) assert(x) 196 | #endif 197 | 198 | #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) 199 | 200 | typedef struct 201 | { 202 | stbi_write_func *func; 203 | void *context; 204 | } stbi__write_context; 205 | 206 | // initialize a callback-based context 207 | static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) 208 | { 209 | s->func = c; 210 | s->context = context; 211 | } 212 | 213 | #ifndef STBI_WRITE_NO_STDIO 214 | 215 | static void stbi__stdio_write(void *context, void *data, int size) 216 | { 217 | fwrite(data,1,size,(FILE*) context); 218 | } 219 | 220 | static int stbi__start_write_file(stbi__write_context *s, const char *filename) 221 | { 222 | FILE *f = fopen(filename, "wb"); 223 | stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); 224 | return f != NULL; 225 | } 226 | 227 | static void stbi__end_write_file(stbi__write_context *s) 228 | { 229 | fclose((FILE *)s->context); 230 | } 231 | 232 | #endif // !STBI_WRITE_NO_STDIO 233 | 234 | typedef unsigned int stbiw_uint32; 235 | typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; 236 | 237 | #ifdef STB_IMAGE_WRITE_STATIC 238 | static int stbi_write_tga_with_rle = 1; 239 | #else 240 | int stbi_write_tga_with_rle = 1; 241 | #endif 242 | 243 | static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) 244 | { 245 | while (*fmt) { 246 | switch (*fmt++) { 247 | case ' ': break; 248 | case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); 249 | s->func(s->context,&x,1); 250 | break; } 251 | case '2': { int x = va_arg(v,int); 252 | unsigned char b[2]; 253 | b[0] = STBIW_UCHAR(x); 254 | b[1] = STBIW_UCHAR(x>>8); 255 | s->func(s->context,b,2); 256 | break; } 257 | case '4': { stbiw_uint32 x = va_arg(v,int); 258 | unsigned char b[4]; 259 | b[0]=STBIW_UCHAR(x); 260 | b[1]=STBIW_UCHAR(x>>8); 261 | b[2]=STBIW_UCHAR(x>>16); 262 | b[3]=STBIW_UCHAR(x>>24); 263 | s->func(s->context,b,4); 264 | break; } 265 | default: 266 | STBIW_ASSERT(0); 267 | return; 268 | } 269 | } 270 | } 271 | 272 | static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) 273 | { 274 | va_list v; 275 | va_start(v, fmt); 276 | stbiw__writefv(s, fmt, v); 277 | va_end(v); 278 | } 279 | 280 | static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) 281 | { 282 | unsigned char arr[3]; 283 | arr[0] = a, arr[1] = b, arr[2] = c; 284 | s->func(s->context, arr, 3); 285 | } 286 | 287 | static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) 288 | { 289 | unsigned char bg[3] = { 255, 0, 255}, px[3]; 290 | int k; 291 | 292 | if (write_alpha < 0) 293 | s->func(s->context, &d[comp - 1], 1); 294 | 295 | switch (comp) { 296 | case 1: 297 | s->func(s->context,d,1); 298 | break; 299 | case 2: 300 | if (expand_mono) 301 | stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp 302 | else 303 | s->func(s->context, d, 1); // monochrome TGA 304 | break; 305 | case 4: 306 | if (!write_alpha) { 307 | // composite against pink background 308 | for (k = 0; k < 3; ++k) 309 | px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; 310 | stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); 311 | break; 312 | } 313 | /* FALLTHROUGH */ 314 | case 3: 315 | stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); 316 | break; 317 | } 318 | if (write_alpha > 0) 319 | s->func(s->context, &d[comp - 1], 1); 320 | } 321 | 322 | static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) 323 | { 324 | stbiw_uint32 zero = 0; 325 | int i,j, j_end; 326 | 327 | if (y <= 0) 328 | return; 329 | 330 | if (vdir < 0) 331 | j_end = -1, j = y-1; 332 | else 333 | j_end = y, j = 0; 334 | 335 | for (; j != j_end; j += vdir) { 336 | for (i=0; i < x; ++i) { 337 | unsigned char *d = (unsigned char *) data + (j*x+i)*comp; 338 | stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); 339 | } 340 | s->func(s->context, &zero, scanline_pad); 341 | } 342 | } 343 | 344 | static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) 345 | { 346 | if (y < 0 || x < 0) { 347 | return 0; 348 | } else { 349 | va_list v; 350 | va_start(v, fmt); 351 | stbiw__writefv(s, fmt, v); 352 | va_end(v); 353 | stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); 354 | return 1; 355 | } 356 | } 357 | 358 | static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) 359 | { 360 | int pad = (-x*3) & 3; 361 | return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, 362 | "11 4 22 4" "4 44 22 444444", 363 | 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header 364 | 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header 365 | } 366 | 367 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) 368 | { 369 | stbi__write_context s; 370 | stbi__start_write_callbacks(&s, func, context); 371 | return stbi_write_bmp_core(&s, x, y, comp, data); 372 | } 373 | 374 | #ifndef STBI_WRITE_NO_STDIO 375 | STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) 376 | { 377 | stbi__write_context s; 378 | if (stbi__start_write_file(&s,filename)) { 379 | int r = stbi_write_bmp_core(&s, x, y, comp, data); 380 | stbi__end_write_file(&s); 381 | return r; 382 | } else 383 | return 0; 384 | } 385 | #endif //!STBI_WRITE_NO_STDIO 386 | 387 | static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) 388 | { 389 | int has_alpha = (comp == 2 || comp == 4); 390 | int colorbytes = has_alpha ? comp-1 : comp; 391 | int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 392 | 393 | if (y < 0 || x < 0) 394 | return 0; 395 | 396 | if (!stbi_write_tga_with_rle) { 397 | return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, 398 | "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); 399 | } else { 400 | int i,j,k; 401 | 402 | stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); 403 | 404 | for (j = y - 1; j >= 0; --j) { 405 | unsigned char *row = (unsigned char *) data + j * x * comp; 406 | int len; 407 | 408 | for (i = 0; i < x; i += len) { 409 | unsigned char *begin = row + i * comp; 410 | int diff = 1; 411 | len = 1; 412 | 413 | if (i < x - 1) { 414 | ++len; 415 | diff = memcmp(begin, row + (i + 1) * comp, comp); 416 | if (diff) { 417 | const unsigned char *prev = begin; 418 | for (k = i + 2; k < x && len < 128; ++k) { 419 | if (memcmp(prev, row + k * comp, comp)) { 420 | prev += comp; 421 | ++len; 422 | } else { 423 | --len; 424 | break; 425 | } 426 | } 427 | } else { 428 | for (k = i + 2; k < x && len < 128; ++k) { 429 | if (!memcmp(begin, row + k * comp, comp)) { 430 | ++len; 431 | } else { 432 | break; 433 | } 434 | } 435 | } 436 | } 437 | 438 | if (diff) { 439 | unsigned char header = STBIW_UCHAR(len - 1); 440 | s->func(s->context, &header, 1); 441 | for (k = 0; k < len; ++k) { 442 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); 443 | } 444 | } else { 445 | unsigned char header = STBIW_UCHAR(len - 129); 446 | s->func(s->context, &header, 1); 447 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); 448 | } 449 | } 450 | } 451 | } 452 | return 1; 453 | } 454 | 455 | int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) 456 | { 457 | stbi__write_context s; 458 | stbi__start_write_callbacks(&s, func, context); 459 | return stbi_write_tga_core(&s, x, y, comp, (void *) data); 460 | } 461 | 462 | #ifndef STBI_WRITE_NO_STDIO 463 | int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) 464 | { 465 | stbi__write_context s; 466 | if (stbi__start_write_file(&s,filename)) { 467 | int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); 468 | stbi__end_write_file(&s); 469 | return r; 470 | } else 471 | return 0; 472 | } 473 | #endif 474 | 475 | // ************************************************************************************************* 476 | // Radiance RGBE HDR writer 477 | // by Baldur Karlsson 478 | #ifndef STBI_WRITE_NO_STDIO 479 | 480 | #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) 481 | 482 | void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) 483 | { 484 | int exponent; 485 | float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); 486 | 487 | if (maxcomp < 1e-32f) { 488 | rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; 489 | } else { 490 | float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; 491 | 492 | rgbe[0] = (unsigned char)(linear[0] * normalize); 493 | rgbe[1] = (unsigned char)(linear[1] * normalize); 494 | rgbe[2] = (unsigned char)(linear[2] * normalize); 495 | rgbe[3] = (unsigned char)(exponent + 128); 496 | } 497 | } 498 | 499 | void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) 500 | { 501 | unsigned char lengthbyte = STBIW_UCHAR(length+128); 502 | STBIW_ASSERT(length+128 <= 255); 503 | s->func(s->context, &lengthbyte, 1); 504 | s->func(s->context, &databyte, 1); 505 | } 506 | 507 | void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) 508 | { 509 | unsigned char lengthbyte = STBIW_UCHAR(length); 510 | STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code 511 | s->func(s->context, &lengthbyte, 1); 512 | s->func(s->context, data, length); 513 | } 514 | 515 | void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) 516 | { 517 | unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; 518 | unsigned char rgbe[4]; 519 | float linear[3]; 520 | int x; 521 | 522 | scanlineheader[2] = (width&0xff00)>>8; 523 | scanlineheader[3] = (width&0x00ff); 524 | 525 | /* skip RLE for images too small or large */ 526 | if (width < 8 || width >= 32768) { 527 | for (x=0; x < width; x++) { 528 | switch (ncomp) { 529 | case 4: /* fallthrough */ 530 | case 3: linear[2] = scanline[x*ncomp + 2]; 531 | linear[1] = scanline[x*ncomp + 1]; 532 | linear[0] = scanline[x*ncomp + 0]; 533 | break; 534 | default: 535 | linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; 536 | break; 537 | } 538 | stbiw__linear_to_rgbe(rgbe, linear); 539 | s->func(s->context, rgbe, 4); 540 | } 541 | } else { 542 | int c,r; 543 | /* encode into scratch buffer */ 544 | for (x=0; x < width; x++) { 545 | switch(ncomp) { 546 | case 4: /* fallthrough */ 547 | case 3: linear[2] = scanline[x*ncomp + 2]; 548 | linear[1] = scanline[x*ncomp + 1]; 549 | linear[0] = scanline[x*ncomp + 0]; 550 | break; 551 | default: 552 | linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; 553 | break; 554 | } 555 | stbiw__linear_to_rgbe(rgbe, linear); 556 | scratch[x + width*0] = rgbe[0]; 557 | scratch[x + width*1] = rgbe[1]; 558 | scratch[x + width*2] = rgbe[2]; 559 | scratch[x + width*3] = rgbe[3]; 560 | } 561 | 562 | s->func(s->context, scanlineheader, 4); 563 | 564 | /* RLE each component separately */ 565 | for (c=0; c < 4; c++) { 566 | unsigned char *comp = &scratch[width*c]; 567 | 568 | x = 0; 569 | while (x < width) { 570 | // find first run 571 | r = x; 572 | while (r+2 < width) { 573 | if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) 574 | break; 575 | ++r; 576 | } 577 | if (r+2 >= width) 578 | r = width; 579 | // dump up to first run 580 | while (x < r) { 581 | int len = r-x; 582 | if (len > 128) len = 128; 583 | stbiw__write_dump_data(s, len, &comp[x]); 584 | x += len; 585 | } 586 | // if there's a run, output it 587 | if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd 588 | // find next byte after run 589 | while (r < width && comp[r] == comp[x]) 590 | ++r; 591 | // output run up to r 592 | while (x < r) { 593 | int len = r-x; 594 | if (len > 127) len = 127; 595 | stbiw__write_run_data(s, len, comp[x]); 596 | x += len; 597 | } 598 | } 599 | } 600 | } 601 | } 602 | } 603 | 604 | static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) 605 | { 606 | if (y <= 0 || x <= 0 || data == NULL) 607 | return 0; 608 | else { 609 | // Each component is stored separately. Allocate scratch space for full output scanline. 610 | unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); 611 | int i, len; 612 | char buffer[128]; 613 | char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; 614 | s->func(s->context, header, sizeof(header)-1); 615 | 616 | len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); 617 | s->func(s->context, buffer, len); 618 | 619 | for(i=0; i < y; i++) 620 | stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); 621 | STBIW_FREE(scratch); 622 | return 1; 623 | } 624 | } 625 | 626 | int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) 627 | { 628 | stbi__write_context s; 629 | stbi__start_write_callbacks(&s, func, context); 630 | return stbi_write_hdr_core(&s, x, y, comp, (float *) data); 631 | } 632 | 633 | int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) 634 | { 635 | stbi__write_context s; 636 | if (stbi__start_write_file(&s,filename)) { 637 | int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); 638 | stbi__end_write_file(&s); 639 | return r; 640 | } else 641 | return 0; 642 | } 643 | #endif // STBI_WRITE_NO_STDIO 644 | 645 | 646 | ////////////////////////////////////////////////////////////////////////////// 647 | // 648 | // PNG writer 649 | // 650 | 651 | // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() 652 | #define stbiw__sbraw(a) ((int *) (a) - 2) 653 | #define stbiw__sbm(a) stbiw__sbraw(a)[0] 654 | #define stbiw__sbn(a) stbiw__sbraw(a)[1] 655 | 656 | #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) 657 | #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) 658 | #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) 659 | 660 | #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) 661 | #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) 662 | #define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) 663 | 664 | static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) 665 | { 666 | int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; 667 | void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); 668 | STBIW_ASSERT(p); 669 | if (p) { 670 | if (!*arr) ((int *) p)[1] = 0; 671 | *arr = (void *) ((int *) p + 2); 672 | stbiw__sbm(*arr) = m; 673 | } 674 | return *arr; 675 | } 676 | 677 | static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) 678 | { 679 | while (*bitcount >= 8) { 680 | stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); 681 | *bitbuffer >>= 8; 682 | *bitcount -= 8; 683 | } 684 | return data; 685 | } 686 | 687 | static int stbiw__zlib_bitrev(int code, int codebits) 688 | { 689 | int res=0; 690 | while (codebits--) { 691 | res = (res << 1) | (code & 1); 692 | code >>= 1; 693 | } 694 | return res; 695 | } 696 | 697 | static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) 698 | { 699 | int i; 700 | for (i=0; i < limit && i < 258; ++i) 701 | if (a[i] != b[i]) break; 702 | return i; 703 | } 704 | 705 | static unsigned int stbiw__zhash(unsigned char *data) 706 | { 707 | stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); 708 | hash ^= hash << 3; 709 | hash += hash >> 5; 710 | hash ^= hash << 4; 711 | hash += hash >> 17; 712 | hash ^= hash << 25; 713 | hash += hash >> 6; 714 | return hash; 715 | } 716 | 717 | #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) 718 | #define stbiw__zlib_add(code,codebits) \ 719 | (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) 720 | #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) 721 | // default huffman tables 722 | #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) 723 | #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) 724 | #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) 725 | #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) 726 | #define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) 727 | #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) 728 | 729 | #define stbiw__ZHASH 16384 730 | 731 | unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) 732 | { 733 | static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; 734 | static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; 735 | static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; 736 | static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; 737 | unsigned int bitbuf=0; 738 | int i,j, bitcount=0; 739 | unsigned char *out = NULL; 740 | unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); 741 | if (quality < 5) quality = 5; 742 | 743 | stbiw__sbpush(out, 0x78); // DEFLATE 32K window 744 | stbiw__sbpush(out, 0x5e); // FLEVEL = 1 745 | stbiw__zlib_add(1,1); // BFINAL = 1 746 | stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman 747 | 748 | for (i=0; i < stbiw__ZHASH; ++i) 749 | hash_table[i] = NULL; 750 | 751 | i=0; 752 | while (i < data_len-3) { 753 | // hash next 3 bytes of data to be compressed 754 | int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; 755 | unsigned char *bestloc = 0; 756 | unsigned char **hlist = hash_table[h]; 757 | int n = stbiw__sbcount(hlist); 758 | for (j=0; j < n; ++j) { 759 | if (hlist[j]-data > i-32768) { // if entry lies within window 760 | int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); 761 | if (d >= best) best=d,bestloc=hlist[j]; 762 | } 763 | } 764 | // when hash table entry is too long, delete half the entries 765 | if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { 766 | STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); 767 | stbiw__sbn(hash_table[h]) = quality; 768 | } 769 | stbiw__sbpush(hash_table[h],data+i); 770 | 771 | if (bestloc) { 772 | // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal 773 | h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); 774 | hlist = hash_table[h]; 775 | n = stbiw__sbcount(hlist); 776 | for (j=0; j < n; ++j) { 777 | if (hlist[j]-data > i-32767) { 778 | int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); 779 | if (e > best) { // if next match is better, bail on current match 780 | bestloc = NULL; 781 | break; 782 | } 783 | } 784 | } 785 | } 786 | 787 | if (bestloc) { 788 | int d = (int) (data+i - bestloc); // distance back 789 | STBIW_ASSERT(d <= 32767 && best <= 258); 790 | for (j=0; best > lengthc[j+1]-1; ++j); 791 | stbiw__zlib_huff(j+257); 792 | if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); 793 | for (j=0; d > distc[j+1]-1; ++j); 794 | stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); 795 | if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); 796 | i += best; 797 | } else { 798 | stbiw__zlib_huffb(data[i]); 799 | ++i; 800 | } 801 | } 802 | // write out final bytes 803 | for (;i < data_len; ++i) 804 | stbiw__zlib_huffb(data[i]); 805 | stbiw__zlib_huff(256); // end of block 806 | // pad with 0 bits to byte boundary 807 | while (bitcount) 808 | stbiw__zlib_add(0,1); 809 | 810 | for (i=0; i < stbiw__ZHASH; ++i) 811 | (void) stbiw__sbfree(hash_table[i]); 812 | STBIW_FREE(hash_table); 813 | 814 | { 815 | // compute adler32 on input 816 | unsigned int s1=1, s2=0; 817 | int blocklen = (int) (data_len % 5552); 818 | j=0; 819 | while (j < data_len) { 820 | for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; 821 | s1 %= 65521, s2 %= 65521; 822 | j += blocklen; 823 | blocklen = 5552; 824 | } 825 | stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); 826 | stbiw__sbpush(out, STBIW_UCHAR(s2)); 827 | stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); 828 | stbiw__sbpush(out, STBIW_UCHAR(s1)); 829 | } 830 | *out_len = stbiw__sbn(out); 831 | // make returned pointer freeable 832 | STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); 833 | return (unsigned char *) stbiw__sbraw(out); 834 | } 835 | 836 | static unsigned int stbiw__crc32(unsigned char *buffer, int len) 837 | { 838 | static unsigned int crc_table[256] = 839 | { 840 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 841 | 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 842 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 843 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 844 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 845 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 846 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 847 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 848 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 849 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 850 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 851 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 852 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 853 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 854 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 855 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 856 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 857 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 858 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 859 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 860 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 861 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 862 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 863 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 864 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 865 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 866 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 867 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 868 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 869 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 870 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 871 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 872 | }; 873 | 874 | unsigned int crc = ~0u; 875 | int i; 876 | for (i=0; i < len; ++i) 877 | crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; 878 | return ~crc; 879 | } 880 | 881 | #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) 882 | #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); 883 | #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) 884 | 885 | static void stbiw__wpcrc(unsigned char **data, int len) 886 | { 887 | unsigned int crc = stbiw__crc32(*data - len - 4, len+4); 888 | stbiw__wp32(*data, crc); 889 | } 890 | 891 | static unsigned char stbiw__paeth(int a, int b, int c) 892 | { 893 | int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); 894 | if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); 895 | if (pb <= pc) return STBIW_UCHAR(b); 896 | return STBIW_UCHAR(c); 897 | } 898 | 899 | unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) 900 | { 901 | int ctype[5] = { -1, 0, 4, 2, 6 }; 902 | unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; 903 | unsigned char *out,*o, *filt, *zlib; 904 | signed char *line_buffer; 905 | int i,j,k,p,zlen; 906 | 907 | if (stride_bytes == 0) 908 | stride_bytes = x * n; 909 | 910 | filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; 911 | line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } 912 | for (j=0; j < y; ++j) { 913 | static int mapping[] = { 0,1,2,3,4 }; 914 | static int firstmap[] = { 0,1,0,5,6 }; 915 | int *mymap = j ? mapping : firstmap; 916 | int best = 0, bestval = 0x7fffffff; 917 | for (p=0; p < 2; ++p) { 918 | for (k= p?best:0; k < 5; ++k) { 919 | int type = mymap[k],est=0; 920 | unsigned char *z = pixels + stride_bytes*j; 921 | for (i=0; i < n; ++i) 922 | switch (type) { 923 | case 0: line_buffer[i] = z[i]; break; 924 | case 1: line_buffer[i] = z[i]; break; 925 | case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; 926 | case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; 927 | case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break; 928 | case 5: line_buffer[i] = z[i]; break; 929 | case 6: line_buffer[i] = z[i]; break; 930 | } 931 | for (i=n; i < x*n; ++i) { 932 | switch (type) { 933 | case 0: line_buffer[i] = z[i]; break; 934 | case 1: line_buffer[i] = z[i] - z[i-n]; break; 935 | case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; 936 | case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; 937 | case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; 938 | case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; 939 | case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; 940 | } 941 | } 942 | if (p) break; 943 | for (i=0; i < x*n; ++i) 944 | est += abs((signed char) line_buffer[i]); 945 | if (est < bestval) { bestval = est; best = k; } 946 | } 947 | } 948 | // when we get here, best contains the filter type, and line_buffer contains the data 949 | filt[j*(x*n+1)] = (unsigned char) best; 950 | STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); 951 | } 952 | STBIW_FREE(line_buffer); 953 | zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory 954 | STBIW_FREE(filt); 955 | if (!zlib) return 0; 956 | 957 | // each tag requires 12 bytes of overhead 958 | out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); 959 | if (!out) return 0; 960 | *out_len = 8 + 12+13 + 12+zlen + 12; 961 | 962 | o=out; 963 | STBIW_MEMMOVE(o,sig,8); o+= 8; 964 | stbiw__wp32(o, 13); // header length 965 | stbiw__wptag(o, "IHDR"); 966 | stbiw__wp32(o, x); 967 | stbiw__wp32(o, y); 968 | *o++ = 8; 969 | *o++ = STBIW_UCHAR(ctype[n]); 970 | *o++ = 0; 971 | *o++ = 0; 972 | *o++ = 0; 973 | stbiw__wpcrc(&o,13); 974 | 975 | stbiw__wp32(o, zlen); 976 | stbiw__wptag(o, "IDAT"); 977 | STBIW_MEMMOVE(o, zlib, zlen); 978 | o += zlen; 979 | STBIW_FREE(zlib); 980 | stbiw__wpcrc(&o, zlen); 981 | 982 | stbiw__wp32(o,0); 983 | stbiw__wptag(o, "IEND"); 984 | stbiw__wpcrc(&o,0); 985 | 986 | STBIW_ASSERT(o == out + *out_len); 987 | 988 | return out; 989 | } 990 | 991 | #ifndef STBI_WRITE_NO_STDIO 992 | STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) 993 | { 994 | FILE *f; 995 | int len; 996 | unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); 997 | if (png == NULL) return 0; 998 | f = fopen(filename, "wb"); 999 | if (!f) { STBIW_FREE(png); return 0; } 1000 | fwrite(png, 1, len, f); 1001 | fclose(f); 1002 | STBIW_FREE(png); 1003 | return 1; 1004 | } 1005 | #endif 1006 | 1007 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) 1008 | { 1009 | int len; 1010 | unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); 1011 | if (png == NULL) return 0; 1012 | func(context, png, len); 1013 | STBIW_FREE(png); 1014 | return 1; 1015 | } 1016 | 1017 | #endif // STB_IMAGE_WRITE_IMPLEMENTATION 1018 | 1019 | /* Revision history 1020 | 1.02 (2016-04-02) 1021 | avoid allocating large structures on the stack 1022 | 1.01 (2016-01-16) 1023 | STBIW_REALLOC_SIZED: support allocators with no realloc support 1024 | avoid race-condition in crc initialization 1025 | minor compile issues 1026 | 1.00 (2015-09-14) 1027 | installable file IO function 1028 | 0.99 (2015-09-13) 1029 | warning fixes; TGA rle support 1030 | 0.98 (2015-04-08) 1031 | added STBIW_MALLOC, STBIW_ASSERT etc 1032 | 0.97 (2015-01-18) 1033 | fixed HDR asserts, rewrote HDR rle logic 1034 | 0.96 (2015-01-17) 1035 | add HDR output 1036 | fix monochrome BMP 1037 | 0.95 (2014-08-17) 1038 | add monochrome TGA output 1039 | 0.94 (2014-05-31) 1040 | rename private functions to avoid conflicts with stb_image.h 1041 | 0.93 (2014-05-27) 1042 | warning fixes 1043 | 0.92 (2010-08-01) 1044 | casts to unsigned char to fix warnings 1045 | 0.91 (2010-07-17) 1046 | first public release 1047 | 0.90 first internal release 1048 | */ 1049 | -------------------------------------------------------------------------------- /src/lib/stb/stb_rect_pack.c: -------------------------------------------------------------------------------- 1 | #define STB_RECT_PACK_IMPLEMENTATION 2 | #include "stb_rect_pack.h" 3 | -------------------------------------------------------------------------------- /src/lib/stb/stb_rect_pack.h: -------------------------------------------------------------------------------- 1 | // stb_rect_pack.h - v0.10 - public domain - rectangle packing 2 | // Sean Barrett 2014 3 | // 4 | // Useful for e.g. packing rectangular textures into an atlas. 5 | // Does not do rotation. 6 | // 7 | // Not necessarily the awesomest packing method, but better than 8 | // the totally naive one in stb_truetype (which is primarily what 9 | // this is meant to replace). 10 | // 11 | // Has only had a few tests run, may have issues. 12 | // 13 | // More docs to come. 14 | // 15 | // No memory allocations; uses qsort() and assert() from stdlib. 16 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 17 | // 18 | // This library currently uses the Skyline Bottom-Left algorithm. 19 | // 20 | // Please note: better rectangle packers are welcome! Please 21 | // implement them to the same API, but with a different init 22 | // function. 23 | // 24 | // Credits 25 | // 26 | // Library 27 | // Sean Barrett 28 | // Minor features 29 | // Martins Mozeiko 30 | // Bugfixes / warning fixes 31 | // Jeremy Jaussaud 32 | // 33 | // Version history: 34 | // 35 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 36 | // 0.09 (2016-08-27) fix compiler warnings 37 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 38 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 39 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 40 | // 0.05: added STBRP_ASSERT to allow replacing assert 41 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 42 | // 0.01: initial release 43 | // 44 | // LICENSE 45 | // 46 | // This software is dual-licensed to the public domain and under the following 47 | // license: you are granted a perpetual, irrevocable license to copy, modify, 48 | // publish, and distribute this file as you see fit. 49 | 50 | ////////////////////////////////////////////////////////////////////////////// 51 | // 52 | // INCLUDE SECTION 53 | // 54 | 55 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 56 | #define STB_INCLUDE_STB_RECT_PACK_H 57 | 58 | #define STB_RECT_PACK_VERSION 1 59 | 60 | #ifdef STBRP_STATIC 61 | #define STBRP_DEF static 62 | #else 63 | #define STBRP_DEF extern 64 | #endif 65 | 66 | #ifdef __cplusplus 67 | extern "C" { 68 | #endif 69 | 70 | typedef struct stbrp_context stbrp_context; 71 | typedef struct stbrp_node stbrp_node; 72 | typedef struct stbrp_rect stbrp_rect; 73 | 74 | #ifdef STBRP_LARGE_RECTS 75 | typedef int stbrp_coord; 76 | #else 77 | typedef unsigned short stbrp_coord; 78 | #endif 79 | 80 | STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 81 | // Assign packed locations to rectangles. The rectangles are of type 82 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 83 | // are 'num_rects' many of them. 84 | // 85 | // Rectangles which are successfully packed have the 'was_packed' flag 86 | // set to a non-zero value and 'x' and 'y' store the minimum location 87 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 88 | // if you imagine y increasing downwards). Rectangles which do not fit 89 | // have the 'was_packed' flag set to 0. 90 | // 91 | // You should not try to access the 'rects' array from another thread 92 | // while this function is running, as the function temporarily reorders 93 | // the array while it executes. 94 | // 95 | // To pack into another rectangle, you need to call stbrp_init_target 96 | // again. To continue packing into the same rectangle, you can call 97 | // this function again. Calling this multiple times with multiple rect 98 | // arrays will probably produce worse packing results than calling it 99 | // a single time with the full rectangle array, but the option is 100 | // available. 101 | 102 | struct stbrp_rect 103 | { 104 | // reserved for your use: 105 | int id; 106 | 107 | // input: 108 | stbrp_coord w, h; 109 | 110 | // output: 111 | stbrp_coord x, y; 112 | int was_packed; // non-zero if valid packing 113 | 114 | }; // 16 bytes, nominally 115 | 116 | 117 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 118 | // Initialize a rectangle packer to: 119 | // pack a rectangle that is 'width' by 'height' in dimensions 120 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 121 | // 122 | // You must call this function every time you start packing into a new target. 123 | // 124 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 125 | // the following stbrp_pack_rects() call (or calls), but can be freed after 126 | // the call (or calls) finish. 127 | // 128 | // Note: to guarantee best results, either: 129 | // 1. make sure 'num_nodes' >= 'width' 130 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 131 | // 132 | // If you don't do either of the above things, widths will be quantized to multiples 133 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 134 | // 135 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 136 | // may run out of temporary storage and be unable to pack some rectangles. 137 | 138 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 139 | // Optionally call this function after init but before doing any packing to 140 | // change the handling of the out-of-temp-memory scenario, described above. 141 | // If you call init again, this will be reset to the default (false). 142 | 143 | 144 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 145 | // Optionally select which packing heuristic the library should use. Different 146 | // heuristics will produce better/worse results for different data sets. 147 | // If you call init again, this will be reset to the default. 148 | 149 | enum 150 | { 151 | STBRP_HEURISTIC_Skyline_default=0, 152 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 153 | STBRP_HEURISTIC_Skyline_BF_sortHeight 154 | }; 155 | 156 | 157 | ////////////////////////////////////////////////////////////////////////////// 158 | // 159 | // the details of the following structures don't matter to you, but they must 160 | // be visible so you can handle the memory allocations for them 161 | 162 | struct stbrp_node 163 | { 164 | stbrp_coord x,y; 165 | stbrp_node *next; 166 | }; 167 | 168 | struct stbrp_context 169 | { 170 | int width; 171 | int height; 172 | int align; 173 | int init_mode; 174 | int heuristic; 175 | int num_nodes; 176 | stbrp_node *active_head; 177 | stbrp_node *free_head; 178 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 179 | }; 180 | 181 | #ifdef __cplusplus 182 | } 183 | #endif 184 | 185 | #endif 186 | 187 | ////////////////////////////////////////////////////////////////////////////// 188 | // 189 | // IMPLEMENTATION SECTION 190 | // 191 | 192 | #ifdef STB_RECT_PACK_IMPLEMENTATION 193 | #ifndef STBRP_SORT 194 | #include 195 | #define STBRP_SORT qsort 196 | #endif 197 | 198 | #ifndef STBRP_ASSERT 199 | #include 200 | #define STBRP_ASSERT assert 201 | #endif 202 | 203 | #ifdef _MSC_VER 204 | #define STBRP__NOTUSED(v) (void)(v) 205 | #else 206 | #define STBRP__NOTUSED(v) (void)sizeof(v) 207 | #endif 208 | 209 | enum 210 | { 211 | STBRP__INIT_skyline = 1 212 | }; 213 | 214 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 215 | { 216 | switch (context->init_mode) { 217 | case STBRP__INIT_skyline: 218 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 219 | context->heuristic = heuristic; 220 | break; 221 | default: 222 | STBRP_ASSERT(0); 223 | } 224 | } 225 | 226 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 227 | { 228 | if (allow_out_of_mem) 229 | // if it's ok to run out of memory, then don't bother aligning them; 230 | // this gives better packing, but may fail due to OOM (even though 231 | // the rectangles easily fit). @TODO a smarter approach would be to only 232 | // quantize once we've hit OOM, then we could get rid of this parameter. 233 | context->align = 1; 234 | else { 235 | // if it's not ok to run out of memory, then quantize the widths 236 | // so that num_nodes is always enough nodes. 237 | // 238 | // I.e. num_nodes * align >= width 239 | // align >= width / num_nodes 240 | // align = ceil(width/num_nodes) 241 | 242 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 243 | } 244 | } 245 | 246 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 247 | { 248 | int i; 249 | #ifndef STBRP_LARGE_RECTS 250 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 251 | #endif 252 | 253 | for (i=0; i < num_nodes-1; ++i) 254 | nodes[i].next = &nodes[i+1]; 255 | nodes[i].next = NULL; 256 | context->init_mode = STBRP__INIT_skyline; 257 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 258 | context->free_head = &nodes[0]; 259 | context->active_head = &context->extra[0]; 260 | context->width = width; 261 | context->height = height; 262 | context->num_nodes = num_nodes; 263 | stbrp_setup_allow_out_of_mem(context, 0); 264 | 265 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 266 | context->extra[0].x = 0; 267 | context->extra[0].y = 0; 268 | context->extra[0].next = &context->extra[1]; 269 | context->extra[1].x = (stbrp_coord) width; 270 | #ifdef STBRP_LARGE_RECTS 271 | context->extra[1].y = (1<<30); 272 | #else 273 | context->extra[1].y = 65535; 274 | #endif 275 | context->extra[1].next = NULL; 276 | } 277 | 278 | // find minimum y position if it starts at x1 279 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 280 | { 281 | stbrp_node *node = first; 282 | int x1 = x0 + width; 283 | int min_y, visited_width, waste_area; 284 | 285 | STBRP__NOTUSED(c); 286 | 287 | STBRP_ASSERT(first->x <= x0); 288 | 289 | #if 0 290 | // skip in case we're past the node 291 | while (node->next->x <= x0) 292 | ++node; 293 | #else 294 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 295 | #endif 296 | 297 | STBRP_ASSERT(node->x <= x0); 298 | 299 | min_y = 0; 300 | waste_area = 0; 301 | visited_width = 0; 302 | while (node->x < x1) { 303 | if (node->y > min_y) { 304 | // raise min_y higher. 305 | // we've accounted for all waste up to min_y, 306 | // but we'll now add more waste for everything we've visted 307 | waste_area += visited_width * (node->y - min_y); 308 | min_y = node->y; 309 | // the first time through, visited_width might be reduced 310 | if (node->x < x0) 311 | visited_width += node->next->x - x0; 312 | else 313 | visited_width += node->next->x - node->x; 314 | } else { 315 | // add waste area 316 | int under_width = node->next->x - node->x; 317 | if (under_width + visited_width > width) 318 | under_width = width - visited_width; 319 | waste_area += under_width * (min_y - node->y); 320 | visited_width += under_width; 321 | } 322 | node = node->next; 323 | } 324 | 325 | *pwaste = waste_area; 326 | return min_y; 327 | } 328 | 329 | typedef struct 330 | { 331 | int x,y; 332 | stbrp_node **prev_link; 333 | } stbrp__findresult; 334 | 335 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 336 | { 337 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 338 | stbrp__findresult fr; 339 | stbrp_node **prev, *node, *tail, **best = NULL; 340 | 341 | // align to multiple of c->align 342 | width = (width + c->align - 1); 343 | width -= width % c->align; 344 | STBRP_ASSERT(width % c->align == 0); 345 | 346 | node = c->active_head; 347 | prev = &c->active_head; 348 | while (node->x + width <= c->width) { 349 | int y,waste; 350 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 351 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 352 | // bottom left 353 | if (y < best_y) { 354 | best_y = y; 355 | best = prev; 356 | } 357 | } else { 358 | // best-fit 359 | if (y + height <= c->height) { 360 | // can only use it if it first vertically 361 | if (y < best_y || (y == best_y && waste < best_waste)) { 362 | best_y = y; 363 | best_waste = waste; 364 | best = prev; 365 | } 366 | } 367 | } 368 | prev = &node->next; 369 | node = node->next; 370 | } 371 | 372 | best_x = (best == NULL) ? 0 : (*best)->x; 373 | 374 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 375 | // 376 | // e.g, if fitting 377 | // 378 | // ____________________ 379 | // |____________________| 380 | // 381 | // into 382 | // 383 | // | | 384 | // | ____________| 385 | // |____________| 386 | // 387 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 388 | // 389 | // This makes BF take about 2x the time 390 | 391 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 392 | tail = c->active_head; 393 | node = c->active_head; 394 | prev = &c->active_head; 395 | // find first node that's admissible 396 | while (tail->x < width) 397 | tail = tail->next; 398 | while (tail) { 399 | int xpos = tail->x - width; 400 | int y,waste; 401 | STBRP_ASSERT(xpos >= 0); 402 | // find the left position that matches this 403 | while (node->next->x <= xpos) { 404 | prev = &node->next; 405 | node = node->next; 406 | } 407 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 408 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 409 | if (y + height < c->height) { 410 | if (y <= best_y) { 411 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 412 | best_x = xpos; 413 | STBRP_ASSERT(y <= best_y); 414 | best_y = y; 415 | best_waste = waste; 416 | best = prev; 417 | } 418 | } 419 | } 420 | tail = tail->next; 421 | } 422 | } 423 | 424 | fr.prev_link = best; 425 | fr.x = best_x; 426 | fr.y = best_y; 427 | return fr; 428 | } 429 | 430 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 431 | { 432 | // find best position according to heuristic 433 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 434 | stbrp_node *node, *cur; 435 | 436 | // bail if: 437 | // 1. it failed 438 | // 2. the best node doesn't fit (we don't always check this) 439 | // 3. we're out of memory 440 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 441 | res.prev_link = NULL; 442 | return res; 443 | } 444 | 445 | // on success, create new node 446 | node = context->free_head; 447 | node->x = (stbrp_coord) res.x; 448 | node->y = (stbrp_coord) (res.y + height); 449 | 450 | context->free_head = node->next; 451 | 452 | // insert the new node into the right starting point, and 453 | // let 'cur' point to the remaining nodes needing to be 454 | // stiched back in 455 | 456 | cur = *res.prev_link; 457 | if (cur->x < res.x) { 458 | // preserve the existing one, so start testing with the next one 459 | stbrp_node *next = cur->next; 460 | cur->next = node; 461 | cur = next; 462 | } else { 463 | *res.prev_link = node; 464 | } 465 | 466 | // from here, traverse cur and free the nodes, until we get to one 467 | // that shouldn't be freed 468 | while (cur->next && cur->next->x <= res.x + width) { 469 | stbrp_node *next = cur->next; 470 | // move the current node to the free list 471 | cur->next = context->free_head; 472 | context->free_head = cur; 473 | cur = next; 474 | } 475 | 476 | // stitch the list back in 477 | node->next = cur; 478 | 479 | if (cur->x < res.x + width) 480 | cur->x = (stbrp_coord) (res.x + width); 481 | 482 | #ifdef _DEBUG 483 | cur = context->active_head; 484 | while (cur->x < context->width) { 485 | STBRP_ASSERT(cur->x < cur->next->x); 486 | cur = cur->next; 487 | } 488 | STBRP_ASSERT(cur->next == NULL); 489 | 490 | { 491 | stbrp_node *L1 = NULL, *L2 = NULL; 492 | int count=0; 493 | cur = context->active_head; 494 | while (cur) { 495 | L1 = cur; 496 | cur = cur->next; 497 | ++count; 498 | } 499 | cur = context->free_head; 500 | while (cur) { 501 | L2 = cur; 502 | cur = cur->next; 503 | ++count; 504 | } 505 | STBRP_ASSERT(count == context->num_nodes+2); 506 | } 507 | #endif 508 | 509 | return res; 510 | } 511 | 512 | static int rect_height_compare(const void *a, const void *b) 513 | { 514 | const stbrp_rect *p = (const stbrp_rect *) a; 515 | const stbrp_rect *q = (const stbrp_rect *) b; 516 | if (p->h > q->h) 517 | return -1; 518 | if (p->h < q->h) 519 | return 1; 520 | return (p->w > q->w) ? -1 : (p->w < q->w); 521 | } 522 | 523 | // static int rect_width_compare(const void *a, const void *b) 524 | // { 525 | // const stbrp_rect *p = (const stbrp_rect *) a; 526 | // const stbrp_rect *q = (const stbrp_rect *) b; 527 | // if (p->w > q->w) 528 | // return -1; 529 | // if (p->w < q->w) 530 | // return 1; 531 | // return (p->h > q->h) ? -1 : (p->h < q->h); 532 | // } 533 | 534 | static int rect_original_order(const void *a, const void *b) 535 | { 536 | const stbrp_rect *p = (const stbrp_rect *) a; 537 | const stbrp_rect *q = (const stbrp_rect *) b; 538 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 539 | } 540 | 541 | #ifdef STBRP_LARGE_RECTS 542 | #define STBRP__MAXVAL 0xffffffff 543 | #else 544 | #define STBRP__MAXVAL 0xffff 545 | #endif 546 | 547 | STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 548 | { 549 | int i; 550 | 551 | // we use the 'was_packed' field internally to allow sorting/unsorting 552 | for (i=0; i < num_rects; ++i) { 553 | rects[i].was_packed = i; 554 | #ifndef STBRP_LARGE_RECTS 555 | // STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff); 556 | #endif 557 | } 558 | 559 | // sort according to heuristic 560 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 561 | 562 | for (i=0; i < num_rects; ++i) { 563 | if (rects[i].w == 0 || rects[i].h == 0) { 564 | rects[i].x = rects[i].y = 0; // empty rect needs no space 565 | } else { 566 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 567 | if (fr.prev_link) { 568 | rects[i].x = (stbrp_coord) fr.x; 569 | rects[i].y = (stbrp_coord) fr.y; 570 | } else { 571 | rects[i].x = rects[i].y = STBRP__MAXVAL; 572 | } 573 | } 574 | } 575 | 576 | // unsort 577 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 578 | 579 | // set was_packed flags 580 | for (i=0; i < num_rects; ++i) 581 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 582 | } 583 | #endif 584 | -------------------------------------------------------------------------------- /src/lib/stb/stb_truetype.c: -------------------------------------------------------------------------------- 1 | #define STB_TRUETYPE_IMPLEMENTATION 2 | #include "stb_rect_pack.h" 3 | #include "stb_truetype.h" 4 | -------------------------------------------------------------------------------- /src/lib/stb/stb_truetype.h: -------------------------------------------------------------------------------- 1 | // stb_truetype.h - v1.12 - public domain 2 | // authored from 2009-2016 by Sean Barrett / RAD Game Tools 3 | // 4 | // This library processes TrueType files: 5 | // parse files 6 | // extract glyph metrics 7 | // extract glyph shapes 8 | // render glyphs to one-channel bitmaps with antialiasing (box filter) 9 | // 10 | // Todo: 11 | // non-MS cmaps 12 | // crashproof on bad data 13 | // hinting? (no longer patented) 14 | // cleartype-style AA? 15 | // optimize: use simple memory allocator for intermediates 16 | // optimize: build edge-list directly from curves 17 | // optimize: rasterize directly from curves? 18 | // 19 | // ADDITIONAL CONTRIBUTORS 20 | // 21 | // Mikko Mononen: compound shape support, more cmap formats 22 | // Tor Andersson: kerning, subpixel rendering 23 | // 24 | // Misc other: 25 | // Ryan Gordon 26 | // Simon Glass 27 | // 28 | // Bug/warning reports/fixes: 29 | // "Zer" on mollyrocket (with fix) 30 | // Cass Everitt 31 | // stoiko (Haemimont Games) 32 | // Brian Hook 33 | // Walter van Niftrik 34 | // David Gow 35 | // David Given 36 | // Ivan-Assen Ivanov 37 | // Anthony Pesch 38 | // Johan Duparc 39 | // Hou Qiming 40 | // Fabian "ryg" Giesen 41 | // Martins Mozeiko 42 | // Cap Petschulat 43 | // Omar Cornut 44 | // github:aloucks 45 | // Peter LaValle 46 | // Sergey Popov 47 | // Giumo X. Clanjor 48 | // Higor Euripedes 49 | // Thomas Fields 50 | // Derek Vinyard 51 | // 52 | // VERSION HISTORY 53 | // 54 | // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual 55 | // 1.11 (2016-04-02) fix unused-variable warning 56 | // 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef 57 | // 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly 58 | // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges 59 | // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; 60 | // variant PackFontRanges to pack and render in separate phases; 61 | // fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); 62 | // fixed an assert() bug in the new rasterizer 63 | // replace assert() with STBTT_assert() in new rasterizer 64 | // 65 | // Full history can be found at the end of this file. 66 | // 67 | // LICENSE 68 | // 69 | // This software is dual-licensed to the public domain and under the following 70 | // license: you are granted a perpetual, irrevocable license to copy, modify, 71 | // publish, and distribute this file as you see fit. 72 | // 73 | // USAGE 74 | // 75 | // Include this file in whatever places neeed to refer to it. In ONE C/C++ 76 | // file, write: 77 | // #define STB_TRUETYPE_IMPLEMENTATION 78 | // before the #include of this file. This expands out the actual 79 | // implementation into that C/C++ file. 80 | // 81 | // To make the implementation private to the file that generates the implementation, 82 | // #define STBTT_STATIC 83 | // 84 | // Simple 3D API (don't ship this, but it's fine for tools and quick start) 85 | // stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture 86 | // stbtt_GetBakedQuad() -- compute quad to draw for a given char 87 | // 88 | // Improved 3D API (more shippable): 89 | // #include "stb_rect_pack.h" -- optional, but you really want it 90 | // stbtt_PackBegin() 91 | // stbtt_PackSetOversample() -- for improved quality on small fonts 92 | // stbtt_PackFontRanges() -- pack and renders 93 | // stbtt_PackEnd() 94 | // stbtt_GetPackedQuad() 95 | // 96 | // "Load" a font file from a memory buffer (you have to keep the buffer loaded) 97 | // stbtt_InitFont() 98 | // stbtt_GetFontOffsetForIndex() -- use for TTC font collections 99 | // 100 | // Render a unicode codepoint to a bitmap 101 | // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap 102 | // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide 103 | // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be 104 | // 105 | // Character advance/positioning 106 | // stbtt_GetCodepointHMetrics() 107 | // stbtt_GetFontVMetrics() 108 | // stbtt_GetCodepointKernAdvance() 109 | // 110 | // Starting with version 1.06, the rasterizer was replaced with a new, 111 | // faster and generally-more-precise rasterizer. The new rasterizer more 112 | // accurately measures pixel coverage for anti-aliasing, except in the case 113 | // where multiple shapes overlap, in which case it overestimates the AA pixel 114 | // coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If 115 | // this turns out to be a problem, you can re-enable the old rasterizer with 116 | // #define STBTT_RASTERIZER_VERSION 1 117 | // which will incur about a 15% speed hit. 118 | // 119 | // ADDITIONAL DOCUMENTATION 120 | // 121 | // Immediately after this block comment are a series of sample programs. 122 | // 123 | // After the sample programs is the "header file" section. This section 124 | // includes documentation for each API function. 125 | // 126 | // Some important concepts to understand to use this library: 127 | // 128 | // Codepoint 129 | // Characters are defined by unicode codepoints, e.g. 65 is 130 | // uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is 131 | // the hiragana for "ma". 132 | // 133 | // Glyph 134 | // A visual character shape (every codepoint is rendered as 135 | // some glyph) 136 | // 137 | // Glyph index 138 | // A font-specific integer ID representing a glyph 139 | // 140 | // Baseline 141 | // Glyph shapes are defined relative to a baseline, which is the 142 | // bottom of uppercase characters. Characters extend both above 143 | // and below the baseline. 144 | // 145 | // Current Point 146 | // As you draw text to the screen, you keep track of a "current point" 147 | // which is the origin of each character. The current point's vertical 148 | // position is the baseline. Even "baked fonts" use this model. 149 | // 150 | // Vertical Font Metrics 151 | // The vertical qualities of the font, used to vertically position 152 | // and space the characters. See docs for stbtt_GetFontVMetrics. 153 | // 154 | // Font Size in Pixels or Points 155 | // The preferred interface for specifying font sizes in stb_truetype 156 | // is to specify how tall the font's vertical extent should be in pixels. 157 | // If that sounds good enough, skip the next paragraph. 158 | // 159 | // Most font APIs instead use "points", which are a common typographic 160 | // measurement for describing font size, defined as 72 points per inch. 161 | // stb_truetype provides a point API for compatibility. However, true 162 | // "per inch" conventions don't make much sense on computer displays 163 | // since they different monitors have different number of pixels per 164 | // inch. For example, Windows traditionally uses a convention that 165 | // there are 96 pixels per inch, thus making 'inch' measurements have 166 | // nothing to do with inches, and thus effectively defining a point to 167 | // be 1.333 pixels. Additionally, the TrueType font data provides 168 | // an explicit scale factor to scale a given font's glyphs to points, 169 | // but the author has observed that this scale factor is often wrong 170 | // for non-commercial fonts, thus making fonts scaled in points 171 | // according to the TrueType spec incoherently sized in practice. 172 | // 173 | // ADVANCED USAGE 174 | // 175 | // Quality: 176 | // 177 | // - Use the functions with Subpixel at the end to allow your characters 178 | // to have subpixel positioning. Since the font is anti-aliased, not 179 | // hinted, this is very import for quality. (This is not possible with 180 | // baked fonts.) 181 | // 182 | // - Kerning is now supported, and if you're supporting subpixel rendering 183 | // then kerning is worth using to give your text a polished look. 184 | // 185 | // Performance: 186 | // 187 | // - Convert Unicode codepoints to glyph indexes and operate on the glyphs; 188 | // if you don't do this, stb_truetype is forced to do the conversion on 189 | // every call. 190 | // 191 | // - There are a lot of memory allocations. We should modify it to take 192 | // a temp buffer and allocate from the temp buffer (without freeing), 193 | // should help performance a lot. 194 | // 195 | // NOTES 196 | // 197 | // The system uses the raw data found in the .ttf file without changing it 198 | // and without building auxiliary data structures. This is a bit inefficient 199 | // on little-endian systems (the data is big-endian), but assuming you're 200 | // caching the bitmaps or glyph shapes this shouldn't be a big deal. 201 | // 202 | // It appears to be very hard to programmatically determine what font a 203 | // given file is in a general way. I provide an API for this, but I don't 204 | // recommend it. 205 | // 206 | // 207 | // SOURCE STATISTICS (based on v0.6c, 2050 LOC) 208 | // 209 | // Documentation & header file 520 LOC \___ 660 LOC documentation 210 | // Sample code 140 LOC / 211 | // Truetype parsing 620 LOC ---- 620 LOC TrueType 212 | // Software rasterization 240 LOC \ . 213 | // Curve tesselation 120 LOC \__ 550 LOC Bitmap creation 214 | // Bitmap management 100 LOC / 215 | // Baked bitmap interface 70 LOC / 216 | // Font name matching & access 150 LOC ---- 150 217 | // C runtime library abstraction 60 LOC ---- 60 218 | // 219 | // 220 | // PERFORMANCE MEASUREMENTS FOR 1.06: 221 | // 222 | // 32-bit 64-bit 223 | // Previous release: 8.83 s 7.68 s 224 | // Pool allocations: 7.72 s 6.34 s 225 | // Inline sort : 6.54 s 5.65 s 226 | // New rasterizer : 5.63 s 5.00 s 227 | 228 | ////////////////////////////////////////////////////////////////////////////// 229 | ////////////////////////////////////////////////////////////////////////////// 230 | //// 231 | //// SAMPLE PROGRAMS 232 | //// 233 | // 234 | // Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless 235 | // 236 | #if 0 237 | #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation 238 | #include "stb_truetype.h" 239 | 240 | unsigned char ttf_buffer[1<<20]; 241 | unsigned char temp_bitmap[512*512]; 242 | 243 | stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs 244 | GLuint ftex; 245 | 246 | void my_stbtt_initfont(void) 247 | { 248 | fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); 249 | stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! 250 | // can free ttf_buffer at this point 251 | glGenTextures(1, &ftex); 252 | glBindTexture(GL_TEXTURE_2D, ftex); 253 | glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); 254 | // can free temp_bitmap at this point 255 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 256 | } 257 | 258 | void my_stbtt_print(float x, float y, char *text) 259 | { 260 | // assume orthographic projection with units = screen pixels, origin at top left 261 | glEnable(GL_TEXTURE_2D); 262 | glBindTexture(GL_TEXTURE_2D, ftex); 263 | glBegin(GL_QUADS); 264 | while (*text) { 265 | if (*text >= 32 && *text < 128) { 266 | stbtt_aligned_quad q; 267 | stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 268 | glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); 269 | glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); 270 | glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); 271 | glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); 272 | } 273 | ++text; 274 | } 275 | glEnd(); 276 | } 277 | #endif 278 | // 279 | // 280 | ////////////////////////////////////////////////////////////////////////////// 281 | // 282 | // Complete program (this compiles): get a single bitmap, print as ASCII art 283 | // 284 | #if 0 285 | #include 286 | #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation 287 | #include "stb_truetype.h" 288 | 289 | char ttf_buffer[1<<25]; 290 | 291 | int main(int argc, char **argv) 292 | { 293 | stbtt_fontinfo font; 294 | unsigned char *bitmap; 295 | int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); 296 | 297 | fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); 298 | 299 | stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); 300 | bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); 301 | 302 | for (j=0; j < h; ++j) { 303 | for (i=0; i < w; ++i) 304 | putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); 305 | putchar('\n'); 306 | } 307 | return 0; 308 | } 309 | #endif 310 | // 311 | // Output: 312 | // 313 | // .ii. 314 | // @@@@@@. 315 | // V@Mio@@o 316 | // :i. V@V 317 | // :oM@@M 318 | // :@@@MM@M 319 | // @@o o@M 320 | // :@@. M@M 321 | // @@@o@@@@ 322 | // :M@@V:@@. 323 | // 324 | ////////////////////////////////////////////////////////////////////////////// 325 | // 326 | // Complete program: print "Hello World!" banner, with bugs 327 | // 328 | #if 0 329 | char buffer[24<<20]; 330 | unsigned char screen[20][79]; 331 | 332 | int main(int arg, char **argv) 333 | { 334 | stbtt_fontinfo font; 335 | int i,j,ascent,baseline,ch=0; 336 | float scale, xpos=2; // leave a little padding in case the character extends left 337 | char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness 338 | 339 | fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); 340 | stbtt_InitFont(&font, buffer, 0); 341 | 342 | scale = stbtt_ScaleForPixelHeight(&font, 15); 343 | stbtt_GetFontVMetrics(&font, &ascent,0,0); 344 | baseline = (int) (ascent*scale); 345 | 346 | while (text[ch]) { 347 | int advance,lsb,x0,y0,x1,y1; 348 | float x_shift = xpos - (float) floor(xpos); 349 | stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); 350 | stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); 351 | stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); 352 | // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong 353 | // because this API is really for baking character bitmaps into textures. if you want to render 354 | // a sequence of characters, you really need to render each bitmap to a temp buffer, then 355 | // "alpha blend" that into the working buffer 356 | xpos += (advance * scale); 357 | if (text[ch+1]) 358 | xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); 359 | ++ch; 360 | } 361 | 362 | for (j=0; j < 20; ++j) { 363 | for (i=0; i < 78; ++i) 364 | putchar(" .:ioVM@"[screen[j][i]>>5]); 365 | putchar('\n'); 366 | } 367 | 368 | return 0; 369 | } 370 | #endif 371 | 372 | 373 | ////////////////////////////////////////////////////////////////////////////// 374 | ////////////////////////////////////////////////////////////////////////////// 375 | //// 376 | //// INTEGRATION WITH YOUR CODEBASE 377 | //// 378 | //// The following sections allow you to supply alternate definitions 379 | //// of C library functions used by stb_truetype. 380 | 381 | #ifdef STB_TRUETYPE_IMPLEMENTATION 382 | // #define your own (u)stbtt_int8/16/32 before including to override this 383 | #ifndef stbtt_uint8 384 | typedef unsigned char stbtt_uint8; 385 | typedef signed char stbtt_int8; 386 | typedef unsigned short stbtt_uint16; 387 | typedef signed short stbtt_int16; 388 | typedef unsigned int stbtt_uint32; 389 | typedef signed int stbtt_int32; 390 | #endif 391 | 392 | typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; 393 | typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; 394 | 395 | // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h 396 | #ifndef STBTT_ifloor 397 | #include 398 | #define STBTT_ifloor(x) ((int) floor(x)) 399 | #define STBTT_iceil(x) ((int) ceil(x)) 400 | #endif 401 | 402 | #ifndef STBTT_sqrt 403 | #include 404 | #define STBTT_sqrt(x) sqrt(x) 405 | #endif 406 | 407 | #ifndef STBTT_fabs 408 | #include 409 | #define STBTT_fabs(x) fabs(x) 410 | #endif 411 | 412 | // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h 413 | #ifndef STBTT_malloc 414 | #include 415 | #define STBTT_malloc(x,u) ((void)(u),malloc(x)) 416 | #define STBTT_free(x,u) ((void)(u),free(x)) 417 | #endif 418 | 419 | #ifndef STBTT_assert 420 | #include 421 | #define STBTT_assert(x) assert(x) 422 | #endif 423 | 424 | #ifndef STBTT_strlen 425 | #include 426 | #define STBTT_strlen(x) strlen(x) 427 | #endif 428 | 429 | #ifndef STBTT_memcpy 430 | #include 431 | #define STBTT_memcpy memcpy 432 | #define STBTT_memset memset 433 | #endif 434 | #endif 435 | 436 | /////////////////////////////////////////////////////////////////////////////// 437 | /////////////////////////////////////////////////////////////////////////////// 438 | //// 439 | //// INTERFACE 440 | //// 441 | //// 442 | 443 | #ifndef __STB_INCLUDE_STB_TRUETYPE_H__ 444 | #define __STB_INCLUDE_STB_TRUETYPE_H__ 445 | 446 | #ifdef STBTT_STATIC 447 | #define STBTT_DEF static 448 | #else 449 | #define STBTT_DEF extern 450 | #endif 451 | 452 | #ifdef __cplusplus 453 | extern "C" { 454 | #endif 455 | 456 | ////////////////////////////////////////////////////////////////////////////// 457 | // 458 | // TEXTURE BAKING API 459 | // 460 | // If you use this API, you only have to call two functions ever. 461 | // 462 | 463 | typedef struct 464 | { 465 | unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap 466 | float xoff,yoff,xadvance; 467 | } stbtt_bakedchar; 468 | 469 | STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) 470 | float pixel_height, // height of font in pixels 471 | unsigned char *pixels, int pw, int ph, // bitmap to be filled in 472 | int first_char, int num_chars, // characters to bake 473 | stbtt_bakedchar *chardata); // you allocate this, it's num_chars long 474 | // if return is positive, the first unused row of the bitmap 475 | // if return is negative, returns the negative of the number of characters that fit 476 | // if return is 0, no characters fit and no rows were used 477 | // This uses a very crappy packing. 478 | 479 | typedef struct 480 | { 481 | float x0,y0,s0,t0; // top-left 482 | float x1,y1,s1,t1; // bottom-right 483 | } stbtt_aligned_quad; 484 | 485 | STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // same data as above 486 | int char_index, // character to display 487 | float *xpos, float *ypos, // pointers to current position in screen pixel space 488 | stbtt_aligned_quad *q, // output: quad to draw 489 | int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier 490 | // Call GetBakedQuad with char_index = 'character - first_char', and it 491 | // creates the quad you need to draw and advances the current position. 492 | // 493 | // The coordinate system used assumes y increases downwards. 494 | // 495 | // Characters will extend both above and below the current position; 496 | // see discussion of "BASELINE" above. 497 | // 498 | // It's inefficient; you might want to c&p it and optimize it. 499 | 500 | 501 | 502 | ////////////////////////////////////////////////////////////////////////////// 503 | // 504 | // NEW TEXTURE BAKING API 505 | // 506 | // This provides options for packing multiple fonts into one atlas, not 507 | // perfectly but better than nothing. 508 | 509 | typedef struct 510 | { 511 | unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap 512 | float xoff,yoff,xadvance; 513 | float xoff2,yoff2; 514 | } stbtt_packedchar; 515 | 516 | typedef struct stbtt_pack_context stbtt_pack_context; 517 | typedef struct stbtt_fontinfo stbtt_fontinfo; 518 | #ifndef STB_RECT_PACK_VERSION 519 | typedef struct stbrp_rect stbrp_rect; 520 | #endif 521 | 522 | STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); 523 | // Initializes a packing context stored in the passed-in stbtt_pack_context. 524 | // Future calls using this context will pack characters into the bitmap passed 525 | // in here: a 1-channel bitmap that is weight x height. stride_in_bytes is 526 | // the distance from one row to the next (or 0 to mean they are packed tightly 527 | // together). "padding" is the amount of padding to leave between each 528 | // character (normally you want '1' for bitmaps you'll use as textures with 529 | // bilinear filtering). 530 | // 531 | // Returns 0 on failure, 1 on success. 532 | 533 | STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); 534 | // Cleans up the packing context and frees all memory. 535 | 536 | #define STBTT_POINT_SIZE(x) (-(x)) 537 | 538 | STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, 539 | int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); 540 | // Creates character bitmaps from the font_index'th font found in fontdata (use 541 | // font_index=0 if you don't know what that is). It creates num_chars_in_range 542 | // bitmaps for characters with unicode values starting at first_unicode_char_in_range 543 | // and increasing. Data for how to render them is stored in chardata_for_range; 544 | // pass these to stbtt_GetPackedQuad to get back renderable quads. 545 | // 546 | // font_size is the full height of the character from ascender to descender, 547 | // as computed by stbtt_ScaleForPixelHeight. To use a point size as computed 548 | // by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() 549 | // and pass that result as 'font_size': 550 | // ..., 20 , ... // font max minus min y is 20 pixels tall 551 | // ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall 552 | 553 | typedef struct 554 | { 555 | float font_size; 556 | int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint 557 | int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints 558 | int num_chars; 559 | stbtt_packedchar *chardata_for_range; // output 560 | unsigned char h_oversample, v_oversample; // don't set these, they're used internally 561 | } stbtt_pack_range; 562 | 563 | STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); 564 | // Creates character bitmaps from multiple ranges of characters stored in 565 | // ranges. This will usually create a better-packed bitmap than multiple 566 | // calls to stbtt_PackFontRange. Note that you can call this multiple 567 | // times within a single PackBegin/PackEnd. 568 | 569 | STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); 570 | // Oversampling a font increases the quality by allowing higher-quality subpixel 571 | // positioning, and is especially valuable at smaller text sizes. 572 | // 573 | // This function sets the amount of oversampling for all following calls to 574 | // stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given 575 | // pack context. The default (no oversampling) is achieved by h_oversample=1 576 | // and v_oversample=1. The total number of pixels required is 577 | // h_oversample*v_oversample larger than the default; for example, 2x2 578 | // oversampling requires 4x the storage of 1x1. For best results, render 579 | // oversampled textures with bilinear filtering. Look at the readme in 580 | // stb/tests/oversample for information about oversampled fonts 581 | // 582 | // To use with PackFontRangesGather etc., you must set it before calls 583 | // call to PackFontRangesGatherRects. 584 | 585 | STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, // same data as above 586 | int char_index, // character to display 587 | float *xpos, float *ypos, // pointers to current position in screen pixel space 588 | stbtt_aligned_quad *q, // output: quad to draw 589 | int align_to_integer); 590 | 591 | STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); 592 | STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); 593 | STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); 594 | // Calling these functions in sequence is roughly equivalent to calling 595 | // stbtt_PackFontRanges(). If you more control over the packing of multiple 596 | // fonts, or if you want to pack custom data into a font texture, take a look 597 | // at the source to of stbtt_PackFontRanges() and create a custom version 598 | // using these functions, e.g. call GatherRects multiple times, 599 | // building up a single array of rects, then call PackRects once, 600 | // then call RenderIntoRects repeatedly. This may result in a 601 | // better packing than calling PackFontRanges multiple times 602 | // (or it may not). 603 | 604 | // this is an opaque structure that you shouldn't mess with which holds 605 | // all the context needed from PackBegin to PackEnd. 606 | struct stbtt_pack_context { 607 | void *user_allocator_context; 608 | void *pack_info; 609 | int width; 610 | int height; 611 | int stride_in_bytes; 612 | int padding; 613 | unsigned int h_oversample, v_oversample; 614 | unsigned char *pixels; 615 | void *nodes; 616 | }; 617 | 618 | ////////////////////////////////////////////////////////////////////////////// 619 | // 620 | // FONT LOADING 621 | // 622 | // 623 | 624 | STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); 625 | // Each .ttf/.ttc file may have more than one font. Each font has a sequential 626 | // index number starting from 0. Call this function to get the font offset for 627 | // a given index; it returns -1 if the index is out of range. A regular .ttf 628 | // file will only define one font and it always be at offset 0, so it will 629 | // return '0' for index 0, and -1 for all other indices. You can just skip 630 | // this step if you know it's that kind of font. 631 | 632 | 633 | // The following structure is defined publically so you can declare one on 634 | // the stack or as a global or etc, but you should treat it as opaque. 635 | struct stbtt_fontinfo 636 | { 637 | void * userdata; 638 | unsigned char * data; // pointer to .ttf file 639 | int fontstart; // offset of start of font 640 | 641 | int numGlyphs; // number of glyphs, needed for range checking 642 | 643 | int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf 644 | int index_map; // a cmap mapping for our chosen character encoding 645 | int indexToLocFormat; // format needed to map from glyph index to glyph 646 | }; 647 | 648 | STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); 649 | // Given an offset into the file that defines a font, this function builds 650 | // the necessary cached info for the rest of the system. You must allocate 651 | // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't 652 | // need to do anything special to free it, because the contents are pure 653 | // value data with no additional data structures. Returns 0 on failure. 654 | 655 | 656 | ////////////////////////////////////////////////////////////////////////////// 657 | // 658 | // CHARACTER TO GLYPH-INDEX CONVERSIOn 659 | 660 | STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); 661 | // If you're going to perform multiple operations on the same character 662 | // and you want a speed-up, call this function with the character you're 663 | // going to process, then use glyph-based functions instead of the 664 | // codepoint-based functions. 665 | 666 | 667 | ////////////////////////////////////////////////////////////////////////////// 668 | // 669 | // CHARACTER PROPERTIES 670 | // 671 | 672 | STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); 673 | // computes a scale factor to produce a font whose "height" is 'pixels' tall. 674 | // Height is measured as the distance from the highest ascender to the lowest 675 | // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics 676 | // and computing: 677 | // scale = pixels / (ascent - descent) 678 | // so if you prefer to measure height by the ascent only, use a similar calculation. 679 | 680 | STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); 681 | // computes a scale factor to produce a font whose EM size is mapped to 682 | // 'pixels' tall. This is probably what traditional APIs compute, but 683 | // I'm not positive. 684 | 685 | STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); 686 | // ascent is the coordinate above the baseline the font extends; descent 687 | // is the coordinate below the baseline the font extends (i.e. it is typically negative) 688 | // lineGap is the spacing between one row's descent and the next row's ascent... 689 | // so you should advance the vertical position by "*ascent - *descent + *lineGap" 690 | // these are expressed in unscaled coordinates, so you must multiply by 691 | // the scale factor for a given size 692 | 693 | STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); 694 | // the bounding box around all possible characters 695 | 696 | STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); 697 | // leftSideBearing is the offset from the current horizontal position to the left edge of the character 698 | // advanceWidth is the offset from the current horizontal position to the next horizontal position 699 | // these are expressed in unscaled coordinates 700 | 701 | STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); 702 | // an additional amount to add to the 'advance' value between ch1 and ch2 703 | 704 | STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); 705 | // Gets the bounding box of the visible part of the glyph, in unscaled coordinates 706 | 707 | STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); 708 | STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); 709 | STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); 710 | // as above, but takes one or more glyph indices for greater efficiency 711 | 712 | 713 | ////////////////////////////////////////////////////////////////////////////// 714 | // 715 | // GLYPH SHAPES (you probably don't need these, but they have to go before 716 | // the bitmaps for C declaration-order reasons) 717 | // 718 | 719 | #ifndef STBTT_vmove // you can predefine these to use different values (but why?) 720 | enum { 721 | STBTT_vmove=1, 722 | STBTT_vline, 723 | STBTT_vcurve 724 | }; 725 | #endif 726 | 727 | #ifndef stbtt_vertex // you can predefine this to use different values 728 | // (we share this with other code at RAD) 729 | #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file 730 | typedef struct 731 | { 732 | stbtt_vertex_type x,y,cx,cy; 733 | unsigned char type,padding; 734 | } stbtt_vertex; 735 | #endif 736 | 737 | STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); 738 | // returns non-zero if nothing is drawn for this glyph 739 | 740 | STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); 741 | STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); 742 | // returns # of vertices and fills *vertices with the pointer to them 743 | // these are expressed in "unscaled" coordinates 744 | // 745 | // The shape is a series of countours. Each one starts with 746 | // a STBTT_moveto, then consists of a series of mixed 747 | // STBTT_lineto and STBTT_curveto segments. A lineto 748 | // draws a line from previous endpoint to its x,y; a curveto 749 | // draws a quadratic bezier from previous endpoint to 750 | // its x,y, using cx,cy as the bezier control point. 751 | 752 | STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); 753 | // frees the data allocated above 754 | 755 | ////////////////////////////////////////////////////////////////////////////// 756 | // 757 | // BITMAP RENDERING 758 | // 759 | 760 | STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); 761 | // frees the bitmap allocated below 762 | 763 | STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); 764 | // allocates a large-enough single-channel 8bpp bitmap and renders the 765 | // specified character/glyph at the specified scale into it, with 766 | // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). 767 | // *width & *height are filled out with the width & height of the bitmap, 768 | // which is stored left-to-right, top-to-bottom. 769 | // 770 | // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap 771 | 772 | STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); 773 | // the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel 774 | // shift for the character 775 | 776 | STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); 777 | // the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap 778 | // in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap 779 | // is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the 780 | // width and height and positioning info for it first. 781 | 782 | STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); 783 | // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel 784 | // shift for the character 785 | 786 | STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); 787 | // get the bbox of the bitmap centered around the glyph origin; so the 788 | // bitmap width is ix1-ix0, height is iy1-iy0, and location to place 789 | // the bitmap top left is (leftSideBearing*scale,iy0). 790 | // (Note that the bitmap uses y-increases-down, but the shape uses 791 | // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) 792 | 793 | STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); 794 | // same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel 795 | // shift for the character 796 | 797 | // the following functions are equivalent to the above functions, but operate 798 | // on glyph indices instead of Unicode codepoints (for efficiency) 799 | STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); 800 | STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); 801 | STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); 802 | STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); 803 | STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); 804 | STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); 805 | 806 | 807 | // @TODO: don't expose this structure 808 | typedef struct 809 | { 810 | int w,h,stride; 811 | unsigned char *pixels; 812 | } stbtt__bitmap; 813 | 814 | // rasterize a shape with quadratic beziers into a bitmap 815 | STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into 816 | float flatness_in_pixels, // allowable error of curve in pixels 817 | stbtt_vertex *vertices, // array of vertices defining shape 818 | int num_verts, // number of vertices in above array 819 | float scale_x, float scale_y, // scale applied to input vertices 820 | float shift_x, float shift_y, // translation applied to input vertices 821 | int x_off, int y_off, // another translation applied to input 822 | int invert, // if non-zero, vertically flip shape 823 | void *userdata); // context for to STBTT_MALLOC 824 | 825 | ////////////////////////////////////////////////////////////////////////////// 826 | // 827 | // Finding the right font... 828 | // 829 | // You should really just solve this offline, keep your own tables 830 | // of what font is what, and don't try to get it out of the .ttf file. 831 | // That's because getting it out of the .ttf file is really hard, because 832 | // the names in the file can appear in many possible encodings, in many 833 | // possible languages, and e.g. if you need a case-insensitive comparison, 834 | // the details of that depend on the encoding & language in a complex way 835 | // (actually underspecified in truetype, but also gigantic). 836 | // 837 | // But you can use the provided functions in two possible ways: 838 | // stbtt_FindMatchingFont() will use *case-sensitive* comparisons on 839 | // unicode-encoded names to try to find the font you want; 840 | // you can run this before calling stbtt_InitFont() 841 | // 842 | // stbtt_GetFontNameString() lets you get any of the various strings 843 | // from the file yourself and do your own comparisons on them. 844 | // You have to have called stbtt_InitFont() first. 845 | 846 | 847 | STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); 848 | // returns the offset (not index) of the font that matches, or -1 if none 849 | // if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". 850 | // if you use any other flag, use a font name like "Arial"; this checks 851 | // the 'macStyle' header field; i don't know if fonts set this consistently 852 | #define STBTT_MACSTYLE_DONTCARE 0 853 | #define STBTT_MACSTYLE_BOLD 1 854 | #define STBTT_MACSTYLE_ITALIC 2 855 | #define STBTT_MACSTYLE_UNDERSCORE 4 856 | #define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 857 | 858 | STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); 859 | // returns 1/0 whether the first string interpreted as utf8 is identical to 860 | // the second string interpreted as big-endian utf16... useful for strings from next func 861 | 862 | STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); 863 | // returns the string (which may be big-endian double byte, e.g. for unicode) 864 | // and puts the length in bytes in *length. 865 | // 866 | // some of the values for the IDs are below; for more see the truetype spec: 867 | // http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html 868 | // http://www.microsoft.com/typography/otspec/name.htm 869 | 870 | enum { // platformID 871 | STBTT_PLATFORM_ID_UNICODE =0, 872 | STBTT_PLATFORM_ID_MAC =1, 873 | STBTT_PLATFORM_ID_ISO =2, 874 | STBTT_PLATFORM_ID_MICROSOFT =3 875 | }; 876 | 877 | enum { // encodingID for STBTT_PLATFORM_ID_UNICODE 878 | STBTT_UNICODE_EID_UNICODE_1_0 =0, 879 | STBTT_UNICODE_EID_UNICODE_1_1 =1, 880 | STBTT_UNICODE_EID_ISO_10646 =2, 881 | STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, 882 | STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 883 | }; 884 | 885 | enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT 886 | STBTT_MS_EID_SYMBOL =0, 887 | STBTT_MS_EID_UNICODE_BMP =1, 888 | STBTT_MS_EID_SHIFTJIS =2, 889 | STBTT_MS_EID_UNICODE_FULL =10 890 | }; 891 | 892 | enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes 893 | STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, 894 | STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, 895 | STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, 896 | STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 897 | }; 898 | 899 | enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... 900 | // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs 901 | STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, 902 | STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, 903 | STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, 904 | STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, 905 | STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, 906 | STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D 907 | }; 908 | 909 | enum { // languageID for STBTT_PLATFORM_ID_MAC 910 | STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, 911 | STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, 912 | STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, 913 | STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , 914 | STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , 915 | STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, 916 | STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 917 | }; 918 | 919 | #ifdef __cplusplus 920 | } 921 | #endif 922 | 923 | #endif // __STB_INCLUDE_STB_TRUETYPE_H__ 924 | 925 | /////////////////////////////////////////////////////////////////////////////// 926 | /////////////////////////////////////////////////////////////////////////////// 927 | //// 928 | //// IMPLEMENTATION 929 | //// 930 | //// 931 | 932 | #ifdef STB_TRUETYPE_IMPLEMENTATION 933 | 934 | #ifndef STBTT_MAX_OVERSAMPLE 935 | #define STBTT_MAX_OVERSAMPLE 8 936 | #endif 937 | 938 | #if STBTT_MAX_OVERSAMPLE > 255 939 | #error "STBTT_MAX_OVERSAMPLE cannot be > 255" 940 | #endif 941 | 942 | typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; 943 | 944 | #ifndef STBTT_RASTERIZER_VERSION 945 | #define STBTT_RASTERIZER_VERSION 2 946 | #endif 947 | 948 | #ifdef _MSC_VER 949 | #define STBTT__NOTUSED(v) (void)(v) 950 | #else 951 | #define STBTT__NOTUSED(v) (void)sizeof(v) 952 | #endif 953 | 954 | ////////////////////////////////////////////////////////////////////////// 955 | // 956 | // accessors to parse data from file 957 | // 958 | 959 | // on platforms that don't allow misaligned reads, if we want to allow 960 | // truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE 961 | 962 | #define ttBYTE(p) (* (stbtt_uint8 *) (p)) 963 | #define ttCHAR(p) (* (stbtt_int8 *) (p)) 964 | #define ttFixed(p) ttLONG(p) 965 | 966 | static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } 967 | static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } 968 | static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } 969 | static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } 970 | 971 | #define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) 972 | #define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) 973 | 974 | static int stbtt__isfont(stbtt_uint8 *font) 975 | { 976 | // check the version number 977 | if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 978 | if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! 979 | if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF 980 | if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 981 | return 0; 982 | } 983 | 984 | // @OPTIMIZE: binary search 985 | static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) 986 | { 987 | stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); 988 | stbtt_uint32 tabledir = fontstart + 12; 989 | stbtt_int32 i; 990 | for (i=0; i < num_tables; ++i) { 991 | stbtt_uint32 loc = tabledir + 16*i; 992 | if (stbtt_tag(data+loc+0, tag)) 993 | return ttULONG(data+loc+8); 994 | } 995 | return 0; 996 | } 997 | 998 | static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) 999 | { 1000 | // if it's just a font, there's only one valid index 1001 | if (stbtt__isfont(font_collection)) 1002 | return index == 0 ? 0 : -1; 1003 | 1004 | // check if it's a TTC 1005 | if (stbtt_tag(font_collection, "ttcf")) { 1006 | // version 1? 1007 | if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { 1008 | stbtt_int32 n = ttLONG(font_collection+8); 1009 | if (index >= n) 1010 | return -1; 1011 | return ttULONG(font_collection+12+index*4); 1012 | } 1013 | } 1014 | return -1; 1015 | } 1016 | 1017 | static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) 1018 | { 1019 | stbtt_uint32 cmap, t; 1020 | stbtt_int32 i,numTables; 1021 | 1022 | info->data = data; 1023 | info->fontstart = fontstart; 1024 | 1025 | cmap = stbtt__find_table(data, fontstart, "cmap"); // required 1026 | info->loca = stbtt__find_table(data, fontstart, "loca"); // required 1027 | info->head = stbtt__find_table(data, fontstart, "head"); // required 1028 | info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required 1029 | info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required 1030 | info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required 1031 | info->kern = stbtt__find_table(data, fontstart, "kern"); // not required 1032 | if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx) 1033 | return 0; 1034 | 1035 | t = stbtt__find_table(data, fontstart, "maxp"); 1036 | if (t) 1037 | info->numGlyphs = ttUSHORT(data+t+4); 1038 | else 1039 | info->numGlyphs = 0xffff; 1040 | 1041 | // find a cmap encoding table we understand *now* to avoid searching 1042 | // later. (todo: could make this installable) 1043 | // the same regardless of glyph. 1044 | numTables = ttUSHORT(data + cmap + 2); 1045 | info->index_map = 0; 1046 | for (i=0; i < numTables; ++i) { 1047 | stbtt_uint32 encoding_record = cmap + 4 + 8 * i; 1048 | // find an encoding we understand: 1049 | switch(ttUSHORT(data+encoding_record)) { 1050 | case STBTT_PLATFORM_ID_MICROSOFT: 1051 | switch (ttUSHORT(data+encoding_record+2)) { 1052 | case STBTT_MS_EID_UNICODE_BMP: 1053 | case STBTT_MS_EID_UNICODE_FULL: 1054 | // MS/Unicode 1055 | info->index_map = cmap + ttULONG(data+encoding_record+4); 1056 | break; 1057 | } 1058 | break; 1059 | case STBTT_PLATFORM_ID_UNICODE: 1060 | // Mac/iOS has these 1061 | // all the encodingIDs are unicode, so we don't bother to check it 1062 | info->index_map = cmap + ttULONG(data+encoding_record+4); 1063 | break; 1064 | } 1065 | } 1066 | if (info->index_map == 0) 1067 | return 0; 1068 | 1069 | info->indexToLocFormat = ttUSHORT(data+info->head + 50); 1070 | return 1; 1071 | } 1072 | 1073 | STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) 1074 | { 1075 | stbtt_uint8 *data = info->data; 1076 | stbtt_uint32 index_map = info->index_map; 1077 | 1078 | stbtt_uint16 format = ttUSHORT(data + index_map + 0); 1079 | if (format == 0) { // apple byte encoding 1080 | stbtt_int32 bytes = ttUSHORT(data + index_map + 2); 1081 | if (unicode_codepoint < bytes-6) 1082 | return ttBYTE(data + index_map + 6 + unicode_codepoint); 1083 | return 0; 1084 | } else if (format == 6) { 1085 | stbtt_uint32 first = ttUSHORT(data + index_map + 6); 1086 | stbtt_uint32 count = ttUSHORT(data + index_map + 8); 1087 | if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) 1088 | return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); 1089 | return 0; 1090 | } else if (format == 2) { 1091 | STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean 1092 | return 0; 1093 | } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges 1094 | stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; 1095 | stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; 1096 | stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); 1097 | stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; 1098 | 1099 | // do a binary search of the segments 1100 | stbtt_uint32 endCount = index_map + 14; 1101 | stbtt_uint32 search = endCount; 1102 | 1103 | if (unicode_codepoint > 0xffff) 1104 | return 0; 1105 | 1106 | // they lie from endCount .. endCount + segCount 1107 | // but searchRange is the nearest power of two, so... 1108 | if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) 1109 | search += rangeShift*2; 1110 | 1111 | // now decrement to bias correctly to find smallest 1112 | search -= 2; 1113 | while (entrySelector) { 1114 | stbtt_uint16 end; 1115 | searchRange >>= 1; 1116 | end = ttUSHORT(data + search + searchRange*2); 1117 | if (unicode_codepoint > end) 1118 | search += searchRange*2; 1119 | --entrySelector; 1120 | } 1121 | search += 2; 1122 | 1123 | { 1124 | stbtt_uint16 offset, start; 1125 | stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); 1126 | 1127 | STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); 1128 | start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); 1129 | if (unicode_codepoint < start) 1130 | return 0; 1131 | 1132 | offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); 1133 | if (offset == 0) 1134 | return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); 1135 | 1136 | return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); 1137 | } 1138 | } else if (format == 12 || format == 13) { 1139 | stbtt_uint32 ngroups = ttULONG(data+index_map+12); 1140 | stbtt_int32 low,high; 1141 | low = 0; high = (stbtt_int32)ngroups; 1142 | // Binary search the right group. 1143 | while (low < high) { 1144 | stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high 1145 | stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); 1146 | stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); 1147 | if ((stbtt_uint32) unicode_codepoint < start_char) 1148 | high = mid; 1149 | else if ((stbtt_uint32) unicode_codepoint > end_char) 1150 | low = mid+1; 1151 | else { 1152 | stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); 1153 | if (format == 12) 1154 | return start_glyph + unicode_codepoint-start_char; 1155 | else // format == 13 1156 | return start_glyph; 1157 | } 1158 | } 1159 | return 0; // not found 1160 | } 1161 | // @TODO 1162 | STBTT_assert(0); 1163 | return 0; 1164 | } 1165 | 1166 | STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) 1167 | { 1168 | return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); 1169 | } 1170 | 1171 | static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) 1172 | { 1173 | v->type = type; 1174 | v->x = (stbtt_int16) x; 1175 | v->y = (stbtt_int16) y; 1176 | v->cx = (stbtt_int16) cx; 1177 | v->cy = (stbtt_int16) cy; 1178 | } 1179 | 1180 | static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) 1181 | { 1182 | int g1,g2; 1183 | 1184 | if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range 1185 | if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format 1186 | 1187 | if (info->indexToLocFormat == 0) { 1188 | g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; 1189 | g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; 1190 | } else { 1191 | g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); 1192 | g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); 1193 | } 1194 | 1195 | return g1==g2 ? -1 : g1; // if length is 0, return -1 1196 | } 1197 | 1198 | STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) 1199 | { 1200 | int g = stbtt__GetGlyfOffset(info, glyph_index); 1201 | if (g < 0) return 0; 1202 | 1203 | if (x0) *x0 = ttSHORT(info->data + g + 2); 1204 | if (y0) *y0 = ttSHORT(info->data + g + 4); 1205 | if (x1) *x1 = ttSHORT(info->data + g + 6); 1206 | if (y1) *y1 = ttSHORT(info->data + g + 8); 1207 | return 1; 1208 | } 1209 | 1210 | STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) 1211 | { 1212 | return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); 1213 | } 1214 | 1215 | STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) 1216 | { 1217 | stbtt_int16 numberOfContours; 1218 | int g = stbtt__GetGlyfOffset(info, glyph_index); 1219 | if (g < 0) return 1; 1220 | numberOfContours = ttSHORT(info->data + g); 1221 | return numberOfContours == 0; 1222 | } 1223 | 1224 | static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, 1225 | stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) 1226 | { 1227 | if (start_off) { 1228 | if (was_off) 1229 | stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); 1230 | stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); 1231 | } else { 1232 | if (was_off) 1233 | stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); 1234 | else 1235 | stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); 1236 | } 1237 | return num_vertices; 1238 | } 1239 | 1240 | STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) 1241 | { 1242 | stbtt_int16 numberOfContours; 1243 | stbtt_uint8 *endPtsOfContours; 1244 | stbtt_uint8 *data = info->data; 1245 | stbtt_vertex *vertices=0; 1246 | int num_vertices=0; 1247 | int g = stbtt__GetGlyfOffset(info, glyph_index); 1248 | 1249 | *pvertices = NULL; 1250 | 1251 | if (g < 0) return 0; 1252 | 1253 | numberOfContours = ttSHORT(data + g); 1254 | 1255 | if (numberOfContours > 0) { 1256 | stbtt_uint8 flags=0,flagcount; 1257 | stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; 1258 | stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; 1259 | stbtt_uint8 *points; 1260 | endPtsOfContours = (data + g + 10); 1261 | ins = ttUSHORT(data + g + 10 + numberOfContours * 2); 1262 | points = data + g + 10 + numberOfContours * 2 + 2 + ins; 1263 | 1264 | n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); 1265 | 1266 | m = n + 2*numberOfContours; // a loose bound on how many vertices we might need 1267 | vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); 1268 | if (vertices == 0) 1269 | return 0; 1270 | 1271 | next_move = 0; 1272 | flagcount=0; 1273 | 1274 | // in first pass, we load uninterpreted data into the allocated array 1275 | // above, shifted to the end of the array so we won't overwrite it when 1276 | // we create our final data starting from the front 1277 | 1278 | off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated 1279 | 1280 | // first load flags 1281 | 1282 | for (i=0; i < n; ++i) { 1283 | if (flagcount == 0) { 1284 | flags = *points++; 1285 | if (flags & 8) 1286 | flagcount = *points++; 1287 | } else 1288 | --flagcount; 1289 | vertices[off+i].type = flags; 1290 | } 1291 | 1292 | // now load x coordinates 1293 | x=0; 1294 | for (i=0; i < n; ++i) { 1295 | flags = vertices[off+i].type; 1296 | if (flags & 2) { 1297 | stbtt_int16 dx = *points++; 1298 | x += (flags & 16) ? dx : -dx; // ??? 1299 | } else { 1300 | if (!(flags & 16)) { 1301 | x = x + (stbtt_int16) (points[0]*256 + points[1]); 1302 | points += 2; 1303 | } 1304 | } 1305 | vertices[off+i].x = (stbtt_int16) x; 1306 | } 1307 | 1308 | // now load y coordinates 1309 | y=0; 1310 | for (i=0; i < n; ++i) { 1311 | flags = vertices[off+i].type; 1312 | if (flags & 4) { 1313 | stbtt_int16 dy = *points++; 1314 | y += (flags & 32) ? dy : -dy; // ??? 1315 | } else { 1316 | if (!(flags & 32)) { 1317 | y = y + (stbtt_int16) (points[0]*256 + points[1]); 1318 | points += 2; 1319 | } 1320 | } 1321 | vertices[off+i].y = (stbtt_int16) y; 1322 | } 1323 | 1324 | // now convert them to our format 1325 | num_vertices=0; 1326 | sx = sy = cx = cy = scx = scy = 0; 1327 | for (i=0; i < n; ++i) { 1328 | flags = vertices[off+i].type; 1329 | x = (stbtt_int16) vertices[off+i].x; 1330 | y = (stbtt_int16) vertices[off+i].y; 1331 | 1332 | if (next_move == i) { 1333 | if (i != 0) 1334 | num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); 1335 | 1336 | // now start the new one 1337 | start_off = !(flags & 1); 1338 | if (start_off) { 1339 | // if we start off with an off-curve point, then when we need to find a point on the curve 1340 | // where we can start, and we need to save some state for when we wraparound. 1341 | scx = x; 1342 | scy = y; 1343 | if (!(vertices[off+i+1].type & 1)) { 1344 | // next point is also a curve point, so interpolate an on-point curve 1345 | sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; 1346 | sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; 1347 | } else { 1348 | // otherwise just use the next point as our start point 1349 | sx = (stbtt_int32) vertices[off+i+1].x; 1350 | sy = (stbtt_int32) vertices[off+i+1].y; 1351 | ++i; // we're using point i+1 as the starting point, so skip it 1352 | } 1353 | } else { 1354 | sx = x; 1355 | sy = y; 1356 | } 1357 | stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); 1358 | was_off = 0; 1359 | next_move = 1 + ttUSHORT(endPtsOfContours+j*2); 1360 | ++j; 1361 | } else { 1362 | if (!(flags & 1)) { // if it's a curve 1363 | if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint 1364 | stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); 1365 | cx = x; 1366 | cy = y; 1367 | was_off = 1; 1368 | } else { 1369 | if (was_off) 1370 | stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); 1371 | else 1372 | stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); 1373 | was_off = 0; 1374 | } 1375 | } 1376 | } 1377 | num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); 1378 | } else if (numberOfContours == -1) { 1379 | // Compound shapes. 1380 | int more = 1; 1381 | stbtt_uint8 *comp = data + g + 10; 1382 | num_vertices = 0; 1383 | vertices = 0; 1384 | while (more) { 1385 | stbtt_uint16 flags, gidx; 1386 | int comp_num_verts = 0, i; 1387 | stbtt_vertex *comp_verts = 0, *tmp = 0; 1388 | float mtx[6] = {1,0,0,1,0,0}, m, n; 1389 | 1390 | flags = ttSHORT(comp); comp+=2; 1391 | gidx = ttSHORT(comp); comp+=2; 1392 | 1393 | if (flags & 2) { // XY values 1394 | if (flags & 1) { // shorts 1395 | mtx[4] = ttSHORT(comp); comp+=2; 1396 | mtx[5] = ttSHORT(comp); comp+=2; 1397 | } else { 1398 | mtx[4] = ttCHAR(comp); comp+=1; 1399 | mtx[5] = ttCHAR(comp); comp+=1; 1400 | } 1401 | } 1402 | else { 1403 | // @TODO handle matching point 1404 | STBTT_assert(0); 1405 | } 1406 | if (flags & (1<<3)) { // WE_HAVE_A_SCALE 1407 | mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 1408 | mtx[1] = mtx[2] = 0; 1409 | } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE 1410 | mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; 1411 | mtx[1] = mtx[2] = 0; 1412 | mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 1413 | } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO 1414 | mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; 1415 | mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; 1416 | mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; 1417 | mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 1418 | } 1419 | 1420 | // Find transformation scales. 1421 | m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); 1422 | n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); 1423 | 1424 | // Get indexed glyph. 1425 | comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); 1426 | if (comp_num_verts > 0) { 1427 | // Transform vertices. 1428 | for (i = 0; i < comp_num_verts; ++i) { 1429 | stbtt_vertex* v = &comp_verts[i]; 1430 | stbtt_vertex_type x,y; 1431 | x=v->x; y=v->y; 1432 | v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); 1433 | v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); 1434 | x=v->cx; y=v->cy; 1435 | v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); 1436 | v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); 1437 | } 1438 | // Append vertices. 1439 | tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); 1440 | if (!tmp) { 1441 | if (vertices) STBTT_free(vertices, info->userdata); 1442 | if (comp_verts) STBTT_free(comp_verts, info->userdata); 1443 | return 0; 1444 | } 1445 | if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); 1446 | STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); 1447 | if (vertices) STBTT_free(vertices, info->userdata); 1448 | vertices = tmp; 1449 | STBTT_free(comp_verts, info->userdata); 1450 | num_vertices += comp_num_verts; 1451 | } 1452 | // More components ? 1453 | more = flags & (1<<5); 1454 | } 1455 | } else if (numberOfContours < 0) { 1456 | // @TODO other compound variations? 1457 | STBTT_assert(0); 1458 | } else { 1459 | // numberOfCounters == 0, do nothing 1460 | } 1461 | 1462 | *pvertices = vertices; 1463 | return num_vertices; 1464 | } 1465 | 1466 | STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) 1467 | { 1468 | stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); 1469 | if (glyph_index < numOfLongHorMetrics) { 1470 | if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); 1471 | if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); 1472 | } else { 1473 | if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); 1474 | if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); 1475 | } 1476 | } 1477 | 1478 | STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) 1479 | { 1480 | stbtt_uint8 *data = info->data + info->kern; 1481 | stbtt_uint32 needle, straw; 1482 | int l, r, m; 1483 | 1484 | // we only look at the first table. it must be 'horizontal' and format 0. 1485 | if (!info->kern) 1486 | return 0; 1487 | if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 1488 | return 0; 1489 | if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format 1490 | return 0; 1491 | 1492 | l = 0; 1493 | r = ttUSHORT(data+10) - 1; 1494 | needle = glyph1 << 16 | glyph2; 1495 | while (l <= r) { 1496 | m = (l + r) >> 1; 1497 | straw = ttULONG(data+18+(m*6)); // note: unaligned read 1498 | if (needle < straw) 1499 | r = m - 1; 1500 | else if (needle > straw) 1501 | l = m + 1; 1502 | else 1503 | return ttSHORT(data+22+(m*6)); 1504 | } 1505 | return 0; 1506 | } 1507 | 1508 | STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) 1509 | { 1510 | if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs 1511 | return 0; 1512 | return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); 1513 | } 1514 | 1515 | STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) 1516 | { 1517 | stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); 1518 | } 1519 | 1520 | STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) 1521 | { 1522 | if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); 1523 | if (descent) *descent = ttSHORT(info->data+info->hhea + 6); 1524 | if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); 1525 | } 1526 | 1527 | STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) 1528 | { 1529 | *x0 = ttSHORT(info->data + info->head + 36); 1530 | *y0 = ttSHORT(info->data + info->head + 38); 1531 | *x1 = ttSHORT(info->data + info->head + 40); 1532 | *y1 = ttSHORT(info->data + info->head + 42); 1533 | } 1534 | 1535 | STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) 1536 | { 1537 | int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); 1538 | return (float) height / fheight; 1539 | } 1540 | 1541 | STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) 1542 | { 1543 | int unitsPerEm = ttUSHORT(info->data + info->head + 18); 1544 | return pixels / unitsPerEm; 1545 | } 1546 | 1547 | STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) 1548 | { 1549 | STBTT_free(v, info->userdata); 1550 | } 1551 | 1552 | ////////////////////////////////////////////////////////////////////////////// 1553 | // 1554 | // antialiasing software rasterizer 1555 | // 1556 | 1557 | STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) 1558 | { 1559 | int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning 1560 | if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { 1561 | // e.g. space character 1562 | if (ix0) *ix0 = 0; 1563 | if (iy0) *iy0 = 0; 1564 | if (ix1) *ix1 = 0; 1565 | if (iy1) *iy1 = 0; 1566 | } else { 1567 | // move to integral bboxes (treating pixels as little squares, what pixels get touched)? 1568 | if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); 1569 | if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); 1570 | if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); 1571 | if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); 1572 | } 1573 | } 1574 | 1575 | STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) 1576 | { 1577 | stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); 1578 | } 1579 | 1580 | STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) 1581 | { 1582 | stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); 1583 | } 1584 | 1585 | STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) 1586 | { 1587 | stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); 1588 | } 1589 | 1590 | ////////////////////////////////////////////////////////////////////////////// 1591 | // 1592 | // Rasterizer 1593 | 1594 | typedef struct stbtt__hheap_chunk 1595 | { 1596 | struct stbtt__hheap_chunk *next; 1597 | } stbtt__hheap_chunk; 1598 | 1599 | typedef struct stbtt__hheap 1600 | { 1601 | struct stbtt__hheap_chunk *head; 1602 | void *first_free; 1603 | int num_remaining_in_head_chunk; 1604 | } stbtt__hheap; 1605 | 1606 | static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) 1607 | { 1608 | if (hh->first_free) { 1609 | void *p = hh->first_free; 1610 | hh->first_free = * (void **) p; 1611 | return p; 1612 | } else { 1613 | if (hh->num_remaining_in_head_chunk == 0) { 1614 | int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); 1615 | stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); 1616 | if (c == NULL) 1617 | return NULL; 1618 | c->next = hh->head; 1619 | hh->head = c; 1620 | hh->num_remaining_in_head_chunk = count; 1621 | } 1622 | --hh->num_remaining_in_head_chunk; 1623 | return (char *) (hh->head) + size * hh->num_remaining_in_head_chunk; 1624 | } 1625 | } 1626 | 1627 | static void stbtt__hheap_free(stbtt__hheap *hh, void *p) 1628 | { 1629 | *(void **) p = hh->first_free; 1630 | hh->first_free = p; 1631 | } 1632 | 1633 | static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) 1634 | { 1635 | stbtt__hheap_chunk *c = hh->head; 1636 | while (c) { 1637 | stbtt__hheap_chunk *n = c->next; 1638 | STBTT_free(c, userdata); 1639 | c = n; 1640 | } 1641 | } 1642 | 1643 | typedef struct stbtt__edge { 1644 | float x0,y0, x1,y1; 1645 | int invert; 1646 | } stbtt__edge; 1647 | 1648 | 1649 | typedef struct stbtt__active_edge 1650 | { 1651 | struct stbtt__active_edge *next; 1652 | #if STBTT_RASTERIZER_VERSION==1 1653 | int x,dx; 1654 | float ey; 1655 | int direction; 1656 | #elif STBTT_RASTERIZER_VERSION==2 1657 | float fx,fdx,fdy; 1658 | float direction; 1659 | float sy; 1660 | float ey; 1661 | #else 1662 | #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 1663 | #endif 1664 | } stbtt__active_edge; 1665 | 1666 | #if STBTT_RASTERIZER_VERSION == 1 1667 | #define STBTT_FIXSHIFT 10 1668 | #define STBTT_FIX (1 << STBTT_FIXSHIFT) 1669 | #define STBTT_FIXMASK (STBTT_FIX-1) 1670 | 1671 | static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) 1672 | { 1673 | stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); 1674 | float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); 1675 | STBTT_assert(z != NULL); 1676 | if (!z) return z; 1677 | 1678 | // round dx down to avoid overshooting 1679 | if (dxdy < 0) 1680 | z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); 1681 | else 1682 | z->dx = STBTT_ifloor(STBTT_FIX * dxdy); 1683 | 1684 | z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount 1685 | z->x -= off_x * STBTT_FIX; 1686 | 1687 | z->ey = e->y1; 1688 | z->next = 0; 1689 | z->direction = e->invert ? 1 : -1; 1690 | return z; 1691 | } 1692 | #elif STBTT_RASTERIZER_VERSION == 2 1693 | static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) 1694 | { 1695 | stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); 1696 | float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); 1697 | STBTT_assert(z != NULL); 1698 | //STBTT_assert(e->y0 <= start_point); 1699 | if (!z) return z; 1700 | z->fdx = dxdy; 1701 | z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; 1702 | z->fx = e->x0 + dxdy * (start_point - e->y0); 1703 | z->fx -= off_x; 1704 | z->direction = e->invert ? 1.0f : -1.0f; 1705 | z->sy = e->y0; 1706 | z->ey = e->y1; 1707 | z->next = 0; 1708 | return z; 1709 | } 1710 | #else 1711 | #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 1712 | #endif 1713 | 1714 | #if STBTT_RASTERIZER_VERSION == 1 1715 | // note: this routine clips fills that extend off the edges... ideally this 1716 | // wouldn't happen, but it could happen if the truetype glyph bounding boxes 1717 | // are wrong, or if the user supplies a too-small bitmap 1718 | static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) 1719 | { 1720 | // non-zero winding fill 1721 | int x0=0, w=0; 1722 | 1723 | while (e) { 1724 | if (w == 0) { 1725 | // if we're currently at zero, we need to record the edge start point 1726 | x0 = e->x; w += e->direction; 1727 | } else { 1728 | int x1 = e->x; w += e->direction; 1729 | // if we went to zero, we need to draw 1730 | if (w == 0) { 1731 | int i = x0 >> STBTT_FIXSHIFT; 1732 | int j = x1 >> STBTT_FIXSHIFT; 1733 | 1734 | if (i < len && j >= 0) { 1735 | if (i == j) { 1736 | // x0,x1 are the same pixel, so compute combined coverage 1737 | scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); 1738 | } else { 1739 | if (i >= 0) // add antialiasing for x0 1740 | scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); 1741 | else 1742 | i = -1; // clip 1743 | 1744 | if (j < len) // add antialiasing for x1 1745 | scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); 1746 | else 1747 | j = len; // clip 1748 | 1749 | for (++i; i < j; ++i) // fill pixels between x0 and x1 1750 | scanline[i] = scanline[i] + (stbtt_uint8) max_weight; 1751 | } 1752 | } 1753 | } 1754 | } 1755 | 1756 | e = e->next; 1757 | } 1758 | } 1759 | 1760 | static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) 1761 | { 1762 | stbtt__hheap hh = { 0, 0, 0 }; 1763 | stbtt__active_edge *active = NULL; 1764 | int y,j=0; 1765 | int max_weight = (255 / vsubsample); // weight per vertical scanline 1766 | int s; // vertical subsample index 1767 | unsigned char scanline_data[512], *scanline; 1768 | 1769 | if (result->w > 512) 1770 | scanline = (unsigned char *) STBTT_malloc(result->w, userdata); 1771 | else 1772 | scanline = scanline_data; 1773 | 1774 | y = off_y * vsubsample; 1775 | e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; 1776 | 1777 | while (j < result->h) { 1778 | STBTT_memset(scanline, 0, result->w); 1779 | for (s=0; s < vsubsample; ++s) { 1780 | // find center of pixel for this scanline 1781 | float scan_y = y + 0.5f; 1782 | stbtt__active_edge **step = &active; 1783 | 1784 | // update all active edges; 1785 | // remove all active edges that terminate before the center of this scanline 1786 | while (*step) { 1787 | stbtt__active_edge * z = *step; 1788 | if (z->ey <= scan_y) { 1789 | *step = z->next; // delete from list 1790 | STBTT_assert(z->direction); 1791 | z->direction = 0; 1792 | stbtt__hheap_free(&hh, z); 1793 | } else { 1794 | z->x += z->dx; // advance to position for current scanline 1795 | step = &((*step)->next); // advance through list 1796 | } 1797 | } 1798 | 1799 | // resort the list if needed 1800 | for(;;) { 1801 | int changed=0; 1802 | step = &active; 1803 | while (*step && (*step)->next) { 1804 | if ((*step)->x > (*step)->next->x) { 1805 | stbtt__active_edge *t = *step; 1806 | stbtt__active_edge *q = t->next; 1807 | 1808 | t->next = q->next; 1809 | q->next = t; 1810 | *step = q; 1811 | changed = 1; 1812 | } 1813 | step = &(*step)->next; 1814 | } 1815 | if (!changed) break; 1816 | } 1817 | 1818 | // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline 1819 | while (e->y0 <= scan_y) { 1820 | if (e->y1 > scan_y) { 1821 | stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); 1822 | if (z != NULL) { 1823 | // find insertion point 1824 | if (active == NULL) 1825 | active = z; 1826 | else if (z->x < active->x) { 1827 | // insert at front 1828 | z->next = active; 1829 | active = z; 1830 | } else { 1831 | // find thing to insert AFTER 1832 | stbtt__active_edge *p = active; 1833 | while (p->next && p->next->x < z->x) 1834 | p = p->next; 1835 | // at this point, p->next->x is NOT < z->x 1836 | z->next = p->next; 1837 | p->next = z; 1838 | } 1839 | } 1840 | } 1841 | ++e; 1842 | } 1843 | 1844 | // now process all active edges in XOR fashion 1845 | if (active) 1846 | stbtt__fill_active_edges(scanline, result->w, active, max_weight); 1847 | 1848 | ++y; 1849 | } 1850 | STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); 1851 | ++j; 1852 | } 1853 | 1854 | stbtt__hheap_cleanup(&hh, userdata); 1855 | 1856 | if (scanline != scanline_data) 1857 | STBTT_free(scanline, userdata); 1858 | } 1859 | 1860 | #elif STBTT_RASTERIZER_VERSION == 2 1861 | 1862 | // the edge passed in here does not cross the vertical line at x or the vertical line at x+1 1863 | // (i.e. it has already been clipped to those) 1864 | static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) 1865 | { 1866 | if (y0 == y1) return; 1867 | STBTT_assert(y0 < y1); 1868 | STBTT_assert(e->sy <= e->ey); 1869 | if (y0 > e->ey) return; 1870 | if (y1 < e->sy) return; 1871 | if (y0 < e->sy) { 1872 | x0 += (x1-x0) * (e->sy - y0) / (y1-y0); 1873 | y0 = e->sy; 1874 | } 1875 | if (y1 > e->ey) { 1876 | x1 += (x1-x0) * (e->ey - y1) / (y1-y0); 1877 | y1 = e->ey; 1878 | } 1879 | 1880 | if (x0 == x) 1881 | STBTT_assert(x1 <= x+1); 1882 | else if (x0 == x+1) 1883 | STBTT_assert(x1 >= x); 1884 | else if (x0 <= x) 1885 | STBTT_assert(x1 <= x); 1886 | else if (x0 >= x+1) 1887 | STBTT_assert(x1 >= x+1); 1888 | else 1889 | STBTT_assert(x1 >= x && x1 <= x+1); 1890 | 1891 | if (x0 <= x && x1 <= x) 1892 | scanline[x] += e->direction * (y1-y0); 1893 | else if (x0 >= x+1 && x1 >= x+1) 1894 | ; 1895 | else { 1896 | STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); 1897 | scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position 1898 | } 1899 | } 1900 | 1901 | static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) 1902 | { 1903 | float y_bottom = y_top+1; 1904 | 1905 | while (e) { 1906 | // brute force every pixel 1907 | 1908 | // compute intersection points with top & bottom 1909 | STBTT_assert(e->ey >= y_top); 1910 | 1911 | if (e->fdx == 0) { 1912 | float x0 = e->fx; 1913 | if (x0 < len) { 1914 | if (x0 >= 0) { 1915 | stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); 1916 | stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); 1917 | } else { 1918 | stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); 1919 | } 1920 | } 1921 | } else { 1922 | float x0 = e->fx; 1923 | float dx = e->fdx; 1924 | float xb = x0 + dx; 1925 | float x_top, x_bottom; 1926 | float sy0,sy1; 1927 | float dy = e->fdy; 1928 | STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); 1929 | 1930 | // compute endpoints of line segment clipped to this scanline (if the 1931 | // line segment starts on this scanline. x0 is the intersection of the 1932 | // line with y_top, but that may be off the line segment. 1933 | if (e->sy > y_top) { 1934 | x_top = x0 + dx * (e->sy - y_top); 1935 | sy0 = e->sy; 1936 | } else { 1937 | x_top = x0; 1938 | sy0 = y_top; 1939 | } 1940 | if (e->ey < y_bottom) { 1941 | x_bottom = x0 + dx * (e->ey - y_top); 1942 | sy1 = e->ey; 1943 | } else { 1944 | x_bottom = xb; 1945 | sy1 = y_bottom; 1946 | } 1947 | 1948 | if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { 1949 | // from here on, we don't have to range check x values 1950 | 1951 | if ((int) x_top == (int) x_bottom) { 1952 | float height; 1953 | // simple case, only spans one pixel 1954 | int x = (int) x_top; 1955 | height = sy1 - sy0; 1956 | STBTT_assert(x >= 0 && x < len); 1957 | scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; 1958 | scanline_fill[x] += e->direction * height; // everything right of this pixel is filled 1959 | } else { 1960 | int x,x1,x2; 1961 | float y_crossing, step, sign, area; 1962 | // covers 2+ pixels 1963 | if (x_top > x_bottom) { 1964 | // flip scanline vertically; signed area is the same 1965 | float t; 1966 | sy0 = y_bottom - (sy0 - y_top); 1967 | sy1 = y_bottom - (sy1 - y_top); 1968 | t = sy0, sy0 = sy1, sy1 = t; 1969 | t = x_bottom, x_bottom = x_top, x_top = t; 1970 | dx = -dx; 1971 | dy = -dy; 1972 | t = x0, x0 = xb, xb = t; 1973 | } 1974 | 1975 | x1 = (int) x_top; 1976 | x2 = (int) x_bottom; 1977 | // compute intersection with y axis at x1+1 1978 | y_crossing = (x1+1 - x0) * dy + y_top; 1979 | 1980 | sign = e->direction; 1981 | // area of the rectangle covered from y0..y_crossing 1982 | area = sign * (y_crossing-sy0); 1983 | // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) 1984 | scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); 1985 | 1986 | step = sign * dy; 1987 | for (x = x1+1; x < x2; ++x) { 1988 | scanline[x] += area + step/2; 1989 | area += step; 1990 | } 1991 | y_crossing += dy * (x2 - (x1+1)); 1992 | 1993 | STBTT_assert(STBTT_fabs(area) <= 1.01f); 1994 | 1995 | scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); 1996 | 1997 | scanline_fill[x2] += sign * (sy1-sy0); 1998 | } 1999 | } else { 2000 | // if edge goes outside of box we're drawing, we require 2001 | // clipping logic. since this does not match the intended use 2002 | // of this library, we use a different, very slow brute 2003 | // force implementation 2004 | int x; 2005 | for (x=0; x < len; ++x) { 2006 | // cases: 2007 | // 2008 | // there can be up to two intersections with the pixel. any intersection 2009 | // with left or right edges can be handled by splitting into two (or three) 2010 | // regions. intersections with top & bottom do not necessitate case-wise logic. 2011 | // 2012 | // the old way of doing this found the intersections with the left & right edges, 2013 | // then used some simple logic to produce up to three segments in sorted order 2014 | // from top-to-bottom. however, this had a problem: if an x edge was epsilon 2015 | // across the x border, then the corresponding y position might not be distinct 2016 | // from the other y segment, and it might ignored as an empty segment. to avoid 2017 | // that, we need to explicitly produce segments based on x positions. 2018 | 2019 | // rename variables to clear pairs 2020 | float y0 = y_top; 2021 | float x1 = (float) (x); 2022 | float x2 = (float) (x+1); 2023 | float x3 = xb; 2024 | float y3 = y_bottom; 2025 | float y1,y2; 2026 | 2027 | // x = e->x + e->dx * (y-y_top) 2028 | // (y-y_top) = (x - e->x) / e->dx 2029 | // y = (x - e->x) / e->dx + y_top 2030 | y1 = (x - x0) / dx + y_top; 2031 | y2 = (x+1 - x0) / dx + y_top; 2032 | 2033 | if (x0 < x1 && x3 > x2) { // three segments descending down-right 2034 | stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 2035 | stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); 2036 | stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 2037 | } else if (x3 < x1 && x0 > x2) { // three segments descending down-left 2038 | stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 2039 | stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); 2040 | stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 2041 | } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right 2042 | stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 2043 | stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 2044 | } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left 2045 | stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 2046 | stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 2047 | } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right 2048 | stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 2049 | stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 2050 | } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left 2051 | stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 2052 | stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 2053 | } else { // one segment 2054 | stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); 2055 | } 2056 | } 2057 | } 2058 | } 2059 | e = e->next; 2060 | } 2061 | } 2062 | 2063 | // directly AA rasterize edges w/o supersampling 2064 | static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) 2065 | { 2066 | stbtt__hheap hh = { 0, 0, 0 }; 2067 | stbtt__active_edge *active = NULL; 2068 | int y,j=0, i; 2069 | float scanline_data[129], *scanline, *scanline2; 2070 | 2071 | STBTT__NOTUSED(vsubsample); 2072 | 2073 | if (result->w > 64) 2074 | scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); 2075 | else 2076 | scanline = scanline_data; 2077 | 2078 | scanline2 = scanline + result->w; 2079 | 2080 | y = off_y; 2081 | e[n].y0 = (float) (off_y + result->h) + 1; 2082 | 2083 | while (j < result->h) { 2084 | // find center of pixel for this scanline 2085 | float scan_y_top = y + 0.0f; 2086 | float scan_y_bottom = y + 1.0f; 2087 | stbtt__active_edge **step = &active; 2088 | 2089 | STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); 2090 | STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); 2091 | 2092 | // update all active edges; 2093 | // remove all active edges that terminate before the top of this scanline 2094 | while (*step) { 2095 | stbtt__active_edge * z = *step; 2096 | if (z->ey <= scan_y_top) { 2097 | *step = z->next; // delete from list 2098 | STBTT_assert(z->direction); 2099 | z->direction = 0; 2100 | stbtt__hheap_free(&hh, z); 2101 | } else { 2102 | step = &((*step)->next); // advance through list 2103 | } 2104 | } 2105 | 2106 | // insert all edges that start before the bottom of this scanline 2107 | while (e->y0 <= scan_y_bottom) { 2108 | if (e->y0 != e->y1) { 2109 | stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); 2110 | if (z != NULL) { 2111 | STBTT_assert(z->ey >= scan_y_top); 2112 | // insert at front 2113 | z->next = active; 2114 | active = z; 2115 | } 2116 | } 2117 | ++e; 2118 | } 2119 | 2120 | // now process all active edges 2121 | if (active) 2122 | stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); 2123 | 2124 | { 2125 | float sum = 0; 2126 | for (i=0; i < result->w; ++i) { 2127 | float k; 2128 | int m; 2129 | sum += scanline2[i]; 2130 | k = scanline[i] + sum; 2131 | k = (float) STBTT_fabs(k)*255 + 0.5f; 2132 | m = (int) k; 2133 | if (m > 255) m = 255; 2134 | result->pixels[j*result->stride + i] = (unsigned char) m; 2135 | } 2136 | } 2137 | // advance all the edges 2138 | step = &active; 2139 | while (*step) { 2140 | stbtt__active_edge *z = *step; 2141 | z->fx += z->fdx; // advance to position for current scanline 2142 | step = &((*step)->next); // advance through list 2143 | } 2144 | 2145 | ++y; 2146 | ++j; 2147 | } 2148 | 2149 | stbtt__hheap_cleanup(&hh, userdata); 2150 | 2151 | if (scanline != scanline_data) 2152 | STBTT_free(scanline, userdata); 2153 | } 2154 | #else 2155 | #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 2156 | #endif 2157 | 2158 | #define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) 2159 | 2160 | static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) 2161 | { 2162 | int i,j; 2163 | for (i=1; i < n; ++i) { 2164 | stbtt__edge t = p[i], *a = &t; 2165 | j = i; 2166 | while (j > 0) { 2167 | stbtt__edge *b = &p[j-1]; 2168 | int c = STBTT__COMPARE(a,b); 2169 | if (!c) break; 2170 | p[j] = p[j-1]; 2171 | --j; 2172 | } 2173 | if (i != j) 2174 | p[j] = t; 2175 | } 2176 | } 2177 | 2178 | static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) 2179 | { 2180 | /* threshhold for transitioning to insertion sort */ 2181 | while (n > 12) { 2182 | stbtt__edge t; 2183 | int c01,c12,c,m,i,j; 2184 | 2185 | /* compute median of three */ 2186 | m = n >> 1; 2187 | c01 = STBTT__COMPARE(&p[0],&p[m]); 2188 | c12 = STBTT__COMPARE(&p[m],&p[n-1]); 2189 | /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ 2190 | if (c01 != c12) { 2191 | /* otherwise, we'll need to swap something else to middle */ 2192 | int z; 2193 | c = STBTT__COMPARE(&p[0],&p[n-1]); 2194 | /* 0>mid && midn => n; 0 0 */ 2195 | /* 0n: 0>n => 0; 0 n */ 2196 | z = (c == c12) ? 0 : n-1; 2197 | t = p[z]; 2198 | p[z] = p[m]; 2199 | p[m] = t; 2200 | } 2201 | /* now p[m] is the median-of-three */ 2202 | /* swap it to the beginning so it won't move around */ 2203 | t = p[0]; 2204 | p[0] = p[m]; 2205 | p[m] = t; 2206 | 2207 | /* partition loop */ 2208 | i=1; 2209 | j=n-1; 2210 | for(;;) { 2211 | /* handling of equality is crucial here */ 2212 | /* for sentinels & efficiency with duplicates */ 2213 | for (;;++i) { 2214 | if (!STBTT__COMPARE(&p[i], &p[0])) break; 2215 | } 2216 | for (;;--j) { 2217 | if (!STBTT__COMPARE(&p[0], &p[j])) break; 2218 | } 2219 | /* make sure we haven't crossed */ 2220 | if (i >= j) break; 2221 | t = p[i]; 2222 | p[i] = p[j]; 2223 | p[j] = t; 2224 | 2225 | ++i; 2226 | --j; 2227 | } 2228 | /* recurse on smaller side, iterate on larger */ 2229 | if (j < (n-i)) { 2230 | stbtt__sort_edges_quicksort(p,j); 2231 | p = p+i; 2232 | n = n-i; 2233 | } else { 2234 | stbtt__sort_edges_quicksort(p+i, n-i); 2235 | n = j; 2236 | } 2237 | } 2238 | } 2239 | 2240 | static void stbtt__sort_edges(stbtt__edge *p, int n) 2241 | { 2242 | stbtt__sort_edges_quicksort(p, n); 2243 | stbtt__sort_edges_ins_sort(p, n); 2244 | } 2245 | 2246 | typedef struct 2247 | { 2248 | float x,y; 2249 | } stbtt__point; 2250 | 2251 | static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) 2252 | { 2253 | float y_scale_inv = invert ? -scale_y : scale_y; 2254 | stbtt__edge *e; 2255 | int n,i,j,k,m; 2256 | #if STBTT_RASTERIZER_VERSION == 1 2257 | int vsubsample = result->h < 8 ? 15 : 5; 2258 | #elif STBTT_RASTERIZER_VERSION == 2 2259 | int vsubsample = 1; 2260 | #else 2261 | #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 2262 | #endif 2263 | // vsubsample should divide 255 evenly; otherwise we won't reach full opacity 2264 | 2265 | // now we have to blow out the windings into explicit edge lists 2266 | n = 0; 2267 | for (i=0; i < windings; ++i) 2268 | n += wcount[i]; 2269 | 2270 | e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel 2271 | if (e == 0) return; 2272 | n = 0; 2273 | 2274 | m=0; 2275 | for (i=0; i < windings; ++i) { 2276 | stbtt__point *p = pts + m; 2277 | m += wcount[i]; 2278 | j = wcount[i]-1; 2279 | for (k=0; k < wcount[i]; j=k++) { 2280 | int a=k,b=j; 2281 | // skip the edge if horizontal 2282 | if (p[j].y == p[k].y) 2283 | continue; 2284 | // add edge from j to k to the list 2285 | e[n].invert = 0; 2286 | if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { 2287 | e[n].invert = 1; 2288 | a=j,b=k; 2289 | } 2290 | e[n].x0 = p[a].x * scale_x + shift_x; 2291 | e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; 2292 | e[n].x1 = p[b].x * scale_x + shift_x; 2293 | e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; 2294 | ++n; 2295 | } 2296 | } 2297 | 2298 | // now sort the edges by their highest point (should snap to integer, and then by x) 2299 | //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); 2300 | stbtt__sort_edges(e, n); 2301 | 2302 | // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule 2303 | stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); 2304 | 2305 | STBTT_free(e, userdata); 2306 | } 2307 | 2308 | static void stbtt__add_point(stbtt__point *points, int n, float x, float y) 2309 | { 2310 | if (!points) return; // during first pass, it's unallocated 2311 | points[n].x = x; 2312 | points[n].y = y; 2313 | } 2314 | 2315 | // tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching 2316 | static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) 2317 | { 2318 | // midpoint 2319 | float mx = (x0 + 2*x1 + x2)/4; 2320 | float my = (y0 + 2*y1 + y2)/4; 2321 | // versus directly drawn line 2322 | float dx = (x0+x2)/2 - mx; 2323 | float dy = (y0+y2)/2 - my; 2324 | if (n > 16) // 65536 segments on one curve better be enough! 2325 | return 1; 2326 | if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA 2327 | stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); 2328 | stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); 2329 | } else { 2330 | stbtt__add_point(points, *num_points,x2,y2); 2331 | *num_points = *num_points+1; 2332 | } 2333 | return 1; 2334 | } 2335 | 2336 | // returns number of contours 2337 | static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) 2338 | { 2339 | stbtt__point *points=0; 2340 | int num_points=0; 2341 | 2342 | float objspace_flatness_squared = objspace_flatness * objspace_flatness; 2343 | int i,n=0,start=0, pass; 2344 | 2345 | // count how many "moves" there are to get the contour count 2346 | for (i=0; i < num_verts; ++i) 2347 | if (vertices[i].type == STBTT_vmove) 2348 | ++n; 2349 | 2350 | *num_contours = n; 2351 | if (n == 0) return 0; 2352 | 2353 | *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); 2354 | 2355 | if (*contour_lengths == 0) { 2356 | *num_contours = 0; 2357 | return 0; 2358 | } 2359 | 2360 | // make two passes through the points so we don't need to realloc 2361 | for (pass=0; pass < 2; ++pass) { 2362 | float x=0,y=0; 2363 | if (pass == 1) { 2364 | points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); 2365 | if (points == NULL) goto error; 2366 | } 2367 | num_points = 0; 2368 | n= -1; 2369 | for (i=0; i < num_verts; ++i) { 2370 | switch (vertices[i].type) { 2371 | case STBTT_vmove: 2372 | // start the next contour 2373 | if (n >= 0) 2374 | (*contour_lengths)[n] = num_points - start; 2375 | ++n; 2376 | start = num_points; 2377 | 2378 | x = vertices[i].x, y = vertices[i].y; 2379 | stbtt__add_point(points, num_points++, x,y); 2380 | break; 2381 | case STBTT_vline: 2382 | x = vertices[i].x, y = vertices[i].y; 2383 | stbtt__add_point(points, num_points++, x, y); 2384 | break; 2385 | case STBTT_vcurve: 2386 | stbtt__tesselate_curve(points, &num_points, x,y, 2387 | vertices[i].cx, vertices[i].cy, 2388 | vertices[i].x, vertices[i].y, 2389 | objspace_flatness_squared, 0); 2390 | x = vertices[i].x, y = vertices[i].y; 2391 | break; 2392 | } 2393 | } 2394 | (*contour_lengths)[n] = num_points - start; 2395 | } 2396 | 2397 | return points; 2398 | error: 2399 | STBTT_free(points, userdata); 2400 | STBTT_free(*contour_lengths, userdata); 2401 | *contour_lengths = 0; 2402 | *num_contours = 0; 2403 | return NULL; 2404 | } 2405 | 2406 | STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) 2407 | { 2408 | float scale = scale_x > scale_y ? scale_y : scale_x; 2409 | int winding_count, *winding_lengths; 2410 | stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); 2411 | if (windings) { 2412 | stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); 2413 | STBTT_free(winding_lengths, userdata); 2414 | STBTT_free(windings, userdata); 2415 | } 2416 | } 2417 | 2418 | STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) 2419 | { 2420 | STBTT_free(bitmap, userdata); 2421 | } 2422 | 2423 | STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) 2424 | { 2425 | int ix0,iy0,ix1,iy1; 2426 | stbtt__bitmap gbm; 2427 | stbtt_vertex *vertices; 2428 | int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 2429 | 2430 | if (scale_x == 0) scale_x = scale_y; 2431 | if (scale_y == 0) { 2432 | if (scale_x == 0) { 2433 | STBTT_free(vertices, info->userdata); 2434 | return NULL; 2435 | } 2436 | scale_y = scale_x; 2437 | } 2438 | 2439 | stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); 2440 | 2441 | // now we get the size 2442 | gbm.w = (ix1 - ix0); 2443 | gbm.h = (iy1 - iy0); 2444 | gbm.pixels = NULL; // in case we error 2445 | 2446 | if (width ) *width = gbm.w; 2447 | if (height) *height = gbm.h; 2448 | if (xoff ) *xoff = ix0; 2449 | if (yoff ) *yoff = iy0; 2450 | 2451 | if (gbm.w && gbm.h) { 2452 | gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); 2453 | if (gbm.pixels) { 2454 | gbm.stride = gbm.w; 2455 | 2456 | stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); 2457 | } 2458 | } 2459 | STBTT_free(vertices, info->userdata); 2460 | return gbm.pixels; 2461 | } 2462 | 2463 | STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) 2464 | { 2465 | return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); 2466 | } 2467 | 2468 | STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) 2469 | { 2470 | int ix0,iy0; 2471 | stbtt_vertex *vertices; 2472 | int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 2473 | stbtt__bitmap gbm; 2474 | 2475 | stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); 2476 | gbm.pixels = output; 2477 | gbm.w = out_w; 2478 | gbm.h = out_h; 2479 | gbm.stride = out_stride; 2480 | 2481 | if (gbm.w && gbm.h) 2482 | stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); 2483 | 2484 | STBTT_free(vertices, info->userdata); 2485 | } 2486 | 2487 | STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) 2488 | { 2489 | stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); 2490 | } 2491 | 2492 | STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) 2493 | { 2494 | return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); 2495 | } 2496 | 2497 | STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) 2498 | { 2499 | stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); 2500 | } 2501 | 2502 | STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) 2503 | { 2504 | return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); 2505 | } 2506 | 2507 | STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) 2508 | { 2509 | stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); 2510 | } 2511 | 2512 | ////////////////////////////////////////////////////////////////////////////// 2513 | // 2514 | // bitmap baking 2515 | // 2516 | // This is SUPER-CRAPPY packing to keep source code small 2517 | 2518 | static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) 2519 | float pixel_height, // height of font in pixels 2520 | unsigned char *pixels, int pw, int ph, // bitmap to be filled in 2521 | int first_char, int num_chars, // characters to bake 2522 | stbtt_bakedchar *chardata) 2523 | { 2524 | float scale; 2525 | int x,y,bottom_y, i; 2526 | stbtt_fontinfo f; 2527 | f.userdata = NULL; 2528 | if (!stbtt_InitFont(&f, data, offset)) 2529 | return -1; 2530 | STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels 2531 | x=y=1; 2532 | bottom_y = 1; 2533 | 2534 | scale = stbtt_ScaleForPixelHeight(&f, pixel_height); 2535 | 2536 | for (i=0; i < num_chars; ++i) { 2537 | int advance, lsb, x0,y0,x1,y1,gw,gh; 2538 | int g = stbtt_FindGlyphIndex(&f, first_char + i); 2539 | stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); 2540 | stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); 2541 | gw = x1-x0; 2542 | gh = y1-y0; 2543 | if (x + gw + 1 >= pw) 2544 | y = bottom_y, x = 1; // advance to next row 2545 | if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row 2546 | return -i; 2547 | STBTT_assert(x+gw < pw); 2548 | STBTT_assert(y+gh < ph); 2549 | stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); 2550 | chardata[i].x0 = (stbtt_int16) x; 2551 | chardata[i].y0 = (stbtt_int16) y; 2552 | chardata[i].x1 = (stbtt_int16) (x + gw); 2553 | chardata[i].y1 = (stbtt_int16) (y + gh); 2554 | chardata[i].xadvance = scale * advance; 2555 | chardata[i].xoff = (float) x0; 2556 | chardata[i].yoff = (float) y0; 2557 | x = x + gw + 1; 2558 | if (y+gh+1 > bottom_y) 2559 | bottom_y = y+gh+1; 2560 | } 2561 | return bottom_y; 2562 | } 2563 | 2564 | STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) 2565 | { 2566 | float d3d_bias = opengl_fillrule ? 0 : -0.5f; 2567 | float ipw = 1.0f / pw, iph = 1.0f / ph; 2568 | stbtt_bakedchar *b = chardata + char_index; 2569 | int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); 2570 | int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); 2571 | 2572 | q->x0 = round_x + d3d_bias; 2573 | q->y0 = round_y + d3d_bias; 2574 | q->x1 = round_x + b->x1 - b->x0 + d3d_bias; 2575 | q->y1 = round_y + b->y1 - b->y0 + d3d_bias; 2576 | 2577 | q->s0 = b->x0 * ipw; 2578 | q->t0 = b->y0 * iph; 2579 | q->s1 = b->x1 * ipw; 2580 | q->t1 = b->y1 * iph; 2581 | 2582 | *xpos += b->xadvance; 2583 | } 2584 | 2585 | ////////////////////////////////////////////////////////////////////////////// 2586 | // 2587 | // rectangle packing replacement routines if you don't have stb_rect_pack.h 2588 | // 2589 | 2590 | #ifndef STB_RECT_PACK_VERSION 2591 | 2592 | typedef int stbrp_coord; 2593 | 2594 | //////////////////////////////////////////////////////////////////////////////////// 2595 | // // 2596 | // // 2597 | // COMPILER WARNING ?!?!? // 2598 | // // 2599 | // // 2600 | // if you get a compile warning due to these symbols being defined more than // 2601 | // once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // 2602 | // // 2603 | //////////////////////////////////////////////////////////////////////////////////// 2604 | 2605 | typedef struct 2606 | { 2607 | int width,height; 2608 | int x,y,bottom_y; 2609 | } stbrp_context; 2610 | 2611 | typedef struct 2612 | { 2613 | unsigned char x; 2614 | } stbrp_node; 2615 | 2616 | struct stbrp_rect 2617 | { 2618 | stbrp_coord x,y; 2619 | int id,w,h,was_packed; 2620 | }; 2621 | 2622 | static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) 2623 | { 2624 | con->width = pw; 2625 | con->height = ph; 2626 | con->x = 0; 2627 | con->y = 0; 2628 | con->bottom_y = 0; 2629 | STBTT__NOTUSED(nodes); 2630 | STBTT__NOTUSED(num_nodes); 2631 | } 2632 | 2633 | static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) 2634 | { 2635 | int i; 2636 | for (i=0; i < num_rects; ++i) { 2637 | if (con->x + rects[i].w > con->width) { 2638 | con->x = 0; 2639 | con->y = con->bottom_y; 2640 | } 2641 | if (con->y + rects[i].h > con->height) 2642 | break; 2643 | rects[i].x = con->x; 2644 | rects[i].y = con->y; 2645 | rects[i].was_packed = 1; 2646 | con->x += rects[i].w; 2647 | if (con->y + rects[i].h > con->bottom_y) 2648 | con->bottom_y = con->y + rects[i].h; 2649 | } 2650 | for ( ; i < num_rects; ++i) 2651 | rects[i].was_packed = 0; 2652 | } 2653 | #endif 2654 | 2655 | ////////////////////////////////////////////////////////////////////////////// 2656 | // 2657 | // bitmap baking 2658 | // 2659 | // This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If 2660 | // stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. 2661 | 2662 | STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) 2663 | { 2664 | stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); 2665 | int num_nodes = pw - padding; 2666 | stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); 2667 | 2668 | if (context == NULL || nodes == NULL) { 2669 | if (context != NULL) STBTT_free(context, alloc_context); 2670 | if (nodes != NULL) STBTT_free(nodes , alloc_context); 2671 | return 0; 2672 | } 2673 | 2674 | spc->user_allocator_context = alloc_context; 2675 | spc->width = pw; 2676 | spc->height = ph; 2677 | spc->pixels = pixels; 2678 | spc->pack_info = context; 2679 | spc->nodes = nodes; 2680 | spc->padding = padding; 2681 | spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; 2682 | spc->h_oversample = 1; 2683 | spc->v_oversample = 1; 2684 | 2685 | stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); 2686 | 2687 | if (pixels) 2688 | STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels 2689 | 2690 | return 1; 2691 | } 2692 | 2693 | STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) 2694 | { 2695 | STBTT_free(spc->nodes , spc->user_allocator_context); 2696 | STBTT_free(spc->pack_info, spc->user_allocator_context); 2697 | } 2698 | 2699 | STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) 2700 | { 2701 | STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); 2702 | STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); 2703 | if (h_oversample <= STBTT_MAX_OVERSAMPLE) 2704 | spc->h_oversample = h_oversample; 2705 | if (v_oversample <= STBTT_MAX_OVERSAMPLE) 2706 | spc->v_oversample = v_oversample; 2707 | } 2708 | 2709 | #define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) 2710 | 2711 | static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) 2712 | { 2713 | unsigned char buffer[STBTT_MAX_OVERSAMPLE]; 2714 | int safe_w = w - kernel_width; 2715 | int j; 2716 | STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze 2717 | for (j=0; j < h; ++j) { 2718 | int i; 2719 | unsigned int total; 2720 | STBTT_memset(buffer, 0, kernel_width); 2721 | 2722 | total = 0; 2723 | 2724 | // make kernel_width a constant in common cases so compiler can optimize out the divide 2725 | switch (kernel_width) { 2726 | case 2: 2727 | for (i=0; i <= safe_w; ++i) { 2728 | total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 2729 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 2730 | pixels[i] = (unsigned char) (total / 2); 2731 | } 2732 | break; 2733 | case 3: 2734 | for (i=0; i <= safe_w; ++i) { 2735 | total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 2736 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 2737 | pixels[i] = (unsigned char) (total / 3); 2738 | } 2739 | break; 2740 | case 4: 2741 | for (i=0; i <= safe_w; ++i) { 2742 | total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 2743 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 2744 | pixels[i] = (unsigned char) (total / 4); 2745 | } 2746 | break; 2747 | case 5: 2748 | for (i=0; i <= safe_w; ++i) { 2749 | total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 2750 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 2751 | pixels[i] = (unsigned char) (total / 5); 2752 | } 2753 | break; 2754 | default: 2755 | for (i=0; i <= safe_w; ++i) { 2756 | total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 2757 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 2758 | pixels[i] = (unsigned char) (total / kernel_width); 2759 | } 2760 | break; 2761 | } 2762 | 2763 | for (; i < w; ++i) { 2764 | STBTT_assert(pixels[i] == 0); 2765 | total -= buffer[i & STBTT__OVER_MASK]; 2766 | pixels[i] = (unsigned char) (total / kernel_width); 2767 | } 2768 | 2769 | pixels += stride_in_bytes; 2770 | } 2771 | } 2772 | 2773 | static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) 2774 | { 2775 | unsigned char buffer[STBTT_MAX_OVERSAMPLE]; 2776 | int safe_h = h - kernel_width; 2777 | int j; 2778 | STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze 2779 | for (j=0; j < w; ++j) { 2780 | int i; 2781 | unsigned int total; 2782 | STBTT_memset(buffer, 0, kernel_width); 2783 | 2784 | total = 0; 2785 | 2786 | // make kernel_width a constant in common cases so compiler can optimize out the divide 2787 | switch (kernel_width) { 2788 | case 2: 2789 | for (i=0; i <= safe_h; ++i) { 2790 | total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 2791 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 2792 | pixels[i*stride_in_bytes] = (unsigned char) (total / 2); 2793 | } 2794 | break; 2795 | case 3: 2796 | for (i=0; i <= safe_h; ++i) { 2797 | total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 2798 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 2799 | pixels[i*stride_in_bytes] = (unsigned char) (total / 3); 2800 | } 2801 | break; 2802 | case 4: 2803 | for (i=0; i <= safe_h; ++i) { 2804 | total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 2805 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 2806 | pixels[i*stride_in_bytes] = (unsigned char) (total / 4); 2807 | } 2808 | break; 2809 | case 5: 2810 | for (i=0; i <= safe_h; ++i) { 2811 | total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 2812 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 2813 | pixels[i*stride_in_bytes] = (unsigned char) (total / 5); 2814 | } 2815 | break; 2816 | default: 2817 | for (i=0; i <= safe_h; ++i) { 2818 | total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 2819 | buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 2820 | pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); 2821 | } 2822 | break; 2823 | } 2824 | 2825 | for (; i < h; ++i) { 2826 | STBTT_assert(pixels[i*stride_in_bytes] == 0); 2827 | total -= buffer[i & STBTT__OVER_MASK]; 2828 | pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); 2829 | } 2830 | 2831 | pixels += 1; 2832 | } 2833 | } 2834 | 2835 | static float stbtt__oversample_shift(int oversample) 2836 | { 2837 | if (!oversample) 2838 | return 0.0f; 2839 | 2840 | // The prefilter is a box filter of width "oversample", 2841 | // which shifts phase by (oversample - 1)/2 pixels in 2842 | // oversampled space. We want to shift in the opposite 2843 | // direction to counter this. 2844 | return (float)-(oversample - 1) / (2.0f * (float)oversample); 2845 | } 2846 | 2847 | // rects array must be big enough to accommodate all characters in the given ranges 2848 | STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) 2849 | { 2850 | int i,j,k; 2851 | 2852 | k=0; 2853 | for (i=0; i < num_ranges; ++i) { 2854 | float fh = ranges[i].font_size; 2855 | float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); 2856 | ranges[i].h_oversample = (unsigned char) spc->h_oversample; 2857 | ranges[i].v_oversample = (unsigned char) spc->v_oversample; 2858 | for (j=0; j < ranges[i].num_chars; ++j) { 2859 | int x0,y0,x1,y1; 2860 | int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; 2861 | int glyph = stbtt_FindGlyphIndex(info, codepoint); 2862 | stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, 2863 | scale * spc->h_oversample, 2864 | scale * spc->v_oversample, 2865 | 0,0, 2866 | &x0,&y0,&x1,&y1); 2867 | rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); 2868 | rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); 2869 | ++k; 2870 | } 2871 | } 2872 | 2873 | return k; 2874 | } 2875 | 2876 | // rects array must be big enough to accommodate all characters in the given ranges 2877 | STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) 2878 | { 2879 | int i,j,k, return_value = 1; 2880 | 2881 | // save current values 2882 | int old_h_over = spc->h_oversample; 2883 | int old_v_over = spc->v_oversample; 2884 | 2885 | k = 0; 2886 | for (i=0; i < num_ranges; ++i) { 2887 | float fh = ranges[i].font_size; 2888 | float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); 2889 | float recip_h,recip_v,sub_x,sub_y; 2890 | spc->h_oversample = ranges[i].h_oversample; 2891 | spc->v_oversample = ranges[i].v_oversample; 2892 | recip_h = 1.0f / spc->h_oversample; 2893 | recip_v = 1.0f / spc->v_oversample; 2894 | sub_x = stbtt__oversample_shift(spc->h_oversample); 2895 | sub_y = stbtt__oversample_shift(spc->v_oversample); 2896 | for (j=0; j < ranges[i].num_chars; ++j) { 2897 | stbrp_rect *r = &rects[k]; 2898 | if (r->was_packed) { 2899 | stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; 2900 | int advance, lsb, x0,y0,x1,y1; 2901 | int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; 2902 | int glyph = stbtt_FindGlyphIndex(info, codepoint); 2903 | stbrp_coord pad = (stbrp_coord) spc->padding; 2904 | 2905 | // pad on left and top 2906 | r->x += pad; 2907 | r->y += pad; 2908 | r->w -= pad; 2909 | r->h -= pad; 2910 | stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); 2911 | stbtt_GetGlyphBitmapBox(info, glyph, 2912 | scale * spc->h_oversample, 2913 | scale * spc->v_oversample, 2914 | &x0,&y0,&x1,&y1); 2915 | stbtt_MakeGlyphBitmapSubpixel(info, 2916 | spc->pixels + r->x + r->y*spc->stride_in_bytes, 2917 | r->w - spc->h_oversample+1, 2918 | r->h - spc->v_oversample+1, 2919 | spc->stride_in_bytes, 2920 | scale * spc->h_oversample, 2921 | scale * spc->v_oversample, 2922 | 0,0, 2923 | glyph); 2924 | 2925 | if (spc->h_oversample > 1) 2926 | stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, 2927 | r->w, r->h, spc->stride_in_bytes, 2928 | spc->h_oversample); 2929 | 2930 | if (spc->v_oversample > 1) 2931 | stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, 2932 | r->w, r->h, spc->stride_in_bytes, 2933 | spc->v_oversample); 2934 | 2935 | bc->x0 = (stbtt_int16) r->x; 2936 | bc->y0 = (stbtt_int16) r->y; 2937 | bc->x1 = (stbtt_int16) (r->x + r->w); 2938 | bc->y1 = (stbtt_int16) (r->y + r->h); 2939 | bc->xadvance = scale * advance; 2940 | bc->xoff = (float) x0 * recip_h + sub_x; 2941 | bc->yoff = (float) y0 * recip_v + sub_y; 2942 | bc->xoff2 = (x0 + r->w) * recip_h + sub_x; 2943 | bc->yoff2 = (y0 + r->h) * recip_v + sub_y; 2944 | } else { 2945 | return_value = 0; // if any fail, report failure 2946 | } 2947 | 2948 | ++k; 2949 | } 2950 | } 2951 | 2952 | // restore original values 2953 | spc->h_oversample = old_h_over; 2954 | spc->v_oversample = old_v_over; 2955 | 2956 | return return_value; 2957 | } 2958 | 2959 | STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) 2960 | { 2961 | stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); 2962 | } 2963 | 2964 | STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) 2965 | { 2966 | stbtt_fontinfo info; 2967 | int i,j,n, return_value = 1; 2968 | //stbrp_context *context = (stbrp_context *) spc->pack_info; 2969 | stbrp_rect *rects; 2970 | 2971 | // flag all characters as NOT packed 2972 | for (i=0; i < num_ranges; ++i) 2973 | for (j=0; j < ranges[i].num_chars; ++j) 2974 | ranges[i].chardata_for_range[j].x0 = 2975 | ranges[i].chardata_for_range[j].y0 = 2976 | ranges[i].chardata_for_range[j].x1 = 2977 | ranges[i].chardata_for_range[j].y1 = 0; 2978 | 2979 | n = 0; 2980 | for (i=0; i < num_ranges; ++i) 2981 | n += ranges[i].num_chars; 2982 | 2983 | rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); 2984 | if (rects == NULL) 2985 | return 0; 2986 | 2987 | info.userdata = spc->user_allocator_context; 2988 | stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); 2989 | 2990 | n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); 2991 | 2992 | stbtt_PackFontRangesPackRects(spc, rects, n); 2993 | 2994 | return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); 2995 | 2996 | STBTT_free(rects, spc->user_allocator_context); 2997 | return return_value; 2998 | } 2999 | 3000 | STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, 3001 | int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) 3002 | { 3003 | stbtt_pack_range range; 3004 | range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; 3005 | range.array_of_unicode_codepoints = NULL; 3006 | range.num_chars = num_chars_in_range; 3007 | range.chardata_for_range = chardata_for_range; 3008 | range.font_size = font_size; 3009 | return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); 3010 | } 3011 | 3012 | STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) 3013 | { 3014 | float ipw = 1.0f / pw, iph = 1.0f / ph; 3015 | stbtt_packedchar *b = chardata + char_index; 3016 | 3017 | if (align_to_integer) { 3018 | float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); 3019 | float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); 3020 | q->x0 = x; 3021 | q->y0 = y; 3022 | q->x1 = x + b->xoff2 - b->xoff; 3023 | q->y1 = y + b->yoff2 - b->yoff; 3024 | } else { 3025 | q->x0 = *xpos + b->xoff; 3026 | q->y0 = *ypos + b->yoff; 3027 | q->x1 = *xpos + b->xoff2; 3028 | q->y1 = *ypos + b->yoff2; 3029 | } 3030 | 3031 | q->s0 = b->x0 * ipw; 3032 | q->t0 = b->y0 * iph; 3033 | q->s1 = b->x1 * ipw; 3034 | q->t1 = b->y1 * iph; 3035 | 3036 | *xpos += b->xadvance; 3037 | } 3038 | 3039 | 3040 | ////////////////////////////////////////////////////////////////////////////// 3041 | // 3042 | // font name matching -- recommended not to use this 3043 | // 3044 | 3045 | // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string 3046 | static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) 3047 | { 3048 | stbtt_int32 i=0; 3049 | 3050 | // convert utf16 to utf8 and compare the results while converting 3051 | while (len2) { 3052 | stbtt_uint16 ch = s2[0]*256 + s2[1]; 3053 | if (ch < 0x80) { 3054 | if (i >= len1) return -1; 3055 | if (s1[i++] != ch) return -1; 3056 | } else if (ch < 0x800) { 3057 | if (i+1 >= len1) return -1; 3058 | if (s1[i++] != 0xc0 + (ch >> 6)) return -1; 3059 | if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; 3060 | } else if (ch >= 0xd800 && ch < 0xdc00) { 3061 | stbtt_uint32 c; 3062 | stbtt_uint16 ch2 = s2[2]*256 + s2[3]; 3063 | if (i+3 >= len1) return -1; 3064 | c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; 3065 | if (s1[i++] != 0xf0 + (c >> 18)) return -1; 3066 | if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; 3067 | if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; 3068 | if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; 3069 | s2 += 2; // plus another 2 below 3070 | len2 -= 2; 3071 | } else if (ch >= 0xdc00 && ch < 0xe000) { 3072 | return -1; 3073 | } else { 3074 | if (i+2 >= len1) return -1; 3075 | if (s1[i++] != 0xe0 + (ch >> 12)) return -1; 3076 | if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; 3077 | if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; 3078 | } 3079 | s2 += 2; 3080 | len2 -= 2; 3081 | } 3082 | return i; 3083 | } 3084 | 3085 | static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) 3086 | { 3087 | return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); 3088 | } 3089 | 3090 | // returns results in whatever encoding you request... but note that 2-byte encodings 3091 | // will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare 3092 | STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) 3093 | { 3094 | stbtt_int32 i,count,stringOffset; 3095 | stbtt_uint8 *fc = font->data; 3096 | stbtt_uint32 offset = font->fontstart; 3097 | stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); 3098 | if (!nm) return NULL; 3099 | 3100 | count = ttUSHORT(fc+nm+2); 3101 | stringOffset = nm + ttUSHORT(fc+nm+4); 3102 | for (i=0; i < count; ++i) { 3103 | stbtt_uint32 loc = nm + 6 + 12 * i; 3104 | if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) 3105 | && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { 3106 | *length = ttUSHORT(fc+loc+8); 3107 | return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); 3108 | } 3109 | } 3110 | return NULL; 3111 | } 3112 | 3113 | static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) 3114 | { 3115 | stbtt_int32 i; 3116 | stbtt_int32 count = ttUSHORT(fc+nm+2); 3117 | stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); 3118 | 3119 | for (i=0; i < count; ++i) { 3120 | stbtt_uint32 loc = nm + 6 + 12 * i; 3121 | stbtt_int32 id = ttUSHORT(fc+loc+6); 3122 | if (id == target_id) { 3123 | // find the encoding 3124 | stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); 3125 | 3126 | // is this a Unicode encoding? 3127 | if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { 3128 | stbtt_int32 slen = ttUSHORT(fc+loc+8); 3129 | stbtt_int32 off = ttUSHORT(fc+loc+10); 3130 | 3131 | // check if there's a prefix match 3132 | stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); 3133 | if (matchlen >= 0) { 3134 | // check for target_id+1 immediately following, with same encoding & language 3135 | if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { 3136 | slen = ttUSHORT(fc+loc+12+8); 3137 | off = ttUSHORT(fc+loc+12+10); 3138 | if (slen == 0) { 3139 | if (matchlen == nlen) 3140 | return 1; 3141 | } else if (matchlen < nlen && name[matchlen] == ' ') { 3142 | ++matchlen; 3143 | if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) 3144 | return 1; 3145 | } 3146 | } else { 3147 | // if nothing immediately following 3148 | if (matchlen == nlen) 3149 | return 1; 3150 | } 3151 | } 3152 | } 3153 | 3154 | // @TODO handle other encodings 3155 | } 3156 | } 3157 | return 0; 3158 | } 3159 | 3160 | static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) 3161 | { 3162 | stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); 3163 | stbtt_uint32 nm,hd; 3164 | if (!stbtt__isfont(fc+offset)) return 0; 3165 | 3166 | // check italics/bold/underline flags in macStyle... 3167 | if (flags) { 3168 | hd = stbtt__find_table(fc, offset, "head"); 3169 | if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; 3170 | } 3171 | 3172 | nm = stbtt__find_table(fc, offset, "name"); 3173 | if (!nm) return 0; 3174 | 3175 | if (flags) { 3176 | // if we checked the macStyle flags, then just check the family and ignore the subfamily 3177 | if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; 3178 | if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; 3179 | if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; 3180 | } else { 3181 | if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; 3182 | if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; 3183 | if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; 3184 | } 3185 | 3186 | return 0; 3187 | } 3188 | 3189 | static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) 3190 | { 3191 | stbtt_int32 i; 3192 | for (i=0;;++i) { 3193 | stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); 3194 | if (off < 0) return off; 3195 | if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) 3196 | return off; 3197 | } 3198 | } 3199 | 3200 | #if defined(__GNUC__) || defined(__clang__) 3201 | #pragma GCC diagnostic push 3202 | #pragma GCC diagnostic ignored "-Wcast-qual" 3203 | #endif 3204 | 3205 | STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, 3206 | float pixel_height, unsigned char *pixels, int pw, int ph, 3207 | int first_char, int num_chars, stbtt_bakedchar *chardata) 3208 | { 3209 | return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); 3210 | } 3211 | 3212 | STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) 3213 | { 3214 | return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); 3215 | } 3216 | 3217 | STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) 3218 | { 3219 | return stbtt_InitFont_internal(info, (unsigned char *) data, offset); 3220 | } 3221 | 3222 | STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) 3223 | { 3224 | return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); 3225 | } 3226 | 3227 | STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) 3228 | { 3229 | return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); 3230 | } 3231 | 3232 | #if defined(__GNUC__) || defined(__clang__) 3233 | #pragma GCC diagnostic pop 3234 | #endif 3235 | 3236 | #endif // STB_TRUETYPE_IMPLEMENTATION 3237 | 3238 | 3239 | // FULL VERSION HISTORY 3240 | // 3241 | // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual 3242 | // 1.11 (2016-04-02) fix unused-variable warning 3243 | // 1.10 (2016-04-02) allow user-defined fabs() replacement 3244 | // fix memory leak if fontsize=0.0 3245 | // fix warning from duplicate typedef 3246 | // 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges 3247 | // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges 3248 | // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; 3249 | // allow PackFontRanges to pack and render in separate phases; 3250 | // fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); 3251 | // fixed an assert() bug in the new rasterizer 3252 | // replace assert() with STBTT_assert() in new rasterizer 3253 | // 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) 3254 | // also more precise AA rasterizer, except if shapes overlap 3255 | // remove need for STBTT_sort 3256 | // 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC 3257 | // 1.04 (2015-04-15) typo in example 3258 | // 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes 3259 | // 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ 3260 | // 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match 3261 | // non-oversampled; STBTT_POINT_SIZE for packed case only 3262 | // 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling 3263 | // 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) 3264 | // 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID 3265 | // 0.8b (2014-07-07) fix a warning 3266 | // 0.8 (2014-05-25) fix a few more warnings 3267 | // 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back 3268 | // 0.6c (2012-07-24) improve documentation 3269 | // 0.6b (2012-07-20) fix a few more warnings 3270 | // 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, 3271 | // stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty 3272 | // 0.5 (2011-12-09) bugfixes: 3273 | // subpixel glyph renderer computed wrong bounding box 3274 | // first vertex of shape can be off-curve (FreeSans) 3275 | // 0.4b (2011-12-03) fixed an error in the font baking example 3276 | // 0.4 (2011-12-01) kerning, subpixel rendering (tor) 3277 | // bugfixes for: 3278 | // codepoint-to-glyph conversion using table fmt=12 3279 | // codepoint-to-glyph conversion using table fmt=4 3280 | // stbtt_GetBakedQuad with non-square texture (Zer) 3281 | // updated Hello World! sample to use kerning and subpixel 3282 | // fixed some warnings 3283 | // 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) 3284 | // userdata, malloc-from-userdata, non-zero fill (stb) 3285 | // 0.2 (2009-03-11) Fix unsigned/signed char warnings 3286 | // 0.1 (2009-03-09) First public release 3287 | // 3288 | -------------------------------------------------------------------------------- /src/limits.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (c) 2016 rxi 3 | ** 4 | ** This project is free software; you can redistribute it and/or modify it 5 | ** under the terms of the MIT license. See LICENSE for details. 6 | **/ 7 | 8 | #ifndef LIMITS_H 9 | #define LIMITS_H 10 | 11 | /* These can be safely changed if they are too small or too large */ 12 | 13 | #define MAX_IMAGE_NAME 127 14 | #define MAX_IMAGES 20000 15 | #define MAX_DIRS 128 16 | #define MIN_ATLAS_WIDTH 64 17 | #define MIN_ATLAS_HEIGHT 64 18 | #define MAX_ATLAS_WIDTH 4096 19 | #define MAX_ATLAS_HEIGHT 4096 20 | #define MAX_FONT_SIZE (1024 * 1024 * 16) 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (c) 2016 rxi 3 | ** 4 | ** This project is free software; you can redistribute it and/or modify it 5 | ** under the terms of the MIT license. See LICENSE for details. 6 | **/ 7 | 8 | #include "lib/stb/stb_rect_pack.h" 9 | #include "lib/stb/stb_truetype.h" 10 | #include "lib/stb/stb_image.h" 11 | #include "lib/stb/stb_image_write.h" 12 | #include "util.h" 13 | #include "limits.h" 14 | #include "bitmap.h" 15 | 16 | #define VERSION "0.0.0" 17 | 18 | 19 | typedef struct { 20 | char name[MAX_IMAGE_NAME + 1]; 21 | Bitmap bitmap; 22 | } Image; 23 | 24 | 25 | static unsigned char font_buf[MAX_FONT_SIZE]; 26 | static stbrp_node nodes[MAX_ATLAS_WIDTH]; 27 | static stbrp_rect rects[MAX_IMAGES]; 28 | static Image images[MAX_IMAGES]; 29 | static int image_count = 0; 30 | 31 | 32 | static void print_help(void) { 33 | printf("Usage: atlas [OPTION]... \n"); 34 | printf("A small utility for generating a texture atlas from all the images\n"); 35 | printf("and fonts in a directory.\n"); 36 | printf("\n"); 37 | printf(" -h, --help Display this help message\n"); 38 | printf(" -v, --version Display the version number\n"); 39 | printf(" -o, --imageout Image output filename (default: 'out.png')\n"); 40 | printf(" -t, --textout Text output filename (default: 'out.txt')\n"); 41 | printf(" -p, --padding Number of pixels padding (default: '0')\n"); 42 | printf(" -s, --fontsize Font size (default: '16')\n"); 43 | printf(" -f, --linefmt Line format string (default: '%%s %%d %%d %%d %%d')\n"); 44 | printf(" -g, --glyphfmt Glyph name format string (default: '%%s_%%d')\n"); 45 | printf(" -r, --ranges Comma-separated glyph ranges (default: '32-127')\n"); 46 | printf(" -e, --keepext Don't trim file extensions from names\n"); 47 | printf("\n"); 48 | } 49 | 50 | 51 | static Image* next_image(void) { 52 | if (image_count >= MAX_IMAGES) { 53 | ERROR("Maximum images (%d) exceeded", MAX_IMAGES); 54 | } 55 | return &images[image_count++]; 56 | } 57 | 58 | 59 | static int load_image(const char *filename, const char *name) { 60 | int w, h, n; 61 | void *data = stbi_load(filename, &w, &h, &n, 4); 62 | if (data) { 63 | Image *img = next_image(); 64 | strcpy(img->name, name); 65 | img->bitmap.data = data; 66 | img->bitmap.width = w; 67 | img->bitmap.height = h; 68 | return 1; 69 | } 70 | return 0; 71 | } 72 | 73 | 74 | static int load_font( 75 | const char *filename, const char *name, double fontsize, 76 | const char *glyphfmt, const char *glyphranges 77 | ) { 78 | /* Load file into buffer */ 79 | FILE *fp = fopen(filename, "rb"); 80 | if (!fp) { 81 | ERROR("Could not load '%s' for reading", filename); 82 | } 83 | int n = fread(font_buf, 1, sizeof(font_buf), fp); 84 | fclose(fp); 85 | if (n == sizeof(font_buf)) { 86 | ERROR("Font ('%s') size exceeds font buffer", name); 87 | } 88 | 89 | /* Init font */ 90 | stbtt_fontinfo font; 91 | if (stbtt_InitFont(&font, font_buf, 0)) { 92 | /* Successfully inited -- Check image name size + glyph idx */ 93 | if (strlen(name) + strlen(glyphfmt) + 16 > MAX_IMAGE_NAME) { 94 | ERROR("File name too long: '%s'", name); 95 | } 96 | 97 | /* Get font height and scale */ 98 | int ascent, descent, linegrap; 99 | double scale = stbtt_ScaleForMappingEmToPixels(&font, fontsize); 100 | stbtt_GetFontVMetrics(&font, &ascent, &descent, &linegrap); 101 | int height = ceil((ascent - descent + linegrap) * scale) + 1; 102 | int baseline = ascent * scale + 1; 103 | 104 | /* Iterate glyph ranges and load glyphs */ 105 | const char *p = glyphranges; 106 | while (*p) { 107 | /* Get range */ 108 | int lo, hi, i; 109 | int n = sscanf(p, "%d-%d%n", &lo, &hi, &i); 110 | if (n != 2 || hi < 0 || lo > 0x10FFFF || lo > hi) { 111 | ERROR("Invalid glyph range list '%s'", glyphranges); 112 | } 113 | p += i; 114 | while (*p == ' ') p++; 115 | if (*p == ',') p++; 116 | 117 | /* Load glyphs from range */ 118 | for (int c = lo; c <= hi; c++) { 119 | Image *img = next_image(); 120 | Bitmap *bmp = &img->bitmap; 121 | sprintf(img->name, glyphfmt, name, c); 122 | 123 | /* Render glyph to 8bit buffer */ 124 | int w, h, gw, x, y; 125 | uint8_t *p = stbtt_GetCodepointBitmap(&font, 0, scale, c, &w, &h, 0,0); 126 | stbtt_GetCodepointBitmapBox(&font, c, scale, scale, &x, &y, 0, 0); 127 | 128 | /* Init bitmap and blit 8bit buffer */ 129 | stbtt_GetCodepointHMetrics(&font, c, &gw, NULL); 130 | bmp->width = gw * scale; 131 | bmp->height = height; 132 | bmp->data = calloc(4, bmp->width * bmp->height); 133 | bitmap_blit8(bmp, p, w, h, x, y + baseline); 134 | 135 | /* Free 8-bit buffer */ 136 | free(p); 137 | } 138 | } 139 | /* Loaded successfully */ 140 | return 1; 141 | } 142 | return 0; 143 | } 144 | 145 | 146 | int main(int argc, const char **argv) { 147 | Bitmap atlas = { NULL, MIN_ATLAS_WIDTH, MIN_ATLAS_HEIGHT }; 148 | int dircount = 0; 149 | 150 | /* Init defaults */ 151 | const char *indirs[MAX_DIRS]; 152 | const char *imageout = "out.png"; 153 | const char *textout = "out.txt"; 154 | const char *linefmt = "%s %d %d %d %d"; 155 | const char *glyphfmt = "%s_%d"; 156 | const char *glyphranges = "32-127"; 157 | double fontsize = 16; 158 | int trimext = 1; 159 | int padding = 0; 160 | 161 | 162 | /* Handle arguments */ 163 | next_arg(&argc, &argv); /* Consume executable name */ 164 | while (argc > 0) { 165 | const char *arg = next_arg(&argc, &argv); 166 | 167 | if (arg[0] != '-') { 168 | if (dircount >= MAX_DIRS) { 169 | ERROR("maximum input directories (%d) exceeded", MAX_DIRS); 170 | } 171 | indirs[dircount++] = arg; 172 | 173 | } else if (match_opt(arg, "h", "help")) { 174 | print_help(); 175 | exit(EXIT_SUCCESS); 176 | 177 | } else if (match_opt(arg, "v", "version")) { 178 | printf("atlas version " VERSION "\n"); 179 | exit(EXIT_SUCCESS); 180 | 181 | } else if (match_opt(arg, "o", "imageout")) { 182 | imageout = next_arg(&argc, &argv); 183 | 184 | } else if (match_opt(arg, "t", "textout")) { 185 | textout = next_arg(&argc, &argv); 186 | 187 | } else if (match_opt(arg, "p", "padding")) { 188 | padding = next_arg_number(&argc, &argv); 189 | if (padding < 0) { 190 | ERROR("Expected padding greater or equal to 0"); 191 | } 192 | 193 | } else if (match_opt(arg, "s", "fontsize")) { 194 | fontsize = next_arg_number(&argc, &argv); 195 | if (fontsize <= 0) { 196 | ERROR("Expected font size greater than 0"); 197 | } 198 | 199 | } else if (match_opt(arg, "f", "linefmt")) { 200 | linefmt = next_arg(&argc, &argv); 201 | check_format_str(linefmt, "sdddd"); 202 | 203 | } else if (match_opt(arg, "g", "glyphfmt")) { 204 | glyphfmt = next_arg(&argc, &argv); 205 | check_format_str(glyphfmt, "sd"); 206 | 207 | } else if (match_opt(arg, "r", "ranges")) { 208 | glyphranges = next_arg(&argc, &argv); 209 | 210 | } else if (match_opt(arg, "e", "keepext")) { 211 | trimext = 0; 212 | 213 | } else { 214 | ERROR("Invalid argument '%s'", arg); 215 | } 216 | } 217 | if (dircount == 0) { 218 | ERROR("Expected input directory"); 219 | } 220 | 221 | 222 | /* Iterate each directory and load each file */ 223 | printf("Loading assets... "); 224 | fflush(stdout); 225 | int filecount = 0; 226 | for (int i = 0; i < dircount; i++) { 227 | DIR *d = opendir(indirs[i]); 228 | if (!d) { 229 | ERROR("Could not open directory '%s'", indirs[i]); 230 | } 231 | struct dirent *ep; 232 | while ( (ep = readdir(d)) ) { 233 | /* Skip dotfiles */ 234 | if (*ep->d_name == '.') { 235 | continue; 236 | } 237 | 238 | /* Check and copy filename */ 239 | if (strlen(ep->d_name) > MAX_IMAGE_NAME) { 240 | ERROR("File name too long: '%s'", ep->d_name); 241 | } 242 | char name[MAX_IMAGE_NAME]; 243 | strcpy(name, ep->d_name); 244 | 245 | /* Get full path */ 246 | char fullname[512]; 247 | sprintf(fullname, "%.240s/%.240s", indirs[i], ep->d_name); 248 | 249 | /* Trim file extension and replace whitespace with `_` */ 250 | if (trimext) { 251 | trim_file_ext(name); 252 | } 253 | replace_whitespace(name); 254 | 255 | /* Try to load */ 256 | if (load_image(fullname, name)) goto loaded; 257 | if (load_font(fullname, name, fontsize, glyphfmt, glyphranges)) goto loaded; 258 | 259 | ERROR("Could not load file '%s'", ep->d_name); 260 | 261 | loaded: 262 | filecount++; 263 | } 264 | closedir(d); 265 | } 266 | printf("Done (%d files)\n", filecount); 267 | 268 | 269 | /* Init rects array and pack */ 270 | pack: 271 | for (int i = 0; i < image_count; i++) { 272 | Bitmap *bitmap = &images[i].bitmap; 273 | /* Init rect */ 274 | rects[i].id = i; 275 | rects[i].w = bitmap->width + padding * 2; 276 | rects[i].h = bitmap->height + padding * 2; 277 | /* Update atlas size if image size is larger */ 278 | if (rects[i].w > atlas.width) atlas.width = round_up_po2(rects[i].w); 279 | if (rects[i].h > atlas.height) atlas.height = round_up_po2(rects[i].h); 280 | } 281 | stbrp_context ctx; 282 | stbrp_init_target(&ctx, atlas.width, atlas.height, nodes, MAX_ATLAS_WIDTH); 283 | stbrp_pack_rects(&ctx, rects, image_count); 284 | 285 | 286 | /* Check all rects were packed, if not increase atlas size and try again */ 287 | for (int i = 0; i < image_count; i++) { 288 | if (!rects[i].was_packed) { 289 | /* Increase size */ 290 | if (atlas.height < atlas.width) { 291 | atlas.height = atlas.width; 292 | } else { 293 | atlas.width *= 2; 294 | } 295 | /* Bounds check */ 296 | if (atlas.width > MAX_ATLAS_WIDTH) { 297 | ERROR("Max atlas width (%d) exceeded", MAX_ATLAS_WIDTH); 298 | } 299 | if (atlas.height > MAX_ATLAS_HEIGHT) { 300 | ERROR("Max atlas height (%d) exceeded", MAX_ATLAS_HEIGHT); 301 | } 302 | /* Retry */ 303 | goto pack; 304 | } 305 | } 306 | 307 | 308 | /* Allocate pixel buffer for atlas */ 309 | atlas.data = calloc(4, atlas.width * atlas.height); 310 | 311 | /* Blit image bitmaps to atlas */ 312 | for (int i = 0; i < image_count; i++) { 313 | bitmap_blit( 314 | &atlas, &images[rects[i].id].bitmap, 315 | rects[i].x + padding, rects[i].y + padding); 316 | } 317 | 318 | 319 | /* Write output image file */ 320 | printf("Writing image file... "); 321 | fflush(stdout); 322 | if (strstr(imageout, ".png")) { 323 | stbi_write_png(imageout, atlas.width, atlas.height, 4, atlas.data, 0); 324 | } else if (strstr(imageout, ".tga")) { 325 | stbi_write_tga(imageout, atlas.width, atlas.height, 4, atlas.data); 326 | } else { 327 | ERROR("Unsupported output image format ('%s'), try '.png'", imageout); 328 | } 329 | printf("Done (%dx%d)\n", atlas.width, atlas.height); 330 | 331 | 332 | /* Write output text file */ 333 | printf("Writing text file... "); 334 | fflush(stdout); 335 | FILE *fp = fopen(textout, "wb"); 336 | if (!fp) { 337 | ERROR("Could not open `%s` for writing", textout); 338 | } 339 | for (int i = 0; i < image_count; i++) { 340 | Image *img = &images[rects[i].id]; 341 | Bitmap *bmp = &img->bitmap; 342 | fprintf( 343 | fp, linefmt, 344 | img->name, rects[i].x + padding, rects[i].y + padding, 345 | bmp->width, bmp->height); 346 | fprintf(fp, "\n"); 347 | } 348 | fclose(fp); 349 | printf("Done (%d images)\n", image_count); 350 | 351 | 352 | /* Clear up */ 353 | for (int i = 0; i < image_count; i++) { 354 | free(images[i].bitmap.data); 355 | } 356 | free(atlas.data); 357 | 358 | 359 | return EXIT_SUCCESS; 360 | } 361 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (c) 2016 rxi 3 | ** 4 | ** This project is free software; you can redistribute it and/or modify it 5 | ** under the terms of the MIT license. See LICENSE for details. 6 | **/ 7 | 8 | #include "util.h" 9 | 10 | 11 | int round_up_po2(int n) { 12 | int x = 1; 13 | while (x < n) x <<= 1; 14 | return x; 15 | } 16 | 17 | 18 | const char* next_arg(int *argc, const char ***argv) { 19 | if (*argc == 0) { 20 | ERROR("Expected additional argument(s)"); 21 | } 22 | (*argc)--; 23 | return *(*argv)++; 24 | } 25 | 26 | 27 | double next_arg_number(int *argc, const char ***argv) { 28 | char *endptr; 29 | const char *arg = next_arg(argc, argv); 30 | double res = strtod(arg, &endptr); 31 | if (arg == endptr) { 32 | ERROR("Expected numerical argument, got '%s'", arg); 33 | } 34 | return res; 35 | } 36 | 37 | 38 | int match_opt(const char *opt, const char *chr, const char *name) { 39 | if (*opt == '-') { 40 | opt++; 41 | if (*opt == '-') { 42 | return strcmp(opt + 1, name) == 0; 43 | } 44 | return strcmp(opt, chr) == 0; 45 | } 46 | return 0; 47 | } 48 | 49 | 50 | void trim_file_ext(char *str) { 51 | int len = strlen(str); 52 | char *p = str + len - 1; 53 | while (p != str) { 54 | if (*p == '.') { 55 | *p = '\0'; 56 | break; 57 | } 58 | p--; 59 | } 60 | } 61 | 62 | 63 | void replace_whitespace(char *str) { 64 | char *p = str; 65 | while (*p) { 66 | if (*p == ' ' || *p == '\t' || *p == '\n') { 67 | *p = '_'; 68 | } 69 | p++; 70 | } 71 | } 72 | 73 | 74 | /* Checks the format string is valid for the given values. For example `expect` 75 | ** should be "sd" if you plan to pass a string and int following the fmt */ 76 | void check_format_str(const char *fmt, const char *expect) { 77 | const char *p = fmt; 78 | const char *e = expect; 79 | while (*p) { 80 | if (*p++ == '%') { 81 | if (*p == *e) { 82 | e++; 83 | } else if (*p != '%') { 84 | if (*e) { 85 | ERROR("Invalid format specifier '%%%c', expected '%%%c'", *p, *e); 86 | } else { 87 | ERROR("Too many format specifiers"); 88 | } 89 | } 90 | p++; 91 | } 92 | } 93 | if (*e) { 94 | ERROR("Too few format specifiers, expected %d", (int) strlen(expect)); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (c) 2016 rxi 3 | ** 4 | ** This project is free software; you can redistribute it and/or modify it 5 | ** under the terms of the MIT license. See LICENSE for details. 6 | **/ 7 | 8 | #ifndef UTIL_H 9 | #define UTIL_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | #define ERROR(...) do { \ 20 | fprintf(stderr, "Error: "); \ 21 | fprintf(stderr, __VA_ARGS__); \ 22 | fprintf(stderr, "\n"); \ 23 | exit(EXIT_FAILURE); \ 24 | } while (0) 25 | 26 | 27 | int round_up_po2(int n); 28 | const char *next_arg(int *argc, const char ***argv); 29 | double next_arg_number(int *argc, const char ***argv); 30 | int match_opt(const char *opt, const char *chr, const char *name); 31 | void trim_file_ext(char *str); 32 | void replace_whitespace(char *str); 33 | void check_format_str(const char *fmt, const char *expect); 34 | 35 | #endif 36 | --------------------------------------------------------------------------------