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