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