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