2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Graphics/Font.cpp $
15 * source file for font stuff
18 * Revision 1.8 2003/06/19 11:51:41 taylor
19 * adjustments to memory leak fixes
21 * Revision 1.7 2003/06/11 18:30:32 taylor
24 * Revision 1.6 2003/05/25 02:30:42 taylor
27 * Revision 1.5 2002/07/13 06:46:47 theoddone33
30 * Revision 1.4 2002/06/09 04:41:17 relnev
31 * added copyright header
33 * Revision 1.3 2002/06/05 08:05:29 relnev
34 * stub/warning removal.
36 * reworked the sound code.
38 * Revision 1.2 2002/05/07 03:16:45 theoddone33
39 * The Great Newline Fix
41 * Revision 1.1.1.1 2002/05/03 03:28:09 root
45 * 9 7/09/99 10:32p Dave
46 * Command brief and red alert screens.
48 * 8 12/14/98 9:21a Dan
49 * Put gr8_string() back in
51 * 7 12/02/98 5:47p Dave
52 * Put in interface xstr code. Converted barracks screen to new format.
54 * 6 11/30/98 1:07p Dave
55 * 16 bit conversion, first run.
57 * 5 11/05/98 4:18p Dave
58 * First run nebula support. Beefed up localization a bit. Removed all
59 * conditional compiles for foreign versions. Modified mission file
62 * 4 10/13/98 9:28a Dave
63 * Started neatening up freespace.h. Many variables renamed and
64 * reorganized. Added AlphaColors.[h,cpp]
66 * 3 10/13/98 9:19a Andsager
67 * Add localization support to cfile. Optional parameter with cfopen that
68 * looks for localized files.
70 * 2 10/07/98 10:52a Dave
73 * 1 10/07/98 10:49a Dave
75 * 49 7/02/98 3:41p Allender
76 * fix nasty assembler bug where pushf wasn't accompanied by corresponding
77 * pop in certain clipping conditions -- manifested only in software and
78 * usually on the PXO chat screen.
80 * 48 6/18/98 10:10a Allender
81 * fixed compiler warnings
83 * 47 6/13/98 10:48p Lawrance
84 * Changed code to utilize proper fixed-space 1 character.
86 * 46 6/13/98 3:18p Hoffoss
87 * NOX()ed out a bunch of strings that shouldn't be translated.
89 * 45 5/25/98 10:32a John
90 * Took out redundant code for font bitmap offsets that converted to a
91 * float, then later on converted back to an integer. Quite unnecessary.
93 * 44 5/12/98 11:45a John
94 * Fixed a bug with the length of string being passed to
95 * gr_get_string_size. The bug occurred if you had two or more'\n'''s in
98 * 43 3/10/98 4:18p John
99 * Cleaned up graphics lib. Took out most unused gr functions. Made D3D
100 * & Glide have popups and print screen. Took out all >8bpp software
101 * support. Made Fred zbuffer. Made zbuffer allocate dynamically to
102 * support Fred. Made zbuffering key off of functions rather than one
105 * 42 3/09/98 6:06p John
106 * Restructured font stuff to avoid duplicate code in Direct3D and Glide.
107 * Restructured Glide to avoid redundent state setting.
109 * 41 3/02/98 10:33a John
110 * Fixed bug where Y clip was using X value.
112 * 40 2/19/98 9:04a John
113 * Fixed fonts with glide
115 * 39 2/17/98 7:27p John
116 * Got fonts and texturing working in Direct3D
118 * 38 2/05/98 9:21p John
119 * Some new Direct3D code. Added code to monitor a ton of stuff in the
122 * 37 1/20/98 2:25p Hoffoss
123 * Fixed bug where timestamp printing incorrectly increments an hour at 6
126 * 36 1/19/98 6:15p John
127 * Fixed all my Optimized Build compiler warnings
129 * 35 11/30/97 12:18p John
130 * added more 24 & 32-bpp primitives
132 * 34 11/29/97 2:24p John
135 * 33 11/29/97 2:06p John
136 * added mode 16-bpp support
138 * 32 11/10/97 2:35p Hoffoss
139 * Changed timestamp printing code to utilize new fixed-space '1'
142 * 31 11/06/97 5:42p Hoffoss
143 * Added support for fixed size timstamp rendering.
145 * 30 11/03/97 10:08p Hoffoss
146 * Changed gr_get_string_size to utilize an optional length specifier, if
147 * you want to use non-null terminated strings.
149 * 29 11/03/97 10:59a John
150 * added support for more than one font.
152 * 28 10/24/97 12:13p Hoffoss
153 * Added gr_force_fit_string().
155 * 27 10/19/97 12:55p John
156 * new code to lock / unlock surfaces for smooth directx integration.
158 * 26 10/14/97 4:50p John
161 * 25 10/14/97 8:08a John
162 * added a bunch more 16 bit support
164 * 24 10/09/97 5:23p John
165 * Added support for more 16-bpp functions
167 * 23 9/23/97 10:53a Hoffoss
168 * Fixed bug in assumptions made half the time, and not the other half.
170 * 22 9/09/97 3:39p Sandeep
171 * warning level 4 bugs
173 * 21 8/19/97 5:46p Hoffoss
174 * Changed font used in Fred, and added display to show current eye
177 * 20 6/25/97 2:35p John
178 * added some functions to use the windows font for Fred.
180 * 19 6/17/97 12:03p John
181 * Moved color/alphacolor functions into their own module. Made all color
182 * functions be part of the low-level graphics drivers, not just the
185 * 18 6/13/97 2:37p John
186 * fixed a string bug that printed weird characters sometimes.
188 * 17 6/11/97 6:00p John
189 * sped up alpha matching a bit.
191 * 16 6/11/97 5:49p John
192 * Changed palette code to only recalculate alphacolors when needed, not
193 * when palette changes.
195 * 15 6/11/97 5:01p John
196 * Fixed mission log text. Added fast clipped font drawer.
198 * 14 6/11/97 4:11p John
199 * addec function to get font height
201 * 13 6/11/97 1:12p John
202 * Started fixing all the text colors in the game.
204 * 12 6/09/97 9:24a John
205 * Changed the way fonts are set.
207 * 11 6/06/97 4:41p John
208 * Fixed alpha colors to be smoothly integrated into gr_set_color_fast
211 * 10 6/06/97 2:40p John
212 * Made all the radar dim in/out
214 * 9 6/05/97 4:53p John
215 * First rev of new antialiased font stuff.
217 * 8 5/12/97 12:27p John
218 * Restructured Graphics Library to add support for multiple renderers.
220 * 7 4/24/97 11:28a Hoffoss
221 * added code to handle gr_String being called before gr_init_font ever
224 * 6 4/23/97 5:26p John
225 * First rev of new debug console stuff.
227 * 5 4/22/97 12:20p John
228 * fixed more resource leaks
230 * 4 4/22/97 10:33a John
231 * fixed the 2d resource leaks that Alan found.
233 * 3 4/04/97 11:21a Hoffoss
234 * JOHN: Fixed invalid param that caused a trap in BoundsChecker.
236 * 2 4/01/97 9:26a Allender
237 * added support for descent style fonts although they are not used in the
240 * 1 3/31/97 9:42a Allender
247 #include <windowsx.h>
251 #include "grinternal.h"
258 #include "localize.h"
261 font Fonts[MAX_FONTS];
262 font *Current_font = NULL;
265 // crops a string if required to force it to not exceed max_width pixels when printed.
266 // Does this by dropping characters at the end of the string and adding '...' to the end.
267 // str = string to crop. Modifies this string directly
268 // max_str = max characters allowed in str
269 // max_width = number of pixels to limit string to (less than or equal to).
270 // Returns: returns same pointer passed in for str.
271 char *gr_force_fit_string(char *str, int max_str, int max_width)
275 gr_get_string_size(&w, NULL, str);
277 if ((int) strlen(str) > max_str - 3) {
278 Assert(max_str >= 3);
279 str[max_str - 3] = 0;
282 strcpy(str + strlen(str) - 1, "...");
283 gr_get_string_size(&w, NULL, str);
284 while (w > max_width) {
285 Assert(strlen(str) >= 4); // if this is hit, a bad max_width was passed in and the calling function needs fixing.
286 strcpy(str + strlen(str) - 4, "...");
287 gr_get_string_size(&w, NULL, str);
294 //takes the character BEFORE being offset into current font
295 // Returns the letter code
296 int get_char_width(ubyte c1,ubyte c2,int *width,int *spacing)
300 Assert ( Current_font != NULL );
301 letter = c1-Current_font->first_ascii;
303 if (letter<0 || letter>=Current_font->num_chars) { //not in font, draw as space
305 *spacing = Current_font->w;
309 *width = Current_font->char_data[letter].byte_width;
310 *spacing = Current_font->char_data[letter].spacing;
312 i = Current_font->char_data[letter].kerning_entry;
314 if (!(c2==0 || c2=='\n')) {
317 letter2 = c2-Current_font->first_ascii;
319 if ((letter2>=0) && (letter2<Current_font->num_chars) ) { //not in font, draw as space
320 font_kernpair *k = &Current_font->kern_data[i];
321 while( (k->c1 == letter) && (k->c2<letter2) && (i<Current_font->num_kern_pairs) ) {
325 if ( k->c2 == letter2 ) {
326 *spacing += k->offset;
334 int get_centered_x(char *s)
338 for (w=0;*s!=0 && *s!='\n';s++) {
339 get_char_width(s[0],s[1],&w2,&s2);
343 return ((gr_screen.clip_width - w) / 2);
346 // draws a character centered on x
347 void gr_char_centered(int x, int y, char chr)
352 sc = Lcl_special_chars;
354 chr = (char)(sc + 1);
358 gr_get_string_size(&w, NULL, str);
359 gr_string(x - w / 2, y, str);
362 void gr_print_timestamp(int x, int y, int timestamp)
364 char h[2], m[3], s[3];
367 // format the time information into strings
368 sprintf(h, "%.1d", (timestamp / 3600000) % 10);
369 sprintf(m, "%.2d", (timestamp / 60000) % 60);
370 sprintf(s, "%.2d", (timestamp / 1000) % 60);
372 gr_get_string_size(&w, NULL, "0");
373 gr_get_string_size(&c, NULL, ":");
375 gr_string(x + w, y, ":");
376 gr_string(x + w * 3 + c, y, ":");
379 gr_char_centered(x, y, h[0]);
381 gr_char_centered(x, y, m[0]);
383 gr_char_centered(x, y, m[1]);
385 gr_char_centered(x, y, s[0]);
387 gr_char_centered(x, y, s[1]);
390 int gr_get_font_height()
393 return Current_font->h;
399 void gr_get_string_size(int *w1, int *h1, char *text, int len)
420 h += Current_font->h;
421 while (*text && (len>0) ) {
423 // Process one or more
424 while ((*text == '\n') && (len>0) ) {
428 h += Current_font->h;
437 get_char_width(text[0], text[1], &width, &spacing);
439 if (w > longest_width)
455 MONITOR( FontChars );
460 void gr8_char(int x,int y,int letter)
464 ch = &Current_font->char_data[letter];
466 gr_aabitmap_ex( x, y, ch->byte_width, Current_font->h, Current_font->u[letter], Current_font->v[letter] );
468 // mprintf(( "String = %s\n", text ));
472 void gr8_string( int sx, int sy, char *s )
474 int width, spacing, letter;
477 if ( !Current_font ) return;
480 gr_set_bitmap(Current_font->bitmap);
485 if (sx==0x8000) { //centered
486 x = get_centered_x(s);
494 y += Current_font->h;
495 if (sx==0x8000) { //centered
496 x = get_centered_x(s);
503 letter = get_char_width(s[0],s[1],&width,&spacing);
505 if (letter<0) { //not in font, draw as space
510 gr8_char( x, y, letter );
518 void gr8_string(int sx, int sy, char *s )
520 int row,width, spacing, letter;
523 if ( !Current_font ) return;
529 if (sx==0x8000) { //centered
530 x = get_centered_x(s);
541 MONITOR_INC( FontChars, 1 );
546 y += Current_font->h;
547 if (sx==0x8000) { //centered
548 x = get_centered_x(s);
555 letter = get_char_width(s[0],s[1],&width,&spacing);
558 //If not in font, draw as space
559 if (letter<0) continue;
564 // Check if this character is totally clipped
565 if ( x + width < gr_screen.clip_left ) continue;
566 if ( y + Current_font->h < gr_screen.clip_top ) continue;
567 if ( x > gr_screen.clip_right ) continue;
568 if ( y > gr_screen.clip_bottom ) continue;
571 if ( x < gr_screen.clip_left ) xd = gr_screen.clip_left - x;
572 if ( y < gr_screen.clip_top ) yd = gr_screen.clip_top - y;
576 wc = width - xd; hc = Current_font->h - yd;
577 if ( xc + wc > gr_screen.clip_right ) wc = gr_screen.clip_right - xc;
578 if ( yc + hc > gr_screen.clip_bottom ) hc = gr_screen.clip_bottom - yc;
580 if ( wc < 1 ) continue;
581 if ( hc < 1 ) continue;
583 ubyte *fp = Current_font->pixel_data + Current_font->char_data[letter].offset + xd + yd*width;
584 ubyte *dptr = GR_SCREEN_PTR(ubyte, xc, yc);
586 #ifndef HARDWARE_ONLY
587 if ( Current_alphacolor ) {
588 for (row=0; row<hc; row++) {
589 #ifdef USE_INLINE_ASM
590 ubyte *lookup = &Current_alphacolor->table.lookup[0][0];
609 _asm mov al, [edx+eax]
610 _asm mov ah, [edx+ebx]
615 _asm jnz InnerFontLoop
623 _asm mov al, [edx+eax]
627 dptr += gr_screen.rowsize;
631 for (i=0; i< wc; i++ ) {
632 *dptr++ = Current_alphacolor->table.lookup[*fp++][*dptr];
635 dptr += gr_screen.rowsize - wc;
638 } else { // No alpha color
640 for (row=0; row<hc; row++) {
642 for (i=0; i< wc; i++ ) {
644 *dptr = gr_screen.current_color.raw8;
649 dptr += gr_screen.rowsize - wc;
657 HFONT MyhFont = NULL;
661 void gr_string_win(int x, int y, char *s)
669 if ( MyhFont==NULL ) {
670 MyhFont = CreateFont(14, 0, 0, 0, // height,width,?,?
675 ANSI_CHARSET, // character set
679 DEFAULT_PITCH | FF_DONTCARE,
681 // "Times New Roman" );
687 SelectObject( hDibDC, MyhFont );
689 if ( gr_screen.bits_per_pixel==8 )
690 SetTextColor(hDibDC, PALETTEINDEX(gr_screen.current_color.raw8));
692 SetTextColor(hDibDC, RGB(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue));
694 SetBkMode(hDibDC,TRANSPARENT);
698 hclip = CreateRectRgn( gr_screen.offset_x,
700 gr_screen.offset_x+gr_screen.clip_width-1,
701 gr_screen.offset_y+gr_screen.clip_height-1 );
703 SelectClipRgn(hDibDC, hclip );
704 x += gr_screen.offset_x;
705 y += gr_screen.offset_y;
706 //ptr = strchr(s,'\n);
707 while ((ptr = strchr(s, '\n'))!=NULL) {
708 TextOut(hDibDC, x, y, s, ptr - s);
709 GetTextExtentPoint32(hDibDC, s, ptr - s, &size);
714 TextOut(hDibDC, x, y, s, strlen(s));
715 SelectClipRgn(hDibDC, NULL);
720 void gr_get_string_size_win(int *w, int *h, char *text)
728 ptr = strchr(text, '\n');
736 SelectObject( hDibDC, MyhFont );
739 GetTextExtentPoint32( hDibDC, text, strlen(text), &size);
745 GetTextExtentPoint32(hDibDC, text, ptr - text, &size);
746 gr_get_string_size_win(w, h, ptr+1);
747 if (w && (size.cx > *w) )
755 char grx_printf_text[2048];
757 void _cdecl gr_printf( int x, int y, char * format, ... )
761 if ( !Current_font ) return;
763 va_start(args, format);
764 vsprintf(grx_printf_text,format,args);
767 gr_string(x,y,grx_printf_text);
777 for (i=0; i<Num_fonts; i++) {
778 if (fnt->kern_data) {
779 free(fnt->kern_data);
780 fnt->kern_data = NULL;
783 if (fnt->char_data) {
784 free(fnt->char_data);
785 fnt->char_data = NULL;
788 if (fnt->pixel_data) {
789 free(fnt->pixel_data);
790 fnt->pixel_data = NULL;
813 // Returns -1 if couldn't init font, otherwise returns the
815 int gr_create_font(char * typeface)
823 for (fontnum=0; fontnum<Num_fonts; fontnum++ ) {
825 if ( !_strnicmp( fnt->filename, typeface, MAX_FILENAME_LEN ) ) {
836 if ( fontnum==MAX_FONTS ) {
837 Error( LOCATION, "Too many fonts!\nSee John, or change MAX_FONTS in Graphics\\Font.h\n" );
840 if ( fontnum == Num_fonts ) {
844 bool localize = true;
846 fp = cfopen( typeface, "rb", CFILE_NORMAL, CF_TYPE_ANY, localize );
847 if ( fp == NULL ) return -1;
849 strncpy( fnt->filename, typeface, MAX_FILENAME_LEN );
850 cfread( &fnt->id, 4, 1, fp );
851 cfread( &fnt->version, sizeof(int), 1, fp );
852 cfread( &fnt->num_chars, sizeof(int), 1, fp );
853 cfread( &fnt->first_ascii, sizeof(int), 1, fp );
854 cfread( &fnt->w, sizeof(int), 1, fp );
855 cfread( &fnt->h, sizeof(int), 1, fp );
856 cfread( &fnt->num_kern_pairs, sizeof(int), 1, fp );
857 cfread( &fnt->kern_data_size, sizeof(int), 1, fp );
858 cfread( &fnt->char_data_size, sizeof(int), 1, fp );
859 cfread( &fnt->pixel_data_size, sizeof(int), 1, fp );
861 if ( fnt->kern_data_size ) {
862 fnt->kern_data = (font_kernpair *)malloc( fnt->kern_data_size );
863 Assert(fnt->kern_data!=NULL);
864 cfread( fnt->kern_data, fnt->kern_data_size, 1, fp );
866 fnt->kern_data = NULL;
868 if ( fnt->char_data_size ) {
869 fnt->char_data = (font_char *)malloc( fnt->char_data_size );
870 Assert( fnt->char_data != NULL );
871 cfread( fnt->char_data, fnt->char_data_size, 1, fp );
873 fnt->char_data = NULL;
875 if ( fnt->pixel_data_size ) {
876 fnt->pixel_data = (ubyte *)malloc( fnt->pixel_data_size );
877 Assert(fnt->pixel_data!=NULL);
878 cfread( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
880 fnt->pixel_data = NULL;
884 // Create a bitmap for hardware cards.
885 // JAS: Try to squeeze this into the smallest square power of two texture.
886 // This should probably be done at font generation time, not here.
888 if ( fnt->pixel_data_size < 64*64 ) {
890 } else if ( fnt->pixel_data_size < 128*128 ) {
898 fnt->bm_data = (ubyte *)malloc(fnt->bm_w*fnt->bm_h);
899 fnt->bm_u = (int *)malloc(sizeof(int)*fnt->num_chars);
900 fnt->bm_v = (int *)malloc(sizeof(int)*fnt->num_chars);
904 for (i=0; i<fnt->num_chars; i++ ) {
907 fp = &fnt->pixel_data[fnt->char_data[i].offset];
908 if ( x + fnt->char_data[i].byte_width >= fnt->bm_w ) {
911 if ( y+fnt->h > fnt->bm_h ) {
912 Error( LOCATION, "Font too big!\n" );
918 for( y1=0; y1<fnt->h; y1++ ) {
919 for (x1=0; x1<fnt->char_data[i].byte_width; x1++ ) {
921 if ( c > 14 ) c = 14;
922 fnt->bm_data[(x+x1)+(y+y1)*fnt->bm_w] = (unsigned char)(c);
925 x += fnt->char_data[i].byte_width;
928 fnt->bitmap_id = bm_create( 8, fnt->bm_w, fnt->bm_h, fnt->bm_data, BMP_AABITMAP );
933 void grx_set_font(int fontnum)
940 if ( fontnum >= 0 ) {
941 Current_font = &Fonts[fontnum];
947 gr_init_font( NOX("font01.vf") );
948 gr_init_font( NOX("font02.vf") );
950 gr_init_font( NOX("font03.vf") );
954 // Returns -1 if couldn't init font, otherwise returns the
956 int gr_init_font(char * typeface)
960 Loaded_fontnum = gr_create_font(typeface);
962 Assert( Loaded_fontnum > -1 );
964 gr_set_font( Loaded_fontnum );
966 return Loaded_fontnum;