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