]> icculus.org git repositories - btb/d2x.git/blob - 2d/rle.c
move old per-file change logs into new file ChangeLog-old
[btb/d2x.git] / 2d / rle.c
1 /* $Id: rle.c,v 1.19 2004-08-28 23:17:45 schaffner 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.19 2004-08-28 23:17:45 schaffner 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 #ifdef D1XD3D
580         Assert (bmp->iMagic == BM_MAGIC_NUMBER);
581 #endif
582
583         sbits = &bmp->bm_data[4 + bmp->bm_h];
584         dbits = rle_temp_bitmap_1->bm_data;
585
586         rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE);
587
588         for (i=0; i < bmp->bm_h; i++ )    {
589 #ifdef RLE_DECODE_ASM
590                 dbits1=(unsigned char *)gr_rle_decode_asm( sbits, dbits );
591 #else
592                 gr_rle_decode( sbits, dbits );
593 #endif
594                 sbits += (int)bmp->bm_data[4+i];
595                 dbits += bmp->bm_w;
596 #ifdef RLE_DECODE_ASM
597                 Assert( dbits == dbits1 );              // Get John, bogus rle data!
598 #endif
599         }
600 #ifdef D1XD3D
601         gr_set_bitmap_data (rle_temp_bitmap_1, rle_temp_bitmap_1->bm_data);
602 #endif
603 }
604
605 #if defined(POLY_ACC)
606 grs_bitmap *rle_get_id_sub(grs_bitmap *bmp)
607 {
608         int i;
609
610         for (i=0;i<MAX_CACHE_BITMAPS;i++) {
611                 if (rle_cache[i].expanded_bitmap == bmp) {
612                         return rle_cache[i].rle_bitmap;
613                 }
614         }
615         return NULL;
616 }
617 #endif
618
619
620 grs_bitmap * rle_expand_texture( grs_bitmap * bmp )
621 {
622         int i;
623         int lowest_count, lc;
624         int least_recently_used;
625
626         if (!rle_cache_initialized) rle_cache_init();
627
628         Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) );
629
630         lc = rle_counter;
631         rle_counter++;
632         if ( rle_counter < lc ) {
633                 for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
634                         rle_cache[i].rle_bitmap = NULL;
635                         rle_cache[i].last_used = 0;
636                 }
637         }
638
639 //      if (((rle_counter % 100)==1) && (rle_hits+rle_misses > 0))
640 //              mprintf(( 0, "RLE-CACHE %d%%, H:%d, M:%d\n", (rle_misses*100)/(rle_hits+rle_misses), rle_hits, rle_misses ));
641
642         lowest_count = rle_cache[rle_next].last_used;
643         least_recently_used = rle_next;
644         rle_next++;
645         if ( rle_next >= MAX_CACHE_BITMAPS )
646                 rle_next = 0;
647
648         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
649                 if (rle_cache[i].rle_bitmap == bmp)     {
650                         rle_hits++;
651                         rle_cache[i].last_used = rle_counter;
652                         return rle_cache[i].expanded_bitmap;
653                 }
654                 if ( rle_cache[i].last_used < lowest_count )    {
655                         lowest_count = rle_cache[i].last_used;
656                         least_recently_used = i;
657                 }
658         }
659
660         Assert(bmp->bm_w<=64 && bmp->bm_h<=64); //dest buffer is 64x64
661         rle_misses++;
662         rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap );
663         rle_cache[least_recently_used].rle_bitmap = bmp;
664         rle_cache[least_recently_used].last_used = rle_counter;
665         return rle_cache[least_recently_used].expanded_bitmap;
666 }
667
668
669 void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 )
670 {
671         int i = 0, j;
672         int count;
673         ubyte color=0;
674
675         if ( x2 < x1 ) return;
676
677         count = 0;
678         while ( i < x1 )        {
679                 color = *src++;
680                 if ( color == RLE_CODE ) return;
681                 if ( IS_RLE_CODE(color) )       {
682                         count = color & NOT_RLE_CODE;
683                         color = *src++;
684                 } else {
685                         // unique
686                         count = 1;
687                 }
688                 i += count;
689         }
690         count = i - x1;
691         i = x1;
692         // we know have '*count' pixels of 'color'.
693
694         if ( x1+count > x2 )    {
695                 count = x2-x1+1;
696                 for ( j=0; j<count; j++ )
697                         gr_bm_pixel( dest, dx++, dy, color );
698                 return;
699         }
700
701         for ( j=0; j<count; j++ )
702                 gr_bm_pixel( dest, dx++, dy, color );
703         i += count;
704
705         while( i <= x2 )                {
706                 color = *src++;
707                 if ( color == RLE_CODE ) return;
708                 if ( IS_RLE_CODE(color) )       {
709                         count = color & NOT_RLE_CODE;
710                         color = *src++;
711                 } else {
712                         // unique
713                         count = 1;
714                 }
715                 // we know have '*count' pixels of 'color'.
716                 if ( i+count <= x2 )    {
717                         for ( j=0; j<count; j++ )
718                                 gr_bm_pixel( dest, dx++, dy, color );
719                         i += count;
720                 } else {
721                         count = x2-i+1;
722                         for ( j=0; j<count; j++ )
723                                 gr_bm_pixel( dest, dx++, dy, color );
724                         i += count;
725                 }
726         }
727 }
728
729 void gr_rle_expand_scanline_generic_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2  )
730 {
731         int i = 0, j;
732         int count;
733         ubyte color = 0;
734
735         if ( x2 < x1 ) return;
736
737         count = 0;
738         while ( i < x1 )        {
739                 color = *src++;
740                 if ( color == RLE_CODE ) return;
741                 if ( IS_RLE_CODE(color) )       {
742                         count = color & NOT_RLE_CODE;
743                         color = *src++;
744                 } else {
745                         // unique
746                         count = 1;
747                 }
748                 i += count;
749         }
750         count = i - x1;
751         i = x1;
752         // we know have '*count' pixels of 'color'.
753
754         if ( x1+count > x2 )    {
755                 count = x2-x1+1;
756                 if (color != TRANSPARENCY_COLOR) {
757                         for ( j=0; j<count; j++ )
758                                 gr_bm_pixel( dest, dx++, dy, color );
759                 }
760                 return;
761         }
762
763         if ( color != TRANSPARENCY_COLOR ) {
764                 for ( j=0; j<count; j++ )
765                         gr_bm_pixel( dest, dx++, dy, color );
766         } else
767                 dx += count;
768         i += count;
769
770         while( i <= x2 )                {
771                 color = *src++;
772                 if ( color == RLE_CODE ) return;
773                 if ( IS_RLE_CODE(color) )       {
774                         count = color & NOT_RLE_CODE;
775                         color = *src++;
776                 } else {
777                         // unique
778                         count = 1;
779                 }
780                 // we know have '*count' pixels of 'color'.
781                 if ( i+count <= x2 )    {
782                         if ( color != TRANSPARENCY_COLOR ) {
783                                 for ( j=0; j<count; j++ )
784                                         gr_bm_pixel( dest, dx++, dy, color );
785                         } else
786                                 dx += count;
787                         i += count;
788                 } else {
789                         count = x2-i+1;
790                         if ( color != TRANSPARENCY_COLOR ) {
791                                 for ( j=0; j<count; j++ )
792                                         gr_bm_pixel( dest, dx++, dy, color );
793                         } else
794                                 dx += count;
795                         i += count;
796                 }
797         }
798 }
799
800
801 #ifdef __MSDOS__
802 void gr_rle_expand_scanline_svga_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2  )
803 {
804         int i = 0, j;
805         int count;
806         ubyte color;
807         ubyte * vram = (ubyte *)0xA0000;
808         int VideoLocation,page,offset;
809
810         if ( x2 < x1 ) return;
811
812         VideoLocation = (unsigned int)dest->bm_data + (dest->bm_rowsize * dy) + dx;
813         page    = VideoLocation >> 16;
814         offset  = VideoLocation & 0xFFFF;
815
816         gr_vesa_setpage( page );
817
818         if ( (offset + (x2-x1+1)) < 65536 )     {
819                 // We don't cross a svga page, so blit it fast!
820                 gr_rle_expand_scanline_masked( &vram[offset], src, x1, x2 );
821                 return;
822         }
823
824         count = 0;
825         while ( i < x1 )        {
826                 color = *src++;
827                 if ( color == RLE_CODE ) return;
828                 if ( IS_RLE_CODE(color) )       {
829                         count = color & NOT_RLE_CODE;
830                         color = *src++;
831                 } else {
832                         // unique
833                         count = 1;
834                 }
835                 i += count;
836         }
837         count = i - x1;
838         i = x1;
839         // we know have '*count' pixels of 'color'.
840
841         if ( x1+count > x2 )    {
842                 count = x2-x1+1;
843                 if (color != TRANSPARENCY_COLOR) {
844                         for ( j=0; j<count; j++ )       {
845                                 vram[offset++] = color;
846                                 if ( offset >= 65536 ) {
847                                         offset -= 65536;
848                                         page++;
849                                         gr_vesa_setpage(page);
850                                 }
851                         }
852                 }
853                 return;
854         }
855
856         if ( color != TRANSPARENCY_COLOR ) {
857                 for ( j=0; j<count; j++ )       {
858                         vram[offset++] = color;
859                         if ( offset >= 65536 ) {
860                                 offset -= 65536;
861                                 page++;
862                                 gr_vesa_setpage(page);
863                         }
864                 }
865         } else  {
866                 offset += count;
867                 if ( offset >= 65536 ) {
868                         offset -= 65536;
869                         page++;
870                         gr_vesa_setpage(page);
871                 }
872         }
873         i += count;
874
875         while( i <= x2 )                {
876                 color = *src++;
877                 if ( color == RLE_CODE ) return;
878                 if ( IS_RLE_CODE(color) )       {
879                         count = color & NOT_RLE_CODE;
880                         color = *src++;
881                 } else {
882                         // unique
883                         count = 1;
884                 }
885                 // we know have '*count' pixels of 'color'.
886                 if ( i+count <= x2 )    {
887                         if ( color != TRANSPARENCY_COLOR ) {
888                                 for ( j=0; j<count; j++ )       {
889                                         vram[offset++] = color;
890                                         if ( offset >= 65536 ) {
891                                                 offset -= 65536;
892                                                 page++;
893                                                 gr_vesa_setpage(page);
894                                         }
895                                 }
896                         } else  {
897                                 offset += count;
898                                 if ( offset >= 65536 ) {
899                                         offset -= 65536;
900                                         page++;
901                                         gr_vesa_setpage(page);
902                                 }
903                         }
904                         i += count;
905                 } else {
906                         count = x2-i+1;
907                         if ( color != TRANSPARENCY_COLOR ) {
908                                 for ( j=0; j<count; j++ )       {
909                                         vram[offset++] = color;
910                                         if ( offset >= 65536 ) {
911                                                 offset -= 65536;
912                                                 page++;
913                                                 gr_vesa_setpage(page);
914                                         }
915                                 }
916                         } else  {
917                                 offset += count;
918                                 if ( offset >= 65536 ) {
919                                         offset -= 65536;
920                                         page++;
921                                         gr_vesa_setpage(page);
922                                 }
923                         }
924                         i += count;
925                 }
926         }
927 }
928 #endif // __MSDOS__
929
930
931 /*
932  * swaps entries 0 and 255 in an RLE bitmap without uncompressing it
933  */
934 void rle_swap_0_255(grs_bitmap *bmp)
935 {
936         int i, j, len, rle_big;
937         unsigned char *ptr, *ptr2, *temp, *start;
938         unsigned short line_size;
939
940         rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG;
941
942         temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) );
943
944         if (rle_big) {                  // set ptrs to first lines
945                 ptr = bmp->bm_data + 4 + 2 * bmp->bm_h;
946                 ptr2 = temp + 4 + 2 * bmp->bm_h;
947         } else {
948                 ptr = bmp->bm_data + 4 + bmp->bm_h;
949                 ptr2 = temp + 4 + bmp->bm_h;
950         }
951         for (i = 0; i < bmp->bm_h; i++) {
952                 start = ptr2;
953                 if (rle_big)
954                         line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i]));
955                 else
956                         line_size = bmp->bm_data[4 + i];
957                 for (j = 0; j < line_size; j++) {
958                         if ( ! IS_RLE_CODE(ptr[j]) ) {
959                                 if (ptr[j] == 0) {
960                                         *ptr2++ = RLE_CODE | 1;
961                                         *ptr2++ = 255;
962                                 } else
963                                         *ptr2++ = ptr[j];
964                         } else {
965                                 *ptr2++ = ptr[j];
966                                 if ((ptr[j] & NOT_RLE_CODE) == 0)
967                                         break;
968                                 j++;
969                                 if (ptr[j] == 0)
970                                         *ptr2++ = 255;
971                                 else if (ptr[j] == 255)
972                                         *ptr2++ = 0;
973                                 else
974                                         *ptr2++ = ptr[j];
975                         }
976                 }
977                 if (rle_big)                // set line size
978                         *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start);
979                 else
980                         temp[4 + i] = ptr2 - start;
981                 ptr += line_size;           // go to next line
982         }
983         len = ptr2 - temp;
984         *((int *)temp) = len;           // set total size
985         memcpy(bmp->bm_data, temp, len);
986         d_free(temp);
987 }
988
989 /*
990  * remaps all entries using colormap in an RLE bitmap without uncompressing it
991  */
992 void rle_remap(grs_bitmap *bmp, ubyte *colormap)
993 {
994         int i, j, len, rle_big;
995         unsigned char *ptr, *ptr2, *temp, *start;
996         unsigned short line_size;
997
998         rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG;
999
1000         temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) + 30000 );
1001
1002         if (rle_big) {                  // set ptrs to first lines
1003                 ptr = bmp->bm_data + 4 + 2 * bmp->bm_h;
1004                 ptr2 = temp + 4 + 2 * bmp->bm_h;
1005         } else {
1006                 ptr = bmp->bm_data + 4 + bmp->bm_h;
1007                 ptr2 = temp + 4 + bmp->bm_h;
1008         }
1009         for (i = 0; i < bmp->bm_h; i++) {
1010                 start = ptr2;
1011                 if (rle_big)
1012                         line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i]));
1013                 else
1014                         line_size = bmp->bm_data[4 + i];
1015                 for (j = 0; j < line_size; j++) {
1016                         if ( ! IS_RLE_CODE(ptr[j])) {
1017                                 if (IS_RLE_CODE(colormap[ptr[j]])) 
1018                                         *ptr2++ = RLE_CODE | 1; // add "escape sequence"
1019                                 *ptr2++ = colormap[ptr[j]]; // translate
1020                         } else {
1021                                 *ptr2++ = ptr[j]; // just copy current rle code
1022                                 if ((ptr[j] & NOT_RLE_CODE) == 0)
1023                                         break;
1024                                 j++;
1025                                 *ptr2++ = colormap[ptr[j]]; // translate
1026                         }
1027                 }
1028                 if (rle_big)                // set line size
1029                         *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start);
1030                 else
1031                         temp[4 + i] = ptr2 - start;
1032                 ptr += line_size;           // go to next line
1033         }
1034         len = ptr2 - temp;
1035         *((int *)temp) = len;           // set total size
1036         memcpy(bmp->bm_data, temp, len);
1037         d_free(temp);
1038 }