]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/font.cpp
stub/warning removal.
[taylor/freespace2.git] / src / graphics / font.cpp
1 /*
2  * $Logfile: /Freespace2/code/Graphics/Font.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * source file for font stuff
8  *
9  * $Log$
10  * Revision 1.3  2002/06/05 08:05:29  relnev
11  * stub/warning removal.
12  *
13  * reworked the sound code.
14  *
15  * Revision 1.2  2002/05/07 03:16:45  theoddone33
16  * The Great Newline Fix
17  *
18  * Revision 1.1.1.1  2002/05/03 03:28:09  root
19  * Initial import.
20  *
21  * 
22  * 9     7/09/99 10:32p Dave
23  * Command brief and red alert screens.
24  * 
25  * 8     12/14/98 9:21a Dan
26  * Put gr8_string() back in
27  * 
28  * 7     12/02/98 5:47p Dave
29  * Put in interface xstr code. Converted barracks screen to new format.
30  * 
31  * 6     11/30/98 1:07p Dave
32  * 16 bit conversion, first run.
33  * 
34  * 5     11/05/98 4:18p Dave
35  * First run nebula support. Beefed up localization a bit. Removed all
36  * conditional compiles for foreign versions. Modified mission file
37  * format.
38  * 
39  * 4     10/13/98 9:28a Dave
40  * Started neatening up freespace.h. Many variables renamed and
41  * reorganized. Added AlphaColors.[h,cpp]
42  * 
43  * 3     10/13/98 9:19a Andsager
44  * Add localization support to cfile.  Optional parameter with cfopen that
45  * looks for localized files.
46  * 
47  * 2     10/07/98 10:52a Dave
48  * Initial checkin.
49  * 
50  * 1     10/07/98 10:49a Dave
51  * 
52  * 49    7/02/98 3:41p Allender
53  * fix nasty assembler bug where pushf wasn't accompanied by corresponding
54  * pop in certain clipping conditions -- manifested only in software and
55  * usually on the PXO chat screen.
56  * 
57  * 48    6/18/98 10:10a Allender
58  * fixed compiler warnings
59  * 
60  * 47    6/13/98 10:48p Lawrance
61  * Changed code to utilize proper fixed-space 1 character.
62  * 
63  * 46    6/13/98 3:18p Hoffoss
64  * NOX()ed out a bunch of strings that shouldn't be translated.
65  * 
66  * 45    5/25/98 10:32a John
67  * Took out redundant code for font bitmap offsets that converted to a
68  * float, then later on converted back to an integer.  Quite unnecessary.
69  * 
70  * 44    5/12/98 11:45a John
71  * Fixed a bug with the length of string being passed to
72  * gr_get_string_size.  The bug occurred if you had two or more'\n'''s in
73  * a row.
74  * 
75  * 43    3/10/98 4:18p John
76  * Cleaned up graphics lib.  Took out most unused gr functions.   Made D3D
77  * & Glide have popups and print screen.  Took out all >8bpp software
78  * support.  Made Fred zbuffer.  Made zbuffer allocate dynamically to
79  * support Fred.  Made zbuffering key off of functions rather than one
80  * global variable.
81  * 
82  * 42    3/09/98 6:06p John
83  * Restructured font stuff to avoid duplicate code in Direct3D and Glide.
84  * Restructured Glide to avoid redundent state setting.
85  * 
86  * 41    3/02/98 10:33a John
87  * Fixed bug where Y clip was using X value.
88  * 
89  * 40    2/19/98 9:04a John
90  * Fixed fonts with glide
91  * 
92  * 39    2/17/98 7:27p John
93  * Got fonts and texturing working in Direct3D
94  * 
95  * 38    2/05/98 9:21p John
96  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
97  * game.
98  * 
99  * 37    1/20/98 2:25p Hoffoss
100  * Fixed bug where timestamp printing incorrectly increments an hour at 6
101  * minutes.
102  * 
103  * 36    1/19/98 6:15p John
104  * Fixed all my Optimized Build compiler warnings
105  * 
106  * 35    11/30/97 12:18p John
107  * added more 24 & 32-bpp primitives
108  * 
109  * 34    11/29/97 2:24p John
110  * fixed warnings
111  * 
112  * 33    11/29/97 2:06p John
113  * added mode 16-bpp support
114  * 
115  * 32    11/10/97 2:35p Hoffoss
116  * Changed timestamp printing code to utilize new fixed-space '1'
117  * character.
118  * 
119  * 31    11/06/97 5:42p Hoffoss
120  * Added support for fixed size timstamp rendering.
121  * 
122  * 30    11/03/97 10:08p Hoffoss
123  * Changed gr_get_string_size to utilize an optional length specifier, if
124  * you want to use non-null terminated strings.
125  * 
126  * 29    11/03/97 10:59a John
127  * added support for more than one font.
128  * 
129  * 28    10/24/97 12:13p Hoffoss
130  * Added gr_force_fit_string().
131  * 
132  * 27    10/19/97 12:55p John
133  * new code to lock / unlock surfaces for smooth directx integration.
134  * 
135  * 26    10/14/97 4:50p John
136  * more 16 bpp stuff.
137  * 
138  * 25    10/14/97 8:08a John
139  * added a bunch more 16 bit support
140  * 
141  * 24    10/09/97 5:23p John
142  * Added support for more 16-bpp functions
143  * 
144  * 23    9/23/97 10:53a Hoffoss
145  * Fixed bug in assumptions made half the time, and not the other half.
146  * 
147  * 22    9/09/97 3:39p Sandeep
148  * warning level 4 bugs
149  * 
150  * 21    8/19/97 5:46p Hoffoss
151  * Changed font used in Fred, and added display to show current eye
152  * position.
153  * 
154  * 20    6/25/97 2:35p John
155  * added some functions to use the windows font for Fred.
156  * 
157  * 19    6/17/97 12:03p John
158  * Moved color/alphacolor functions into their own module.  Made all color
159  * functions be part of the low-level graphics drivers, not just the
160  * grsoft.
161  * 
162  * 18    6/13/97 2:37p John
163  * fixed a string bug that printed weird characters sometimes.
164  * 
165  * 17    6/11/97 6:00p John
166  * sped up alpha matching a bit.
167  * 
168  * 16    6/11/97 5:49p John
169  * Changed palette code to only recalculate alphacolors when needed, not
170  * when palette changes.
171  * 
172  * 15    6/11/97 5:01p John
173  * Fixed mission log text.  Added fast clipped font drawer.  
174  * 
175  * 14    6/11/97 4:11p John
176  * addec function to get font height
177  * 
178  * 13    6/11/97 1:12p John
179  * Started fixing all the text colors in the game.
180  * 
181  * 12    6/09/97 9:24a John
182  * Changed the way fonts are set.
183  * 
184  * 11    6/06/97 4:41p John
185  * Fixed alpha colors to be smoothly integrated into gr_set_color_fast
186  * code.
187  * 
188  * 10    6/06/97 2:40p John
189  * Made all the radar dim in/out
190  * 
191  * 9     6/05/97 4:53p John
192  * First rev of new antialiased font stuff.
193  * 
194  * 8     5/12/97 12:27p John
195  * Restructured Graphics Library to add support for multiple renderers.
196  * 
197  * 7     4/24/97 11:28a Hoffoss
198  * added code to handle gr_String being called before gr_init_font ever
199  * was called
200  * 
201  * 6     4/23/97 5:26p John
202  * First rev of new debug console stuff.
203  * 
204  * 5     4/22/97 12:20p John
205  * fixed more resource leaks
206  * 
207  * 4     4/22/97 10:33a John
208  * fixed the 2d resource leaks that Alan found.
209  * 
210  * 3     4/04/97 11:21a Hoffoss
211  * JOHN: Fixed invalid param that caused a trap in BoundsChecker.    
212  * 
213  * 2     4/01/97 9:26a Allender
214  * added support for descent style fonts although they are not used in the
215  * game yet
216  * 
217  * 1     3/31/97 9:42a Allender
218  *
219  * $NoKeywords: $
220  */
221
222 #ifndef PLAT_UNIX
223 #include <windows.h>
224 #include <windowsx.h>
225 #endif
226 #include <stdio.h>
227 #include <stdarg.h>
228 #include "grinternal.h"
229 #include "2d.h"
230 #include "cfile.h"
231 #include "font.h"
232 #include "palman.h"
233 #include "key.h"
234 #include "bmpman.h"
235 #include "localize.h"
236
237 int Num_fonts = 0;
238 font Fonts[MAX_FONTS];
239 font *Current_font = NULL;
240
241
242 // crops a string if required to force it to not exceed max_width pixels when printed.
243 // Does this by dropping characters at the end of the string and adding '...' to the end.
244 //    str = string to crop.  Modifies this string directly
245 //    max_str = max characters allowed in str
246 //    max_width = number of pixels to limit string to (less than or equal to).
247 //    Returns: returns same pointer passed in for str.
248 char *gr_force_fit_string(char *str, int max_str, int max_width)
249 {
250         int w;
251
252         gr_get_string_size(&w, NULL, str);
253         if (w > max_width) {
254                 if ((int) strlen(str) > max_str - 3) {
255                         Assert(max_str >= 3);
256                         str[max_str - 3] = 0;
257                 }
258
259                 strcpy(str + strlen(str) - 1, "...");
260                 gr_get_string_size(&w, NULL, str);
261                 while (w > max_width) {
262                         Assert(strlen(str) >= 4);  // if this is hit, a bad max_width was passed in and the calling function needs fixing.
263                         strcpy(str + strlen(str) - 4, "...");
264                         gr_get_string_size(&w, NULL, str);
265                 }
266         }
267
268         return str;
269 }
270
271 //takes the character BEFORE being offset into current font
272 // Returns the letter code
273 int get_char_width(ubyte c1,ubyte c2,int *width,int *spacing)
274 {
275         int i, letter;
276
277         Assert ( Current_font != NULL );
278         letter = c1-Current_font->first_ascii;
279
280         if (letter<0 || letter>=Current_font->num_chars) {                              //not in font, draw as space
281                 *width=0;
282                 *spacing = Current_font->w;
283                 return -1;
284         }
285
286         *width = Current_font->char_data[letter].byte_width;
287         *spacing = Current_font->char_data[letter].spacing;
288
289         i = Current_font->char_data[letter].kerning_entry;
290         if ( i > -1)  {
291                 if (!(c2==0 || c2=='\n')) {
292                         int letter2;
293
294                         letter2 = c2-Current_font->first_ascii;
295
296                         if ((letter2>=0) && (letter2<Current_font->num_chars) ) {                               //not in font, draw as space
297                                 font_kernpair   *k = &Current_font->kern_data[i];
298                                 while( (k->c1 == letter) && (k->c2<letter2) && (i<Current_font->num_kern_pairs) )       {
299                                         i++;
300                                         k++;
301                                 }
302                                 if ( k->c2 == letter2 ) {
303                                         *spacing += k->offset;
304                                 }
305                         }
306                 }
307         }
308         return letter;
309 }
310
311 int get_centered_x(char *s)
312 {
313         int w,w2,s2;
314
315         for (w=0;*s!=0 && *s!='\n';s++) {
316                 get_char_width(s[0],s[1],&w2,&s2);
317                 w += s2;
318         }
319
320         return ((gr_screen.clip_width - w) / 2);
321 }
322
323 // draws a character centered on x
324 void gr_char_centered(int x, int y, char chr)
325 {
326         char str[2];
327         int w, sc;
328
329         sc = Lcl_special_chars;
330         if (chr == '1')
331                 chr = (char)(sc + 1);
332
333         str[0] = chr;
334         str[1] = 0;
335         gr_get_string_size(&w, NULL, str);
336         gr_string(x - w / 2, y, str);
337 }
338
339 void gr_print_timestamp(int x, int y, int timestamp)
340 {
341         char h[2], m[3], s[3];
342         int w, c;
343
344         // format the time information into strings
345         sprintf(h, "%0.1d", (timestamp / 3600000) % 10);
346         sprintf(m, "%0.2d", (timestamp / 60000) % 60);
347         sprintf(s, "%0.2d", (timestamp / 1000) % 60);
348
349         gr_get_string_size(&w, NULL, "0");
350         gr_get_string_size(&c, NULL, ":");
351
352         gr_string(x + w, y, ":");
353         gr_string(x + w * 3 + c, y, ":");
354
355         x += w / 2;
356         gr_char_centered(x, y, h[0]);
357         x += w + c;
358         gr_char_centered(x, y, m[0]);
359         x += w;
360         gr_char_centered(x, y, m[1]);
361         x += w + c;
362         gr_char_centered(x, y, s[0]);
363         x += w;
364         gr_char_centered(x, y, s[1]);
365 }
366
367 int gr_get_font_height()
368 {
369         if (Current_font)       {
370                 return Current_font->h;
371         } else {
372                 return 16;
373         }
374 }
375
376 void gr_get_string_size(int *w1, int *h1, char *text, int len)
377 {
378         int longest_width;
379         int width,spacing;
380         int w, h;
381
382         if (!Current_font)      {
383                 if ( w1)
384                         *w1 = 16;
385
386                 if ( h1 )
387                         *h1 = 16;
388
389                 return;
390         }       
391
392         w = 0;
393         h = 0;
394         longest_width = 0;
395
396         if (text != NULL ) {
397                 h += Current_font->h;
398                 while (*text && (len>0) ) {
399
400                         // Process one or more 
401                         while ((*text == '\n') && (len>0) ) {
402                                 text++;
403                                 len--;
404                                 if ( *text )    {
405                                         h += Current_font->h;
406                                 }
407                                 w = 0;
408                         }
409
410                         if (*text == 0) {
411                                 break;
412                         }
413
414                         get_char_width(text[0], text[1], &width, &spacing);
415                         w += spacing;
416                         if (w > longest_width)
417                                 longest_width = w;
418
419                         text++;
420                         len--;
421                 }
422         }
423
424         if ( h1 )
425                 *h1 = h;
426
427         if ( w1 )
428                 *w1 = longest_width;
429 }
430
431
432 MONITOR( FontChars );   
433
434
435 /*
436
437 void gr8_char(int x,int y,int letter)
438 {
439         font_char *ch;
440         
441         ch = &Current_font->char_data[letter];
442
443         gr_aabitmap_ex( x, y, ch->byte_width, Current_font->h, Current_font->u[letter], Current_font->v[letter] );
444
445 //      mprintf(( "String = %s\n", text ));
446 }
447
448
449 void gr8_string( int sx, int sy, char *s )
450 {
451         int width, spacing, letter;
452         int x, y;
453
454         if ( !Current_font ) return;
455         if ( !s ) return;
456         
457         gr_set_bitmap(Current_font->bitmap);
458
459         x = sx;
460         y = sy;
461
462         if (sx==0x8000) {                       //centered
463                 x = get_centered_x(s);
464         } else {
465                 x = sx;
466         }
467
468         while (*s)      {
469                 while (*s== '\n' )      {
470                         s++;
471                         y += Current_font->h;
472                         if (sx==0x8000) {                       //centered
473                                 x = get_centered_x(s);
474                         } else {
475                                 x = sx;
476                         }
477                 }
478                 if (*s == 0 ) break;
479
480                 letter = get_char_width(s[0],s[1],&width,&spacing);
481
482                 if (letter<0) { //not in font, draw as space
483                         x += spacing;
484                         s++;
485                         continue;
486                 }
487                 gr8_char( x, y, letter );
488         
489                 x += spacing;
490                 s++;
491         }
492 }
493 */
494
495 void gr8_string(int sx, int sy, char *s )
496 {
497         int row,width, spacing, letter;
498         int x, y;
499
500         if ( !Current_font ) return;
501         if ( !s ) return;
502
503         x = sx;
504         y = sy;
505
506         if (sx==0x8000) {                       //centered
507                 x = get_centered_x(s);
508         } else {
509                 x = sx;
510         }
511
512         spacing = 0;
513
514         gr_lock();
515
516
517         while (*s)      {
518                 MONITOR_INC( FontChars, 1 );    
519
520                 x += spacing;
521                 while (*s== '\n' )      {
522                         s++;
523                         y += Current_font->h;
524                         if (sx==0x8000) {                       //centered
525                                 x = get_centered_x(s);
526                         } else {
527                                 x = sx;
528                         }
529                 }
530                 if (*s == 0 ) break;
531
532                 letter = get_char_width(s[0],s[1],&width,&spacing);
533                 s++;
534
535                 //If not in font, draw as space
536                 if (letter<0) continue;
537
538                 int xd, yd, xc, yc;
539                 int wc, hc;
540
541                 // Check if this character is totally clipped
542                 if ( x + width < gr_screen.clip_left ) continue;
543                 if ( y + Current_font->h < gr_screen.clip_top ) continue;
544                 if ( x > gr_screen.clip_right ) continue;
545                 if ( y > gr_screen.clip_bottom ) continue;
546
547                 xd = yd = 0;
548                 if ( x < gr_screen.clip_left ) xd = gr_screen.clip_left - x;
549                 if ( y < gr_screen.clip_top ) yd = gr_screen.clip_top - y;
550                 xc = x+xd;
551                 yc = y+yd;
552
553                 wc = width - xd; hc = Current_font->h - yd;
554                 if ( xc + wc > gr_screen.clip_right ) wc = gr_screen.clip_right - xc;
555                 if ( yc + hc > gr_screen.clip_bottom ) hc = gr_screen.clip_bottom - yc;
556
557                 if ( wc < 1 ) continue;
558                 if ( hc < 1 ) continue;
559
560                 ubyte *fp = Current_font->pixel_data + Current_font->char_data[letter].offset + xd + yd*width;
561                 ubyte *dptr = GR_SCREEN_PTR(ubyte, xc, yc);                     
562
563 #ifndef HARDWARE_ONLY
564                 if ( Current_alphacolor )       {
565                         for (row=0; row<hc; row++)      {
566                                 #ifdef USE_INLINE_ASM
567                                         ubyte *lookup = &Current_alphacolor->table.lookup[0][0];
568                                                 _asm mov edx, lookup
569                                                 _asm xor eax, eax
570                                                 _asm mov ecx, wc
571                                                 _asm xor ebx, ebx
572                                                 _asm mov edi, dptr
573                                                 _asm mov esi, fp
574                                                 _asm shr ecx, 1
575                                                 _asm jz  OnlyOne
576                                                 _asm pushf
577                                         InnerFontLoop:
578                                                 _asm mov al, [edi]
579                                                 _asm mov bl, [edi+1]
580                                                 _asm add edi,2
581
582                                                 _asm mov ah, [esi]
583                                                 _asm mov bh, [esi+1]
584                                                 _asm add esi,2
585
586                                                 _asm mov al, [edx+eax]
587                                                 _asm mov ah, [edx+ebx]
588
589                                                 _asm mov [edi-2], ax
590
591                                                 _asm dec ecx
592                                                 _asm jnz InnerFontLoop
593
594                                                 _asm popf
595                                                 _asm jnc NotOdd
596
597                                         OnlyOne:
598                                                 _asm mov al, [edi]
599                                                 _asm mov ah, [esi]
600                                                 _asm mov al, [edx+eax]
601                                                 _asm mov [edi], al
602
603                                         NotOdd:
604                                         dptr += gr_screen.rowsize;
605                                         fp += width;
606                                 #else
607                                         int i;
608                                         for (i=0; i< wc; i++ )  {
609                                                 *dptr++ = Current_alphacolor->table.lookup[*fp++][*dptr];
610                                         }
611                                         fp += width - wc;
612                                         dptr += gr_screen.rowsize - wc;
613                                 #endif
614                         }
615                 } else {                // No alpha color
616 #endif
617                         for (row=0; row<hc; row++)      {
618                                 int i;
619                                 for (i=0; i< wc; i++ )  {
620                                         if (*fp > 5 )
621                                                 *dptr = gr_screen.current_color.raw8;
622                                         dptr++;
623                                         fp++;
624                                 }
625                                 fp += width - wc;
626                                 dptr += gr_screen.rowsize - wc;
627                         }
628                 // }
629         }
630         gr_unlock();
631 }
632
633 #ifndef PLAT_UNIX
634 HFONT MyhFont = NULL;
635 extern HDC hDibDC;
636 #endif
637
638 void gr_string_win(int x, int y, char *s)
639 {
640 #ifdef PLAT_UNIX
641 //      STUB_FUNCTION;
642 #else
643         char *ptr;
644         SIZE size;
645
646         if ( MyhFont==NULL )    {
647                 MyhFont = CreateFont(14, 0, 0, 0,                               // height,width,?,?
648                                 700,
649                                 FALSE,
650                                 FALSE,
651                                 FALSE,                                                                                  // strikeout?
652                                 ANSI_CHARSET,                                                                   // character set
653                                 OUT_DEVICE_PRECIS,
654                                 CLIP_DEFAULT_PRECIS,
655                                 DEFAULT_QUALITY,
656                                 DEFAULT_PITCH | FF_DONTCARE,
657 //                              NULL );
658 //                              "Times New Roman" );
659 //XSTR:OFF
660                                 "Ariel" );
661 //XSTR:ON
662         }
663
664         SelectObject( hDibDC, MyhFont );
665
666         if ( gr_screen.bits_per_pixel==8 )
667                 SetTextColor(hDibDC, PALETTEINDEX(gr_screen.current_color.raw8));
668         else
669                 SetTextColor(hDibDC, RGB(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue));
670
671         SetBkMode(hDibDC,TRANSPARENT);
672
673
674         HRGN hclip;
675         hclip = CreateRectRgn( gr_screen.offset_x, 
676                                                                   gr_screen.offset_y, 
677                                                                   gr_screen.offset_x+gr_screen.clip_width-1, 
678                                                                   gr_screen.offset_y+gr_screen.clip_height-1 );
679
680         SelectClipRgn(hDibDC, hclip );
681         x += gr_screen.offset_x;
682         y += gr_screen.offset_y;
683         //ptr = strchr(s,'\n);
684         while ((ptr = strchr(s, '\n'))!=NULL) {
685                 TextOut(hDibDC, x, y, s, ptr - s);
686                 GetTextExtentPoint32(hDibDC, s, ptr - s, &size);
687                 y += size.cy;
688                 s = ptr + 1;
689         }
690
691         TextOut(hDibDC, x, y, s, strlen(s));
692         SelectClipRgn(hDibDC, NULL);
693         DeleteObject(hclip);
694 #endif
695 }
696
697 void gr_get_string_size_win(int *w, int *h, char *text)
698 {
699 #ifdef PLAT_UNIX
700 //      STUB_FUNCTION;
701 #else
702         char *ptr;
703         SIZE size;
704
705         ptr = strchr(text, '\n');
706
707         if (MyhFont==NULL)      {
708                 if (w) *w = 0;
709                 if (h) *h = 0;
710                 return;
711         }
712
713         SelectObject( hDibDC, MyhFont );
714
715         if (!ptr)       {
716                 GetTextExtentPoint32( hDibDC, text, strlen(text), &size);
717                 if (w) *w = size.cx;
718                 if (h) *h = size.cy;
719                 return;
720         }
721
722         GetTextExtentPoint32(hDibDC, text, ptr - text, &size);
723         gr_get_string_size_win(w, h, ptr+1);
724         if (w && (size.cx > *w) )
725                 *w = size.cx;
726
727         if (h)
728                 *h += size.cy;
729 #endif
730 }
731
732 char grx_printf_text[2048];     
733
734 void _cdecl gr_printf( int x, int y, char * format, ... )
735 {
736         va_list args;
737
738         if ( !Current_font ) return;
739         
740         va_start(args, format);
741         vsprintf(grx_printf_text,format,args);
742         va_end(args);
743
744         gr_string(x,y,grx_printf_text);
745 }
746
747 void gr_font_close()
748 {
749
750 }
751
752 // Returns -1 if couldn't init font, otherwise returns the
753 // font id number.
754 int gr_create_font(char * typeface)
755 {
756         CFILE *fp;
757         font *fnt;
758         int n, fontnum;
759
760         fnt = Fonts;
761         n = -1;
762         for (fontnum=0; fontnum<Num_fonts; fontnum++ )  {
763                 if (fnt->id != 0 )      {
764                         if ( !_strnicmp( fnt->filename, typeface, MAX_FILENAME_LEN ) )  {
765                                 return fontnum;
766                         }
767                 } else {
768                         if ( n < 0 )    {
769                                 n = fontnum;
770                         }                               
771                 }
772                 fnt++;
773         }
774
775         if ( fontnum==MAX_FONTS )       {
776                 Error( LOCATION, "Too many fonts!\nSee John, or change MAX_FONTS in Graphics\\Font.h\n" );
777         }
778
779         if ( fontnum == Num_fonts )     {
780                 Num_fonts++;
781         }
782         
783         bool localize = true;
784
785         fp = cfopen( typeface, "rb", CFILE_NORMAL, CF_TYPE_ANY, localize );
786         if ( fp == NULL ) return -1;
787
788         strncpy( fnt->filename, typeface, MAX_FILENAME_LEN );
789         cfread( &fnt->id, 4, 1, fp );
790         cfread( &fnt->version, sizeof(int), 1, fp );
791         cfread( &fnt->num_chars, sizeof(int), 1, fp );
792         cfread( &fnt->first_ascii, sizeof(int), 1, fp );
793         cfread( &fnt->w, sizeof(int), 1, fp );
794         cfread( &fnt->h, sizeof(int), 1, fp );
795         cfread( &fnt->num_kern_pairs, sizeof(int), 1, fp );
796         cfread( &fnt->kern_data_size, sizeof(int), 1, fp );
797         cfread( &fnt->char_data_size, sizeof(int), 1, fp );
798         cfread( &fnt->pixel_data_size, sizeof(int), 1, fp );
799
800         if ( fnt->kern_data_size )      {
801                 fnt->kern_data = (font_kernpair *)malloc( fnt->kern_data_size );
802                 Assert(fnt->kern_data!=NULL);
803                 cfread( fnt->kern_data, fnt->kern_data_size, 1, fp );
804         } else {
805                 fnt->kern_data = NULL;
806         }
807         if ( fnt->char_data_size )      {
808                 fnt->char_data = (font_char *)malloc( fnt->char_data_size );
809                 Assert( fnt->char_data != NULL );
810                 cfread( fnt->char_data, fnt->char_data_size, 1, fp );
811         } else {
812                 fnt->char_data = NULL;
813         }
814         if ( fnt->pixel_data_size )     {
815                 fnt->pixel_data = (ubyte *)malloc( fnt->pixel_data_size );
816                 Assert(fnt->pixel_data!=NULL);
817                 cfread( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
818         } else {
819                 fnt->pixel_data = NULL;
820         }
821         cfclose(fp);
822
823         // Create a bitmap for hardware cards.
824         // JAS:  Try to squeeze this into the smallest square power of two texture.
825         // This should probably be done at font generation time, not here.
826         int w, h;
827         if ( fnt->pixel_data_size < 64*64 )     {
828                 w = h = 64;
829         } else if ( fnt->pixel_data_size < 128*128 )    {
830                 w = h = 128;
831         } else {
832                 w = h = 256;
833         }
834
835         fnt->bm_w = w;
836         fnt->bm_h = h;
837         fnt->bm_data = (ubyte *)malloc(fnt->bm_w*fnt->bm_h);
838         fnt->bm_u = (int *)malloc(sizeof(int)*fnt->num_chars);
839         fnt->bm_v = (int *)malloc(sizeof(int)*fnt->num_chars);
840
841         int i,x,y;
842         x = y = 0;
843         for (i=0; i<fnt->num_chars; i++ )       {
844                 ubyte * fp;
845                 int x1, y1;
846                 fp = &fnt->pixel_data[fnt->char_data[i].offset];
847                 if ( x + fnt->char_data[i].byte_width >= fnt->bm_w )    {
848                         x = 0;
849                         y += fnt->h;
850                         if ( y+fnt->h > fnt->bm_h ) {
851                                 Error( LOCATION, "Font too big!\n" );
852                         }
853                 }
854                 fnt->bm_u[i] = x;
855                 fnt->bm_v[i] = y;
856
857                 for( y1=0; y1<fnt->h; y1++ )    {
858                         for (x1=0; x1<fnt->char_data[i].byte_width; x1++ )      {
859                                 uint c = *fp++;
860                                 if ( c > 14 ) c = 14;
861                                 fnt->bm_data[(x+x1)+(y+y1)*fnt->bm_w] = (unsigned char)(c);     
862                         }
863                 }
864                 x += fnt->char_data[i].byte_width;
865         }
866
867         fnt->bitmap_id = bm_create( 8, fnt->bm_w, fnt->bm_h, fnt->bm_data, BMP_AABITMAP );
868
869         return fontnum;
870 }
871
872 void grx_set_font(int fontnum)
873 {
874         if ( fontnum < 0 ) {
875                 Current_font = NULL;
876                 return;
877         }
878
879         if ( fontnum >= 0 ) {
880                 Current_font = &Fonts[fontnum];
881         }
882 }
883
884 void gr_font_init()
885 {
886         gr_init_font( NOX("font01.vf") );
887         gr_init_font( NOX("font02.vf") );
888         gr_init_font( NOX("font03.vf") );
889 }
890
891 // Returns -1 if couldn't init font, otherwise returns the
892 // font id number.
893 int gr_init_font(char * typeface)
894 {
895         int Loaded_fontnum;
896
897         Loaded_fontnum = gr_create_font(typeface);
898
899         Assert( Loaded_fontnum > -1 );
900
901         gr_set_font( Loaded_fontnum );
902
903         return Loaded_fontnum;
904 }
905