Annotation of /trunk/linterm_tools/fw_builder/bootsplash/ttf.c
Parent Directory | Revision Log
Revision 658 -
(hide annotations)
(download)
Mon Jan 14 16:57:24 2008 UTC (16 years, 4 months ago) by niro
File MIME type: text/plain
File size: 17482 byte(s)
Mon Jan 14 16:57:24 2008 UTC (16 years, 4 months ago) by niro
File MIME type: text/plain
File size: 17482 byte(s)
initial import
1 | niro | 658 | /* render true type fonts to fb0 |
2 | * | ||
3 | * (w) by stepan@suse.de, code reused from SDL_ttf | ||
4 | * | ||
5 | */ | ||
6 | |||
7 | #include <math.h> | ||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #include <assert.h> | ||
12 | |||
13 | #include <freetype/freetype.h> | ||
14 | #include <freetype/ftoutln.h> | ||
15 | #include <freetype/ttnameid.h> | ||
16 | |||
17 | #include "ttf.h" | ||
18 | |||
19 | #define DEFAULT_PTSIZE 18 | ||
20 | |||
21 | |||
22 | /* FIXME: Right now we assume the gray-scale renderer Freetype is using | ||
23 | * supports 256 shades of gray, but we should instead key off of num_grays | ||
24 | * in the result FT_Bitmap after the FT_Render_Glyph() call. */ | ||
25 | #define NUM_GRAYS 256 | ||
26 | |||
27 | |||
28 | extern unsigned int fbbytes, fbx, fby, fblinelen, alpha; | ||
29 | extern unsigned char *framebuffer; | ||
30 | |||
31 | extern unsigned int fbypos, fbxpos; | ||
32 | |||
33 | unsigned char *TTF_RenderUNICODE_Shaded(TTF_Font * font, | ||
34 | const unsigned short *text, | ||
35 | unsigned int fg, unsigned int bg); | ||
36 | |||
37 | /* Cached glyph information */ | ||
38 | typedef struct cached_glyph { | ||
39 | int stored; | ||
40 | FT_UInt index; | ||
41 | FT_Bitmap bitmap; | ||
42 | FT_Bitmap pixmap; | ||
43 | int minx; | ||
44 | int maxx; | ||
45 | int miny; | ||
46 | int maxy; | ||
47 | int yoffset; | ||
48 | int advance; | ||
49 | unsigned short cached; | ||
50 | } c_glyph; | ||
51 | |||
52 | struct _TTF_Font { | ||
53 | /* Freetype2 maintains all sorts of useful info itself */ | ||
54 | FT_Face face; | ||
55 | |||
56 | /* We'll cache these ourselves */ | ||
57 | int height; | ||
58 | int ascent; | ||
59 | int descent; | ||
60 | int lineskip; | ||
61 | |||
62 | /* The font style */ | ||
63 | int style; | ||
64 | |||
65 | /* Extra width in glyph bounds for text styles */ | ||
66 | int glyph_overhang; | ||
67 | float glyph_italics; | ||
68 | |||
69 | /* Information in the font for underlining */ | ||
70 | int underline_offset; | ||
71 | int underline_height; | ||
72 | |||
73 | /* Cache for style-transformed glyphs */ | ||
74 | c_glyph *current; | ||
75 | c_glyph cache[256]; | ||
76 | c_glyph scratch; | ||
77 | }; | ||
78 | |||
79 | static void Flush_Glyph(c_glyph * glyph); | ||
80 | |||
81 | static void Flush_Cache(TTF_Font * font) | ||
82 | { | ||
83 | int i; | ||
84 | int size = sizeof(font->cache) / sizeof(font->cache[0]); | ||
85 | |||
86 | for (i = 0; i < size; ++i) { | ||
87 | if (font->cache[i].cached) { | ||
88 | Flush_Glyph(&font->cache[i]); | ||
89 | } | ||
90 | |||
91 | } | ||
92 | if (font->scratch.cached) { | ||
93 | Flush_Glyph(&font->scratch); | ||
94 | } | ||
95 | |||
96 | } | ||
97 | |||
98 | |||
99 | /* character conversion */ | ||
100 | |||
101 | /* Macro to convert a character to a Unicode value -- assume already Unicode */ | ||
102 | #define UNICODE(c) c | ||
103 | |||
104 | |||
105 | |||
106 | static unsigned short *ASCII_to_UNICODE(unsigned short *unicode, | ||
107 | const char *text, int len) | ||
108 | { | ||
109 | int i; | ||
110 | |||
111 | for (i = 0; i < len; ++i) { | ||
112 | unicode[i] = ((const unsigned char *) text)[i]; | ||
113 | } | ||
114 | unicode[i] = 0; | ||
115 | |||
116 | return unicode; | ||
117 | } | ||
118 | |||
119 | #if 0 | ||
120 | static unsigned short *UTF8_to_UNICODE(unsigned short *unicode, | ||
121 | const char *utf8, int len) | ||
122 | { | ||
123 | int i, j; | ||
124 | unsigned short ch; | ||
125 | |||
126 | for (i = 0, j = 0; i < len; ++i, ++j) { | ||
127 | ch = ((const unsigned char *) utf8)[i]; | ||
128 | if (ch >= 0xF0) { | ||
129 | ch = (unsigned short) (utf8[i] & 0x07) << 18; | ||
130 | ch |= (unsigned short) (utf8[++i] & 0x3F) << 12; | ||
131 | ch |= (unsigned short) (utf8[++i] & 0x3F) << 6; | ||
132 | ch |= (unsigned short) (utf8[++i] & 0x3F); | ||
133 | } else if (ch >= 0xE0) { | ||
134 | ch = (unsigned short) (utf8[i] & 0x3F) << 12; | ||
135 | ch |= (unsigned short) (utf8[++i] & 0x3F) << 6; | ||
136 | ch |= (unsigned short) (utf8[++i] & 0x3F); | ||
137 | } else if (ch >= 0xC0) { | ||
138 | ch = (unsigned short) (utf8[i] & 0x3F) << 6; | ||
139 | ch |= (unsigned short) (utf8[++i] & 0x3F); | ||
140 | } | ||
141 | unicode[j] = ch; | ||
142 | } | ||
143 | unicode[j] = 0; | ||
144 | |||
145 | return unicode; | ||
146 | } | ||
147 | #endif | ||
148 | |||
149 | /* TTF stuff */ | ||
150 | |||
151 | static FT_Library library; | ||
152 | static int TTF_initialized = 0; | ||
153 | |||
154 | int TTF_Init(void) | ||
155 | { | ||
156 | int status; | ||
157 | FT_Error error; | ||
158 | |||
159 | status = 0; | ||
160 | error = FT_Init_FreeType(&library); | ||
161 | if (error) { | ||
162 | fprintf(stderr, "Couldn't init FreeType engine %d\n", | ||
163 | error); | ||
164 | status = -1; | ||
165 | } else { | ||
166 | TTF_initialized = 1; | ||
167 | } | ||
168 | return status; | ||
169 | } | ||
170 | |||
171 | void TTF_Quit(void) | ||
172 | { | ||
173 | if (TTF_initialized) { | ||
174 | FT_Done_FreeType(library); | ||
175 | } | ||
176 | TTF_initialized = 0; | ||
177 | } | ||
178 | |||
179 | #if 0 | ||
180 | SDL_Surface *TTF_RenderText_Solid(TTF_Font * font, | ||
181 | const char *text, SDL_Color fg) | ||
182 | { | ||
183 | SDL_Surface *textbuf; | ||
184 | Uint16 *unicode_text; | ||
185 | int unicode_len; | ||
186 | |||
187 | /* Copy the Latin-1 text to a UNICODE text buffer */ | ||
188 | unicode_len = strlen(text); | ||
189 | unicode_text = | ||
190 | (Uint16 *) malloc((unicode_len + 1) * (sizeof *unicode_text)); | ||
191 | if (unicode_text == NULL) { | ||
192 | TTF_SetError("Out of memory"); | ||
193 | return (NULL); | ||
194 | } | ||
195 | ASCII_to_UNICODE(unicode_text, text, unicode_len); | ||
196 | |||
197 | RenderUnicode(font, unicode_text, fg); | ||
198 | |||
199 | /* Render the new text */ | ||
200 | textbuf = TTF_RenderUNICODE_Solid(font, unicode_text, fg); | ||
201 | |||
202 | /* Free the text buffer and return */ | ||
203 | free(unicode_text); | ||
204 | return (textbuf); | ||
205 | } | ||
206 | #endif | ||
207 | |||
208 | unsigned char *TTF_RenderText_Shaded(TTF_Font * font, const char *text, | ||
209 | unsigned int fg, unsigned int bg) | ||
210 | { | ||
211 | unsigned char *textbuf; | ||
212 | unsigned short *unicode_text; | ||
213 | int unicode_len; | ||
214 | |||
215 | /* Copy the Latin-1 text to a UNICODE text buffer */ | ||
216 | unicode_len = strlen(text); | ||
217 | unicode_text = | ||
218 | (unsigned short *) malloc((unicode_len + 1) * | ||
219 | (sizeof *unicode_text)); | ||
220 | if (unicode_text == NULL) { | ||
221 | printf("Out of memory\n"); | ||
222 | return (NULL); | ||
223 | } | ||
224 | ASCII_to_UNICODE(unicode_text, text, unicode_len); | ||
225 | |||
226 | /* Render the new text */ | ||
227 | textbuf = TTF_RenderUNICODE_Shaded(font, unicode_text, fg, bg); | ||
228 | |||
229 | /* Free the text buffer and return */ | ||
230 | free(unicode_text); | ||
231 | return (textbuf); | ||
232 | } | ||
233 | |||
234 | |||
235 | |||
236 | void TTF_CloseFont(TTF_Font * font) | ||
237 | { | ||
238 | Flush_Cache(font); | ||
239 | FT_Done_Face(font->face); | ||
240 | free(font); | ||
241 | } | ||
242 | |||
243 | void TTF_SetFontStyle(TTF_Font * font, int style) | ||
244 | { | ||
245 | font->style = style; | ||
246 | Flush_Cache(font); | ||
247 | } | ||
248 | |||
249 | |||
250 | |||
251 | TTF_Font *TTF_OpenFontIndex(const char *file, int ptsize, long index) | ||
252 | { | ||
253 | TTF_Font *font; | ||
254 | FT_Error error; | ||
255 | FT_Face face; | ||
256 | FT_Fixed scale; | ||
257 | |||
258 | extern int strict_font; | ||
259 | |||
260 | font = (TTF_Font *) malloc(sizeof *font); | ||
261 | if (font == NULL) { | ||
262 | fprintf(stderr, "Out of memory\n"); | ||
263 | return NULL; | ||
264 | } | ||
265 | memset(font, 0, sizeof(*font)); | ||
266 | |||
267 | /* Open the font and create ancillary data */ | ||
268 | error = FT_New_Face(library, file, 0, &font->face); | ||
269 | |||
270 | if (error && !strict_font) | ||
271 | error = | ||
272 | FT_New_Memory_Face(library, | ||
273 | (const FT_Byte *) luxisri_ttf, | ||
274 | LUXISRI_SIZE, 0, &font->face); | ||
275 | |||
276 | if (error) { | ||
277 | printf("Couldn't load font file\n"); | ||
278 | free(font); | ||
279 | return NULL; | ||
280 | } | ||
281 | |||
282 | if (index != 0) { | ||
283 | if (font->face->num_faces > index) { | ||
284 | FT_Done_Face(font->face); | ||
285 | error = | ||
286 | FT_New_Face(library, file, index, &font->face); | ||
287 | if (error) { | ||
288 | printf("Couldn't get font face\n"); | ||
289 | free(font); | ||
290 | return NULL; | ||
291 | } | ||
292 | } else { | ||
293 | fprintf(stderr, "No such font face\n"); | ||
294 | free(font); | ||
295 | return NULL; | ||
296 | } | ||
297 | } | ||
298 | face = font->face; | ||
299 | |||
300 | /* Make sure that our font face is scalable (global metrics) */ | ||
301 | if (!FT_IS_SCALABLE(face)) { | ||
302 | fprintf(stderr, "Font face is not scalable\n"); | ||
303 | TTF_CloseFont(font); | ||
304 | return NULL; | ||
305 | } | ||
306 | /* Set the character size and use default DPI (72) */ | ||
307 | error = FT_Set_Char_Size(font->face, 0, ptsize * 64, 0, 0); | ||
308 | if (error) { | ||
309 | fprintf(stderr, "Couldn't set font size\n"); | ||
310 | TTF_CloseFont(font); | ||
311 | return NULL; | ||
312 | } | ||
313 | |||
314 | /* Get the scalable font metrics for this font */ | ||
315 | scale = face->size->metrics.y_scale; | ||
316 | font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale)); | ||
317 | font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale)); | ||
318 | font->height = font->ascent - font->descent + /* baseline */ 1; | ||
319 | font->lineskip = FT_CEIL(FT_MulFix(face->height, scale)); | ||
320 | font->underline_offset = | ||
321 | FT_FLOOR(FT_MulFix(face->underline_position, scale)); | ||
322 | font->underline_height = | ||
323 | FT_FLOOR(FT_MulFix(face->underline_thickness, scale)); | ||
324 | if (font->underline_height < 1) { | ||
325 | font->underline_height = 1; | ||
326 | } | ||
327 | #ifdef DEBUG_FONTS | ||
328 | printf("Font metrics:\n"); | ||
329 | printf("\tascent = %d, descent = %d\n", | ||
330 | font->ascent, font->descent); | ||
331 | printf("\theight = %d, lineskip = %d\n", | ||
332 | font->height, font->lineskip); | ||
333 | printf("\tunderline_offset = %d, underline_height = %d\n", | ||
334 | font->underline_offset, font->underline_height); | ||
335 | #endif | ||
336 | |||
337 | /* Set the default font style */ | ||
338 | font->style = TTF_STYLE_NORMAL; | ||
339 | font->glyph_overhang = face->size->metrics.y_ppem / 10; | ||
340 | /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */ | ||
341 | font->glyph_italics = 0.207f; | ||
342 | font->glyph_italics *= font->height; | ||
343 | |||
344 | return font; | ||
345 | } | ||
346 | |||
347 | |||
348 | |||
349 | TTF_Font *TTF_OpenFont(const char *file, int ptsize) | ||
350 | { | ||
351 | return TTF_OpenFontIndex(file, ptsize, 0); | ||
352 | } | ||
353 | |||
354 | |||
355 | |||
356 | static void Flush_Glyph(c_glyph * glyph) | ||
357 | { | ||
358 | glyph->stored = 0; | ||
359 | glyph->index = 0; | ||
360 | if (glyph->bitmap.buffer) { | ||
361 | free(glyph->bitmap.buffer); | ||
362 | glyph->bitmap.buffer = 0; | ||
363 | } | ||
364 | if (glyph->pixmap.buffer) { | ||
365 | free(glyph->pixmap.buffer); | ||
366 | glyph->pixmap.buffer = 0; | ||
367 | } | ||
368 | glyph->cached = 0; | ||
369 | } | ||
370 | |||
371 | static FT_Error Load_Glyph(TTF_Font * font, unsigned short ch, | ||
372 | c_glyph * cached, int want) | ||
373 | { | ||
374 | FT_Face face; | ||
375 | FT_Error error; | ||
376 | FT_GlyphSlot glyph; | ||
377 | FT_Glyph_Metrics *metrics; | ||
378 | FT_Outline *outline; | ||
379 | |||
380 | assert(font); | ||
381 | assert(font->face); | ||
382 | |||
383 | face = font->face; | ||
384 | |||
385 | /* Load the glyph */ | ||
386 | if (!cached->index) { | ||
387 | cached->index = FT_Get_Char_Index(face, ch); | ||
388 | } | ||
389 | error = FT_Load_Glyph(face, cached->index, FT_LOAD_DEFAULT); | ||
390 | if (error) { | ||
391 | return error; | ||
392 | } | ||
393 | /* Get our glyph shortcuts */ | ||
394 | glyph = face->glyph; | ||
395 | metrics = &glyph->metrics; | ||
396 | outline = &glyph->outline; | ||
397 | |||
398 | /* Get the glyph metrics if desired */ | ||
399 | if ((want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS)) { | ||
400 | /* Get the bounding box */ | ||
401 | cached->minx = FT_FLOOR(metrics->horiBearingX); | ||
402 | cached->maxx = cached->minx + FT_CEIL(metrics->width); | ||
403 | cached->maxy = FT_FLOOR(metrics->horiBearingY); | ||
404 | cached->miny = cached->maxy - FT_CEIL(metrics->height); | ||
405 | cached->yoffset = font->ascent - cached->maxy; | ||
406 | cached->advance = FT_CEIL(metrics->horiAdvance); | ||
407 | |||
408 | /* Adjust for bold and italic text */ | ||
409 | if (font->style & TTF_STYLE_BOLD) { | ||
410 | cached->maxx += font->glyph_overhang; | ||
411 | } | ||
412 | if (font->style & TTF_STYLE_ITALIC) { | ||
413 | cached->maxx += (int) ceil(font->glyph_italics); | ||
414 | } | ||
415 | cached->stored |= CACHED_METRICS; | ||
416 | } | ||
417 | |||
418 | if (((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) | ||
419 | || ((want & CACHED_PIXMAP) | ||
420 | && !(cached->stored & CACHED_PIXMAP))) { | ||
421 | int mono = (want & CACHED_BITMAP); | ||
422 | int i; | ||
423 | FT_Bitmap *src; | ||
424 | FT_Bitmap *dst; | ||
425 | |||
426 | /* Handle the italic style */ | ||
427 | if (font->style & TTF_STYLE_ITALIC) { | ||
428 | FT_Matrix shear; | ||
429 | |||
430 | shear.xx = 1 << 16; | ||
431 | shear.xy = (int) (font->glyph_italics * (1 << 16)) | ||
432 | / font->height; | ||
433 | shear.yx = 0; | ||
434 | shear.yy = 1 << 16; | ||
435 | |||
436 | FT_Outline_Transform(outline, &shear); | ||
437 | } | ||
438 | |||
439 | /* Render the glyph */ | ||
440 | if (mono) { | ||
441 | error = | ||
442 | FT_Render_Glyph(glyph, ft_render_mode_mono); | ||
443 | } else { | ||
444 | error = | ||
445 | FT_Render_Glyph(glyph, ft_render_mode_normal); | ||
446 | } | ||
447 | if (error) { | ||
448 | return error; | ||
449 | } | ||
450 | |||
451 | /* Copy over information to cache */ | ||
452 | src = &glyph->bitmap; | ||
453 | if (mono) { | ||
454 | dst = &cached->bitmap; | ||
455 | } else { | ||
456 | dst = &cached->pixmap; | ||
457 | } | ||
458 | memcpy(dst, src, sizeof(*dst)); | ||
459 | if (mono) { | ||
460 | dst->pitch *= 8; | ||
461 | } | ||
462 | |||
463 | /* Adjust for bold and italic text */ | ||
464 | if (font->style & TTF_STYLE_BOLD) { | ||
465 | int bump = font->glyph_overhang; | ||
466 | dst->pitch += bump; | ||
467 | dst->width += bump; | ||
468 | } | ||
469 | if (font->style & TTF_STYLE_ITALIC) { | ||
470 | int bump = (int) ceil(font->glyph_italics); | ||
471 | dst->pitch += bump; | ||
472 | dst->width += bump; | ||
473 | } | ||
474 | |||
475 | if (dst->rows != 0) { | ||
476 | dst->buffer = malloc(dst->pitch * dst->rows); | ||
477 | if (!dst->buffer) { | ||
478 | return FT_Err_Out_Of_Memory; | ||
479 | } | ||
480 | memset(dst->buffer, 0, dst->pitch * dst->rows); | ||
481 | |||
482 | for (i = 0; i < src->rows; i++) { | ||
483 | int soffset = i * src->pitch; | ||
484 | int doffset = i * dst->pitch; | ||
485 | if (mono) { | ||
486 | unsigned char *srcp = src->buffer + | ||
487 | soffset; | ||
488 | unsigned char *dstp = dst->buffer + | ||
489 | doffset; | ||
490 | int j; | ||
491 | for (j = 0; j < src->width; j += 8) { | ||
492 | unsigned char ch = *srcp++; | ||
493 | *dstp++ = (ch & 0x80) >> 7; | ||
494 | ch <<= 1; | ||
495 | *dstp++ = (ch & 0x80) >> 7; | ||
496 | ch <<= 1; | ||
497 | *dstp++ = (ch & 0x80) >> 7; | ||
498 | ch <<= 1; | ||
499 | *dstp++ = (ch & 0x80) >> 7; | ||
500 | ch <<= 1; | ||
501 | *dstp++ = (ch & 0x80) >> 7; | ||
502 | ch <<= 1; | ||
503 | *dstp++ = (ch & 0x80) >> 7; | ||
504 | ch <<= 1; | ||
505 | *dstp++ = (ch & 0x80) >> 7; | ||
506 | ch <<= 1; | ||
507 | *dstp++ = (ch & 0x80) >> 7; | ||
508 | } | ||
509 | } else { | ||
510 | memcpy(dst->buffer + doffset, | ||
511 | src->buffer + soffset, | ||
512 | src->pitch); | ||
513 | } | ||
514 | } | ||
515 | } | ||
516 | |||
517 | /* Handle the bold style */ | ||
518 | if (font->style & TTF_STYLE_BOLD) { | ||
519 | int row; | ||
520 | int col; | ||
521 | int offset; | ||
522 | int pixel; | ||
523 | unsigned char *pixmap; | ||
524 | |||
525 | /* The pixmap is a little hard, we have to add and clamp */ | ||
526 | for (row = dst->rows - 1; row >= 0; --row) { | ||
527 | pixmap = | ||
528 | (unsigned char *) dst->buffer + | ||
529 | row * dst->pitch; | ||
530 | for (offset = 1; | ||
531 | offset <= font->glyph_overhang; | ||
532 | ++offset) { | ||
533 | for (col = dst->width - 1; col > 0; | ||
534 | --col) { | ||
535 | pixel = | ||
536 | (pixmap[col] + | ||
537 | pixmap[col - 1]); | ||
538 | if (pixel > NUM_GRAYS - 1) { | ||
539 | pixel = | ||
540 | NUM_GRAYS - 1; | ||
541 | } | ||
542 | pixmap[col] = | ||
543 | (unsigned char) pixel; | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | |||
549 | /* Mark that we rendered this format */ | ||
550 | if (mono) { | ||
551 | cached->stored |= CACHED_BITMAP; | ||
552 | } else { | ||
553 | cached->stored |= CACHED_PIXMAP; | ||
554 | } | ||
555 | } | ||
556 | |||
557 | /* We're done, mark this glyph cached */ | ||
558 | cached->cached = ch; | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | |||
564 | |||
565 | |||
566 | |||
567 | |||
568 | |||
569 | static FT_Error Find_Glyph(TTF_Font * font, unsigned short ch, int want) | ||
570 | { | ||
571 | int retval = 0; | ||
572 | |||
573 | if (ch < 256) { | ||
574 | font->current = &font->cache[ch]; | ||
575 | } else { | ||
576 | if (font->scratch.cached != ch) { | ||
577 | Flush_Glyph(&font->scratch); | ||
578 | } | ||
579 | font->current = &font->scratch; | ||
580 | } | ||
581 | if ((font->current->stored & want) != want) { | ||
582 | retval = Load_Glyph(font, ch, font->current, want); | ||
583 | } | ||
584 | return retval; | ||
585 | } | ||
586 | |||
587 | int TTF_SizeUNICODE(TTF_Font * font, const unsigned short *text, int *w, | ||
588 | int *h) | ||
589 | { | ||
590 | int status; | ||
591 | const unsigned short *ch; | ||
592 | int x, z; | ||
593 | int minx, maxx; | ||
594 | int miny, maxy; | ||
595 | c_glyph *glyph; | ||
596 | FT_Error error; | ||
597 | |||
598 | /* Initialize everything to 0 */ | ||
599 | if (!TTF_initialized) { | ||
600 | return -1; | ||
601 | } | ||
602 | status = 0; | ||
603 | minx = maxx = 0; | ||
604 | miny = maxy = 0; | ||
605 | |||
606 | /* Load each character and sum it's bounding box */ | ||
607 | x = 0; | ||
608 | for (ch = text; *ch; ++ch) { | ||
609 | error = Find_Glyph(font, *ch, CACHED_METRICS); | ||
610 | if (error) { | ||
611 | return -1; | ||
612 | } | ||
613 | glyph = font->current; | ||
614 | |||
615 | z = x + glyph->minx; | ||
616 | if (minx > z) { | ||
617 | minx = z; | ||
618 | } | ||
619 | if (font->style & TTF_STYLE_BOLD) { | ||
620 | x += font->glyph_overhang; | ||
621 | } | ||
622 | if (glyph->advance > glyph->maxx) { | ||
623 | z = x + glyph->advance; | ||
624 | } else { | ||
625 | z = x + glyph->maxx; | ||
626 | } | ||
627 | if (maxx < z) { | ||
628 | maxx = z; | ||
629 | } | ||
630 | x += glyph->advance; | ||
631 | |||
632 | if (glyph->miny < miny) { | ||
633 | miny = glyph->miny; | ||
634 | } | ||
635 | if (glyph->maxy > maxy) { | ||
636 | maxy = glyph->maxy; | ||
637 | } | ||
638 | } | ||
639 | |||
640 | /* Fill the bounds rectangle */ | ||
641 | if (w) { | ||
642 | *w = (maxx - minx); | ||
643 | } | ||
644 | if (h) | ||
645 | *h = font->height; | ||
646 | |||
647 | return status; | ||
648 | } | ||
649 | |||
650 | |||
651 | unsigned char *TTF_RenderUNICODE_Shaded(TTF_Font * font, | ||
652 | const unsigned short *text, | ||
653 | unsigned int fg, unsigned int bg) | ||
654 | { | ||
655 | int xstart; | ||
656 | int width; | ||
657 | int height; | ||
658 | unsigned char *textbuf; | ||
659 | int rdiff; | ||
660 | int gdiff; | ||
661 | int bdiff; | ||
662 | unsigned short val, bgc; | ||
663 | const unsigned short *ch; | ||
664 | unsigned char *src; | ||
665 | unsigned char *dst; | ||
666 | int row, col; | ||
667 | c_glyph *glyph; | ||
668 | FT_Error error; | ||
669 | |||
670 | /* Get the dimensions of the text surface */ | ||
671 | if ((TTF_SizeUNICODE(font, text, &width, NULL) < 0) || !width) { | ||
672 | fprintf(stderr, "Text has zero width\n"); | ||
673 | return NULL; | ||
674 | } | ||
675 | height = font->height; | ||
676 | |||
677 | /* Create the target surface */ | ||
678 | textbuf = malloc(width * height * fbbytes); | ||
679 | |||
680 | if (textbuf == NULL) { | ||
681 | return NULL; | ||
682 | } | ||
683 | |||
684 | /* Load and render each character */ | ||
685 | xstart = 0; | ||
686 | for (ch = text; *ch; ++ch) { | ||
687 | FT_Bitmap *current; | ||
688 | |||
689 | error = | ||
690 | Find_Glyph(font, *ch, CACHED_METRICS | CACHED_PIXMAP); | ||
691 | if (error) { | ||
692 | free(textbuf); | ||
693 | return NULL; | ||
694 | } | ||
695 | glyph = font->current; | ||
696 | |||
697 | current = &glyph->pixmap; | ||
698 | for (row = 0; row < current->rows; ++row) { | ||
699 | dst = (unsigned char *) framebuffer + | ||
700 | (fbypos + row + glyph->yoffset) * fblinelen + | ||
701 | (xstart + glyph->minx + fbxpos) * fbbytes; | ||
702 | src = current->buffer + row * current->pitch; | ||
703 | for (col = current->width; col > 0; --col) { | ||
704 | val = *src++; | ||
705 | bgc = *(unsigned short *) dst; | ||
706 | |||
707 | /* get color parts from real color */ | ||
708 | rdiff = (fg >> 16); | ||
709 | gdiff = ((fg >> 8) & 0xff); | ||
710 | bdiff = (fg & 0xff); | ||
711 | |||
712 | val = alpha * val / 100; | ||
713 | /* dim color down to current pixel value */ | ||
714 | rdiff = rdiff * val / 0xff; | ||
715 | gdiff = gdiff * val / 0xff; | ||
716 | bdiff = bdiff * val / 0xff; | ||
717 | |||
718 | #if 1 | ||
719 | /* do alpha transparency */ | ||
720 | //rdiff=(rdiff*alpha/100); | ||
721 | rdiff += | ||
722 | ((bgc) >> 8 & 0xf8) * (0xff - | ||
723 | val) / 0xff; | ||
724 | |||
725 | //gdiff=(gdiff*alpha/100); | ||
726 | gdiff += | ||
727 | ((bgc >> 3) & 0xfc) * (0xff - | ||
728 | val) / 0xff; | ||
729 | |||
730 | //bdiff=(bdiff*alpha/100); | ||
731 | bdiff += | ||
732 | ((bgc << 3) & 0xf8) * (0xff - | ||
733 | val) / 0xff; | ||
734 | #endif | ||
735 | |||
736 | val = | ||
737 | ((rdiff & 0xf8) << 8) | ((gdiff & 0xfc) | ||
738 | << 3) | (bdiff | ||
739 | >> | ||
740 | 3); | ||
741 | //*dst++ = (val >>8); | ||
742 | *dst++ = val & 0xff; | ||
743 | *dst++ = (val >> 8); | ||
744 | } | ||
745 | //printf("\n"); | ||
746 | } | ||
747 | |||
748 | xstart += glyph->advance; | ||
749 | if (font->style & TTF_STYLE_BOLD) { | ||
750 | xstart += font->glyph_overhang; | ||
751 | } | ||
752 | } | ||
753 | |||
754 | /* Handle the underline style */ | ||
755 | if (font->style & TTF_STYLE_UNDERLINE) { | ||
756 | row = font->ascent - font->underline_offset - 1; | ||
757 | if (row >= fby) { | ||
758 | row = (height - 1) - font->underline_height; | ||
759 | } | ||
760 | dst = (unsigned char *) textbuf + row * width * fbbytes; | ||
761 | for (row = font->underline_height; row > 0; --row) { | ||
762 | memset(dst, NUM_GRAYS - 1, width); | ||
763 | dst += width * fbbytes; | ||
764 | } | ||
765 | } | ||
766 | return textbuf; | ||
767 | } | ||
768 | |||
769 | |||
770 | int rendertext(char *text, char *fontname, unsigned int ptsize, | ||
771 | unsigned int forecol) | ||
772 | { | ||
773 | TTF_Font *font; | ||
774 | int renderstyle = 0; | ||
775 | |||
776 | enum { | ||
777 | RENDER_LATIN1, | ||
778 | RENDER_UTF8, | ||
779 | RENDER_UNICODE | ||
780 | } rendertype; | ||
781 | |||
782 | |||
783 | /* Initialize the TTF library */ | ||
784 | if (TTF_Init() < 0) { | ||
785 | fprintf(stderr, "Couldn't initialize TTF.\n"); | ||
786 | return (2); | ||
787 | } | ||
788 | atexit(TTF_Quit); | ||
789 | |||
790 | /* Open the font file with the requested point size */ | ||
791 | font = TTF_OpenFont(fontname, ptsize); | ||
792 | if (font == NULL) { | ||
793 | fprintf(stderr, "Couldn't load %d pt font from %s\n", | ||
794 | ptsize, fontname); | ||
795 | return (2); | ||
796 | } | ||
797 | |||
798 | renderstyle = TTF_STYLE_NORMAL; | ||
799 | rendertype = RENDER_LATIN1; | ||
800 | |||
801 | TTF_SetFontStyle(font, renderstyle); | ||
802 | text = TTF_RenderText_Shaded(font, text, forecol, 0); | ||
803 | |||
804 | return 0; | ||
805 | } |