Contents of /trunk/linterm_tools/fw_builder/bootsplash/ttf.c
Parent Directory | Revision Log
Revision 658 -
(show annotations)
(download)
Mon Jan 14 16:57:24 2008 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 17482 byte(s)
Mon Jan 14 16:57:24 2008 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 17482 byte(s)
initial import
1 | /* 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 | } |