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