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