(メッセージはありません)
@@ -1,630 +0,0 @@ | ||
1 | -// [DEAR IMGUI] | |
2 | -// This is a slightly modified version of stb_rect_pack.h 0.99. | |
3 | -// Those changes would need to be pushed into nothings/stb: | |
4 | -// - Added STBRP__CDECL | |
5 | -// Grep for [DEAR IMGUI] to find the changes. | |
6 | - | |
7 | -// stb_rect_pack.h - v0.99 - public domain - rectangle packing | |
8 | -// Sean Barrett 2014 | |
9 | -// | |
10 | -// Useful for e.g. packing rectangular textures into an atlas. | |
11 | -// Does not do rotation. | |
12 | -// | |
13 | -// Not necessarily the awesomest packing method, but better than | |
14 | -// the totally naive one in stb_truetype (which is primarily what | |
15 | -// this is meant to replace). | |
16 | -// | |
17 | -// Has only had a few tests run, may have issues. | |
18 | -// | |
19 | -// More docs to come. | |
20 | -// | |
21 | -// No memory allocations; uses qsort() and assert() from stdlib. | |
22 | -// Can override those by defining STBRP_SORT and STBRP_ASSERT. | |
23 | -// | |
24 | -// This library currently uses the Skyline Bottom-Left algorithm. | |
25 | -// | |
26 | -// Please note: better rectangle packers are welcome! Please | |
27 | -// implement them to the same API, but with a different init | |
28 | -// function. | |
29 | -// | |
30 | -// Credits | |
31 | -// | |
32 | -// Library | |
33 | -// Sean Barrett | |
34 | -// Minor features | |
35 | -// Martins Mozeiko | |
36 | -// github:IntellectualKitty | |
37 | -// | |
38 | -// Bugfixes / warning fixes | |
39 | -// Jeremy Jaussaud | |
40 | -// | |
41 | -// Version history: | |
42 | -// | |
43 | -// 0.99 (2019-02-07) warning fixes | |
44 | -// 0.11 (2017-03-03) return packing success/fail result | |
45 | -// 0.10 (2016-10-25) remove cast-away-const to avoid warnings | |
46 | -// 0.09 (2016-08-27) fix compiler warnings | |
47 | -// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) | |
48 | -// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) | |
49 | -// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort | |
50 | -// 0.05: added STBRP_ASSERT to allow replacing assert | |
51 | -// 0.04: fixed minor bug in STBRP_LARGE_RECTS support | |
52 | -// 0.01: initial release | |
53 | -// | |
54 | -// LICENSE | |
55 | -// | |
56 | -// See end of file for license information. | |
57 | - | |
58 | -////////////////////////////////////////////////////////////////////////////// | |
59 | -// | |
60 | -// INCLUDE SECTION | |
61 | -// | |
62 | - | |
63 | -#ifndef STB_INCLUDE_STB_RECT_PACK_H | |
64 | -#define STB_INCLUDE_STB_RECT_PACK_H | |
65 | - | |
66 | -#define STB_RECT_PACK_VERSION 1 | |
67 | - | |
68 | -#ifdef STBRP_STATIC | |
69 | -#define STBRP_DEF static | |
70 | -#else | |
71 | -#define STBRP_DEF extern | |
72 | -#endif | |
73 | - | |
74 | -#ifdef __cplusplus | |
75 | -extern "C" { | |
76 | -#endif | |
77 | - | |
78 | -typedef struct stbrp_context stbrp_context; | |
79 | -typedef struct stbrp_node stbrp_node; | |
80 | -typedef struct stbrp_rect stbrp_rect; | |
81 | - | |
82 | -#ifdef STBRP_LARGE_RECTS | |
83 | -typedef int stbrp_coord; | |
84 | -#else | |
85 | -typedef unsigned short stbrp_coord; | |
86 | -#endif | |
87 | - | |
88 | -STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); | |
89 | -// Assign packed locations to rectangles. The rectangles are of type | |
90 | -// 'stbrp_rect' defined below, stored in the array 'rects', and there | |
91 | -// are 'num_rects' many of them. | |
92 | -// | |
93 | -// Rectangles which are successfully packed have the 'was_packed' flag | |
94 | -// set to a non-zero value and 'x' and 'y' store the minimum location | |
95 | -// on each axis (i.e. bottom-left in cartesian coordinates, top-left | |
96 | -// if you imagine y increasing downwards). Rectangles which do not fit | |
97 | -// have the 'was_packed' flag set to 0. | |
98 | -// | |
99 | -// You should not try to access the 'rects' array from another thread | |
100 | -// while this function is running, as the function temporarily reorders | |
101 | -// the array while it executes. | |
102 | -// | |
103 | -// To pack into another rectangle, you need to call stbrp_init_target | |
104 | -// again. To continue packing into the same rectangle, you can call | |
105 | -// this function again. Calling this multiple times with multiple rect | |
106 | -// arrays will probably produce worse packing results than calling it | |
107 | -// a single time with the full rectangle array, but the option is | |
108 | -// available. | |
109 | -// | |
110 | -// The function returns 1 if all of the rectangles were successfully | |
111 | -// packed and 0 otherwise. | |
112 | - | |
113 | -struct stbrp_rect | |
114 | -{ | |
115 | - // reserved for your use: | |
116 | - int id; | |
117 | - | |
118 | - // input: | |
119 | - stbrp_coord w, h; | |
120 | - | |
121 | - // output: | |
122 | - stbrp_coord x, y; | |
123 | - int was_packed; // non-zero if valid packing | |
124 | - | |
125 | -}; // 16 bytes, nominally | |
126 | - | |
127 | - | |
128 | -STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); | |
129 | -// Initialize a rectangle packer to: | |
130 | -// pack a rectangle that is 'width' by 'height' in dimensions | |
131 | -// using temporary storage provided by the array 'nodes', which is 'num_nodes' long | |
132 | -// | |
133 | -// You must call this function every time you start packing into a new target. | |
134 | -// | |
135 | -// There is no "shutdown" function. The 'nodes' memory must stay valid for | |
136 | -// the following stbrp_pack_rects() call (or calls), but can be freed after | |
137 | -// the call (or calls) finish. | |
138 | -// | |
139 | -// Note: to guarantee best results, either: | |
140 | -// 1. make sure 'num_nodes' >= 'width' | |
141 | -// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' | |
142 | -// | |
143 | -// If you don't do either of the above things, widths will be quantized to multiples | |
144 | -// of small integers to guarantee the algorithm doesn't run out of temporary storage. | |
145 | -// | |
146 | -// If you do #2, then the non-quantized algorithm will be used, but the algorithm | |
147 | -// may run out of temporary storage and be unable to pack some rectangles. | |
148 | - | |
149 | -STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); | |
150 | -// Optionally call this function after init but before doing any packing to | |
151 | -// change the handling of the out-of-temp-memory scenario, described above. | |
152 | -// If you call init again, this will be reset to the default (false). | |
153 | - | |
154 | - | |
155 | -STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); | |
156 | -// Optionally select which packing heuristic the library should use. Different | |
157 | -// heuristics will produce better/worse results for different data sets. | |
158 | -// If you call init again, this will be reset to the default. | |
159 | - | |
160 | -enum | |
161 | -{ | |
162 | - STBRP_HEURISTIC_Skyline_default=0, | |
163 | - STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, | |
164 | - STBRP_HEURISTIC_Skyline_BF_sortHeight | |
165 | -}; | |
166 | - | |
167 | - | |
168 | -////////////////////////////////////////////////////////////////////////////// | |
169 | -// | |
170 | -// the details of the following structures don't matter to you, but they must | |
171 | -// be visible so you can handle the memory allocations for them | |
172 | - | |
173 | -struct stbrp_node | |
174 | -{ | |
175 | - stbrp_coord x,y; | |
176 | - stbrp_node *next; | |
177 | -}; | |
178 | - | |
179 | -struct stbrp_context | |
180 | -{ | |
181 | - int width; | |
182 | - int height; | |
183 | - int align; | |
184 | - int init_mode; | |
185 | - int heuristic; | |
186 | - int num_nodes; | |
187 | - stbrp_node *active_head; | |
188 | - stbrp_node *free_head; | |
189 | - stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' | |
190 | -}; | |
191 | - | |
192 | -#ifdef __cplusplus | |
193 | -} | |
194 | -#endif | |
195 | - | |
196 | -#endif | |
197 | - | |
198 | -////////////////////////////////////////////////////////////////////////////// | |
199 | -// | |
200 | -// IMPLEMENTATION SECTION | |
201 | -// | |
202 | - | |
203 | -#ifdef STB_RECT_PACK_IMPLEMENTATION | |
204 | -#ifndef STBRP_SORT | |
205 | -#include <stdlib.h> | |
206 | -#define STBRP_SORT qsort | |
207 | -#endif | |
208 | - | |
209 | -#ifndef STBRP_ASSERT | |
210 | -#include <assert.h> | |
211 | -#define STBRP_ASSERT assert | |
212 | -#endif | |
213 | - | |
214 | -// [DEAR IMGUI] Added STBRP__CDECL | |
215 | -#ifdef _MSC_VER | |
216 | -#define STBRP__NOTUSED(v) (void)(v) | |
217 | -#define STBRP__CDECL __cdecl | |
218 | -#else | |
219 | -#define STBRP__NOTUSED(v) (void)sizeof(v) | |
220 | -#define STBRP__CDECL | |
221 | -#endif | |
222 | - | |
223 | -enum | |
224 | -{ | |
225 | - STBRP__INIT_skyline = 1 | |
226 | -}; | |
227 | - | |
228 | -STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) | |
229 | -{ | |
230 | - switch (context->init_mode) { | |
231 | - case STBRP__INIT_skyline: | |
232 | - STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); | |
233 | - context->heuristic = heuristic; | |
234 | - break; | |
235 | - default: | |
236 | - STBRP_ASSERT(0); | |
237 | - } | |
238 | -} | |
239 | - | |
240 | -STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) | |
241 | -{ | |
242 | - if (allow_out_of_mem) | |
243 | - // if it's ok to run out of memory, then don't bother aligning them; | |
244 | - // this gives better packing, but may fail due to OOM (even though | |
245 | - // the rectangles easily fit). @TODO a smarter approach would be to only | |
246 | - // quantize once we've hit OOM, then we could get rid of this parameter. | |
247 | - context->align = 1; | |
248 | - else { | |
249 | - // if it's not ok to run out of memory, then quantize the widths | |
250 | - // so that num_nodes is always enough nodes. | |
251 | - // | |
252 | - // I.e. num_nodes * align >= width | |
253 | - // align >= width / num_nodes | |
254 | - // align = ceil(width/num_nodes) | |
255 | - | |
256 | - context->align = (context->width + context->num_nodes-1) / context->num_nodes; | |
257 | - } | |
258 | -} | |
259 | - | |
260 | -STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) | |
261 | -{ | |
262 | - int i; | |
263 | -#ifndef STBRP_LARGE_RECTS | |
264 | - STBRP_ASSERT(width <= 0xffff && height <= 0xffff); | |
265 | -#endif | |
266 | - | |
267 | - for (i=0; i < num_nodes-1; ++i) | |
268 | - nodes[i].next = &nodes[i+1]; | |
269 | - nodes[i].next = NULL; | |
270 | - context->init_mode = STBRP__INIT_skyline; | |
271 | - context->heuristic = STBRP_HEURISTIC_Skyline_default; | |
272 | - context->free_head = &nodes[0]; | |
273 | - context->active_head = &context->extra[0]; | |
274 | - context->width = width; | |
275 | - context->height = height; | |
276 | - context->num_nodes = num_nodes; | |
277 | - stbrp_setup_allow_out_of_mem(context, 0); | |
278 | - | |
279 | - // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) | |
280 | - context->extra[0].x = 0; | |
281 | - context->extra[0].y = 0; | |
282 | - context->extra[0].next = &context->extra[1]; | |
283 | - context->extra[1].x = (stbrp_coord) width; | |
284 | -#ifdef STBRP_LARGE_RECTS | |
285 | - context->extra[1].y = (1<<30); | |
286 | -#else | |
287 | - context->extra[1].y = 65535; | |
288 | -#endif | |
289 | - context->extra[1].next = NULL; | |
290 | -} | |
291 | - | |
292 | -// find minimum y position if it starts at x1 | |
293 | -static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) | |
294 | -{ | |
295 | - stbrp_node *node = first; | |
296 | - int x1 = x0 + width; | |
297 | - int min_y, visited_width, waste_area; | |
298 | - | |
299 | - STBRP__NOTUSED(c); | |
300 | - | |
301 | - STBRP_ASSERT(first->x <= x0); | |
302 | - | |
303 | - #if 0 | |
304 | - // skip in case we're past the node | |
305 | - while (node->next->x <= x0) | |
306 | - ++node; | |
307 | - #else | |
308 | - STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency | |
309 | - #endif | |
310 | - | |
311 | - STBRP_ASSERT(node->x <= x0); | |
312 | - | |
313 | - min_y = 0; | |
314 | - waste_area = 0; | |
315 | - visited_width = 0; | |
316 | - while (node->x < x1) { | |
317 | - if (node->y > min_y) { | |
318 | - // raise min_y higher. | |
319 | - // we've accounted for all waste up to min_y, | |
320 | - // but we'll now add more waste for everything we've visted | |
321 | - waste_area += visited_width * (node->y - min_y); | |
322 | - min_y = node->y; | |
323 | - // the first time through, visited_width might be reduced | |
324 | - if (node->x < x0) | |
325 | - visited_width += node->next->x - x0; | |
326 | - else | |
327 | - visited_width += node->next->x - node->x; | |
328 | - } else { | |
329 | - // add waste area | |
330 | - int under_width = node->next->x - node->x; | |
331 | - if (under_width + visited_width > width) | |
332 | - under_width = width - visited_width; | |
333 | - waste_area += under_width * (min_y - node->y); | |
334 | - visited_width += under_width; | |
335 | - } | |
336 | - node = node->next; | |
337 | - } | |
338 | - | |
339 | - *pwaste = waste_area; | |
340 | - return min_y; | |
341 | -} | |
342 | - | |
343 | -typedef struct | |
344 | -{ | |
345 | - int x,y; | |
346 | - stbrp_node **prev_link; | |
347 | -} stbrp__findresult; | |
348 | - | |
349 | -static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) | |
350 | -{ | |
351 | - int best_waste = (1<<30), best_x, best_y = (1 << 30); | |
352 | - stbrp__findresult fr; | |
353 | - stbrp_node **prev, *node, *tail, **best = NULL; | |
354 | - | |
355 | - // align to multiple of c->align | |
356 | - width = (width + c->align - 1); | |
357 | - width -= width % c->align; | |
358 | - STBRP_ASSERT(width % c->align == 0); | |
359 | - | |
360 | - node = c->active_head; | |
361 | - prev = &c->active_head; | |
362 | - while (node->x + width <= c->width) { | |
363 | - int y,waste; | |
364 | - y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); | |
365 | - if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL | |
366 | - // bottom left | |
367 | - if (y < best_y) { | |
368 | - best_y = y; | |
369 | - best = prev; | |
370 | - } | |
371 | - } else { | |
372 | - // best-fit | |
373 | - if (y + height <= c->height) { | |
374 | - // can only use it if it first vertically | |
375 | - if (y < best_y || (y == best_y && waste < best_waste)) { | |
376 | - best_y = y; | |
377 | - best_waste = waste; | |
378 | - best = prev; | |
379 | - } | |
380 | - } | |
381 | - } | |
382 | - prev = &node->next; | |
383 | - node = node->next; | |
384 | - } | |
385 | - | |
386 | - best_x = (best == NULL) ? 0 : (*best)->x; | |
387 | - | |
388 | - // if doing best-fit (BF), we also have to try aligning right edge to each node position | |
389 | - // | |
390 | - // e.g, if fitting | |
391 | - // | |
392 | - // ____________________ | |
393 | - // |____________________| | |
394 | - // | |
395 | - // into | |
396 | - // | |
397 | - // | | | |
398 | - // | ____________| | |
399 | - // |____________| | |
400 | - // | |
401 | - // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned | |
402 | - // | |
403 | - // This makes BF take about 2x the time | |
404 | - | |
405 | - if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { | |
406 | - tail = c->active_head; | |
407 | - node = c->active_head; | |
408 | - prev = &c->active_head; | |
409 | - // find first node that's admissible | |
410 | - while (tail->x < width) | |
411 | - tail = tail->next; | |
412 | - while (tail) { | |
413 | - int xpos = tail->x - width; | |
414 | - int y,waste; | |
415 | - STBRP_ASSERT(xpos >= 0); | |
416 | - // find the left position that matches this | |
417 | - while (node->next->x <= xpos) { | |
418 | - prev = &node->next; | |
419 | - node = node->next; | |
420 | - } | |
421 | - STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); | |
422 | - y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); | |
423 | - if (y + height < c->height) { | |
424 | - if (y <= best_y) { | |
425 | - if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { | |
426 | - best_x = xpos; | |
427 | - STBRP_ASSERT(y <= best_y); | |
428 | - best_y = y; | |
429 | - best_waste = waste; | |
430 | - best = prev; | |
431 | - } | |
432 | - } | |
433 | - } | |
434 | - tail = tail->next; | |
435 | - } | |
436 | - } | |
437 | - | |
438 | - fr.prev_link = best; | |
439 | - fr.x = best_x; | |
440 | - fr.y = best_y; | |
441 | - return fr; | |
442 | -} | |
443 | - | |
444 | -static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) | |
445 | -{ | |
446 | - // find best position according to heuristic | |
447 | - stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); | |
448 | - stbrp_node *node, *cur; | |
449 | - | |
450 | - // bail if: | |
451 | - // 1. it failed | |
452 | - // 2. the best node doesn't fit (we don't always check this) | |
453 | - // 3. we're out of memory | |
454 | - if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { | |
455 | - res.prev_link = NULL; | |
456 | - return res; | |
457 | - } | |
458 | - | |
459 | - // on success, create new node | |
460 | - node = context->free_head; | |
461 | - node->x = (stbrp_coord) res.x; | |
462 | - node->y = (stbrp_coord) (res.y + height); | |
463 | - | |
464 | - context->free_head = node->next; | |
465 | - | |
466 | - // insert the new node into the right starting point, and | |
467 | - // let 'cur' point to the remaining nodes needing to be | |
468 | - // stiched back in | |
469 | - | |
470 | - cur = *res.prev_link; | |
471 | - if (cur->x < res.x) { | |
472 | - // preserve the existing one, so start testing with the next one | |
473 | - stbrp_node *next = cur->next; | |
474 | - cur->next = node; | |
475 | - cur = next; | |
476 | - } else { | |
477 | - *res.prev_link = node; | |
478 | - } | |
479 | - | |
480 | - // from here, traverse cur and free the nodes, until we get to one | |
481 | - // that shouldn't be freed | |
482 | - while (cur->next && cur->next->x <= res.x + width) { | |
483 | - stbrp_node *next = cur->next; | |
484 | - // move the current node to the free list | |
485 | - cur->next = context->free_head; | |
486 | - context->free_head = cur; | |
487 | - cur = next; | |
488 | - } | |
489 | - | |
490 | - // stitch the list back in | |
491 | - node->next = cur; | |
492 | - | |
493 | - if (cur->x < res.x + width) | |
494 | - cur->x = (stbrp_coord) (res.x + width); | |
495 | - | |
496 | -#ifdef _DEBUG | |
497 | - cur = context->active_head; | |
498 | - while (cur->x < context->width) { | |
499 | - STBRP_ASSERT(cur->x < cur->next->x); | |
500 | - cur = cur->next; | |
501 | - } | |
502 | - STBRP_ASSERT(cur->next == NULL); | |
503 | - | |
504 | - { | |
505 | - int count=0; | |
506 | - cur = context->active_head; | |
507 | - while (cur) { | |
508 | - cur = cur->next; | |
509 | - ++count; | |
510 | - } | |
511 | - cur = context->free_head; | |
512 | - while (cur) { | |
513 | - cur = cur->next; | |
514 | - ++count; | |
515 | - } | |
516 | - STBRP_ASSERT(count == context->num_nodes+2); | |
517 | - } | |
518 | -#endif | |
519 | - | |
520 | - return res; | |
521 | -} | |
522 | - | |
523 | -// [DEAR IMGUI] Added STBRP__CDECL | |
524 | -static int STBRP__CDECL rect_height_compare(const void *a, const void *b) | |
525 | -{ | |
526 | - const stbrp_rect *p = (const stbrp_rect *) a; | |
527 | - const stbrp_rect *q = (const stbrp_rect *) b; | |
528 | - if (p->h > q->h) | |
529 | - return -1; | |
530 | - if (p->h < q->h) | |
531 | - return 1; | |
532 | - return (p->w > q->w) ? -1 : (p->w < q->w); | |
533 | -} | |
534 | - | |
535 | -// [DEAR IMGUI] Added STBRP__CDECL | |
536 | -static int STBRP__CDECL rect_original_order(const void *a, const void *b) | |
537 | -{ | |
538 | - const stbrp_rect *p = (const stbrp_rect *) a; | |
539 | - const stbrp_rect *q = (const stbrp_rect *) b; | |
540 | - return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); | |
541 | -} | |
542 | - | |
543 | -#ifdef STBRP_LARGE_RECTS | |
544 | -#define STBRP__MAXVAL 0xffffffff | |
545 | -#else | |
546 | -#define STBRP__MAXVAL 0xffff | |
547 | -#endif | |
548 | - | |
549 | -STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) | |
550 | -{ | |
551 | - int i, all_rects_packed = 1; | |
552 | - | |
553 | - // we use the 'was_packed' field internally to allow sorting/unsorting | |
554 | - for (i=0; i < num_rects; ++i) { | |
555 | - rects[i].was_packed = i; | |
556 | - } | |
557 | - | |
558 | - // sort according to heuristic | |
559 | - STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); | |
560 | - | |
561 | - for (i=0; i < num_rects; ++i) { | |
562 | - if (rects[i].w == 0 || rects[i].h == 0) { | |
563 | - rects[i].x = rects[i].y = 0; // empty rect needs no space | |
564 | - } else { | |
565 | - stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); | |
566 | - if (fr.prev_link) { | |
567 | - rects[i].x = (stbrp_coord) fr.x; | |
568 | - rects[i].y = (stbrp_coord) fr.y; | |
569 | - } else { | |
570 | - rects[i].x = rects[i].y = STBRP__MAXVAL; | |
571 | - } | |
572 | - } | |
573 | - } | |
574 | - | |
575 | - // unsort | |
576 | - STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); | |
577 | - | |
578 | - // set was_packed flags and all_rects_packed status | |
579 | - for (i=0; i < num_rects; ++i) { | |
580 | - rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); | |
581 | - if (!rects[i].was_packed) | |
582 | - all_rects_packed = 0; | |
583 | - } | |
584 | - | |
585 | - // return the all_rects_packed status | |
586 | - return all_rects_packed; | |
587 | -} | |
588 | -#endif | |
589 | - | |
590 | -/* | |
591 | ------------------------------------------------------------------------------- | |
592 | -This software is available under 2 licenses -- choose whichever you prefer. | |
593 | ------------------------------------------------------------------------------- | |
594 | -ALTERNATIVE A - MIT License | |
595 | -Copyright (c) 2017 Sean Barrett | |
596 | -Permission is hereby granted, free of charge, to any person obtaining a copy of | |
597 | -this software and associated documentation files (the "Software"), to deal in | |
598 | -the Software without restriction, including without limitation the rights to | |
599 | -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
600 | -of the Software, and to permit persons to whom the Software is furnished to do | |
601 | -so, subject to the following conditions: | |
602 | -The above copyright notice and this permission notice shall be included in all | |
603 | -copies or substantial portions of the Software. | |
604 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
605 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
606 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
607 | -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
608 | -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
609 | -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
610 | -SOFTWARE. | |
611 | ------------------------------------------------------------------------------- | |
612 | -ALTERNATIVE B - Public Domain (www.unlicense.org) | |
613 | -This is free and unencumbered software released into the public domain. | |
614 | -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this | |
615 | -software, either in source code form or as a compiled binary, for any purpose, | |
616 | -commercial or non-commercial, and by any means. | |
617 | -In jurisdictions that recognize copyright laws, the author or authors of this | |
618 | -software dedicate any and all copyright interest in the software to the public | |
619 | -domain. We make this dedication for the benefit of the public at large and to | |
620 | -the detriment of our heirs and successors. We intend this dedication to be an | |
621 | -overt act of relinquishment in perpetuity of all present and future rights to | |
622 | -this software under copyright law. | |
623 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
624 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
625 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
626 | -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
627 | -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
628 | -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
629 | ------------------------------------------------------------------------------- | |
630 | -*/ |
@@ -1,4903 +0,0 @@ | ||
1 | -// [DEAR IMGUI] | |
2 | -// This is a slightly modified version of stb_truetype.h 1.20. | |
3 | -// Mostly fixing for compiler and static analyzer warnings. | |
4 | -// Grep for [DEAR IMGUI] to find the changes. | |
5 | - | |
6 | -// stb_truetype.h - v1.20 - public domain | |
7 | -// authored from 2009-2016 by Sean Barrett / RAD Game Tools | |
8 | -// | |
9 | -// This library processes TrueType files: | |
10 | -// parse files | |
11 | -// extract glyph metrics | |
12 | -// extract glyph shapes | |
13 | -// render glyphs to one-channel bitmaps with antialiasing (box filter) | |
14 | -// render glyphs to one-channel SDF bitmaps (signed-distance field/function) | |
15 | -// | |
16 | -// Todo: | |
17 | -// non-MS cmaps | |
18 | -// crashproof on bad data | |
19 | -// hinting? (no longer patented) | |
20 | -// cleartype-style AA? | |
21 | -// optimize: use simple memory allocator for intermediates | |
22 | -// optimize: build edge-list directly from curves | |
23 | -// optimize: rasterize directly from curves? | |
24 | -// | |
25 | -// ADDITIONAL CONTRIBUTORS | |
26 | -// | |
27 | -// Mikko Mononen: compound shape support, more cmap formats | |
28 | -// Tor Andersson: kerning, subpixel rendering | |
29 | -// Dougall Johnson: OpenType / Type 2 font handling | |
30 | -// Daniel Ribeiro Maciel: basic GPOS-based kerning | |
31 | -// | |
32 | -// Misc other: | |
33 | -// Ryan Gordon | |
34 | -// Simon Glass | |
35 | -// github:IntellectualKitty | |
36 | -// Imanol Celaya | |
37 | -// Daniel Ribeiro Maciel | |
38 | -// | |
39 | -// Bug/warning reports/fixes: | |
40 | -// "Zer" on mollyrocket Fabian "ryg" Giesen | |
41 | -// Cass Everitt Martins Mozeiko | |
42 | -// stoiko (Haemimont Games) Cap Petschulat | |
43 | -// Brian Hook Omar Cornut | |
44 | -// Walter van Niftrik github:aloucks | |
45 | -// David Gow Peter LaValle | |
46 | -// David Given Sergey Popov | |
47 | -// Ivan-Assen Ivanov Giumo X. Clanjor | |
48 | -// Anthony Pesch Higor Euripedes | |
49 | -// Johan Duparc Thomas Fields | |
50 | -// Hou Qiming Derek Vinyard | |
51 | -// Rob Loach Cort Stratton | |
52 | -// Kenney Phillis Jr. github:oyvindjam | |
53 | -// Brian Costabile github:vassvik | |
54 | -// | |
55 | -// VERSION HISTORY | |
56 | -// | |
57 | -// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() | |
58 | -// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod | |
59 | -// 1.18 (2018-01-29) add missing function | |
60 | -// 1.17 (2017-07-23) make more arguments const; doc fix | |
61 | -// 1.16 (2017-07-12) SDF support | |
62 | -// 1.15 (2017-03-03) make more arguments const | |
63 | -// 1.14 (2017-01-16) num-fonts-in-TTC function | |
64 | -// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts | |
65 | -// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual | |
66 | -// 1.11 (2016-04-02) fix unused-variable warning | |
67 | -// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef | |
68 | -// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly | |
69 | -// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges | |
70 | -// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; | |
71 | -// variant PackFontRanges to pack and render in separate phases; | |
72 | -// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); | |
73 | -// fixed an assert() bug in the new rasterizer | |
74 | -// replace assert() with STBTT_assert() in new rasterizer | |
75 | -// | |
76 | -// Full history can be found at the end of this file. | |
77 | -// | |
78 | -// LICENSE | |
79 | -// | |
80 | -// See end of file for license information. | |
81 | -// | |
82 | -// USAGE | |
83 | -// | |
84 | -// Include this file in whatever places need to refer to it. In ONE C/C++ | |
85 | -// file, write: | |
86 | -// #define STB_TRUETYPE_IMPLEMENTATION | |
87 | -// before the #include of this file. This expands out the actual | |
88 | -// implementation into that C/C++ file. | |
89 | -// | |
90 | -// To make the implementation private to the file that generates the implementation, | |
91 | -// #define STBTT_STATIC | |
92 | -// | |
93 | -// Simple 3D API (don't ship this, but it's fine for tools and quick start) | |
94 | -// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture | |
95 | -// stbtt_GetBakedQuad() -- compute quad to draw for a given char | |
96 | -// | |
97 | -// Improved 3D API (more shippable): | |
98 | -// #include "stb_rect_pack.h" -- optional, but you really want it | |
99 | -// stbtt_PackBegin() | |
100 | -// stbtt_PackSetOversampling() -- for improved quality on small fonts | |
101 | -// stbtt_PackFontRanges() -- pack and renders | |
102 | -// stbtt_PackEnd() | |
103 | -// stbtt_GetPackedQuad() | |
104 | -// | |
105 | -// "Load" a font file from a memory buffer (you have to keep the buffer loaded) | |
106 | -// stbtt_InitFont() | |
107 | -// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections | |
108 | -// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections | |
109 | -// | |
110 | -// Render a unicode codepoint to a bitmap | |
111 | -// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap | |
112 | -// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide | |
113 | -// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be | |
114 | -// | |
115 | -// Character advance/positioning | |
116 | -// stbtt_GetCodepointHMetrics() | |
117 | -// stbtt_GetFontVMetrics() | |
118 | -// stbtt_GetFontVMetricsOS2() | |
119 | -// stbtt_GetCodepointKernAdvance() | |
120 | -// | |
121 | -// Starting with version 1.06, the rasterizer was replaced with a new, | |
122 | -// faster and generally-more-precise rasterizer. The new rasterizer more | |
123 | -// accurately measures pixel coverage for anti-aliasing, except in the case | |
124 | -// where multiple shapes overlap, in which case it overestimates the AA pixel | |
125 | -// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If | |
126 | -// this turns out to be a problem, you can re-enable the old rasterizer with | |
127 | -// #define STBTT_RASTERIZER_VERSION 1 | |
128 | -// which will incur about a 15% speed hit. | |
129 | -// | |
130 | -// ADDITIONAL DOCUMENTATION | |
131 | -// | |
132 | -// Immediately after this block comment are a series of sample programs. | |
133 | -// | |
134 | -// After the sample programs is the "header file" section. This section | |
135 | -// includes documentation for each API function. | |
136 | -// | |
137 | -// Some important concepts to understand to use this library: | |
138 | -// | |
139 | -// Codepoint | |
140 | -// Characters are defined by unicode codepoints, e.g. 65 is | |
141 | -// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is | |
142 | -// the hiragana for "ma". | |
143 | -// | |
144 | -// Glyph | |
145 | -// A visual character shape (every codepoint is rendered as | |
146 | -// some glyph) | |
147 | -// | |
148 | -// Glyph index | |
149 | -// A font-specific integer ID representing a glyph | |
150 | -// | |
151 | -// Baseline | |
152 | -// Glyph shapes are defined relative to a baseline, which is the | |
153 | -// bottom of uppercase characters. Characters extend both above | |
154 | -// and below the baseline. | |
155 | -// | |
156 | -// Current Point | |
157 | -// As you draw text to the screen, you keep track of a "current point" | |
158 | -// which is the origin of each character. The current point's vertical | |
159 | -// position is the baseline. Even "baked fonts" use this model. | |
160 | -// | |
161 | -// Vertical Font Metrics | |
162 | -// The vertical qualities of the font, used to vertically position | |
163 | -// and space the characters. See docs for stbtt_GetFontVMetrics. | |
164 | -// | |
165 | -// Font Size in Pixels or Points | |
166 | -// The preferred interface for specifying font sizes in stb_truetype | |
167 | -// is to specify how tall the font's vertical extent should be in pixels. | |
168 | -// If that sounds good enough, skip the next paragraph. | |
169 | -// | |
170 | -// Most font APIs instead use "points", which are a common typographic | |
171 | -// measurement for describing font size, defined as 72 points per inch. | |
172 | -// stb_truetype provides a point API for compatibility. However, true | |
173 | -// "per inch" conventions don't make much sense on computer displays | |
174 | -// since different monitors have different number of pixels per | |
175 | -// inch. For example, Windows traditionally uses a convention that | |
176 | -// there are 96 pixels per inch, thus making 'inch' measurements have | |
177 | -// nothing to do with inches, and thus effectively defining a point to | |
178 | -// be 1.333 pixels. Additionally, the TrueType font data provides | |
179 | -// an explicit scale factor to scale a given font's glyphs to points, | |
180 | -// but the author has observed that this scale factor is often wrong | |
181 | -// for non-commercial fonts, thus making fonts scaled in points | |
182 | -// according to the TrueType spec incoherently sized in practice. | |
183 | -// | |
184 | -// DETAILED USAGE: | |
185 | -// | |
186 | -// Scale: | |
187 | -// Select how high you want the font to be, in points or pixels. | |
188 | -// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute | |
189 | -// a scale factor SF that will be used by all other functions. | |
190 | -// | |
191 | -// Baseline: | |
192 | -// You need to select a y-coordinate that is the baseline of where | |
193 | -// your text will appear. Call GetFontBoundingBox to get the baseline-relative | |
194 | -// bounding box for all characters. SF*-y0 will be the distance in pixels | |
195 | -// that the worst-case character could extend above the baseline, so if | |
196 | -// you want the top edge of characters to appear at the top of the | |
197 | -// screen where y=0, then you would set the baseline to SF*-y0. | |
198 | -// | |
199 | -// Current point: | |
200 | -// Set the current point where the first character will appear. The | |
201 | -// first character could extend left of the current point; this is font | |
202 | -// dependent. You can either choose a current point that is the leftmost | |
203 | -// point and hope, or add some padding, or check the bounding box or | |
204 | -// left-side-bearing of the first character to be displayed and set | |
205 | -// the current point based on that. | |
206 | -// | |
207 | -// Displaying a character: | |
208 | -// Compute the bounding box of the character. It will contain signed values | |
209 | -// relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1, | |
210 | -// then the character should be displayed in the rectangle from | |
211 | -// <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1). | |
212 | -// | |
213 | -// Advancing for the next character: | |
214 | -// Call GlyphHMetrics, and compute 'current_point += SF * advance'. | |
215 | -// | |
216 | -// | |
217 | -// ADVANCED USAGE | |
218 | -// | |
219 | -// Quality: | |
220 | -// | |
221 | -// - Use the functions with Subpixel at the end to allow your characters | |
222 | -// to have subpixel positioning. Since the font is anti-aliased, not | |
223 | -// hinted, this is very import for quality. (This is not possible with | |
224 | -// baked fonts.) | |
225 | -// | |
226 | -// - Kerning is now supported, and if you're supporting subpixel rendering | |
227 | -// then kerning is worth using to give your text a polished look. | |
228 | -// | |
229 | -// Performance: | |
230 | -// | |
231 | -// - Convert Unicode codepoints to glyph indexes and operate on the glyphs; | |
232 | -// if you don't do this, stb_truetype is forced to do the conversion on | |
233 | -// every call. | |
234 | -// | |
235 | -// - There are a lot of memory allocations. We should modify it to take | |
236 | -// a temp buffer and allocate from the temp buffer (without freeing), | |
237 | -// should help performance a lot. | |
238 | -// | |
239 | -// NOTES | |
240 | -// | |
241 | -// The system uses the raw data found in the .ttf file without changing it | |
242 | -// and without building auxiliary data structures. This is a bit inefficient | |
243 | -// on little-endian systems (the data is big-endian), but assuming you're | |
244 | -// caching the bitmaps or glyph shapes this shouldn't be a big deal. | |
245 | -// | |
246 | -// It appears to be very hard to programmatically determine what font a | |
247 | -// given file is in a general way. I provide an API for this, but I don't | |
248 | -// recommend it. | |
249 | -// | |
250 | -// | |
251 | -// SOURCE STATISTICS (based on v0.6c, 2050 LOC) | |
252 | -// | |
253 | -// Documentation & header file 520 LOC \___ 660 LOC documentation | |
254 | -// Sample code 140 LOC / | |
255 | -// Truetype parsing 620 LOC ---- 620 LOC TrueType | |
256 | -// Software rasterization 240 LOC \. | |
257 | -// Curve tessellation 120 LOC \__ 550 LOC Bitmap creation | |
258 | -// Bitmap management 100 LOC / | |
259 | -// Baked bitmap interface 70 LOC / | |
260 | -// Font name matching & access 150 LOC ---- 150 | |
261 | -// C runtime library abstraction 60 LOC ---- 60 | |
262 | -// | |
263 | -// | |
264 | -// PERFORMANCE MEASUREMENTS FOR 1.06: | |
265 | -// | |
266 | -// 32-bit 64-bit | |
267 | -// Previous release: 8.83 s 7.68 s | |
268 | -// Pool allocations: 7.72 s 6.34 s | |
269 | -// Inline sort : 6.54 s 5.65 s | |
270 | -// New rasterizer : 5.63 s 5.00 s | |
271 | - | |
272 | -////////////////////////////////////////////////////////////////////////////// | |
273 | -////////////////////////////////////////////////////////////////////////////// | |
274 | -//// | |
275 | -//// SAMPLE PROGRAMS | |
276 | -//// | |
277 | -// | |
278 | -// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless | |
279 | -// | |
280 | -#if 0 | |
281 | -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation | |
282 | -#include "stb_truetype.h" | |
283 | - | |
284 | -unsigned char ttf_buffer[1<<20]; | |
285 | -unsigned char temp_bitmap[512*512]; | |
286 | - | |
287 | -stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs | |
288 | -GLuint ftex; | |
289 | - | |
290 | -void my_stbtt_initfont(void) | |
291 | -{ | |
292 | - fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); | |
293 | - stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! | |
294 | - // can free ttf_buffer at this point | |
295 | - glGenTextures(1, &ftex); | |
296 | - glBindTexture(GL_TEXTURE_2D, ftex); | |
297 | - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); | |
298 | - // can free temp_bitmap at this point | |
299 | - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
300 | -} | |
301 | - | |
302 | -void my_stbtt_print(float x, float y, char *text) | |
303 | -{ | |
304 | - // assume orthographic projection with units = screen pixels, origin at top left | |
305 | - glEnable(GL_TEXTURE_2D); | |
306 | - glBindTexture(GL_TEXTURE_2D, ftex); | |
307 | - glBegin(GL_QUADS); | |
308 | - while (*text) { | |
309 | - if (*text >= 32 && *text < 128) { | |
310 | - stbtt_aligned_quad q; | |
311 | - stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 | |
312 | - glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); | |
313 | - glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); | |
314 | - glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); | |
315 | - glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); | |
316 | - } | |
317 | - ++text; | |
318 | - } | |
319 | - glEnd(); | |
320 | -} | |
321 | -#endif | |
322 | -// | |
323 | -// | |
324 | -////////////////////////////////////////////////////////////////////////////// | |
325 | -// | |
326 | -// Complete program (this compiles): get a single bitmap, print as ASCII art | |
327 | -// | |
328 | -#if 0 | |
329 | -#include <stdio.h> | |
330 | -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation | |
331 | -#include "stb_truetype.h" | |
332 | - | |
333 | -char ttf_buffer[1<<25]; | |
334 | - | |
335 | -int main(int argc, char **argv) | |
336 | -{ | |
337 | - stbtt_fontinfo font; | |
338 | - unsigned char *bitmap; | |
339 | - int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); | |
340 | - | |
341 | - fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); | |
342 | - | |
343 | - stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); | |
344 | - bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); | |
345 | - | |
346 | - for (j=0; j < h; ++j) { | |
347 | - for (i=0; i < w; ++i) | |
348 | - putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); | |
349 | - putchar('\n'); | |
350 | - } | |
351 | - return 0; | |
352 | -} | |
353 | -#endif | |
354 | -// | |
355 | -// Output: | |
356 | -// | |
357 | -// .ii. | |
358 | -// @@@@@@. | |
359 | -// V@Mio@@o | |
360 | -// :i. V@V | |
361 | -// :oM@@M | |
362 | -// :@@@MM@M | |
363 | -// @@o o@M | |
364 | -// :@@. M@M | |
365 | -// @@@o@@@@ | |
366 | -// :M@@V:@@. | |
367 | -// | |
368 | -////////////////////////////////////////////////////////////////////////////// | |
369 | -// | |
370 | -// Complete program: print "Hello World!" banner, with bugs | |
371 | -// | |
372 | -#if 0 | |
373 | -char buffer[24<<20]; | |
374 | -unsigned char screen[20][79]; | |
375 | - | |
376 | -int main(int arg, char **argv) | |
377 | -{ | |
378 | - stbtt_fontinfo font; | |
379 | - int i,j,ascent,baseline,ch=0; | |
380 | - float scale, xpos=2; // leave a little padding in case the character extends left | |
381 | - char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness | |
382 | - | |
383 | - fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); | |
384 | - stbtt_InitFont(&font, buffer, 0); | |
385 | - | |
386 | - scale = stbtt_ScaleForPixelHeight(&font, 15); | |
387 | - stbtt_GetFontVMetrics(&font, &ascent,0,0); | |
388 | - baseline = (int) (ascent*scale); | |
389 | - | |
390 | - while (text[ch]) { | |
391 | - int advance,lsb,x0,y0,x1,y1; | |
392 | - float x_shift = xpos - (float) floor(xpos); | |
393 | - stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); | |
394 | - stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); | |
395 | - stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); | |
396 | - // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong | |
397 | - // because this API is really for baking character bitmaps into textures. if you want to render | |
398 | - // a sequence of characters, you really need to render each bitmap to a temp buffer, then | |
399 | - // "alpha blend" that into the working buffer | |
400 | - xpos += (advance * scale); | |
401 | - if (text[ch+1]) | |
402 | - xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); | |
403 | - ++ch; | |
404 | - } | |
405 | - | |
406 | - for (j=0; j < 20; ++j) { | |
407 | - for (i=0; i < 78; ++i) | |
408 | - putchar(" .:ioVM@"[screen[j][i]>>5]); | |
409 | - putchar('\n'); | |
410 | - } | |
411 | - | |
412 | - return 0; | |
413 | -} | |
414 | -#endif | |
415 | - | |
416 | - | |
417 | -////////////////////////////////////////////////////////////////////////////// | |
418 | -////////////////////////////////////////////////////////////////////////////// | |
419 | -//// | |
420 | -//// INTEGRATION WITH YOUR CODEBASE | |
421 | -//// | |
422 | -//// The following sections allow you to supply alternate definitions | |
423 | -//// of C library functions used by stb_truetype, e.g. if you don't | |
424 | -//// link with the C runtime library. | |
425 | - | |
426 | -#ifdef STB_TRUETYPE_IMPLEMENTATION | |
427 | - // #define your own (u)stbtt_int8/16/32 before including to override this | |
428 | - #ifndef stbtt_uint8 | |
429 | - typedef unsigned char stbtt_uint8; | |
430 | - typedef signed char stbtt_int8; | |
431 | - typedef unsigned short stbtt_uint16; | |
432 | - typedef signed short stbtt_int16; | |
433 | - typedef unsigned int stbtt_uint32; | |
434 | - typedef signed int stbtt_int32; | |
435 | - #endif | |
436 | - | |
437 | - typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; | |
438 | - typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; | |
439 | - | |
440 | - // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h | |
441 | - #ifndef STBTT_ifloor | |
442 | - #include <math.h> | |
443 | - #define STBTT_ifloor(x) ((int) floor(x)) | |
444 | - #define STBTT_iceil(x) ((int) ceil(x)) | |
445 | - #endif | |
446 | - | |
447 | - #ifndef STBTT_sqrt | |
448 | - #include <math.h> | |
449 | - #define STBTT_sqrt(x) sqrt(x) | |
450 | - #define STBTT_pow(x,y) pow(x,y) | |
451 | - #endif | |
452 | - | |
453 | - #ifndef STBTT_fmod | |
454 | - #include <math.h> | |
455 | - #define STBTT_fmod(x,y) fmod(x,y) | |
456 | - #endif | |
457 | - | |
458 | - #ifndef STBTT_cos | |
459 | - #include <math.h> | |
460 | - #define STBTT_cos(x) cos(x) | |
461 | - #define STBTT_acos(x) acos(x) | |
462 | - #endif | |
463 | - | |
464 | - #ifndef STBTT_fabs | |
465 | - #include <math.h> | |
466 | - #define STBTT_fabs(x) fabs(x) | |
467 | - #endif | |
468 | - | |
469 | - // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h | |
470 | - #ifndef STBTT_malloc | |
471 | - #include <stdlib.h> | |
472 | - #define STBTT_malloc(x,u) ((void)(u),malloc(x)) | |
473 | - #define STBTT_free(x,u) ((void)(u),free(x)) | |
474 | - #endif | |
475 | - | |
476 | - #ifndef STBTT_assert | |
477 | - #include <assert.h> | |
478 | - #define STBTT_assert(x) assert(x) | |
479 | - #endif | |
480 | - | |
481 | - #ifndef STBTT_strlen | |
482 | - #include <string.h> | |
483 | - #define STBTT_strlen(x) strlen(x) | |
484 | - #endif | |
485 | - | |
486 | - #ifndef STBTT_memcpy | |
487 | - #include <string.h> | |
488 | - #define STBTT_memcpy memcpy | |
489 | - #define STBTT_memset memset | |
490 | - #endif | |
491 | -#endif | |
492 | - | |
493 | -/////////////////////////////////////////////////////////////////////////////// | |
494 | -/////////////////////////////////////////////////////////////////////////////// | |
495 | -//// | |
496 | -//// INTERFACE | |
497 | -//// | |
498 | -//// | |
499 | - | |
500 | -#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ | |
501 | -#define __STB_INCLUDE_STB_TRUETYPE_H__ | |
502 | - | |
503 | -#ifdef STBTT_STATIC | |
504 | -#define STBTT_DEF static | |
505 | -#else | |
506 | -#define STBTT_DEF extern | |
507 | -#endif | |
508 | - | |
509 | -#ifdef __cplusplus | |
510 | -extern "C" { | |
511 | -#endif | |
512 | - | |
513 | -// private structure | |
514 | -typedef struct | |
515 | -{ | |
516 | - unsigned char *data; | |
517 | - int cursor; | |
518 | - int size; | |
519 | -} stbtt__buf; | |
520 | - | |
521 | -////////////////////////////////////////////////////////////////////////////// | |
522 | -// | |
523 | -// TEXTURE BAKING API | |
524 | -// | |
525 | -// If you use this API, you only have to call two functions ever. | |
526 | -// | |
527 | - | |
528 | -typedef struct | |
529 | -{ | |
530 | - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap | |
531 | - float xoff,yoff,xadvance; | |
532 | -} stbtt_bakedchar; | |
533 | - | |
534 | -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) | |
535 | - float pixel_height, // height of font in pixels | |
536 | - unsigned char *pixels, int pw, int ph, // bitmap to be filled in | |
537 | - int first_char, int num_chars, // characters to bake | |
538 | - stbtt_bakedchar *chardata); // you allocate this, it's num_chars long | |
539 | -// if return is positive, the first unused row of the bitmap | |
540 | -// if return is negative, returns the negative of the number of characters that fit | |
541 | -// if return is 0, no characters fit and no rows were used | |
542 | -// This uses a very crappy packing. | |
543 | - | |
544 | -typedef struct | |
545 | -{ | |
546 | - float x0,y0,s0,t0; // top-left | |
547 | - float x1,y1,s1,t1; // bottom-right | |
548 | -} stbtt_aligned_quad; | |
549 | - | |
550 | -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above | |
551 | - int char_index, // character to display | |
552 | - float *xpos, float *ypos, // pointers to current position in screen pixel space | |
553 | - stbtt_aligned_quad *q, // output: quad to draw | |
554 | - int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier | |
555 | -// Call GetBakedQuad with char_index = 'character - first_char', and it | |
556 | -// creates the quad you need to draw and advances the current position. | |
557 | -// | |
558 | -// The coordinate system used assumes y increases downwards. | |
559 | -// | |
560 | -// Characters will extend both above and below the current position; | |
561 | -// see discussion of "BASELINE" above. | |
562 | -// | |
563 | -// It's inefficient; you might want to c&p it and optimize it. | |
564 | - | |
565 | -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); | |
566 | -// Query the font vertical metrics without having to create a font first. | |
567 | - | |
568 | - | |
569 | -////////////////////////////////////////////////////////////////////////////// | |
570 | -// | |
571 | -// NEW TEXTURE BAKING API | |
572 | -// | |
573 | -// This provides options for packing multiple fonts into one atlas, not | |
574 | -// perfectly but better than nothing. | |
575 | - | |
576 | -typedef struct | |
577 | -{ | |
578 | - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap | |
579 | - float xoff,yoff,xadvance; | |
580 | - float xoff2,yoff2; | |
581 | -} stbtt_packedchar; | |
582 | - | |
583 | -typedef struct stbtt_pack_context stbtt_pack_context; | |
584 | -typedef struct stbtt_fontinfo stbtt_fontinfo; | |
585 | -#ifndef STB_RECT_PACK_VERSION | |
586 | -typedef struct stbrp_rect stbrp_rect; | |
587 | -#endif | |
588 | - | |
589 | -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); | |
590 | -// Initializes a packing context stored in the passed-in stbtt_pack_context. | |
591 | -// Future calls using this context will pack characters into the bitmap passed | |
592 | -// in here: a 1-channel bitmap that is width * height. stride_in_bytes is | |
593 | -// the distance from one row to the next (or 0 to mean they are packed tightly | |
594 | -// together). "padding" is the amount of padding to leave between each | |
595 | -// character (normally you want '1' for bitmaps you'll use as textures with | |
596 | -// bilinear filtering). | |
597 | -// | |
598 | -// Returns 0 on failure, 1 on success. | |
599 | - | |
600 | -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); | |
601 | -// Cleans up the packing context and frees all memory. | |
602 | - | |
603 | -#define STBTT_POINT_SIZE(x) (-(x)) | |
604 | - | |
605 | -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, | |
606 | - int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); | |
607 | -// Creates character bitmaps from the font_index'th font found in fontdata (use | |
608 | -// font_index=0 if you don't know what that is). It creates num_chars_in_range | |
609 | -// bitmaps for characters with unicode values starting at first_unicode_char_in_range | |
610 | -// and increasing. Data for how to render them is stored in chardata_for_range; | |
611 | -// pass these to stbtt_GetPackedQuad to get back renderable quads. | |
612 | -// | |
613 | -// font_size is the full height of the character from ascender to descender, | |
614 | -// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed | |
615 | -// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() | |
616 | -// and pass that result as 'font_size': | |
617 | -// ..., 20 , ... // font max minus min y is 20 pixels tall | |
618 | -// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall | |
619 | - | |
620 | -typedef struct | |
621 | -{ | |
622 | - float font_size; | |
623 | - int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint | |
624 | - int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints | |
625 | - int num_chars; | |
626 | - stbtt_packedchar *chardata_for_range; // output | |
627 | - unsigned char h_oversample, v_oversample; // don't set these, they're used internally | |
628 | -} stbtt_pack_range; | |
629 | - | |
630 | -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); | |
631 | -// Creates character bitmaps from multiple ranges of characters stored in | |
632 | -// ranges. This will usually create a better-packed bitmap than multiple | |
633 | -// calls to stbtt_PackFontRange. Note that you can call this multiple | |
634 | -// times within a single PackBegin/PackEnd. | |
635 | - | |
636 | -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); | |
637 | -// Oversampling a font increases the quality by allowing higher-quality subpixel | |
638 | -// positioning, and is especially valuable at smaller text sizes. | |
639 | -// | |
640 | -// This function sets the amount of oversampling for all following calls to | |
641 | -// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given | |
642 | -// pack context. The default (no oversampling) is achieved by h_oversample=1 | |
643 | -// and v_oversample=1. The total number of pixels required is | |
644 | -// h_oversample*v_oversample larger than the default; for example, 2x2 | |
645 | -// oversampling requires 4x the storage of 1x1. For best results, render | |
646 | -// oversampled textures with bilinear filtering. Look at the readme in | |
647 | -// stb/tests/oversample for information about oversampled fonts | |
648 | -// | |
649 | -// To use with PackFontRangesGather etc., you must set it before calls | |
650 | -// call to PackFontRangesGatherRects. | |
651 | - | |
652 | -STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); | |
653 | -// If skip != 0, this tells stb_truetype to skip any codepoints for which | |
654 | -// there is no corresponding glyph. If skip=0, which is the default, then | |
655 | -// codepoints without a glyph recived the font's "missing character" glyph, | |
656 | -// typically an empty box by convention. | |
657 | - | |
658 | -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above | |
659 | - int char_index, // character to display | |
660 | - float *xpos, float *ypos, // pointers to current position in screen pixel space | |
661 | - stbtt_aligned_quad *q, // output: quad to draw | |
662 | - int align_to_integer); | |
663 | - | |
664 | -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); | |
665 | -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); | |
666 | -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); | |
667 | -// Calling these functions in sequence is roughly equivalent to calling | |
668 | -// stbtt_PackFontRanges(). If you more control over the packing of multiple | |
669 | -// fonts, or if you want to pack custom data into a font texture, take a look | |
670 | -// at the source to of stbtt_PackFontRanges() and create a custom version | |
671 | -// using these functions, e.g. call GatherRects multiple times, | |
672 | -// building up a single array of rects, then call PackRects once, | |
673 | -// then call RenderIntoRects repeatedly. This may result in a | |
674 | -// better packing than calling PackFontRanges multiple times | |
675 | -// (or it may not). | |
676 | - | |
677 | -// this is an opaque structure that you shouldn't mess with which holds | |
678 | -// all the context needed from PackBegin to PackEnd. | |
679 | -struct stbtt_pack_context { | |
680 | - void *user_allocator_context; | |
681 | - void *pack_info; | |
682 | - int width; | |
683 | - int height; | |
684 | - int stride_in_bytes; | |
685 | - int padding; | |
686 | - int skip_missing; | |
687 | - unsigned int h_oversample, v_oversample; | |
688 | - unsigned char *pixels; | |
689 | - void *nodes; | |
690 | -}; | |
691 | - | |
692 | -////////////////////////////////////////////////////////////////////////////// | |
693 | -// | |
694 | -// FONT LOADING | |
695 | -// | |
696 | -// | |
697 | - | |
698 | -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); | |
699 | -// This function will determine the number of fonts in a font file. TrueType | |
700 | -// collection (.ttc) files may contain multiple fonts, while TrueType font | |
701 | -// (.ttf) files only contain one font. The number of fonts can be used for | |
702 | -// indexing with the previous function where the index is between zero and one | |
703 | -// less than the total fonts. If an error occurs, -1 is returned. | |
704 | - | |
705 | -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); | |
706 | -// Each .ttf/.ttc file may have more than one font. Each font has a sequential | |
707 | -// index number starting from 0. Call this function to get the font offset for | |
708 | -// a given index; it returns -1 if the index is out of range. A regular .ttf | |
709 | -// file will only define one font and it always be at offset 0, so it will | |
710 | -// return '0' for index 0, and -1 for all other indices. | |
711 | - | |
712 | -// The following structure is defined publicly so you can declare one on | |
713 | -// the stack or as a global or etc, but you should treat it as opaque. | |
714 | -struct stbtt_fontinfo | |
715 | -{ | |
716 | - void * userdata; | |
717 | - unsigned char * data; // pointer to .ttf file | |
718 | - int fontstart; // offset of start of font | |
719 | - | |
720 | - int numGlyphs; // number of glyphs, needed for range checking | |
721 | - | |
722 | - int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf | |
723 | - int index_map; // a cmap mapping for our chosen character encoding | |
724 | - int indexToLocFormat; // format needed to map from glyph index to glyph | |
725 | - | |
726 | - stbtt__buf cff; // cff font data | |
727 | - stbtt__buf charstrings; // the charstring index | |
728 | - stbtt__buf gsubrs; // global charstring subroutines index | |
729 | - stbtt__buf subrs; // private charstring subroutines index | |
730 | - stbtt__buf fontdicts; // array of font dicts | |
731 | - stbtt__buf fdselect; // map from glyph to fontdict | |
732 | -}; | |
733 | - | |
734 | -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); | |
735 | -// Given an offset into the file that defines a font, this function builds | |
736 | -// the necessary cached info for the rest of the system. You must allocate | |
737 | -// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't | |
738 | -// need to do anything special to free it, because the contents are pure | |
739 | -// value data with no additional data structures. Returns 0 on failure. | |
740 | - | |
741 | - | |
742 | -////////////////////////////////////////////////////////////////////////////// | |
743 | -// | |
744 | -// CHARACTER TO GLYPH-INDEX CONVERSIOn | |
745 | - | |
746 | -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); | |
747 | -// If you're going to perform multiple operations on the same character | |
748 | -// and you want a speed-up, call this function with the character you're | |
749 | -// going to process, then use glyph-based functions instead of the | |
750 | -// codepoint-based functions. | |
751 | -// Returns 0 if the character codepoint is not defined in the font. | |
752 | - | |
753 | - | |
754 | -////////////////////////////////////////////////////////////////////////////// | |
755 | -// | |
756 | -// CHARACTER PROPERTIES | |
757 | -// | |
758 | - | |
759 | -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); | |
760 | -// computes a scale factor to produce a font whose "height" is 'pixels' tall. | |
761 | -// Height is measured as the distance from the highest ascender to the lowest | |
762 | -// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics | |
763 | -// and computing: | |
764 | -// scale = pixels / (ascent - descent) | |
765 | -// so if you prefer to measure height by the ascent only, use a similar calculation. | |
766 | - | |
767 | -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); | |
768 | -// computes a scale factor to produce a font whose EM size is mapped to | |
769 | -// 'pixels' tall. This is probably what traditional APIs compute, but | |
770 | -// I'm not positive. | |
771 | - | |
772 | -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); | |
773 | -// ascent is the coordinate above the baseline the font extends; descent | |
774 | -// is the coordinate below the baseline the font extends (i.e. it is typically negative) | |
775 | -// lineGap is the spacing between one row's descent and the next row's ascent... | |
776 | -// so you should advance the vertical position by "*ascent - *descent + *lineGap" | |
777 | -// these are expressed in unscaled coordinates, so you must multiply by | |
778 | -// the scale factor for a given size | |
779 | - | |
780 | -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); | |
781 | -// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 | |
782 | -// table (specific to MS/Windows TTF files). | |
783 | -// | |
784 | -// Returns 1 on success (table present), 0 on failure. | |
785 | - | |
786 | -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); | |
787 | -// the bounding box around all possible characters | |
788 | - | |
789 | -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); | |
790 | -// leftSideBearing is the offset from the current horizontal position to the left edge of the character | |
791 | -// advanceWidth is the offset from the current horizontal position to the next horizontal position | |
792 | -// these are expressed in unscaled coordinates | |
793 | - | |
794 | -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); | |
795 | -// an additional amount to add to the 'advance' value between ch1 and ch2 | |
796 | - | |
797 | -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); | |
798 | -// Gets the bounding box of the visible part of the glyph, in unscaled coordinates | |
799 | - | |
800 | -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); | |
801 | -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); | |
802 | -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); | |
803 | -// as above, but takes one or more glyph indices for greater efficiency | |
804 | - | |
805 | - | |
806 | -////////////////////////////////////////////////////////////////////////////// | |
807 | -// | |
808 | -// GLYPH SHAPES (you probably don't need these, but they have to go before | |
809 | -// the bitmaps for C declaration-order reasons) | |
810 | -// | |
811 | - | |
812 | -#ifndef STBTT_vmove // you can predefine these to use different values (but why?) | |
813 | - enum { | |
814 | - STBTT_vmove=1, | |
815 | - STBTT_vline, | |
816 | - STBTT_vcurve, | |
817 | - STBTT_vcubic | |
818 | - }; | |
819 | -#endif | |
820 | - | |
821 | -#ifndef stbtt_vertex // you can predefine this to use different values | |
822 | - // (we share this with other code at RAD) | |
823 | - #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file | |
824 | - typedef struct | |
825 | - { | |
826 | - stbtt_vertex_type x,y,cx,cy,cx1,cy1; | |
827 | - unsigned char type,padding; | |
828 | - } stbtt_vertex; | |
829 | -#endif | |
830 | - | |
831 | -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); | |
832 | -// returns non-zero if nothing is drawn for this glyph | |
833 | - | |
834 | -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); | |
835 | -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); | |
836 | -// returns # of vertices and fills *vertices with the pointer to them | |
837 | -// these are expressed in "unscaled" coordinates | |
838 | -// | |
839 | -// The shape is a series of contours. Each one starts with | |
840 | -// a STBTT_moveto, then consists of a series of mixed | |
841 | -// STBTT_lineto and STBTT_curveto segments. A lineto | |
842 | -// draws a line from previous endpoint to its x,y; a curveto | |
843 | -// draws a quadratic bezier from previous endpoint to | |
844 | -// its x,y, using cx,cy as the bezier control point. | |
845 | - | |
846 | -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); | |
847 | -// frees the data allocated above | |
848 | - | |
849 | -////////////////////////////////////////////////////////////////////////////// | |
850 | -// | |
851 | -// BITMAP RENDERING | |
852 | -// | |
853 | - | |
854 | -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); | |
855 | -// frees the bitmap allocated below | |
856 | - | |
857 | -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); | |
858 | -// allocates a large-enough single-channel 8bpp bitmap and renders the | |
859 | -// specified character/glyph at the specified scale into it, with | |
860 | -// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). | |
861 | -// *width & *height are filled out with the width & height of the bitmap, | |
862 | -// which is stored left-to-right, top-to-bottom. | |
863 | -// | |
864 | -// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap | |
865 | - | |
866 | -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); | |
867 | -// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel | |
868 | -// shift for the character | |
869 | - | |
870 | -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); | |
871 | -// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap | |
872 | -// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap | |
873 | -// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the | |
874 | -// width and height and positioning info for it first. | |
875 | - | |
876 | -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); | |
877 | -// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel | |
878 | -// shift for the character | |
879 | - | |
880 | -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(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 oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); | |
881 | -// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering | |
882 | -// is performed (see stbtt_PackSetOversampling) | |
883 | - | |
884 | -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); | |
885 | -// get the bbox of the bitmap centered around the glyph origin; so the | |
886 | -// bitmap width is ix1-ix0, height is iy1-iy0, and location to place | |
887 | -// the bitmap top left is (leftSideBearing*scale,iy0). | |
888 | -// (Note that the bitmap uses y-increases-down, but the shape uses | |
889 | -// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) | |
890 | - | |
891 | -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); | |
892 | -// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel | |
893 | -// shift for the character | |
894 | - | |
895 | -// the following functions are equivalent to the above functions, but operate | |
896 | -// on glyph indices instead of Unicode codepoints (for efficiency) | |
897 | -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); | |
898 | -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); | |
899 | -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); | |
900 | -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); | |
901 | -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(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 oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); | |
902 | -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); | |
903 | -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); | |
904 | - | |
905 | - | |
906 | -// @TODO: don't expose this structure | |
907 | -typedef struct | |
908 | -{ | |
909 | - int w,h,stride; | |
910 | - unsigned char *pixels; | |
911 | -} stbtt__bitmap; | |
912 | - | |
913 | -// rasterize a shape with quadratic beziers into a bitmap | |
914 | -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into | |
915 | - float flatness_in_pixels, // allowable error of curve in pixels | |
916 | - stbtt_vertex *vertices, // array of vertices defining shape | |
917 | - int num_verts, // number of vertices in above array | |
918 | - float scale_x, float scale_y, // scale applied to input vertices | |
919 | - float shift_x, float shift_y, // translation applied to input vertices | |
920 | - int x_off, int y_off, // another translation applied to input | |
921 | - int invert, // if non-zero, vertically flip shape | |
922 | - void *userdata); // context for to STBTT_MALLOC | |
923 | - | |
924 | -////////////////////////////////////////////////////////////////////////////// | |
925 | -// | |
926 | -// Signed Distance Function (or Field) rendering | |
927 | - | |
928 | -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); | |
929 | -// frees the SDF bitmap allocated below | |
930 | - | |
931 | -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); | |
932 | -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); | |
933 | -// These functions compute a discretized SDF field for a single character, suitable for storing | |
934 | -// in a single-channel texture, sampling with bilinear filtering, and testing against | |
935 | -// larger than some threshold to produce scalable fonts. | |
936 | -// info -- the font | |
937 | -// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap | |
938 | -// glyph/codepoint -- the character to generate the SDF for | |
939 | -// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), | |
940 | -// which allows effects like bit outlines | |
941 | -// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) | |
942 | -// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) | |
943 | -// if positive, > onedge_value is inside; if negative, < onedge_value is inside | |
944 | -// width,height -- output height & width of the SDF bitmap (including padding) | |
945 | -// xoff,yoff -- output origin of the character | |
946 | -// return value -- a 2D array of bytes 0..255, width*height in size | |
947 | -// | |
948 | -// pixel_dist_scale & onedge_value are a scale & bias that allows you to make | |
949 | -// optimal use of the limited 0..255 for your application, trading off precision | |
950 | -// and special effects. SDF values outside the range 0..255 are clamped to 0..255. | |
951 | -// | |
952 | -// Example: | |
953 | -// scale = stbtt_ScaleForPixelHeight(22) | |
954 | -// padding = 5 | |
955 | -// onedge_value = 180 | |
956 | -// pixel_dist_scale = 180/5.0 = 36.0 | |
957 | -// | |
958 | -// This will create an SDF bitmap in which the character is about 22 pixels | |
959 | -// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled | |
960 | -// shape, sample the SDF at each pixel and fill the pixel if the SDF value | |
961 | -// is greater than or equal to 180/255. (You'll actually want to antialias, | |
962 | -// which is beyond the scope of this example.) Additionally, you can compute | |
963 | -// offset outlines (e.g. to stroke the character border inside & outside, | |
964 | -// or only outside). For example, to fill outside the character up to 3 SDF | |
965 | -// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above | |
966 | -// choice of variables maps a range from 5 pixels outside the shape to | |
967 | -// 2 pixels inside the shape to 0..255; this is intended primarily for apply | |
968 | -// outside effects only (the interior range is needed to allow proper | |
969 | -// antialiasing of the font at *smaller* sizes) | |
970 | -// | |
971 | -// The function computes the SDF analytically at each SDF pixel, not by e.g. | |
972 | -// building a higher-res bitmap and approximating it. In theory the quality | |
973 | -// should be as high as possible for an SDF of this size & representation, but | |
974 | -// unclear if this is true in practice (perhaps building a higher-res bitmap | |
975 | -// and computing from that can allow drop-out prevention). | |
976 | -// | |
977 | -// The algorithm has not been optimized at all, so expect it to be slow | |
978 | -// if computing lots of characters or very large sizes. | |
979 | - | |
980 | - | |
981 | - | |
982 | -////////////////////////////////////////////////////////////////////////////// | |
983 | -// | |
984 | -// Finding the right font... | |
985 | -// | |
986 | -// You should really just solve this offline, keep your own tables | |
987 | -// of what font is what, and don't try to get it out of the .ttf file. | |
988 | -// That's because getting it out of the .ttf file is really hard, because | |
989 | -// the names in the file can appear in many possible encodings, in many | |
990 | -// possible languages, and e.g. if you need a case-insensitive comparison, | |
991 | -// the details of that depend on the encoding & language in a complex way | |
992 | -// (actually underspecified in truetype, but also gigantic). | |
993 | -// | |
994 | -// But you can use the provided functions in two possible ways: | |
995 | -// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on | |
996 | -// unicode-encoded names to try to find the font you want; | |
997 | -// you can run this before calling stbtt_InitFont() | |
998 | -// | |
999 | -// stbtt_GetFontNameString() lets you get any of the various strings | |
1000 | -// from the file yourself and do your own comparisons on them. | |
1001 | -// You have to have called stbtt_InitFont() first. | |
1002 | - | |
1003 | - | |
1004 | -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); | |
1005 | -// returns the offset (not index) of the font that matches, or -1 if none | |
1006 | -// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". | |
1007 | -// if you use any other flag, use a font name like "Arial"; this checks | |
1008 | -// the 'macStyle' header field; i don't know if fonts set this consistently | |
1009 | -#define STBTT_MACSTYLE_DONTCARE 0 | |
1010 | -#define STBTT_MACSTYLE_BOLD 1 | |
1011 | -#define STBTT_MACSTYLE_ITALIC 2 | |
1012 | -#define STBTT_MACSTYLE_UNDERSCORE 4 | |
1013 | -#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 | |
1014 | - | |
1015 | -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); | |
1016 | -// returns 1/0 whether the first string interpreted as utf8 is identical to | |
1017 | -// the second string interpreted as big-endian utf16... useful for strings from next func | |
1018 | - | |
1019 | -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); | |
1020 | -// returns the string (which may be big-endian double byte, e.g. for unicode) | |
1021 | -// and puts the length in bytes in *length. | |
1022 | -// | |
1023 | -// some of the values for the IDs are below; for more see the truetype spec: | |
1024 | -// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html | |
1025 | -// http://www.microsoft.com/typography/otspec/name.htm | |
1026 | - | |
1027 | -enum { // platformID | |
1028 | - STBTT_PLATFORM_ID_UNICODE =0, | |
1029 | - STBTT_PLATFORM_ID_MAC =1, | |
1030 | - STBTT_PLATFORM_ID_ISO =2, | |
1031 | - STBTT_PLATFORM_ID_MICROSOFT =3 | |
1032 | -}; | |
1033 | - | |
1034 | -enum { // encodingID for STBTT_PLATFORM_ID_UNICODE | |
1035 | - STBTT_UNICODE_EID_UNICODE_1_0 =0, | |
1036 | - STBTT_UNICODE_EID_UNICODE_1_1 =1, | |
1037 | - STBTT_UNICODE_EID_ISO_10646 =2, | |
1038 | - STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, | |
1039 | - STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 | |
1040 | -}; | |
1041 | - | |
1042 | -enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT | |
1043 | - STBTT_MS_EID_SYMBOL =0, | |
1044 | - STBTT_MS_EID_UNICODE_BMP =1, | |
1045 | - STBTT_MS_EID_SHIFTJIS =2, | |
1046 | - STBTT_MS_EID_UNICODE_FULL =10 | |
1047 | -}; | |
1048 | - | |
1049 | -enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes | |
1050 | - STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, | |
1051 | - STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, | |
1052 | - STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, | |
1053 | - STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 | |
1054 | -}; | |
1055 | - | |
1056 | -enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... | |
1057 | - // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs | |
1058 | - STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, | |
1059 | - STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, | |
1060 | - STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, | |
1061 | - STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, | |
1062 | - STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, | |
1063 | - STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D | |
1064 | -}; | |
1065 | - | |
1066 | -enum { // languageID for STBTT_PLATFORM_ID_MAC | |
1067 | - STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, | |
1068 | - STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, | |
1069 | - STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, | |
1070 | - STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , | |
1071 | - STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , | |
1072 | - STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, | |
1073 | - STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 | |
1074 | -}; | |
1075 | - | |
1076 | -#ifdef __cplusplus | |
1077 | -} | |
1078 | -#endif | |
1079 | - | |
1080 | -#endif // __STB_INCLUDE_STB_TRUETYPE_H__ | |
1081 | - | |
1082 | -/////////////////////////////////////////////////////////////////////////////// | |
1083 | -/////////////////////////////////////////////////////////////////////////////// | |
1084 | -//// | |
1085 | -//// IMPLEMENTATION | |
1086 | -//// | |
1087 | -//// | |
1088 | - | |
1089 | -#ifdef STB_TRUETYPE_IMPLEMENTATION | |
1090 | - | |
1091 | -#ifndef STBTT_MAX_OVERSAMPLE | |
1092 | -#define STBTT_MAX_OVERSAMPLE 8 | |
1093 | -#endif | |
1094 | - | |
1095 | -#if STBTT_MAX_OVERSAMPLE > 255 | |
1096 | -#error "STBTT_MAX_OVERSAMPLE cannot be > 255" | |
1097 | -#endif | |
1098 | - | |
1099 | -typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; | |
1100 | - | |
1101 | -#ifndef STBTT_RASTERIZER_VERSION | |
1102 | -#define STBTT_RASTERIZER_VERSION 2 | |
1103 | -#endif | |
1104 | - | |
1105 | -#ifdef _MSC_VER | |
1106 | -#define STBTT__NOTUSED(v) (void)(v) | |
1107 | -#else | |
1108 | -#define STBTT__NOTUSED(v) (void)sizeof(v) | |
1109 | -#endif | |
1110 | - | |
1111 | -////////////////////////////////////////////////////////////////////////// | |
1112 | -// | |
1113 | -// stbtt__buf helpers to parse data from file | |
1114 | -// | |
1115 | - | |
1116 | -static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) | |
1117 | -{ | |
1118 | - if (b->cursor >= b->size) | |
1119 | - return 0; | |
1120 | - return b->data[b->cursor++]; | |
1121 | -} | |
1122 | - | |
1123 | -static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) | |
1124 | -{ | |
1125 | - if (b->cursor >= b->size) | |
1126 | - return 0; | |
1127 | - return b->data[b->cursor]; | |
1128 | -} | |
1129 | - | |
1130 | -static void stbtt__buf_seek(stbtt__buf *b, int o) | |
1131 | -{ | |
1132 | - STBTT_assert(!(o > b->size || o < 0)); | |
1133 | - b->cursor = (o > b->size || o < 0) ? b->size : o; | |
1134 | -} | |
1135 | - | |
1136 | -static void stbtt__buf_skip(stbtt__buf *b, int o) | |
1137 | -{ | |
1138 | - stbtt__buf_seek(b, b->cursor + o); | |
1139 | -} | |
1140 | - | |
1141 | -static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) | |
1142 | -{ | |
1143 | - stbtt_uint32 v = 0; | |
1144 | - int i; | |
1145 | - STBTT_assert(n >= 1 && n <= 4); | |
1146 | - for (i = 0; i < n; i++) | |
1147 | - v = (v << 8) | stbtt__buf_get8(b); | |
1148 | - return v; | |
1149 | -} | |
1150 | - | |
1151 | -static stbtt__buf stbtt__new_buf(const void *p, size_t size) | |
1152 | -{ | |
1153 | - stbtt__buf r; | |
1154 | - STBTT_assert(size < 0x40000000); | |
1155 | - r.data = (stbtt_uint8*) p; | |
1156 | - r.size = (int) size; | |
1157 | - r.cursor = 0; | |
1158 | - return r; | |
1159 | -} | |
1160 | - | |
1161 | -#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) | |
1162 | -#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) | |
1163 | - | |
1164 | -static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) | |
1165 | -{ | |
1166 | - stbtt__buf r = stbtt__new_buf(NULL, 0); | |
1167 | - if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; | |
1168 | - r.data = b->data + o; | |
1169 | - r.size = s; | |
1170 | - return r; | |
1171 | -} | |
1172 | - | |
1173 | -static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) | |
1174 | -{ | |
1175 | - int count, start, offsize; | |
1176 | - start = b->cursor; | |
1177 | - count = stbtt__buf_get16(b); | |
1178 | - if (count) { | |
1179 | - offsize = stbtt__buf_get8(b); | |
1180 | - STBTT_assert(offsize >= 1 && offsize <= 4); | |
1181 | - stbtt__buf_skip(b, offsize * count); | |
1182 | - stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); | |
1183 | - } | |
1184 | - return stbtt__buf_range(b, start, b->cursor - start); | |
1185 | -} | |
1186 | - | |
1187 | -static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) | |
1188 | -{ | |
1189 | - int b0 = stbtt__buf_get8(b); | |
1190 | - if (b0 >= 32 && b0 <= 246) return b0 - 139; | |
1191 | - else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; | |
1192 | - else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; | |
1193 | - else if (b0 == 28) return stbtt__buf_get16(b); | |
1194 | - else if (b0 == 29) return stbtt__buf_get32(b); | |
1195 | - STBTT_assert(0); | |
1196 | - return 0; | |
1197 | -} | |
1198 | - | |
1199 | -static void stbtt__cff_skip_operand(stbtt__buf *b) { | |
1200 | - int v, b0 = stbtt__buf_peek8(b); | |
1201 | - STBTT_assert(b0 >= 28); | |
1202 | - if (b0 == 30) { | |
1203 | - stbtt__buf_skip(b, 1); | |
1204 | - while (b->cursor < b->size) { | |
1205 | - v = stbtt__buf_get8(b); | |
1206 | - if ((v & 0xF) == 0xF || (v >> 4) == 0xF) | |
1207 | - break; | |
1208 | - } | |
1209 | - } else { | |
1210 | - stbtt__cff_int(b); | |
1211 | - } | |
1212 | -} | |
1213 | - | |
1214 | -static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) | |
1215 | -{ | |
1216 | - stbtt__buf_seek(b, 0); | |
1217 | - while (b->cursor < b->size) { | |
1218 | - int start = b->cursor, end, op; | |
1219 | - while (stbtt__buf_peek8(b) >= 28) | |
1220 | - stbtt__cff_skip_operand(b); | |
1221 | - end = b->cursor; | |
1222 | - op = stbtt__buf_get8(b); | |
1223 | - if (op == 12) op = stbtt__buf_get8(b) | 0x100; | |
1224 | - if (op == key) return stbtt__buf_range(b, start, end-start); | |
1225 | - } | |
1226 | - return stbtt__buf_range(b, 0, 0); | |
1227 | -} | |
1228 | - | |
1229 | -static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) | |
1230 | -{ | |
1231 | - int i; | |
1232 | - stbtt__buf operands = stbtt__dict_get(b, key); | |
1233 | - for (i = 0; i < outcount && operands.cursor < operands.size; i++) | |
1234 | - out[i] = stbtt__cff_int(&operands); | |
1235 | -} | |
1236 | - | |
1237 | -static int stbtt__cff_index_count(stbtt__buf *b) | |
1238 | -{ | |
1239 | - stbtt__buf_seek(b, 0); | |
1240 | - return stbtt__buf_get16(b); | |
1241 | -} | |
1242 | - | |
1243 | -static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) | |
1244 | -{ | |
1245 | - int count, offsize, start, end; | |
1246 | - stbtt__buf_seek(&b, 0); | |
1247 | - count = stbtt__buf_get16(&b); | |
1248 | - offsize = stbtt__buf_get8(&b); | |
1249 | - STBTT_assert(i >= 0 && i < count); | |
1250 | - STBTT_assert(offsize >= 1 && offsize <= 4); | |
1251 | - stbtt__buf_skip(&b, i*offsize); | |
1252 | - start = stbtt__buf_get(&b, offsize); | |
1253 | - end = stbtt__buf_get(&b, offsize); | |
1254 | - return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); | |
1255 | -} | |
1256 | - | |
1257 | -////////////////////////////////////////////////////////////////////////// | |
1258 | -// | |
1259 | -// accessors to parse data from file | |
1260 | -// | |
1261 | - | |
1262 | -// on platforms that don't allow misaligned reads, if we want to allow | |
1263 | -// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE | |
1264 | - | |
1265 | -#define ttBYTE(p) (* (stbtt_uint8 *) (p)) | |
1266 | -#define ttCHAR(p) (* (stbtt_int8 *) (p)) | |
1267 | -#define ttFixed(p) ttLONG(p) | |
1268 | - | |
1269 | -static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } | |
1270 | -static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } | |
1271 | -static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } | |
1272 | -static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } | |
1273 | - | |
1274 | -#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) | |
1275 | -#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) | |
1276 | - | |
1277 | -static int stbtt__isfont(stbtt_uint8 *font) | |
1278 | -{ | |
1279 | - // check the version number | |
1280 | - if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 | |
1281 | - if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! | |
1282 | - if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF | |
1283 | - if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 | |
1284 | - if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts | |
1285 | - return 0; | |
1286 | -} | |
1287 | - | |
1288 | -// @OPTIMIZE: binary search | |
1289 | -static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) | |
1290 | -{ | |
1291 | - stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); | |
1292 | - stbtt_uint32 tabledir = fontstart + 12; | |
1293 | - stbtt_int32 i; | |
1294 | - for (i=0; i < num_tables; ++i) { | |
1295 | - stbtt_uint32 loc = tabledir + 16*i; | |
1296 | - if (stbtt_tag(data+loc+0, tag)) | |
1297 | - return ttULONG(data+loc+8); | |
1298 | - } | |
1299 | - return 0; | |
1300 | -} | |
1301 | - | |
1302 | -static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) | |
1303 | -{ | |
1304 | - // if it's just a font, there's only one valid index | |
1305 | - if (stbtt__isfont(font_collection)) | |
1306 | - return index == 0 ? 0 : -1; | |
1307 | - | |
1308 | - // check if it's a TTC | |
1309 | - if (stbtt_tag(font_collection, "ttcf")) { | |
1310 | - // version 1? | |
1311 | - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { | |
1312 | - stbtt_int32 n = ttLONG(font_collection+8); | |
1313 | - if (index >= n) | |
1314 | - return -1; | |
1315 | - return ttULONG(font_collection+12+index*4); | |
1316 | - } | |
1317 | - } | |
1318 | - return -1; | |
1319 | -} | |
1320 | - | |
1321 | -static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) | |
1322 | -{ | |
1323 | - // if it's just a font, there's only one valid font | |
1324 | - if (stbtt__isfont(font_collection)) | |
1325 | - return 1; | |
1326 | - | |
1327 | - // check if it's a TTC | |
1328 | - if (stbtt_tag(font_collection, "ttcf")) { | |
1329 | - // version 1? | |
1330 | - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { | |
1331 | - return ttLONG(font_collection+8); | |
1332 | - } | |
1333 | - } | |
1334 | - return 0; | |
1335 | -} | |
1336 | - | |
1337 | -static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) | |
1338 | -{ | |
1339 | - stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; | |
1340 | - stbtt__buf pdict; | |
1341 | - stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); | |
1342 | - if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); | |
1343 | - pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); | |
1344 | - stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); | |
1345 | - if (!subrsoff) return stbtt__new_buf(NULL, 0); | |
1346 | - stbtt__buf_seek(&cff, private_loc[1]+subrsoff); | |
1347 | - return stbtt__cff_get_index(&cff); | |
1348 | -} | |
1349 | - | |
1350 | -static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) | |
1351 | -{ | |
1352 | - stbtt_uint32 cmap, t; | |
1353 | - stbtt_int32 i,numTables; | |
1354 | - | |
1355 | - info->data = data; | |
1356 | - info->fontstart = fontstart; | |
1357 | - info->cff = stbtt__new_buf(NULL, 0); | |
1358 | - | |
1359 | - cmap = stbtt__find_table(data, fontstart, "cmap"); // required | |
1360 | - info->loca = stbtt__find_table(data, fontstart, "loca"); // required | |
1361 | - info->head = stbtt__find_table(data, fontstart, "head"); // required | |
1362 | - info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required | |
1363 | - info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required | |
1364 | - info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required | |
1365 | - info->kern = stbtt__find_table(data, fontstart, "kern"); // not required | |
1366 | - info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required | |
1367 | - | |
1368 | - if (!cmap || !info->head || !info->hhea || !info->hmtx) | |
1369 | - return 0; | |
1370 | - if (info->glyf) { | |
1371 | - // required for truetype | |
1372 | - if (!info->loca) return 0; | |
1373 | - } else { | |
1374 | - // initialization for CFF / Type2 fonts (OTF) | |
1375 | - stbtt__buf b, topdict, topdictidx; | |
1376 | - stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; | |
1377 | - stbtt_uint32 cff; | |
1378 | - | |
1379 | - cff = stbtt__find_table(data, fontstart, "CFF "); | |
1380 | - if (!cff) return 0; | |
1381 | - | |
1382 | - info->fontdicts = stbtt__new_buf(NULL, 0); | |
1383 | - info->fdselect = stbtt__new_buf(NULL, 0); | |
1384 | - | |
1385 | - // @TODO this should use size from table (not 512MB) | |
1386 | - info->cff = stbtt__new_buf(data+cff, 512*1024*1024); | |
1387 | - b = info->cff; | |
1388 | - | |
1389 | - // read the header | |
1390 | - stbtt__buf_skip(&b, 2); | |
1391 | - stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize | |
1392 | - | |
1393 | - // @TODO the name INDEX could list multiple fonts, | |
1394 | - // but we just use the first one. | |
1395 | - stbtt__cff_get_index(&b); // name INDEX | |
1396 | - topdictidx = stbtt__cff_get_index(&b); | |
1397 | - topdict = stbtt__cff_index_get(topdictidx, 0); | |
1398 | - stbtt__cff_get_index(&b); // string INDEX | |
1399 | - info->gsubrs = stbtt__cff_get_index(&b); | |
1400 | - | |
1401 | - stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); | |
1402 | - stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); | |
1403 | - stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); | |
1404 | - stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); | |
1405 | - info->subrs = stbtt__get_subrs(b, topdict); | |
1406 | - | |
1407 | - // we only support Type 2 charstrings | |
1408 | - if (cstype != 2) return 0; | |
1409 | - if (charstrings == 0) return 0; | |
1410 | - | |
1411 | - if (fdarrayoff) { | |
1412 | - // looks like a CID font | |
1413 | - if (!fdselectoff) return 0; | |
1414 | - stbtt__buf_seek(&b, fdarrayoff); | |
1415 | - info->fontdicts = stbtt__cff_get_index(&b); | |
1416 | - info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); | |
1417 | - } | |
1418 | - | |
1419 | - stbtt__buf_seek(&b, charstrings); | |
1420 | - info->charstrings = stbtt__cff_get_index(&b); | |
1421 | - } | |
1422 | - | |
1423 | - t = stbtt__find_table(data, fontstart, "maxp"); | |
1424 | - if (t) | |
1425 | - info->numGlyphs = ttUSHORT(data+t+4); | |
1426 | - else | |
1427 | - info->numGlyphs = 0xffff; | |
1428 | - | |
1429 | - // find a cmap encoding table we understand *now* to avoid searching | |
1430 | - // later. (todo: could make this installable) | |
1431 | - // the same regardless of glyph. | |
1432 | - numTables = ttUSHORT(data + cmap + 2); | |
1433 | - info->index_map = 0; | |
1434 | - for (i=0; i < numTables; ++i) { | |
1435 | - stbtt_uint32 encoding_record = cmap + 4 + 8 * i; | |
1436 | - // find an encoding we understand: | |
1437 | - switch(ttUSHORT(data+encoding_record)) { | |
1438 | - case STBTT_PLATFORM_ID_MICROSOFT: | |
1439 | - switch (ttUSHORT(data+encoding_record+2)) { | |
1440 | - case STBTT_MS_EID_UNICODE_BMP: | |
1441 | - case STBTT_MS_EID_UNICODE_FULL: | |
1442 | - // MS/Unicode | |
1443 | - info->index_map = cmap + ttULONG(data+encoding_record+4); | |
1444 | - break; | |
1445 | - } | |
1446 | - break; | |
1447 | - case STBTT_PLATFORM_ID_UNICODE: | |
1448 | - // Mac/iOS has these | |
1449 | - // all the encodingIDs are unicode, so we don't bother to check it | |
1450 | - info->index_map = cmap + ttULONG(data+encoding_record+4); | |
1451 | - break; | |
1452 | - } | |
1453 | - } | |
1454 | - if (info->index_map == 0) | |
1455 | - return 0; | |
1456 | - | |
1457 | - info->indexToLocFormat = ttUSHORT(data+info->head + 50); | |
1458 | - return 1; | |
1459 | -} | |
1460 | - | |
1461 | -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) | |
1462 | -{ | |
1463 | - stbtt_uint8 *data = info->data; | |
1464 | - stbtt_uint32 index_map = info->index_map; | |
1465 | - | |
1466 | - stbtt_uint16 format = ttUSHORT(data + index_map + 0); | |
1467 | - if (format == 0) { // apple byte encoding | |
1468 | - stbtt_int32 bytes = ttUSHORT(data + index_map + 2); | |
1469 | - if (unicode_codepoint < bytes-6) | |
1470 | - return ttBYTE(data + index_map + 6 + unicode_codepoint); | |
1471 | - return 0; | |
1472 | - } else if (format == 6) { | |
1473 | - stbtt_uint32 first = ttUSHORT(data + index_map + 6); | |
1474 | - stbtt_uint32 count = ttUSHORT(data + index_map + 8); | |
1475 | - if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) | |
1476 | - return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); | |
1477 | - return 0; | |
1478 | - } else if (format == 2) { | |
1479 | - STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean | |
1480 | - return 0; | |
1481 | - } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges | |
1482 | - stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; | |
1483 | - stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; | |
1484 | - stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); | |
1485 | - stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; | |
1486 | - | |
1487 | - // do a binary search of the segments | |
1488 | - stbtt_uint32 endCount = index_map + 14; | |
1489 | - stbtt_uint32 search = endCount; | |
1490 | - | |
1491 | - if (unicode_codepoint > 0xffff) | |
1492 | - return 0; | |
1493 | - | |
1494 | - // they lie from endCount .. endCount + segCount | |
1495 | - // but searchRange is the nearest power of two, so... | |
1496 | - if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) | |
1497 | - search += rangeShift*2; | |
1498 | - | |
1499 | - // now decrement to bias correctly to find smallest | |
1500 | - search -= 2; | |
1501 | - while (entrySelector) { | |
1502 | - stbtt_uint16 end; | |
1503 | - searchRange >>= 1; | |
1504 | - end = ttUSHORT(data + search + searchRange*2); | |
1505 | - if (unicode_codepoint > end) | |
1506 | - search += searchRange*2; | |
1507 | - --entrySelector; | |
1508 | - } | |
1509 | - search += 2; | |
1510 | - | |
1511 | - { | |
1512 | - stbtt_uint16 offset, start; | |
1513 | - stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); | |
1514 | - | |
1515 | - STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); | |
1516 | - start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); | |
1517 | - if (unicode_codepoint < start) | |
1518 | - return 0; | |
1519 | - | |
1520 | - offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); | |
1521 | - if (offset == 0) | |
1522 | - return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); | |
1523 | - | |
1524 | - return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); | |
1525 | - } | |
1526 | - } else if (format == 12 || format == 13) { | |
1527 | - stbtt_uint32 ngroups = ttULONG(data+index_map+12); | |
1528 | - stbtt_int32 low,high; | |
1529 | - low = 0; high = (stbtt_int32)ngroups; | |
1530 | - // Binary search the right group. | |
1531 | - while (low < high) { | |
1532 | - stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high | |
1533 | - stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); | |
1534 | - stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); | |
1535 | - if ((stbtt_uint32) unicode_codepoint < start_char) | |
1536 | - high = mid; | |
1537 | - else if ((stbtt_uint32) unicode_codepoint > end_char) | |
1538 | - low = mid+1; | |
1539 | - else { | |
1540 | - stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); | |
1541 | - if (format == 12) | |
1542 | - return start_glyph + unicode_codepoint-start_char; | |
1543 | - else // format == 13 | |
1544 | - return start_glyph; | |
1545 | - } | |
1546 | - } | |
1547 | - return 0; // not found | |
1548 | - } | |
1549 | - // @TODO | |
1550 | - STBTT_assert(0); | |
1551 | - return 0; | |
1552 | -} | |
1553 | - | |
1554 | -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) | |
1555 | -{ | |
1556 | - return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); | |
1557 | -} | |
1558 | - | |
1559 | -static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) | |
1560 | -{ | |
1561 | - v->type = type; | |
1562 | - v->x = (stbtt_int16) x; | |
1563 | - v->y = (stbtt_int16) y; | |
1564 | - v->cx = (stbtt_int16) cx; | |
1565 | - v->cy = (stbtt_int16) cy; | |
1566 | -} | |
1567 | - | |
1568 | -static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) | |
1569 | -{ | |
1570 | - int g1,g2; | |
1571 | - | |
1572 | - STBTT_assert(!info->cff.size); | |
1573 | - | |
1574 | - if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range | |
1575 | - if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format | |
1576 | - | |
1577 | - if (info->indexToLocFormat == 0) { | |
1578 | - g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; | |
1579 | - g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; | |
1580 | - } else { | |
1581 | - g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); | |
1582 | - g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); | |
1583 | - } | |
1584 | - | |
1585 | - return g1==g2 ? -1 : g1; // if length is 0, return -1 | |
1586 | -} | |
1587 | - | |
1588 | -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); | |
1589 | - | |
1590 | -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) | |
1591 | -{ | |
1592 | - if (info->cff.size) { | |
1593 | - stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); | |
1594 | - } else { | |
1595 | - int g = stbtt__GetGlyfOffset(info, glyph_index); | |
1596 | - if (g < 0) return 0; | |
1597 | - | |
1598 | - if (x0) *x0 = ttSHORT(info->data + g + 2); | |
1599 | - if (y0) *y0 = ttSHORT(info->data + g + 4); | |
1600 | - if (x1) *x1 = ttSHORT(info->data + g + 6); | |
1601 | - if (y1) *y1 = ttSHORT(info->data + g + 8); | |
1602 | - } | |
1603 | - return 1; | |
1604 | -} | |
1605 | - | |
1606 | -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) | |
1607 | -{ | |
1608 | - return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); | |
1609 | -} | |
1610 | - | |
1611 | -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) | |
1612 | -{ | |
1613 | - stbtt_int16 numberOfContours; | |
1614 | - int g; | |
1615 | - if (info->cff.size) | |
1616 | - return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; | |
1617 | - g = stbtt__GetGlyfOffset(info, glyph_index); | |
1618 | - if (g < 0) return 1; | |
1619 | - numberOfContours = ttSHORT(info->data + g); | |
1620 | - return numberOfContours == 0; | |
1621 | -} | |
1622 | - | |
1623 | -static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, | |
1624 | - stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) | |
1625 | -{ | |
1626 | - if (start_off) { | |
1627 | - if (was_off) | |
1628 | - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); | |
1629 | - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); | |
1630 | - } else { | |
1631 | - if (was_off) | |
1632 | - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); | |
1633 | - else | |
1634 | - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); | |
1635 | - } | |
1636 | - return num_vertices; | |
1637 | -} | |
1638 | - | |
1639 | -static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) | |
1640 | -{ | |
1641 | - stbtt_int16 numberOfContours; | |
1642 | - stbtt_uint8 *endPtsOfContours; | |
1643 | - stbtt_uint8 *data = info->data; | |
1644 | - stbtt_vertex *vertices=0; | |
1645 | - int num_vertices=0; | |
1646 | - int g = stbtt__GetGlyfOffset(info, glyph_index); | |
1647 | - | |
1648 | - *pvertices = NULL; | |
1649 | - | |
1650 | - if (g < 0) return 0; | |
1651 | - | |
1652 | - numberOfContours = ttSHORT(data + g); | |
1653 | - | |
1654 | - if (numberOfContours > 0) { | |
1655 | - stbtt_uint8 flags=0,flagcount; | |
1656 | - stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; | |
1657 | - stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; | |
1658 | - stbtt_uint8 *points; | |
1659 | - endPtsOfContours = (data + g + 10); | |
1660 | - ins = ttUSHORT(data + g + 10 + numberOfContours * 2); | |
1661 | - points = data + g + 10 + numberOfContours * 2 + 2 + ins; | |
1662 | - | |
1663 | - n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); | |
1664 | - | |
1665 | - m = n + 2*numberOfContours; // a loose bound on how many vertices we might need | |
1666 | - vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); | |
1667 | - if (vertices == 0) | |
1668 | - return 0; | |
1669 | - | |
1670 | - next_move = 0; | |
1671 | - flagcount=0; | |
1672 | - | |
1673 | - // in first pass, we load uninterpreted data into the allocated array | |
1674 | - // above, shifted to the end of the array so we won't overwrite it when | |
1675 | - // we create our final data starting from the front | |
1676 | - | |
1677 | - off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated | |
1678 | - | |
1679 | - // first load flags | |
1680 | - | |
1681 | - for (i=0; i < n; ++i) { | |
1682 | - if (flagcount == 0) { | |
1683 | - flags = *points++; | |
1684 | - if (flags & 8) | |
1685 | - flagcount = *points++; | |
1686 | - } else | |
1687 | - --flagcount; | |
1688 | - vertices[off+i].type = flags; | |
1689 | - } | |
1690 | - | |
1691 | - // now load x coordinates | |
1692 | - x=0; | |
1693 | - for (i=0; i < n; ++i) { | |
1694 | - flags = vertices[off+i].type; | |
1695 | - if (flags & 2) { | |
1696 | - stbtt_int16 dx = *points++; | |
1697 | - x += (flags & 16) ? dx : -dx; // ??? | |
1698 | - } else { | |
1699 | - if (!(flags & 16)) { | |
1700 | - x = x + (stbtt_int16) (points[0]*256 + points[1]); | |
1701 | - points += 2; | |
1702 | - } | |
1703 | - } | |
1704 | - vertices[off+i].x = (stbtt_int16) x; | |
1705 | - } | |
1706 | - | |
1707 | - // now load y coordinates | |
1708 | - y=0; | |
1709 | - for (i=0; i < n; ++i) { | |
1710 | - flags = vertices[off+i].type; | |
1711 | - if (flags & 4) { | |
1712 | - stbtt_int16 dy = *points++; | |
1713 | - y += (flags & 32) ? dy : -dy; // ??? | |
1714 | - } else { | |
1715 | - if (!(flags & 32)) { | |
1716 | - y = y + (stbtt_int16) (points[0]*256 + points[1]); | |
1717 | - points += 2; | |
1718 | - } | |
1719 | - } | |
1720 | - vertices[off+i].y = (stbtt_int16) y; | |
1721 | - } | |
1722 | - | |
1723 | - // now convert them to our format | |
1724 | - num_vertices=0; | |
1725 | - sx = sy = cx = cy = scx = scy = 0; | |
1726 | - for (i=0; i < n; ++i) { | |
1727 | - flags = vertices[off+i].type; | |
1728 | - x = (stbtt_int16) vertices[off+i].x; | |
1729 | - y = (stbtt_int16) vertices[off+i].y; | |
1730 | - | |
1731 | - if (next_move == i) { | |
1732 | - if (i != 0) | |
1733 | - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); | |
1734 | - | |
1735 | - // now start the new one | |
1736 | - start_off = !(flags & 1); | |
1737 | - if (start_off) { | |
1738 | - // if we start off with an off-curve point, then when we need to find a point on the curve | |
1739 | - // where we can start, and we need to save some state for when we wraparound. | |
1740 | - scx = x; | |
1741 | - scy = y; | |
1742 | - if (!(vertices[off+i+1].type & 1)) { | |
1743 | - // next point is also a curve point, so interpolate an on-point curve | |
1744 | - sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; | |
1745 | - sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; | |
1746 | - } else { | |
1747 | - // otherwise just use the next point as our start point | |
1748 | - sx = (stbtt_int32) vertices[off+i+1].x; | |
1749 | - sy = (stbtt_int32) vertices[off+i+1].y; | |
1750 | - ++i; // we're using point i+1 as the starting point, so skip it | |
1751 | - } | |
1752 | - } else { | |
1753 | - sx = x; | |
1754 | - sy = y; | |
1755 | - } | |
1756 | - stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); | |
1757 | - was_off = 0; | |
1758 | - next_move = 1 + ttUSHORT(endPtsOfContours+j*2); | |
1759 | - ++j; | |
1760 | - } else { | |
1761 | - if (!(flags & 1)) { // if it's a curve | |
1762 | - if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint | |
1763 | - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); | |
1764 | - cx = x; | |
1765 | - cy = y; | |
1766 | - was_off = 1; | |
1767 | - } else { | |
1768 | - if (was_off) | |
1769 | - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); | |
1770 | - else | |
1771 | - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); | |
1772 | - was_off = 0; | |
1773 | - } | |
1774 | - } | |
1775 | - } | |
1776 | - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); | |
1777 | - } else if (numberOfContours == -1) { | |
1778 | - // Compound shapes. | |
1779 | - int more = 1; | |
1780 | - stbtt_uint8 *comp = data + g + 10; | |
1781 | - num_vertices = 0; | |
1782 | - vertices = 0; | |
1783 | - while (more) { | |
1784 | - stbtt_uint16 flags, gidx; | |
1785 | - int comp_num_verts = 0, i; | |
1786 | - stbtt_vertex *comp_verts = 0, *tmp = 0; | |
1787 | - float mtx[6] = {1,0,0,1,0,0}, m, n; | |
1788 | - | |
1789 | - flags = ttSHORT(comp); comp+=2; | |
1790 | - gidx = ttSHORT(comp); comp+=2; | |
1791 | - | |
1792 | - if (flags & 2) { // XY values | |
1793 | - if (flags & 1) { // shorts | |
1794 | - mtx[4] = ttSHORT(comp); comp+=2; | |
1795 | - mtx[5] = ttSHORT(comp); comp+=2; | |
1796 | - } else { | |
1797 | - mtx[4] = ttCHAR(comp); comp+=1; | |
1798 | - mtx[5] = ttCHAR(comp); comp+=1; | |
1799 | - } | |
1800 | - } | |
1801 | - else { | |
1802 | - // @TODO handle matching point | |
1803 | - STBTT_assert(0); | |
1804 | - } | |
1805 | - if (flags & (1<<3)) { // WE_HAVE_A_SCALE | |
1806 | - mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; | |
1807 | - mtx[1] = mtx[2] = 0; | |
1808 | - } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE | |
1809 | - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; | |
1810 | - mtx[1] = mtx[2] = 0; | |
1811 | - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; | |
1812 | - } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO | |
1813 | - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; | |
1814 | - mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; | |
1815 | - mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; | |
1816 | - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; | |
1817 | - } | |
1818 | - | |
1819 | - // Find transformation scales. | |
1820 | - m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); | |
1821 | - n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); | |
1822 | - | |
1823 | - // Get indexed glyph. | |
1824 | - comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); | |
1825 | - if (comp_num_verts > 0) { | |
1826 | - // Transform vertices. | |
1827 | - for (i = 0; i < comp_num_verts; ++i) { | |
1828 | - stbtt_vertex* v = &comp_verts[i]; | |
1829 | - stbtt_vertex_type x,y; | |
1830 | - x=v->x; y=v->y; | |
1831 | - v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); | |
1832 | - v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); | |
1833 | - x=v->cx; y=v->cy; | |
1834 | - v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); | |
1835 | - v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); | |
1836 | - } | |
1837 | - // Append vertices. | |
1838 | - tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); | |
1839 | - if (!tmp) { | |
1840 | - if (vertices) STBTT_free(vertices, info->userdata); | |
1841 | - if (comp_verts) STBTT_free(comp_verts, info->userdata); | |
1842 | - return 0; | |
1843 | - } | |
1844 | - if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595 | |
1845 | - STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); | |
1846 | - if (vertices) STBTT_free(vertices, info->userdata); | |
1847 | - vertices = tmp; | |
1848 | - STBTT_free(comp_verts, info->userdata); | |
1849 | - num_vertices += comp_num_verts; | |
1850 | - } | |
1851 | - // More components ? | |
1852 | - more = flags & (1<<5); | |
1853 | - } | |
1854 | - } else if (numberOfContours < 0) { | |
1855 | - // @TODO other compound variations? | |
1856 | - STBTT_assert(0); | |
1857 | - } else { | |
1858 | - // numberOfCounters == 0, do nothing | |
1859 | - } | |
1860 | - | |
1861 | - *pvertices = vertices; | |
1862 | - return num_vertices; | |
1863 | -} | |
1864 | - | |
1865 | -typedef struct | |
1866 | -{ | |
1867 | - int bounds; | |
1868 | - int started; | |
1869 | - float first_x, first_y; | |
1870 | - float x, y; | |
1871 | - stbtt_int32 min_x, max_x, min_y, max_y; | |
1872 | - | |
1873 | - stbtt_vertex *pvertices; | |
1874 | - int num_vertices; | |
1875 | -} stbtt__csctx; | |
1876 | - | |
1877 | -#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} | |
1878 | - | |
1879 | -static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) | |
1880 | -{ | |
1881 | - if (x > c->max_x || !c->started) c->max_x = x; | |
1882 | - if (y > c->max_y || !c->started) c->max_y = y; | |
1883 | - if (x < c->min_x || !c->started) c->min_x = x; | |
1884 | - if (y < c->min_y || !c->started) c->min_y = y; | |
1885 | - c->started = 1; | |
1886 | -} | |
1887 | - | |
1888 | -static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) | |
1889 | -{ | |
1890 | - if (c->bounds) { | |
1891 | - stbtt__track_vertex(c, x, y); | |
1892 | - if (type == STBTT_vcubic) { | |
1893 | - stbtt__track_vertex(c, cx, cy); | |
1894 | - stbtt__track_vertex(c, cx1, cy1); | |
1895 | - } | |
1896 | - } else { | |
1897 | - stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); | |
1898 | - c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; | |
1899 | - c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; | |
1900 | - } | |
1901 | - c->num_vertices++; | |
1902 | -} | |
1903 | - | |
1904 | -static void stbtt__csctx_close_shape(stbtt__csctx *ctx) | |
1905 | -{ | |
1906 | - if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) | |
1907 | - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); | |
1908 | -} | |
1909 | - | |
1910 | -static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) | |
1911 | -{ | |
1912 | - stbtt__csctx_close_shape(ctx); | |
1913 | - ctx->first_x = ctx->x = ctx->x + dx; | |
1914 | - ctx->first_y = ctx->y = ctx->y + dy; | |
1915 | - stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); | |
1916 | -} | |
1917 | - | |
1918 | -static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) | |
1919 | -{ | |
1920 | - ctx->x += dx; | |
1921 | - ctx->y += dy; | |
1922 | - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); | |
1923 | -} | |
1924 | - | |
1925 | -static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) | |
1926 | -{ | |
1927 | - float cx1 = ctx->x + dx1; | |
1928 | - float cy1 = ctx->y + dy1; | |
1929 | - float cx2 = cx1 + dx2; | |
1930 | - float cy2 = cy1 + dy2; | |
1931 | - ctx->x = cx2 + dx3; | |
1932 | - ctx->y = cy2 + dy3; | |
1933 | - stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); | |
1934 | -} | |
1935 | - | |
1936 | -static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) | |
1937 | -{ | |
1938 | - int count = stbtt__cff_index_count(&idx); | |
1939 | - int bias = 107; | |
1940 | - if (count >= 33900) | |
1941 | - bias = 32768; | |
1942 | - else if (count >= 1240) | |
1943 | - bias = 1131; | |
1944 | - n += bias; | |
1945 | - if (n < 0 || n >= count) | |
1946 | - return stbtt__new_buf(NULL, 0); | |
1947 | - return stbtt__cff_index_get(idx, n); | |
1948 | -} | |
1949 | - | |
1950 | -static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) | |
1951 | -{ | |
1952 | - stbtt__buf fdselect = info->fdselect; | |
1953 | - int nranges, start, end, v, fmt, fdselector = -1, i; | |
1954 | - | |
1955 | - stbtt__buf_seek(&fdselect, 0); | |
1956 | - fmt = stbtt__buf_get8(&fdselect); | |
1957 | - if (fmt == 0) { | |
1958 | - // untested | |
1959 | - stbtt__buf_skip(&fdselect, glyph_index); | |
1960 | - fdselector = stbtt__buf_get8(&fdselect); | |
1961 | - } else if (fmt == 3) { | |
1962 | - nranges = stbtt__buf_get16(&fdselect); | |
1963 | - start = stbtt__buf_get16(&fdselect); | |
1964 | - for (i = 0; i < nranges; i++) { | |
1965 | - v = stbtt__buf_get8(&fdselect); | |
1966 | - end = stbtt__buf_get16(&fdselect); | |
1967 | - if (glyph_index >= start && glyph_index < end) { | |
1968 | - fdselector = v; | |
1969 | - break; | |
1970 | - } | |
1971 | - start = end; | |
1972 | - } | |
1973 | - } | |
1974 | - if (fdselector == -1) stbtt__new_buf(NULL, 0); | |
1975 | - return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); | |
1976 | -} | |
1977 | - | |
1978 | -static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) | |
1979 | -{ | |
1980 | - int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; | |
1981 | - int has_subrs = 0, clear_stack; | |
1982 | - float s[48]; | |
1983 | - stbtt__buf subr_stack[10], subrs = info->subrs, b; | |
1984 | - float f; | |
1985 | - | |
1986 | -#define STBTT__CSERR(s) (0) | |
1987 | - | |
1988 | - // this currently ignores the initial width value, which isn't needed if we have hmtx | |
1989 | - b = stbtt__cff_index_get(info->charstrings, glyph_index); | |
1990 | - while (b.cursor < b.size) { | |
1991 | - i = 0; | |
1992 | - clear_stack = 1; | |
1993 | - b0 = stbtt__buf_get8(&b); | |
1994 | - switch (b0) { | |
1995 | - // @TODO implement hinting | |
1996 | - case 0x13: // hintmask | |
1997 | - case 0x14: // cntrmask | |
1998 | - if (in_header) | |
1999 | - maskbits += (sp / 2); // implicit "vstem" | |
2000 | - in_header = 0; | |
2001 | - stbtt__buf_skip(&b, (maskbits + 7) / 8); | |
2002 | - break; | |
2003 | - | |
2004 | - case 0x01: // hstem | |
2005 | - case 0x03: // vstem | |
2006 | - case 0x12: // hstemhm | |
2007 | - case 0x17: // vstemhm | |
2008 | - maskbits += (sp / 2); | |
2009 | - break; | |
2010 | - | |
2011 | - case 0x15: // rmoveto | |
2012 | - in_header = 0; | |
2013 | - if (sp < 2) return STBTT__CSERR("rmoveto stack"); | |
2014 | - stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); | |
2015 | - break; | |
2016 | - case 0x04: // vmoveto | |
2017 | - in_header = 0; | |
2018 | - if (sp < 1) return STBTT__CSERR("vmoveto stack"); | |
2019 | - stbtt__csctx_rmove_to(c, 0, s[sp-1]); | |
2020 | - break; | |
2021 | - case 0x16: // hmoveto | |
2022 | - in_header = 0; | |
2023 | - if (sp < 1) return STBTT__CSERR("hmoveto stack"); | |
2024 | - stbtt__csctx_rmove_to(c, s[sp-1], 0); | |
2025 | - break; | |
2026 | - | |
2027 | - case 0x05: // rlineto | |
2028 | - if (sp < 2) return STBTT__CSERR("rlineto stack"); | |
2029 | - for (; i + 1 < sp; i += 2) | |
2030 | - stbtt__csctx_rline_to(c, s[i], s[i+1]); | |
2031 | - break; | |
2032 | - | |
2033 | - // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical | |
2034 | - // starting from a different place. | |
2035 | - | |
2036 | - case 0x07: // vlineto | |
2037 | - if (sp < 1) return STBTT__CSERR("vlineto stack"); | |
2038 | - goto vlineto; | |
2039 | - case 0x06: // hlineto | |
2040 | - if (sp < 1) return STBTT__CSERR("hlineto stack"); | |
2041 | - for (;;) { | |
2042 | - if (i >= sp) break; | |
2043 | - stbtt__csctx_rline_to(c, s[i], 0); | |
2044 | - i++; | |
2045 | - vlineto: | |
2046 | - if (i >= sp) break; | |
2047 | - stbtt__csctx_rline_to(c, 0, s[i]); | |
2048 | - i++; | |
2049 | - } | |
2050 | - break; | |
2051 | - | |
2052 | - case 0x1F: // hvcurveto | |
2053 | - if (sp < 4) return STBTT__CSERR("hvcurveto stack"); | |
2054 | - goto hvcurveto; | |
2055 | - case 0x1E: // vhcurveto | |
2056 | - if (sp < 4) return STBTT__CSERR("vhcurveto stack"); | |
2057 | - for (;;) { | |
2058 | - if (i + 3 >= sp) break; | |
2059 | - stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); | |
2060 | - i += 4; | |
2061 | - hvcurveto: | |
2062 | - if (i + 3 >= sp) break; | |
2063 | - stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); | |
2064 | - i += 4; | |
2065 | - } | |
2066 | - break; | |
2067 | - | |
2068 | - case 0x08: // rrcurveto | |
2069 | - if (sp < 6) return STBTT__CSERR("rcurveline stack"); | |
2070 | - for (; i + 5 < sp; i += 6) | |
2071 | - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); | |
2072 | - break; | |
2073 | - | |
2074 | - case 0x18: // rcurveline | |
2075 | - if (sp < 8) return STBTT__CSERR("rcurveline stack"); | |
2076 | - for (; i + 5 < sp - 2; i += 6) | |
2077 | - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); | |
2078 | - if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); | |
2079 | - stbtt__csctx_rline_to(c, s[i], s[i+1]); | |
2080 | - break; | |
2081 | - | |
2082 | - case 0x19: // rlinecurve | |
2083 | - if (sp < 8) return STBTT__CSERR("rlinecurve stack"); | |
2084 | - for (; i + 1 < sp - 6; i += 2) | |
2085 | - stbtt__csctx_rline_to(c, s[i], s[i+1]); | |
2086 | - if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); | |
2087 | - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); | |
2088 | - break; | |
2089 | - | |
2090 | - case 0x1A: // vvcurveto | |
2091 | - case 0x1B: // hhcurveto | |
2092 | - if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); | |
2093 | - f = 0.0; | |
2094 | - if (sp & 1) { f = s[i]; i++; } | |
2095 | - for (; i + 3 < sp; i += 4) { | |
2096 | - if (b0 == 0x1B) | |
2097 | - stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); | |
2098 | - else | |
2099 | - stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); | |
2100 | - f = 0.0; | |
2101 | - } | |
2102 | - break; | |
2103 | - | |
2104 | - case 0x0A: // callsubr | |
2105 | - if (!has_subrs) { | |
2106 | - if (info->fdselect.size) | |
2107 | - subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); | |
2108 | - has_subrs = 1; | |
2109 | - } | |
2110 | - // fallthrough | |
2111 | - case 0x1D: // callgsubr | |
2112 | - if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); | |
2113 | - v = (int) s[--sp]; | |
2114 | - if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); | |
2115 | - subr_stack[subr_stack_height++] = b; | |
2116 | - b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); | |
2117 | - if (b.size == 0) return STBTT__CSERR("subr not found"); | |
2118 | - b.cursor = 0; | |
2119 | - clear_stack = 0; | |
2120 | - break; | |
2121 | - | |
2122 | - case 0x0B: // return | |
2123 | - if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); | |
2124 | - b = subr_stack[--subr_stack_height]; | |
2125 | - clear_stack = 0; | |
2126 | - break; | |
2127 | - | |
2128 | - case 0x0E: // endchar | |
2129 | - stbtt__csctx_close_shape(c); | |
2130 | - return 1; | |
2131 | - | |
2132 | - case 0x0C: { // two-byte escape | |
2133 | - float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; | |
2134 | - float dx, dy; | |
2135 | - int b1 = stbtt__buf_get8(&b); | |
2136 | - switch (b1) { | |
2137 | - // @TODO These "flex" implementations ignore the flex-depth and resolution, | |
2138 | - // and always draw beziers. | |
2139 | - case 0x22: // hflex | |
2140 | - if (sp < 7) return STBTT__CSERR("hflex stack"); | |
2141 | - dx1 = s[0]; | |
2142 | - dx2 = s[1]; | |
2143 | - dy2 = s[2]; | |
2144 | - dx3 = s[3]; | |
2145 | - dx4 = s[4]; | |
2146 | - dx5 = s[5]; | |
2147 | - dx6 = s[6]; | |
2148 | - stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); | |
2149 | - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); | |
2150 | - break; | |
2151 | - | |
2152 | - case 0x23: // flex | |
2153 | - if (sp < 13) return STBTT__CSERR("flex stack"); | |
2154 | - dx1 = s[0]; | |
2155 | - dy1 = s[1]; | |
2156 | - dx2 = s[2]; | |
2157 | - dy2 = s[3]; | |
2158 | - dx3 = s[4]; | |
2159 | - dy3 = s[5]; | |
2160 | - dx4 = s[6]; | |
2161 | - dy4 = s[7]; | |
2162 | - dx5 = s[8]; | |
2163 | - dy5 = s[9]; | |
2164 | - dx6 = s[10]; | |
2165 | - dy6 = s[11]; | |
2166 | - //fd is s[12] | |
2167 | - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); | |
2168 | - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); | |
2169 | - break; | |
2170 | - | |
2171 | - case 0x24: // hflex1 | |
2172 | - if (sp < 9) return STBTT__CSERR("hflex1 stack"); | |
2173 | - dx1 = s[0]; | |
2174 | - dy1 = s[1]; | |
2175 | - dx2 = s[2]; | |
2176 | - dy2 = s[3]; | |
2177 | - dx3 = s[4]; | |
2178 | - dx4 = s[5]; | |
2179 | - dx5 = s[6]; | |
2180 | - dy5 = s[7]; | |
2181 | - dx6 = s[8]; | |
2182 | - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); | |
2183 | - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); | |
2184 | - break; | |
2185 | - | |
2186 | - case 0x25: // flex1 | |
2187 | - if (sp < 11) return STBTT__CSERR("flex1 stack"); | |
2188 | - dx1 = s[0]; | |
2189 | - dy1 = s[1]; | |
2190 | - dx2 = s[2]; | |
2191 | - dy2 = s[3]; | |
2192 | - dx3 = s[4]; | |
2193 | - dy3 = s[5]; | |
2194 | - dx4 = s[6]; | |
2195 | - dy4 = s[7]; | |
2196 | - dx5 = s[8]; | |
2197 | - dy5 = s[9]; | |
2198 | - dx6 = dy6 = s[10]; | |
2199 | - dx = dx1+dx2+dx3+dx4+dx5; | |
2200 | - dy = dy1+dy2+dy3+dy4+dy5; | |
2201 | - if (STBTT_fabs(dx) > STBTT_fabs(dy)) | |
2202 | - dy6 = -dy; | |
2203 | - else | |
2204 | - dx6 = -dx; | |
2205 | - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); | |
2206 | - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); | |
2207 | - break; | |
2208 | - | |
2209 | - default: | |
2210 | - return STBTT__CSERR("unimplemented"); | |
2211 | - } | |
2212 | - } break; | |
2213 | - | |
2214 | - default: | |
2215 | - if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560 | |
2216 | - return STBTT__CSERR("reserved operator"); | |
2217 | - | |
2218 | - // push immediate | |
2219 | - if (b0 == 255) { | |
2220 | - f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; | |
2221 | - } else { | |
2222 | - stbtt__buf_skip(&b, -1); | |
2223 | - f = (float)(stbtt_int16)stbtt__cff_int(&b); | |
2224 | - } | |
2225 | - if (sp >= 48) return STBTT__CSERR("push stack overflow"); | |
2226 | - s[sp++] = f; | |
2227 | - clear_stack = 0; | |
2228 | - break; | |
2229 | - } | |
2230 | - if (clear_stack) sp = 0; | |
2231 | - } | |
2232 | - return STBTT__CSERR("no endchar"); | |
2233 | - | |
2234 | -#undef STBTT__CSERR | |
2235 | -} | |
2236 | - | |
2237 | -static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) | |
2238 | -{ | |
2239 | - // runs the charstring twice, once to count and once to output (to avoid realloc) | |
2240 | - stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); | |
2241 | - stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); | |
2242 | - if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { | |
2243 | - *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); | |
2244 | - output_ctx.pvertices = *pvertices; | |
2245 | - if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { | |
2246 | - STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); | |
2247 | - return output_ctx.num_vertices; | |
2248 | - } | |
2249 | - } | |
2250 | - *pvertices = NULL; | |
2251 | - return 0; | |
2252 | -} | |
2253 | - | |
2254 | -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) | |
2255 | -{ | |
2256 | - stbtt__csctx c = STBTT__CSCTX_INIT(1); | |
2257 | - int r = stbtt__run_charstring(info, glyph_index, &c); | |
2258 | - if (x0) *x0 = r ? c.min_x : 0; | |
2259 | - if (y0) *y0 = r ? c.min_y : 0; | |
2260 | - if (x1) *x1 = r ? c.max_x : 0; | |
2261 | - if (y1) *y1 = r ? c.max_y : 0; | |
2262 | - return r ? c.num_vertices : 0; | |
2263 | -} | |
2264 | - | |
2265 | -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) | |
2266 | -{ | |
2267 | - if (!info->cff.size) | |
2268 | - return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); | |
2269 | - else | |
2270 | - return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); | |
2271 | -} | |
2272 | - | |
2273 | -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) | |
2274 | -{ | |
2275 | - stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); | |
2276 | - if (glyph_index < numOfLongHorMetrics) { | |
2277 | - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); | |
2278 | - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); | |
2279 | - } else { | |
2280 | - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); | |
2281 | - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); | |
2282 | - } | |
2283 | -} | |
2284 | - | |
2285 | -static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) | |
2286 | -{ | |
2287 | - stbtt_uint8 *data = info->data + info->kern; | |
2288 | - stbtt_uint32 needle, straw; | |
2289 | - int l, r, m; | |
2290 | - | |
2291 | - // we only look at the first table. it must be 'horizontal' and format 0. | |
2292 | - if (!info->kern) | |
2293 | - return 0; | |
2294 | - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 | |
2295 | - return 0; | |
2296 | - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format | |
2297 | - return 0; | |
2298 | - | |
2299 | - l = 0; | |
2300 | - r = ttUSHORT(data+10) - 1; | |
2301 | - needle = glyph1 << 16 | glyph2; | |
2302 | - while (l <= r) { | |
2303 | - m = (l + r) >> 1; | |
2304 | - straw = ttULONG(data+18+(m*6)); // note: unaligned read | |
2305 | - if (needle < straw) | |
2306 | - r = m - 1; | |
2307 | - else if (needle > straw) | |
2308 | - l = m + 1; | |
2309 | - else | |
2310 | - return ttSHORT(data+22+(m*6)); | |
2311 | - } | |
2312 | - return 0; | |
2313 | -} | |
2314 | - | |
2315 | -static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) | |
2316 | -{ | |
2317 | - stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); | |
2318 | - switch(coverageFormat) { | |
2319 | - case 1: { | |
2320 | - stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); | |
2321 | - | |
2322 | - // Binary search. | |
2323 | - stbtt_int32 l=0, r=glyphCount-1, m; | |
2324 | - int straw, needle=glyph; | |
2325 | - while (l <= r) { | |
2326 | - stbtt_uint8 *glyphArray = coverageTable + 4; | |
2327 | - stbtt_uint16 glyphID; | |
2328 | - m = (l + r) >> 1; | |
2329 | - glyphID = ttUSHORT(glyphArray + 2 * m); | |
2330 | - straw = glyphID; | |
2331 | - if (needle < straw) | |
2332 | - r = m - 1; | |
2333 | - else if (needle > straw) | |
2334 | - l = m + 1; | |
2335 | - else { | |
2336 | - return m; | |
2337 | - } | |
2338 | - } | |
2339 | - } break; | |
2340 | - | |
2341 | - case 2: { | |
2342 | - stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); | |
2343 | - stbtt_uint8 *rangeArray = coverageTable + 4; | |
2344 | - | |
2345 | - // Binary search. | |
2346 | - stbtt_int32 l=0, r=rangeCount-1, m; | |
2347 | - int strawStart, strawEnd, needle=glyph; | |
2348 | - while (l <= r) { | |
2349 | - stbtt_uint8 *rangeRecord; | |
2350 | - m = (l + r) >> 1; | |
2351 | - rangeRecord = rangeArray + 6 * m; | |
2352 | - strawStart = ttUSHORT(rangeRecord); | |
2353 | - strawEnd = ttUSHORT(rangeRecord + 2); | |
2354 | - if (needle < strawStart) | |
2355 | - r = m - 1; | |
2356 | - else if (needle > strawEnd) | |
2357 | - l = m + 1; | |
2358 | - else { | |
2359 | - stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); | |
2360 | - return startCoverageIndex + glyph - strawStart; | |
2361 | - } | |
2362 | - } | |
2363 | - } break; | |
2364 | - | |
2365 | - default: { | |
2366 | - // There are no other cases. | |
2367 | - STBTT_assert(0); | |
2368 | - } break; | |
2369 | - } | |
2370 | - | |
2371 | - return -1; | |
2372 | -} | |
2373 | - | |
2374 | -static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) | |
2375 | -{ | |
2376 | - stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); | |
2377 | - switch(classDefFormat) | |
2378 | - { | |
2379 | - case 1: { | |
2380 | - stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); | |
2381 | - stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); | |
2382 | - stbtt_uint8 *classDef1ValueArray = classDefTable + 6; | |
2383 | - | |
2384 | - if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) | |
2385 | - return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); | |
2386 | - | |
2387 | - // [DEAR IMGUI] Commented to fix static analyzer warning | |
2388 | - //classDefTable = classDef1ValueArray + 2 * glyphCount; | |
2389 | - } break; | |
2390 | - | |
2391 | - case 2: { | |
2392 | - stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); | |
2393 | - stbtt_uint8 *classRangeRecords = classDefTable + 4; | |
2394 | - | |
2395 | - // Binary search. | |
2396 | - stbtt_int32 l=0, r=classRangeCount-1, m; | |
2397 | - int strawStart, strawEnd, needle=glyph; | |
2398 | - while (l <= r) { | |
2399 | - stbtt_uint8 *classRangeRecord; | |
2400 | - m = (l + r) >> 1; | |
2401 | - classRangeRecord = classRangeRecords + 6 * m; | |
2402 | - strawStart = ttUSHORT(classRangeRecord); | |
2403 | - strawEnd = ttUSHORT(classRangeRecord + 2); | |
2404 | - if (needle < strawStart) | |
2405 | - r = m - 1; | |
2406 | - else if (needle > strawEnd) | |
2407 | - l = m + 1; | |
2408 | - else | |
2409 | - return (stbtt_int32)ttUSHORT(classRangeRecord + 4); | |
2410 | - } | |
2411 | - | |
2412 | - // [DEAR IMGUI] Commented to fix static analyzer warning | |
2413 | - //classDefTable = classRangeRecords + 6 * classRangeCount; | |
2414 | - } break; | |
2415 | - | |
2416 | - default: { | |
2417 | - // There are no other cases. | |
2418 | - STBTT_assert(0); | |
2419 | - } break; | |
2420 | - } | |
2421 | - | |
2422 | - return -1; | |
2423 | -} | |
2424 | - | |
2425 | -// Define to STBTT_assert(x) if you want to break on unimplemented formats. | |
2426 | -#define STBTT_GPOS_TODO_assert(x) | |
2427 | - | |
2428 | -static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) | |
2429 | -{ | |
2430 | - stbtt_uint16 lookupListOffset; | |
2431 | - stbtt_uint8 *lookupList; | |
2432 | - stbtt_uint16 lookupCount; | |
2433 | - stbtt_uint8 *data; | |
2434 | - stbtt_int32 i; | |
2435 | - | |
2436 | - if (!info->gpos) return 0; | |
2437 | - | |
2438 | - data = info->data + info->gpos; | |
2439 | - | |
2440 | - if (ttUSHORT(data+0) != 1) return 0; // Major version 1 | |
2441 | - if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 | |
2442 | - | |
2443 | - lookupListOffset = ttUSHORT(data+8); | |
2444 | - lookupList = data + lookupListOffset; | |
2445 | - lookupCount = ttUSHORT(lookupList); | |
2446 | - | |
2447 | - for (i=0; i<lookupCount; ++i) { | |
2448 | - stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i); | |
2449 | - stbtt_uint8 *lookupTable = lookupList + lookupOffset; | |
2450 | - | |
2451 | - stbtt_uint16 lookupType = ttUSHORT(lookupTable); | |
2452 | - stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4); | |
2453 | - stbtt_uint8 *subTableOffsets = lookupTable + 6; | |
2454 | - switch(lookupType) { | |
2455 | - case 2: { // Pair Adjustment Positioning Subtable | |
2456 | - stbtt_int32 sti; | |
2457 | - for (sti=0; sti<subTableCount; sti++) { | |
2458 | - stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti); | |
2459 | - stbtt_uint8 *table = lookupTable + subtableOffset; | |
2460 | - stbtt_uint16 posFormat = ttUSHORT(table); | |
2461 | - stbtt_uint16 coverageOffset = ttUSHORT(table + 2); | |
2462 | - stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1); | |
2463 | - if (coverageIndex == -1) continue; | |
2464 | - | |
2465 | - switch (posFormat) { | |
2466 | - case 1: { | |
2467 | - stbtt_int32 l, r, m; | |
2468 | - int straw, needle; | |
2469 | - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); | |
2470 | - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); | |
2471 | - stbtt_int32 valueRecordPairSizeInBytes = 2; | |
2472 | - stbtt_uint16 pairSetCount = ttUSHORT(table + 8); | |
2473 | - stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); | |
2474 | - stbtt_uint8 *pairValueTable = table + pairPosOffset; | |
2475 | - stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); | |
2476 | - stbtt_uint8 *pairValueArray = pairValueTable + 2; | |
2477 | - // TODO: Support more formats. | |
2478 | - STBTT_GPOS_TODO_assert(valueFormat1 == 4); | |
2479 | - if (valueFormat1 != 4) return 0; | |
2480 | - STBTT_GPOS_TODO_assert(valueFormat2 == 0); | |
2481 | - if (valueFormat2 != 0) return 0; | |
2482 | - | |
2483 | - STBTT_assert(coverageIndex < pairSetCount); | |
2484 | - STBTT__NOTUSED(pairSetCount); | |
2485 | - | |
2486 | - needle=glyph2; | |
2487 | - r=pairValueCount-1; | |
2488 | - l=0; | |
2489 | - | |
2490 | - // Binary search. | |
2491 | - while (l <= r) { | |
2492 | - stbtt_uint16 secondGlyph; | |
2493 | - stbtt_uint8 *pairValue; | |
2494 | - m = (l + r) >> 1; | |
2495 | - pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; | |
2496 | - secondGlyph = ttUSHORT(pairValue); | |
2497 | - straw = secondGlyph; | |
2498 | - if (needle < straw) | |
2499 | - r = m - 1; | |
2500 | - else if (needle > straw) | |
2501 | - l = m + 1; | |
2502 | - else { | |
2503 | - stbtt_int16 xAdvance = ttSHORT(pairValue + 2); | |
2504 | - return xAdvance; | |
2505 | - } | |
2506 | - } | |
2507 | - } break; | |
2508 | - | |
2509 | - case 2: { | |
2510 | - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); | |
2511 | - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); | |
2512 | - | |
2513 | - stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); | |
2514 | - stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); | |
2515 | - int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); | |
2516 | - int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); | |
2517 | - | |
2518 | - stbtt_uint16 class1Count = ttUSHORT(table + 12); | |
2519 | - stbtt_uint16 class2Count = ttUSHORT(table + 14); | |
2520 | - STBTT_assert(glyph1class < class1Count); | |
2521 | - STBTT_assert(glyph2class < class2Count); | |
2522 | - | |
2523 | - // TODO: Support more formats. | |
2524 | - STBTT_GPOS_TODO_assert(valueFormat1 == 4); | |
2525 | - if (valueFormat1 != 4) return 0; | |
2526 | - STBTT_GPOS_TODO_assert(valueFormat2 == 0); | |
2527 | - if (valueFormat2 != 0) return 0; | |
2528 | - | |
2529 | - if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { | |
2530 | - stbtt_uint8 *class1Records = table + 16; | |
2531 | - stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); | |
2532 | - stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); | |
2533 | - return xAdvance; | |
2534 | - } | |
2535 | - } break; | |
2536 | - | |
2537 | - default: { | |
2538 | - // There are no other cases. | |
2539 | - STBTT_assert(0); | |
2540 | - break; | |
2541 | - }; | |
2542 | - } | |
2543 | - } | |
2544 | - break; | |
2545 | - }; | |
2546 | - | |
2547 | - default: | |
2548 | - // TODO: Implement other stuff. | |
2549 | - break; | |
2550 | - } | |
2551 | - } | |
2552 | - | |
2553 | - return 0; | |
2554 | -} | |
2555 | - | |
2556 | -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) | |
2557 | -{ | |
2558 | - int xAdvance = 0; | |
2559 | - | |
2560 | - if (info->gpos) | |
2561 | - xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); | |
2562 | - | |
2563 | - if (info->kern) | |
2564 | - xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); | |
2565 | - | |
2566 | - return xAdvance; | |
2567 | -} | |
2568 | - | |
2569 | -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) | |
2570 | -{ | |
2571 | - if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs | |
2572 | - return 0; | |
2573 | - return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); | |
2574 | -} | |
2575 | - | |
2576 | -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) | |
2577 | -{ | |
2578 | - stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); | |
2579 | -} | |
2580 | - | |
2581 | -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) | |
2582 | -{ | |
2583 | - if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); | |
2584 | - if (descent) *descent = ttSHORT(info->data+info->hhea + 6); | |
2585 | - if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); | |
2586 | -} | |
2587 | - | |
2588 | -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) | |
2589 | -{ | |
2590 | - int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); | |
2591 | - if (!tab) | |
2592 | - return 0; | |
2593 | - if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); | |
2594 | - if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); | |
2595 | - if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); | |
2596 | - return 1; | |
2597 | -} | |
2598 | - | |
2599 | -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) | |
2600 | -{ | |
2601 | - *x0 = ttSHORT(info->data + info->head + 36); | |
2602 | - *y0 = ttSHORT(info->data + info->head + 38); | |
2603 | - *x1 = ttSHORT(info->data + info->head + 40); | |
2604 | - *y1 = ttSHORT(info->data + info->head + 42); | |
2605 | -} | |
2606 | - | |
2607 | -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) | |
2608 | -{ | |
2609 | - int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); | |
2610 | - return (float) height / fheight; | |
2611 | -} | |
2612 | - | |
2613 | -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) | |
2614 | -{ | |
2615 | - int unitsPerEm = ttUSHORT(info->data + info->head + 18); | |
2616 | - return pixels / unitsPerEm; | |
2617 | -} | |
2618 | - | |
2619 | -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) | |
2620 | -{ | |
2621 | - STBTT_free(v, info->userdata); | |
2622 | -} | |
2623 | - | |
2624 | -////////////////////////////////////////////////////////////////////////////// | |
2625 | -// | |
2626 | -// antialiasing software rasterizer | |
2627 | -// | |
2628 | - | |
2629 | -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) | |
2630 | -{ | |
2631 | - int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning | |
2632 | - if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { | |
2633 | - // e.g. space character | |
2634 | - if (ix0) *ix0 = 0; | |
2635 | - if (iy0) *iy0 = 0; | |
2636 | - if (ix1) *ix1 = 0; | |
2637 | - if (iy1) *iy1 = 0; | |
2638 | - } else { | |
2639 | - // move to integral bboxes (treating pixels as little squares, what pixels get touched)? | |
2640 | - if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); | |
2641 | - if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); | |
2642 | - if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); | |
2643 | - if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); | |
2644 | - } | |
2645 | -} | |
2646 | - | |
2647 | -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) | |
2648 | -{ | |
2649 | - stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); | |
2650 | -} | |
2651 | - | |
2652 | -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) | |
2653 | -{ | |
2654 | - stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); | |
2655 | -} | |
2656 | - | |
2657 | -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) | |
2658 | -{ | |
2659 | - stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); | |
2660 | -} | |
2661 | - | |
2662 | -////////////////////////////////////////////////////////////////////////////// | |
2663 | -// | |
2664 | -// Rasterizer | |
2665 | - | |
2666 | -typedef struct stbtt__hheap_chunk | |
2667 | -{ | |
2668 | - struct stbtt__hheap_chunk *next; | |
2669 | -} stbtt__hheap_chunk; | |
2670 | - | |
2671 | -typedef struct stbtt__hheap | |
2672 | -{ | |
2673 | - struct stbtt__hheap_chunk *head; | |
2674 | - void *first_free; | |
2675 | - int num_remaining_in_head_chunk; | |
2676 | -} stbtt__hheap; | |
2677 | - | |
2678 | -static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) | |
2679 | -{ | |
2680 | - if (hh->first_free) { | |
2681 | - void *p = hh->first_free; | |
2682 | - hh->first_free = * (void **) p; | |
2683 | - return p; | |
2684 | - } else { | |
2685 | - if (hh->num_remaining_in_head_chunk == 0) { | |
2686 | - int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); | |
2687 | - stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); | |
2688 | - if (c == NULL) | |
2689 | - return NULL; | |
2690 | - c->next = hh->head; | |
2691 | - hh->head = c; | |
2692 | - hh->num_remaining_in_head_chunk = count; | |
2693 | - } | |
2694 | - --hh->num_remaining_in_head_chunk; | |
2695 | - return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; | |
2696 | - } | |
2697 | -} | |
2698 | - | |
2699 | -static void stbtt__hheap_free(stbtt__hheap *hh, void *p) | |
2700 | -{ | |
2701 | - *(void **) p = hh->first_free; | |
2702 | - hh->first_free = p; | |
2703 | -} | |
2704 | - | |
2705 | -static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) | |
2706 | -{ | |
2707 | - stbtt__hheap_chunk *c = hh->head; | |
2708 | - while (c) { | |
2709 | - stbtt__hheap_chunk *n = c->next; | |
2710 | - STBTT_free(c, userdata); | |
2711 | - c = n; | |
2712 | - } | |
2713 | -} | |
2714 | - | |
2715 | -typedef struct stbtt__edge { | |
2716 | - float x0,y0, x1,y1; | |
2717 | - int invert; | |
2718 | -} stbtt__edge; | |
2719 | - | |
2720 | - | |
2721 | -typedef struct stbtt__active_edge | |
2722 | -{ | |
2723 | - struct stbtt__active_edge *next; | |
2724 | - #if STBTT_RASTERIZER_VERSION==1 | |
2725 | - int x,dx; | |
2726 | - float ey; | |
2727 | - int direction; | |
2728 | - #elif STBTT_RASTERIZER_VERSION==2 | |
2729 | - float fx,fdx,fdy; | |
2730 | - float direction; | |
2731 | - float sy; | |
2732 | - float ey; | |
2733 | - #else | |
2734 | - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" | |
2735 | - #endif | |
2736 | -} stbtt__active_edge; | |
2737 | - | |
2738 | -#if STBTT_RASTERIZER_VERSION == 1 | |
2739 | -#define STBTT_FIXSHIFT 10 | |
2740 | -#define STBTT_FIX (1 << STBTT_FIXSHIFT) | |
2741 | -#define STBTT_FIXMASK (STBTT_FIX-1) | |
2742 | - | |
2743 | -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) | |
2744 | -{ | |
2745 | - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); | |
2746 | - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); | |
2747 | - STBTT_assert(z != NULL); | |
2748 | - if (!z) return z; | |
2749 | - | |
2750 | - // round dx down to avoid overshooting | |
2751 | - if (dxdy < 0) | |
2752 | - z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); | |
2753 | - else | |
2754 | - z->dx = STBTT_ifloor(STBTT_FIX * dxdy); | |
2755 | - | |
2756 | - 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 | |
2757 | - z->x -= off_x * STBTT_FIX; | |
2758 | - | |
2759 | - z->ey = e->y1; | |
2760 | - z->next = 0; | |
2761 | - z->direction = e->invert ? 1 : -1; | |
2762 | - return z; | |
2763 | -} | |
2764 | -#elif STBTT_RASTERIZER_VERSION == 2 | |
2765 | -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) | |
2766 | -{ | |
2767 | - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); | |
2768 | - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); | |
2769 | - STBTT_assert(z != NULL); | |
2770 | - //STBTT_assert(e->y0 <= start_point); | |
2771 | - if (!z) return z; | |
2772 | - z->fdx = dxdy; | |
2773 | - z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; | |
2774 | - z->fx = e->x0 + dxdy * (start_point - e->y0); | |
2775 | - z->fx -= off_x; | |
2776 | - z->direction = e->invert ? 1.0f : -1.0f; | |
2777 | - z->sy = e->y0; | |
2778 | - z->ey = e->y1; | |
2779 | - z->next = 0; | |
2780 | - return z; | |
2781 | -} | |
2782 | -#else | |
2783 | -#error "Unrecognized value of STBTT_RASTERIZER_VERSION" | |
2784 | -#endif | |
2785 | - | |
2786 | -#if STBTT_RASTERIZER_VERSION == 1 | |
2787 | -// note: this routine clips fills that extend off the edges... ideally this | |
2788 | -// wouldn't happen, but it could happen if the truetype glyph bounding boxes | |
2789 | -// are wrong, or if the user supplies a too-small bitmap | |
2790 | -static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) | |
2791 | -{ | |
2792 | - // non-zero winding fill | |
2793 | - int x0=0, w=0; | |
2794 | - | |
2795 | - while (e) { | |
2796 | - if (w == 0) { | |
2797 | - // if we're currently at zero, we need to record the edge start point | |
2798 | - x0 = e->x; w += e->direction; | |
2799 | - } else { | |
2800 | - int x1 = e->x; w += e->direction; | |
2801 | - // if we went to zero, we need to draw | |
2802 | - if (w == 0) { | |
2803 | - int i = x0 >> STBTT_FIXSHIFT; | |
2804 | - int j = x1 >> STBTT_FIXSHIFT; | |
2805 | - | |
2806 | - if (i < len && j >= 0) { | |
2807 | - if (i == j) { | |
2808 | - // x0,x1 are the same pixel, so compute combined coverage | |
2809 | - scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); | |
2810 | - } else { | |
2811 | - if (i >= 0) // add antialiasing for x0 | |
2812 | - scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); | |
2813 | - else | |
2814 | - i = -1; // clip | |
2815 | - | |
2816 | - if (j < len) // add antialiasing for x1 | |
2817 | - scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); | |
2818 | - else | |
2819 | - j = len; // clip | |
2820 | - | |
2821 | - for (++i; i < j; ++i) // fill pixels between x0 and x1 | |
2822 | - scanline[i] = scanline[i] + (stbtt_uint8) max_weight; | |
2823 | - } | |
2824 | - } | |
2825 | - } | |
2826 | - } | |
2827 | - | |
2828 | - e = e->next; | |
2829 | - } | |
2830 | -} | |
2831 | - | |
2832 | -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) | |
2833 | -{ | |
2834 | - stbtt__hheap hh = { 0, 0, 0 }; | |
2835 | - stbtt__active_edge *active = NULL; | |
2836 | - int y,j=0; | |
2837 | - int max_weight = (255 / vsubsample); // weight per vertical scanline | |
2838 | - int s; // vertical subsample index | |
2839 | - unsigned char scanline_data[512], *scanline; | |
2840 | - | |
2841 | - if (result->w > 512) | |
2842 | - scanline = (unsigned char *) STBTT_malloc(result->w, userdata); | |
2843 | - else | |
2844 | - scanline = scanline_data; | |
2845 | - | |
2846 | - y = off_y * vsubsample; | |
2847 | - e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; | |
2848 | - | |
2849 | - while (j < result->h) { | |
2850 | - STBTT_memset(scanline, 0, result->w); | |
2851 | - for (s=0; s < vsubsample; ++s) { | |
2852 | - // find center of pixel for this scanline | |
2853 | - float scan_y = y + 0.5f; | |
2854 | - stbtt__active_edge **step = &active; | |
2855 | - | |
2856 | - // update all active edges; | |
2857 | - // remove all active edges that terminate before the center of this scanline | |
2858 | - while (*step) { | |
2859 | - stbtt__active_edge * z = *step; | |
2860 | - if (z->ey <= scan_y) { | |
2861 | - *step = z->next; // delete from list | |
2862 | - STBTT_assert(z->direction); | |
2863 | - z->direction = 0; | |
2864 | - stbtt__hheap_free(&hh, z); | |
2865 | - } else { | |
2866 | - z->x += z->dx; // advance to position for current scanline | |
2867 | - step = &((*step)->next); // advance through list | |
2868 | - } | |
2869 | - } | |
2870 | - | |
2871 | - // resort the list if needed | |
2872 | - for(;;) { | |
2873 | - int changed=0; | |
2874 | - step = &active; | |
2875 | - while (*step && (*step)->next) { | |
2876 | - if ((*step)->x > (*step)->next->x) { | |
2877 | - stbtt__active_edge *t = *step; | |
2878 | - stbtt__active_edge *q = t->next; | |
2879 | - | |
2880 | - t->next = q->next; | |
2881 | - q->next = t; | |
2882 | - *step = q; | |
2883 | - changed = 1; | |
2884 | - } | |
2885 | - step = &(*step)->next; | |
2886 | - } | |
2887 | - if (!changed) break; | |
2888 | - } | |
2889 | - | |
2890 | - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline | |
2891 | - while (e->y0 <= scan_y) { | |
2892 | - if (e->y1 > scan_y) { | |
2893 | - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); | |
2894 | - if (z != NULL) { | |
2895 | - // find insertion point | |
2896 | - if (active == NULL) | |
2897 | - active = z; | |
2898 | - else if (z->x < active->x) { | |
2899 | - // insert at front | |
2900 | - z->next = active; | |
2901 | - active = z; | |
2902 | - } else { | |
2903 | - // find thing to insert AFTER | |
2904 | - stbtt__active_edge *p = active; | |
2905 | - while (p->next && p->next->x < z->x) | |
2906 | - p = p->next; | |
2907 | - // at this point, p->next->x is NOT < z->x | |
2908 | - z->next = p->next; | |
2909 | - p->next = z; | |
2910 | - } | |
2911 | - } | |
2912 | - } | |
2913 | - ++e; | |
2914 | - } | |
2915 | - | |
2916 | - // now process all active edges in XOR fashion | |
2917 | - if (active) | |
2918 | - stbtt__fill_active_edges(scanline, result->w, active, max_weight); | |
2919 | - | |
2920 | - ++y; | |
2921 | - } | |
2922 | - STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); | |
2923 | - ++j; | |
2924 | - } | |
2925 | - | |
2926 | - stbtt__hheap_cleanup(&hh, userdata); | |
2927 | - | |
2928 | - if (scanline != scanline_data) | |
2929 | - STBTT_free(scanline, userdata); | |
2930 | -} | |
2931 | - | |
2932 | -#elif STBTT_RASTERIZER_VERSION == 2 | |
2933 | - | |
2934 | -// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 | |
2935 | -// (i.e. it has already been clipped to those) | |
2936 | -static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) | |
2937 | -{ | |
2938 | - if (y0 == y1) return; | |
2939 | - STBTT_assert(y0 < y1); | |
2940 | - STBTT_assert(e->sy <= e->ey); | |
2941 | - if (y0 > e->ey) return; | |
2942 | - if (y1 < e->sy) return; | |
2943 | - if (y0 < e->sy) { | |
2944 | - x0 += (x1-x0) * (e->sy - y0) / (y1-y0); | |
2945 | - y0 = e->sy; | |
2946 | - } | |
2947 | - if (y1 > e->ey) { | |
2948 | - x1 += (x1-x0) * (e->ey - y1) / (y1-y0); | |
2949 | - y1 = e->ey; | |
2950 | - } | |
2951 | - | |
2952 | - if (x0 == x) | |
2953 | - STBTT_assert(x1 <= x+1); | |
2954 | - else if (x0 == x+1) | |
2955 | - STBTT_assert(x1 >= x); | |
2956 | - else if (x0 <= x) | |
2957 | - STBTT_assert(x1 <= x); | |
2958 | - else if (x0 >= x+1) | |
2959 | - STBTT_assert(x1 >= x+1); | |
2960 | - else | |
2961 | - STBTT_assert(x1 >= x && x1 <= x+1); | |
2962 | - | |
2963 | - if (x0 <= x && x1 <= x) | |
2964 | - scanline[x] += e->direction * (y1-y0); | |
2965 | - else if (x0 >= x+1 && x1 >= x+1) | |
2966 | - ; | |
2967 | - else { | |
2968 | - STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); | |
2969 | - scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position | |
2970 | - } | |
2971 | -} | |
2972 | - | |
2973 | -static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) | |
2974 | -{ | |
2975 | - float y_bottom = y_top+1; | |
2976 | - | |
2977 | - while (e) { | |
2978 | - // brute force every pixel | |
2979 | - | |
2980 | - // compute intersection points with top & bottom | |
2981 | - STBTT_assert(e->ey >= y_top); | |
2982 | - | |
2983 | - if (e->fdx == 0) { | |
2984 | - float x0 = e->fx; | |
2985 | - if (x0 < len) { | |
2986 | - if (x0 >= 0) { | |
2987 | - stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); | |
2988 | - stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); | |
2989 | - } else { | |
2990 | - stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); | |
2991 | - } | |
2992 | - } | |
2993 | - } else { | |
2994 | - float x0 = e->fx; | |
2995 | - float dx = e->fdx; | |
2996 | - float xb = x0 + dx; | |
2997 | - float x_top, x_bottom; | |
2998 | - float sy0,sy1; | |
2999 | - float dy = e->fdy; | |
3000 | - STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); | |
3001 | - | |
3002 | - // compute endpoints of line segment clipped to this scanline (if the | |
3003 | - // line segment starts on this scanline. x0 is the intersection of the | |
3004 | - // line with y_top, but that may be off the line segment. | |
3005 | - if (e->sy > y_top) { | |
3006 | - x_top = x0 + dx * (e->sy - y_top); | |
3007 | - sy0 = e->sy; | |
3008 | - } else { | |
3009 | - x_top = x0; | |
3010 | - sy0 = y_top; | |
3011 | - } | |
3012 | - if (e->ey < y_bottom) { | |
3013 | - x_bottom = x0 + dx * (e->ey - y_top); | |
3014 | - sy1 = e->ey; | |
3015 | - } else { | |
3016 | - x_bottom = xb; | |
3017 | - sy1 = y_bottom; | |
3018 | - } | |
3019 | - | |
3020 | - if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { | |
3021 | - // from here on, we don't have to range check x values | |
3022 | - | |
3023 | - if ((int) x_top == (int) x_bottom) { | |
3024 | - float height; | |
3025 | - // simple case, only spans one pixel | |
3026 | - int x = (int) x_top; | |
3027 | - height = sy1 - sy0; | |
3028 | - STBTT_assert(x >= 0 && x < len); | |
3029 | - scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; | |
3030 | - scanline_fill[x] += e->direction * height; // everything right of this pixel is filled | |
3031 | - } else { | |
3032 | - int x,x1,x2; | |
3033 | - float y_crossing, step, sign, area; | |
3034 | - // covers 2+ pixels | |
3035 | - if (x_top > x_bottom) { | |
3036 | - // flip scanline vertically; signed area is the same | |
3037 | - float t; | |
3038 | - sy0 = y_bottom - (sy0 - y_top); | |
3039 | - sy1 = y_bottom - (sy1 - y_top); | |
3040 | - t = sy0, sy0 = sy1, sy1 = t; | |
3041 | - t = x_bottom, x_bottom = x_top, x_top = t; | |
3042 | - dx = -dx; | |
3043 | - dy = -dy; | |
3044 | - t = x0, x0 = xb, xb = t; | |
3045 | - // [DEAR IMGUI] Fix static analyzer warning | |
3046 | - (void)dx; // [ImGui: fix static analyzer warning] | |
3047 | - } | |
3048 | - | |
3049 | - x1 = (int) x_top; | |
3050 | - x2 = (int) x_bottom; | |
3051 | - // compute intersection with y axis at x1+1 | |
3052 | - y_crossing = (x1+1 - x0) * dy + y_top; | |
3053 | - | |
3054 | - sign = e->direction; | |
3055 | - // area of the rectangle covered from y0..y_crossing | |
3056 | - area = sign * (y_crossing-sy0); | |
3057 | - // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) | |
3058 | - scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); | |
3059 | - | |
3060 | - step = sign * dy; | |
3061 | - for (x = x1+1; x < x2; ++x) { | |
3062 | - scanline[x] += area + step/2; | |
3063 | - area += step; | |
3064 | - } | |
3065 | - y_crossing += dy * (x2 - (x1+1)); | |
3066 | - | |
3067 | - STBTT_assert(STBTT_fabs(area) <= 1.01f); | |
3068 | - | |
3069 | - scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); | |
3070 | - | |
3071 | - scanline_fill[x2] += sign * (sy1-sy0); | |
3072 | - } | |
3073 | - } else { | |
3074 | - // if edge goes outside of box we're drawing, we require | |
3075 | - // clipping logic. since this does not match the intended use | |
3076 | - // of this library, we use a different, very slow brute | |
3077 | - // force implementation | |
3078 | - int x; | |
3079 | - for (x=0; x < len; ++x) { | |
3080 | - // cases: | |
3081 | - // | |
3082 | - // there can be up to two intersections with the pixel. any intersection | |
3083 | - // with left or right edges can be handled by splitting into two (or three) | |
3084 | - // regions. intersections with top & bottom do not necessitate case-wise logic. | |
3085 | - // | |
3086 | - // the old way of doing this found the intersections with the left & right edges, | |
3087 | - // then used some simple logic to produce up to three segments in sorted order | |
3088 | - // from top-to-bottom. however, this had a problem: if an x edge was epsilon | |
3089 | - // across the x border, then the corresponding y position might not be distinct | |
3090 | - // from the other y segment, and it might ignored as an empty segment. to avoid | |
3091 | - // that, we need to explicitly produce segments based on x positions. | |
3092 | - | |
3093 | - // rename variables to clearly-defined pairs | |
3094 | - float y0 = y_top; | |
3095 | - float x1 = (float) (x); | |
3096 | - float x2 = (float) (x+1); | |
3097 | - float x3 = xb; | |
3098 | - float y3 = y_bottom; | |
3099 | - | |
3100 | - // x = e->x + e->dx * (y-y_top) | |
3101 | - // (y-y_top) = (x - e->x) / e->dx | |
3102 | - // y = (x - e->x) / e->dx + y_top | |
3103 | - float y1 = (x - x0) / dx + y_top; | |
3104 | - float y2 = (x+1 - x0) / dx + y_top; | |
3105 | - | |
3106 | - if (x0 < x1 && x3 > x2) { // three segments descending down-right | |
3107 | - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); | |
3108 | - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); | |
3109 | - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); | |
3110 | - } else if (x3 < x1 && x0 > x2) { // three segments descending down-left | |
3111 | - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); | |
3112 | - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); | |
3113 | - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); | |
3114 | - } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right | |
3115 | - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); | |
3116 | - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); | |
3117 | - } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left | |
3118 | - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); | |
3119 | - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); | |
3120 | - } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right | |
3121 | - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); | |
3122 | - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); | |
3123 | - } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left | |
3124 | - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); | |
3125 | - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); | |
3126 | - } else { // one segment | |
3127 | - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); | |
3128 | - } | |
3129 | - } | |
3130 | - } | |
3131 | - } | |
3132 | - e = e->next; | |
3133 | - } | |
3134 | -} | |
3135 | - | |
3136 | -// directly AA rasterize edges w/o supersampling | |
3137 | -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) | |
3138 | -{ | |
3139 | - stbtt__hheap hh = { 0, 0, 0 }; | |
3140 | - stbtt__active_edge *active = NULL; | |
3141 | - int y,j=0, i; | |
3142 | - float scanline_data[129], *scanline, *scanline2; | |
3143 | - | |
3144 | - STBTT__NOTUSED(vsubsample); | |
3145 | - | |
3146 | - if (result->w > 64) | |
3147 | - scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); | |
3148 | - else | |
3149 | - scanline = scanline_data; | |
3150 | - | |
3151 | - scanline2 = scanline + result->w; | |
3152 | - | |
3153 | - y = off_y; | |
3154 | - e[n].y0 = (float) (off_y + result->h) + 1; | |
3155 | - | |
3156 | - while (j < result->h) { | |
3157 | - // find center of pixel for this scanline | |
3158 | - float scan_y_top = y + 0.0f; | |
3159 | - float scan_y_bottom = y + 1.0f; | |
3160 | - stbtt__active_edge **step = &active; | |
3161 | - | |
3162 | - STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); | |
3163 | - STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); | |
3164 | - | |
3165 | - // update all active edges; | |
3166 | - // remove all active edges that terminate before the top of this scanline | |
3167 | - while (*step) { | |
3168 | - stbtt__active_edge * z = *step; | |
3169 | - if (z->ey <= scan_y_top) { | |
3170 | - *step = z->next; // delete from list | |
3171 | - STBTT_assert(z->direction); | |
3172 | - z->direction = 0; | |
3173 | - stbtt__hheap_free(&hh, z); | |
3174 | - } else { | |
3175 | - step = &((*step)->next); // advance through list | |
3176 | - } | |
3177 | - } | |
3178 | - | |
3179 | - // insert all edges that start before the bottom of this scanline | |
3180 | - while (e->y0 <= scan_y_bottom) { | |
3181 | - if (e->y0 != e->y1) { | |
3182 | - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); | |
3183 | - if (z != NULL) { | |
3184 | - if (j == 0 && off_y != 0) { | |
3185 | - if (z->ey < scan_y_top) { | |
3186 | - // this can happen due to subpixel positioning and some kind of fp rounding error i think | |
3187 | - z->ey = scan_y_top; | |
3188 | - } | |
3189 | - } | |
3190 | - STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds | |
3191 | - // insert at front | |
3192 | - z->next = active; | |
3193 | - active = z; | |
3194 | - } | |
3195 | - } | |
3196 | - ++e; | |
3197 | - } | |
3198 | - | |
3199 | - // now process all active edges | |
3200 | - if (active) | |
3201 | - stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); | |
3202 | - | |
3203 | - { | |
3204 | - float sum = 0; | |
3205 | - for (i=0; i < result->w; ++i) { | |
3206 | - float k; | |
3207 | - int m; | |
3208 | - sum += scanline2[i]; | |
3209 | - k = scanline[i] + sum; | |
3210 | - k = (float) STBTT_fabs(k)*255 + 0.5f; | |
3211 | - m = (int) k; | |
3212 | - if (m > 255) m = 255; | |
3213 | - result->pixels[j*result->stride + i] = (unsigned char) m; | |
3214 | - } | |
3215 | - } | |
3216 | - // advance all the edges | |
3217 | - step = &active; | |
3218 | - while (*step) { | |
3219 | - stbtt__active_edge *z = *step; | |
3220 | - z->fx += z->fdx; // advance to position for current scanline | |
3221 | - step = &((*step)->next); // advance through list | |
3222 | - } | |
3223 | - | |
3224 | - ++y; | |
3225 | - ++j; | |
3226 | - } | |
3227 | - | |
3228 | - stbtt__hheap_cleanup(&hh, userdata); | |
3229 | - | |
3230 | - if (scanline != scanline_data) | |
3231 | - STBTT_free(scanline, userdata); | |
3232 | -} | |
3233 | -#else | |
3234 | -#error "Unrecognized value of STBTT_RASTERIZER_VERSION" | |
3235 | -#endif | |
3236 | - | |
3237 | -#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) | |
3238 | - | |
3239 | -static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) | |
3240 | -{ | |
3241 | - int i,j; | |
3242 | - for (i=1; i < n; ++i) { | |
3243 | - stbtt__edge t = p[i], *a = &t; | |
3244 | - j = i; | |
3245 | - while (j > 0) { | |
3246 | - stbtt__edge *b = &p[j-1]; | |
3247 | - int c = STBTT__COMPARE(a,b); | |
3248 | - if (!c) break; | |
3249 | - p[j] = p[j-1]; | |
3250 | - --j; | |
3251 | - } | |
3252 | - if (i != j) | |
3253 | - p[j] = t; | |
3254 | - } | |
3255 | -} | |
3256 | - | |
3257 | -static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) | |
3258 | -{ | |
3259 | - /* threshold for transitioning to insertion sort */ | |
3260 | - while (n > 12) { | |
3261 | - stbtt__edge t; | |
3262 | - int c01,c12,c,m,i,j; | |
3263 | - | |
3264 | - /* compute median of three */ | |
3265 | - m = n >> 1; | |
3266 | - c01 = STBTT__COMPARE(&p[0],&p[m]); | |
3267 | - c12 = STBTT__COMPARE(&p[m],&p[n-1]); | |
3268 | - /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ | |
3269 | - if (c01 != c12) { | |
3270 | - /* otherwise, we'll need to swap something else to middle */ | |
3271 | - int z; | |
3272 | - c = STBTT__COMPARE(&p[0],&p[n-1]); | |
3273 | - /* 0>mid && mid<n: 0>n => n; 0<n => 0 */ | |
3274 | - /* 0<mid && mid>n: 0>n => 0; 0<n => n */ | |
3275 | - z = (c == c12) ? 0 : n-1; | |
3276 | - t = p[z]; | |
3277 | - p[z] = p[m]; | |
3278 | - p[m] = t; | |
3279 | - } | |
3280 | - /* now p[m] is the median-of-three */ | |
3281 | - /* swap it to the beginning so it won't move around */ | |
3282 | - t = p[0]; | |
3283 | - p[0] = p[m]; | |
3284 | - p[m] = t; | |
3285 | - | |
3286 | - /* partition loop */ | |
3287 | - i=1; | |
3288 | - j=n-1; | |
3289 | - for(;;) { | |
3290 | - /* handling of equality is crucial here */ | |
3291 | - /* for sentinels & efficiency with duplicates */ | |
3292 | - for (;;++i) { | |
3293 | - if (!STBTT__COMPARE(&p[i], &p[0])) break; | |
3294 | - } | |
3295 | - for (;;--j) { | |
3296 | - if (!STBTT__COMPARE(&p[0], &p[j])) break; | |
3297 | - } | |
3298 | - /* make sure we haven't crossed */ | |
3299 | - if (i >= j) break; | |
3300 | - t = p[i]; | |
3301 | - p[i] = p[j]; | |
3302 | - p[j] = t; | |
3303 | - | |
3304 | - ++i; | |
3305 | - --j; | |
3306 | - } | |
3307 | - /* recurse on smaller side, iterate on larger */ | |
3308 | - if (j < (n-i)) { | |
3309 | - stbtt__sort_edges_quicksort(p,j); | |
3310 | - p = p+i; | |
3311 | - n = n-i; | |
3312 | - } else { | |
3313 | - stbtt__sort_edges_quicksort(p+i, n-i); | |
3314 | - n = j; | |
3315 | - } | |
3316 | - } | |
3317 | -} | |
3318 | - | |
3319 | -static void stbtt__sort_edges(stbtt__edge *p, int n) | |
3320 | -{ | |
3321 | - stbtt__sort_edges_quicksort(p, n); | |
3322 | - stbtt__sort_edges_ins_sort(p, n); | |
3323 | -} | |
3324 | - | |
3325 | -typedef struct | |
3326 | -{ | |
3327 | - float x,y; | |
3328 | -} stbtt__point; | |
3329 | - | |
3330 | -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) | |
3331 | -{ | |
3332 | - float y_scale_inv = invert ? -scale_y : scale_y; | |
3333 | - stbtt__edge *e; | |
3334 | - int n,i,j,k,m; | |
3335 | -#if STBTT_RASTERIZER_VERSION == 1 | |
3336 | - int vsubsample = result->h < 8 ? 15 : 5; | |
3337 | -#elif STBTT_RASTERIZER_VERSION == 2 | |
3338 | - int vsubsample = 1; | |
3339 | -#else | |
3340 | - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" | |
3341 | -#endif | |
3342 | - // vsubsample should divide 255 evenly; otherwise we won't reach full opacity | |
3343 | - | |
3344 | - // now we have to blow out the windings into explicit edge lists | |
3345 | - n = 0; | |
3346 | - for (i=0; i < windings; ++i) | |
3347 | - n += wcount[i]; | |
3348 | - | |
3349 | - e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel | |
3350 | - if (e == 0) return; | |
3351 | - n = 0; | |
3352 | - | |
3353 | - m=0; | |
3354 | - for (i=0; i < windings; ++i) { | |
3355 | - stbtt__point *p = pts + m; | |
3356 | - m += wcount[i]; | |
3357 | - j = wcount[i]-1; | |
3358 | - for (k=0; k < wcount[i]; j=k++) { | |
3359 | - int a=k,b=j; | |
3360 | - // skip the edge if horizontal | |
3361 | - if (p[j].y == p[k].y) | |
3362 | - continue; | |
3363 | - // add edge from j to k to the list | |
3364 | - e[n].invert = 0; | |
3365 | - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { | |
3366 | - e[n].invert = 1; | |
3367 | - a=j,b=k; | |
3368 | - } | |
3369 | - e[n].x0 = p[a].x * scale_x + shift_x; | |
3370 | - e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; | |
3371 | - e[n].x1 = p[b].x * scale_x + shift_x; | |
3372 | - e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; | |
3373 | - ++n; | |
3374 | - } | |
3375 | - } | |
3376 | - | |
3377 | - // now sort the edges by their highest point (should snap to integer, and then by x) | |
3378 | - //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); | |
3379 | - stbtt__sort_edges(e, n); | |
3380 | - | |
3381 | - // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule | |
3382 | - stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); | |
3383 | - | |
3384 | - STBTT_free(e, userdata); | |
3385 | -} | |
3386 | - | |
3387 | -static void stbtt__add_point(stbtt__point *points, int n, float x, float y) | |
3388 | -{ | |
3389 | - if (!points) return; // during first pass, it's unallocated | |
3390 | - points[n].x = x; | |
3391 | - points[n].y = y; | |
3392 | -} | |
3393 | - | |
3394 | -// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching | |
3395 | -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) | |
3396 | -{ | |
3397 | - // midpoint | |
3398 | - float mx = (x0 + 2*x1 + x2)/4; | |
3399 | - float my = (y0 + 2*y1 + y2)/4; | |
3400 | - // versus directly drawn line | |
3401 | - float dx = (x0+x2)/2 - mx; | |
3402 | - float dy = (y0+y2)/2 - my; | |
3403 | - if (n > 16) // 65536 segments on one curve better be enough! | |
3404 | - return 1; | |
3405 | - if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA | |
3406 | - stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); | |
3407 | - stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); | |
3408 | - } else { | |
3409 | - stbtt__add_point(points, *num_points,x2,y2); | |
3410 | - *num_points = *num_points+1; | |
3411 | - } | |
3412 | - return 1; | |
3413 | -} | |
3414 | - | |
3415 | -static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) | |
3416 | -{ | |
3417 | - // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough | |
3418 | - float dx0 = x1-x0; | |
3419 | - float dy0 = y1-y0; | |
3420 | - float dx1 = x2-x1; | |
3421 | - float dy1 = y2-y1; | |
3422 | - float dx2 = x3-x2; | |
3423 | - float dy2 = y3-y2; | |
3424 | - float dx = x3-x0; | |
3425 | - float dy = y3-y0; | |
3426 | - float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); | |
3427 | - float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); | |
3428 | - float flatness_squared = longlen*longlen-shortlen*shortlen; | |
3429 | - | |
3430 | - if (n > 16) // 65536 segments on one curve better be enough! | |
3431 | - return; | |
3432 | - | |
3433 | - if (flatness_squared > objspace_flatness_squared) { | |
3434 | - float x01 = (x0+x1)/2; | |
3435 | - float y01 = (y0+y1)/2; | |
3436 | - float x12 = (x1+x2)/2; | |
3437 | - float y12 = (y1+y2)/2; | |
3438 | - float x23 = (x2+x3)/2; | |
3439 | - float y23 = (y2+y3)/2; | |
3440 | - | |
3441 | - float xa = (x01+x12)/2; | |
3442 | - float ya = (y01+y12)/2; | |
3443 | - float xb = (x12+x23)/2; | |
3444 | - float yb = (y12+y23)/2; | |
3445 | - | |
3446 | - float mx = (xa+xb)/2; | |
3447 | - float my = (ya+yb)/2; | |
3448 | - | |
3449 | - stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); | |
3450 | - stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); | |
3451 | - } else { | |
3452 | - stbtt__add_point(points, *num_points,x3,y3); | |
3453 | - *num_points = *num_points+1; | |
3454 | - } | |
3455 | -} | |
3456 | - | |
3457 | -// returns number of contours | |
3458 | -static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) | |
3459 | -{ | |
3460 | - stbtt__point *points=0; | |
3461 | - int num_points=0; | |
3462 | - | |
3463 | - float objspace_flatness_squared = objspace_flatness * objspace_flatness; | |
3464 | - int i,n=0,start=0, pass; | |
3465 | - | |
3466 | - // count how many "moves" there are to get the contour count | |
3467 | - for (i=0; i < num_verts; ++i) | |
3468 | - if (vertices[i].type == STBTT_vmove) | |
3469 | - ++n; | |
3470 | - | |
3471 | - *num_contours = n; | |
3472 | - if (n == 0) return 0; | |
3473 | - | |
3474 | - *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); | |
3475 | - | |
3476 | - if (*contour_lengths == 0) { | |
3477 | - *num_contours = 0; | |
3478 | - return 0; | |
3479 | - } | |
3480 | - | |
3481 | - // make two passes through the points so we don't need to realloc | |
3482 | - for (pass=0; pass < 2; ++pass) { | |
3483 | - float x=0,y=0; | |
3484 | - if (pass == 1) { | |
3485 | - points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); | |
3486 | - if (points == NULL) goto error; | |
3487 | - } | |
3488 | - num_points = 0; | |
3489 | - n= -1; | |
3490 | - for (i=0; i < num_verts; ++i) { | |
3491 | - switch (vertices[i].type) { | |
3492 | - case STBTT_vmove: | |
3493 | - // start the next contour | |
3494 | - if (n >= 0) | |
3495 | - (*contour_lengths)[n] = num_points - start; | |
3496 | - ++n; | |
3497 | - start = num_points; | |
3498 | - | |
3499 | - x = vertices[i].x, y = vertices[i].y; | |
3500 | - stbtt__add_point(points, num_points++, x,y); | |
3501 | - break; | |
3502 | - case STBTT_vline: | |
3503 | - x = vertices[i].x, y = vertices[i].y; | |
3504 | - stbtt__add_point(points, num_points++, x, y); | |
3505 | - break; | |
3506 | - case STBTT_vcurve: | |
3507 | - stbtt__tesselate_curve(points, &num_points, x,y, | |
3508 | - vertices[i].cx, vertices[i].cy, | |
3509 | - vertices[i].x, vertices[i].y, | |
3510 | - objspace_flatness_squared, 0); | |
3511 | - x = vertices[i].x, y = vertices[i].y; | |
3512 | - break; | |
3513 | - case STBTT_vcubic: | |
3514 | - stbtt__tesselate_cubic(points, &num_points, x,y, | |
3515 | - vertices[i].cx, vertices[i].cy, | |
3516 | - vertices[i].cx1, vertices[i].cy1, | |
3517 | - vertices[i].x, vertices[i].y, | |
3518 | - objspace_flatness_squared, 0); | |
3519 | - x = vertices[i].x, y = vertices[i].y; | |
3520 | - break; | |
3521 | - } | |
3522 | - } | |
3523 | - (*contour_lengths)[n] = num_points - start; | |
3524 | - } | |
3525 | - | |
3526 | - return points; | |
3527 | -error: | |
3528 | - STBTT_free(points, userdata); | |
3529 | - STBTT_free(*contour_lengths, userdata); | |
3530 | - *contour_lengths = 0; | |
3531 | - *num_contours = 0; | |
3532 | - return NULL; | |
3533 | -} | |
3534 | - | |
3535 | -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) | |
3536 | -{ | |
3537 | - float scale = scale_x > scale_y ? scale_y : scale_x; | |
3538 | - int winding_count = 0; | |
3539 | - int *winding_lengths = NULL; | |
3540 | - stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); | |
3541 | - if (windings) { | |
3542 | - stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); | |
3543 | - STBTT_free(winding_lengths, userdata); | |
3544 | - STBTT_free(windings, userdata); | |
3545 | - } | |
3546 | -} | |
3547 | - | |
3548 | -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) | |
3549 | -{ | |
3550 | - STBTT_free(bitmap, userdata); | |
3551 | -} | |
3552 | - | |
3553 | -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) | |
3554 | -{ | |
3555 | - int ix0,iy0,ix1,iy1; | |
3556 | - stbtt__bitmap gbm; | |
3557 | - stbtt_vertex *vertices; | |
3558 | - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); | |
3559 | - | |
3560 | - if (scale_x == 0) scale_x = scale_y; | |
3561 | - if (scale_y == 0) { | |
3562 | - if (scale_x == 0) { | |
3563 | - STBTT_free(vertices, info->userdata); | |
3564 | - return NULL; | |
3565 | - } | |
3566 | - scale_y = scale_x; | |
3567 | - } | |
3568 | - | |
3569 | - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); | |
3570 | - | |
3571 | - // now we get the size | |
3572 | - gbm.w = (ix1 - ix0); | |
3573 | - gbm.h = (iy1 - iy0); | |
3574 | - gbm.pixels = NULL; // in case we error | |
3575 | - | |
3576 | - if (width ) *width = gbm.w; | |
3577 | - if (height) *height = gbm.h; | |
3578 | - if (xoff ) *xoff = ix0; | |
3579 | - if (yoff ) *yoff = iy0; | |
3580 | - | |
3581 | - if (gbm.w && gbm.h) { | |
3582 | - gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); | |
3583 | - if (gbm.pixels) { | |
3584 | - gbm.stride = gbm.w; | |
3585 | - | |
3586 | - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); | |
3587 | - } | |
3588 | - } | |
3589 | - STBTT_free(vertices, info->userdata); | |
3590 | - return gbm.pixels; | |
3591 | -} | |
3592 | - | |
3593 | -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) | |
3594 | -{ | |
3595 | - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); | |
3596 | -} | |
3597 | - | |
3598 | -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) | |
3599 | -{ | |
3600 | - int ix0,iy0; | |
3601 | - stbtt_vertex *vertices; | |
3602 | - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); | |
3603 | - stbtt__bitmap gbm; | |
3604 | - | |
3605 | - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); | |
3606 | - gbm.pixels = output; | |
3607 | - gbm.w = out_w; | |
3608 | - gbm.h = out_h; | |
3609 | - gbm.stride = out_stride; | |
3610 | - | |
3611 | - if (gbm.w && gbm.h) | |
3612 | - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); | |
3613 | - | |
3614 | - STBTT_free(vertices, info->userdata); | |
3615 | -} | |
3616 | - | |
3617 | -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) | |
3618 | -{ | |
3619 | - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); | |
3620 | -} | |
3621 | - | |
3622 | -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) | |
3623 | -{ | |
3624 | - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); | |
3625 | -} | |
3626 | - | |
3627 | -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(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 oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) | |
3628 | -{ | |
3629 | - stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); | |
3630 | -} | |
3631 | - | |
3632 | -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) | |
3633 | -{ | |
3634 | - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); | |
3635 | -} | |
3636 | - | |
3637 | -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) | |
3638 | -{ | |
3639 | - return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); | |
3640 | -} | |
3641 | - | |
3642 | -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) | |
3643 | -{ | |
3644 | - stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); | |
3645 | -} | |
3646 | - | |
3647 | -////////////////////////////////////////////////////////////////////////////// | |
3648 | -// | |
3649 | -// bitmap baking | |
3650 | -// | |
3651 | -// This is SUPER-CRAPPY packing to keep source code small | |
3652 | - | |
3653 | -static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) | |
3654 | - float pixel_height, // height of font in pixels | |
3655 | - unsigned char *pixels, int pw, int ph, // bitmap to be filled in | |
3656 | - int first_char, int num_chars, // characters to bake | |
3657 | - stbtt_bakedchar *chardata) | |
3658 | -{ | |
3659 | - float scale; | |
3660 | - int x,y,bottom_y, i; | |
3661 | - stbtt_fontinfo f; | |
3662 | - f.userdata = NULL; | |
3663 | - if (!stbtt_InitFont(&f, data, offset)) | |
3664 | - return -1; | |
3665 | - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels | |
3666 | - x=y=1; | |
3667 | - bottom_y = 1; | |
3668 | - | |
3669 | - scale = stbtt_ScaleForPixelHeight(&f, pixel_height); | |
3670 | - | |
3671 | - for (i=0; i < num_chars; ++i) { | |
3672 | - int advance, lsb, x0,y0,x1,y1,gw,gh; | |
3673 | - int g = stbtt_FindGlyphIndex(&f, first_char + i); | |
3674 | - stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); | |
3675 | - stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); | |
3676 | - gw = x1-x0; | |
3677 | - gh = y1-y0; | |
3678 | - if (x + gw + 1 >= pw) | |
3679 | - y = bottom_y, x = 1; // advance to next row | |
3680 | - if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row | |
3681 | - return -i; | |
3682 | - STBTT_assert(x+gw < pw); | |
3683 | - STBTT_assert(y+gh < ph); | |
3684 | - stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); | |
3685 | - chardata[i].x0 = (stbtt_int16) x; | |
3686 | - chardata[i].y0 = (stbtt_int16) y; | |
3687 | - chardata[i].x1 = (stbtt_int16) (x + gw); | |
3688 | - chardata[i].y1 = (stbtt_int16) (y + gh); | |
3689 | - chardata[i].xadvance = scale * advance; | |
3690 | - chardata[i].xoff = (float) x0; | |
3691 | - chardata[i].yoff = (float) y0; | |
3692 | - x = x + gw + 1; | |
3693 | - if (y+gh+1 > bottom_y) | |
3694 | - bottom_y = y+gh+1; | |
3695 | - } | |
3696 | - return bottom_y; | |
3697 | -} | |
3698 | - | |
3699 | -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) | |
3700 | -{ | |
3701 | - float d3d_bias = opengl_fillrule ? 0 : -0.5f; | |
3702 | - float ipw = 1.0f / pw, iph = 1.0f / ph; | |
3703 | - const stbtt_bakedchar *b = chardata + char_index; | |
3704 | - int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); | |
3705 | - int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); | |
3706 | - | |
3707 | - q->x0 = round_x + d3d_bias; | |
3708 | - q->y0 = round_y + d3d_bias; | |
3709 | - q->x1 = round_x + b->x1 - b->x0 + d3d_bias; | |
3710 | - q->y1 = round_y + b->y1 - b->y0 + d3d_bias; | |
3711 | - | |
3712 | - q->s0 = b->x0 * ipw; | |
3713 | - q->t0 = b->y0 * iph; | |
3714 | - q->s1 = b->x1 * ipw; | |
3715 | - q->t1 = b->y1 * iph; | |
3716 | - | |
3717 | - *xpos += b->xadvance; | |
3718 | -} | |
3719 | - | |
3720 | -////////////////////////////////////////////////////////////////////////////// | |
3721 | -// | |
3722 | -// rectangle packing replacement routines if you don't have stb_rect_pack.h | |
3723 | -// | |
3724 | - | |
3725 | -#ifndef STB_RECT_PACK_VERSION | |
3726 | - | |
3727 | -typedef int stbrp_coord; | |
3728 | - | |
3729 | -//////////////////////////////////////////////////////////////////////////////////// | |
3730 | -// // | |
3731 | -// // | |
3732 | -// COMPILER WARNING ?!?!? // | |
3733 | -// // | |
3734 | -// // | |
3735 | -// if you get a compile warning due to these symbols being defined more than // | |
3736 | -// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // | |
3737 | -// // | |
3738 | -//////////////////////////////////////////////////////////////////////////////////// | |
3739 | - | |
3740 | -typedef struct | |
3741 | -{ | |
3742 | - int width,height; | |
3743 | - int x,y,bottom_y; | |
3744 | -} stbrp_context; | |
3745 | - | |
3746 | -typedef struct | |
3747 | -{ | |
3748 | - unsigned char x; | |
3749 | -} stbrp_node; | |
3750 | - | |
3751 | -struct stbrp_rect | |
3752 | -{ | |
3753 | - stbrp_coord x,y; | |
3754 | - int id,w,h,was_packed; | |
3755 | -}; | |
3756 | - | |
3757 | -static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) | |
3758 | -{ | |
3759 | - con->width = pw; | |
3760 | - con->height = ph; | |
3761 | - con->x = 0; | |
3762 | - con->y = 0; | |
3763 | - con->bottom_y = 0; | |
3764 | - STBTT__NOTUSED(nodes); | |
3765 | - STBTT__NOTUSED(num_nodes); | |
3766 | -} | |
3767 | - | |
3768 | -static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) | |
3769 | -{ | |
3770 | - int i; | |
3771 | - for (i=0; i < num_rects; ++i) { | |
3772 | - if (con->x + rects[i].w > con->width) { | |
3773 | - con->x = 0; | |
3774 | - con->y = con->bottom_y; | |
3775 | - } | |
3776 | - if (con->y + rects[i].h > con->height) | |
3777 | - break; | |
3778 | - rects[i].x = con->x; | |
3779 | - rects[i].y = con->y; | |
3780 | - rects[i].was_packed = 1; | |
3781 | - con->x += rects[i].w; | |
3782 | - if (con->y + rects[i].h > con->bottom_y) | |
3783 | - con->bottom_y = con->y + rects[i].h; | |
3784 | - } | |
3785 | - for ( ; i < num_rects; ++i) | |
3786 | - rects[i].was_packed = 0; | |
3787 | -} | |
3788 | -#endif | |
3789 | - | |
3790 | -////////////////////////////////////////////////////////////////////////////// | |
3791 | -// | |
3792 | -// bitmap baking | |
3793 | -// | |
3794 | -// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If | |
3795 | -// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. | |
3796 | - | |
3797 | -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) | |
3798 | -{ | |
3799 | - stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); | |
3800 | - int num_nodes = pw - padding; | |
3801 | - stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); | |
3802 | - | |
3803 | - if (context == NULL || nodes == NULL) { | |
3804 | - if (context != NULL) STBTT_free(context, alloc_context); | |
3805 | - if (nodes != NULL) STBTT_free(nodes , alloc_context); | |
3806 | - return 0; | |
3807 | - } | |
3808 | - | |
3809 | - spc->user_allocator_context = alloc_context; | |
3810 | - spc->width = pw; | |
3811 | - spc->height = ph; | |
3812 | - spc->pixels = pixels; | |
3813 | - spc->pack_info = context; | |
3814 | - spc->nodes = nodes; | |
3815 | - spc->padding = padding; | |
3816 | - spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; | |
3817 | - spc->h_oversample = 1; | |
3818 | - spc->v_oversample = 1; | |
3819 | - spc->skip_missing = 0; | |
3820 | - | |
3821 | - stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); | |
3822 | - | |
3823 | - if (pixels) | |
3824 | - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels | |
3825 | - | |
3826 | - return 1; | |
3827 | -} | |
3828 | - | |
3829 | -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) | |
3830 | -{ | |
3831 | - STBTT_free(spc->nodes , spc->user_allocator_context); | |
3832 | - STBTT_free(spc->pack_info, spc->user_allocator_context); | |
3833 | -} | |
3834 | - | |
3835 | -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) | |
3836 | -{ | |
3837 | - STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); | |
3838 | - STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); | |
3839 | - if (h_oversample <= STBTT_MAX_OVERSAMPLE) | |
3840 | - spc->h_oversample = h_oversample; | |
3841 | - if (v_oversample <= STBTT_MAX_OVERSAMPLE) | |
3842 | - spc->v_oversample = v_oversample; | |
3843 | -} | |
3844 | - | |
3845 | -STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) | |
3846 | -{ | |
3847 | - spc->skip_missing = skip; | |
3848 | -} | |
3849 | - | |
3850 | -#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) | |
3851 | - | |
3852 | -static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) | |
3853 | -{ | |
3854 | - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; | |
3855 | - int safe_w = w - kernel_width; | |
3856 | - int j; | |
3857 | - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze | |
3858 | - for (j=0; j < h; ++j) { | |
3859 | - int i; | |
3860 | - unsigned int total; | |
3861 | - STBTT_memset(buffer, 0, kernel_width); | |
3862 | - | |
3863 | - total = 0; | |
3864 | - | |
3865 | - // make kernel_width a constant in common cases so compiler can optimize out the divide | |
3866 | - switch (kernel_width) { | |
3867 | - case 2: | |
3868 | - for (i=0; i <= safe_w; ++i) { | |
3869 | - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; | |
3870 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; | |
3871 | - pixels[i] = (unsigned char) (total / 2); | |
3872 | - } | |
3873 | - break; | |
3874 | - case 3: | |
3875 | - for (i=0; i <= safe_w; ++i) { | |
3876 | - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; | |
3877 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; | |
3878 | - pixels[i] = (unsigned char) (total / 3); | |
3879 | - } | |
3880 | - break; | |
3881 | - case 4: | |
3882 | - for (i=0; i <= safe_w; ++i) { | |
3883 | - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; | |
3884 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; | |
3885 | - pixels[i] = (unsigned char) (total / 4); | |
3886 | - } | |
3887 | - break; | |
3888 | - case 5: | |
3889 | - for (i=0; i <= safe_w; ++i) { | |
3890 | - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; | |
3891 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; | |
3892 | - pixels[i] = (unsigned char) (total / 5); | |
3893 | - } | |
3894 | - break; | |
3895 | - default: | |
3896 | - for (i=0; i <= safe_w; ++i) { | |
3897 | - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; | |
3898 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; | |
3899 | - pixels[i] = (unsigned char) (total / kernel_width); | |
3900 | - } | |
3901 | - break; | |
3902 | - } | |
3903 | - | |
3904 | - for (; i < w; ++i) { | |
3905 | - STBTT_assert(pixels[i] == 0); | |
3906 | - total -= buffer[i & STBTT__OVER_MASK]; | |
3907 | - pixels[i] = (unsigned char) (total / kernel_width); | |
3908 | - } | |
3909 | - | |
3910 | - pixels += stride_in_bytes; | |
3911 | - } | |
3912 | -} | |
3913 | - | |
3914 | -static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) | |
3915 | -{ | |
3916 | - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; | |
3917 | - int safe_h = h - kernel_width; | |
3918 | - int j; | |
3919 | - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze | |
3920 | - for (j=0; j < w; ++j) { | |
3921 | - int i; | |
3922 | - unsigned int total; | |
3923 | - STBTT_memset(buffer, 0, kernel_width); | |
3924 | - | |
3925 | - total = 0; | |
3926 | - | |
3927 | - // make kernel_width a constant in common cases so compiler can optimize out the divide | |
3928 | - switch (kernel_width) { | |
3929 | - case 2: | |
3930 | - for (i=0; i <= safe_h; ++i) { | |
3931 | - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; | |
3932 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; | |
3933 | - pixels[i*stride_in_bytes] = (unsigned char) (total / 2); | |
3934 | - } | |
3935 | - break; | |
3936 | - case 3: | |
3937 | - for (i=0; i <= safe_h; ++i) { | |
3938 | - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; | |
3939 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; | |
3940 | - pixels[i*stride_in_bytes] = (unsigned char) (total / 3); | |
3941 | - } | |
3942 | - break; | |
3943 | - case 4: | |
3944 | - for (i=0; i <= safe_h; ++i) { | |
3945 | - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; | |
3946 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; | |
3947 | - pixels[i*stride_in_bytes] = (unsigned char) (total / 4); | |
3948 | - } | |
3949 | - break; | |
3950 | - case 5: | |
3951 | - for (i=0; i <= safe_h; ++i) { | |
3952 | - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; | |
3953 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; | |
3954 | - pixels[i*stride_in_bytes] = (unsigned char) (total / 5); | |
3955 | - } | |
3956 | - break; | |
3957 | - default: | |
3958 | - for (i=0; i <= safe_h; ++i) { | |
3959 | - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; | |
3960 | - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; | |
3961 | - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); | |
3962 | - } | |
3963 | - break; | |
3964 | - } | |
3965 | - | |
3966 | - for (; i < h; ++i) { | |
3967 | - STBTT_assert(pixels[i*stride_in_bytes] == 0); | |
3968 | - total -= buffer[i & STBTT__OVER_MASK]; | |
3969 | - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); | |
3970 | - } | |
3971 | - | |
3972 | - pixels += 1; | |
3973 | - } | |
3974 | -} | |
3975 | - | |
3976 | -static float stbtt__oversample_shift(int oversample) | |
3977 | -{ | |
3978 | - if (!oversample) | |
3979 | - return 0.0f; | |
3980 | - | |
3981 | - // The prefilter is a box filter of width "oversample", | |
3982 | - // which shifts phase by (oversample - 1)/2 pixels in | |
3983 | - // oversampled space. We want to shift in the opposite | |
3984 | - // direction to counter this. | |
3985 | - return (float)-(oversample - 1) / (2.0f * (float)oversample); | |
3986 | -} | |
3987 | - | |
3988 | -// rects array must be big enough to accommodate all characters in the given ranges | |
3989 | -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) | |
3990 | -{ | |
3991 | - int i,j,k; | |
3992 | - | |
3993 | - k=0; | |
3994 | - for (i=0; i < num_ranges; ++i) { | |
3995 | - float fh = ranges[i].font_size; | |
3996 | - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); | |
3997 | - ranges[i].h_oversample = (unsigned char) spc->h_oversample; | |
3998 | - ranges[i].v_oversample = (unsigned char) spc->v_oversample; | |
3999 | - for (j=0; j < ranges[i].num_chars; ++j) { | |
4000 | - int x0,y0,x1,y1; | |
4001 | - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; | |
4002 | - int glyph = stbtt_FindGlyphIndex(info, codepoint); | |
4003 | - if (glyph == 0 && spc->skip_missing) { | |
4004 | - rects[k].w = rects[k].h = 0; | |
4005 | - } else { | |
4006 | - stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, | |
4007 | - scale * spc->h_oversample, | |
4008 | - scale * spc->v_oversample, | |
4009 | - 0,0, | |
4010 | - &x0,&y0,&x1,&y1); | |
4011 | - rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); | |
4012 | - rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); | |
4013 | - } | |
4014 | - ++k; | |
4015 | - } | |
4016 | - } | |
4017 | - | |
4018 | - return k; | |
4019 | -} | |
4020 | - | |
4021 | -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(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 prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) | |
4022 | -{ | |
4023 | - stbtt_MakeGlyphBitmapSubpixel(info, | |
4024 | - output, | |
4025 | - out_w - (prefilter_x - 1), | |
4026 | - out_h - (prefilter_y - 1), | |
4027 | - out_stride, | |
4028 | - scale_x, | |
4029 | - scale_y, | |
4030 | - shift_x, | |
4031 | - shift_y, | |
4032 | - glyph); | |
4033 | - | |
4034 | - if (prefilter_x > 1) | |
4035 | - stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); | |
4036 | - | |
4037 | - if (prefilter_y > 1) | |
4038 | - stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); | |
4039 | - | |
4040 | - *sub_x = stbtt__oversample_shift(prefilter_x); | |
4041 | - *sub_y = stbtt__oversample_shift(prefilter_y); | |
4042 | -} | |
4043 | - | |
4044 | -// rects array must be big enough to accommodate all characters in the given ranges | |
4045 | -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) | |
4046 | -{ | |
4047 | - int i,j,k, return_value = 1; | |
4048 | - | |
4049 | - // save current values | |
4050 | - int old_h_over = spc->h_oversample; | |
4051 | - int old_v_over = spc->v_oversample; | |
4052 | - | |
4053 | - k = 0; | |
4054 | - for (i=0; i < num_ranges; ++i) { | |
4055 | - float fh = ranges[i].font_size; | |
4056 | - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); | |
4057 | - float recip_h,recip_v,sub_x,sub_y; | |
4058 | - spc->h_oversample = ranges[i].h_oversample; | |
4059 | - spc->v_oversample = ranges[i].v_oversample; | |
4060 | - recip_h = 1.0f / spc->h_oversample; | |
4061 | - recip_v = 1.0f / spc->v_oversample; | |
4062 | - sub_x = stbtt__oversample_shift(spc->h_oversample); | |
4063 | - sub_y = stbtt__oversample_shift(spc->v_oversample); | |
4064 | - for (j=0; j < ranges[i].num_chars; ++j) { | |
4065 | - stbrp_rect *r = &rects[k]; | |
4066 | - if (r->was_packed && r->w != 0 && r->h != 0) { | |
4067 | - stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; | |
4068 | - int advance, lsb, x0,y0,x1,y1; | |
4069 | - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; | |
4070 | - int glyph = stbtt_FindGlyphIndex(info, codepoint); | |
4071 | - stbrp_coord pad = (stbrp_coord) spc->padding; | |
4072 | - | |
4073 | - // pad on left and top | |
4074 | - r->x += pad; | |
4075 | - r->y += pad; | |
4076 | - r->w -= pad; | |
4077 | - r->h -= pad; | |
4078 | - stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); | |
4079 | - stbtt_GetGlyphBitmapBox(info, glyph, | |
4080 | - scale * spc->h_oversample, | |
4081 | - scale * spc->v_oversample, | |
4082 | - &x0,&y0,&x1,&y1); | |
4083 | - stbtt_MakeGlyphBitmapSubpixel(info, | |
4084 | - spc->pixels + r->x + r->y*spc->stride_in_bytes, | |
4085 | - r->w - spc->h_oversample+1, | |
4086 | - r->h - spc->v_oversample+1, | |
4087 | - spc->stride_in_bytes, | |
4088 | - scale * spc->h_oversample, | |
4089 | - scale * spc->v_oversample, | |
4090 | - 0,0, | |
4091 | - glyph); | |
4092 | - | |
4093 | - if (spc->h_oversample > 1) | |
4094 | - stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, | |
4095 | - r->w, r->h, spc->stride_in_bytes, | |
4096 | - spc->h_oversample); | |
4097 | - | |
4098 | - if (spc->v_oversample > 1) | |
4099 | - stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, | |
4100 | - r->w, r->h, spc->stride_in_bytes, | |
4101 | - spc->v_oversample); | |
4102 | - | |
4103 | - bc->x0 = (stbtt_int16) r->x; | |
4104 | - bc->y0 = (stbtt_int16) r->y; | |
4105 | - bc->x1 = (stbtt_int16) (r->x + r->w); | |
4106 | - bc->y1 = (stbtt_int16) (r->y + r->h); | |
4107 | - bc->xadvance = scale * advance; | |
4108 | - bc->xoff = (float) x0 * recip_h + sub_x; | |
4109 | - bc->yoff = (float) y0 * recip_v + sub_y; | |
4110 | - bc->xoff2 = (x0 + r->w) * recip_h + sub_x; | |
4111 | - bc->yoff2 = (y0 + r->h) * recip_v + sub_y; | |
4112 | - } else { | |
4113 | - return_value = 0; // if any fail, report failure | |
4114 | - } | |
4115 | - | |
4116 | - ++k; | |
4117 | - } | |
4118 | - } | |
4119 | - | |
4120 | - // restore original values | |
4121 | - spc->h_oversample = old_h_over; | |
4122 | - spc->v_oversample = old_v_over; | |
4123 | - | |
4124 | - return return_value; | |
4125 | -} | |
4126 | - | |
4127 | -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) | |
4128 | -{ | |
4129 | - stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); | |
4130 | -} | |
4131 | - | |
4132 | -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) | |
4133 | -{ | |
4134 | - stbtt_fontinfo info; | |
4135 | - int i,j,n, return_value = 1; | |
4136 | - //stbrp_context *context = (stbrp_context *) spc->pack_info; | |
4137 | - stbrp_rect *rects; | |
4138 | - | |
4139 | - // flag all characters as NOT packed | |
4140 | - for (i=0; i < num_ranges; ++i) | |
4141 | - for (j=0; j < ranges[i].num_chars; ++j) | |
4142 | - ranges[i].chardata_for_range[j].x0 = | |
4143 | - ranges[i].chardata_for_range[j].y0 = | |
4144 | - ranges[i].chardata_for_range[j].x1 = | |
4145 | - ranges[i].chardata_for_range[j].y1 = 0; | |
4146 | - | |
4147 | - n = 0; | |
4148 | - for (i=0; i < num_ranges; ++i) | |
4149 | - n += ranges[i].num_chars; | |
4150 | - | |
4151 | - rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); | |
4152 | - if (rects == NULL) | |
4153 | - return 0; | |
4154 | - | |
4155 | - info.userdata = spc->user_allocator_context; | |
4156 | - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); | |
4157 | - | |
4158 | - n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); | |
4159 | - | |
4160 | - stbtt_PackFontRangesPackRects(spc, rects, n); | |
4161 | - | |
4162 | - return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); | |
4163 | - | |
4164 | - STBTT_free(rects, spc->user_allocator_context); | |
4165 | - return return_value; | |
4166 | -} | |
4167 | - | |
4168 | -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, | |
4169 | - int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) | |
4170 | -{ | |
4171 | - stbtt_pack_range range; | |
4172 | - range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; | |
4173 | - range.array_of_unicode_codepoints = NULL; | |
4174 | - range.num_chars = num_chars_in_range; | |
4175 | - range.chardata_for_range = chardata_for_range; | |
4176 | - range.font_size = font_size; | |
4177 | - return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); | |
4178 | -} | |
4179 | - | |
4180 | -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) | |
4181 | -{ | |
4182 | - int i_ascent, i_descent, i_lineGap; | |
4183 | - float scale; | |
4184 | - stbtt_fontinfo info; | |
4185 | - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); | |
4186 | - scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); | |
4187 | - stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); | |
4188 | - *ascent = (float) i_ascent * scale; | |
4189 | - *descent = (float) i_descent * scale; | |
4190 | - *lineGap = (float) i_lineGap * scale; | |
4191 | -} | |
4192 | - | |
4193 | -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) | |
4194 | -{ | |
4195 | - float ipw = 1.0f / pw, iph = 1.0f / ph; | |
4196 | - const stbtt_packedchar *b = chardata + char_index; | |
4197 | - | |
4198 | - if (align_to_integer) { | |
4199 | - float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); | |
4200 | - float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); | |
4201 | - q->x0 = x; | |
4202 | - q->y0 = y; | |
4203 | - q->x1 = x + b->xoff2 - b->xoff; | |
4204 | - q->y1 = y + b->yoff2 - b->yoff; | |
4205 | - } else { | |
4206 | - q->x0 = *xpos + b->xoff; | |
4207 | - q->y0 = *ypos + b->yoff; | |
4208 | - q->x1 = *xpos + b->xoff2; | |
4209 | - q->y1 = *ypos + b->yoff2; | |
4210 | - } | |
4211 | - | |
4212 | - q->s0 = b->x0 * ipw; | |
4213 | - q->t0 = b->y0 * iph; | |
4214 | - q->s1 = b->x1 * ipw; | |
4215 | - q->t1 = b->y1 * iph; | |
4216 | - | |
4217 | - *xpos += b->xadvance; | |
4218 | -} | |
4219 | - | |
4220 | -////////////////////////////////////////////////////////////////////////////// | |
4221 | -// | |
4222 | -// sdf computation | |
4223 | -// | |
4224 | - | |
4225 | -#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) | |
4226 | -#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) | |
4227 | - | |
4228 | -static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) | |
4229 | -{ | |
4230 | - float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; | |
4231 | - float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; | |
4232 | - float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; | |
4233 | - float roperp = orig[1]*ray[0] - orig[0]*ray[1]; | |
4234 | - | |
4235 | - float a = q0perp - 2*q1perp + q2perp; | |
4236 | - float b = q1perp - q0perp; | |
4237 | - float c = q0perp - roperp; | |
4238 | - | |
4239 | - float s0 = 0., s1 = 0.; | |
4240 | - int num_s = 0; | |
4241 | - | |
4242 | - if (a != 0.0) { | |
4243 | - float discr = b*b - a*c; | |
4244 | - if (discr > 0.0) { | |
4245 | - float rcpna = -1 / a; | |
4246 | - float d = (float) STBTT_sqrt(discr); | |
4247 | - s0 = (b+d) * rcpna; | |
4248 | - s1 = (b-d) * rcpna; | |
4249 | - if (s0 >= 0.0 && s0 <= 1.0) | |
4250 | - num_s = 1; | |
4251 | - if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { | |
4252 | - if (num_s == 0) s0 = s1; | |
4253 | - ++num_s; | |
4254 | - } | |
4255 | - } | |
4256 | - } else { | |
4257 | - // 2*b*s + c = 0 | |
4258 | - // s = -c / (2*b) | |
4259 | - s0 = c / (-2 * b); | |
4260 | - if (s0 >= 0.0 && s0 <= 1.0) | |
4261 | - num_s = 1; | |
4262 | - } | |
4263 | - | |
4264 | - if (num_s == 0) | |
4265 | - return 0; | |
4266 | - else { | |
4267 | - float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); | |
4268 | - float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; | |
4269 | - | |
4270 | - float q0d = q0[0]*rayn_x + q0[1]*rayn_y; | |
4271 | - float q1d = q1[0]*rayn_x + q1[1]*rayn_y; | |
4272 | - float q2d = q2[0]*rayn_x + q2[1]*rayn_y; | |
4273 | - float rod = orig[0]*rayn_x + orig[1]*rayn_y; | |
4274 | - | |
4275 | - float q10d = q1d - q0d; | |
4276 | - float q20d = q2d - q0d; | |
4277 | - float q0rd = q0d - rod; | |
4278 | - | |
4279 | - hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; | |
4280 | - hits[0][1] = a*s0+b; | |
4281 | - | |
4282 | - if (num_s > 1) { | |
4283 | - hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; | |
4284 | - hits[1][1] = a*s1+b; | |
4285 | - return 2; | |
4286 | - } else { | |
4287 | - return 1; | |
4288 | - } | |
4289 | - } | |
4290 | -} | |
4291 | - | |
4292 | -static int equal(float *a, float *b) | |
4293 | -{ | |
4294 | - return (a[0] == b[0] && a[1] == b[1]); | |
4295 | -} | |
4296 | - | |
4297 | -static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) | |
4298 | -{ | |
4299 | - int i; | |
4300 | - float orig[2], ray[2] = { 1, 0 }; | |
4301 | - float y_frac; | |
4302 | - int winding = 0; | |
4303 | - | |
4304 | - orig[0] = x; | |
4305 | - //orig[1] = y; // [DEAR IMGUI] commmented double assignment | |
4306 | - | |
4307 | - // make sure y never passes through a vertex of the shape | |
4308 | - y_frac = (float) STBTT_fmod(y, 1.0f); | |
4309 | - if (y_frac < 0.01f) | |
4310 | - y += 0.01f; | |
4311 | - else if (y_frac > 0.99f) | |
4312 | - y -= 0.01f; | |
4313 | - orig[1] = y; | |
4314 | - | |
4315 | - // test a ray from (-infinity,y) to (x,y) | |
4316 | - for (i=0; i < nverts; ++i) { | |
4317 | - if (verts[i].type == STBTT_vline) { | |
4318 | - int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; | |
4319 | - int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; | |
4320 | - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { | |
4321 | - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; | |
4322 | - if (x_inter < x) | |
4323 | - winding += (y0 < y1) ? 1 : -1; | |
4324 | - } | |
4325 | - } | |
4326 | - if (verts[i].type == STBTT_vcurve) { | |
4327 | - int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; | |
4328 | - int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; | |
4329 | - int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; | |
4330 | - int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); | |
4331 | - int by = STBTT_max(y0,STBTT_max(y1,y2)); | |
4332 | - if (y > ay && y < by && x > ax) { | |
4333 | - float q0[2],q1[2],q2[2]; | |
4334 | - float hits[2][2]; | |
4335 | - q0[0] = (float)x0; | |
4336 | - q0[1] = (float)y0; | |
4337 | - q1[0] = (float)x1; | |
4338 | - q1[1] = (float)y1; | |
4339 | - q2[0] = (float)x2; | |
4340 | - q2[1] = (float)y2; | |
4341 | - if (equal(q0,q1) || equal(q1,q2)) { | |
4342 | - x0 = (int)verts[i-1].x; | |
4343 | - y0 = (int)verts[i-1].y; | |
4344 | - x1 = (int)verts[i ].x; | |
4345 | - y1 = (int)verts[i ].y; | |
4346 | - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { | |
4347 | - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; | |
4348 | - if (x_inter < x) | |
4349 | - winding += (y0 < y1) ? 1 : -1; | |
4350 | - } | |
4351 | - } else { | |
4352 | - int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); | |
4353 | - if (num_hits >= 1) | |
4354 | - if (hits[0][0] < 0) | |
4355 | - winding += (hits[0][1] < 0 ? -1 : 1); | |
4356 | - if (num_hits >= 2) | |
4357 | - if (hits[1][0] < 0) | |
4358 | - winding += (hits[1][1] < 0 ? -1 : 1); | |
4359 | - } | |
4360 | - } | |
4361 | - } | |
4362 | - } | |
4363 | - return winding; | |
4364 | -} | |
4365 | - | |
4366 | -static float stbtt__cuberoot( float x ) | |
4367 | -{ | |
4368 | - if (x<0) | |
4369 | - return -(float) STBTT_pow(-x,1.0f/3.0f); | |
4370 | - else | |
4371 | - return (float) STBTT_pow( x,1.0f/3.0f); | |
4372 | -} | |
4373 | - | |
4374 | -// x^3 + c*x^2 + b*x + a = 0 | |
4375 | -static int stbtt__solve_cubic(float a, float b, float c, float* r) | |
4376 | -{ | |
4377 | - float s = -a / 3; | |
4378 | - float p = b - a*a / 3; | |
4379 | - float q = a * (2*a*a - 9*b) / 27 + c; | |
4380 | - float p3 = p*p*p; | |
4381 | - float d = q*q + 4*p3 / 27; | |
4382 | - if (d >= 0) { | |
4383 | - float z = (float) STBTT_sqrt(d); | |
4384 | - float u = (-q + z) / 2; | |
4385 | - float v = (-q - z) / 2; | |
4386 | - u = stbtt__cuberoot(u); | |
4387 | - v = stbtt__cuberoot(v); | |
4388 | - r[0] = s + u + v; | |
4389 | - return 1; | |
4390 | - } else { | |
4391 | - float u = (float) STBTT_sqrt(-p/3); | |
4392 | - float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative | |
4393 | - float m = (float) STBTT_cos(v); | |
4394 | - float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; | |
4395 | - r[0] = s + u * 2 * m; | |
4396 | - r[1] = s - u * (m + n); | |
4397 | - r[2] = s - u * (m - n); | |
4398 | - | |
4399 | - //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? | |
4400 | - //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); | |
4401 | - //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); | |
4402 | - return 3; | |
4403 | - } | |
4404 | -} | |
4405 | - | |
4406 | -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) | |
4407 | -{ | |
4408 | - float scale_x = scale, scale_y = scale; | |
4409 | - int ix0,iy0,ix1,iy1; | |
4410 | - int w,h; | |
4411 | - unsigned char *data; | |
4412 | - | |
4413 | - // if one scale is 0, use same scale for both | |
4414 | - if (scale_x == 0) scale_x = scale_y; | |
4415 | - if (scale_y == 0) { | |
4416 | - if (scale_x == 0) return NULL; // if both scales are 0, return NULL | |
4417 | - scale_y = scale_x; | |
4418 | - } | |
4419 | - | |
4420 | - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); | |
4421 | - | |
4422 | - // if empty, return NULL | |
4423 | - if (ix0 == ix1 || iy0 == iy1) | |
4424 | - return NULL; | |
4425 | - | |
4426 | - ix0 -= padding; | |
4427 | - iy0 -= padding; | |
4428 | - ix1 += padding; | |
4429 | - iy1 += padding; | |
4430 | - | |
4431 | - w = (ix1 - ix0); | |
4432 | - h = (iy1 - iy0); | |
4433 | - | |
4434 | - if (width ) *width = w; | |
4435 | - if (height) *height = h; | |
4436 | - if (xoff ) *xoff = ix0; | |
4437 | - if (yoff ) *yoff = iy0; | |
4438 | - | |
4439 | - // invert for y-downwards bitmaps | |
4440 | - scale_y = -scale_y; | |
4441 | - | |
4442 | - { | |
4443 | - int x,y,i,j; | |
4444 | - float *precompute; | |
4445 | - stbtt_vertex *verts; | |
4446 | - int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); | |
4447 | - data = (unsigned char *) STBTT_malloc(w * h, info->userdata); | |
4448 | - precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); | |
4449 | - | |
4450 | - for (i=0,j=num_verts-1; i < num_verts; j=i++) { | |
4451 | - if (verts[i].type == STBTT_vline) { | |
4452 | - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; | |
4453 | - float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; | |
4454 | - float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); | |
4455 | - precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; | |
4456 | - } else if (verts[i].type == STBTT_vcurve) { | |
4457 | - float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; | |
4458 | - float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; | |
4459 | - float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; | |
4460 | - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; | |
4461 | - float len2 = bx*bx + by*by; | |
4462 | - if (len2 != 0.0f) | |
4463 | - precompute[i] = 1.0f / (bx*bx + by*by); | |
4464 | - else | |
4465 | - precompute[i] = 0.0f; | |
4466 | - } else | |
4467 | - precompute[i] = 0.0f; | |
4468 | - } | |
4469 | - | |
4470 | - for (y=iy0; y < iy1; ++y) { | |
4471 | - for (x=ix0; x < ix1; ++x) { | |
4472 | - float val; | |
4473 | - float min_dist = 999999.0f; | |
4474 | - float sx = (float) x + 0.5f; | |
4475 | - float sy = (float) y + 0.5f; | |
4476 | - float x_gspace = (sx / scale_x); | |
4477 | - float y_gspace = (sy / scale_y); | |
4478 | - | |
4479 | - int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path | |
4480 | - | |
4481 | - for (i=0; i < num_verts; ++i) { | |
4482 | - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; | |
4483 | - | |
4484 | - // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve | |
4485 | - float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); | |
4486 | - if (dist2 < min_dist*min_dist) | |
4487 | - min_dist = (float) STBTT_sqrt(dist2); | |
4488 | - | |
4489 | - if (verts[i].type == STBTT_vline) { | |
4490 | - float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; | |
4491 | - | |
4492 | - // coarse culling against bbox | |
4493 | - //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && | |
4494 | - // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) | |
4495 | - float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; | |
4496 | - STBTT_assert(i != 0); | |
4497 | - if (dist < min_dist) { | |
4498 | - // check position along line | |
4499 | - // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) | |
4500 | - // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) | |
4501 | - float dx = x1-x0, dy = y1-y0; | |
4502 | - float px = x0-sx, py = y0-sy; | |
4503 | - // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy | |
4504 | - // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve | |
4505 | - float t = -(px*dx + py*dy) / (dx*dx + dy*dy); | |
4506 | - if (t >= 0.0f && t <= 1.0f) | |
4507 | - min_dist = dist; | |
4508 | - } | |
4509 | - } else if (verts[i].type == STBTT_vcurve) { | |
4510 | - float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; | |
4511 | - float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; | |
4512 | - float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); | |
4513 | - float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); | |
4514 | - float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); | |
4515 | - float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); | |
4516 | - // coarse culling against bbox to avoid computing cubic unnecessarily | |
4517 | - if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { | |
4518 | - int num=0; | |
4519 | - float ax = x1-x0, ay = y1-y0; | |
4520 | - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; | |
4521 | - float mx = x0 - sx, my = y0 - sy; | |
4522 | - float res[3],px,py,t,it; | |
4523 | - float a_inv = precompute[i]; | |
4524 | - if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula | |
4525 | - float a = 3*(ax*bx + ay*by); | |
4526 | - float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); | |
4527 | - float c = mx*ax+my*ay; | |
4528 | - if (a == 0.0) { // if a is 0, it's linear | |
4529 | - if (b != 0.0) { | |
4530 | - res[num++] = -c/b; | |
4531 | - } | |
4532 | - } else { | |
4533 | - float discriminant = b*b - 4*a*c; | |
4534 | - if (discriminant < 0) | |
4535 | - num = 0; | |
4536 | - else { | |
4537 | - float root = (float) STBTT_sqrt(discriminant); | |
4538 | - res[0] = (-b - root)/(2*a); | |
4539 | - res[1] = (-b + root)/(2*a); | |
4540 | - num = 2; // don't bother distinguishing 1-solution case, as code below will still work | |
4541 | - } | |
4542 | - } | |
4543 | - } else { | |
4544 | - float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point | |
4545 | - float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; | |
4546 | - float d = (mx*ax+my*ay) * a_inv; | |
4547 | - num = stbtt__solve_cubic(b, c, d, res); | |
4548 | - } | |
4549 | - if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { | |
4550 | - t = res[0], it = 1.0f - t; | |
4551 | - px = it*it*x0 + 2*t*it*x1 + t*t*x2; | |
4552 | - py = it*it*y0 + 2*t*it*y1 + t*t*y2; | |
4553 | - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); | |
4554 | - if (dist2 < min_dist * min_dist) | |
4555 | - min_dist = (float) STBTT_sqrt(dist2); | |
4556 | - } | |
4557 | - if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { | |
4558 | - t = res[1], it = 1.0f - t; | |
4559 | - px = it*it*x0 + 2*t*it*x1 + t*t*x2; | |
4560 | - py = it*it*y0 + 2*t*it*y1 + t*t*y2; | |
4561 | - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); | |
4562 | - if (dist2 < min_dist * min_dist) | |
4563 | - min_dist = (float) STBTT_sqrt(dist2); | |
4564 | - } | |
4565 | - if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { | |
4566 | - t = res[2], it = 1.0f - t; | |
4567 | - px = it*it*x0 + 2*t*it*x1 + t*t*x2; | |
4568 | - py = it*it*y0 + 2*t*it*y1 + t*t*y2; | |
4569 | - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); | |
4570 | - if (dist2 < min_dist * min_dist) | |
4571 | - min_dist = (float) STBTT_sqrt(dist2); | |
4572 | - } | |
4573 | - } | |
4574 | - } | |
4575 | - } | |
4576 | - if (winding == 0) | |
4577 | - min_dist = -min_dist; // if outside the shape, value is negative | |
4578 | - val = onedge_value + pixel_dist_scale * min_dist; | |
4579 | - if (val < 0) | |
4580 | - val = 0; | |
4581 | - else if (val > 255) | |
4582 | - val = 255; | |
4583 | - data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; | |
4584 | - } | |
4585 | - } | |
4586 | - STBTT_free(precompute, info->userdata); | |
4587 | - STBTT_free(verts, info->userdata); | |
4588 | - } | |
4589 | - return data; | |
4590 | -} | |
4591 | - | |
4592 | -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) | |
4593 | -{ | |
4594 | - return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); | |
4595 | -} | |
4596 | - | |
4597 | -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) | |
4598 | -{ | |
4599 | - STBTT_free(bitmap, userdata); | |
4600 | -} | |
4601 | - | |
4602 | -////////////////////////////////////////////////////////////////////////////// | |
4603 | -// | |
4604 | -// font name matching -- recommended not to use this | |
4605 | -// | |
4606 | - | |
4607 | -// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string | |
4608 | -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) | |
4609 | -{ | |
4610 | - stbtt_int32 i=0; | |
4611 | - | |
4612 | - // convert utf16 to utf8 and compare the results while converting | |
4613 | - while (len2) { | |
4614 | - stbtt_uint16 ch = s2[0]*256 + s2[1]; | |
4615 | - if (ch < 0x80) { | |
4616 | - if (i >= len1) return -1; | |
4617 | - if (s1[i++] != ch) return -1; | |
4618 | - } else if (ch < 0x800) { | |
4619 | - if (i+1 >= len1) return -1; | |
4620 | - if (s1[i++] != 0xc0 + (ch >> 6)) return -1; | |
4621 | - if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; | |
4622 | - } else if (ch >= 0xd800 && ch < 0xdc00) { | |
4623 | - stbtt_uint32 c; | |
4624 | - stbtt_uint16 ch2 = s2[2]*256 + s2[3]; | |
4625 | - if (i+3 >= len1) return -1; | |
4626 | - c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; | |
4627 | - if (s1[i++] != 0xf0 + (c >> 18)) return -1; | |
4628 | - if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; | |
4629 | - if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; | |
4630 | - if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; | |
4631 | - s2 += 2; // plus another 2 below | |
4632 | - len2 -= 2; | |
4633 | - } else if (ch >= 0xdc00 && ch < 0xe000) { | |
4634 | - return -1; | |
4635 | - } else { | |
4636 | - if (i+2 >= len1) return -1; | |
4637 | - if (s1[i++] != 0xe0 + (ch >> 12)) return -1; | |
4638 | - if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; | |
4639 | - if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; | |
4640 | - } | |
4641 | - s2 += 2; | |
4642 | - len2 -= 2; | |
4643 | - } | |
4644 | - return i; | |
4645 | -} | |
4646 | - | |
4647 | -static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) | |
4648 | -{ | |
4649 | - return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); | |
4650 | -} | |
4651 | - | |
4652 | -// returns results in whatever encoding you request... but note that 2-byte encodings | |
4653 | -// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare | |
4654 | -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) | |
4655 | -{ | |
4656 | - stbtt_int32 i,count,stringOffset; | |
4657 | - stbtt_uint8 *fc = font->data; | |
4658 | - stbtt_uint32 offset = font->fontstart; | |
4659 | - stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); | |
4660 | - if (!nm) return NULL; | |
4661 | - | |
4662 | - count = ttUSHORT(fc+nm+2); | |
4663 | - stringOffset = nm + ttUSHORT(fc+nm+4); | |
4664 | - for (i=0; i < count; ++i) { | |
4665 | - stbtt_uint32 loc = nm + 6 + 12 * i; | |
4666 | - if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) | |
4667 | - && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { | |
4668 | - *length = ttUSHORT(fc+loc+8); | |
4669 | - return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); | |
4670 | - } | |
4671 | - } | |
4672 | - return NULL; | |
4673 | -} | |
4674 | - | |
4675 | -static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) | |
4676 | -{ | |
4677 | - stbtt_int32 i; | |
4678 | - stbtt_int32 count = ttUSHORT(fc+nm+2); | |
4679 | - stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); | |
4680 | - | |
4681 | - for (i=0; i < count; ++i) { | |
4682 | - stbtt_uint32 loc = nm + 6 + 12 * i; | |
4683 | - stbtt_int32 id = ttUSHORT(fc+loc+6); | |
4684 | - if (id == target_id) { | |
4685 | - // find the encoding | |
4686 | - stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); | |
4687 | - | |
4688 | - // is this a Unicode encoding? | |
4689 | - if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { | |
4690 | - stbtt_int32 slen = ttUSHORT(fc+loc+8); | |
4691 | - stbtt_int32 off = ttUSHORT(fc+loc+10); | |
4692 | - | |
4693 | - // check if there's a prefix match | |
4694 | - stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); | |
4695 | - if (matchlen >= 0) { | |
4696 | - // check for target_id+1 immediately following, with same encoding & language | |
4697 | - 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) { | |
4698 | - slen = ttUSHORT(fc+loc+12+8); | |
4699 | - off = ttUSHORT(fc+loc+12+10); | |
4700 | - if (slen == 0) { | |
4701 | - if (matchlen == nlen) | |
4702 | - return 1; | |
4703 | - } else if (matchlen < nlen && name[matchlen] == ' ') { | |
4704 | - ++matchlen; | |
4705 | - if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) | |
4706 | - return 1; | |
4707 | - } | |
4708 | - } else { | |
4709 | - // if nothing immediately following | |
4710 | - if (matchlen == nlen) | |
4711 | - return 1; | |
4712 | - } | |
4713 | - } | |
4714 | - } | |
4715 | - | |
4716 | - // @TODO handle other encodings | |
4717 | - } | |
4718 | - } | |
4719 | - return 0; | |
4720 | -} | |
4721 | - | |
4722 | -static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) | |
4723 | -{ | |
4724 | - stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); | |
4725 | - stbtt_uint32 nm,hd; | |
4726 | - if (!stbtt__isfont(fc+offset)) return 0; | |
4727 | - | |
4728 | - // check italics/bold/underline flags in macStyle... | |
4729 | - if (flags) { | |
4730 | - hd = stbtt__find_table(fc, offset, "head"); | |
4731 | - if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; | |
4732 | - } | |
4733 | - | |
4734 | - nm = stbtt__find_table(fc, offset, "name"); | |
4735 | - if (!nm) return 0; | |
4736 | - | |
4737 | - if (flags) { | |
4738 | - // if we checked the macStyle flags, then just check the family and ignore the subfamily | |
4739 | - if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; | |
4740 | - if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; | |
4741 | - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; | |
4742 | - } else { | |
4743 | - if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; | |
4744 | - if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; | |
4745 | - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; | |
4746 | - } | |
4747 | - | |
4748 | - return 0; | |
4749 | -} | |
4750 | - | |
4751 | -static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) | |
4752 | -{ | |
4753 | - stbtt_int32 i; | |
4754 | - for (i=0;;++i) { | |
4755 | - stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); | |
4756 | - if (off < 0) return off; | |
4757 | - if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) | |
4758 | - return off; | |
4759 | - } | |
4760 | -} | |
4761 | - | |
4762 | -#if defined(__GNUC__) || defined(__clang__) | |
4763 | -#pragma GCC diagnostic push | |
4764 | -#pragma GCC diagnostic ignored "-Wcast-qual" | |
4765 | -#endif | |
4766 | - | |
4767 | -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, | |
4768 | - float pixel_height, unsigned char *pixels, int pw, int ph, | |
4769 | - int first_char, int num_chars, stbtt_bakedchar *chardata) | |
4770 | -{ | |
4771 | - return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); | |
4772 | -} | |
4773 | - | |
4774 | -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) | |
4775 | -{ | |
4776 | - return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); | |
4777 | -} | |
4778 | - | |
4779 | -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) | |
4780 | -{ | |
4781 | - return stbtt_GetNumberOfFonts_internal((unsigned char *) data); | |
4782 | -} | |
4783 | - | |
4784 | -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) | |
4785 | -{ | |
4786 | - return stbtt_InitFont_internal(info, (unsigned char *) data, offset); | |
4787 | -} | |
4788 | - | |
4789 | -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) | |
4790 | -{ | |
4791 | - return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); | |
4792 | -} | |
4793 | - | |
4794 | -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) | |
4795 | -{ | |
4796 | - return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); | |
4797 | -} | |
4798 | - | |
4799 | -#if defined(__GNUC__) || defined(__clang__) | |
4800 | -#pragma GCC diagnostic pop | |
4801 | -#endif | |
4802 | - | |
4803 | -#endif // STB_TRUETYPE_IMPLEMENTATION | |
4804 | - | |
4805 | - | |
4806 | -// FULL VERSION HISTORY | |
4807 | -// | |
4808 | -// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod | |
4809 | -// 1.18 (2018-01-29) add missing function | |
4810 | -// 1.17 (2017-07-23) make more arguments const; doc fix | |
4811 | -// 1.16 (2017-07-12) SDF support | |
4812 | -// 1.15 (2017-03-03) make more arguments const | |
4813 | -// 1.14 (2017-01-16) num-fonts-in-TTC function | |
4814 | -// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts | |
4815 | -// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual | |
4816 | -// 1.11 (2016-04-02) fix unused-variable warning | |
4817 | -// 1.10 (2016-04-02) allow user-defined fabs() replacement | |
4818 | -// fix memory leak if fontsize=0.0 | |
4819 | -// fix warning from duplicate typedef | |
4820 | -// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges | |
4821 | -// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges | |
4822 | -// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; | |
4823 | -// allow PackFontRanges to pack and render in separate phases; | |
4824 | -// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); | |
4825 | -// fixed an assert() bug in the new rasterizer | |
4826 | -// replace assert() with STBTT_assert() in new rasterizer | |
4827 | -// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) | |
4828 | -// also more precise AA rasterizer, except if shapes overlap | |
4829 | -// remove need for STBTT_sort | |
4830 | -// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC | |
4831 | -// 1.04 (2015-04-15) typo in example | |
4832 | -// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes | |
4833 | -// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ | |
4834 | -// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match | |
4835 | -// non-oversampled; STBTT_POINT_SIZE for packed case only | |
4836 | -// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling | |
4837 | -// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) | |
4838 | -// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID | |
4839 | -// 0.8b (2014-07-07) fix a warning | |
4840 | -// 0.8 (2014-05-25) fix a few more warnings | |
4841 | -// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back | |
4842 | -// 0.6c (2012-07-24) improve documentation | |
4843 | -// 0.6b (2012-07-20) fix a few more warnings | |
4844 | -// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, | |
4845 | -// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty | |
4846 | -// 0.5 (2011-12-09) bugfixes: | |
4847 | -// subpixel glyph renderer computed wrong bounding box | |
4848 | -// first vertex of shape can be off-curve (FreeSans) | |
4849 | -// 0.4b (2011-12-03) fixed an error in the font baking example | |
4850 | -// 0.4 (2011-12-01) kerning, subpixel rendering (tor) | |
4851 | -// bugfixes for: | |
4852 | -// codepoint-to-glyph conversion using table fmt=12 | |
4853 | -// codepoint-to-glyph conversion using table fmt=4 | |
4854 | -// stbtt_GetBakedQuad with non-square texture (Zer) | |
4855 | -// updated Hello World! sample to use kerning and subpixel | |
4856 | -// fixed some warnings | |
4857 | -// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) | |
4858 | -// userdata, malloc-from-userdata, non-zero fill (stb) | |
4859 | -// 0.2 (2009-03-11) Fix unsigned/signed char warnings | |
4860 | -// 0.1 (2009-03-09) First public release | |
4861 | -// | |
4862 | - | |
4863 | -/* | |
4864 | ------------------------------------------------------------------------------- | |
4865 | -This software is available under 2 licenses -- choose whichever you prefer. | |
4866 | ------------------------------------------------------------------------------- | |
4867 | -ALTERNATIVE A - MIT License | |
4868 | -Copyright (c) 2017 Sean Barrett | |
4869 | -Permission is hereby granted, free of charge, to any person obtaining a copy of | |
4870 | -this software and associated documentation files (the "Software"), to deal in | |
4871 | -the Software without restriction, including without limitation the rights to | |
4872 | -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
4873 | -of the Software, and to permit persons to whom the Software is furnished to do | |
4874 | -so, subject to the following conditions: | |
4875 | -The above copyright notice and this permission notice shall be included in all | |
4876 | -copies or substantial portions of the Software. | |
4877 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
4878 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
4879 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
4880 | -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
4881 | -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
4882 | -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
4883 | -SOFTWARE. | |
4884 | ------------------------------------------------------------------------------- | |
4885 | -ALTERNATIVE B - Public Domain (www.unlicense.org) | |
4886 | -This is free and unencumbered software released into the public domain. | |
4887 | -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this | |
4888 | -software, either in source code form or as a compiled binary, for any purpose, | |
4889 | -commercial or non-commercial, and by any means. | |
4890 | -In jurisdictions that recognize copyright laws, the author or authors of this | |
4891 | -software dedicate any and all copyright interest in the software to the public | |
4892 | -domain. We make this dedication for the benefit of the public at large and to | |
4893 | -the detriment of our heirs and successors. We intend this dedication to be an | |
4894 | -overt act of relinquishment in perpetuity of all present and future rights to | |
4895 | -this software under copyright law. | |
4896 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
4897 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
4898 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
4899 | -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
4900 | -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
4901 | -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
4902 | ------------------------------------------------------------------------------- | |
4903 | -*/ |
@@ -1,1417 +0,0 @@ | ||
1 | -// [DEAR IMGUI] | |
2 | -// This is a slightly modified version of stb_textedit.h 1.13. | |
3 | -// Those changes would need to be pushed into nothings/stb: | |
4 | -// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) | |
5 | -// Grep for [DEAR IMGUI] to find the changes. | |
6 | - | |
7 | -// stb_textedit.h - v1.13 - public domain - Sean Barrett | |
8 | -// Development of this library was sponsored by RAD Game Tools | |
9 | -// | |
10 | -// This C header file implements the guts of a multi-line text-editing | |
11 | -// widget; you implement display, word-wrapping, and low-level string | |
12 | -// insertion/deletion, and stb_textedit will map user inputs into | |
13 | -// insertions & deletions, plus updates to the cursor position, | |
14 | -// selection state, and undo state. | |
15 | -// | |
16 | -// It is intended for use in games and other systems that need to build | |
17 | -// their own custom widgets and which do not have heavy text-editing | |
18 | -// requirements (this library is not recommended for use for editing large | |
19 | -// texts, as its performance does not scale and it has limited undo). | |
20 | -// | |
21 | -// Non-trivial behaviors are modelled after Windows text controls. | |
22 | -// | |
23 | -// | |
24 | -// LICENSE | |
25 | -// | |
26 | -// See end of file for license information. | |
27 | -// | |
28 | -// | |
29 | -// DEPENDENCIES | |
30 | -// | |
31 | -// Uses the C runtime function 'memmove', which you can override | |
32 | -// by defining STB_TEXTEDIT_memmove before the implementation. | |
33 | -// Uses no other functions. Performs no runtime allocations. | |
34 | -// | |
35 | -// | |
36 | -// VERSION HISTORY | |
37 | -// | |
38 | -// 1.13 (2019-02-07) fix bug in undo size management | |
39 | -// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash | |
40 | -// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield | |
41 | -// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual | |
42 | -// 1.9 (2016-08-27) customizable move-by-word | |
43 | -// 1.8 (2016-04-02) better keyboard handling when mouse button is down | |
44 | -// 1.7 (2015-09-13) change y range handling in case baseline is non-0 | |
45 | -// 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove | |
46 | -// 1.5 (2014-09-10) add support for secondary keys for OS X | |
47 | -// 1.4 (2014-08-17) fix signed/unsigned warnings | |
48 | -// 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary | |
49 | -// 1.2 (2014-05-27) fix some RAD types that had crept into the new code | |
50 | -// 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) | |
51 | -// 1.0 (2012-07-26) improve documentation, initial public release | |
52 | -// 0.3 (2012-02-24) bugfixes, single-line mode; insert mode | |
53 | -// 0.2 (2011-11-28) fixes to undo/redo | |
54 | -// 0.1 (2010-07-08) initial version | |
55 | -// | |
56 | -// ADDITIONAL CONTRIBUTORS | |
57 | -// | |
58 | -// Ulf Winklemann: move-by-word in 1.1 | |
59 | -// Fabian Giesen: secondary key inputs in 1.5 | |
60 | -// Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 | |
61 | -// | |
62 | -// Bugfixes: | |
63 | -// Scott Graham | |
64 | -// Daniel Keller | |
65 | -// Omar Cornut | |
66 | -// Dan Thompson | |
67 | -// | |
68 | -// USAGE | |
69 | -// | |
70 | -// This file behaves differently depending on what symbols you define | |
71 | -// before including it. | |
72 | -// | |
73 | -// | |
74 | -// Header-file mode: | |
75 | -// | |
76 | -// If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, | |
77 | -// it will operate in "header file" mode. In this mode, it declares a | |
78 | -// single public symbol, STB_TexteditState, which encapsulates the current | |
79 | -// state of a text widget (except for the string, which you will store | |
80 | -// separately). | |
81 | -// | |
82 | -// To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a | |
83 | -// primitive type that defines a single character (e.g. char, wchar_t, etc). | |
84 | -// | |
85 | -// To save space or increase undo-ability, you can optionally define the | |
86 | -// following things that are used by the undo system: | |
87 | -// | |
88 | -// STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position | |
89 | -// STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow | |
90 | -// STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer | |
91 | -// | |
92 | -// If you don't define these, they are set to permissive types and | |
93 | -// moderate sizes. The undo system does no memory allocations, so | |
94 | -// it grows STB_TexteditState by the worst-case storage which is (in bytes): | |
95 | -// | |
96 | -// [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT | |
97 | -// + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT | |
98 | -// | |
99 | -// | |
100 | -// Implementation mode: | |
101 | -// | |
102 | -// If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it | |
103 | -// will compile the implementation of the text edit widget, depending | |
104 | -// on a large number of symbols which must be defined before the include. | |
105 | -// | |
106 | -// The implementation is defined only as static functions. You will then | |
107 | -// need to provide your own APIs in the same file which will access the | |
108 | -// static functions. | |
109 | -// | |
110 | -// The basic concept is that you provide a "string" object which | |
111 | -// behaves like an array of characters. stb_textedit uses indices to | |
112 | -// refer to positions in the string, implicitly representing positions | |
113 | -// in the displayed textedit. This is true for both plain text and | |
114 | -// rich text; even with rich text stb_truetype interacts with your | |
115 | -// code as if there was an array of all the displayed characters. | |
116 | -// | |
117 | -// Symbols that must be the same in header-file and implementation mode: | |
118 | -// | |
119 | -// STB_TEXTEDIT_CHARTYPE the character type | |
120 | -// STB_TEXTEDIT_POSITIONTYPE small type that is a valid cursor position | |
121 | -// STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow | |
122 | -// STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer | |
123 | -// | |
124 | -// Symbols you must define for implementation mode: | |
125 | -// | |
126 | -// STB_TEXTEDIT_STRING the type of object representing a string being edited, | |
127 | -// typically this is a wrapper object with other data you need | |
128 | -// | |
129 | -// STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) | |
130 | -// STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters | |
131 | -// starting from character #n (see discussion below) | |
132 | -// STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character | |
133 | -// to the xpos of the i+1'th char for a line of characters | |
134 | -// starting at character #n (i.e. accounts for kerning | |
135 | -// with previous char) | |
136 | -// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character | |
137 | -// (return type is int, -1 means not valid to insert) | |
138 | -// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based | |
139 | -// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize | |
140 | -// as manually wordwrapping for end-of-line positioning | |
141 | -// | |
142 | -// STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i | |
143 | -// STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) | |
144 | -// | |
145 | -// STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key | |
146 | -// | |
147 | -// STB_TEXTEDIT_K_LEFT keyboard input to move cursor left | |
148 | -// STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right | |
149 | -// STB_TEXTEDIT_K_UP keyboard input to move cursor up | |
150 | -// STB_TEXTEDIT_K_DOWN keyboard input to move cursor down | |
151 | -// STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME | |
152 | -// STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END | |
153 | -// STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME | |
154 | -// STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END | |
155 | -// STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor | |
156 | -// STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor | |
157 | -// STB_TEXTEDIT_K_UNDO keyboard input to perform undo | |
158 | -// STB_TEXTEDIT_K_REDO keyboard input to perform redo | |
159 | -// | |
160 | -// Optional: | |
161 | -// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode | |
162 | -// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), | |
163 | -// required for default WORDLEFT/WORDRIGHT handlers | |
164 | -// STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to | |
165 | -// STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to | |
166 | -// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT | |
167 | -// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT | |
168 | -// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line | |
169 | -// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line | |
170 | -// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text | |
171 | -// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text | |
172 | -// | |
173 | -// Todo: | |
174 | -// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page | |
175 | -// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page | |
176 | -// | |
177 | -// Keyboard input must be encoded as a single integer value; e.g. a character code | |
178 | -// and some bitflags that represent shift states. to simplify the interface, SHIFT must | |
179 | -// be a bitflag, so we can test the shifted state of cursor movements to allow selection, | |
180 | -// i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. | |
181 | -// | |
182 | -// You can encode other things, such as CONTROL or ALT, in additional bits, and | |
183 | -// then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, | |
184 | -// my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN | |
185 | -// bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, | |
186 | -// and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the | |
187 | -// API below. The control keys will only match WM_KEYDOWN events because of the | |
188 | -// keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN | |
189 | -// bit so it only decodes WM_CHAR events. | |
190 | -// | |
191 | -// STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed | |
192 | -// row of characters assuming they start on the i'th character--the width and | |
193 | -// the height and the number of characters consumed. This allows this library | |
194 | -// to traverse the entire layout incrementally. You need to compute word-wrapping | |
195 | -// here. | |
196 | -// | |
197 | -// Each textfield keeps its own insert mode state, which is not how normal | |
198 | -// applications work. To keep an app-wide insert mode, update/copy the | |
199 | -// "insert_mode" field of STB_TexteditState before/after calling API functions. | |
200 | -// | |
201 | -// API | |
202 | -// | |
203 | -// void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) | |
204 | -// | |
205 | -// void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) | |
206 | -// void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) | |
207 | -// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) | |
208 | -// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) | |
209 | -// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) | |
210 | -// | |
211 | -// Each of these functions potentially updates the string and updates the | |
212 | -// state. | |
213 | -// | |
214 | -// initialize_state: | |
215 | -// set the textedit state to a known good default state when initially | |
216 | -// constructing the textedit. | |
217 | -// | |
218 | -// click: | |
219 | -// call this with the mouse x,y on a mouse down; it will update the cursor | |
220 | -// and reset the selection start/end to the cursor point. the x,y must | |
221 | -// be relative to the text widget, with (0,0) being the top left. | |
222 | -// | |
223 | -// drag: | |
224 | -// call this with the mouse x,y on a mouse drag/up; it will update the | |
225 | -// cursor and the selection end point | |
226 | -// | |
227 | -// cut: | |
228 | -// call this to delete the current selection; returns true if there was | |
229 | -// one. you should FIRST copy the current selection to the system paste buffer. | |
230 | -// (To copy, just copy the current selection out of the string yourself.) | |
231 | -// | |
232 | -// paste: | |
233 | -// call this to paste text at the current cursor point or over the current | |
234 | -// selection if there is one. | |
235 | -// | |
236 | -// key: | |
237 | -// call this for keyboard inputs sent to the textfield. you can use it | |
238 | -// for "key down" events or for "translated" key events. if you need to | |
239 | -// do both (as in Win32), or distinguish Unicode characters from control | |
240 | -// inputs, set a high bit to distinguish the two; then you can define the | |
241 | -// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit | |
242 | -// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is | |
243 | -// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to | |
244 | -// anything other type you wante before including. | |
245 | -// | |
246 | -// | |
247 | -// When rendering, you can read the cursor position and selection state from | |
248 | -// the STB_TexteditState. | |
249 | -// | |
250 | -// | |
251 | -// Notes: | |
252 | -// | |
253 | -// This is designed to be usable in IMGUI, so it allows for the possibility of | |
254 | -// running in an IMGUI that has NOT cached the multi-line layout. For this | |
255 | -// reason, it provides an interface that is compatible with computing the | |
256 | -// layout incrementally--we try to make sure we make as few passes through | |
257 | -// as possible. (For example, to locate the mouse pointer in the text, we | |
258 | -// could define functions that return the X and Y positions of characters | |
259 | -// and binary search Y and then X, but if we're doing dynamic layout this | |
260 | -// will run the layout algorithm many times, so instead we manually search | |
261 | -// forward in one pass. Similar logic applies to e.g. up-arrow and | |
262 | -// down-arrow movement.) | |
263 | -// | |
264 | -// If it's run in a widget that *has* cached the layout, then this is less | |
265 | -// efficient, but it's not horrible on modern computers. But you wouldn't | |
266 | -// want to edit million-line files with it. | |
267 | - | |
268 | - | |
269 | -//////////////////////////////////////////////////////////////////////////// | |
270 | -//////////////////////////////////////////////////////////////////////////// | |
271 | -//// | |
272 | -//// Header-file mode | |
273 | -//// | |
274 | -//// | |
275 | - | |
276 | -#ifndef INCLUDE_STB_TEXTEDIT_H | |
277 | -#define INCLUDE_STB_TEXTEDIT_H | |
278 | - | |
279 | -//////////////////////////////////////////////////////////////////////// | |
280 | -// | |
281 | -// STB_TexteditState | |
282 | -// | |
283 | -// Definition of STB_TexteditState which you should store | |
284 | -// per-textfield; it includes cursor position, selection state, | |
285 | -// and undo state. | |
286 | -// | |
287 | - | |
288 | -#ifndef STB_TEXTEDIT_UNDOSTATECOUNT | |
289 | -#define STB_TEXTEDIT_UNDOSTATECOUNT 99 | |
290 | -#endif | |
291 | -#ifndef STB_TEXTEDIT_UNDOCHARCOUNT | |
292 | -#define STB_TEXTEDIT_UNDOCHARCOUNT 999 | |
293 | -#endif | |
294 | -#ifndef STB_TEXTEDIT_CHARTYPE | |
295 | -#define STB_TEXTEDIT_CHARTYPE int | |
296 | -#endif | |
297 | -#ifndef STB_TEXTEDIT_POSITIONTYPE | |
298 | -#define STB_TEXTEDIT_POSITIONTYPE int | |
299 | -#endif | |
300 | - | |
301 | -typedef struct | |
302 | -{ | |
303 | - // private data | |
304 | - STB_TEXTEDIT_POSITIONTYPE where; | |
305 | - STB_TEXTEDIT_POSITIONTYPE insert_length; | |
306 | - STB_TEXTEDIT_POSITIONTYPE delete_length; | |
307 | - int char_storage; | |
308 | -} StbUndoRecord; | |
309 | - | |
310 | -typedef struct | |
311 | -{ | |
312 | - // private data | |
313 | - StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; | |
314 | - STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; | |
315 | - short undo_point, redo_point; | |
316 | - int undo_char_point, redo_char_point; | |
317 | -} StbUndoState; | |
318 | - | |
319 | -typedef struct | |
320 | -{ | |
321 | - ///////////////////// | |
322 | - // | |
323 | - // public data | |
324 | - // | |
325 | - | |
326 | - int cursor; | |
327 | - // position of the text cursor within the string | |
328 | - | |
329 | - int select_start; // selection start point | |
330 | - int select_end; | |
331 | - // selection start and end point in characters; if equal, no selection. | |
332 | - // note that start may be less than or greater than end (e.g. when | |
333 | - // dragging the mouse, start is where the initial click was, and you | |
334 | - // can drag in either direction) | |
335 | - | |
336 | - unsigned char insert_mode; | |
337 | - // each textfield keeps its own insert mode state. to keep an app-wide | |
338 | - // insert mode, copy this value in/out of the app state | |
339 | - | |
340 | - ///////////////////// | |
341 | - // | |
342 | - // private data | |
343 | - // | |
344 | - unsigned char cursor_at_end_of_line; // not implemented yet | |
345 | - unsigned char initialized; | |
346 | - unsigned char has_preferred_x; | |
347 | - unsigned char single_line; | |
348 | - unsigned char padding1, padding2, padding3; | |
349 | - float preferred_x; // this determines where the cursor up/down tries to seek to along x | |
350 | - StbUndoState undostate; | |
351 | -} STB_TexteditState; | |
352 | - | |
353 | - | |
354 | -//////////////////////////////////////////////////////////////////////// | |
355 | -// | |
356 | -// StbTexteditRow | |
357 | -// | |
358 | -// Result of layout query, used by stb_textedit to determine where | |
359 | -// the text in each row is. | |
360 | - | |
361 | -// result of layout query | |
362 | -typedef struct | |
363 | -{ | |
364 | - float x0,x1; // starting x location, end x location (allows for align=right, etc) | |
365 | - float baseline_y_delta; // position of baseline relative to previous row's baseline | |
366 | - float ymin,ymax; // height of row above and below baseline | |
367 | - int num_chars; | |
368 | -} StbTexteditRow; | |
369 | -#endif //INCLUDE_STB_TEXTEDIT_H | |
370 | - | |
371 | - | |
372 | -//////////////////////////////////////////////////////////////////////////// | |
373 | -//////////////////////////////////////////////////////////////////////////// | |
374 | -//// | |
375 | -//// Implementation mode | |
376 | -//// | |
377 | -//// | |
378 | - | |
379 | - | |
380 | -// implementation isn't include-guarded, since it might have indirectly | |
381 | -// included just the "header" portion | |
382 | -#ifdef STB_TEXTEDIT_IMPLEMENTATION | |
383 | - | |
384 | -#ifndef STB_TEXTEDIT_memmove | |
385 | -#include <string.h> | |
386 | -#define STB_TEXTEDIT_memmove memmove | |
387 | -#endif | |
388 | - | |
389 | - | |
390 | -///////////////////////////////////////////////////////////////////////////// | |
391 | -// | |
392 | -// Mouse input handling | |
393 | -// | |
394 | - | |
395 | -// traverse the layout to locate the nearest character to a display position | |
396 | -static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) | |
397 | -{ | |
398 | - StbTexteditRow r; | |
399 | - int n = STB_TEXTEDIT_STRINGLEN(str); | |
400 | - float base_y = 0, prev_x; | |
401 | - int i=0, k; | |
402 | - | |
403 | - r.x0 = r.x1 = 0; | |
404 | - r.ymin = r.ymax = 0; | |
405 | - r.num_chars = 0; | |
406 | - | |
407 | - // search rows to find one that straddles 'y' | |
408 | - while (i < n) { | |
409 | - STB_TEXTEDIT_LAYOUTROW(&r, str, i); | |
410 | - if (r.num_chars <= 0) | |
411 | - return n; | |
412 | - | |
413 | - if (i==0 && y < base_y + r.ymin) | |
414 | - return 0; | |
415 | - | |
416 | - if (y < base_y + r.ymax) | |
417 | - break; | |
418 | - | |
419 | - i += r.num_chars; | |
420 | - base_y += r.baseline_y_delta; | |
421 | - } | |
422 | - | |
423 | - // below all text, return 'after' last character | |
424 | - if (i >= n) | |
425 | - return n; | |
426 | - | |
427 | - // check if it's before the beginning of the line | |
428 | - if (x < r.x0) | |
429 | - return i; | |
430 | - | |
431 | - // check if it's before the end of the line | |
432 | - if (x < r.x1) { | |
433 | - // search characters in row for one that straddles 'x' | |
434 | - prev_x = r.x0; | |
435 | - for (k=0; k < r.num_chars; ++k) { | |
436 | - float w = STB_TEXTEDIT_GETWIDTH(str, i, k); | |
437 | - if (x < prev_x+w) { | |
438 | - if (x < prev_x+w/2) | |
439 | - return k+i; | |
440 | - else | |
441 | - return k+i+1; | |
442 | - } | |
443 | - prev_x += w; | |
444 | - } | |
445 | - // shouldn't happen, but if it does, fall through to end-of-line case | |
446 | - } | |
447 | - | |
448 | - // if the last character is a newline, return that. otherwise return 'after' the last character | |
449 | - if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) | |
450 | - return i+r.num_chars-1; | |
451 | - else | |
452 | - return i+r.num_chars; | |
453 | -} | |
454 | - | |
455 | -// API click: on mouse down, move the cursor to the clicked location, and reset the selection | |
456 | -static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) | |
457 | -{ | |
458 | - // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse | |
459 | - // goes off the top or bottom of the text | |
460 | - if( state->single_line ) | |
461 | - { | |
462 | - StbTexteditRow r; | |
463 | - STB_TEXTEDIT_LAYOUTROW(&r, str, 0); | |
464 | - y = r.ymin; | |
465 | - } | |
466 | - | |
467 | - state->cursor = stb_text_locate_coord(str, x, y); | |
468 | - state->select_start = state->cursor; | |
469 | - state->select_end = state->cursor; | |
470 | - state->has_preferred_x = 0; | |
471 | -} | |
472 | - | |
473 | -// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location | |
474 | -static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) | |
475 | -{ | |
476 | - int p = 0; | |
477 | - | |
478 | - // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse | |
479 | - // goes off the top or bottom of the text | |
480 | - if( state->single_line ) | |
481 | - { | |
482 | - StbTexteditRow r; | |
483 | - STB_TEXTEDIT_LAYOUTROW(&r, str, 0); | |
484 | - y = r.ymin; | |
485 | - } | |
486 | - | |
487 | - if (state->select_start == state->select_end) | |
488 | - state->select_start = state->cursor; | |
489 | - | |
490 | - p = stb_text_locate_coord(str, x, y); | |
491 | - state->cursor = state->select_end = p; | |
492 | -} | |
493 | - | |
494 | -///////////////////////////////////////////////////////////////////////////// | |
495 | -// | |
496 | -// Keyboard input handling | |
497 | -// | |
498 | - | |
499 | -// forward declarations | |
500 | -static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); | |
501 | -static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); | |
502 | -static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); | |
503 | -static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); | |
504 | -static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); | |
505 | - | |
506 | -typedef struct | |
507 | -{ | |
508 | - float x,y; // position of n'th character | |
509 | - float height; // height of line | |
510 | - int first_char, length; // first char of row, and length | |
511 | - int prev_first; // first char of previous row | |
512 | -} StbFindState; | |
513 | - | |
514 | -// find the x/y location of a character, and remember info about the previous row in | |
515 | -// case we get a move-up event (for page up, we'll have to rescan) | |
516 | -static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) | |
517 | -{ | |
518 | - StbTexteditRow r; | |
519 | - int prev_start = 0; | |
520 | - int z = STB_TEXTEDIT_STRINGLEN(str); | |
521 | - int i=0, first; | |
522 | - | |
523 | - if (n == z) { | |
524 | - // if it's at the end, then find the last line -- simpler than trying to | |
525 | - // explicitly handle this case in the regular code | |
526 | - if (single_line) { | |
527 | - STB_TEXTEDIT_LAYOUTROW(&r, str, 0); | |
528 | - find->y = 0; | |
529 | - find->first_char = 0; | |
530 | - find->length = z; | |
531 | - find->height = r.ymax - r.ymin; | |
532 | - find->x = r.x1; | |
533 | - } else { | |
534 | - find->y = 0; | |
535 | - find->x = 0; | |
536 | - find->height = 1; | |
537 | - while (i < z) { | |
538 | - STB_TEXTEDIT_LAYOUTROW(&r, str, i); | |
539 | - prev_start = i; | |
540 | - i += r.num_chars; | |
541 | - } | |
542 | - find->first_char = i; | |
543 | - find->length = 0; | |
544 | - find->prev_first = prev_start; | |
545 | - } | |
546 | - return; | |
547 | - } | |
548 | - | |
549 | - // search rows to find the one that straddles character n | |
550 | - find->y = 0; | |
551 | - | |
552 | - for(;;) { | |
553 | - STB_TEXTEDIT_LAYOUTROW(&r, str, i); | |
554 | - if (n < i + r.num_chars) | |
555 | - break; | |
556 | - prev_start = i; | |
557 | - i += r.num_chars; | |
558 | - find->y += r.baseline_y_delta; | |
559 | - } | |
560 | - | |
561 | - find->first_char = first = i; | |
562 | - find->length = r.num_chars; | |
563 | - find->height = r.ymax - r.ymin; | |
564 | - find->prev_first = prev_start; | |
565 | - | |
566 | - // now scan to find xpos | |
567 | - find->x = r.x0; | |
568 | - for (i=0; first+i < n; ++i) | |
569 | - find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); | |
570 | -} | |
571 | - | |
572 | -#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) | |
573 | - | |
574 | -// make the selection/cursor state valid if client altered the string | |
575 | -static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) | |
576 | -{ | |
577 | - int n = STB_TEXTEDIT_STRINGLEN(str); | |
578 | - if (STB_TEXT_HAS_SELECTION(state)) { | |
579 | - if (state->select_start > n) state->select_start = n; | |
580 | - if (state->select_end > n) state->select_end = n; | |
581 | - // if clamping forced them to be equal, move the cursor to match | |
582 | - if (state->select_start == state->select_end) | |
583 | - state->cursor = state->select_start; | |
584 | - } | |
585 | - if (state->cursor > n) state->cursor = n; | |
586 | -} | |
587 | - | |
588 | -// delete characters while updating undo | |
589 | -static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) | |
590 | -{ | |
591 | - stb_text_makeundo_delete(str, state, where, len); | |
592 | - STB_TEXTEDIT_DELETECHARS(str, where, len); | |
593 | - state->has_preferred_x = 0; | |
594 | -} | |
595 | - | |
596 | -// delete the section | |
597 | -static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) | |
598 | -{ | |
599 | - stb_textedit_clamp(str, state); | |
600 | - if (STB_TEXT_HAS_SELECTION(state)) { | |
601 | - if (state->select_start < state->select_end) { | |
602 | - stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); | |
603 | - state->select_end = state->cursor = state->select_start; | |
604 | - } else { | |
605 | - stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); | |
606 | - state->select_start = state->cursor = state->select_end; | |
607 | - } | |
608 | - state->has_preferred_x = 0; | |
609 | - } | |
610 | -} | |
611 | - | |
612 | -// canoncialize the selection so start <= end | |
613 | -static void stb_textedit_sortselection(STB_TexteditState *state) | |
614 | -{ | |
615 | - if (state->select_end < state->select_start) { | |
616 | - int temp = state->select_end; | |
617 | - state->select_end = state->select_start; | |
618 | - state->select_start = temp; | |
619 | - } | |
620 | -} | |
621 | - | |
622 | -// move cursor to first character of selection | |
623 | -static void stb_textedit_move_to_first(STB_TexteditState *state) | |
624 | -{ | |
625 | - if (STB_TEXT_HAS_SELECTION(state)) { | |
626 | - stb_textedit_sortselection(state); | |
627 | - state->cursor = state->select_start; | |
628 | - state->select_end = state->select_start; | |
629 | - state->has_preferred_x = 0; | |
630 | - } | |
631 | -} | |
632 | - | |
633 | -// move cursor to last character of selection | |
634 | -static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) | |
635 | -{ | |
636 | - if (STB_TEXT_HAS_SELECTION(state)) { | |
637 | - stb_textedit_sortselection(state); | |
638 | - stb_textedit_clamp(str, state); | |
639 | - state->cursor = state->select_end; | |
640 | - state->select_start = state->select_end; | |
641 | - state->has_preferred_x = 0; | |
642 | - } | |
643 | -} | |
644 | - | |
645 | -#ifdef STB_TEXTEDIT_IS_SPACE | |
646 | -static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) | |
647 | -{ | |
648 | - return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; | |
649 | -} | |
650 | - | |
651 | -#ifndef STB_TEXTEDIT_MOVEWORDLEFT | |
652 | -static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) | |
653 | -{ | |
654 | - --c; // always move at least one character | |
655 | - while( c >= 0 && !is_word_boundary( str, c ) ) | |
656 | - --c; | |
657 | - | |
658 | - if( c < 0 ) | |
659 | - c = 0; | |
660 | - | |
661 | - return c; | |
662 | -} | |
663 | -#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous | |
664 | -#endif | |
665 | - | |
666 | -#ifndef STB_TEXTEDIT_MOVEWORDRIGHT | |
667 | -static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) | |
668 | -{ | |
669 | - const int len = STB_TEXTEDIT_STRINGLEN(str); | |
670 | - ++c; // always move at least one character | |
671 | - while( c < len && !is_word_boundary( str, c ) ) | |
672 | - ++c; | |
673 | - | |
674 | - if( c > len ) | |
675 | - c = len; | |
676 | - | |
677 | - return c; | |
678 | -} | |
679 | -#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next | |
680 | -#endif | |
681 | - | |
682 | -#endif | |
683 | - | |
684 | -// update selection and cursor to match each other | |
685 | -static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) | |
686 | -{ | |
687 | - if (!STB_TEXT_HAS_SELECTION(state)) | |
688 | - state->select_start = state->select_end = state->cursor; | |
689 | - else | |
690 | - state->cursor = state->select_end; | |
691 | -} | |
692 | - | |
693 | -// API cut: delete selection | |
694 | -static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) | |
695 | -{ | |
696 | - if (STB_TEXT_HAS_SELECTION(state)) { | |
697 | - stb_textedit_delete_selection(str,state); // implicitly clamps | |
698 | - state->has_preferred_x = 0; | |
699 | - return 1; | |
700 | - } | |
701 | - return 0; | |
702 | -} | |
703 | - | |
704 | -// API paste: replace existing selection with passed-in text | |
705 | -static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) | |
706 | -{ | |
707 | - // if there's a selection, the paste should delete it | |
708 | - stb_textedit_clamp(str, state); | |
709 | - stb_textedit_delete_selection(str,state); | |
710 | - // try to insert the characters | |
711 | - if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { | |
712 | - stb_text_makeundo_insert(state, state->cursor, len); | |
713 | - state->cursor += len; | |
714 | - state->has_preferred_x = 0; | |
715 | - return 1; | |
716 | - } | |
717 | - // remove the undo since we didn't actually insert the characters | |
718 | - if (state->undostate.undo_point) | |
719 | - --state->undostate.undo_point; | |
720 | - return 0; | |
721 | -} | |
722 | - | |
723 | -#ifndef STB_TEXTEDIT_KEYTYPE | |
724 | -#define STB_TEXTEDIT_KEYTYPE int | |
725 | -#endif | |
726 | - | |
727 | -// API key: process a keyboard input | |
728 | -static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) | |
729 | -{ | |
730 | -retry: | |
731 | - switch (key) { | |
732 | - default: { | |
733 | - int c = STB_TEXTEDIT_KEYTOTEXT(key); | |
734 | - if (c > 0) { | |
735 | - STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; | |
736 | - | |
737 | - // can't add newline in single-line mode | |
738 | - if (c == '\n' && state->single_line) | |
739 | - break; | |
740 | - | |
741 | - if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { | |
742 | - stb_text_makeundo_replace(str, state, state->cursor, 1, 1); | |
743 | - STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); | |
744 | - if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { | |
745 | - ++state->cursor; | |
746 | - state->has_preferred_x = 0; | |
747 | - } | |
748 | - } else { | |
749 | - stb_textedit_delete_selection(str,state); // implicitly clamps | |
750 | - if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { | |
751 | - stb_text_makeundo_insert(state, state->cursor, 1); | |
752 | - ++state->cursor; | |
753 | - state->has_preferred_x = 0; | |
754 | - } | |
755 | - } | |
756 | - } | |
757 | - break; | |
758 | - } | |
759 | - | |
760 | -#ifdef STB_TEXTEDIT_K_INSERT | |
761 | - case STB_TEXTEDIT_K_INSERT: | |
762 | - state->insert_mode = !state->insert_mode; | |
763 | - break; | |
764 | -#endif | |
765 | - | |
766 | - case STB_TEXTEDIT_K_UNDO: | |
767 | - stb_text_undo(str, state); | |
768 | - state->has_preferred_x = 0; | |
769 | - break; | |
770 | - | |
771 | - case STB_TEXTEDIT_K_REDO: | |
772 | - stb_text_redo(str, state); | |
773 | - state->has_preferred_x = 0; | |
774 | - break; | |
775 | - | |
776 | - case STB_TEXTEDIT_K_LEFT: | |
777 | - // if currently there's a selection, move cursor to start of selection | |
778 | - if (STB_TEXT_HAS_SELECTION(state)) | |
779 | - stb_textedit_move_to_first(state); | |
780 | - else | |
781 | - if (state->cursor > 0) | |
782 | - --state->cursor; | |
783 | - state->has_preferred_x = 0; | |
784 | - break; | |
785 | - | |
786 | - case STB_TEXTEDIT_K_RIGHT: | |
787 | - // if currently there's a selection, move cursor to end of selection | |
788 | - if (STB_TEXT_HAS_SELECTION(state)) | |
789 | - stb_textedit_move_to_last(str, state); | |
790 | - else | |
791 | - ++state->cursor; | |
792 | - stb_textedit_clamp(str, state); | |
793 | - state->has_preferred_x = 0; | |
794 | - break; | |
795 | - | |
796 | - case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: | |
797 | - stb_textedit_clamp(str, state); | |
798 | - stb_textedit_prep_selection_at_cursor(state); | |
799 | - // move selection left | |
800 | - if (state->select_end > 0) | |
801 | - --state->select_end; | |
802 | - state->cursor = state->select_end; | |
803 | - state->has_preferred_x = 0; | |
804 | - break; | |
805 | - | |
806 | -#ifdef STB_TEXTEDIT_MOVEWORDLEFT | |
807 | - case STB_TEXTEDIT_K_WORDLEFT: | |
808 | - if (STB_TEXT_HAS_SELECTION(state)) | |
809 | - stb_textedit_move_to_first(state); | |
810 | - else { | |
811 | - state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); | |
812 | - stb_textedit_clamp( str, state ); | |
813 | - } | |
814 | - break; | |
815 | - | |
816 | - case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: | |
817 | - if( !STB_TEXT_HAS_SELECTION( state ) ) | |
818 | - stb_textedit_prep_selection_at_cursor(state); | |
819 | - | |
820 | - state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); | |
821 | - state->select_end = state->cursor; | |
822 | - | |
823 | - stb_textedit_clamp( str, state ); | |
824 | - break; | |
825 | -#endif | |
826 | - | |
827 | -#ifdef STB_TEXTEDIT_MOVEWORDRIGHT | |
828 | - case STB_TEXTEDIT_K_WORDRIGHT: | |
829 | - if (STB_TEXT_HAS_SELECTION(state)) | |
830 | - stb_textedit_move_to_last(str, state); | |
831 | - else { | |
832 | - state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); | |
833 | - stb_textedit_clamp( str, state ); | |
834 | - } | |
835 | - break; | |
836 | - | |
837 | - case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: | |
838 | - if( !STB_TEXT_HAS_SELECTION( state ) ) | |
839 | - stb_textedit_prep_selection_at_cursor(state); | |
840 | - | |
841 | - state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); | |
842 | - state->select_end = state->cursor; | |
843 | - | |
844 | - stb_textedit_clamp( str, state ); | |
845 | - break; | |
846 | -#endif | |
847 | - | |
848 | - case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: | |
849 | - stb_textedit_prep_selection_at_cursor(state); | |
850 | - // move selection right | |
851 | - ++state->select_end; | |
852 | - stb_textedit_clamp(str, state); | |
853 | - state->cursor = state->select_end; | |
854 | - state->has_preferred_x = 0; | |
855 | - break; | |
856 | - | |
857 | - case STB_TEXTEDIT_K_DOWN: | |
858 | - case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: { | |
859 | - StbFindState find; | |
860 | - StbTexteditRow row; | |
861 | - int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; | |
862 | - | |
863 | - if (state->single_line) { | |
864 | - // on windows, up&down in single-line behave like left&right | |
865 | - key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); | |
866 | - goto retry; | |
867 | - } | |
868 | - | |
869 | - if (sel) | |
870 | - stb_textedit_prep_selection_at_cursor(state); | |
871 | - else if (STB_TEXT_HAS_SELECTION(state)) | |
872 | - stb_textedit_move_to_last(str,state); | |
873 | - | |
874 | - // compute current position of cursor point | |
875 | - stb_textedit_clamp(str, state); | |
876 | - stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); | |
877 | - | |
878 | - // now find character position down a row | |
879 | - if (find.length) { | |
880 | - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; | |
881 | - float x; | |
882 | - int start = find.first_char + find.length; | |
883 | - state->cursor = start; | |
884 | - STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); | |
885 | - x = row.x0; | |
886 | - for (i=0; i < row.num_chars; ++i) { | |
887 | - float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); | |
888 | - #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE | |
889 | - if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) | |
890 | - break; | |
891 | - #endif | |
892 | - x += dx; | |
893 | - if (x > goal_x) | |
894 | - break; | |
895 | - ++state->cursor; | |
896 | - } | |
897 | - stb_textedit_clamp(str, state); | |
898 | - | |
899 | - state->has_preferred_x = 1; | |
900 | - state->preferred_x = goal_x; | |
901 | - | |
902 | - if (sel) | |
903 | - state->select_end = state->cursor; | |
904 | - } | |
905 | - break; | |
906 | - } | |
907 | - | |
908 | - case STB_TEXTEDIT_K_UP: | |
909 | - case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: { | |
910 | - StbFindState find; | |
911 | - StbTexteditRow row; | |
912 | - int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; | |
913 | - | |
914 | - if (state->single_line) { | |
915 | - // on windows, up&down become left&right | |
916 | - key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); | |
917 | - goto retry; | |
918 | - } | |
919 | - | |
920 | - if (sel) | |
921 | - stb_textedit_prep_selection_at_cursor(state); | |
922 | - else if (STB_TEXT_HAS_SELECTION(state)) | |
923 | - stb_textedit_move_to_first(state); | |
924 | - | |
925 | - // compute current position of cursor point | |
926 | - stb_textedit_clamp(str, state); | |
927 | - stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); | |
928 | - | |
929 | - // can only go up if there's a previous row | |
930 | - if (find.prev_first != find.first_char) { | |
931 | - // now find character position up a row | |
932 | - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; | |
933 | - float x; | |
934 | - state->cursor = find.prev_first; | |
935 | - STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); | |
936 | - x = row.x0; | |
937 | - for (i=0; i < row.num_chars; ++i) { | |
938 | - float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); | |
939 | - #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE | |
940 | - if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) | |
941 | - break; | |
942 | - #endif | |
943 | - x += dx; | |
944 | - if (x > goal_x) | |
945 | - break; | |
946 | - ++state->cursor; | |
947 | - } | |
948 | - stb_textedit_clamp(str, state); | |
949 | - | |
950 | - state->has_preferred_x = 1; | |
951 | - state->preferred_x = goal_x; | |
952 | - | |
953 | - if (sel) | |
954 | - state->select_end = state->cursor; | |
955 | - } | |
956 | - break; | |
957 | - } | |
958 | - | |
959 | - case STB_TEXTEDIT_K_DELETE: | |
960 | - case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: | |
961 | - if (STB_TEXT_HAS_SELECTION(state)) | |
962 | - stb_textedit_delete_selection(str, state); | |
963 | - else { | |
964 | - int n = STB_TEXTEDIT_STRINGLEN(str); | |
965 | - if (state->cursor < n) | |
966 | - stb_textedit_delete(str, state, state->cursor, 1); | |
967 | - } | |
968 | - state->has_preferred_x = 0; | |
969 | - break; | |
970 | - | |
971 | - case STB_TEXTEDIT_K_BACKSPACE: | |
972 | - case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: | |
973 | - if (STB_TEXT_HAS_SELECTION(state)) | |
974 | - stb_textedit_delete_selection(str, state); | |
975 | - else { | |
976 | - stb_textedit_clamp(str, state); | |
977 | - if (state->cursor > 0) { | |
978 | - stb_textedit_delete(str, state, state->cursor-1, 1); | |
979 | - --state->cursor; | |
980 | - } | |
981 | - } | |
982 | - state->has_preferred_x = 0; | |
983 | - break; | |
984 | - | |
985 | -#ifdef STB_TEXTEDIT_K_TEXTSTART2 | |
986 | - case STB_TEXTEDIT_K_TEXTSTART2: | |
987 | -#endif | |
988 | - case STB_TEXTEDIT_K_TEXTSTART: | |
989 | - state->cursor = state->select_start = state->select_end = 0; | |
990 | - state->has_preferred_x = 0; | |
991 | - break; | |
992 | - | |
993 | -#ifdef STB_TEXTEDIT_K_TEXTEND2 | |
994 | - case STB_TEXTEDIT_K_TEXTEND2: | |
995 | -#endif | |
996 | - case STB_TEXTEDIT_K_TEXTEND: | |
997 | - state->cursor = STB_TEXTEDIT_STRINGLEN(str); | |
998 | - state->select_start = state->select_end = 0; | |
999 | - state->has_preferred_x = 0; | |
1000 | - break; | |
1001 | - | |
1002 | -#ifdef STB_TEXTEDIT_K_TEXTSTART2 | |
1003 | - case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: | |
1004 | -#endif | |
1005 | - case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: | |
1006 | - stb_textedit_prep_selection_at_cursor(state); | |
1007 | - state->cursor = state->select_end = 0; | |
1008 | - state->has_preferred_x = 0; | |
1009 | - break; | |
1010 | - | |
1011 | -#ifdef STB_TEXTEDIT_K_TEXTEND2 | |
1012 | - case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: | |
1013 | -#endif | |
1014 | - case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: | |
1015 | - stb_textedit_prep_selection_at_cursor(state); | |
1016 | - state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); | |
1017 | - state->has_preferred_x = 0; | |
1018 | - break; | |
1019 | - | |
1020 | - | |
1021 | -#ifdef STB_TEXTEDIT_K_LINESTART2 | |
1022 | - case STB_TEXTEDIT_K_LINESTART2: | |
1023 | -#endif | |
1024 | - case STB_TEXTEDIT_K_LINESTART: | |
1025 | - stb_textedit_clamp(str, state); | |
1026 | - stb_textedit_move_to_first(state); | |
1027 | - if (state->single_line) | |
1028 | - state->cursor = 0; | |
1029 | - else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) | |
1030 | - --state->cursor; | |
1031 | - state->has_preferred_x = 0; | |
1032 | - break; | |
1033 | - | |
1034 | -#ifdef STB_TEXTEDIT_K_LINEEND2 | |
1035 | - case STB_TEXTEDIT_K_LINEEND2: | |
1036 | -#endif | |
1037 | - case STB_TEXTEDIT_K_LINEEND: { | |
1038 | - int n = STB_TEXTEDIT_STRINGLEN(str); | |
1039 | - stb_textedit_clamp(str, state); | |
1040 | - stb_textedit_move_to_first(state); | |
1041 | - if (state->single_line) | |
1042 | - state->cursor = n; | |
1043 | - else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) | |
1044 | - ++state->cursor; | |
1045 | - state->has_preferred_x = 0; | |
1046 | - break; | |
1047 | - } | |
1048 | - | |
1049 | -#ifdef STB_TEXTEDIT_K_LINESTART2 | |
1050 | - case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: | |
1051 | -#endif | |
1052 | - case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: | |
1053 | - stb_textedit_clamp(str, state); | |
1054 | - stb_textedit_prep_selection_at_cursor(state); | |
1055 | - if (state->single_line) | |
1056 | - state->cursor = 0; | |
1057 | - else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) | |
1058 | - --state->cursor; | |
1059 | - state->select_end = state->cursor; | |
1060 | - state->has_preferred_x = 0; | |
1061 | - break; | |
1062 | - | |
1063 | -#ifdef STB_TEXTEDIT_K_LINEEND2 | |
1064 | - case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: | |
1065 | -#endif | |
1066 | - case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { | |
1067 | - int n = STB_TEXTEDIT_STRINGLEN(str); | |
1068 | - stb_textedit_clamp(str, state); | |
1069 | - stb_textedit_prep_selection_at_cursor(state); | |
1070 | - if (state->single_line) | |
1071 | - state->cursor = n; | |
1072 | - else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) | |
1073 | - ++state->cursor; | |
1074 | - state->select_end = state->cursor; | |
1075 | - state->has_preferred_x = 0; | |
1076 | - break; | |
1077 | - } | |
1078 | - | |
1079 | -// @TODO: | |
1080 | -// STB_TEXTEDIT_K_PGUP - move cursor up a page | |
1081 | -// STB_TEXTEDIT_K_PGDOWN - move cursor down a page | |
1082 | - } | |
1083 | -} | |
1084 | - | |
1085 | -///////////////////////////////////////////////////////////////////////////// | |
1086 | -// | |
1087 | -// Undo processing | |
1088 | -// | |
1089 | -// @OPTIMIZE: the undo/redo buffer should be circular | |
1090 | - | |
1091 | -static void stb_textedit_flush_redo(StbUndoState *state) | |
1092 | -{ | |
1093 | - state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; | |
1094 | - state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; | |
1095 | -} | |
1096 | - | |
1097 | -// discard the oldest entry in the undo list | |
1098 | -static void stb_textedit_discard_undo(StbUndoState *state) | |
1099 | -{ | |
1100 | - if (state->undo_point > 0) { | |
1101 | - // if the 0th undo state has characters, clean those up | |
1102 | - if (state->undo_rec[0].char_storage >= 0) { | |
1103 | - int n = state->undo_rec[0].insert_length, i; | |
1104 | - // delete n characters from all other records | |
1105 | - state->undo_char_point -= n; | |
1106 | - STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); | |
1107 | - for (i=0; i < state->undo_point; ++i) | |
1108 | - if (state->undo_rec[i].char_storage >= 0) | |
1109 | - state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it | |
1110 | - } | |
1111 | - --state->undo_point; | |
1112 | - STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); | |
1113 | - } | |
1114 | -} | |
1115 | - | |
1116 | -// discard the oldest entry in the redo list--it's bad if this | |
1117 | -// ever happens, but because undo & redo have to store the actual | |
1118 | -// characters in different cases, the redo character buffer can | |
1119 | -// fill up even though the undo buffer didn't | |
1120 | -static void stb_textedit_discard_redo(StbUndoState *state) | |
1121 | -{ | |
1122 | - int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; | |
1123 | - | |
1124 | - if (state->redo_point <= k) { | |
1125 | - // if the k'th undo state has characters, clean those up | |
1126 | - if (state->undo_rec[k].char_storage >= 0) { | |
1127 | - int n = state->undo_rec[k].insert_length, i; | |
1128 | - // move the remaining redo character data to the end of the buffer | |
1129 | - state->redo_char_point += n; | |
1130 | - STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); | |
1131 | - // adjust the position of all the other records to account for above memmove | |
1132 | - for (i=state->redo_point; i < k; ++i) | |
1133 | - if (state->undo_rec[i].char_storage >= 0) | |
1134 | - state->undo_rec[i].char_storage += n; | |
1135 | - } | |
1136 | - // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' | |
1137 | - // {DEAR IMGUI] | |
1138 | - size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); | |
1139 | - const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; | |
1140 | - const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; | |
1141 | - IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin); | |
1142 | - IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end); | |
1143 | - STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size); | |
1144 | - | |
1145 | - // now move redo_point to point to the new one | |
1146 | - ++state->redo_point; | |
1147 | - } | |
1148 | -} | |
1149 | - | |
1150 | -static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) | |
1151 | -{ | |
1152 | - // any time we create a new undo record, we discard redo | |
1153 | - stb_textedit_flush_redo(state); | |
1154 | - | |
1155 | - // if we have no free records, we have to make room, by sliding the | |
1156 | - // existing records down | |
1157 | - if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) | |
1158 | - stb_textedit_discard_undo(state); | |
1159 | - | |
1160 | - // if the characters to store won't possibly fit in the buffer, we can't undo | |
1161 | - if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { | |
1162 | - state->undo_point = 0; | |
1163 | - state->undo_char_point = 0; | |
1164 | - return NULL; | |
1165 | - } | |
1166 | - | |
1167 | - // if we don't have enough free characters in the buffer, we have to make room | |
1168 | - while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) | |
1169 | - stb_textedit_discard_undo(state); | |
1170 | - | |
1171 | - return &state->undo_rec[state->undo_point++]; | |
1172 | -} | |
1173 | - | |
1174 | -static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) | |
1175 | -{ | |
1176 | - StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); | |
1177 | - if (r == NULL) | |
1178 | - return NULL; | |
1179 | - | |
1180 | - r->where = pos; | |
1181 | - r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len; | |
1182 | - r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len; | |
1183 | - | |
1184 | - if (insert_len == 0) { | |
1185 | - r->char_storage = -1; | |
1186 | - return NULL; | |
1187 | - } else { | |
1188 | - r->char_storage = state->undo_char_point; | |
1189 | - state->undo_char_point += insert_len; | |
1190 | - return &state->undo_char[r->char_storage]; | |
1191 | - } | |
1192 | -} | |
1193 | - | |
1194 | -static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) | |
1195 | -{ | |
1196 | - StbUndoState *s = &state->undostate; | |
1197 | - StbUndoRecord u, *r; | |
1198 | - if (s->undo_point == 0) | |
1199 | - return; | |
1200 | - | |
1201 | - // we need to do two things: apply the undo record, and create a redo record | |
1202 | - u = s->undo_rec[s->undo_point-1]; | |
1203 | - r = &s->undo_rec[s->redo_point-1]; | |
1204 | - r->char_storage = -1; | |
1205 | - | |
1206 | - r->insert_length = u.delete_length; | |
1207 | - r->delete_length = u.insert_length; | |
1208 | - r->where = u.where; | |
1209 | - | |
1210 | - if (u.delete_length) { | |
1211 | - // if the undo record says to delete characters, then the redo record will | |
1212 | - // need to re-insert the characters that get deleted, so we need to store | |
1213 | - // them. | |
1214 | - | |
1215 | - // there are three cases: | |
1216 | - // there's enough room to store the characters | |
1217 | - // characters stored for *redoing* don't leave room for redo | |
1218 | - // characters stored for *undoing* don't leave room for redo | |
1219 | - // if the last is true, we have to bail | |
1220 | - | |
1221 | - if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { | |
1222 | - // the undo records take up too much character space; there's no space to store the redo characters | |
1223 | - r->insert_length = 0; | |
1224 | - } else { | |
1225 | - int i; | |
1226 | - | |
1227 | - // there's definitely room to store the characters eventually | |
1228 | - while (s->undo_char_point + u.delete_length > s->redo_char_point) { | |
1229 | - // should never happen: | |
1230 | - if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) | |
1231 | - return; | |
1232 | - // there's currently not enough room, so discard a redo record | |
1233 | - stb_textedit_discard_redo(s); | |
1234 | - } | |
1235 | - r = &s->undo_rec[s->redo_point-1]; | |
1236 | - | |
1237 | - r->char_storage = s->redo_char_point - u.delete_length; | |
1238 | - s->redo_char_point = s->redo_char_point - u.delete_length; | |
1239 | - | |
1240 | - // now save the characters | |
1241 | - for (i=0; i < u.delete_length; ++i) | |
1242 | - s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); | |
1243 | - } | |
1244 | - | |
1245 | - // now we can carry out the deletion | |
1246 | - STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); | |
1247 | - } | |
1248 | - | |
1249 | - // check type of recorded action: | |
1250 | - if (u.insert_length) { | |
1251 | - // easy case: was a deletion, so we need to insert n characters | |
1252 | - STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); | |
1253 | - s->undo_char_point -= u.insert_length; | |
1254 | - } | |
1255 | - | |
1256 | - state->cursor = u.where + u.insert_length; | |
1257 | - | |
1258 | - s->undo_point--; | |
1259 | - s->redo_point--; | |
1260 | -} | |
1261 | - | |
1262 | -static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) | |
1263 | -{ | |
1264 | - StbUndoState *s = &state->undostate; | |
1265 | - StbUndoRecord *u, r; | |
1266 | - if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) | |
1267 | - return; | |
1268 | - | |
1269 | - // we need to do two things: apply the redo record, and create an undo record | |
1270 | - u = &s->undo_rec[s->undo_point]; | |
1271 | - r = s->undo_rec[s->redo_point]; | |
1272 | - | |
1273 | - // we KNOW there must be room for the undo record, because the redo record | |
1274 | - // was derived from an undo record | |
1275 | - | |
1276 | - u->delete_length = r.insert_length; | |
1277 | - u->insert_length = r.delete_length; | |
1278 | - u->where = r.where; | |
1279 | - u->char_storage = -1; | |
1280 | - | |
1281 | - if (r.delete_length) { | |
1282 | - // the redo record requires us to delete characters, so the undo record | |
1283 | - // needs to store the characters | |
1284 | - | |
1285 | - if (s->undo_char_point + u->insert_length > s->redo_char_point) { | |
1286 | - u->insert_length = 0; | |
1287 | - u->delete_length = 0; | |
1288 | - } else { | |
1289 | - int i; | |
1290 | - u->char_storage = s->undo_char_point; | |
1291 | - s->undo_char_point = s->undo_char_point + u->insert_length; | |
1292 | - | |
1293 | - // now save the characters | |
1294 | - for (i=0; i < u->insert_length; ++i) | |
1295 | - s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); | |
1296 | - } | |
1297 | - | |
1298 | - STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); | |
1299 | - } | |
1300 | - | |
1301 | - if (r.insert_length) { | |
1302 | - // easy case: need to insert n characters | |
1303 | - STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); | |
1304 | - s->redo_char_point += r.insert_length; | |
1305 | - } | |
1306 | - | |
1307 | - state->cursor = r.where + r.insert_length; | |
1308 | - | |
1309 | - s->undo_point++; | |
1310 | - s->redo_point++; | |
1311 | -} | |
1312 | - | |
1313 | -static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) | |
1314 | -{ | |
1315 | - stb_text_createundo(&state->undostate, where, 0, length); | |
1316 | -} | |
1317 | - | |
1318 | -static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) | |
1319 | -{ | |
1320 | - int i; | |
1321 | - STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); | |
1322 | - if (p) { | |
1323 | - for (i=0; i < length; ++i) | |
1324 | - p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); | |
1325 | - } | |
1326 | -} | |
1327 | - | |
1328 | -static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) | |
1329 | -{ | |
1330 | - int i; | |
1331 | - STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); | |
1332 | - if (p) { | |
1333 | - for (i=0; i < old_length; ++i) | |
1334 | - p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); | |
1335 | - } | |
1336 | -} | |
1337 | - | |
1338 | -// reset the state to default | |
1339 | -static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) | |
1340 | -{ | |
1341 | - state->undostate.undo_point = 0; | |
1342 | - state->undostate.undo_char_point = 0; | |
1343 | - state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; | |
1344 | - state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; | |
1345 | - state->select_end = state->select_start = 0; | |
1346 | - state->cursor = 0; | |
1347 | - state->has_preferred_x = 0; | |
1348 | - state->preferred_x = 0; | |
1349 | - state->cursor_at_end_of_line = 0; | |
1350 | - state->initialized = 1; | |
1351 | - state->single_line = (unsigned char) is_single_line; | |
1352 | - state->insert_mode = 0; | |
1353 | -} | |
1354 | - | |
1355 | -// API initialize | |
1356 | -static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) | |
1357 | -{ | |
1358 | - stb_textedit_clear_state(state, is_single_line); | |
1359 | -} | |
1360 | - | |
1361 | -#if defined(__GNUC__) || defined(__clang__) | |
1362 | -#pragma GCC diagnostic push | |
1363 | -#pragma GCC diagnostic ignored "-Wcast-qual" | |
1364 | -#endif | |
1365 | - | |
1366 | -static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) | |
1367 | -{ | |
1368 | - return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len); | |
1369 | -} | |
1370 | - | |
1371 | -#if defined(__GNUC__) || defined(__clang__) | |
1372 | -#pragma GCC diagnostic pop | |
1373 | -#endif | |
1374 | - | |
1375 | -#endif//STB_TEXTEDIT_IMPLEMENTATION | |
1376 | - | |
1377 | -/* | |
1378 | ------------------------------------------------------------------------------- | |
1379 | -This software is available under 2 licenses -- choose whichever you prefer. | |
1380 | ------------------------------------------------------------------------------- | |
1381 | -ALTERNATIVE A - MIT License | |
1382 | -Copyright (c) 2017 Sean Barrett | |
1383 | -Permission is hereby granted, free of charge, to any person obtaining a copy of | |
1384 | -this software and associated documentation files (the "Software"), to deal in | |
1385 | -the Software without restriction, including without limitation the rights to | |
1386 | -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
1387 | -of the Software, and to permit persons to whom the Software is furnished to do | |
1388 | -so, subject to the following conditions: | |
1389 | -The above copyright notice and this permission notice shall be included in all | |
1390 | -copies or substantial portions of the Software. | |
1391 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
1392 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
1393 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
1394 | -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
1395 | -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
1396 | -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
1397 | -SOFTWARE. | |
1398 | ------------------------------------------------------------------------------- | |
1399 | -ALTERNATIVE B - Public Domain (www.unlicense.org) | |
1400 | -This is free and unencumbered software released into the public domain. | |
1401 | -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this | |
1402 | -software, either in source code form or as a compiled binary, for any purpose, | |
1403 | -commercial or non-commercial, and by any means. | |
1404 | -In jurisdictions that recognize copyright laws, the author or authors of this | |
1405 | -software dedicate any and all copyright interest in the software to the public | |
1406 | -domain. We make this dedication for the benefit of the public at large and to | |
1407 | -the detriment of our heirs and successors. We intend this dedication to be an | |
1408 | -overt act of relinquishment in perpetuity of all present and future rights to | |
1409 | -this software under copyright law. | |
1410 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
1411 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
1412 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
1413 | -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
1414 | -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
1415 | -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
1416 | ------------------------------------------------------------------------------- | |
1417 | -*/ |
@@ -1,59 +1,42 @@ | ||
1 | 1 | //----------------------------------------------------------------------------- |
2 | -// COMPILE-TIME OPTIONS FOR DEAR IMGUI | |
3 | -// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. | |
4 | -// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. | |
2 | +// USER IMPLEMENTATION | |
3 | +// This file contains compile-time options for ImGui. | |
4 | +// Other options (memory allocation overrides, callbacks, etc.) can be set at runtime via the ImGuiIO structure - ImGui::GetIO(). | |
5 | 5 | //----------------------------------------------------------------------------- |
6 | -// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h) | |
7 | -// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" | |
8 | -// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include | |
9 | -// the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. | |
10 | -// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. | |
11 | -// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. | |
12 | -//----------------------------------------------------------------------------- | |
13 | 6 | |
14 | 7 | #pragma once |
15 | 8 | |
16 | 9 | //---- Define assertion handler. Defaults to calling assert(). |
17 | 10 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) |
18 | -//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts | |
19 | 11 | |
20 | -//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows | |
21 | -// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. | |
12 | +//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows. | |
22 | 13 | //#define IMGUI_API __declspec( dllexport ) |
23 | 14 | //#define IMGUI_API __declspec( dllimport ) |
24 | 15 | |
25 | -//---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. | |
16 | +//---- Don't define obsolete functions names. Consider enabling from time to time or when updating to reduce like hood of using already obsolete function/names | |
26 | 17 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
27 | 18 | |
28 | -//---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) | |
29 | -// It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp. | |
30 | -//#define IMGUI_DISABLE_DEMO_WINDOWS | |
31 | -//#define IMGUI_DISABLE_METRICS_WINDOW | |
19 | +//---- Include imgui_user.h at the end of imgui.h | |
20 | +//#define IMGUI_INCLUDE_IMGUI_USER_H | |
32 | 21 | |
33 | -//---- Don't implement some functions to reduce linkage requirements. | |
34 | -//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. | |
35 | -//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. | |
36 | -//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). | |
37 | -//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices'). | |
38 | -//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf. | |
39 | -//#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h. | |
40 | -//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). | |
22 | +//---- Don't implement default handlers for Windows (so as not to link with OpenClipboard() and others Win32 functions) | |
23 | +//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS | |
24 | +//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS | |
41 | 25 | |
42 | -//---- Include imgui_user.h at the end of imgui.h as a convenience | |
43 | -//#define IMGUI_INCLUDE_IMGUI_USER_H | |
26 | +//---- Don't implement test window functionality (ShowTestWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) | |
27 | +//---- It is very strongly recommended to NOT disable the test windows. Please read the comment at the top of imgui_demo.cpp to learn why. | |
28 | +//#define IMGUI_DISABLE_TEST_WINDOWS | |
44 | 29 | |
45 | -//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) | |
30 | +//---- Don't implement ImFormatString(), ImFormatStringV() so you can reimplement them yourself. | |
31 | +//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS | |
32 | + | |
33 | +//---- Pack colors to BGRA instead of RGBA (remove need to post process vertex buffer in back ends) | |
46 | 34 | //#define IMGUI_USE_BGRA_PACKED_COLOR |
47 | 35 | |
48 | -//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version | |
49 | -// By default the embedded implementations are declared static and not available outside of imgui cpp files. | |
50 | -//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" | |
51 | -//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" | |
52 | -//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION | |
53 | -//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION | |
36 | +//---- Implement STB libraries in a namespace to avoid linkage conflicts | |
37 | +//#define IMGUI_STB_NAMESPACE ImGuiStb | |
54 | 38 | |
55 | -//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. | |
56 | -// This will be inlined as part of ImVec2 and ImVec4 class declarations. | |
39 | +//---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4. | |
57 | 40 | /* |
58 | 41 | #define IM_VEC2_CLASS_EXTRA \ |
59 | 42 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ |
@@ -64,30 +47,15 @@ | ||
64 | 47 | operator MyVec4() const { return MyVec4(x,y,z,w); } |
65 | 48 | */ |
66 | 49 | |
67 | -//---- Using 32-bits vertex indices (default is 16-bits) is one way to allow large meshes with more than 64K vertices. | |
68 | -// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bits indices). | |
69 | -// Another way to allow large meshes while keeping 16-bits indices is to handle ImDrawCmd::VtxOffset in your renderer. | |
70 | -// Read about ImGuiBackendFlags_RendererHasVtxOffset for details. | |
50 | +//---- Use 32-bit vertex indices (instead of default: 16-bit) to allow meshes with more than 64K vertices | |
71 | 51 | //#define ImDrawIdx unsigned int |
72 | 52 | |
73 | -//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly) | |
74 | -//struct ImDrawList; | |
75 | -//struct ImDrawCmd; | |
76 | -//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); | |
77 | -//#define ImDrawCallback MyImDrawCallback | |
78 | - | |
79 | -//---- Debug Tools | |
80 | -// Use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging. | |
81 | -//#define IM_DEBUG_BREAK IM_ASSERT(0) | |
82 | -//#define IM_DEBUG_BREAK __debugbreak() | |
83 | -// Have the Item Picker break in the ItemAdd() function instead of ItemHoverable() - which is earlier in the code, will catch a few extra items, allow picking items other than Hovered one. | |
84 | -// This adds a small runtime cost which is why it is not enabled by default. | |
85 | -//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX | |
86 | - | |
87 | 53 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. |
54 | +//---- e.g. create variants of the ImGui::Value() helper for your low-level math types, or your own widgets/helpers. | |
88 | 55 | /* |
89 | 56 | namespace ImGui |
90 | 57 | { |
91 | - void MyFunction(const char* name, const MyMatrix44& v); | |
58 | + void Value(const char* prefix, const MyMatrix44& v, const char* float_format = NULL); | |
92 | 59 | } |
93 | 60 | */ |
61 | + |
@@ -0,0 +1,10887 @@ | ||
1 | +// dear imgui, v1.52 | |
2 | +// (main code and documentation) | |
3 | + | |
4 | +// See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code. | |
5 | +// Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. | |
6 | +// Get latest version at https://github.com/ocornut/imgui | |
7 | +// Releases change-log at https://github.com/ocornut/imgui/releases | |
8 | +// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269 | |
9 | +// Developed by Omar Cornut and every direct or indirect contributors to the GitHub. | |
10 | +// This library is free but I need your support to sustain development and maintenance. | |
11 | +// If you work for a company, please consider financial support, e.g: https://www.patreon.com/imgui | |
12 | + | |
13 | +/* | |
14 | + | |
15 | + Index | |
16 | + - MISSION STATEMENT | |
17 | + - END-USER GUIDE | |
18 | + - PROGRAMMER GUIDE (read me!) | |
19 | + - Read first | |
20 | + - How to update to a newer version of Dear ImGui | |
21 | + - Getting started with integrating Dear ImGui in your code/engine | |
22 | + - API BREAKING CHANGES (read me when you update!) | |
23 | + - ISSUES & TODO LIST | |
24 | + - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS | |
25 | + - How can I help? | |
26 | + - What is ImTextureID and how do I display an image? | |
27 | + - I integrated Dear ImGui in my engine and the text or lines are blurry.. | |
28 | + - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. | |
29 | + - How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on labels/IDs. | |
30 | + - How can I tell when Dear ImGui wants my mouse/keyboard inputs VS when I can pass them to my application? | |
31 | + - How can I load a different font than the default? | |
32 | + - How can I easily use icons in my application? | |
33 | + - How can I load multiple fonts? | |
34 | + - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? | |
35 | + - How can I preserve my Dear ImGui context across reloading a DLL? (loss of the global/static variables) | |
36 | + - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) | |
37 | + - ISSUES & TODO-LIST | |
38 | + - CODE | |
39 | + | |
40 | + | |
41 | + MISSION STATEMENT | |
42 | + ================= | |
43 | + | |
44 | + - Easy to use to create code-driven and data-driven tools | |
45 | + - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools | |
46 | + - Easy to hack and improve | |
47 | + - Minimize screen real-estate usage | |
48 | + - Minimize setup and maintenance | |
49 | + - Minimize state storage on user side | |
50 | + - Portable, minimize dependencies, run on target (consoles, phones, etc.) | |
51 | + - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window, opening a tree node | |
52 | + for the first time, etc. but a typical frame won't allocate anything) | |
53 | + | |
54 | + Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: | |
55 | + - Doesn't look fancy, doesn't animate | |
56 | + - Limited layout features, intricate layouts are typically crafted in code | |
57 | + | |
58 | + | |
59 | + END-USER GUIDE | |
60 | + ============== | |
61 | + | |
62 | + - Double-click title bar to collapse window | |
63 | + - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin() | |
64 | + - Click and drag on lower right corner to resize window | |
65 | + - Click and drag on any empty space to move window | |
66 | + - Double-click/double-tap on lower right corner grip to auto-fit to content | |
67 | + - TAB/SHIFT+TAB to cycle through keyboard editable fields | |
68 | + - Use mouse wheel to scroll | |
69 | + - Use CTRL+mouse wheel to zoom window contents (if io.FontAllowScaling is true) | |
70 | + - CTRL+Click on a slider or drag box to input value as text | |
71 | + - Text editor: | |
72 | + - Hold SHIFT or use mouse to select text. | |
73 | + - CTRL+Left/Right to word jump | |
74 | + - CTRL+Shift+Left/Right to select words | |
75 | + - CTRL+A our Double-Click to select all | |
76 | + - CTRL+X,CTRL+C,CTRL+V to use OS clipboard | |
77 | + - CTRL+Z,CTRL+Y to undo/redo | |
78 | + - ESCAPE to revert text to its original value | |
79 | + - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) | |
80 | + - Controls are automatically adjusted for OSX to match standard OSX text editing operations. | |
81 | + | |
82 | + | |
83 | + PROGRAMMER GUIDE | |
84 | + ================ | |
85 | + | |
86 | + READ FIRST | |
87 | + | |
88 | + - Read the FAQ below this section! | |
89 | + - Your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention | |
90 | + on your side, no state duplication, less sync, less bugs. | |
91 | + - Call and read ImGui::ShowTestWindow() for demo code demonstrating most features. | |
92 | + - You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861 | |
93 | + | |
94 | + HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI | |
95 | + | |
96 | + - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) | |
97 | + - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. | |
98 | + If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed from the public API. | |
99 | + If you have a problem with a missing function/symbols, search for its name in the code, there will likely be a comment about it. | |
100 | + Please report any issue to the GitHub page! | |
101 | + - Try to keep your copy of dear imgui reasonably up to date. | |
102 | + | |
103 | + GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE | |
104 | + | |
105 | + - Add the Dear ImGui source files to your projects, using your preferred build system. | |
106 | + It is recommended you build the .cpp files as part of your project and not as a library. | |
107 | + - You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types. | |
108 | + - See examples/ folder for standalone sample applications. To understand the integration process, you can read examples/opengl2_example/ because | |
109 | + it is short, then switch to the one more appropriate to your use case. | |
110 | + - You may be able to grab and copy a ready made imgui_impl_*** file from the examples/. | |
111 | + - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. | |
112 | + | |
113 | + - Init: retrieve the ImGuiIO structure with ImGui::GetIO() and fill the fields marked 'Settings': at minimum you need to set io.DisplaySize | |
114 | + (application resolution). Later on you will fill your keyboard mapping, clipboard handlers, and other advanced features but for a basic | |
115 | + integration you don't need to worry about it all. | |
116 | + - Init: call io.Fonts->GetTexDataAsRGBA32(...), it will build the font atlas texture, then load the texture pixels into graphics memory. | |
117 | + - Every frame: | |
118 | + - In your main loop as early a possible, fill the IO fields marked 'Input' (e.g. mouse position, buttons, keyboard info, etc.) | |
119 | + - Call ImGui::NewFrame() to begin the frame | |
120 | + - You can use any ImGui function you want between NewFrame() and Render() | |
121 | + - Call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your io.RenderDrawListFn handler. | |
122 | + (Even if you don't render, call Render() and ignore the callback, or call EndFrame() instead. Otherwhise some features will break) | |
123 | + - All rendering information are stored into command-lists until ImGui::Render() is called. | |
124 | + - Dear ImGui never touches or knows about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide. | |
125 | + - Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases | |
126 | + of your own application. | |
127 | + - Refer to the examples applications in the examples/ folder for instruction on how to setup your code. | |
128 | + - A minimal application skeleton may be: | |
129 | + | |
130 | + // Application init | |
131 | + ImGuiIO& io = ImGui::GetIO(); | |
132 | + io.DisplaySize.x = 1920.0f; | |
133 | + io.DisplaySize.y = 1280.0f; | |
134 | + io.RenderDrawListsFn = MyRenderFunction; // Setup a render function, or set to NULL and call GetDrawData() after Render() to access render data. | |
135 | + // TODO: Fill others settings of the io structure later. | |
136 | + | |
137 | + // Load texture atlas (there is a default font so you don't need to care about choosing a font yet) | |
138 | + unsigned char* pixels; | |
139 | + int width, height; | |
140 | + io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height); | |
141 | + // TODO: At this points you've got the texture data and you need to upload that your your graphic system: | |
142 | + MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA) | |
143 | + // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID'. This will be passed back to your via the renderer. | |
144 | + io.Fonts->TexID = (void*)texture; | |
145 | + | |
146 | + // Application main loop | |
147 | + while (true) | |
148 | + { | |
149 | + // Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or write to those fields from your Windows message loop handlers, etc.) | |
150 | + ImGuiIO& io = ImGui::GetIO(); | |
151 | + io.DeltaTime = 1.0f/60.0f; | |
152 | + io.MousePos = mouse_pos; | |
153 | + io.MouseDown[0] = mouse_button_0; | |
154 | + io.MouseDown[1] = mouse_button_1; | |
155 | + | |
156 | + // Call NewFrame(), after this point you can use ImGui::* functions anytime | |
157 | + ImGui::NewFrame(); | |
158 | + | |
159 | + // Most of your application code here | |
160 | + MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); | |
161 | + MyGameRender(); // may use any ImGui functions as well! | |
162 | + | |
163 | + // Render & swap video buffers | |
164 | + ImGui::Render(); | |
165 | + SwapBuffers(); | |
166 | + } | |
167 | + | |
168 | + - A minimal render function skeleton may be: | |
169 | + | |
170 | + void void MyRenderFunction(ImDrawData* draw_data)(ImDrawData* draw_data) | |
171 | + { | |
172 | + // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled | |
173 | + // TODO: Setup viewport, orthographic projection matrix | |
174 | + // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. | |
175 | + for (int n = 0; n < draw_data->CmdListsCount; n++) | |
176 | + { | |
177 | + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui | |
178 | + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui | |
179 | + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) | |
180 | + { | |
181 | + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; | |
182 | + if (pcmd->UserCallback) | |
183 | + { | |
184 | + pcmd->UserCallback(cmd_list, pcmd); | |
185 | + } | |
186 | + else | |
187 | + { | |
188 | + // The texture for the draw call is specified by pcmd->TextureId. | |
189 | + // The vast majority of draw calls with use the imgui texture atlas, which value you have set yourself during initialization. | |
190 | + MyEngineBindTexture(pcmd->TextureId); | |
191 | + | |
192 | + // We are using scissoring to clip some objects. All low-level graphics API supports it. | |
193 | + // If your engine doesn't support scissoring yet, you will get some small glitches (some elements outside their bounds) which you can fix later. | |
194 | + MyEngineScissor((int)pcmd->ClipRect.x, (int)pcmd->ClipRect.y, (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); | |
195 | + | |
196 | + // Render 'pcmd->ElemCount/3' indexed triangles. | |
197 | + // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits if your engine doesn't support 16-bits indices. | |
198 | + MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); | |
199 | + } | |
200 | + idx_buffer += pcmd->ElemCount; | |
201 | + } | |
202 | + } | |
203 | + } | |
204 | + | |
205 | + - The examples/ folders contains many functional implementation of the pseudo-code above. | |
206 | + - When calling NewFrame(), the 'io.WantCaptureMouse'/'io.WantCaptureKeyboard'/'io.WantTextInput' flags are updated. | |
207 | + They tell you if ImGui intends to use your inputs. So for example, if 'io.WantCaptureMouse' is set you would typically want to hide | |
208 | + mouse inputs from the rest of your application. Read the FAQ below for more information about those flags. | |
209 | + | |
210 | + | |
211 | + | |
212 | + API BREAKING CHANGES | |
213 | + ==================== | |
214 | + | |
215 | + Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. | |
216 | + Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. | |
217 | + Also read releases logs https://github.com/ocornut/imgui/releases for more details. | |
218 | + | |
219 | + - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency. | |
220 | + - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. | |
221 | + - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details. | |
222 | + removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. | |
223 | + - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! | |
224 | + - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). | |
225 | + - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). | |
226 | + - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". | |
227 | + - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! | |
228 | + - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). | |
229 | + - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). | |
230 | + - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. | |
231 | + - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix. | |
232 | + - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame. | |
233 | + - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely. | |
234 | + - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete). | |
235 | + - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete). | |
236 | + - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). | |
237 | + - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu. | |
238 | + - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options. | |
239 | + - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))' | |
240 | + - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse | |
241 | + - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. | |
242 | + - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. | |
243 | + - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). | |
244 | + - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. | |
245 | + - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. | |
246 | + - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. | |
247 | + - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. | |
248 | + If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. | |
249 | + However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. | |
250 | + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color. | |
251 | + ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) | |
252 | + { | |
253 | + float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; | |
254 | + return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); | |
255 | + } | |
256 | + If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. | |
257 | + - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). | |
258 | + - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. | |
259 | + - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). | |
260 | + - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. | |
261 | + - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). | |
262 | + - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) | |
263 | + - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). | |
264 | + - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. | |
265 | + - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. | |
266 | + - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. | |
267 | + - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. | |
268 | + - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. | |
269 | + GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side. | |
270 | + GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out! | |
271 | + - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize | |
272 | + - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project. | |
273 | + - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason | |
274 | + - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure. | |
275 | + you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. | |
276 | + - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost. | |
277 | + this necessary change will break your rendering function! the fix should be very easy. sorry for that :( | |
278 | + - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. | |
279 | + - the signature of the io.RenderDrawListsFn handler has changed! | |
280 | + ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) | |
281 | + became: | |
282 | + ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). | |
283 | + argument 'cmd_lists' -> 'draw_data->CmdLists' | |
284 | + argument 'cmd_lists_count' -> 'draw_data->CmdListsCount' | |
285 | + ImDrawList 'commands' -> 'CmdBuffer' | |
286 | + ImDrawList 'vtx_buffer' -> 'VtxBuffer' | |
287 | + ImDrawList n/a -> 'IdxBuffer' (new) | |
288 | + ImDrawCmd 'vtx_count' -> 'ElemCount' | |
289 | + ImDrawCmd 'clip_rect' -> 'ClipRect' | |
290 | + ImDrawCmd 'user_callback' -> 'UserCallback' | |
291 | + ImDrawCmd 'texture_id' -> 'TextureId' | |
292 | + - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer. | |
293 | + - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering! | |
294 | + - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! | |
295 | + - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. | |
296 | + - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). | |
297 | + - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. | |
298 | + - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence | |
299 | + - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry! | |
300 | + - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). | |
301 | + - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). | |
302 | + - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. | |
303 | + - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened. | |
304 | + - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). | |
305 | + - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. | |
306 | + - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API | |
307 | + - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. | |
308 | + - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. | |
309 | + - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. | |
310 | + - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing | |
311 | + - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. | |
312 | + - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) | |
313 | + - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. | |
314 | + - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. | |
315 | + - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. | |
316 | + - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior | |
317 | + - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() | |
318 | + - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) | |
319 | + - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. | |
320 | + - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. | |
321 | + (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. | |
322 | + this sequence: | |
323 | + const void* png_data; | |
324 | + unsigned int png_size; | |
325 | + ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); | |
326 | + // <Copy to GPU> | |
327 | + became: | |
328 | + unsigned char* pixels; | |
329 | + int width, height; | |
330 | + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); | |
331 | + // <Copy to GPU> | |
332 | + io.Fonts->TexID = (your_texture_identifier); | |
333 | + you now have much more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. | |
334 | + it is now recommended that you sample the font texture with bilinear interpolation. | |
335 | + (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. | |
336 | + (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) | |
337 | + (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets | |
338 | + - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) | |
339 | + - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) | |
340 | + - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility | |
341 | + - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() | |
342 | + - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly) | |
343 | + - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) | |
344 | + - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() | |
345 | + - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn | |
346 | + - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) | |
347 | + - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite | |
348 | + - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes | |
349 | + | |
350 | + | |
351 | + ISSUES & TODO-LIST | |
352 | + ================== | |
353 | + See TODO.txt | |
354 | + | |
355 | + | |
356 | + FREQUENTLY ASKED QUESTIONS (FAQ), TIPS | |
357 | + ====================================== | |
358 | + | |
359 | + Q: How can I help? | |
360 | + A: - If you are experienced enough with Dear ImGui and with C/C++, look at the todo list and see how you want/can help! | |
361 | + - Become a Patron/donate! Convince your company to become a Patron or provide serious funding for development time! See http://www.patreon.com/imgui | |
362 | + | |
363 | + Q: What is ImTextureID and how do I display an image? | |
364 | + A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function. | |
365 | + Dear ImGui knows nothing about what those bits represent, it just passes them around. It is up to you to decide what you want the void* to carry! | |
366 | + It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc. | |
367 | + At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render. | |
368 | + Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing. | |
369 | + (c++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address!) | |
370 | + To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions. | |
371 | + Dear ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use. | |
372 | + It is your responsibility to get textures uploaded to your GPU. | |
373 | + | |
374 | + Q: I integrated Dear ImGui in my engine and the text or lines are blurry.. | |
375 | + A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). | |
376 | + Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. | |
377 | + | |
378 | + Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. | |
379 | + A: You are probably mishandling the clipping rectangles in your render function. | |
380 | + Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height). | |
381 | + | |
382 | + Q: Can I have multiple widgets with the same label? Can I have widget without a label? | |
383 | + A: Yes. A primer on the use of labels/IDs in Dear ImGui.. | |
384 | + | |
385 | + - Elements that are not clickable, such as Text() items don't need an ID. | |
386 | + | |
387 | + - Interactive widgets require state to be carried over multiple frames (most typically Dear ImGui often needs to remember what is | |
388 | + the "active" widget). to do so they need a unique ID. unique ID are typically derived from a string label, an integer index or a pointer. | |
389 | + | |
390 | + Button("OK"); // Label = "OK", ID = hash of "OK" | |
391 | + Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel" | |
392 | + | |
393 | + - ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK" | |
394 | + in two different windows or in two different locations of a tree. | |
395 | + | |
396 | + - If you have a same ID twice in the same location, you'll have a conflict: | |
397 | + | |
398 | + Button("OK"); | |
399 | + Button("OK"); // ID collision! Both buttons will be treated as the same. | |
400 | + | |
401 | + Fear not! this is easy to solve and there are many ways to solve it! | |
402 | + | |
403 | + - When passing a label you can optionally specify extra unique ID information within string itself. | |
404 | + This helps solving the simpler collision cases. Use "##" to pass a complement to the ID that won't be visible to the end-user: | |
405 | + | |
406 | + Button("Play"); // Label = "Play", ID = hash of "Play" | |
407 | + Button("Play##foo1"); // Label = "Play", ID = hash of "Play##foo1" (different from above) | |
408 | + Button("Play##foo2"); // Label = "Play", ID = hash of "Play##foo2" (different from above) | |
409 | + | |
410 | + - If you want to completely hide the label, but still need an ID: | |
411 | + | |
412 | + Checkbox("##On", &b); // Label = "", ID = hash of "##On" (no label!) | |
413 | + | |
414 | + - Occasionally/rarely you might want change a label while preserving a constant ID. This allows you to animate labels. | |
415 | + For example you may want to include varying information in a window title bar (and windows are uniquely identified by their ID.. obviously) | |
416 | + Use "###" to pass a label that isn't part of ID: | |
417 | + | |
418 | + Button("Hello###ID"; // Label = "Hello", ID = hash of "ID" | |
419 | + Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above) | |
420 | + | |
421 | + sprintf(buf, "My game (%f FPS)###MyGame"); | |
422 | + Begin(buf); // Variable label, ID = hash of "MyGame" | |
423 | + | |
424 | + - Use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window. | |
425 | + This is the most convenient way of distinguishing ID if you are iterating and creating many UI elements. | |
426 | + You can push a pointer, a string or an integer value. Remember that ID are formed from the concatenation of everything in the ID stack! | |
427 | + | |
428 | + for (int i = 0; i < 100; i++) | |
429 | + { | |
430 | + PushID(i); | |
431 | + Button("Click"); // Label = "Click", ID = hash of integer + "label" (unique) | |
432 | + PopID(); | |
433 | + } | |
434 | + | |
435 | + for (int i = 0; i < 100; i++) | |
436 | + { | |
437 | + MyObject* obj = Objects[i]; | |
438 | + PushID(obj); | |
439 | + Button("Click"); // Label = "Click", ID = hash of pointer + "label" (unique) | |
440 | + PopID(); | |
441 | + } | |
442 | + | |
443 | + for (int i = 0; i < 100; i++) | |
444 | + { | |
445 | + MyObject* obj = Objects[i]; | |
446 | + PushID(obj->Name); | |
447 | + Button("Click"); // Label = "Click", ID = hash of string + "label" (unique) | |
448 | + PopID(); | |
449 | + } | |
450 | + | |
451 | + - More example showing that you can stack multiple prefixes into the ID stack: | |
452 | + | |
453 | + Button("Click"); // Label = "Click", ID = hash of "Click" | |
454 | + PushID("node"); | |
455 | + Button("Click"); // Label = "Click", ID = hash of "node" + "Click" | |
456 | + PushID(my_ptr); | |
457 | + Button("Click"); // Label = "Click", ID = hash of "node" + ptr + "Click" | |
458 | + PopID(); | |
459 | + PopID(); | |
460 | + | |
461 | + - Tree nodes implicitly creates a scope for you by calling PushID(). | |
462 | + | |
463 | + Button("Click"); // Label = "Click", ID = hash of "Click" | |
464 | + if (TreeNode("node")) | |
465 | + { | |
466 | + Button("Click"); // Label = "Click", ID = hash of "node" + "Click" | |
467 | + TreePop(); | |
468 | + } | |
469 | + | |
470 | + - When working with trees, ID are used to preserve the open/close state of each tree node. | |
471 | + Depending on your use cases you may want to use strings, indices or pointers as ID. | |
472 | + e.g. when displaying a single object that may change over time (dynamic 1-1 relationship), using a static string as ID will preserve your | |
473 | + node open/closed state when the targeted object change. | |
474 | + e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. | |
475 | + experiment and see what makes more sense! | |
476 | + | |
477 | + Q: How can I tell when Dear ImGui wants my mouse/keyboard inputs VS when I can pass them to my application? | |
478 | + A: You can read the 'io.WantCaptureMouse'/'io.WantCaptureKeyboard'/'ioWantTextInput' flags from the ImGuiIO structure. | |
479 | + - When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application. | |
480 | + - When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console OS). | |
481 | + Preferably read the flags after calling ImGui::NewFrame() to avoid them lagging by one frame. But reading those flags before calling NewFrame() is | |
482 | + also generally ok, as the bool toggles fairly rarely and you don't generally expect to interact with either Dear ImGui or your application during | |
483 | + the same frame when that transition occurs. Dear ImGui is tracking dragging and widget activity that may occur outside the boundary of a window, | |
484 | + so 'io.WantCaptureMouse' is more accurate and correct than checking if a window is hovered. | |
485 | + (Advanced note: text input releases focus on Return 'KeyDown', so the following Return 'KeyUp' event that your application receive will typically | |
486 | + have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs | |
487 | + were for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.) | |
488 | + | |
489 | + Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13) | |
490 | + A: Use the font atlas to load the TTF/OTF file you want: | |
491 | + | |
492 | + ImGuiIO& io = ImGui::GetIO(); | |
493 | + io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); | |
494 | + io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() | |
495 | + | |
496 | + Q: How can I easily use icons in my application? | |
497 | + A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you main font. Then you can refer to icons within your | |
498 | + strings. Read 'How can I load multiple fonts?' and the file 'extra_fonts/README.txt' for instructions and useful header files. | |
499 | + | |
500 | + Q: How can I load multiple fonts? | |
501 | + A: Use the font atlas to pack them into a single texture: | |
502 | + (Read extra_fonts/README.txt and the code in ImFontAtlas for more details.) | |
503 | + | |
504 | + ImGuiIO& io = ImGui::GetIO(); | |
505 | + ImFont* font0 = io.Fonts->AddFontDefault(); | |
506 | + ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); | |
507 | + ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels); | |
508 | + io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() | |
509 | + // the first loaded font gets used by default | |
510 | + // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime | |
511 | + | |
512 | + // Options | |
513 | + ImFontConfig config; | |
514 | + config.OversampleH = 3; | |
515 | + config.OversampleV = 1; | |
516 | + config.GlyphOffset.y -= 2.0f; // Move everything by 2 pixels up | |
517 | + config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters | |
518 | + io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config); | |
519 | + | |
520 | + // Combine multiple fonts into one (e.g. for icon fonts) | |
521 | + ImWchar ranges[] = { 0xf000, 0xf3ff, 0 }; | |
522 | + ImFontConfig config; | |
523 | + config.MergeMode = true; | |
524 | + io.Fonts->AddFontDefault(); | |
525 | + io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font | |
526 | + io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs | |
527 | + | |
528 | + Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? | |
529 | + A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. | |
530 | + | |
531 | + // Add default Japanese ranges | |
532 | + io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); | |
533 | + | |
534 | + // Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need) | |
535 | + ImVector<ImWchar> ranges; | |
536 | + ImFontAtlas::GlyphRangesBuilder builder; | |
537 | + builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) | |
538 | + builder.AddChar(0x7262); // Add a specific character | |
539 | + builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges | |
540 | + builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted) | |
541 | + io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data); | |
542 | + | |
543 | + All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax. | |
544 | + Specifying literal in your source code using a local code page (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work! | |
545 | + Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. | |
546 | + | |
547 | + Text input: it is up to your application to pass the right character code to io.AddInputCharacter(). The applications in examples/ are doing that. | |
548 | + For languages using IME, on Windows you can copy the Hwnd of your application to io.ImeWindowHandle. | |
549 | + The default implementation of io.ImeSetInputScreenPosFn() on Windows will set your IME position correctly. | |
550 | + | |
551 | + Q: How can I preserve my Dear ImGui context across reloading a DLL? (loss of the global/static variables) | |
552 | + A: Create your own context 'ctx = CreateContext()' + 'SetCurrentContext(ctx)' and your own font atlas 'ctx->GetIO().Fonts = new ImFontAtlas()' | |
553 | + so you don't rely on the default globals. | |
554 | + | |
555 | + Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API) | |
556 | + A: The easiest way is to create a dummy window. Call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flag, | |
557 | + zero background alpha, then retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like. | |
558 | + You can also perfectly create a standalone ImDrawList instance _but_ you need ImGui to be initialized because ImDrawList pulls from ImGui | |
559 | + data to retrieve the coordinates of the white pixel. | |
560 | + | |
561 | + - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. | |
562 | + this is also useful to set yourself in the context of another window (to get/set other settings) | |
563 | + - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug". | |
564 | + - tip: the ImGuiOnceUponAFrame helper will allow run the block of code only once a frame. You can use it to quickly add custom UI in the middle | |
565 | + of a deep nested inner loop in your code. | |
566 | + - tip: you can call Render() multiple times (e.g for VR renders). | |
567 | + - tip: call and read the ShowTestWindow() code in imgui_demo.cpp for more example of how to use ImGui! | |
568 | + | |
569 | +*/ | |
570 | + | |
571 | +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) | |
572 | +#define _CRT_SECURE_NO_WARNINGS | |
573 | +#endif | |
574 | + | |
575 | +#include "imgui.h" | |
576 | +#define IMGUI_DEFINE_MATH_OPERATORS | |
577 | +#define IMGUI_DEFINE_PLACEMENT_NEW | |
578 | +#include "imgui_internal.h" | |
579 | + | |
580 | +#include <ctype.h> // toupper, isprint | |
581 | +#include <stdlib.h> // NULL, malloc, free, qsort, atoi | |
582 | +#include <stdio.h> // vsnprintf, sscanf, printf | |
583 | +#include <limits.h> // INT_MIN, INT_MAX | |
584 | +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier | |
585 | +#include <stddef.h> // intptr_t | |
586 | +#else | |
587 | +#include <stdint.h> // intptr_t | |
588 | +#endif | |
589 | + | |
590 | +#ifdef _MSC_VER | |
591 | +#pragma warning (disable: 4127) // condition expression is constant | |
592 | +#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) | |
593 | +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen | |
594 | +#endif | |
595 | + | |
596 | +// Clang warnings with -Weverything | |
597 | +#ifdef __clang__ | |
598 | +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great! | |
599 | +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. | |
600 | +#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. | |
601 | +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. | |
602 | +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. | |
603 | +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. | |
604 | +#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // | |
605 | +#pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. | |
606 | +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' // | |
607 | +#elif defined(__GNUC__) | |
608 | +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used | |
609 | +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size | |
610 | +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' | |
611 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function | |
612 | +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value | |
613 | +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'xxxx' to type 'xxxx' casts away qualifiers | |
614 | +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked | |
615 | +#endif | |
616 | + | |
617 | +//------------------------------------------------------------------------- | |
618 | +// Forward Declarations | |
619 | +//------------------------------------------------------------------------- | |
620 | + | |
621 | +static float GetDraggedColumnOffset(int column_index); | |
622 | + | |
623 | +static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true); | |
624 | + | |
625 | +static ImFont* GetDefaultFont(); | |
626 | +static void SetCurrentFont(ImFont* font); | |
627 | +static void SetCurrentWindow(ImGuiWindow* window); | |
628 | +static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y); | |
629 | +static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond); | |
630 | +static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond); | |
631 | +static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond); | |
632 | +static ImGuiWindow* FindHoveredWindow(ImVec2 pos); | |
633 | +static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags); | |
634 | +static void ClearSetNextWindowData(); | |
635 | +static void CheckStacksSize(ImGuiWindow* window, bool write); | |
636 | +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window); | |
637 | + | |
638 | +static void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_list, ImDrawList* draw_list); | |
639 | +static void AddWindowToRenderList(ImVector<ImDrawList*>& out_render_list, ImGuiWindow* window); | |
640 | +static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>& out_sorted_windows, ImGuiWindow* window); | |
641 | + | |
642 | +static ImGuiIniData* FindWindowSettings(const char* name); | |
643 | +static ImGuiIniData* AddWindowSettings(const char* name); | |
644 | +static void LoadIniSettingsFromDisk(const char* ini_filename); | |
645 | +static void SaveIniSettingsToDisk(const char* ini_filename); | |
646 | +static void MarkIniSettingsDirty(ImGuiWindow* window); | |
647 | + | |
648 | +static ImRect GetVisibleRect(); | |
649 | + | |
650 | +static void CloseInactivePopups(ImGuiWindow* ref_window); | |
651 | +static void ClosePopupToLevel(int remaining); | |
652 | +static ImGuiWindow* GetFrontMostModalRootWindow(); | |
653 | +static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, int* last_dir, const ImRect& rect_to_avoid); | |
654 | + | |
655 | +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data); | |
656 | +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); | |
657 | +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); | |
658 | + | |
659 | +static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, const char* display_format, char* buf, int buf_size); | |
660 | +static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, int decimal_precision, char* buf, int buf_size); | |
661 | +static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* value1, const void* value2); | |
662 | +static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format); | |
663 | + | |
664 | +namespace ImGui | |
665 | +{ | |
666 | +static void FocusPreviousWindow(); | |
667 | +} | |
668 | + | |
669 | +//----------------------------------------------------------------------------- | |
670 | +// Platform dependent default implementations | |
671 | +//----------------------------------------------------------------------------- | |
672 | + | |
673 | +static const char* GetClipboardTextFn_DefaultImpl(void* user_data); | |
674 | +static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); | |
675 | +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); | |
676 | + | |
677 | +//----------------------------------------------------------------------------- | |
678 | +// Context | |
679 | +//----------------------------------------------------------------------------- | |
680 | + | |
681 | +// Default font atlas storage. | |
682 | +// New contexts always point by default to this font atlas. It can be changed by reassigning the GetIO().Fonts variable. | |
683 | +static ImFontAtlas GImDefaultFontAtlas; | |
684 | + | |
685 | +// Default context storage + current context pointer. | |
686 | +// Implicitely used by all ImGui functions. Always assumed to be != NULL. Change to a different context by calling ImGui::SetCurrentContext() | |
687 | +// If you are hot-reloading this code in a DLL you will lose the static/global variables. Create your own context+font atlas instead of relying on those default (see FAQ entry "How can I preserve my ImGui context across reloading a DLL?"). | |
688 | +// ImGui is currently not thread-safe because of this variable. If you want thread-safety to allow N threads to access N different contexts, you might work around it by: | |
689 | +// - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts) | |
690 | +// - or: Changing this variable to be TLS. You may #define GImGui in imconfig.h for further custom hackery. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 | |
691 | +#ifndef GImGui | |
692 | +static ImGuiContext GImDefaultContext; | |
693 | +ImGuiContext* GImGui = &GImDefaultContext; | |
694 | +#endif | |
695 | + | |
696 | +//----------------------------------------------------------------------------- | |
697 | +// User facing structures | |
698 | +//----------------------------------------------------------------------------- | |
699 | + | |
700 | +ImGuiStyle::ImGuiStyle() | |
701 | +{ | |
702 | + Alpha = 1.0f; // Global alpha applies to everything in ImGui | |
703 | + WindowPadding = ImVec2(8,8); // Padding within a window | |
704 | + WindowMinSize = ImVec2(32,32); // Minimum window size | |
705 | + WindowRounding = 9.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows | |
706 | + WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text | |
707 | + ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows | |
708 | + FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) | |
709 | + FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). | |
710 | + ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines | |
711 | + ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) | |
712 | + TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! | |
713 | + IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). | |
714 | + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns | |
715 | + ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar | |
716 | + ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar | |
717 | + GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar | |
718 | + GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. | |
719 | + ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. | |
720 | + DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. | |
721 | + DisplaySafeAreaPadding = ImVec2(4,4); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. | |
722 | + AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. | |
723 | + AntiAliasedShapes = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) | |
724 | + CurveTessellationTol = 1.25f; // Tessellation tolerance. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. | |
725 | + | |
726 | + ImGui::StyleColorsClassic(this); | |
727 | +} | |
728 | + | |
729 | +void ImGui::StyleColorsClassic(ImGuiStyle* dst) | |
730 | +{ | |
731 | + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); | |
732 | + ImVec4* colors = style->Colors; | |
733 | + | |
734 | + colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); | |
735 | + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); | |
736 | + colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); | |
737 | + colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); | |
738 | + colors[ImGuiCol_PopupBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f); | |
739 | + colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 0.40f); | |
740 | + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); | |
741 | + colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input | |
742 | + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.90f, 0.80f, 0.80f, 0.40f); | |
743 | + colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f); | |
744 | + colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); | |
745 | + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); | |
746 | + colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); | |
747 | + colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); | |
748 | + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); | |
749 | + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); | |
750 | + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); | |
751 | + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 0.40f); | |
752 | + colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f); | |
753 | + colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); | |
754 | + colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); | |
755 | + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f); | |
756 | + colors[ImGuiCol_Button] = ImVec4(0.67f, 0.40f, 0.40f, 0.60f); | |
757 | + colors[ImGuiCol_ButtonHovered] = ImVec4(0.67f, 0.40f, 0.40f, 1.00f); | |
758 | + colors[ImGuiCol_ButtonActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f); | |
759 | + colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); | |
760 | + colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); | |
761 | + colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); | |
762 | + colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); | |
763 | + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); | |
764 | + colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); | |
765 | + colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); | |
766 | + colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); | |
767 | + colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f); | |
768 | + colors[ImGui |