1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | #define SG_BUILD_LIBRARY |
16 | #include <siege/graphics/texture.h> |
17 | #include <siege/graphics/font.h> |
18 | #include <siege/util/string.h> |
19 | #include <siege/util/vector.h> |
20 | |
21 | #include <stdio.h> |
22 | #include <stdlib.h> |
23 | #include <stdarg.h> |
24 | #include <string.h> |
25 | #include <wchar.h> |
26 | |
27 | #include "../internal/stb/stb_truetype.h" |
28 | |
29 | typedef struct FontFace |
30 | { |
31 | stbtt_fontinfo info; |
32 | void* buf; |
33 | float scale; |
34 | } FontFace; |
35 | |
36 | static SGint SG_CALL__cdecl _sgFontMapCmp(const SGdchar* a, const SGdchar* b, void* data) |
37 | { |
38 | return *a - *b; |
39 | } |
40 | |
41 | SGCharInfo* SG_CALL__cdecl _sgFontFindCache(SGFont* font, SGdchar c) |
42 | { |
43 | size_t* ind = sgMapFind(font->cmap, &c); |
44 | if(!ind) return NULL((void*)0); |
45 | |
46 | return &font->cache[*ind]; |
47 | } |
48 | SGbool SG_CALL__cdecl _sgFontGetChars(SGFont* font, SGdchar* str, SGuint strlen, SGCharInfo* info) |
49 | { |
50 | if(!_sgFontLoad(font, str, strlen, SG_FALSE0)) |
51 | return SG_FALSE0; |
52 | |
53 | SGuint i; |
54 | SGCharInfo* ci; |
55 | for(i = 0; i < strlen; i++) |
56 | { |
57 | if(str[i] < font->numchars) |
58 | { |
59 | info[i] = font->chars[str[i]]; |
60 | } |
61 | else |
62 | { |
63 | ci = _sgFontFindCache(font, str[i]); |
64 | |
65 | info[i] = *ci; |
66 | } |
67 | } |
68 | return SG_TRUE1; |
69 | } |
70 | void SG_CALL__cdecl _sgFontToLoad(SGFont* font, SGdchar* input, SGuint inlen, SGdchar* output, SGuint* outlen) |
71 | { |
72 | SGuint i; |
73 | *outlen = 0; |
74 | for(i = 0; i < inlen; i++) |
75 | { |
76 | if(input[i] < font->numchars) |
77 | continue; |
78 | if(_sgFontFindCache(font, input[i]) != NULL((void*)0)) |
79 | continue; |
80 | output[(*outlen)++] = input[i]; |
81 | } |
82 | } |
83 | SGbool SG_CALL__cdecl _sgFontLoad(SGFont* font, SGdchar* chars, SGuint numchars, SGbool force) |
84 | { |
85 | SGdchar* achars = malloc(numchars * sizeof(SGdchar)); |
86 | SGuint alen = numchars; |
87 | if(!force) |
88 | _sgFontToLoad(font, chars, numchars, achars, &alen); |
89 | else |
90 | memcpy(achars, chars, numchars * sizeof(SGdchar)); |
91 | if(alen == 0) |
92 | { |
93 | free(achars); |
94 | return SG_TRUE1; |
95 | } |
96 | |
97 | FontFace* fface = font->handle; |
98 | int adv, left; |
99 | int dw, dh; |
100 | int xo, yo; |
101 | int glyph; |
102 | |
103 | SGuint i; |
104 | SGCharInfo ci; |
105 | void* data; |
106 | SGubyte* rgba; |
107 | SGCharInfo* cache; |
108 | SGdchar* key; |
109 | size_t* val; |
110 | for(i = 0; i < alen; i++) |
111 | { |
112 | glyph = stbtt_FindGlyphIndex(&fface->info, achars[i]); |
113 | |
114 | dw = dh = 0; |
115 | data = stbtt_GetGlyphBitmap(&fface->info, fface->scale, fface->scale, glyph, &dw, &dh, &xo, &yo); |
116 | |
117 | ci.dwidth = dw; |
118 | ci.dheight = dh; |
119 | |
120 | stbtt_GetGlyphHMetrics(&fface->info, glyph, &adv, &left); |
121 | ci.xpre = xo; |
122 | ci.ypre = yo; |
123 | ci.xpost = adv * fface->scale; |
124 | ci.ypost = 0; |
125 | ci.width = adv * fface->scale; |
126 | ci.height = 0; |
127 | |
128 | rgba = _sgFontToRGBA(font, data, ci.dwidth * ci.dheight); |
129 | stbtt_FreeBitmap(data, NULL((void*)0)); |
130 | |
131 | SGTexture* texture = sgTextureCreateData(ci.dwidth, ci.dheight, 32, rgba); |
132 | sgTextureSetWrap(texture, SG_WRAP_CLAMP_TO_EDGE0x02, SG_WRAP_CLAMP_TO_EDGE0x02); |
133 | free(rgba); |
134 | ci.texture = texture; |
135 | if(achars[i] < font->numchars) |
136 | { |
137 | memcpy(&font->chars[achars[i]], &ci, sizeof(SGCharInfo)); |
138 | } |
139 | else |
140 | { |
141 | cache = _sgFontFindCache(font, achars[i]); |
142 | if(cache != NULL((void*)0)) |
143 | { |
144 | sgTextureDestroy(cache->texture); |
145 | } |
146 | else |
147 | { |
148 | font->numcache++; |
149 | font->cachechars = realloc(font->cachechars, font->numcache * sizeof(SGdchar)); |
150 | font->cache = realloc(font->cache, font->numcache * sizeof(SGCharInfo)); |
151 | font->cachechars[font->numcache - 1] = achars[i]; |
152 | cache = &font->cache[font->numcache - 1]; |
153 | |
154 | key = malloc(sizeof(SGdchar)); |
155 | *key = achars[i]; |
156 | val = malloc(sizeof(size_t)); |
157 | *val = font->numcache - 1; |
158 | sgMapAssign(font->cmap, key, val); |
159 | } |
160 | memcpy(cache, &ci, sizeof(SGCharInfo)); |
161 | } |
162 | } |
163 | |
164 | free(achars); |
165 | return SG_TRUE1; |
166 | } |
167 | SGubyte* SG_CALL__cdecl _sgFontToRGBA(SGFont* font, SGubyte* data, SGuint datalen) |
168 | { |
169 | SGuint i; |
170 | SGubyte* newData = malloc(datalen * 4); |
171 | for(i = 0; i < datalen; i++) |
172 | { |
173 | newData[4*i ] = |
174 | newData[4*i+1] = |
175 | newData[4*i+2] = 0xFF; |
176 | newData[4*i+3] = data[i]; |
177 | } |
178 | return newData; |
179 | } |
180 | |
181 | void SG_CALL__cdecl _sgFontCenterOffsetU32(SGFont* font, float* x, float* y, const SGdchar* text) |
182 | { |
183 | float sx, sy; |
184 | sgFontStrSizeU32(font, &sx, &sy, text); |
185 | *x = -sx / 2.0; |
186 | *y = sy / 2.0; |
187 | } |
188 | |
189 | SGdchar* SG_CALL__cdecl _sgFontU16ToU32(SGFont* font, const SGwchar* text) |
190 | { |
191 | size_t len; |
192 | for(len = 0; text[len]; len++) { } |
193 | size_t buflen = len + 1; |
194 | |
195 | SGdchar* buf = malloc(buflen * sizeof(SGdchar)); |
196 | sgConv(font->conv[3], buf, buflen, text, len, SG_FALSE0); |
197 | return buf; |
198 | } |
199 | SGdchar* SG_CALL__cdecl _sgFontU8ToU32(SGFont* font, const SGchar* text) |
200 | { |
201 | size_t len = strlen(text); |
202 | size_t buflen = len + 1; |
203 | |
204 | SGdchar* buf = malloc(buflen * sizeof(SGdchar)); |
205 | sgConv(font->conv[2], buf, buflen, text, len, SG_FALSE0); |
206 | return buf; |
207 | } |
208 | SGdchar* SG_CALL__cdecl _sgFontWToU32(SGFont* font, const wchar_t* text) |
209 | { |
210 | size_t len = wcslen(text); |
211 | size_t buflen = len + 1; |
212 | |
213 | SGdchar* buf = malloc(buflen * sizeof(SGdchar)); |
214 | sgConv(font->conv[1], buf, buflen, text, len, SG_FALSE0); |
215 | return buf; |
216 | } |
217 | SGdchar* SG_CALL__cdecl _sgFontToU32(SGFont* font, const char* text) |
218 | { |
219 | size_t len = strlen(text); |
220 | size_t buflen = len + 1; |
221 | |
222 | SGdchar* buf = malloc(buflen * sizeof(SGdchar)); |
223 | sgConv(font->conv[0], buf, buflen, text, len, SG_FALSE0); |
224 | return buf; |
225 | } |
226 | |
227 | static void SG_CALL__cdecl _sgFontCreateCache(SGFont* font) |
228 | { |
229 | font->numchars = font->npreload; |
230 | font->chars = malloc(font->npreload * sizeof(SGCharInfo)); |
231 | |
232 | font->numcache = 0; |
233 | font->cachechars = NULL((void*)0); |
234 | font->cache = NULL((void*)0); |
235 | |
236 | font->cmap = sgMapCreate((SGMapCmp*)_sgFontMapCmp, NULL((void*)0)); |
237 | |
238 | size_t i; |
239 | SGdchar* prestr = malloc(font->npreload * sizeof(SGdchar)); |
240 | for(i = 0; i < font->npreload; i++) |
241 | prestr[i] = i; |
242 | |
243 | _sgFontLoad(font, prestr, font->npreload, SG_TRUE1); |
244 | free(prestr); |
245 | } |
246 | static void SG_CALL__cdecl _sgFontDestroyCache(SGFont* font) |
247 | { |
248 | size_t i; |
249 | for(i = 0; i < font->numchars; i++) |
250 | sgTextureDestroy(font->chars[i].texture); |
251 | for(i = 0; i < font->numcache; i++) |
252 | sgTextureDestroy(font->cache[i].texture); |
253 | |
254 | free(font->chars); |
255 | free(font->cachechars); |
256 | free(font->cache); |
257 | |
258 | SGMapNode* node; |
259 | SGdchar* key; |
260 | if(font->cmap) |
261 | { |
262 | for(;;) |
263 | { |
264 | node = sgMapGetRoot(font->cmap); |
265 | if(!node) break; |
266 | |
267 | key = node->key; |
268 | free(sgMapPopRoot(font->cmap)); |
269 | free(key); |
270 | } |
271 | sgMapDestroy(font->cmap); |
272 | } |
273 | } |
274 | static void SG_CALL__cdecl _sgFontSetHeight(SGFont* font, float height, SGuint dpi) |
275 | { |
276 | font->height = height; |
277 | font->dpi = dpi ? dpi : 96; |
278 | |
279 | FontFace* fface = font->handle; |
280 | |
281 | fface->scale = stbtt_ScaleForMappingEmToPixels(&fface->info, height * font->dpi / 72.0); |
282 | |
283 | int iasc, idesc, igap; |
284 | stbtt_GetFontVMetrics(&fface->info, &iasc, &idesc, &igap); |
285 | font->ascent = iasc * fface->scale; |
286 | font->descent = idesc * fface->scale; |
287 | font->linegap = igap * fface->scale; |
288 | } |
289 | |
290 | typedef SGbool SG_CALL__cdecl ExecLineStartFunction(SGFont* font, const SGdchar* text, const SGdchar* start, const SGdchar* end, void* data); |
291 | typedef SGbool SG_CALL__cdecl ExecLineEndFunction(SGFont* font, const SGdchar* text, const SGdchar* start, const SGdchar* end, float xoffset, float yoffset, void* data); |
292 | typedef SGbool SG_CALL__cdecl ExecCharFunction(SGFont* font, const SGdchar* text, const SGdchar* chr, SGCharInfo* cinfo, float xoffset, float yoffset, void* data); |
293 | typedef SGbool SG_CALL__cdecl ExecDoneFunction(SGFont* font, float xoffset, float yoffset, void* data); |
294 | static SGbool SG_CALL__cdecl _sgFontExecuteU32(SGFont* font, const SGdchar* text, ExecLineStartFunction* execLineStart, ExecCharFunction* execChar, ExecLineEndFunction* execLineEnd, ExecDoneFunction* execDone, void* data) |
295 | { |
296 | if(!font) |
| |
297 | return SG_FALSE0; |
298 | |
299 | FontFace* fface = font->handle; |
300 | |
301 | float xoffset = 0.0; |
302 | float yoffset = 0.0; |
303 | |
304 | const SGdchar* start = text; |
305 | const SGdchar* end; |
306 | const SGdchar* chr; |
307 | size_t line = 0; |
308 | |
309 | float linesep = font->ascent - font->descent + font->linegap; |
310 | |
311 | SGCharInfo* info = NULL((void*)0); |
312 | float* kerning = NULL((void*)0); |
313 | size_t i; |
314 | while(start != NULL((void*)0)) |
| 4 | | Assuming 'start' is not equal to null | |
|
| 5 | | Loop condition is true. Entering loop body | |
|
315 | { |
316 | end = sgLineEndU32(start); |
317 | if(execLineStart && execLineStart(font, text, start, end, data)) |
| |
318 | goto end; |
319 | info = realloc(info, (end - start) * sizeof(SGCharInfo)); |
320 | |
321 | |
322 | |
323 | |
324 | |
325 | kerning = realloc(kerning, (end - start) * sizeof(float)); |
326 | for(i = 1; i < end - start; i++) |
| 7 | | Loop condition is false. Execution continues on line 328 | |
|
327 | kerning[i-1] = stbtt_GetCodepointKernAdvance(&fface->info, start[i-1], start[i]) * fface->scale; |
328 | if(!_sgFontGetChars(font, (SGdchar*)start, end - start, info) && ((end - start) != 0)) |
329 | { |
330 | start = sgNextLineU32(start); |
331 | continue; |
332 | } |
333 | xoffset = 0.0; |
334 | yoffset = linesep * line; |
335 | for(chr = start; chr < end; chr++) |
| 8 | | Loop condition is true. Entering loop body | |
|
336 | { |
337 | if(execChar && execChar(font, text, chr, &info[chr-start], xoffset, yoffset, data)) |
| |
338 | goto end; |
339 | if(chr != end - 1) |
| |
340 | xoffset += kerning[chr - start]; |
| 11 | | Assigned value is garbage or undefined |
|
341 | xoffset += info[chr - start].xpost; |
342 | yoffset += info[chr - start].ypost; |
343 | } |
344 | if(execLineEnd && execLineEnd(font, text, start, end, xoffset, yoffset, data)) |
345 | goto end; |
346 | line++; |
347 | start = sgNextLineU32(start); |
348 | } |
349 | end: |
350 | free(info); |
351 | free(kerning); |
352 | if(execDone) |
353 | return execDone(font, xoffset, yoffset, data); |
354 | return SG_TRUE1; |
355 | } |
356 | |
357 | SGFont* SG_CALL__cdecl sgFontCreateStream(SGStream* stream, SGbool delstream, float height, SGuint dpi, SGuint preload) |
358 | { |
359 | SGFont* font = malloc(sizeof(SGFont)); |
360 | if(font == NULL((void*)0)) |
361 | return NULL((void*)0); |
362 | |
363 | font->stream = stream; |
364 | font->del = delstream; |
365 | FontFace* fface = NULL((void*)0); |
366 | |
367 | fface = malloc(sizeof(FontFace)); |
368 | if(!fface) goto err; |
369 | fface->buf = NULL((void*)0); |
370 | |
371 | font->handle = fface; |
372 | |
373 | SGlong pos = sgStreamTell(stream); |
374 | SGlong size = sgStreamTellSize(stream); |
375 | size -= pos; |
376 | if(pos < 0 || size < 0) |
377 | goto err; |
378 | |
379 | fface->buf = malloc(size); |
380 | if(sgStreamRead(stream, fface->buf, 1, size) != size) |
381 | goto err; |
382 | if(!stbtt_InitFont(&fface->info, fface->buf, 0)) |
383 | goto err; |
384 | |
385 | fface->scale = 1.0; |
386 | |
387 | font->conv[0] = sgConvCreate(SG_CONV_TYPE_UTF326, SG_CONV_TYPE_CHAR1); |
388 | font->conv[1] = sgConvCreate(SG_CONV_TYPE_UTF326, SG_CONV_TYPE_WCHAR_T2); |
389 | font->conv[2] = sgConvCreate(SG_CONV_TYPE_UTF326, SG_CONV_TYPE_UTF83); |
390 | font->conv[3] = sgConvCreate(SG_CONV_TYPE_UTF326, SG_CONV_TYPE_UTF164); |
391 | |
392 | font->npreload = preload; |
393 | |
394 | _sgFontSetHeight(font, height, dpi); |
395 | _sgFontCreateCache(font); |
396 | |
397 | return font; |
398 | err: |
399 | if(fface) |
400 | { |
401 | if(fface->buf) |
402 | free(fface->buf); |
403 | free(fface); |
404 | } |
405 | fprintf(stderr(&_iob[2]), "Warning: Cannot create font\n"); |
406 | free(font); |
407 | return NULL((void*)0); |
408 | } |
409 | SGFont* SG_CALL__cdecl sgFontCreate(const char* fname, float height, SGuint dpi, SGuint preload) |
410 | { |
411 | SGStream* stream = sgStreamCreateFile(fname, "r"); |
412 | if(!stream) |
413 | { |
414 | fprintf(stderr(&_iob[2]), "Warning: Cannot create font %s\n", fname); |
415 | return NULL((void*)0); |
416 | } |
417 | return sgFontCreateStream(stream, SG_TRUE1, height, dpi, preload); |
418 | } |
419 | void SG_CALL__cdecl sgFontDestroy(SGFont* font) |
420 | { |
421 | if(font == NULL((void*)0)) |
422 | return; |
423 | |
424 | size_t i; |
425 | for(i = 0; i < 4; i++) |
426 | sgConvDestroy(font->conv[i]); |
427 | |
428 | FontFace* fface = font->handle; |
429 | free(fface->buf); |
430 | free(fface); |
431 | |
432 | _sgFontDestroyCache(font); |
433 | |
434 | if(font->del) |
435 | sgStreamDestroy(font->stream); |
436 | free(font); |
437 | } |
438 | |
439 | void SG_CALL__cdecl sgFontClearCache(SGFont* font) |
440 | { |
441 | _sgFontDestroyCache(font); |
442 | _sgFontCreateCache(font); |
443 | } |
444 | void SG_CALL__cdecl sgFontSetHeight(SGFont* font, float height, SGuint dpi) |
445 | { |
446 | _sgFontSetHeight(font, height, dpi); |
447 | sgFontClearCache(font); |
448 | } |
449 | |
450 | void SG_CALL__cdecl sgFontPrintfW(SGFont* font, float x, float y, const wchar_t* format, ...) |
451 | { |
452 | va_list args; |
453 | va_start(args, format)__builtin_va_start(args, format); |
454 | sgFontPrintfvW(font, x, y, format, args); |
455 | va_end(args)__builtin_va_end(args); |
456 | } |
457 | void SG_CALL__cdecl sgFontPrintfvW(SGFont* font, float x, float y, const wchar_t* format, va_list args) |
458 | { |
459 | wchar_t* buf = sgAPrintfvW(format, args); |
460 | sgFontPrintW(font, x, y, buf); |
461 | sgAPrintFree(buf); |
462 | } |
463 | |
464 | void SG_CALL__cdecl sgFontPrintf(SGFont* font, float x, float y, const char* format, ...) |
465 | { |
466 | va_list args; |
467 | va_start(args, format)__builtin_va_start(args, format); |
468 | sgFontPrintfv(font, x, y, format, args); |
469 | va_end(args)__builtin_va_end(args); |
470 | } |
471 | void SG_CALL__cdecl sgFontPrintfv(SGFont* font, float x, float y, const char* format, va_list args) |
472 | { |
473 | char* buf = sgAPrintfv(format, args); |
474 | sgFontPrint(font, x, y, buf); |
475 | sgAPrintFree(buf); |
476 | } |
477 | |
478 | static SGbool SG_CALL__cdecl _printChar(SGFont* font, const SGdchar* text, const SGdchar* chr, SGCharInfo* cinfo, float xoffset, float yoffset, void* data) |
479 | { |
480 | SGVec2* pos = data; |
481 | sgTextureDrawRads3f2f2f1f(cinfo->texture, pos->x + xoffset + cinfo->xpre, ((int)(pos->y + yoffset)) + cinfo->ypre, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0); |
482 | return SG_FALSE0; |
483 | } |
484 | void SG_CALL__cdecl sgFontPrintU32(SGFont* font, float x, float y, const SGdchar* text) |
485 | { |
486 | SGVec2 pos = sgVec2f(x, y); |
487 | _sgFontExecuteU32(font, text, NULL((void*)0), _printChar, NULL((void*)0), NULL((void*)0), &pos); |
488 | } |
489 | void SG_CALL__cdecl sgFontPrintU16(SGFont* font, float x, float y, const SGwchar* text) |
490 | { |
491 | SGdchar* dtext = _sgFontU16ToU32(font, text); |
492 | sgFontPrintU32(font, x, y, dtext); |
493 | free(dtext); |
494 | } |
495 | void SG_CALL__cdecl sgFontPrintU8(SGFont* font, float x, float y, const SGchar* text) |
496 | { |
497 | SGdchar* dtext = _sgFontU8ToU32(font, text); |
498 | sgFontPrintU32(font, x, y, dtext); |
499 | free(dtext); |
500 | } |
501 | void SG_CALL__cdecl sgFontPrintW(SGFont* font, float x, float y, const wchar_t* text) |
502 | { |
503 | SGdchar* dtext = _sgFontWToU32(font, text); |
504 | sgFontPrintU32(font, x, y, dtext); |
505 | free(dtext); |
506 | } |
507 | void SG_CALL__cdecl sgFontPrint(SGFont* font, float x, float y, const char* text) |
508 | { |
509 | SGdchar* dtext = _sgFontToU32(font, text); |
510 | sgFontPrintU32(font, x, y, dtext); |
511 | free(dtext); |
512 | } |
513 | |
514 | void SG_CALL__cdecl sgFontPrintAlignedfW(SGFont* font, float x, float y, SGenum align, const wchar_t* format, ...) |
515 | { |
516 | va_list args; |
517 | va_start(args, format)__builtin_va_start(args, format); |
518 | sgFontPrintAlignedfvW(font, x, y, align, format, args); |
519 | va_end(args)__builtin_va_end(args); |
520 | } |
521 | void SG_CALL__cdecl sgFontPrintAlignedfvW(SGFont* font, float x, float y, SGenum align, const wchar_t* format, va_list args) |
522 | { |
523 | wchar_t* buf = sgAPrintfvW(format, args); |
524 | sgFontPrintAlignedW(font, x, y, align, buf); |
525 | sgAPrintFree(buf); |
526 | } |
527 | |
528 | void SG_CALL__cdecl SG_HINT_PRINTF(5, 6)__attribute__((format(printf, 5, 6))) sgFontPrintAlignedf(SGFont* font, float x, float y, SGenum align, const char* format, ...) |
529 | { |
530 | va_list args; |
531 | va_start(args, format)__builtin_va_start(args, format); |
532 | sgFontPrintAlignedfv(font, x, y, align, format, args); |
533 | va_end(args)__builtin_va_end(args); |
534 | } |
535 | void SG_CALL__cdecl SG_HINT_PRINTF(5, 0)__attribute__((format(printf, 5, 0))) sgFontPrintAlignedfv(SGFont* font, float x, float y, SGenum align, const char* format, va_list args) |
536 | { |
537 | char* buf = sgAPrintfv(format, args); |
538 | sgFontPrintAligned(font, x, y, align, buf); |
539 | sgAPrintFree(buf); |
540 | } |
541 | |
542 | void SG_CALL__cdecl sgFontPrintAlignedU32(SGFont* font, float x, float y, SGenum align, const SGdchar* text) |
543 | { |
544 | float ox, oy; |
545 | float sx, sy; |
546 | |
547 | _sgFontCenterOffsetU32(font, &ox, &oy, text); |
548 | sgFontStrSizeU32(font, &sx, &sy, text); |
549 | switch(align & SG_ALIGN_HMASK0x0F) |
550 | { |
551 | case SG_ALIGN_CENTER0x00: x += ox; break; |
552 | case SG_ALIGN_LEFT0x01: break; |
553 | case SG_ALIGN_RIGHT0x02: x += ox - sx / 2.0; break; |
554 | } |
555 | switch(align & SG_ALIGN_VMASK0xF0) |
556 | { |
557 | case SG_ALIGN_CENTER0x00: y += oy; break; |
558 | case SG_ALIGN_TOP0x10: y += oy + sy / 2.0; break; |
559 | case SG_ALIGN_BASELINE0x20: break; |
560 | case SG_ALIGN_BOTTOM0x40: y += oy - sy / 2.0; break; |
561 | } |
562 | sgFontPrintU32(font, x, y, text); |
563 | } |
564 | void SG_CALL__cdecl sgFontPrintAlignedU16(SGFont* font, float x, float y, SGenum align, const SGwchar* text) |
565 | { |
566 | SGdchar* dtext = _sgFontU16ToU32(font, text); |
567 | sgFontPrintAlignedU32(font, x, y, align, dtext); |
568 | free(dtext); |
569 | } |
570 | void SG_CALL__cdecl sgFontPrintAlignedU8(SGFont* font, float x, float y, SGenum align, const SGchar* text) |
571 | { |
572 | SGdchar* dtext = _sgFontU8ToU32(font, text); |
573 | sgFontPrintAlignedU32(font, x, y, align, dtext); |
574 | free(dtext); |
575 | } |
576 | void SG_CALL__cdecl sgFontPrintAlignedW(SGFont* font, float x, float y, SGenum align, const wchar_t* text) |
577 | { |
578 | SGdchar* dtext = _sgFontWToU32(font, text); |
579 | sgFontPrintAlignedU32(font, x, y, align, dtext); |
580 | free(dtext); |
581 | } |
582 | void SG_CALL__cdecl sgFontPrintAligned(SGFont* font, float x, float y, SGenum align, const char* text) |
583 | { |
584 | SGdchar* dtext = _sgFontToU32(font, text); |
585 | sgFontPrintAlignedU32(font, x, y, align, dtext); |
586 | free(dtext); |
587 | } |
588 | |
589 | void SG_CALL__cdecl sgFontStrSizefW(SGFont* font, float* x, float* y, const wchar_t* format, ...) |
590 | { |
591 | va_list args; |
592 | va_start(args, format)__builtin_va_start(args, format); |
593 | sgFontStrSizefvW(font, x, y, format, args); |
594 | va_end(args)__builtin_va_end(args); |
595 | } |
596 | void SG_CALL__cdecl sgFontStrSizefvW(SGFont* font, float* x, float* y, const wchar_t* format, va_list args) |
597 | { |
598 | wchar_t* buf = sgAPrintfvW(format, args); |
599 | sgFontStrSizeW(font, x, y, buf); |
600 | sgAPrintFree(buf); |
601 | } |
602 | |
603 | void SG_CALL__cdecl sgFontStrSizef(SGFont* font, float* x, float* y, const char* format, ...) |
604 | { |
605 | va_list args; |
606 | va_start(args, format)__builtin_va_start(args, format); |
607 | sgFontStrSizefv(font, x, y, format, args); |
608 | va_end(args)__builtin_va_end(args); |
609 | } |
610 | void SG_CALL__cdecl sgFontStrSizefv(SGFont* font, float* x, float* y, const char* format, va_list args) |
611 | { |
612 | char* buf = sgAPrintfv(format, args); |
613 | sgFontStrSize(font, x, y, buf); |
614 | sgAPrintFree(buf); |
615 | } |
616 | |
617 | static SGbool SG_CALL__cdecl _strSizeLineEnd(SGFont* font, const SGdchar* text, const SGdchar* start, const SGdchar* end, float xoffset, float yoffset, void* data) |
618 | { |
619 | SGVec2* size = data; |
620 | if(size->x < xoffset) |
621 | size->x = xoffset; |
622 | return SG_FALSE0; |
623 | } |
624 | static SGbool SG_CALL__cdecl _strSizeDone(SGFont* font, float xoffset, float yoffset, void* data) |
625 | { |
626 | SGVec2* size = data; |
627 | size->y = yoffset + font->ascent - font->descent; |
628 | return SG_TRUE1; |
629 | } |
630 | void SG_CALL__cdecl sgFontStrSizeU32(SGFont* font, float* x, float* y, const SGdchar* text) |
631 | { |
632 | SGVec2 size = sgVec2f(0.0, 0.0); |
633 | _sgFontExecuteU32(font, text, NULL((void*)0), NULL((void*)0), _strSizeLineEnd, _strSizeDone, &size); |
634 | *x = size.x; |
635 | *y = size.y; |
636 | } |
637 | void SG_CALL__cdecl sgFontStrSizeU16(SGFont* font, float* x, float* y, const SGwchar* text) |
638 | { |
639 | SGdchar* dtext = _sgFontU16ToU32(font, text); |
640 | sgFontStrSizeU32(font, x, y, dtext); |
641 | free(dtext); |
642 | } |
643 | void SG_CALL__cdecl sgFontStrSizeU8(SGFont* font, float* x, float* y, const SGchar* text) |
644 | { |
645 | SGdchar* dtext = _sgFontU8ToU32(font, text); |
646 | sgFontStrSizeU32(font, x, y, dtext); |
647 | free(dtext); |
648 | } |
649 | void SG_CALL__cdecl sgFontStrSizeW(SGFont* font, float* x, float* y, const wchar_t* text) |
650 | { |
651 | SGdchar* dtext = _sgFontWToU32(font, text); |
652 | sgFontStrSizeU32(font, x, y, dtext); |
653 | free(dtext); |
654 | } |
655 | void SG_CALL__cdecl sgFontStrSize(SGFont* font, float* x, float* y, const char* text) |
656 | { |
657 | SGdchar* dtext = _sgFontToU32(font, text); |
658 | sgFontStrSizeU32(font, x, y, dtext); |
659 | free(dtext); |
660 | } |
661 | |
662 | size_t SG_CALL__cdecl sgFontFindIndexfW(SGFont* font, float x, float y, const wchar_t* format, ...) |
663 | { |
664 | va_list args; |
665 | va_start(args, format)__builtin_va_start(args, format); |
666 | size_t pos = sgFontFindIndexfvW(font, x, y, format, args); |
667 | va_end(args)__builtin_va_end(args); |
668 | return pos; |
669 | } |
670 | size_t SG_CALL__cdecl sgFontFindIndexfvW(SGFont* font, float x, float y, const wchar_t* format, va_list args) |
671 | { |
672 | wchar_t* buf = sgAPrintfvW(format, args); |
673 | size_t ind = sgFontFindIndexW(font, x, y, buf); |
674 | sgAPrintFree(buf); |
675 | return ind; |
676 | } |
677 | |
678 | size_t SG_CALL__cdecl sgFontFindIndexf(SGFont* font, float x, float y, const char* format, ...) |
679 | { |
680 | va_list args; |
681 | va_start(args, format)__builtin_va_start(args, format); |
682 | size_t pos = sgFontFindIndexfv(font, x, y, format, args); |
683 | va_end(args)__builtin_va_end(args); |
684 | return pos; |
685 | } |
686 | size_t SG_CALL__cdecl sgFontFindIndexfv(SGFont* font, float x, float y, const char* format, va_list args) |
687 | { |
688 | char* buf = sgAPrintfv(format, args); |
689 | size_t ind = sgFontFindIndex(font, x, y, buf); |
690 | sgAPrintFree(buf); |
691 | return ind; |
692 | } |
693 | |
694 | |
695 | size_t SG_CALL__cdecl sgFontFindIndexU32(SGFont* font, float x, float y, const SGdchar* text) |
696 | { |
697 | y += font->height; |
698 | |
699 | size_t len; |
700 | for(len = 0; text[len]; len++) |
701 | { |
702 | } |
703 | if(len == 0) |
704 | return 0; |
705 | |
706 | SGdchar* cpy = malloc((len + 1) * sizeof(SGdchar)); |
707 | memset(cpy, 0, (len + 1) * sizeof(SGdchar)); |
708 | |
709 | float sx, sy, px; |
710 | |
711 | const SGdchar* prev = text; |
712 | const SGdchar* line = text; |
713 | const SGdchar* end; |
714 | |
715 | do |
716 | { |
717 | end = sgLineEndU32(line); |
718 | |
719 | memcpy(&cpy[line-text], &text[line-text], (end - line) * sizeof(SGdchar)); |
720 | |
721 | sgFontStrSizeU32(font, &sx, &sy, cpy); |
722 | |
723 | prev = line; |
724 | line = sgNextLineU32(end); |
725 | |
726 | if(line) |
727 | memcpy(&cpy[end-text], &text[end-text], (line - end) * sizeof(SGdchar)); |
728 | } |
729 | while(line && sy < y); |
730 | |
731 | end = sgLineEndU32(prev); |
732 | memcpy(cpy, &text[prev-text], (end-prev) * sizeof(SGdchar)); |
733 | |
734 | sx = 0.0; |
735 | |
736 | line = prev; |
737 | do |
738 | { |
739 | cpy[line - prev] = *line; |
740 | cpy[line - prev + 1] = 0; |
741 | |
742 | px = sx; |
743 | sgFontStrSizeU32(font, &sx, &sy, cpy); |
744 | |
745 | line++; |
746 | } |
747 | while(line < end && sx < x); |
748 | |
749 | free(cpy); |
750 | |
751 | if(sx < x) |
752 | return line - text; |
753 | |
754 | |
755 | if(SG_ABS(px - x)(((px - x) < 0) ? -(px - x) : (px - x)) < SG_ABS(sx - x)(((sx - x) < 0) ? -(sx - x) : (sx - x))) |
756 | return line - text - 1; |
757 | return line - text; |
758 | |
759 | } |
760 | |
761 | size_t SG_CALL__cdecl sgFontFindIndexU16(SGFont* font, float x, float y, const SGwchar* text) |
762 | { |
763 | SGdchar* dtext = _sgFontU16ToU32(font, text); |
764 | size_t pos = sgFontFindIndexU32(font, x, y, dtext); |
765 | free(dtext); |
766 | return pos; |
767 | } |
768 | size_t SG_CALL__cdecl sgFontFindIndexU8(SGFont* font, float x, float y, const SGchar* text) |
769 | { |
770 | SGdchar* dtext = _sgFontU8ToU32(font, text); |
771 | size_t pos = sgFontFindIndexU32(font, x, y, dtext); |
772 | free(dtext); |
773 | return pos; |
774 | } |
775 | size_t SG_CALL__cdecl sgFontFindIndexW(SGFont* font, float x, float y, const wchar_t* text) |
776 | { |
777 | SGdchar* dtext = _sgFontWToU32(font, text); |
778 | size_t pos = sgFontFindIndexU32(font, x, y, dtext); |
779 | free(dtext); |
780 | return pos; |
781 | } |
782 | size_t SG_CALL__cdecl sgFontFindIndex(SGFont* font, float x, float y, const char* text) |
783 | { |
784 | SGdchar* dtext = _sgFontToU32(font, text); |
785 | size_t pos = sgFontFindIndexU32(font, x, y, dtext); |
786 | free(dtext); |
787 | return pos; |
788 | } |
789 | |
790 | void SG_CALL__cdecl sgFontGetPosfW(SGFont* font, float* x, float* y, size_t index, const wchar_t* format, ...) |
791 | { |
792 | va_list args; |
793 | va_start(args, format)__builtin_va_start(args, format); |
794 | sgFontGetPosfvW(font, x, y, index, format, args); |
795 | va_end(args)__builtin_va_end(args); |
796 | } |
797 | void SG_CALL__cdecl sgFontGetPosfvW(SGFont* font, float* x, float* y, size_t index, const wchar_t* format, va_list args) |
798 | { |
799 | wchar_t* buf = sgAPrintfvW(format, args); |
800 | sgFontGetPosW(font, x, y, index, buf); |
801 | sgAPrintFree(buf); |
802 | } |
803 | |
804 | void SG_CALL__cdecl SG_HINT_PRINTF(5, 6)__attribute__((format(printf, 5, 6))) sgFontGetPosf(SGFont* font, float* x, float* y, size_t index, const char* format, ...) |
805 | { |
806 | va_list args; |
807 | va_start(args, format)__builtin_va_start(args, format); |
808 | sgFontGetPosfv(font, x, y, index, format, args); |
809 | va_end(args)__builtin_va_end(args); |
810 | } |
811 | void SG_CALL__cdecl SG_HINT_PRINTF(5, 0)__attribute__((format(printf, 5, 0))) sgFontGetPosfv(SGFont* font, float* x, float* y, size_t index, const char* format, va_list args) |
812 | { |
813 | char* buf = sgAPrintfv(format, args); |
814 | sgFontGetPos(font, x, y, index, buf); |
815 | sgAPrintFree(buf); |
816 | } |
817 | |
818 | typedef struct PosInfo |
819 | { |
820 | SGVec2 pos; |
821 | size_t index; |
822 | } PosInfo; |
823 | |
824 | static SGbool SG_CALL__cdecl _getPosLineStart(SGFont* font, const SGdchar* text, const SGdchar* start, const SGdchar* end, void* data) |
825 | { |
826 | PosInfo* pi = data; |
827 | if(start - text > pi->index) |
828 | return SG_TRUE1; |
829 | return SG_FALSE0; |
830 | } |
831 | static SGbool SG_CALL__cdecl _getPosChar(SGFont* font, const SGdchar* text, const SGdchar* chr, SGCharInfo* cinfo, float xoffset, float yoffset, void* data) |
832 | { |
833 | PosInfo* pi = data; |
834 | if(chr - text == pi->index) |
835 | { |
836 | pi->pos.x += cinfo->xpre; |
837 | return SG_TRUE1; |
838 | } |
839 | return SG_FALSE0; |
840 | } |
841 | static SGbool SG_CALL__cdecl _getPosDone(SGFont* font, float xoffset, float yoffset, void* data) |
842 | { |
843 | PosInfo* pi = data; |
844 | pi->pos.x += xoffset; |
845 | pi->pos.y += yoffset; |
846 | return SG_TRUE1; |
847 | } |
848 | void SG_CALL__cdecl sgFontGetPosU32(SGFont* font, float* x, float* y, size_t index, const SGdchar* text) |
849 | { |
850 | PosInfo pi; |
851 | pi.pos = sgVec2f(0.0, 0.0); |
852 | pi.index = index; |
853 | _sgFontExecuteU32(font, text, _getPosLineStart, _getPosChar, NULL((void*)0), _getPosDone, &pi); |
| 2 | | Calling '_sgFontExecuteU32' | |
|
854 | *x = pi.pos.x; |
855 | *y = pi.pos.y; |
856 | } |
857 | void SG_CALL__cdecl sgFontGetPosU16(SGFont* font, float* x, float* y, size_t index, const SGwchar* text) |
858 | { |
859 | SGdchar* dtext = _sgFontU16ToU32(font, text); |
860 | sgFontGetPosU32(font, x, y, index, dtext); |
861 | free(dtext); |
862 | } |
863 | void SG_CALL__cdecl sgFontGetPosU8(SGFont* font, float* x, float* y, size_t index, const SGchar* text) |
864 | { |
865 | SGdchar* dtext = _sgFontU8ToU32(font, text); |
866 | sgFontGetPosU32(font, x, y, index, dtext); |
867 | free(dtext); |
868 | } |
869 | void SG_CALL__cdecl sgFontGetPosW(SGFont* font, float* x, float* y, size_t index, const wchar_t* text) |
870 | { |
871 | SGdchar* dtext = _sgFontWToU32(font, text); |
872 | sgFontGetPosU32(font, x, y, index, dtext); |
873 | free(dtext); |
874 | } |
875 | void SG_CALL__cdecl sgFontGetPos(SGFont* font, float* x, float* y, size_t index, const char* text) |
876 | { |
877 | SGdchar* dtext = _sgFontToU32(font, text); |
878 | sgFontGetPosU32(font, x, y, index, dtext); |
| 1 | Calling 'sgFontGetPosU32' | |
|
879 | free(dtext); |
880 | } |