]> icculus.org git repositories - btb/d2x.git/blob - 2d/font.c
remove rcs tags
[btb/d2x.git] / 2d / font.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Graphical routines for drawing fonts.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <conf.h>
22 #endif
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #if !defined(_MSC_VER) && !defined(macintosh)
30 #include <fcntl.h>
31 #include <unistd.h>
32 #endif
33
34 #include "u_mem.h"
35
36 #include "gr.h"
37 #include "grdef.h"
38 #include "error.h"
39
40 #include "cfile.h"
41 #include "mono.h"
42 #include "byteswap.h"
43 #include "bitmap.h"
44
45 #include "makesig.h"
46
47 #define MAX_OPEN_FONTS  50
48 #define FILENAME_LEN            13
49
50 typedef struct openfont {
51         char filename[FILENAME_LEN];
52         grs_font *ptr;
53         char *dataptr;
54 } openfont;
55
56 //list of open fonts, for use (for now) for palette remapping
57 openfont open_font[MAX_OPEN_FONTS];
58
59 #define FONT        grd_curcanv->cv_font
60 #define FG_COLOR    grd_curcanv->cv_font_fg_color
61 #define BG_COLOR    grd_curcanv->cv_font_bg_color
62 #define FWIDTH       FONT->ft_w
63 #define FHEIGHT      FONT->ft_h
64 #define FBASELINE    FONT->ft_baseline
65 #define FFLAGS       FONT->ft_flags
66 #define FMINCHAR     FONT->ft_minchar
67 #define FMAXCHAR     FONT->ft_maxchar
68 #define FDATA        FONT->ft_data
69 #define FCHARS       FONT->ft_chars
70 #define FWIDTHS      FONT->ft_widths
71
72 #define BITS_TO_BYTES(x)    (((x)+7)>>3)
73
74 int gr_internal_string_clipped(int x, int y, char *s );
75 int gr_internal_string_clipped_m(int x, int y, char *s );
76
77 ubyte *find_kern_entry(grs_font *font,ubyte first,ubyte second)
78 {
79         ubyte *p=font->ft_kerndata;
80
81         while (*p!=255)
82                 if (p[0]==first && p[1]==second)
83                         return p;
84                 else p+=3;
85
86         return NULL;
87
88 }
89
90 //takes the character AFTER being offset into font
91 #define INFONT(_c) ((_c >= 0) && (_c <= FMAXCHAR-FMINCHAR))
92
93 //takes the character BEFORE being offset into current font
94 void get_char_width(ubyte c,ubyte c2,int *width,int *spacing)
95 {
96         int letter;
97
98         letter = c-FMINCHAR;
99
100         if (!INFONT(letter)) {                          //not in font, draw as space
101                 *width=0;
102                 if (FFLAGS & FT_PROPORTIONAL)
103                         *spacing = FWIDTH/2;
104                 else
105                         *spacing = FWIDTH;
106                 return;
107         }
108
109         if (FFLAGS & FT_PROPORTIONAL)
110                 *width = FWIDTHS[letter];
111         else
112                 *width = FWIDTH;
113
114         *spacing = *width;
115
116         if (FFLAGS & FT_KERNED)  {
117                 ubyte *p;
118
119                 if (!(c2==0 || c2=='\n')) {
120                         int letter2;
121
122                         letter2 = c2-FMINCHAR;
123
124                         if (INFONT(letter2)) {
125
126                                 p = find_kern_entry(FONT,(ubyte)letter,letter2);
127
128                                 if (p)
129                                         *spacing = p[2];
130                         }
131                 }
132         }
133 }
134
135 int get_centered_x(char *s)
136 {
137         int w,w2,s2;
138
139         for (w=0;*s!=0 && *s!='\n';s++) {
140                 if (*s<=0x06) {
141                         if (*s<=0x03)
142                                 s++;
143                         continue;//skip color codes.
144                 }
145                 get_char_width(s[0],s[1],&w2,&s2);
146                 w += s2;
147         }
148
149         return ((grd_curcanv->cv_bitmap.bm_w - w) / 2);
150 }
151
152 //hack to allow color codes to be embedded in strings -MPM
153 //note we subtract one from color, since 255 is "transparent" so it'll never be used, and 0 would otherwise end the string.
154 //function must already have orig_color var set (or they could be passed as args...)
155 //perhaps some sort of recursive orig_color type thing would be better, but that would be way too much trouble for little gain
156 int gr_message_color_level=1;
157 #define CHECK_EMBEDDED_COLORS() if ((*text_ptr >= 0x01) && (*text_ptr <= 0x03)) { \
158                 text_ptr++; \
159                 if (*text_ptr){ \
160                         if (gr_message_color_level >= *(text_ptr-1)) \
161                                 FG_COLOR = *text_ptr - 1; \
162                         text_ptr++; \
163                 } \
164         } \
165         else if ((*text_ptr >= 0x04) && (*text_ptr <= 0x06)){ \
166                 if (gr_message_color_level >= *text_ptr - 3) \
167                         FG_COLOR=orig_color; \
168                 text_ptr++; \
169         }
170
171 int gr_internal_string0(int x, int y, char *s )
172 {
173         unsigned char * fp;
174         char * text_ptr, * next_row, * text_ptr1;
175         int r, BitMask, i, bits, width, spacing, letter, underline;
176         int     skip_lines = 0;
177
178         unsigned int VideoOffset, VideoOffset1;
179
180         bits=0;
181
182         VideoOffset1 = y * ROWSIZE + x;
183
184         next_row = s;
185
186         while (next_row != NULL )
187         {
188                 text_ptr1 = next_row;
189                 next_row = NULL;
190
191                 if (x==0x8000) {                        //centered
192                         int xx = get_centered_x(text_ptr1);
193                         VideoOffset1 = y * ROWSIZE + xx;
194                 }
195
196                 for (r=0; r<FHEIGHT; r++)
197                 {
198
199                         text_ptr = text_ptr1;
200
201                         VideoOffset = VideoOffset1;
202
203                         while (*text_ptr)
204                         {
205                                 if (*text_ptr == '\n' )
206                                 {
207                                         next_row = &text_ptr[1];
208                                         break;
209                                 }
210
211                                 if (*text_ptr == CC_COLOR) {
212                                         FG_COLOR = *(text_ptr+1);
213                                         text_ptr += 2;
214                                         continue;
215                                 }
216
217                                 if (*text_ptr == CC_LSPACING) {
218                                         skip_lines = *(text_ptr+1) - '0';
219                                         text_ptr += 2;
220                                         continue;
221                                 }
222
223                                 underline = 0;
224                                 if (*text_ptr == CC_UNDERLINE )
225                                 {
226                                         if ((r==FBASELINE+2) || (r==FBASELINE+3))
227                                                 underline = 1;
228                                         text_ptr++;
229                                 }
230
231                                 get_char_width(text_ptr[0],text_ptr[1],&width,&spacing);
232
233                                 letter = (unsigned char)*text_ptr - FMINCHAR;
234
235                                 if (!INFONT(letter)) {  //not in font, draw as space
236                                         VideoOffset += spacing;
237                                         text_ptr++;
238                                         continue;
239                                 }
240
241                                 if (FFLAGS & FT_PROPORTIONAL)
242                                         fp = FCHARS[letter];
243                                 else
244                                         fp = FDATA + letter * BITS_TO_BYTES(width)*FHEIGHT;
245
246                                 if (underline)
247                                         for (i=0; i< width; i++ )
248                                                 DATA[VideoOffset++] = (unsigned char) FG_COLOR;
249                                 else
250                                 {
251                                         fp += BITS_TO_BYTES(width)*r;
252
253                                         BitMask = 0;
254
255                                         for (i=0; i< width; i++ )
256                                         {
257                                                 if (BitMask==0) {
258                                                         bits = *fp++;
259                                                         BitMask = 0x80;
260                                                 }
261
262                                                 if (bits & BitMask)
263                                                         DATA[VideoOffset++] = (unsigned char) FG_COLOR;
264                                                 else
265                                                         DATA[VideoOffset++] = (unsigned char) BG_COLOR;
266                                                 BitMask >>= 1;
267                                         }
268                                 }
269
270                                 VideoOffset += spacing-width;           //for kerning
271
272                                 text_ptr++;
273                         }
274
275                         VideoOffset1 += ROWSIZE; y++;
276                 }
277
278                 y += skip_lines;
279                 VideoOffset1 += ROWSIZE * skip_lines;
280                 skip_lines = 0;
281         }
282         return 0;
283 }
284
285 int gr_internal_string0m(int x, int y, char *s )
286 {
287         unsigned char * fp;
288         char * text_ptr, * next_row, * text_ptr1;
289         int r, BitMask, i, bits, width, spacing, letter, underline;
290         int     skip_lines = 0;
291
292         unsigned int VideoOffset, VideoOffset1;
293
294         int orig_color=FG_COLOR;//to allow easy reseting to default string color with colored strings -MPM
295
296         bits=0;
297
298         VideoOffset1 = y * ROWSIZE + x;
299
300         next_row = s;
301
302         while (next_row != NULL )
303         {
304                 text_ptr1 = next_row;
305                 next_row = NULL;
306
307                 if (x==0x8000) {                        //centered
308                         int xx = get_centered_x(text_ptr1);
309                         VideoOffset1 = y * ROWSIZE + xx;
310                 }
311
312                 for (r=0; r<FHEIGHT; r++)
313                 {
314
315                         text_ptr = text_ptr1;
316
317                         VideoOffset = VideoOffset1;
318
319                         while (*text_ptr)
320                         {
321                                 if (*text_ptr == '\n' )
322                                 {
323                                         next_row = &text_ptr[1];
324                                         break;
325                                 }
326
327                                 if (*text_ptr == CC_COLOR) {
328                                         FG_COLOR = *(text_ptr+1);
329                                         text_ptr += 2;
330                                         continue;
331                                 }
332
333                                 if (*text_ptr == CC_LSPACING) {
334                                         skip_lines = *(text_ptr+1) - '0';
335                                         text_ptr += 2;
336                                         continue;
337                                 }
338
339                                 underline = 0;
340                                 if (*text_ptr == CC_UNDERLINE )
341                                 {
342                                         if ((r==FBASELINE+2) || (r==FBASELINE+3))
343                                                 underline = 1;
344                                         text_ptr++;
345                                 }
346
347                                 get_char_width(text_ptr[0],text_ptr[1],&width,&spacing);
348
349                                 letter = (unsigned char)*text_ptr-FMINCHAR;
350
351                                 if (!INFONT(letter) || (unsigned char) *text_ptr <= 0x06)       //not in font, draw as space
352                                 {
353                                         CHECK_EMBEDDED_COLORS() else{
354                                                 VideoOffset += spacing;
355                                                 text_ptr++;
356                                         }
357                                         continue;
358                                 }
359
360                                 if (FFLAGS & FT_PROPORTIONAL)
361                                         fp = FCHARS[letter];
362                                 else
363                                         fp = FDATA + letter * BITS_TO_BYTES(width)*FHEIGHT;
364
365                                 if (underline)
366                                         for (i=0; i< width; i++ )
367                                                 DATA[VideoOffset++] = (unsigned int) FG_COLOR;
368                                 else
369                                 {
370                                         fp += BITS_TO_BYTES(width)*r;
371
372                                         BitMask = 0;
373
374                                         for (i=0; i< width; i++ )
375                                         {
376                                                 if (BitMask==0) {
377                                                         bits = *fp++;
378                                                         BitMask = 0x80;
379                                                 }
380
381                                                 if (bits & BitMask)
382                                                         DATA[VideoOffset++] = (unsigned int) FG_COLOR;
383                                                 else
384                                                         VideoOffset++;
385                                                 BitMask >>= 1;
386                                         }
387                                 }
388                                 text_ptr++;
389
390                                 VideoOffset += spacing-width;
391                         }
392
393                         VideoOffset1 += ROWSIZE;
394                         y++;
395                 }
396                 y += skip_lines;
397                 VideoOffset1 += ROWSIZE * skip_lines;
398                 skip_lines = 0;
399         }
400         return 0;
401 }
402
403 #ifdef __MSDOS__
404 int gr_internal_string2(int x, int y, char *s )
405 {
406         unsigned char * fp;
407         ubyte * text_ptr, * next_row, * text_ptr1;
408         int r, BitMask, i, bits, width, spacing, letter, underline;
409         int page_switched, skip_lines = 0;
410
411         unsigned int VideoOffset, VideoOffset1;
412
413         VideoOffset1 = (size_t)DATA + y * ROWSIZE + x;
414
415         bits = 0;
416
417         gr_vesa_setpage(VideoOffset1 >> 16);
418
419         VideoOffset1 &= 0xFFFF;
420
421         next_row = s;
422
423         while (next_row != NULL )
424         {
425                 text_ptr1 = next_row;
426                 next_row = NULL;
427
428                 if (x==0x8000) {                        //centered
429                         int xx = get_centered_x(text_ptr1);
430                         VideoOffset1 = y * ROWSIZE + xx;
431                         gr_vesa_setpage(VideoOffset1 >> 16);
432                         VideoOffset1 &= 0xFFFF;
433                 }
434
435                 for (r=0; r<FHEIGHT; r++)
436                 {
437                         text_ptr = text_ptr1;
438
439                         VideoOffset = VideoOffset1;
440
441                         page_switched = 0;
442
443                         while (*text_ptr)
444                         {
445                                 if (*text_ptr == '\n' )
446                                 {
447                                         next_row = &text_ptr[1];
448                                         break;
449                                 }
450
451                                 if (*text_ptr == CC_COLOR) {
452                                         FG_COLOR = *(text_ptr+1);
453                                         text_ptr += 2;
454                                         continue;
455                                 }
456
457                                 if (*text_ptr == CC_LSPACING) {
458                                         skip_lines = *(text_ptr+1) - '0';
459                                         text_ptr += 2;
460                                         continue;
461                                 }
462
463                                 underline = 0;
464                                 if (*text_ptr == CC_UNDERLINE )
465                                 {
466                                         if ((r==FBASELINE+2) || (r==FBASELINE+3))
467                                                 underline = 1;
468                                         text_ptr++;
469                                 }
470
471                                 get_char_width(text_ptr[0],text_ptr[1],&width,&spacing);
472
473                                 Assert(width==spacing);         //no kerning support here
474
475                                 letter = *text_ptr-FMINCHAR;
476
477                                 if (!INFONT(letter)) {  //not in font, draw as space
478                                         VideoOffset += spacing;
479                                         text_ptr++;
480                                         continue;
481                                 }
482
483                                 if (FFLAGS & FT_PROPORTIONAL)
484                                         fp = FCHARS[letter];
485                                 else
486                                         fp = FDATA + letter * BITS_TO_BYTES(width)*FHEIGHT;
487
488                                 if (underline)
489                                 {
490                                         if ( VideoOffset+width > 0xFFFF )
491                                         {
492                                                 for (i=0; i< width; i++ )
493                                                 {
494                                                         gr_video_memory[VideoOffset++] = FG_COLOR;
495
496                                                         if (VideoOffset > 0xFFFF )
497                                                         {
498                                                                 VideoOffset -= 0xFFFF + 1;
499                                                                 page_switched = 1;
500                                                                 gr_vesa_incpage();
501                                                         }
502                                                 }
503                                         }
504                                         else
505                                         {
506                                                 for (i=0; i< width; i++ )
507                                                         gr_video_memory[VideoOffset++] = FG_COLOR;
508                                         }
509                                 }
510                                 else
511                                 {
512                                         // fp -- dword
513                                         // VideoOffset
514                                         // width
515
516                                         fp += BITS_TO_BYTES(width)*r;
517
518                                         BitMask = 0;
519
520                                         if ( VideoOffset+width > 0xFFFF )
521                                         {
522                                                 for (i=0; i< width; i++ )
523                                                 {
524                                                         if (BitMask==0) {
525                                                                 bits = *fp++;
526                                                                 BitMask = 0x80;
527                                                         }
528
529                                                         if (bits & BitMask)
530                                                                 gr_video_memory[VideoOffset++] = FG_COLOR;
531                                                         else
532                                                                 gr_video_memory[VideoOffset++] = BG_COLOR;
533
534                                                         BitMask >>= 1;
535
536                                                         if (VideoOffset > 0xFFFF )
537                                                         {
538                                                                 VideoOffset -= 0xFFFF + 1;
539                                                                 page_switched = 1;
540                                                                 gr_vesa_incpage();
541                                                         }
542
543                                                 }
544                                         } else {
545
546                                                 if (width == 8 )
547                                                 {
548                                                         bits = *fp++;
549
550                                                         if (bits & 0x80) gr_video_memory[VideoOffset+0] = FG_COLOR;
551                                                         else gr_video_memory[VideoOffset+0] = BG_COLOR;
552
553                                                         if (bits & 0x40) gr_video_memory[VideoOffset+1] = FG_COLOR;
554                                                         else gr_video_memory[VideoOffset+1] = BG_COLOR;
555
556                                                         if (bits & 0x20) gr_video_memory[VideoOffset+2] = FG_COLOR;
557                                                         else gr_video_memory[VideoOffset+2] = BG_COLOR;
558
559                                                         if (bits & 0x10) gr_video_memory[VideoOffset+3] = FG_COLOR;
560                                                         else gr_video_memory[VideoOffset+3] = BG_COLOR;
561
562                                                         if (bits & 0x08) gr_video_memory[VideoOffset+4] = FG_COLOR;
563                                                         else gr_video_memory[VideoOffset+4] = BG_COLOR;
564
565                                                         if (bits & 0x04) gr_video_memory[VideoOffset+5] = FG_COLOR;
566                                                         else gr_video_memory[VideoOffset+5] = BG_COLOR;
567
568                                                         if (bits & 0x02) gr_video_memory[VideoOffset+6] = FG_COLOR;
569                                                         else gr_video_memory[VideoOffset+6] = BG_COLOR;
570
571                                                         if (bits & 0x01) gr_video_memory[VideoOffset+7] = FG_COLOR;
572                                                         else gr_video_memory[VideoOffset+7] = BG_COLOR;
573
574                                                         VideoOffset += 8;
575                                                 } else {
576                                                         for (i=0; i< width/2 ; i++ )
577                                                         {
578                                                                 if (BitMask==0) {
579                                                                         bits = *fp++;
580                                                                         BitMask = 0x80;
581                                                                 }
582
583                                                                 if (bits & BitMask)
584                                                                         gr_video_memory[VideoOffset++] = FG_COLOR;
585                                                                 else
586                                                                         gr_video_memory[VideoOffset++] = BG_COLOR;
587                                                                 BitMask >>= 1;
588
589
590                                                                 // Unroll twice
591
592                                                                 if (BitMask==0) {
593                                                                         bits = *fp++;
594                                                                         BitMask = 0x80;
595                                                                 }
596
597                                                                 if (bits & BitMask)
598                                                                         gr_video_memory[VideoOffset++] = FG_COLOR;
599                                                                 else
600                                                                         gr_video_memory[VideoOffset++] = BG_COLOR;
601                                                                 BitMask >>= 1;
602                                                         }
603                                                 }
604                                         }
605                                 }
606                                 text_ptr++;
607                         }
608
609                         y ++;
610                         VideoOffset1 += ROWSIZE;
611
612                         if (VideoOffset1 > 0xFFFF ) {
613                                 VideoOffset1 -= 0xFFFF + 1;
614                                 if (!page_switched)
615                                         gr_vesa_incpage();
616                         }
617                 }
618
619                 y += skip_lines;
620                 VideoOffset1 += ROWSIZE * skip_lines;
621                 skip_lines = 0;
622         }
623         return 0;
624 }
625
626 int gr_internal_string2m(int x, int y, char *s )
627 {
628         unsigned char * fp;
629         unsigned char * text_ptr, * next_row, * text_ptr1;
630         int r, BitMask, i, bits, width, spacing, letter, underline;
631         int page_switched, skip_lines = 0;
632
633         unsigned int VideoOffset, VideoOffset1;
634
635         VideoOffset1 = (size_t)DATA + y * ROWSIZE + x;
636
637         gr_vesa_setpage(VideoOffset1 >> 16);
638
639         VideoOffset1 &= 0xFFFF;
640
641         next_row = s;
642
643         while (next_row != NULL )
644         {
645                 text_ptr1 = next_row;
646                 next_row = NULL;
647
648                 if (x==0x8000) {                        //centered
649                         int xx = get_centered_x(text_ptr1);
650                         VideoOffset1 = y * ROWSIZE + xx;
651                         gr_vesa_setpage(VideoOffset1 >> 16);
652                         VideoOffset1 &= 0xFFFF;
653                 }
654
655                 for (r=0; r<FHEIGHT; r++)
656                 {
657                         text_ptr = text_ptr1;
658
659                         VideoOffset = VideoOffset1;
660
661                         page_switched = 0;
662
663                         while (*text_ptr)
664                         {
665                                 if (*text_ptr == '\n' )
666                                 {
667                                         next_row = &text_ptr[1];
668                                         break;
669                                 }
670
671                                 if (*text_ptr == CC_COLOR) {
672                                         FG_COLOR = *(text_ptr+1);
673                                         text_ptr += 2;
674                                         continue;
675                                 }
676
677                                 if (*text_ptr == CC_LSPACING) {
678                                         skip_lines = *(text_ptr+1) - '0';
679                                         text_ptr += 2;
680                                         continue;
681                                 }
682
683                                 underline = 0;
684                                 if (*text_ptr == CC_UNDERLINE )
685                                 {
686                                         if ((r==FBASELINE+2) || (r==FBASELINE+3))
687                                                 underline = 1;
688                                         text_ptr++;
689                                 }
690
691                                 get_char_width(text_ptr[0],text_ptr[1],&width,&spacing);
692
693                                 letter = *text_ptr-FMINCHAR;
694
695                                 if (!INFONT(letter)) {  //not in font, draw as space
696                                         VideoOffset += width;
697                                         text_ptr++;
698                                         continue;
699                                 }
700
701                                 if (FFLAGS & FT_PROPORTIONAL)
702                                         fp = FCHARS[letter];
703                                 else
704                                         fp = FDATA + letter * BITS_TO_BYTES(width)*FHEIGHT;
705
706                                 if (underline)
707                                 {
708                                         if ( VideoOffset+width > 0xFFFF )
709                                         {
710                                                 for (i=0; i< width; i++ )
711                                                 {
712                                                         gr_video_memory[VideoOffset++] = FG_COLOR;
713
714                                                         if (VideoOffset > 0xFFFF )
715                                                         {
716                                                                 VideoOffset -= 0xFFFF + 1;
717                                                                 page_switched = 1;
718                                                                 gr_vesa_incpage();
719                                                         }
720                                                 }
721                                         }
722                                         else
723                                         {
724                                                 for (i=0; i< width; i++ )
725                                                         gr_video_memory[VideoOffset++] = FG_COLOR;
726                                         }
727                                 }
728                                 else
729                                 {
730                                         fp += BITS_TO_BYTES(width)*r;
731
732                                         BitMask = 0;
733
734                                         if ( VideoOffset+width > 0xFFFF )
735                                         {
736                                                 for (i=0; i< width; i++ )
737                                                 {
738                                                         if (BitMask==0) {
739                                                                 bits = *fp++;
740                                                                 BitMask = 0x80;
741                                                         }
742
743                                                         if (bits & BitMask)
744                                                                 gr_video_memory[VideoOffset++] = FG_COLOR;
745                                                         else
746                                                                 VideoOffset++;
747
748                                                         BitMask >>= 1;
749
750                                                         if (VideoOffset > 0xFFFF )
751                                                         {
752                                                                 VideoOffset -= 0xFFFF + 1;
753                                                                 page_switched = 1;
754                                                                 gr_vesa_incpage();
755                                                         }
756
757                                                 }
758                                         } else {
759                                                 for (i=0; i< width; i++ )
760                                                 {
761                                                         if (BitMask==0) {
762                                                                 bits = *fp++;
763                                                                 BitMask = 0x80;
764                                                         }
765
766                                                         if (bits & BitMask)
767                                                                 gr_video_memory[VideoOffset++] = FG_COLOR;
768                                                         else
769                                                                 VideoOffset++;;
770                                                         BitMask >>= 1;
771                                                 }
772                                         }
773                                 }
774                                 text_ptr++;
775
776                                 VideoOffset += spacing-width;
777                         }
778
779                         y ++;
780                         VideoOffset1 += ROWSIZE;
781
782                         if (VideoOffset1 > 0xFFFF ) {
783                                 VideoOffset1 -= 0xFFFF + 1;
784                                 if (!page_switched)
785                                         gr_vesa_incpage();
786                         }
787                 }
788
789                 y += skip_lines;
790                 VideoOffset1 += ROWSIZE * skip_lines;
791                 skip_lines = 0;
792         }
793         return 0;
794 }
795
796 #endif // __MSDOS__
797
798 #ifndef OGL
799 //a bitmap for the character
800 grs_bitmap char_bm = {
801                                 0,0,0,0,                                                //x,y,w,h
802                                 BM_LINEAR,                                      //type
803                                 BM_FLAG_TRANSPARENT,            //flags
804                                 0,                                                              //rowsize
805                                 NULL,                                                   //data
806 #ifdef BITMAP_SELECTOR
807                                 0,                              //selector
808 #endif
809                                 0,     //avg_color
810                                 0      //unused
811 };
812
813 int gr_internal_color_string(int x, int y, char *s )
814 {
815         unsigned char * fp;
816         char *text_ptr, *next_row, *text_ptr1;
817         int width, spacing,letter;
818         int xx,yy;
819
820         char_bm.bm_h = FHEIGHT;         //set height for chars of this font
821
822         next_row = s;
823
824         yy = y;
825
826
827         while (next_row != NULL)
828         {
829                 text_ptr1 = next_row;
830                 next_row = NULL;
831
832                 text_ptr = text_ptr1;
833
834                 xx = x;
835
836                 if (xx==0x8000)                 //centered
837                         xx = get_centered_x(text_ptr);
838
839                 while (*text_ptr)
840                 {
841                         if (*text_ptr == '\n' )
842                         {
843                                 next_row = &text_ptr[1];
844                                 yy += FHEIGHT;
845                                 break;
846                         }
847
848                         letter = (unsigned char)*text_ptr - FMINCHAR;
849
850                         get_char_width(text_ptr[0],text_ptr[1],&width,&spacing);
851
852                         if (!INFONT(letter)) {  //not in font, draw as space
853                                 xx += spacing;
854                                 text_ptr++;
855                                 continue;
856                         }
857
858                         if (FFLAGS & FT_PROPORTIONAL)
859                                 fp = FCHARS[letter];
860                         else
861                                 fp = FDATA + letter * BITS_TO_BYTES(width)*FHEIGHT;
862
863                         gr_init_bitmap (&char_bm, BM_LINEAR, 0, 0, width, FHEIGHT, width, fp);
864                         gr_bitmapm(xx,yy,&char_bm);
865
866                         xx += spacing;
867
868                         text_ptr++;
869                 }
870
871         }
872         return 0;
873 }
874
875 #else //OGL
876
877 #include "ogl_init.h"
878 #include "args.h"
879 //font handling routines for OpenGL - Added 9/25/99 Matthew Mueller - they are here instead of in arch/ogl because they use all these defines
880
881 int pow2ize(int x);//from ogl.c
882
883 int get_font_total_width(grs_font * font){
884         if (font->ft_flags & FT_PROPORTIONAL){
885                 int i,w=0,c=font->ft_minchar;
886                 for (i=0;c<=font->ft_maxchar;i++,c++){
887                         if (font->ft_widths[i]<0)
888                                 Error("heh?\n");
889                         w+=font->ft_widths[i];
890                 }
891                 return w;
892         }else{
893                 return font->ft_w*(font->ft_maxchar-font->ft_minchar+1);
894         }
895 }
896 void ogl_font_choose_size(grs_font * font,int gap,int *rw,int *rh){
897         int     nchars = font->ft_maxchar-font->ft_minchar+1;
898         int r,x,y,nc=0,smallest=999999,smallr=-1,tries;
899         int smallprop=10000;
900         int h,w;
901         for (h=32;h<=256;h*=2){
902 //              h=pow2ize(font->ft_h*rows+gap*(rows-1));
903                 if (font->ft_h>h)continue;
904                 r=(h/(font->ft_h+gap));
905                 w=pow2ize((get_font_total_width(font)+(nchars-r)*gap)/r);
906                 tries=0;
907                 do {
908                         if (tries)
909                                 w=pow2ize(w+1);
910                         if(tries>3){
911                                 mprintf((0,"failed to fit (%ix%i, %ic)\n",w,h,nc));
912                                 break;
913                         }
914                         nc=0;
915                         y=0;
916                         while(y+font->ft_h<=h){
917                                 x=0;
918                                 while (x<w){
919                                         if (nc==nchars)
920                                                 break;
921                                         if (font->ft_flags & FT_PROPORTIONAL){
922                                                 if (x+font->ft_widths[nc]+gap>w)break;
923                                                 x+=font->ft_widths[nc++]+gap;
924                                         }else{
925                                                 if (x+font->ft_w+gap>w)break;
926                                                 x+=font->ft_w+gap;
927                                                 nc++;
928                                         }
929                                 }
930                                 if (nc==nchars)
931                                         break;
932                                 y+=font->ft_h+gap;
933                         }
934                         
935                         tries++;
936                 }while(nc!=nchars);
937                 if (nc!=nchars)
938                         continue;
939                 mprintf((0,"fit: %ix%i  %i tries\n",w,h,tries));
940
941                 if (w*h==smallest){//this gives squarer sizes priority (ie, 128x128 would be better than 512*32)
942                         if (w>=h){
943                                 if (w/h<smallprop){
944                                         smallprop=w/h;
945                                         smallest++;//hack
946                                 }
947                         }else{
948                                 if (h/w<smallprop){
949                                         smallprop=h/w;
950                                         smallest++;//hack
951                                 }
952                         }
953                 }
954                 if (w*h<smallest){
955                         smallr=1;
956                         smallest=w*h;
957                         *rw=w;
958                         *rh=h;
959                 }
960         }
961         if (smallr<=0)
962                 Error("couldn't fit font?\n");
963         mprintf((0,"using %ix%i\n",*rw,*rh));
964         
965 }
966
967 void ogl_init_font(grs_font * font){
968         int oglflags = OGL_FLAG_ALPHA;
969         int     nchars = font->ft_maxchar-font->ft_minchar+1;
970         int i,w,h,tw,th,x,y,curx=0,cury=0;
971         unsigned char *fp;
972         //      char data[32*32*4];
973         ubyte *data;
974         int gap=0;//having a gap just wastes ram, since we don't filter text textures at all.
975         //      char s[2];
976         ogl_font_choose_size(font,gap,&tw,&th);
977         data=d_malloc(tw*th);
978         memset(data, 0, tw * th);
979         gr_init_bitmap(&font->ft_parent_bitmap,BM_LINEAR,0,0,tw,th,tw,data);
980         gr_set_transparent(&font->ft_parent_bitmap, 1);
981
982         if (!(font->ft_flags & FT_COLOR))
983                 oglflags |= OGL_FLAG_NOCOLOR;
984         ogl_init_texture(font->ft_parent_bitmap.gltexture = ogl_get_free_texture(), tw, th, oglflags); // have to init the gltexture here so the subbitmaps will find it.
985
986         font->ft_bitmaps=(grs_bitmap*)d_malloc( nchars * sizeof(grs_bitmap));
987         mprintf((0,"ogl_init_font %s, %s, nchars=%i, (%ix%i tex)\n",(font->ft_flags & FT_PROPORTIONAL)?"proportional":"fixedwidth",(font->ft_flags & FT_COLOR)?"color":"mono",nchars,tw,th));
988         //      s[1]=0;
989         h=font->ft_h;
990         //      sleep(5);
991
992         for(i=0;i<nchars;i++){
993                 //              s[0]=font->ft_minchar+i;
994                 //              gr_get_string_size(s,&w,&h,&aw);
995                 if (font->ft_flags & FT_PROPORTIONAL)
996                         w=font->ft_widths[i];
997                 else
998                         w=font->ft_w;
999 //              mprintf((0,"char %i(%ix%i): ",i,w,h));
1000                 if (w<1 || w>256){
1001                         mprintf((0,"grr\n"));continue;
1002                 }
1003                 if (curx+w+gap>tw){
1004                         cury+=h+gap;
1005                         curx=0;
1006                 }
1007                 if (cury+h>th)
1008                         Error("font doesn't really fit (%i/%i)?\n",i,nchars);
1009                 if (font->ft_flags & FT_COLOR) {
1010                         if (font->ft_flags & FT_PROPORTIONAL)
1011                                 fp = font->ft_chars[i];
1012                         else
1013                                 fp = font->ft_data + i * w*h;
1014                         for (y=0;y<h;y++)
1015                                 for (x=0;x<w;x++){
1016                                         font->ft_parent_bitmap.bm_data[curx+x+(cury+y)*tw]=fp[x+y*w];
1017                                 }
1018
1019                         //                      gr_init_bitmap(&font->ft_bitmaps[i],BM_LINEAR,0,0,w,h,w,font->);
1020                 }else{
1021                         int BitMask,bits=0,white=gr_find_closest_color(63,63,63);
1022                         //                      if (w*h>sizeof(data))
1023                         //                              Error("ogl_init_font: toobig\n");
1024                         if (font->ft_flags & FT_PROPORTIONAL)
1025                                 fp = font->ft_chars[i];
1026                         else
1027                                 fp = font->ft_data + i * BITS_TO_BYTES(w)*h;
1028                         for (y=0;y<h;y++){
1029                                 BitMask=0;
1030                                 for (x=0; x< w; x++ )
1031                                 {
1032                                         if (BitMask==0) {
1033                                                 bits = *fp++;
1034                                                 BitMask = 0x80;
1035                                         }
1036
1037                                         if (bits & BitMask)
1038                                                 font->ft_parent_bitmap.bm_data[curx+x+(cury+y)*tw]=white;
1039                                         else
1040                                                 font->ft_parent_bitmap.bm_data[curx+x+(cury+y)*tw]=255;
1041                                         BitMask >>= 1;
1042                                 }
1043                         }
1044                 }
1045                 gr_init_sub_bitmap(&font->ft_bitmaps[i],&font->ft_parent_bitmap,curx,cury,w,h);
1046
1047                 curx+=w+gap;
1048         }
1049         ogl_loadbmtexture_f(&font->ft_parent_bitmap, oglflags);
1050 }
1051
1052 int ogl_internal_string(int x, int y, char *s )
1053 {
1054         char * text_ptr, * next_row, * text_ptr1;
1055         int width, spacing,letter;
1056         int xx,yy;
1057         int orig_color=FG_COLOR;//to allow easy reseting to default string color with colored strings -MPM
1058         int skip_lines = 0;
1059
1060         next_row = s;
1061
1062         yy = y;
1063
1064         if (grd_curscreen->sc_canvas.cv_bitmap.bm_type != BM_OGL)
1065                 Error("carp.\n");
1066         while (next_row != NULL)
1067         {
1068                 text_ptr1 = next_row;
1069                 next_row = NULL;
1070
1071                 text_ptr = text_ptr1;
1072
1073                 xx = x;
1074
1075                 if (xx==0x8000)                 //centered
1076                         xx = get_centered_x(text_ptr);
1077
1078                 while (*text_ptr)
1079                 {
1080                         if (*text_ptr == '\n' )
1081                         {
1082                                 next_row = &text_ptr[1];
1083                                 yy += FHEIGHT;
1084                                 break;
1085                         }
1086
1087                         if (*text_ptr == CC_LSPACING) {
1088                                 skip_lines = *(text_ptr+1) - '0';
1089                                 text_ptr += 2;
1090                                 continue;
1091                         }
1092
1093                         if (*text_ptr == CC_UNDERLINE ) {
1094                                 text_ptr++;
1095                                 continue;
1096                         }
1097
1098                         letter = (unsigned char)*text_ptr - FMINCHAR;
1099
1100                         get_char_width(text_ptr[0],text_ptr[1],&width,&spacing);
1101
1102                         if (!INFONT(letter) || (unsigned char)*text_ptr <= 0x06)
1103                         {   //not in font, draw as space
1104                                 CHECK_EMBEDDED_COLORS() else{
1105                                         xx += spacing;
1106                                         text_ptr++;
1107                                 }
1108                                 continue;
1109                         }
1110                         
1111 //                      ogl_ubitblt(FONT->ft_bitmaps[letter].bm_w,FONT->ft_bitmaps[letter].bm_h,xx,yy,0,0,&FONT->ft_bitmaps[letter],NULL);
1112 //                      if (*text_ptr>='0' && *text_ptr<='9'){
1113                         if (FFLAGS&FT_COLOR)
1114                                 gr_ubitmapm(xx,yy,&FONT->ft_bitmaps[letter]);
1115                         else{
1116                                 if (grd_curcanv->cv_bitmap.bm_type==BM_OGL)
1117                                         ogl_ubitmapm_c(xx,yy,&FONT->ft_bitmaps[letter],FG_COLOR);
1118                                 else
1119                                         Error("ogl_internal_string: non-color string to non-ogl dest\n");
1120 //                                      gr_ubitmapm(xx,yy,&FONT->ft_bitmaps[letter]);//ignores color..
1121                         }
1122                         //}
1123
1124                         xx += spacing;
1125
1126                         text_ptr++;
1127                 }
1128
1129                 yy += skip_lines;
1130                 skip_lines = 0;
1131         }
1132         return 0;
1133 }
1134
1135 int gr_internal_color_string(int x, int y, char *s ){
1136         return ogl_internal_string(x,y,s);
1137 }
1138 #endif //OGL
1139
1140 int gr_string(int x, int y, char *s )
1141 {
1142         int w, h, aw;
1143         int clipped=0;
1144
1145         Assert(FONT != NULL);
1146
1147         if ( x == 0x8000 )      {
1148                 if ( y<0 ) clipped |= 1;
1149                 gr_get_string_size(s, &w, &h, &aw );
1150                 // for x, since this will be centered, only look at
1151                 // width.
1152                 if ( w > grd_curcanv->cv_bitmap.bm_w ) clipped |= 1;
1153                 if ( (y+h) > grd_curcanv->cv_bitmap.bm_h ) clipped |= 1;
1154
1155                 if ( (y+h) < 0 ) clipped |= 2;
1156                 if ( y > grd_curcanv->cv_bitmap.bm_h ) clipped |= 2;
1157
1158         } else {
1159                 if ( (x<0) || (y<0) ) clipped |= 1;
1160                 gr_get_string_size(s, &w, &h, &aw );
1161                 if ( (x+w) > grd_curcanv->cv_bitmap.bm_w ) clipped |= 1;
1162                 if ( (y+h) > grd_curcanv->cv_bitmap.bm_h ) clipped |= 1;
1163                 if ( (x+w) < 0 ) clipped |= 2;
1164                 if ( (y+h) < 0 ) clipped |= 2;
1165                 if ( x > grd_curcanv->cv_bitmap.bm_w ) clipped |= 2;
1166                 if ( y > grd_curcanv->cv_bitmap.bm_h ) clipped |= 2;
1167         }
1168
1169         if ( !clipped )
1170                 return gr_ustring(x, y, s );
1171
1172         if ( clipped & 2 )      {
1173                 // Completely clipped...
1174                 mprintf( (1, "Text '%s' at (%d,%d) is off screen!\n", s, x, y ));
1175                 return 0;
1176         }
1177
1178         if ( clipped & 1 )      {
1179                 // Partially clipped...
1180                 //mprintf( (0, "Text '%s' at (%d,%d) is getting clipped!\n", s, x, y ));
1181         }
1182
1183         // Partially clipped...
1184 #ifdef OGL
1185         if (TYPE==BM_OGL)
1186                 return ogl_internal_string(x,y,s);
1187 #endif
1188
1189         if (FFLAGS & FT_COLOR)
1190                 return gr_internal_color_string( x, y, s);
1191
1192         if ( BG_COLOR == -1)
1193                 return gr_internal_string_clipped_m( x, y, s );
1194
1195         return gr_internal_string_clipped( x, y, s );
1196 }
1197
1198 int gr_ustring(int x, int y, char *s )
1199 {
1200 #ifdef OGL
1201         if (TYPE==BM_OGL)
1202                 return ogl_internal_string(x,y,s);
1203 #endif
1204         
1205         if (FFLAGS & FT_COLOR) {
1206
1207                 return gr_internal_color_string(x,y,s);
1208
1209         }
1210         else
1211                 switch( TYPE )
1212                 {
1213                 case BM_LINEAR:
1214                         if ( BG_COLOR == -1)
1215                                 return gr_internal_string0m(x,y,s);
1216                         else
1217                                 return gr_internal_string0(x,y,s);
1218 #ifdef __MSDOS__
1219                 case BM_SVGA:
1220                         if ( BG_COLOR == -1)
1221                                 return gr_internal_string2m(x,y,s);
1222                         else
1223                                 return gr_internal_string2(x,y,s);
1224 #endif // __MSDOS__
1225                 }
1226         return 0;
1227 }
1228
1229
1230 void gr_get_string_size(char *s, int *string_width, int *string_height, int *average_width )
1231 {
1232         int i = 0, longest_width = 0;
1233         int width,spacing;
1234
1235         *string_height = FHEIGHT;
1236         *string_width = 0;
1237         *average_width = FWIDTH;
1238
1239         if (s != NULL )
1240         {
1241                 *string_width = 0;
1242                 while (*s)
1243                 {
1244 //                      if (*s == CC_UNDERLINE)
1245 //                              s++;
1246                         while (*s == '\n')
1247                         {
1248                                 s++;
1249                                 *string_height += FHEIGHT;
1250                                 *string_width = 0;
1251                         }
1252
1253                         if (*s == 0) break;
1254
1255                         //      1 = next byte specifies color, so skip the 1 and the color value
1256                         if (*s == CC_COLOR)
1257                                 s += 2;
1258                         else if (*s == CC_LSPACING) {
1259                                 *string_height += *(s+1)-'0';
1260                                 s += 2;
1261                         } else {
1262                                 get_char_width(s[0],s[1],&width,&spacing);
1263
1264                                 *string_width += spacing;
1265
1266                                 if (*string_width > longest_width)
1267                                         longest_width = *string_width;
1268
1269                                 i++;
1270                                 s++;
1271                         }
1272                 }
1273         }
1274         *string_width = longest_width;
1275 }
1276
1277
1278 int gr_uprintf( int x, int y, char * format, ... )
1279 {
1280         char buffer[1000];
1281         va_list args;
1282
1283         va_start(args, format );
1284         vsprintf(buffer,format,args);
1285         return gr_ustring( x, y, buffer );
1286 }
1287
1288 int gr_printf( int x, int y, char * format, ... )
1289 {
1290         char buffer[1000];
1291         va_list args;
1292
1293         va_start(args, format );
1294         vsprintf(buffer,format,args);
1295         return gr_string( x, y, buffer );
1296 }
1297
1298 void gr_close_font( grs_font * font )
1299 {
1300         if (font)
1301         {
1302                 int fontnum;
1303                 char * font_data;
1304
1305                 //find font in list
1306                 for (fontnum=0;fontnum<MAX_OPEN_FONTS && open_font[fontnum].ptr!=font;fontnum++);
1307                 Assert(fontnum<MAX_OPEN_FONTS); //did we find slot?
1308
1309                 font_data = open_font[fontnum].dataptr;
1310                 d_free( font_data );
1311
1312                 open_font[fontnum].ptr = NULL;
1313                 open_font[fontnum].dataptr = NULL;
1314
1315                 if ( font->ft_chars )
1316                         d_free( font->ft_chars );
1317 #ifdef OGL
1318                 if (font->ft_bitmaps)
1319                         d_free( font->ft_bitmaps );
1320                 gr_free_bitmap_data(&font->ft_parent_bitmap);
1321 //              ogl_freebmtexture(&font->ft_parent_bitmap);
1322 #endif
1323                 d_free( font );
1324
1325
1326         }
1327 }
1328
1329 //remap (by re-reading) all the color fonts
1330 void gr_remap_color_fonts()
1331 {
1332         int fontnum;
1333
1334         for (fontnum=0;fontnum<MAX_OPEN_FONTS;fontnum++) {
1335                 grs_font *font;
1336
1337                 font = open_font[fontnum].ptr;
1338
1339                 if (font && (font->ft_flags & FT_COLOR))
1340                         gr_remap_font(font, open_font[fontnum].filename, open_font[fontnum].dataptr);
1341         }
1342 }
1343
1344 void gr_remap_mono_fonts()
1345 {
1346         int fontnum;
1347         con_printf (CON_DEBUG, "gr_remap_mono_fonts ()\n");
1348         for (fontnum=0;fontnum<MAX_OPEN_FONTS;fontnum++) {
1349                 grs_font *font;
1350                 font = open_font[fontnum].ptr;
1351                 if (font && !(font->ft_flags & FT_COLOR))
1352                         gr_remap_font(font, open_font[fontnum].filename, open_font[fontnum].dataptr);
1353         }
1354 }
1355
1356 #ifdef FAST_FILE_IO
1357 #define grs_font_read(gf, fp) cfread(gf, GRS_FONT_SIZE, 1, fp)
1358 #else
1359 /*
1360  * reads a grs_font structure from a CFILE
1361  */
1362 void grs_font_read(grs_font *gf, CFILE *fp)
1363 {
1364         gf->ft_w = cfile_read_short(fp);
1365         gf->ft_h = cfile_read_short(fp);
1366         gf->ft_flags = cfile_read_short(fp);
1367         gf->ft_baseline = cfile_read_short(fp);
1368         gf->ft_minchar = cfile_read_byte(fp);
1369         gf->ft_maxchar = cfile_read_byte(fp);
1370         gf->ft_bytewidth = cfile_read_short(fp);
1371         gf->ft_data = (ubyte *)cfile_read_int(fp);
1372         gf->ft_chars = (ubyte **)cfile_read_int(fp);
1373         gf->ft_widths = (short *)cfile_read_int(fp);
1374         gf->ft_kerndata = (ubyte *)cfile_read_int(fp);
1375 }
1376 #endif
1377
1378 grs_font * gr_init_font( char * fontname )
1379 {
1380         static int first_time=1;
1381         grs_font *font;
1382         char *font_data;
1383         int i,fontnum;
1384         unsigned char * ptr;
1385         int nchars;
1386         CFILE *fontfile;
1387         char file_id[4];
1388         int datasize;   //size up to (but not including) palette
1389
1390         if (first_time) {
1391                 int i;
1392                 for (i=0;i<MAX_OPEN_FONTS;i++)
1393                 {
1394                         open_font[i].ptr = NULL;
1395                         open_font[i].dataptr = NULL;
1396                 }
1397                 first_time=0;
1398         }
1399
1400         //find free font slot
1401         for (fontnum=0;fontnum<MAX_OPEN_FONTS && open_font[fontnum].ptr!=NULL;fontnum++);
1402         Assert(fontnum<MAX_OPEN_FONTS); //did we find one?
1403
1404         strncpy(open_font[fontnum].filename,fontname,FILENAME_LEN);
1405
1406         fontfile = cfopen(fontname, "rb");
1407
1408         if (!fontfile) {
1409                 con_printf(CON_VERBOSE, "Can't open font file %s\n", fontname);
1410                 return NULL;
1411         }
1412
1413         cfread(file_id, 4, 1, fontfile);
1414         if ( !strncmp( file_id, "NFSP", 4 ) ) {
1415                 con_printf(CON_NORMAL, "File %s is not a font file\n", fontname );
1416                 return NULL;
1417         }
1418
1419         datasize = cfile_read_int(fontfile);
1420         datasize -= GRS_FONT_SIZE; // subtract the size of the header.
1421
1422         MALLOC(font, grs_font, sizeof(grs_font));
1423         grs_font_read(font, fontfile);
1424
1425         MALLOC(font_data, char, datasize);
1426         cfread(font_data, 1, datasize, fontfile);
1427
1428         open_font[fontnum].ptr = font;
1429         open_font[fontnum].dataptr = font_data;
1430
1431         // make these offsets relative to font_data
1432         font->ft_data = (ubyte *)((int)font->ft_data - GRS_FONT_SIZE);
1433         font->ft_widths = (short *)((int)font->ft_widths - GRS_FONT_SIZE);
1434         font->ft_kerndata = (ubyte *)((int)font->ft_kerndata - GRS_FONT_SIZE);
1435
1436         nchars = font->ft_maxchar - font->ft_minchar + 1;
1437
1438         if (font->ft_flags & FT_PROPORTIONAL) {
1439
1440                 font->ft_widths = (short *) &font_data[(int)font->ft_widths];
1441                 font->ft_data = (unsigned char *) &font_data[(int)font->ft_data];
1442                 font->ft_chars = (unsigned char **)d_malloc( nchars * sizeof(unsigned char *));
1443
1444                 ptr = font->ft_data;
1445
1446                 for (i=0; i< nchars; i++ ) {
1447                         font->ft_widths[i] = INTEL_SHORT(font->ft_widths[i]);
1448                         font->ft_chars[i] = ptr;
1449                         if (font->ft_flags & FT_COLOR)
1450                                 ptr += font->ft_widths[i] * font->ft_h;
1451                         else
1452                                 ptr += BITS_TO_BYTES(font->ft_widths[i]) * font->ft_h;
1453                 }
1454
1455         } else  {
1456
1457                 font->ft_data   = (unsigned char *) font_data;
1458                 font->ft_chars  = NULL;
1459                 font->ft_widths = NULL;
1460
1461                 ptr = font->ft_data + (nchars * font->ft_w * font->ft_h);
1462         }
1463
1464         if (font->ft_flags & FT_KERNED)
1465                 font->ft_kerndata = (unsigned char *) &font_data[(int)font->ft_kerndata];
1466
1467         if (font->ft_flags & FT_COLOR) {                //remap palette
1468                 ubyte palette[256*3];
1469                 ubyte colormap[256];
1470                 int freq[256];
1471
1472                 cfread(palette,3,256,fontfile);         //read the palette
1473
1474 #ifdef SWAP_0_255                       // swap the first and last palette entries (black and white)
1475                 {
1476                         int i;
1477                         ubyte c;
1478
1479                         for (i = 0; i < 3; i++) {
1480                                 c = palette[i];
1481                                 palette[i] = palette[765+i];
1482                                 palette[765+i] = c;
1483                         }
1484
1485 //  we also need to swap the data entries as well.  black is white and white is black
1486
1487                         for (i = 0; i < ptr-font->ft_data; i++) {
1488                                 if (font->ft_data[i] == 0)
1489                                         font->ft_data[i] = 255;
1490                                 else if (font->ft_data[i] == 255)
1491                                         font->ft_data[i] = 0;
1492                         }
1493
1494                 }
1495 #endif
1496
1497                 build_colormap_good( (ubyte *)&palette, colormap, freq );
1498
1499                 colormap[TRANSPARENCY_COLOR] = TRANSPARENCY_COLOR;              // changed from colormap[255] = 255 to this for macintosh
1500
1501                 decode_data_asm(font->ft_data, ptr - font->ft_data, colormap, freq );
1502
1503         }
1504
1505         cfclose(fontfile);
1506
1507         //set curcanv vars
1508
1509         FONT        = font;
1510         FG_COLOR    = 0;
1511         BG_COLOR    = 0;
1512
1513         {
1514                 int x,y,aw;
1515                 char tests[]="abcdefghij1234.A";
1516                 gr_get_string_size(tests,&x,&y,&aw);
1517 //              newfont->ft_aw=x/(float)strlen(tests);
1518         }
1519
1520 #ifdef OGL
1521         ogl_init_font(font);
1522 #endif
1523
1524         return font;
1525
1526 }
1527
1528 //remap a font by re-reading its data & palette
1529 void gr_remap_font( grs_font *font, char * fontname, char *font_data )
1530 {
1531         int i;
1532         int nchars;
1533         CFILE *fontfile;
1534         char file_id[4];
1535         int datasize;        //size up to (but not including) palette
1536         unsigned char *ptr;
1537
1538         if (! (font->ft_flags & FT_COLOR))
1539                 return;
1540
1541         fontfile = cfopen(fontname, "rb");
1542
1543         if (!fontfile)
1544                 Error( "Can't open font file %s", fontname );
1545
1546         cfread(file_id, 4, 1, fontfile);
1547         if ( !strncmp( file_id, "NFSP", 4 ) )
1548                 Error( "File %s is not a font file", fontname );
1549
1550         datasize = cfile_read_int(fontfile);
1551         datasize -= GRS_FONT_SIZE; // subtract the size of the header.
1552
1553         d_free(font->ft_chars);
1554         grs_font_read(font, fontfile); // have to reread in case mission hogfile overrides font.
1555
1556         cfread(font_data, 1, datasize, fontfile);  //read raw data
1557
1558         // make these offsets relative to font_data
1559         font->ft_data = (ubyte *)((int)font->ft_data - GRS_FONT_SIZE);
1560         font->ft_widths = (short *)((int)font->ft_widths - GRS_FONT_SIZE);
1561         font->ft_kerndata = (ubyte *)((int)font->ft_kerndata - GRS_FONT_SIZE);
1562
1563         nchars = font->ft_maxchar - font->ft_minchar + 1;
1564
1565         if (font->ft_flags & FT_PROPORTIONAL) {
1566
1567                 font->ft_widths = (short *) &font_data[(int)font->ft_widths];
1568                 font->ft_data = (unsigned char *) &font_data[(int)font->ft_data];
1569                 font->ft_chars = (unsigned char **)d_malloc( nchars * sizeof(unsigned char *));
1570
1571                 ptr = font->ft_data;
1572
1573                 for (i=0; i< nchars; i++ ) {
1574                         font->ft_widths[i] = INTEL_SHORT(font->ft_widths[i]);
1575                         font->ft_chars[i] = ptr;
1576                         if (font->ft_flags & FT_COLOR)
1577                                 ptr += font->ft_widths[i] * font->ft_h;
1578                         else
1579                                 ptr += BITS_TO_BYTES(font->ft_widths[i]) * font->ft_h;
1580                 }
1581
1582         } else  {
1583
1584                 font->ft_data   = (unsigned char *) font_data;
1585                 font->ft_chars  = NULL;
1586                 font->ft_widths = NULL;
1587
1588                 ptr = font->ft_data + (nchars * font->ft_w * font->ft_h);
1589         }
1590
1591         if (font->ft_flags & FT_KERNED)
1592                 font->ft_kerndata = (unsigned char *) &font_data[(int)font->ft_kerndata];
1593
1594         if (font->ft_flags & FT_COLOR) {                //remap palette
1595                 ubyte palette[256*3];
1596                 ubyte colormap[256];
1597                 int freq[256];
1598
1599                 cfread(palette,3,256,fontfile);         //read the palette
1600
1601 #ifdef SWAP_0_255                       // swap the first and last palette entries (black and white)
1602                 {
1603                         int i;
1604                         ubyte c;
1605
1606                         for (i = 0; i < 3; i++) {
1607                                 c = palette[i];
1608                                 palette[i] = palette[765+i];
1609                                 palette[765+i] = c;
1610                         }
1611
1612 //  we also need to swap the data entries as well.  black is white and white is black
1613
1614                         for (i = 0; i < ptr-font->ft_data; i++) {
1615                                 if (font->ft_data[i] == 0)
1616                                         font->ft_data[i] = 255;
1617                                 else if (font->ft_data[i] == 255)
1618                                         font->ft_data[i] = 0;
1619                         }
1620
1621                 }
1622 #endif
1623
1624                 build_colormap_good( (ubyte *)&palette, colormap, freq );
1625
1626                 colormap[TRANSPARENCY_COLOR] = TRANSPARENCY_COLOR;              // changed from colormap[255] = 255 to this for macintosh
1627
1628                 decode_data_asm(font->ft_data, ptr - font->ft_data, colormap, freq );
1629
1630         }
1631
1632         cfclose(fontfile);
1633
1634 #ifdef OGL
1635         if (font->ft_bitmaps)
1636                 d_free( font->ft_bitmaps );
1637         gr_free_bitmap_data(&font->ft_parent_bitmap);
1638 //      ogl_freebmtexture(&font->ft_parent_bitmap);
1639
1640         ogl_init_font(font);
1641 #endif
1642 }
1643
1644
1645 void gr_set_fontcolor( int fg, int bg )
1646 {
1647         FG_COLOR    = fg;
1648         BG_COLOR    = bg;
1649 }
1650
1651 void gr_set_curfont( grs_font * new )
1652 {
1653         FONT = new;
1654 }
1655
1656
1657 int gr_internal_string_clipped(int x, int y, char *s )
1658 {
1659         unsigned char * fp;
1660         char * text_ptr, * next_row, * text_ptr1;
1661         int r, BitMask, i, bits, width, spacing, letter, underline;
1662         int x1 = x, last_x;
1663
1664         bits=0;
1665
1666         next_row = s;
1667
1668         while (next_row != NULL )
1669         {
1670                 text_ptr1 = next_row;
1671                 next_row = NULL;
1672
1673                 x = x1;
1674                 if (x==0x8000)                  //centered
1675                         x = get_centered_x(text_ptr1);
1676
1677                 last_x = x;
1678
1679                 for (r=0; r<FHEIGHT; r++)       {
1680                         text_ptr = text_ptr1;
1681                         x = last_x;
1682
1683                         while (*text_ptr)       {
1684                                 if (*text_ptr == '\n' ) {
1685                                         next_row = &text_ptr[1];
1686                                         break;
1687                                 }
1688
1689                                 if (*text_ptr == CC_COLOR) {
1690                                         FG_COLOR = *(text_ptr+1);
1691                                         text_ptr += 2;
1692                                         continue;
1693                                 }
1694
1695                                 if (*text_ptr == CC_LSPACING) {
1696                                         Int3(); //      Warning: skip lines not supported for clipped strings.
1697                                         text_ptr += 2;
1698                                         continue;
1699                                 }
1700
1701                                 underline = 0;
1702                                 if (*text_ptr == CC_UNDERLINE ) {
1703                                         if ((r==FBASELINE+2) || (r==FBASELINE+3))
1704                                                 underline = 1;
1705                                         text_ptr++;
1706                                 }
1707
1708                                 get_char_width(text_ptr[0],text_ptr[1],&width,&spacing);
1709
1710                                 letter = *text_ptr-FMINCHAR;
1711
1712                                 if (!INFONT(letter)) {  //not in font, draw as space
1713                                         x += spacing;
1714                                         text_ptr++;
1715                                         continue;
1716                                 }
1717
1718                                 if (FFLAGS & FT_PROPORTIONAL)
1719                                         fp = FCHARS[letter];
1720                                 else
1721                                         fp = FDATA + letter * BITS_TO_BYTES(width)*FHEIGHT;
1722
1723                                 if (underline)  {
1724                                         for (i=0; i< width; i++ )       {
1725                                                 gr_setcolor(FG_COLOR);
1726                                                 gr_pixel( x++, y );
1727                                         }
1728                                 } else {
1729                                         fp += BITS_TO_BYTES(width)*r;
1730
1731                                         BitMask = 0;
1732
1733                                         for (i=0; i< width; i++ )       {
1734                                                 if (BitMask==0) {
1735                                                         bits = *fp++;
1736                                                         BitMask = 0x80;
1737                                                 }
1738                                                 if (bits & BitMask)
1739                                                         gr_setcolor(FG_COLOR);
1740                                                 else
1741                                                         gr_setcolor(BG_COLOR);
1742                                                 gr_pixel( x++, y );
1743                                                 BitMask >>= 1;
1744                                         }
1745                                 }
1746
1747                                 x += spacing-width;             //for kerning
1748
1749                                 text_ptr++;
1750                         }
1751                         y++;
1752                 }
1753         }
1754         return 0;
1755 }
1756
1757 int gr_internal_string_clipped_m(int x, int y, char *s )
1758 {
1759         unsigned char * fp;
1760         char * text_ptr, * next_row, * text_ptr1;
1761         int r, BitMask, i, bits, width, spacing, letter, underline;
1762         int x1 = x, last_x;
1763
1764         bits=0;
1765
1766         next_row = s;
1767
1768         while (next_row != NULL )
1769         {
1770                 text_ptr1 = next_row;
1771                 next_row = NULL;
1772
1773                 x = x1;
1774                 if (x==0x8000)                  //centered
1775                         x = get_centered_x(text_ptr1);
1776
1777                 last_x = x;
1778
1779                 for (r=0; r<FHEIGHT; r++)       {
1780                         x = last_x;
1781
1782                         text_ptr = text_ptr1;
1783
1784                         while (*text_ptr)       {
1785                                 if (*text_ptr == '\n' ) {
1786                                         next_row = &text_ptr[1];
1787                                         break;
1788                                 }
1789
1790                                 if (*text_ptr == CC_COLOR) {
1791                                         FG_COLOR = *(text_ptr+1);
1792                                         text_ptr += 2;
1793                                         continue;
1794                                 }
1795
1796                                 if (*text_ptr == CC_LSPACING) {
1797                                         Int3(); //      Warning: skip lines not supported for clipped strings.
1798                                         text_ptr += 2;
1799                                         continue;
1800                                 }
1801
1802                                 underline = 0;
1803                                 if (*text_ptr == CC_UNDERLINE ) {
1804                                         if ((r==FBASELINE+2) || (r==FBASELINE+3))
1805                                                 underline = 1;
1806                                         text_ptr++;
1807                                 }
1808
1809                                 get_char_width(text_ptr[0],text_ptr[1],&width,&spacing);
1810
1811                                 letter = *text_ptr-FMINCHAR;
1812
1813                                 if (!INFONT(letter)) {  //not in font, draw as space
1814                                         x += spacing;
1815                                         text_ptr++;
1816                                         continue;
1817                                 }
1818
1819                                 if (FFLAGS & FT_PROPORTIONAL)
1820                                         fp = FCHARS[letter];
1821                                 else
1822                                         fp = FDATA + letter * BITS_TO_BYTES(width)*FHEIGHT;
1823
1824                                 if (underline)  {
1825                                         for (i=0; i< width; i++ )       {
1826                                                 gr_setcolor(FG_COLOR);
1827                                                 gr_pixel( x++, y );
1828                                         }
1829                                 } else {
1830                                         fp += BITS_TO_BYTES(width)*r;
1831
1832                                         BitMask = 0;
1833
1834                                         for (i=0; i< width; i++ )       {
1835                                                 if (BitMask==0) {
1836                                                         bits = *fp++;
1837                                                         BitMask = 0x80;
1838                                                 }
1839                                                 if (bits & BitMask)     {
1840                                                         gr_setcolor(FG_COLOR);
1841                                                         gr_pixel( x++, y );
1842                                                 } else {
1843                                                         x++;
1844                                                 }
1845                                                 BitMask >>= 1;
1846                                         }
1847                                 }
1848
1849                                 x += spacing-width;             //for kerning
1850
1851                                 text_ptr++;
1852                         }
1853                         y++;
1854                 }
1855         }
1856         return 0;
1857 }