1 /**
2  * Fonts
3 
4  * Copyright (C) 2007, 2008, 2009  Sylvain Beucler
5 
6  * This file is part of GNU FreeDink
7 
8  * GNU FreeDink is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 3 of the
11  * License, or (at your option) any later version.
12 
13  * GNU FreeDink is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17 
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see
20  * <http://www.gnu.org/licenses/>.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__
28 #define WIN32_LEAN_AND_MEAN
29 #define _WIN32_IE 0x0401
30 #include <windows.h>
31 #include <shlobj.h>
32 #endif
33 
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include "SDL.h"
38 #include "SDL_ttf.h"
39 #include "dinkvar.h"
40 #include "gfx.h"
41 #include "io_util.h"
42 #include "paths.h"
43 #include "gfx_fonts.h"
44 #include "gfx_palette.h"
45 #include "vgasys_fon.h"
46 #include "init.h"
47 #include "log.h"
48 
49 
50 /* Default size was 18 in the original game, but it refers to a
51    different part of the font glyph (see doc/fonts.txt for
52    details). 16 matches that size with SDL_ttf (possibly only for
53    LiberationSans). */
54 #define FONT_SIZE 16
55 
56 /* Default fonts: dialog and system */
57 static TTF_Font *dialog_font = NULL;
58 static TTF_Font *system_font = NULL;
59 
60 /* Current font parameters */
61 static SDL_Color text_color;
62 
63 static TTF_Font *load_default_font();
64 static void setup_font(TTF_Font *font);
65 
66 // D-Mod-defined font colors
67 struct font_color
68 {
69   int red;
70   int green;
71   int blue;
72 };
73 static struct font_color font_colors[16];
74 
75 #ifdef HAVE_FONTCONFIG
76 #include <fontconfig/fontconfig.h>
77 /* Get filename for canonical font name 'fontname'. Return NULL if the
78    font cannot be found (for correctness, no alternate font will be
79    provided). */
get_fontconfig_path(char * fontname)80 char* get_fontconfig_path(char* fontname)
81 {
82   char* filename = NULL;
83   FcPattern* p = NULL;
84   FcChar8* strval = NULL;
85   FcObjectSet *attr = NULL;
86 
87   if (!FcInit())
88     {
89       log_error("get_fontconfig_path: cannot initialize fontconfig");
90       return NULL;
91     }
92 
93   p = FcNameParse((FcChar8*)fontname);
94   if (p == NULL)
95     {
96       log_error("get_fontconfig_path: invalid font pattern: %s", fontname);
97       return NULL;
98     }
99   /* Grab filename attribute */
100   attr = FcObjectSetBuild (FC_FILE, (char *) 0);
101 
102   FcFontSet *fs = FcFontList (0, p, attr);
103   if (fs->nfont == 0)
104     {
105       log_error("get_fontconfig_path: no matching font for %s", fontname);
106       return NULL;
107     }
108   if (FcPatternGetString(fs->fonts[0], FC_FILE, 0, &strval) == FcResultTypeMismatch
109       || strval == NULL)
110     {
111       log_error("get_fontconfig_path: cannot find font filename for %s", fontname);
112       return NULL;
113     }
114 
115   filename = strdup((char*)strval);
116 
117   FcFontSetDestroy(fs);
118   FcObjectSetDestroy(attr);
119   FcPatternDestroy(p);
120   FcFini();
121 
122   return filename;
123 }
124 #endif
125 
126 /**
127  * Init font subsystem and one built-in font, so we can display error
128  * messages in emergency (init error) situations
129  */
gfx_fonts_init_failsafe()130 int gfx_fonts_init_failsafe()
131 {
132   if (!TTF_WasInit() && TTF_Init() == -1)
133     return -1;
134 
135   /* Load system font from compiled data */
136   if (system_font == NULL)
137     {
138       system_font = TTF_OpenFontRW(SDL_RWFromConstMem(vgasys_fon, sizeof(vgasys_fon)),
139 				   1, FONT_SIZE);
140       if (system_font == NULL)
141 	return -1;
142       setup_font(system_font);
143     }
144 
145   return 0;
146 }
147 
148 /**
149  * Init font subsystem and load the default fonts
150  */
gfx_fonts_init()151 int gfx_fonts_init()
152 {
153   if (TTF_Init() == -1) {
154     init_set_error_msg(TTF_GetError());
155     return -1;
156   }
157 
158   /* Load system font from compiled data */
159   system_font = TTF_OpenFontRW(SDL_RWFromConstMem(vgasys_fon, sizeof(vgasys_fon)),
160 			       1, FONT_SIZE);
161   if (system_font == NULL)
162     {
163       init_set_error_msg("Failed to load builtin 'vgasys.fon' font.");
164       return -1;
165     }
166   setup_font(system_font);
167 
168   /* Load dialog font from built-in resources */
169   dialog_font = load_default_font();
170   if (dialog_font == NULL)
171     return -1; /* error message set by load_default_font */
172   setup_font(dialog_font);
173 
174   gfx_fonts_init_colors();
175 
176   return 0;
177 }
178 
179 /**
180  * Quit the font subsystem (and free loaded fonts from memory)
181  */
gfx_fonts_quit(void)182 void gfx_fonts_quit(void)
183 {
184   if (dialog_font != NULL)
185     {
186       TTF_CloseFont(dialog_font);
187       dialog_font = NULL;
188     }
189   if (system_font != NULL)
190     {
191       // Uncomment when FreeType 2.5.3 is widespread
192       // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=747002
193       //TTF_CloseFont(system_font);
194       system_font = NULL;
195     }
196 
197   TTF_Quit();
198 }
199 
200 
201 /**
202  * Default font from resources and pkgdatadir
203  */
load_default_font()204 static TTF_Font *load_default_font() {
205   TTF_Font *font_object = NULL;
206   SDL_RWops* rwops = NULL;
207 
208   /* Try from resources */
209   if (rwops == NULL)
210     {
211       rwops = find_resource_as_rwops("LiberationSans-Regular.ttf");
212     }
213 #ifdef HAVE_FONTCONFIG
214   if (rwops == NULL)
215     {
216       char *path = get_fontconfig_path("Liberation Sans:style=Regular");
217       rwops = SDL_RWFromFile(path, "rb");
218       free(path);
219     }
220 #endif
221   if (rwops == NULL)
222     {
223       init_set_error_msg("Could not open font 'LiberationSans-Regular.ttf'. I tried:\n"
224 			 "- loading from '%s'\n"
225 			 "- loading from '%s'\n"
226 			 "- loading from '%s'\n"
227 			 "- loading from executable's resources\n"
228 #ifdef HAVE_FONTCONFIG
229 			 "- querying fontconfig"
230 #endif
231 			 ,
232 			 paths_getpkgdatadir(), paths_getdefaultpkgdatadir(), paths_getexedir());
233       return NULL;
234     }
235 
236   font_object = TTF_OpenFontRW(rwops, 1, FONT_SIZE);
237   if (font_object == NULL)
238     {
239       init_set_error_msg("Could not open font 'LiberationSans-Regular.ttf': %s", TTF_GetError());
240       return NULL;
241     }
242 
243   return font_object;
244 }
245 
246 /**
247  * Change the current dialog font (DinkC initfont() command)
248  */
initfont(char * fontname)249 int initfont(char* fontname) {
250   TTF_Font *new_font = NULL;
251   char* ext = ".ttf";
252   char* filename = malloc(strlen(fontname) + strlen(ext) + 1);
253   strcpy(filename, fontname);
254   strcat(filename, ext);
255 
256   if (new_font == NULL)
257     {
258       char *path = NULL;
259 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__
260       /* Look in system fonts dir */
261       path = malloc(MAX_PATH + 1 + strlen(filename) + 1);
262       /* C:\WINNT\Fonts */
263       SHGetSpecialFolderPath(NULL, path, CSIDL_FONTS, 0);
264       strcat(path, "\\");
265       strcat(path, filename);
266 #else
267 #  ifdef HAVE_FONTCONFIG
268       path = get_fontconfig_path(fontname);
269 #  else
270       path = NULL;
271 #  endif
272 #endif
273       if (path == NULL)
274 	{
275 	  log_error("initfont: cannot find '%s'", fontname);
276 	}
277       else
278 	{
279 	  new_font = TTF_OpenFont(path, FONT_SIZE);
280 	  if (new_font == NULL)
281 	    log_error("TTF_OpenFont: %s", TTF_GetError());
282 	  free(path);
283 	}
284     }
285 
286   if (new_font == NULL)
287     return -1;
288 
289 
290   /* new_font could be loaded - we can free the previous one */
291   TTF_CloseFont(dialog_font);
292   dialog_font = new_font;
293 
294   setup_font(dialog_font);
295 
296   return 0;
297 }
298 
299 /**
300  * Change a font color (DinkC set_font_color() command)
301  */
set_font_color(int no,int red,int green,int blue)302 void set_font_color(int no, int red, int green, int blue)
303 {
304   if (no >= 1 && no <= 15
305       && red   >= 0 && red   <= 255
306       && green >= 0 && green <= 255
307       && blue  >= 0 && blue  <= 255)
308     {
309       font_colors[no].red = red;
310       font_colors[no].green = green;
311       font_colors[no].blue = blue;
312     }
313 }
314 
315 
316 /**
317  * Apply default style to the font
318  * Plus some informative output
319  */
320 static void
setup_font(TTF_Font * font)321 setup_font(TTF_Font *font)
322 {
323   char *familyname = TTF_FontFaceFamilyName(font);
324   if(familyname)
325     log_info("The family name of the face in the font is: %s", familyname);
326   char *stylename = TTF_FontFaceStyleName(font);
327   if(stylename)
328     log_info("The name of the face in the font is: %s", stylename);
329   log_info("The font max height is: %d", TTF_FontHeight(font));
330   log_info("The font ascent is: %d", TTF_FontAscent(font));
331   log_info("The font descent is: %d", TTF_FontDescent(font));
332   log_info("The font line skip is: %d", TTF_FontLineSkip(font));
333   if(TTF_FontFaceIsFixedWidth(font))
334     log_info("The font is fixed width.");
335   else
336     log_info("The font is not fixed width.");
337 
338   TTF_SetFontStyle(font, TTF_STYLE_BOLD);
339 }
340 
341 
342 
343 
FONTS_SetTextColor(Uint8 r,Uint8 g,Uint8 b)344 void FONTS_SetTextColor(Uint8 r, Uint8 g, Uint8 b) {
345   text_color.r = r;
346   text_color.g = g;
347   text_color.b = b;
348 }
FONTS_SetTextColorIndex(int no)349 void FONTS_SetTextColorIndex(int no) {
350   text_color.r = font_colors[no].red;
351   text_color.g = font_colors[no].green;
352   text_color.b = font_colors[no].blue;
353 }
354 
355 
356 static void
print_text(TTF_Font * font,char * str,int x,int y,int w,SDL_Color color,int hcenter)357 print_text (TTF_Font * font, char *str, int x, int y, int w, SDL_Color /*&*/color,
358 	    /*bool*/int hcenter)
359 {
360   int new_x, text_w, text_h;
361   SDL_Surface *tmp;
362   SDL_Rect dst;
363 
364   if (strlen (str) == 0)
365     return;
366 
367   /* Msg (("printing \"%s\"", str)); */
368 
369 
370   /* Rationale: text color is not affected by palette shifts (yellow
371      stays yellow even if we're using the negative palette from Lyna's
372      story) _but_ text color is the closest one in the final palette
373      color (so when after a fade_down(), the available colors are only
374      black and white, yellow becomes white, as yellow is just not
375      available, and white is closest than black). */
376   /* So we get the color index from cur_screen_palette (final color
377      even after palette effects), and use the color value from
378      GFX_real_pal (reference palette used for all graphics before
379      palette effects). */
380   /* Previously this was implemented using BlitSurface palette
381      conversion (commit 2007-11-01) but this was terribly slow (full
382      palette conversion done 5 times per text (for the border effect)
383      and per frame). */
384   if (!truecolor)
385     {
386       SDL_PixelFormat fmt;
387       SDL_Palette pal;
388         pal.ncolors = 256;
389         SDL_Color tmppal[256];
390         gfx_palette_get_phys(tmppal);
391         pal.colors = tmppal;
392       fmt.palette = &pal;
393       Uint32 phys_index = SDL_MapRGB(&fmt, color.r, color.g, color.b);
394       SDL_GetRGB(phys_index, GFX_lpDDSBack->format, &(color.r), &(color.g), &(color.b));
395     }
396 
397   /* Transparent, low quality - closest to the original engine. */
398   /* Besides, we do need a monochrome render, since we're doing nasty
399      tricks to set the color appropriately */
400   tmp = TTF_RenderUTF8_Solid(font, str, color);
401 
402   /* Bigger, with a box background */
403   // SDL_Color background = {0, 0, 0};
404   // tmp = TTF_RenderText_Shaded(font, str, color, background);
405 
406   /* High quality, 32bit+alpha, but I can't get the transparency
407      OK. Directly applying it on lpDDSBack messed with the colors of
408      the graphics behind the text, and trying to pre-convert it by
409      blitting it on a transparent surface missed some of the text
410      borders in the final result (i.e. multiple calls to print_text
411      with a small postponement to make the borders). */
412   // tmp = TTF_RenderText_Blended(font, str, color);
413   // {
414   //   // SDL_Surface *conv = SDL_DisplayFormat(tmp);
415   //   SDL_Surface *conv = SDL_CreateRGBSurface(SDL_SWSURFACE, tmp->w, tmp->h, 8,
416   // 			     			0, 0, 0, 0);
417   //   SDL_SetPalette(conv, SDL_LOGPAL, GFX_real_pal, 0, 256);
418   //   SDL_SetColorKey(conv, SDL_SRCCOLORKEY, 0);
419   //   SDL_FillRect(conv, NULL, 0);
420   //   SDL_BlitSurface(tmp, NULL, conv, NULL);
421   //   SDL_FreeSurface(tmp);
422   //   tmp = conv;
423   // }
424 
425   if (tmp == NULL)
426     {
427       log_error("Error rendering text: %s; font is %p", TTF_GetError(), font);
428       return;
429     }
430 
431   TTF_SizeUTF8 (font, str, &text_w, &text_h);
432   new_x = x;
433   if (hcenter)
434     {
435       new_x += w / 2;
436       new_x -= text_w / 2;
437     }
438   dst.x = new_x; dst.y = y;
439 
440   SDL_Rect src;
441   src.x = src.y = 0;
442   src.w = w; // truncate text if outside the box
443   src.h = tmp->h;
444   SDL_BlitSurface(tmp, &src, GFX_lpDDSBack, &dst);
445 
446   SDL_FreeSurface (tmp);
447 }
448 
449 /**
450  * Get the size in pixel of 'len' chars starting at 'str'
451  */
452 static int
font_len(TTF_Font * font,char * str,int len)453 font_len (TTF_Font *font, char *str, int len)
454 {
455   int text_w;
456   char *tmp;
457 
458   /* Get the specified string portion and terminate it by \0 */
459   tmp = (char *) malloc ((len + 1) * sizeof (char));
460   strncpy (tmp, str, len);
461   tmp[len] = 0;
462 
463   TTF_SizeUTF8 (font, tmp, &text_w, NULL);
464   free (tmp);
465 
466   return text_w;
467 }
468 
469 /**
470  * Add newlines in the text so that it fit in 'box'
471  * (a.k.a. word-wrapping)
472  */
473 static int
process_text_for_wrapping(TTF_Font * font,char * str,int max_len)474 process_text_for_wrapping (TTF_Font *font, char *str, int max_len)
475 {
476   //printf("process_text_for_wrapping: %s on %dx%d\n", str, box->right - box->left, box->bottom - box->top);
477   int i, start, line, last_fit;
478 
479   start = 0;
480   i = 0;
481   last_fit = -1;
482   line = 0;
483   while (str[i] != '\0')
484     {
485       int len;
486 
487       /* Skip forward to the end of the word */
488       while (str[i] != '\0' && str[i] != ' ' && str[i] != '\n')
489 	i++;
490 
491       /* If the length of the text from start to i is bigger than the
492 	 box, then draw the text up to the last fitting portion -
493 	 unless that was the beginning of the string. */
494       len = font_len (font, &str[start], i - start);
495 
496       if (len > max_len)
497 	{
498 	  /* String is bigger than the textbox */
499 
500 	  if (last_fit == -1)
501 	    {
502 	      /* Current word is too long by itself already, let's
503 		 keep it on a single line */
504 	      if (str[i] != '\0')
505 		str[i] = '\n';
506 	      /* continue on a new line */
507 	      line++;
508 	      start = i + 1;
509 	      if (str[i] != '\0')
510 		i++;
511 	    }
512 	  else
513 	    {
514 	      /* All those words is bigger than the textbox, linebreak
515 		 at previous space */
516 	      str[last_fit] = '\n';
517 	      /* continue on a new line */
518 	      line++;
519 	      start = last_fit + 1;
520 	      i = last_fit + 1;
521 	    }
522 	  last_fit = -1;
523 	}
524       else if (str[i] == '\0')
525 	{
526 	  line++;
527 	}
528       else if (str[i] == '\n')
529 	{
530 	  line++;
531 	  i++;
532 	  start = i;
533 	  last_fit = -1;
534 	}
535       else
536 	{
537 	  last_fit = i;
538 	  i++;
539 	}
540     }
541 
542   return line;
543 }
544 
545 /**
546  * Print text 'str' in 'box', adding newlines if necessary
547  * (word-wrapping). Return the text height in pixels.
548  *
549  * calc_only: don't actually draw text on screen, but still compute
550  * the text height
551  */
552 int
print_text_wrap(char * str,rect * box,int hcenter,int calc_only,FONT_TYPE font_type)553 print_text_wrap (char *str, rect* box,
554 		 /*bool*/int hcenter, int calc_only, FONT_TYPE font_type)
555 {
556   int x, y, res_height;
557   char *tmp, *pline, *pc;
558   int this_is_last_line = 0;
559   //  SDL_Color color = {0, 0, 0};
560   SDL_Color color = text_color;
561   TTF_Font *font;
562   int lineskip = 0;
563 
564   if (font_type == FONT_DIALOG)
565     font = dialog_font;
566   else if (font_type == FONT_SYSTEM)
567     font = system_font;
568   else
569     {
570       log_error("Error: unknown font type %d", font_type);
571       exit(1);
572     }
573 
574   /* Workaround: with vgasys.fon, lineskip is always 1. We'll use it's
575      height instead. */
576   lineskip = TTF_FontLineSkip(font);
577   if (lineskip == 1)
578     lineskip = TTF_FontHeight(font);
579 
580   tmp = strdup(str);
581   process_text_for_wrapping(font, tmp, box->right - box->left);
582 
583   x = box->left;
584   y = box->top;
585 
586   res_height = 0;
587   pline = pc = tmp;
588   this_is_last_line = 0;
589   while (!this_is_last_line)
590     {
591       while (*pc != '\n' && *pc != '\0')
592 	pc++;
593 
594       if (*pc == '\0')
595 	this_is_last_line = 1;
596       else
597 	/* Terminate the current line to feed it to print_text */
598 	*pc= '\0';
599 
600       if (!calc_only)
601 	print_text(font, pline, x, y + res_height, (box->right - box->left), color, hcenter);
602 
603       res_height += lineskip;
604 
605       /* advance to next line*/
606       pc++;
607       pline = pc;
608     }
609   free(tmp);
610   return res_height;
611 }
612 
613 
614 /**
615  * Display text for debug mode (with a white background)
616  */
617 void
print_text_wrap_debug(char * text,int x,int y)618 print_text_wrap_debug(char *text, int x, int y)
619 {
620   char *tmp, *pline, *pc;
621   int this_is_last_line = 0;
622   int res_height = 0;
623   SDL_Color bgcolor = {255, 255, 255};
624   int max_len = 640;
625 
626   /* Workaround: with vgasys.fon, lineskip is always 1. We'll use it's
627      height instead. */
628   int lineskip = TTF_FontHeight(system_font);
629 
630   int textlen = strlen(text);
631   tmp = malloc(strlen(text) + 1);
632   /* drop '\r' */
633   pc = tmp;
634   int i;
635   for (i = 0; i < textlen; i++)
636     if (text[i] == '\r' && text[i+1] == '\n')
637       continue;
638     else
639       *(pc++) = text[i];
640   *pc = '\0';
641 
642   process_text_for_wrapping(system_font, tmp, max_len);
643 
644   pline = pc = tmp;
645   this_is_last_line = 0;
646   while (!this_is_last_line)
647     {
648       while (*pc != '\n' && *pc != '\0')
649 	pc++;
650 
651       if (*pc == '\0')
652 	this_is_last_line = 1;
653       else
654 	/* Terminate the current line to feed it to print_text */
655 	*pc= '\0';
656 
657       SDL_Rect dst = {x, y + res_height, -1, -1};
658       SDL_Surface *rendered_text = TTF_RenderUTF8_Shaded(system_font, pline, text_color, bgcolor);
659       SDL_BlitSurface(rendered_text, NULL, GFX_lpDDSBack, &dst);
660       SDL_FreeSurface(rendered_text);
661 
662       res_height += lineskip;
663 
664       /* advance to next line*/
665       pc++;
666       pline = pc;
667     }
668   free(tmp);
669 }
670 
671 
672 
673 /* Say, SaySmall: only used by freedinkedit.c */
674 /**
675  * SaySmall: print text in a 40x40 small square; without font border
676  * (sprite info boxes when typing 'I', plus something in tile
677  * hardness)
678  */
SaySmall(char thing[500],int px,int py,int r,int g,int b)679 void SaySmall(char thing[500], int px, int py, int r, int g, int b)
680 {
681   rect rcRect;
682 /*   HDC hdc; */
683 /*   if (lpDDSBack->GetDC(&hdc) == DD_OK) */
684 /*     {       */
685 /*       SetBkMode(hdc, TRANSPARENT);  */
686       rect_set(&rcRect,px,py,px+40,py+40);
687 /*       SetTextColor(hdc,RGB(r,g,b)); */
688 /*       DrawText(hdc,thing,lstrlen(thing),&rcRect,DT_WORDBREAK); */
689       // FONTS
690       FONTS_SetTextColor(r, g, b);
691       print_text_wrap(thing, &rcRect, 0, 0, FONT_SYSTEM);
692 
693 /*       lpDDSBack->ReleaseDC(hdc); */
694 /*     }    */
695 }
696 /**
697  * Say: print text until it reaches the border of the screen, with a
698  * font border (input dialog boxes)
699  */
Say(char thing[500],int px,int py)700 void Say(char thing[500], int px, int py)
701 {
702   rect rcRect;
703 /*   HDC hdc; */
704 
705 /*   if (lpDDSBack->GetDC(&hdc) == DD_OK) */
706 /*     {       */
707 /*       SetBkMode(hdc, TRANSPARENT);  */
708       rect_set(&rcRect,px,py,620,480);
709 /*       SelectObject (hdc, hfont_small); */
710 
711 /*       SetTextColor(hdc,RGB(8,14,21)); */
712 /*       DrawText(hdc,thing,lstrlen(thing),&rcRect,DT_WORDBREAK); */
713       // FONTS
714       FONTS_SetTextColor(8, 14, 21);
715       print_text_wrap(thing, &rcRect, 0, 0, FONT_DIALOG);
716 
717       rect_offset(&rcRect,-2,-2);
718 /*       DrawText(hdc,thing,lstrlen(thing),&rcRect,DT_WORDBREAK); */
719       // FONTS
720       print_text_wrap(thing, &rcRect, 0, 0, FONT_DIALOG);
721 
722       rect_offset(&rcRect,1,1);
723 /*       SetTextColor(hdc,RGB(255,255,0)); */
724 /*       DrawText(hdc,thing,lstrlen(thing),&rcRect,DT_WORDBREAK); */
725       // FONTS
726       FONTS_SetTextColor(255, 255, 0);
727       print_text_wrap(thing, &rcRect, 0, 0, FONT_DIALOG);
728 
729 /*       lpDDSBack->ReleaseDC(hdc); */
730 /*     }    */
731 }
732 
733 
gfx_fonts_init_colors()734 void gfx_fonts_init_colors()
735 {
736   //Light Magenta
737   font_colors[1].red = 255;
738   font_colors[1].green = 198;
739   font_colors[1].blue = 255;
740 
741   //Dark Green
742   font_colors[2].red = 131;
743   font_colors[2].green = 181;
744   font_colors[2].blue = 74;
745 
746   //Bold Cyan
747   font_colors[3].red = 99;
748   font_colors[3].green = 242;
749   font_colors[3].blue = 247;
750 
751   //Orange
752   font_colors[4].red = 255;
753   font_colors[4].green = 156;
754   font_colors[4].blue = 74;
755 
756   //Magenta
757   font_colors[5].red = 222;
758   font_colors[5].green = 173;
759   font_colors[5].blue = 255;
760 
761   //Brown Orange
762   font_colors[6].red = 244;
763   font_colors[6].green = 188;
764   font_colors[6].blue = 73;
765 
766   //Light Gray
767   font_colors[7].red = 173;
768   font_colors[7].green = 173;
769   font_colors[7].blue = 173;
770 
771   //Dark Gray
772   font_colors[8].red = 85;
773   font_colors[8].green = 85;
774   font_colors[8].blue = 85;
775 
776   //Sky Blue
777   font_colors[9].red = 148;
778   font_colors[9].green = 198;
779   font_colors[9].blue = 255;
780 
781   //Bright Green
782   font_colors[10].red = 0;
783   font_colors[10].green = 255;
784   font_colors[10].blue = 0;
785 
786   //Yellow
787   font_colors[11].red = 255;
788   font_colors[11].green = 255;
789   font_colors[11].blue = 2;
790 
791   //Yellow
792   font_colors[12].red = 255;
793   font_colors[12].green = 255;
794   font_colors[12].blue = 2;
795 
796   //Hot Pink
797   font_colors[13].red = 255;
798   font_colors[13].green = 132;
799   font_colors[13].blue = 132;
800 
801   //Yellow
802   font_colors[14].red = 255;
803   font_colors[14].green = 255;
804   font_colors[14].blue = 2;
805 
806   //White
807   font_colors[15].red = 255;
808   font_colors[15].green = 255;
809   font_colors[15].blue = 255;
810 }
811