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