├── 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 |
--------------------------------------------------------------------------------