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