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