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.10 2004/06/11 00:55:25 tigital
19 * byte-swapping changes for bigendian systems
21 * Revision 1.9 2003/08/03 15:51:58 taylor
22 * fix issue with FS1 fonts
24 * Revision 1.8 2003/06/19 11:51:41 taylor
25 * adjustments to memory leak fixes
27 * Revision 1.7 2003/06/11 18:30:32 taylor
30 * Revision 1.6 2003/05/25 02:30:42 taylor
33 * Revision 1.5 2002/07/13 06:46:47 theoddone33
36 * Revision 1.4 2002/06/09 04:41:17 relnev
37 * added copyright header
39 * Revision 1.3 2002/06/05 08:05:29 relnev
40 * stub/warning removal.
42 * reworked the sound code.
44 * Revision 1.2 2002/05/07 03:16:45 theoddone33
45 * The Great Newline Fix
47 * Revision 1.1.1.1 2002/05/03 03:28:09 root
51 * 9 7/09/99 10:32p Dave
52 * Command brief and red alert screens.
54 * 8 12/14/98 9:21a Dan
55 * Put gr8_string() back in
57 * 7 12/02/98 5:47p Dave
58 * Put in interface xstr code. Converted barracks screen to new format.
60 * 6 11/30/98 1:07p Dave
61 * 16 bit conversion, first run.
63 * 5 11/05/98 4:18p Dave
64 * First run nebula support. Beefed up localization a bit. Removed all
65 * conditional compiles for foreign versions. Modified mission file
68 * 4 10/13/98 9:28a Dave
69 * Started neatening up freespace.h. Many variables renamed and
70 * reorganized. Added AlphaColors.[h,cpp]
72 * 3 10/13/98 9:19a Andsager
73 * Add localization support to cfile. Optional parameter with cfopen that
74 * looks for localized files.
76 * 2 10/07/98 10:52a Dave
79 * 1 10/07/98 10:49a Dave
81 * 49 7/02/98 3:41p Allender
82 * fix nasty assembler bug where pushf wasn't accompanied by corresponding
83 * pop in certain clipping conditions -- manifested only in software and
84 * usually on the PXO chat screen.
86 * 48 6/18/98 10:10a Allender
87 * fixed compiler warnings
89 * 47 6/13/98 10:48p Lawrance
90 * Changed code to utilize proper fixed-space 1 character.
92 * 46 6/13/98 3:18p Hoffoss
93 * NOX()ed out a bunch of strings that shouldn't be translated.
95 * 45 5/25/98 10:32a John
96 * Took out redundant code for font bitmap offsets that converted to a
97 * float, then later on converted back to an integer. Quite unnecessary.
99 * 44 5/12/98 11:45a John
100 * Fixed a bug with the length of string being passed to
101 * gr_get_string_size. The bug occurred if you had two or more'\n'''s in
104 * 43 3/10/98 4:18p John
105 * Cleaned up graphics lib. Took out most unused gr functions. Made D3D
106 * & Glide have popups and print screen. Took out all >8bpp software
107 * support. Made Fred zbuffer. Made zbuffer allocate dynamically to
108 * support Fred. Made zbuffering key off of functions rather than one
111 * 42 3/09/98 6:06p John
112 * Restructured font stuff to avoid duplicate code in Direct3D and Glide.
113 * Restructured Glide to avoid redundent state setting.
115 * 41 3/02/98 10:33a John
116 * Fixed bug where Y clip was using X value.
118 * 40 2/19/98 9:04a John
119 * Fixed fonts with glide
121 * 39 2/17/98 7:27p John
122 * Got fonts and texturing working in Direct3D
124 * 38 2/05/98 9:21p John
125 * Some new Direct3D code. Added code to monitor a ton of stuff in the
128 * 37 1/20/98 2:25p Hoffoss
129 * Fixed bug where timestamp printing incorrectly increments an hour at 6
132 * 36 1/19/98 6:15p John
133 * Fixed all my Optimized Build compiler warnings
135 * 35 11/30/97 12:18p John
136 * added more 24 & 32-bpp primitives
138 * 34 11/29/97 2:24p John
141 * 33 11/29/97 2:06p John
142 * added mode 16-bpp support
144 * 32 11/10/97 2:35p Hoffoss
145 * Changed timestamp printing code to utilize new fixed-space '1'
148 * 31 11/06/97 5:42p Hoffoss
149 * Added support for fixed size timstamp rendering.
151 * 30 11/03/97 10:08p Hoffoss
152 * Changed gr_get_string_size to utilize an optional length specifier, if
153 * you want to use non-null terminated strings.
155 * 29 11/03/97 10:59a John
156 * added support for more than one font.
158 * 28 10/24/97 12:13p Hoffoss
159 * Added gr_force_fit_string().
161 * 27 10/19/97 12:55p John
162 * new code to lock / unlock surfaces for smooth directx integration.
164 * 26 10/14/97 4:50p John
167 * 25 10/14/97 8:08a John
168 * added a bunch more 16 bit support
170 * 24 10/09/97 5:23p John
171 * Added support for more 16-bpp functions
173 * 23 9/23/97 10:53a Hoffoss
174 * Fixed bug in assumptions made half the time, and not the other half.
176 * 22 9/09/97 3:39p Sandeep
177 * warning level 4 bugs
179 * 21 8/19/97 5:46p Hoffoss
180 * Changed font used in Fred, and added display to show current eye
183 * 20 6/25/97 2:35p John
184 * added some functions to use the windows font for Fred.
186 * 19 6/17/97 12:03p John
187 * Moved color/alphacolor functions into their own module. Made all color
188 * functions be part of the low-level graphics drivers, not just the
191 * 18 6/13/97 2:37p John
192 * fixed a string bug that printed weird characters sometimes.
194 * 17 6/11/97 6:00p John
195 * sped up alpha matching a bit.
197 * 16 6/11/97 5:49p John
198 * Changed palette code to only recalculate alphacolors when needed, not
199 * when palette changes.
201 * 15 6/11/97 5:01p John
202 * Fixed mission log text. Added fast clipped font drawer.
204 * 14 6/11/97 4:11p John
205 * addec function to get font height
207 * 13 6/11/97 1:12p John
208 * Started fixing all the text colors in the game.
210 * 12 6/09/97 9:24a John
211 * Changed the way fonts are set.
213 * 11 6/06/97 4:41p John
214 * Fixed alpha colors to be smoothly integrated into gr_set_color_fast
217 * 10 6/06/97 2:40p John
218 * Made all the radar dim in/out
220 * 9 6/05/97 4:53p John
221 * First rev of new antialiased font stuff.
223 * 8 5/12/97 12:27p John
224 * Restructured Graphics Library to add support for multiple renderers.
226 * 7 4/24/97 11:28a Hoffoss
227 * added code to handle gr_String being called before gr_init_font ever
230 * 6 4/23/97 5:26p John
231 * First rev of new debug console stuff.
233 * 5 4/22/97 12:20p John
234 * fixed more resource leaks
236 * 4 4/22/97 10:33a John
237 * fixed the 2d resource leaks that Alan found.
239 * 3 4/04/97 11:21a Hoffoss
240 * JOHN: Fixed invalid param that caused a trap in BoundsChecker.
242 * 2 4/01/97 9:26a Allender
243 * added support for descent style fonts although they are not used in the
246 * 1 3/31/97 9:42a Allender
254 #include "grinternal.h"
261 #include "localize.h"
264 font Fonts[MAX_FONTS];
265 font *Current_font = NULL;
268 // crops a string if required to force it to not exceed max_width pixels when printed.
269 // Does this by dropping characters at the end of the string and adding '...' to the end.
270 // str = string to crop. Modifies this string directly
271 // max_str = max characters allowed in str
272 // max_width = number of pixels to limit string to (less than or equal to).
273 // Returns: returns same pointer passed in for str.
274 char *gr_force_fit_string(char *str, int max_str, int max_width)
278 gr_get_string_size(&w, NULL, str);
280 if ((int) strlen(str) > max_str - 3) {
281 SDL_assert(max_str >= 3);
282 str[max_str - 3] = 0;
285 SDL_strlcpy(str + strlen(str) - 1, "...", max_str);
286 gr_get_string_size(&w, NULL, str);
287 while (w > max_width) {
288 SDL_assert(strlen(str) >= 4); // if this is hit, a bad max_width was passed in and the calling function needs fixing.
289 SDL_strlcpy(str + strlen(str) - 4, "...", max_str);
290 gr_get_string_size(&w, NULL, str);
297 //takes the character BEFORE being offset into current font
298 // Returns the letter code
299 int get_char_width(ubyte c1,ubyte c2,int *width,int *spacing)
303 SDL_assert ( Current_font != NULL );
304 letter = c1-Current_font->first_ascii;
306 if (letter<0 || letter>=Current_font->num_chars) { //not in font, draw as space
308 *spacing = Current_font->w;
312 *width = Current_font->char_data[letter].byte_width;
313 *spacing = Current_font->char_data[letter].spacing;
315 i = Current_font->char_data[letter].kerning_entry;
317 if (!(c2==0 || c2=='\n')) {
320 letter2 = c2-Current_font->first_ascii;
323 if ((letter2>=0) && (letter2<Current_font->num_chars) ) { //not in font, draw as space
325 // umm, not sure about this, issue with FS1 fonts that's no longer handled apparently
326 if ((letter2>=0) && (letter2<Current_font->num_chars) && (Current_font->num_kern_pairs != 159) ) { //not in font, draw as space
328 font_kernpair *k = &Current_font->kern_data[i];
329 while( (k->c1 == letter) && (k->c2<letter2) && (i<Current_font->num_kern_pairs) ) {
333 if ( k->c2 == letter2 ) {
334 *spacing += k->offset;
342 int get_centered_x(const char *s)
346 for (w=0;*s!=0 && *s!='\n';s++) {
347 get_char_width(s[0],s[1],&w2,&s2);
351 return ((gr_screen.clip_width - w) / 2);
354 // draws a character centered on x
355 void gr_char_centered(int x, int y, char chr)
360 sc = Lcl_special_chars;
362 chr = (char)(sc + 1);
366 gr_get_string_size(&w, NULL, str);
367 gr_string(x - w / 2, y, str);
370 void gr_print_timestamp(int x, int y, int timestamp)
372 char h[2], m[3], s[3];
375 // format the time information into strings
376 SDL_snprintf(h, sizeof(h), "%.1d", (timestamp / 3600000) % 10);
377 SDL_snprintf(m, sizeof(m), "%.2d", (timestamp / 60000) % 60);
378 SDL_snprintf(s, sizeof(s), "%.2d", (timestamp / 1000) % 60);
380 gr_get_string_size(&w, NULL, "0");
381 gr_get_string_size(&c, NULL, ":");
383 gr_string(x + w, y, ":");
384 gr_string(x + w * 3 + c, y, ":");
387 gr_char_centered(x, y, h[0]);
389 gr_char_centered(x, y, m[0]);
391 gr_char_centered(x, y, m[1]);
393 gr_char_centered(x, y, s[0]);
395 gr_char_centered(x, y, s[1]);
398 int gr_get_font_height()
401 return Current_font->h;
407 void gr_get_string_size(int *w1, int *h1, const char *text, int len)
428 h += Current_font->h;
429 while (*text && (len>0) ) {
431 // Process one or more
432 while ((*text == '\n') && (len>0) ) {
436 h += Current_font->h;
445 get_char_width(text[0], text[1], &width, &spacing);
447 if (w > longest_width)
463 MONITOR( FontChars );
466 void gr_string_win(int x, int y, const char *s)
471 void gr_get_string_size_win(int *w, int *h, const char *text)
476 char grx_printf_text[2048];
478 void __cdecl gr_printf( int x, int y, const char * format, ... )
482 if ( !Current_font ) return;
484 va_start(args, format);
485 SDL_vsnprintf(grx_printf_text, sizeof(grx_printf_text), format, args);
488 gr_string(x,y,grx_printf_text);
498 for (i=0; i<Num_fonts; i++) {
499 if (fnt->kern_data) {
500 free(fnt->kern_data);
501 fnt->kern_data = NULL;
504 if (fnt->char_data) {
505 free(fnt->char_data);
506 fnt->char_data = NULL;
509 if (fnt->pixel_data) {
510 free(fnt->pixel_data);
511 fnt->pixel_data = NULL;
534 // Returns -1 if couldn't init font, otherwise returns the
536 int gr_create_font(const char * typeface)
544 for (fontnum=0; fontnum<Num_fonts; fontnum++ ) {
546 if ( !SDL_strncasecmp( fnt->filename, typeface, MAX_FILENAME_LEN ) ) {
557 if ( fontnum==MAX_FONTS ) {
558 Error( LOCATION, "Too many fonts!\nSee John, or change MAX_FONTS in Graphics\\Font.h\n" );
561 if ( fontnum == Num_fonts ) {
565 bool localize = true;
567 fp = cfopen( typeface, "rb", CFILE_NORMAL, CF_TYPE_ANY, localize );
568 if ( fp == NULL ) return -1;
570 SDL_strlcpy( fnt->filename, typeface, MAX_FILENAME_LEN );
571 cfread( &fnt->id, 4, 1, fp );
572 cfread( &fnt->version, sizeof(int), 1, fp );
573 cfread( &fnt->num_chars, sizeof(int), 1, fp );
574 cfread( &fnt->first_ascii, sizeof(int), 1, fp );
575 cfread( &fnt->w, sizeof(int), 1, fp );
576 cfread( &fnt->h, sizeof(int), 1, fp );
577 cfread( &fnt->num_kern_pairs, sizeof(int), 1, fp );
578 cfread( &fnt->kern_data_size, sizeof(int), 1, fp );
579 cfread( &fnt->char_data_size, sizeof(int), 1, fp );
580 cfread( &fnt->pixel_data_size, sizeof(int), 1, fp );
582 fnt->id = INTEL_SHORT( fnt->id );
583 fnt->version = INTEL_INT( fnt->version );
584 fnt->num_chars = INTEL_INT( fnt->num_chars );
585 fnt->first_ascii = INTEL_INT( fnt->first_ascii );
586 fnt->w = INTEL_INT( fnt->w );
587 fnt->h = INTEL_INT( fnt->h );
588 fnt->num_kern_pairs = INTEL_INT( fnt->num_kern_pairs );
589 fnt->kern_data_size = INTEL_INT( fnt->kern_data_size );
590 fnt->char_data_size = INTEL_INT( fnt->char_data_size );
591 fnt->pixel_data_size = INTEL_INT( fnt->pixel_data_size );
593 if ( fnt->kern_data_size ) {
594 fnt->kern_data = (font_kernpair *)malloc( fnt->kern_data_size );
595 SDL_assert(fnt->kern_data!=NULL);
596 cfread( fnt->kern_data, fnt->kern_data_size, 1, fp );
598 fnt->kern_data = NULL;
600 if ( fnt->char_data_size ) {
601 fnt->char_data = (font_char *)malloc( fnt->char_data_size );
602 SDL_assert( fnt->char_data != NULL );
603 cfread( fnt->char_data, fnt->char_data_size, 1, fp );
604 for ( int i=0; i<fnt->num_chars; i++){
605 fnt->char_data[i].spacing = INTEL_INT( fnt->char_data[i].spacing );
606 fnt->char_data[i].byte_width = INTEL_INT( fnt->char_data[i].byte_width );
607 fnt->char_data[i].offset = INTEL_INT( fnt->char_data[i].offset );
608 fnt->char_data[i].kerning_entry = INTEL_SHORT( fnt->char_data[i].kerning_entry );
609 fnt->char_data[i].user_data = INTEL_SHORT( fnt->char_data[i].user_data );
612 fnt->char_data = NULL;
614 if ( fnt->pixel_data_size ) {
615 fnt->pixel_data = (ubyte *)malloc( fnt->pixel_data_size );
616 SDL_assert(fnt->pixel_data!=NULL);
617 cfread( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
619 fnt->pixel_data = NULL;
623 // Create a bitmap for hardware cards.
624 // JAS: Try to squeeze this into the smallest square power of two texture.
625 // This should probably be done at font generation time, not here.
627 if ( fnt->pixel_data_size < 64*64 ) {
629 } else if ( fnt->pixel_data_size < 128*128 ) {
637 fnt->bm_data = (ubyte *)malloc(fnt->bm_w*fnt->bm_h);
638 fnt->bm_u = (int *)malloc(sizeof(int)*fnt->num_chars);
639 fnt->bm_v = (int *)malloc(sizeof(int)*fnt->num_chars);
641 memset(fnt->bm_data, 0, fnt->bm_w * fnt->bm_h);
642 memset(fnt->bm_u, 0, sizeof(int) * fnt->num_chars);
643 memset(fnt->bm_v, 0, sizeof(int) * fnt->num_chars);
647 for (i=0; i<fnt->num_chars; i++ ) {
650 fp = &fnt->pixel_data[fnt->char_data[i].offset];
651 if ( x + fnt->char_data[i].byte_width >= fnt->bm_w ) {
654 if ( y+fnt->h > fnt->bm_h ) {
655 Error( LOCATION, "Font too big!\n" );
661 for( y1=0; y1<fnt->h; y1++ ) {
662 for (x1=0; x1<fnt->char_data[i].byte_width; x1++ ) {
664 if ( c > 14 ) c = 14;
665 fnt->bm_data[(x+x1)+(y+y1)*fnt->bm_w] = (unsigned char)(c);
668 x += fnt->char_data[i].byte_width;
671 fnt->bitmap_id = bm_create( 8, fnt->bm_w, fnt->bm_h, fnt->bm_data, BMP_AABITMAP );
676 void gr_set_font(int fontnum)
683 if ( fontnum >= 0 ) {
684 Current_font = &Fonts[fontnum];
690 gr_init_font( NOX("font01.vf") );
691 gr_init_font( NOX("font02.vf") );
693 gr_init_font( NOX("font03.vf") );
697 // Returns -1 if couldn't init font, otherwise returns the
699 int gr_init_font(const char * typeface)
703 Loaded_fontnum = gr_create_font(typeface);
705 SDL_assert( Loaded_fontnum > -1 );
707 gr_set_font( Loaded_fontnum );
709 return Loaded_fontnum;