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