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