amd64 fixes
[btb/d2x.git] / 2d / rle.c
1 /* $Id: rle.c,v 1.21 2005-08-02 06:15:08 chris 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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Routines to do run length encoding/decoding
18  * on bitmaps.
19  *
20  */
21
22
23 #ifdef HAVE_CONFIG_H
24 #include <conf.h>
25 #endif
26
27 #ifdef RCS
28 static char rcsid[] = "$Id: rle.c,v 1.21 2005-08-02 06:15:08 chris Exp $";
29 #endif
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include "pstypes.h"
36 #include "u_mem.h"
37 #include "mono.h"
38
39
40 #include "gr.h"
41 #include "grdef.h"
42 #include "error.h"
43 //#include "key.h"
44 #include "rle.h"
45 #include "byteswap.h"
46
47 #define RLE_CODE        0xE0
48 #define NOT_RLE_CODE    31
49
50 #define IS_RLE_CODE(x) (((x) & RLE_CODE) == RLE_CODE)
51
52 #if !defined(NO_ASM) && defined(__WATCOMC__)
53 #define RLE_DECODE_ASM
54
55 ubyte *gr_rle_decode_asm( ubyte * src, ubyte * dest );
56 #pragma aux gr_rle_decode_asm parm [esi] [edi] value [edi] modify exact [eax ebx ecx edx esi edi] = \
57 "  cld              " \
58 "   xor ecx, ecx    " \
59 "   cld             " \
60 "   jmp NextByte    " \
61 "                   " \
62 "Unique:            " \
63 "   mov [edi],al    " \
64 "   inc edi         " \
65 "                   " \
66 "NextByte:          " \
67 "   mov al,[esi]    " \
68 "   inc esi         " \
69 "                   " \
70 "   mov ah, al      " \
71 "   and ah, 0xE0    " \
72 "  cmp  ah, 0xE0    " \
73 "   jne   Unique    " \
74 "                   " \
75 "   mov cl, al      " \
76 "   and cl, 31      " \
77 "   je      done    " \
78 "                   " \
79 "   mov al,[esi]    " \
80 "   inc esi         " \
81 "   mov ah, al      " \
82 "   shr ecx,1       " \
83 "   rep stosw       " \
84 "   jnc NextByte    " \
85 "   mov [edi],al    " \
86 "   inc edi         " \
87 "                   " \
88 "   jmp NextByte    " \
89 "                   " \
90 "done:              ";
91
92 #elif !defined(NO_ASM) && defined(__GNUC__)
93 #define RLE_DECODE_ASM
94
95 static inline int gr_rle_decode_asm( ubyte * src, ubyte * dest ) {
96    register int __ret;
97    int dummy;
98    __asm__ __volatile__ (
99 "   cld;"
100 "   xorl %%ecx, %%ecx;"
101 "   jmp 1f;"
102 "0:;"
103 "   movb %%al,(%%edi);"
104 "   incl %%edi;"
105 "1:;"
106 "   movb (%%esi), %%al;"
107 "   incl %%esi;"
108 "   movb %%al, %%ah;"
109 "   andb $0xE0, %%ah;"
110 "   cmpb $0xE0, %%ah;"
111 "   jne 0b;"
112 "   movb %%al, %%cl;"
113 "   andb $31, %%cl;"
114 "   je 2f;"
115 "   movb (%%esi), %%al;"
116 "   incl %%esi;"
117 "   movb %%al, %%ah;"
118 "   shrl $1, %%ecx;"
119 "   rep; stosw;"
120 "   jnc 1b;"
121 "   movb %%al, (%%edi);"
122 "   incl %%edi;"
123 "   jmp 1b;"
124 "2:"
125 : "=D" (__ret), "=S" (dummy) : "1" (src), "D" (dest) : "%eax", "%ecx");
126   return __ret;
127 }
128
129 #elif !defined(NO_ASM) && defined(_MSC_VER)
130 #define RLE_DECODE_ASM
131
132 __inline int gr_rle_decode_asm( ubyte * src, ubyte * dest )
133 {
134          int retval;
135         __asm {
136                 mov esi,[src]
137                 mov edi,[dest]
138         xor ecx, ecx
139                 cld
140                 jmp NextByte
141 Unique:
142                 mov [edi], al
143                 inc edi
144 NextByte:
145                 mov al,[esi]
146                 inc esi
147                 mov ah, al
148                 and ah,0xE0
149                 cmp ah,0xE0
150                 jne Unique
151
152                 mov cl, al
153                 and cl, 31
154                 je done
155
156                 mov al, [esi]
157                 inc esi
158                 mov ah, al
159                 shr ecx, 1
160                 rep stosw
161                 jnc NextByte
162                 mov [edi], al
163                 inc edi
164                 jmp NextByte
165 done:
166                 mov [retval],edi
167         }
168         return retval;
169 }
170
171 #endif
172
173 #ifdef RLE_DECODE_ASM
174
175 #if 0
176 void gr_rle_decode( ubyte * src, ubyte * dest, int dest_len )
177 {
178         ubyte *dest_end;
179
180         dest_end = (ubyte *)gr_rle_decode_asm( src, dest );
181
182         Assert(dest_end-src < dest_len);
183 }
184 #else
185 void gr_rle_decode( ubyte * src, ubyte * dest )
186 {
187     gr_rle_decode_asm( src, dest );
188 }
189 #endif
190
191 #else // NO_ASM or unknown compiler
192
193 void gr_rle_decode( ubyte * src, ubyte * dest )
194 {
195         int i;
196         ubyte data, count = 0;
197
198         while(1) {
199                 data = *src++;
200                 if ( ! IS_RLE_CODE(data) ) {
201                         *dest++ = data;
202                 } else {
203                         count = data & NOT_RLE_CODE;
204                         if (count == 0)
205                                 return;
206                         data = *src++;
207                         for (i = 0; i < count; i++)
208                                 *dest++ = data;
209                 }
210         }
211 }
212
213 #endif
214
215 void rle_stosb (unsigned char *dest, int len, int color);
216
217 #if !defined(NO_ASM) && defined(__WATCOMC__)
218
219 #pragma aux rle_stosb = "cld rep    stosb" parm [edi] [ecx] [eax] modify exact [edi ecx];
220
221 #elif !defined(NO_ASM) && defined(__GNUC__)
222
223 inline void rle_stosb (unsigned char *dest, int len, int color) {
224         int dummy[2];
225    __asm__ __volatile__ (
226     "cld; rep; stosb"
227     : "=D" (dummy[0]), "=c" (dummy[1])
228         : "0" (dest), "1" (len), "a" (color) );
229 }
230
231 #elif !defined(NO_ASM) && defined(_MSC_VER)
232
233 __inline void rle_stosb (unsigned char *dest, int len, int color)
234 {
235   __asm {
236         mov edi,[dest]
237         mov ecx,[len]
238         mov eax,[color]
239         cld
240         rep stosb
241   }
242 }
243
244 #else // NO_ASM or unknown compiler
245
246 void rle_stosb (unsigned char *dest, int len, int color)
247 {
248         int i;
249         for (i=0; i<len; i++ )
250                 *dest++ = color;
251 }
252
253 #endif
254
255 // Given pointer to start of one scanline of rle data, uncompress it to
256 // dest, from source pixels x1 to x2.
257 void gr_rle_expand_scanline_masked( ubyte *dest, ubyte *src, int x1, int x2  )
258 {
259         int i = 0;
260         ubyte count;
261         ubyte color=0;
262
263         if ( x2 < x1 ) return;
264
265         count = 0;
266         while ( i < x1 )        {
267                 color = *src++;
268                 if ( color == RLE_CODE ) return;
269                 if ( IS_RLE_CODE(color) )       {
270                         count = color & (~RLE_CODE);
271                         color = *src++;
272                 } else {
273                         // unique
274                         count = 1;
275                 }
276                 i += count;
277         }
278         count = i - x1;
279         i = x1;
280         // we know have '*count' pixels of 'color'.
281         
282         if ( x1+count > x2 )    {
283                 count = x2-x1+1;
284                 if ( color != TRANSPARENCY_COLOR )      rle_stosb( dest, count, color );
285                 return;
286         }
287
288         if ( color != TRANSPARENCY_COLOR )      rle_stosb( dest, count, color );
289         dest += count;
290         i += count;
291
292         while( i <= x2 )                {
293                 color = *src++;
294                 if ( color == RLE_CODE ) return;
295                 if ( IS_RLE_CODE(color) )       {
296                         count = color & (~RLE_CODE);
297                         color = *src++;
298                 } else {
299                         // unique
300                         count = 1;
301                 }
302                 // we know have '*count' pixels of 'color'.
303                 if ( i+count <= x2 )    {
304                         if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
305                         i += count;
306                         dest += count;
307                 } else {
308                         count = x2-i+1;
309                         if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
310                         i += count;
311                         dest += count;
312                 }
313
314         }       
315 }
316
317 void gr_rle_expand_scanline( ubyte *dest, ubyte *src, int x1, int x2  )
318 {
319         int i = 0;
320         ubyte count;
321         ubyte color=0;
322
323         if ( x2 < x1 ) return;
324
325         count = 0;
326         while ( i < x1 )        {
327                 color = *src++;
328                 if ( color == RLE_CODE ) return;
329                 if ( IS_RLE_CODE(color) )       {
330                         count = color & (~RLE_CODE);
331                         color = *src++;
332                 } else {
333                         // unique
334                         count = 1;
335                 }
336                 i += count;
337         }
338         count = i - x1;
339         i = x1;
340         // we know have '*count' pixels of 'color'.
341         
342         if ( x1+count > x2 )    {
343                 count = x2-x1+1;
344                 rle_stosb( dest, count, color );
345                 return;
346         }
347
348         rle_stosb( dest, count, color );
349         dest += count;
350         i += count;
351
352         while( i <= x2 )                {
353                 color = *src++;
354                 if ( color == RLE_CODE ) return;
355                 if ( IS_RLE_CODE(color) )       {
356                         count = color & (~RLE_CODE);
357                         color = *src++;
358                 } else {
359                         // unique
360                         count = 1;
361                 }
362                 // we know have '*count' pixels of 'color'.
363                 if ( i+count <= x2 )    {
364                         rle_stosb( dest, count, color );
365                         i += count;
366                         dest += count;
367                 } else {
368                         count = x2-i+1;
369                         rle_stosb( dest, count, color );
370                         i += count;
371                         dest += count;
372                 }
373         }
374 }
375
376
377 int gr_rle_encode( int org_size, ubyte *src, ubyte *dest )
378 {
379         int i;
380         ubyte c, oc;
381         ubyte count;
382         ubyte *dest_start;
383
384         dest_start = dest;
385         oc = *src++;
386         count = 1;
387
388         for (i=1; i<org_size; i++ )     {
389                 c = *src++;
390                 if ( c!=oc )    {
391                         if ( count )    {
392                                 if ( (count==1) && (! IS_RLE_CODE(oc)) )        {
393                                         *dest++ = oc;
394                                         Assert( oc != RLE_CODE );
395                                 } else {
396                                         count |= RLE_CODE;
397                                         *dest++ = count;
398                                         *dest++ = oc;
399                                 }
400                         }
401                         oc = c;
402                         count = 0;
403                 }
404                 count++;
405                 if ( count == NOT_RLE_CODE )    {
406                         count |= RLE_CODE;
407                         *dest++=count;
408                         *dest++=oc;
409                         count = 0;
410                 }
411         }
412         if (count)      {
413                 if ( (count==1) && (! IS_RLE_CODE(oc)) )        {
414                         *dest++ = oc;
415                         Assert( oc != RLE_CODE );
416                 } else {
417                         count |= RLE_CODE;
418                         *dest++ = count;
419                         *dest++ = oc;
420                 }
421         }
422         *dest++ = RLE_CODE;
423
424         return dest-dest_start;
425 }
426
427
428 int gr_rle_getsize( int org_size, ubyte *src )
429 {
430         int i;
431         ubyte c, oc;
432         ubyte count;
433         int dest_size=0;
434
435         oc = *src++;
436         count = 1;
437
438         for (i=1; i<org_size; i++ )     {
439                 c = *src++;
440                 if ( c!=oc )    {
441                         if ( count )    {
442                                 if ( (count==1) && (! IS_RLE_CODE(oc)) )        {
443                                         dest_size++;
444                                 } else {
445                                         dest_size++;
446                                         dest_size++;
447                                 }
448                         }
449                         oc = c;
450                         count = 0;
451                 }
452                 count++;
453                 if ( count == NOT_RLE_CODE )    {
454                         dest_size++;
455                         dest_size++;
456                         count = 0;
457                 }
458         }
459         if (count)      {
460                 if ( (count==1) && (! IS_RLE_CODE(oc)) )        {
461                         dest_size++;
462                 } else {
463                         dest_size++;
464                         dest_size++;
465                 }
466         }
467         dest_size++;
468
469         return dest_size;
470 }
471
472 int gr_bitmap_rle_compress( grs_bitmap * bmp )
473 {
474         int y, d1, d;
475         int doffset;
476         ubyte *rle_data;
477         int large_rle = 0;
478
479         // first must check to see if this is large bitmap.
480
481         for (y=0; y<bmp->bm_h; y++ )    {
482                 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
483                 if (d1 > 255) {
484                         large_rle = 1;
485                         break;
486                 }
487         }
488
489         rle_data=d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) );
490         if (rle_data==NULL) return 0;
491         if (!large_rle)
492                 doffset = 4 + bmp->bm_h;
493         else
494                 doffset = 4 + (2 * bmp->bm_h);          // each row of rle'd bitmap has short instead of byte offset now
495
496         for (y=0; y<bmp->bm_h; y++ )    {
497                 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
498                 if ( ((doffset+d1) > bmp->bm_w*bmp->bm_h) || (d1 > (large_rle?32767:255) ) ) {
499                         d_free(rle_data);
500                         return 0;
501                 }
502                 d = gr_rle_encode( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y], &rle_data[doffset] );
503                 Assert( d==d1 );
504                 doffset += d;
505                 if (large_rle)
506                         *((short *)&(rle_data[(y*2)+4])) = (short)d;
507                 else
508                         rle_data[y+4] = d;
509         }
510         //mprintf( 0, "Bitmap of size %dx%d, (%d bytes) went down to %d bytes\n", bmp->bm_w, bmp->bm_h, bmp->bm_h*bmp->bm_w, doffset );
511         memcpy(         rle_data, &doffset, 4 );
512         memcpy(         bmp->bm_data, rle_data, doffset );
513         d_free(rle_data);
514         bmp->bm_flags |= BM_FLAG_RLE;
515         if (large_rle)
516                 bmp->bm_flags |= BM_FLAG_RLE_BIG;
517         return 1;
518 }
519
520 #define MAX_CACHE_BITMAPS 32
521
522 typedef struct rle_cache_element {
523         grs_bitmap * rle_bitmap;
524         ubyte * rle_data;
525         grs_bitmap * expanded_bitmap;
526         int last_used;
527 } rle_cache_element;
528
529 int rle_cache_initialized = 0;
530 int rle_counter = 0;
531 int rle_next = 0;
532 rle_cache_element rle_cache[MAX_CACHE_BITMAPS];
533
534 int rle_hits = 0;
535 int rle_misses = 0;
536
537 void rle_cache_close(void)
538 {
539         if (rle_cache_initialized)      {
540                 int i;
541                 rle_cache_initialized = 0;
542                 for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
543                         gr_free_bitmap(rle_cache[i].expanded_bitmap);
544                 }
545         }
546 }
547
548 void rle_cache_init()
549 {
550         int i;
551         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
552                 rle_cache[i].rle_bitmap = NULL;
553                 rle_cache[i].expanded_bitmap = gr_create_bitmap( 64, 64 );
554                 rle_cache[i].last_used = 0;
555                 Assert( rle_cache[i].expanded_bitmap != NULL );
556         }
557         rle_cache_initialized = 1;
558         atexit( rle_cache_close );
559 }
560
561 void rle_cache_flush()
562 {
563         int i;
564         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
565                 rle_cache[i].rle_bitmap = NULL;
566                 rle_cache[i].last_used = 0;
567         }
568 }
569
570 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 )
571 {
572         unsigned char * dbits;
573         unsigned char * sbits;
574         int i;
575 #ifdef RLE_DECODE_ASM
576         unsigned char * dbits1;
577 #endif
578
579         sbits = &bmp->bm_data[4 + bmp->bm_h];
580         dbits = rle_temp_bitmap_1->bm_data;
581
582         rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE);
583
584         for (i=0; i < bmp->bm_h; i++ )    {
585 #ifdef RLE_DECODE_ASM
586                 dbits1=(unsigned char *)gr_rle_decode_asm( sbits, dbits );
587 #else
588                 gr_rle_decode( sbits, dbits );
589 #endif
590                 sbits += (int)bmp->bm_data[4+i];
591                 dbits += bmp->bm_w;
592 #ifdef RLE_DECODE_ASM
593                 Assert( dbits == dbits1 );              // Get John, bogus rle data!
594 #endif
595         }
596 }
597
598
599 grs_bitmap * rle_expand_texture( grs_bitmap * bmp )
600 {
601         int i;
602         int lowest_count, lc;
603         int least_recently_used;
604
605         if (!rle_cache_initialized) rle_cache_init();
606
607         Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) );
608
609         lc = rle_counter;
610         rle_counter++;
611         if ( rle_counter < lc ) {
612                 for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
613                         rle_cache[i].rle_bitmap = NULL;
614                         rle_cache[i].last_used = 0;
615                 }
616         }
617
618 //      if (((rle_counter % 100)==1) && (rle_hits+rle_misses > 0))
619 //              mprintf(( 0, "RLE-CACHE %d%%, H:%d, M:%d\n", (rle_misses*100)/(rle_hits+rle_misses), rle_hits, rle_misses ));
620
621         lowest_count = rle_cache[rle_next].last_used;
622         least_recently_used = rle_next;
623         rle_next++;
624         if ( rle_next >= MAX_CACHE_BITMAPS )
625                 rle_next = 0;
626
627         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
628                 if (rle_cache[i].rle_bitmap == bmp)     {
629                         rle_hits++;
630                         rle_cache[i].last_used = rle_counter;
631                         return rle_cache[i].expanded_bitmap;
632                 }
633                 if ( rle_cache[i].last_used < lowest_count )    {
634                         lowest_count = rle_cache[i].last_used;
635                         least_recently_used = i;
636                 }
637         }
638
639         Assert(bmp->bm_w<=64 && bmp->bm_h<=64); //dest buffer is 64x64
640         rle_misses++;
641         rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap );
642         rle_cache[least_recently_used].rle_bitmap = bmp;
643         rle_cache[least_recently_used].last_used = rle_counter;
644         return rle_cache[least_recently_used].expanded_bitmap;
645 }
646
647
648 void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 )
649 {
650         int i = 0, j;
651         int count;
652         ubyte color=0;
653
654         if ( x2 < x1 ) return;
655
656         count = 0;
657         while ( i < x1 )        {
658                 color = *src++;
659                 if ( color == RLE_CODE ) return;
660                 if ( IS_RLE_CODE(color) )       {
661                         count = color & NOT_RLE_CODE;
662                         color = *src++;
663                 } else {
664                         // unique
665                         count = 1;
666                 }
667                 i += count;
668         }
669         count = i - x1;
670         i = x1;
671         // we know have '*count' pixels of 'color'.
672
673         if ( x1+count > x2 )    {
674                 count = x2-x1+1;
675                 for ( j=0; j<count; j++ )
676                         gr_bm_pixel( dest, dx++, dy, color );
677                 return;
678         }
679
680         for ( j=0; j<count; j++ )
681                 gr_bm_pixel( dest, dx++, dy, color );
682         i += count;
683
684         while( i <= x2 )                {
685                 color = *src++;
686                 if ( color == RLE_CODE ) return;
687                 if ( IS_RLE_CODE(color) )       {
688                         count = color & NOT_RLE_CODE;
689                         color = *src++;
690                 } else {
691                         // unique
692                         count = 1;
693                 }
694                 // we know have '*count' pixels of 'color'.
695                 if ( i+count <= x2 )    {
696                         for ( j=0; j<count; j++ )
697                                 gr_bm_pixel( dest, dx++, dy, color );
698                         i += count;
699                 } else {
700                         count = x2-i+1;
701                         for ( j=0; j<count; j++ )
702                                 gr_bm_pixel( dest, dx++, dy, color );
703                         i += count;
704                 }
705         }
706 }
707
708 void gr_rle_expand_scanline_generic_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2  )
709 {
710         int i = 0, j;
711         int count;
712         ubyte color = 0;
713
714         if ( x2 < x1 ) return;
715
716         count = 0;
717         while ( i < x1 )        {
718                 color = *src++;
719                 if ( color == RLE_CODE ) return;
720                 if ( IS_RLE_CODE(color) )       {
721                         count = color & NOT_RLE_CODE;
722                         color = *src++;
723                 } else {
724                         // unique
725                         count = 1;
726                 }
727                 i += count;
728         }
729         count = i - x1;
730         i = x1;
731         // we know have '*count' pixels of 'color'.
732
733         if ( x1+count > x2 )    {
734                 count = x2-x1+1;
735                 if (color != TRANSPARENCY_COLOR) {
736                         for ( j=0; j<count; j++ )
737                                 gr_bm_pixel( dest, dx++, dy, color );
738                 }
739                 return;
740         }
741
742         if ( color != TRANSPARENCY_COLOR ) {
743                 for ( j=0; j<count; j++ )
744                         gr_bm_pixel( dest, dx++, dy, color );
745         } else
746                 dx += count;
747         i += count;
748
749         while( i <= x2 )                {
750                 color = *src++;
751                 if ( color == RLE_CODE ) return;
752                 if ( IS_RLE_CODE(color) )       {
753                         count = color & NOT_RLE_CODE;
754                         color = *src++;
755                 } else {
756                         // unique
757                         count = 1;
758                 }
759                 // we know have '*count' pixels of 'color'.
760                 if ( i+count <= x2 )    {
761                         if ( color != TRANSPARENCY_COLOR ) {
762                                 for ( j=0; j<count; j++ )
763                                         gr_bm_pixel( dest, dx++, dy, color );
764                         } else
765                                 dx += count;
766                         i += count;
767                 } else {
768                         count = x2-i+1;
769                         if ( color != TRANSPARENCY_COLOR ) {
770                                 for ( j=0; j<count; j++ )
771                                         gr_bm_pixel( dest, dx++, dy, color );
772                         } else
773                                 dx += count;
774                         i += count;
775                 }
776         }
777 }
778
779
780 #ifdef __MSDOS__
781 void gr_rle_expand_scanline_svga_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2  )
782 {
783         int i = 0, j;
784         int count;
785         ubyte color;
786         ubyte * vram = (ubyte *)0xA0000;
787         int VideoLocation,page,offset;
788
789         if ( x2 < x1 ) return;
790
791         VideoLocation = (unsigned int)dest->bm_data + (dest->bm_rowsize * dy) + dx;
792         page    = VideoLocation >> 16;
793         offset  = VideoLocation & 0xFFFF;
794
795         gr_vesa_setpage( page );
796
797         if ( (offset + (x2-x1+1)) < 65536 )     {
798                 // We don't cross a svga page, so blit it fast!
799                 gr_rle_expand_scanline_masked( &vram[offset], src, x1, x2 );
800                 return;
801         }
802
803         count = 0;
804         while ( i < x1 )        {
805                 color = *src++;
806                 if ( color == RLE_CODE ) return;
807                 if ( IS_RLE_CODE(color) )       {
808                         count = color & NOT_RLE_CODE;
809                         color = *src++;
810                 } else {
811                         // unique
812                         count = 1;
813                 }
814                 i += count;
815         }
816         count = i - x1;
817         i = x1;
818         // we know have '*count' pixels of 'color'.
819
820         if ( x1+count > x2 )    {
821                 count = x2-x1+1;
822                 if (color != TRANSPARENCY_COLOR) {
823                         for ( j=0; j<count; j++ )       {
824                                 vram[offset++] = color;
825                                 if ( offset >= 65536 ) {
826                                         offset -= 65536;
827                                         page++;
828                                         gr_vesa_setpage(page);
829                                 }
830                         }
831                 }
832                 return;
833         }
834
835         if ( color != TRANSPARENCY_COLOR ) {
836                 for ( j=0; j<count; j++ )       {
837                         vram[offset++] = color;
838                         if ( offset >= 65536 ) {
839                                 offset -= 65536;
840                                 page++;
841                                 gr_vesa_setpage(page);
842                         }
843                 }
844         } else  {
845                 offset += count;
846                 if ( offset >= 65536 ) {
847                         offset -= 65536;
848                         page++;
849                         gr_vesa_setpage(page);
850                 }
851         }
852         i += count;
853
854         while( i <= x2 )                {
855                 color = *src++;
856                 if ( color == RLE_CODE ) return;
857                 if ( IS_RLE_CODE(color) )       {
858                         count = color & NOT_RLE_CODE;
859                         color = *src++;
860                 } else {
861                         // unique
862                         count = 1;
863                 }
864                 // we know have '*count' pixels of 'color'.
865                 if ( i+count <= x2 )    {
866                         if ( color != TRANSPARENCY_COLOR ) {
867                                 for ( j=0; j<count; j++ )       {
868                                         vram[offset++] = color;
869                                         if ( offset >= 65536 ) {
870                                                 offset -= 65536;
871                                                 page++;
872                                                 gr_vesa_setpage(page);
873                                         }
874                                 }
875                         } else  {
876                                 offset += count;
877                                 if ( offset >= 65536 ) {
878                                         offset -= 65536;
879                                         page++;
880                                         gr_vesa_setpage(page);
881                                 }
882                         }
883                         i += count;
884                 } else {
885                         count = x2-i+1;
886                         if ( color != TRANSPARENCY_COLOR ) {
887                                 for ( j=0; j<count; j++ )       {
888                                         vram[offset++] = color;
889                                         if ( offset >= 65536 ) {
890                                                 offset -= 65536;
891                                                 page++;
892                                                 gr_vesa_setpage(page);
893                                         }
894                                 }
895                         } else  {
896                                 offset += count;
897                                 if ( offset >= 65536 ) {
898                                         offset -= 65536;
899                                         page++;
900                                         gr_vesa_setpage(page);
901                                 }
902                         }
903                         i += count;
904                 }
905         }
906 }
907 #endif // __MSDOS__
908
909
910 /*
911  * swaps entries 0 and 255 in an RLE bitmap without uncompressing it
912  */
913 void rle_swap_0_255(grs_bitmap *bmp)
914 {
915         int i, j, len, rle_big;
916         unsigned char *ptr, *ptr2, *temp, *start;
917         unsigned short line_size;
918
919         rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG;
920
921         temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) );
922
923         if (rle_big) {                  // set ptrs to first lines
924                 ptr = bmp->bm_data + 4 + 2 * bmp->bm_h;
925                 ptr2 = temp + 4 + 2 * bmp->bm_h;
926         } else {
927                 ptr = bmp->bm_data + 4 + bmp->bm_h;
928                 ptr2 = temp + 4 + bmp->bm_h;
929         }
930         for (i = 0; i < bmp->bm_h; i++) {
931                 start = ptr2;
932                 if (rle_big)
933                         line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i]));
934                 else
935                         line_size = bmp->bm_data[4 + i];
936                 for (j = 0; j < line_size; j++) {
937                         if ( ! IS_RLE_CODE(ptr[j]) ) {
938                                 if (ptr[j] == 0) {
939                                         *ptr2++ = RLE_CODE | 1;
940                                         *ptr2++ = 255;
941                                 } else
942                                         *ptr2++ = ptr[j];
943                         } else {
944                                 *ptr2++ = ptr[j];
945                                 if ((ptr[j] & NOT_RLE_CODE) == 0)
946                                         break;
947                                 j++;
948                                 if (ptr[j] == 0)
949                                         *ptr2++ = 255;
950                                 else if (ptr[j] == 255)
951                                         *ptr2++ = 0;
952                                 else
953                                         *ptr2++ = ptr[j];
954                         }
955                 }
956                 if (rle_big)                // set line size
957                         *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start);
958                 else
959                         temp[4 + i] = ptr2 - start;
960                 ptr += line_size;           // go to next line
961         }
962         len = ptr2 - temp;
963         *((int *)temp) = len;           // set total size
964         memcpy(bmp->bm_data, temp, len);
965         d_free(temp);
966 }
967
968 /*
969  * remaps all entries using colormap in an RLE bitmap without uncompressing it
970  */
971 void rle_remap(grs_bitmap *bmp, ubyte *colormap)
972 {
973         int i, j, len, rle_big;
974         unsigned char *ptr, *ptr2, *temp, *start;
975         unsigned short line_size;
976
977         rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG;
978
979         temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) + 30000 );
980
981         if (rle_big) {                  // set ptrs to first lines
982                 ptr = bmp->bm_data + 4 + 2 * bmp->bm_h;
983                 ptr2 = temp + 4 + 2 * bmp->bm_h;
984         } else {
985                 ptr = bmp->bm_data + 4 + bmp->bm_h;
986                 ptr2 = temp + 4 + bmp->bm_h;
987         }
988         for (i = 0; i < bmp->bm_h; i++) {
989                 start = ptr2;
990                 if (rle_big)
991                         line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i]));
992                 else
993                         line_size = bmp->bm_data[4 + i];
994                 for (j = 0; j < line_size; j++) {
995                         if ( ! IS_RLE_CODE(ptr[j])) {
996                                 if (IS_RLE_CODE(colormap[ptr[j]])) 
997                                         *ptr2++ = RLE_CODE | 1; // add "escape sequence"
998                                 *ptr2++ = colormap[ptr[j]]; // translate
999                         } else {
1000                                 *ptr2++ = ptr[j]; // just copy current rle code
1001                                 if ((ptr[j] & NOT_RLE_CODE) == 0)
1002                                         break;
1003                                 j++;
1004                                 *ptr2++ = colormap[ptr[j]]; // translate
1005                         }
1006                 }
1007                 if (rle_big)                // set line size
1008                         *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start);
1009                 else
1010                         temp[4 + i] = ptr2 - start;
1011                 ptr += line_size;           // go to next line
1012         }
1013         len = ptr2 - temp;
1014         *((int *)temp) = len;           // set total size
1015         memcpy(bmp->bm_data, temp, len);
1016         d_free(temp);
1017 }