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