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