Bug Summary

File:c:\siege\siege/src/siege/graphics/font.c
Location:line 340, column 25
Description:Assigned value is garbage or undefined

Annotated Source Code

1/*
2 * Copyright (c) 2007 SIEGE Development Team
3 * All rights reserved.
4 *
5 * This file is part of libSIEGE.
6 *
7 * This software is copyrighted work licensed under the terms of the
8 * 2-clause BSD license. Please consult the file "license.txt" for
9 * details.
10 *
11 * If you did not recieve the file with this program, please email
12 * Tim Chas <darkuranium@gmail.com>.
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
29typedef struct FontFace
30{
31 stbtt_fontinfo info;
32 void* buf;
33 float scale;
34} FontFace;
35
36static SGint SG_CALL__cdecl _sgFontMapCmp(const SGdchar* a, const SGdchar* b, void* data)
37{
38 return *a - *b;
39}
40
41SGCharInfo* 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}
48SGbool 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 //if(ci != NULL)
65 info[i] = *ci;
66 }
67 }
68 return SG_TRUE1;
69}
70void 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}
83SGbool 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 //if(!data) goto err;
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; // TODO
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}
167SGubyte* 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
181void 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
189SGdchar* 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}
199SGdchar* 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}
208SGdchar* 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}
217SGdchar* 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
227static 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}
246static 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}
274static 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 //fface->scale = stbtt_ScaleForPixelHeight(&fface->info, height);
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
290typedef SGbool SG_CALL__cdecl ExecLineStartFunction(SGFont* font, const SGdchar* text, const SGdchar* start, const SGdchar* end, void* data);
291typedef SGbool SG_CALL__cdecl ExecLineEndFunction(SGFont* font, const SGdchar* text, const SGdchar* start, const SGdchar* end, float xoffset, float yoffset, void* data);
292typedef SGbool SG_CALL__cdecl ExecCharFunction(SGFont* font, const SGdchar* text, const SGdchar* chr, SGCharInfo* cinfo, float xoffset, float yoffset, void* data);
293typedef SGbool SG_CALL__cdecl ExecDoneFunction(SGFont* font, float xoffset, float yoffset, void* data);
294static SGbool SG_CALL__cdecl _sgFontExecuteU32(SGFont* font, const SGdchar* text, ExecLineStartFunction* execLineStart, ExecCharFunction* execChar, ExecLineEndFunction* execLineEnd, ExecDoneFunction* execDone, void* data)
295{
296 if(!font)
3
Taking false branch
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))
6
Taking false branch
318 goto end;
319 info = realloc(info, (end - start) * sizeof(SGCharInfo));
320 /*
321 * we actually alloc 1 more, but it's better
322 * than getting into trouble because of unsigned wrap
323 * due to end being the same as start
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))
9
Taking false branch
338 goto end;
339 if(chr != end - 1)
10
Taking true branch
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 }
349end:
350 free(info);
351 free(kerning);
352 if(execDone)
353 return execDone(font, xoffset, yoffset, data);
354 return SG_TRUE1;
355}
356
357SGFont* 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;
398err:
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}
409SGFont* 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}
419void 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
439void SG_CALL__cdecl sgFontClearCache(SGFont* font)
440{
441 _sgFontDestroyCache(font);
442 _sgFontCreateCache(font);
443}
444void SG_CALL__cdecl sgFontSetHeight(SGFont* font, float height, SGuint dpi)
445{
446 _sgFontSetHeight(font, height, dpi);
447 sgFontClearCache(font);
448}
449
450void 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}
457void 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
464void 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}
471void 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
478static 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}
484void 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}
489void 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}
495void 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}
501void 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}
507void 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
514void 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}
521void 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
528void 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}
535void 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
542void 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 // todo: only calc these when needed
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}
564void 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}
570void 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}
576void 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}
582void 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
589void 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}
596void 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
603void 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}
610void 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
617static 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}
624static 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}
630void 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}
637void 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}
643void 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}
649void 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}
655void 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
662size_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}
670size_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
678size_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}
686size_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// todo: make this bisect instead of performing a linear search
695size_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)); // append CR/LF/CRLF
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 //float avg = (int)((px + sx) * 0.5 + 0.5); // rounded of average
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 //return line - text - 1;
759}
760
761size_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}
768size_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}
775size_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}
782size_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
790void 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}
797void 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
804void 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}
811void 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
818typedef struct PosInfo
819{
820 SGVec2 pos;
821 size_t index;
822} PosInfo;
823
824static 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}
831static 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}
841static 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}
848void 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}
857void 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}
863void 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}
869void 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}
875void 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}