merge with original d2 file
[btb/d2x.git] / 2d / rle.c
1 /* $Id: rle.c,v 1.8 2002-08-22 02:43:35 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Routines to do run length encoding/decoding
18  * on bitmaps.
19  *
20  * Changed shorts to ints in parameters.
21  *
22  *
23  * Old Log:
24  * Revision 1.10  1995/08/14  14:26:34  allender
25  * changed transparency color to 0
26  *
27  * Revision 1.9  1995/07/05  16:07:49  allender
28  * transparency/kitchen chagnes
29  *
30  * Revision 1.8  1995/05/12  11:54:03  allender
31  * changed memory stuff again
32  *
33  * Revision 1.7  1995/05/11  12:49:19  allender
34  * change transparency color
35  *
36  * Revision 1.6  1995/05/04  20:00:30  allender
37  * use NewPtr instead of malloc.  Fix gr_rle_scanline (which caused me
38  * *many* hours of frustration!!!!)
39  *
40  * Revision 1.5  1995/05/01  08:40:32  allender
41  * trying to find memory bug....this stuff works -- it's johns code
42  *
43  * Revision 1.4  1995/04/27  07:38:24  allender
44  * new rle code ala John
45  *
46  * Revision 1.3  1995/04/19  14:36:06  allender
47  * *** empty log message ***
48  *
49  * Revision 1.2  1995/04/18  12:08:30  allender
50  * *** empty log message ***
51  *
52  * Revision 1.1  1995/03/09  09:23:04  allender
53  * Initial revision
54  *
55  *
56  * --- PC RCS information ---
57  * Revision 1.19  1995/01/14  19:18:31  john
58  * Added assert to check for paged out bitmap.
59  *
60  * Revision 1.18  1995/01/14  11:32:07  john
61  * Added rle_cache_flush function.
62  *
63  * Revision 1.17  1994/12/13  10:58:27  john
64  * Fixed bug with 2 consecutive calls to get_expanded_Texture
65  * with 2 different bitmaps, returning the same rle texture,
66  * causing doors to disapper.
67  *
68  * Revision 1.16  1994/11/30  00:55:03  mike
69  * optimization
70  *
71  * Revision 1.15  1994/11/24  13:24:44  john
72  * Made sure that some rep movs had the cld set first.
73  * Took some unused functions out.
74  *
75  * Revision 1.14  1994/11/23  16:03:46  john
76  * Fixed generic rle'ing to use new bit method.
77  *
78  * Revision 1.13  1994/11/23  15:45:51  john
79  * Changed to a 3 bit rle scheme.
80  *
81  * Revision 1.12  1994/11/18  22:50:24  john
82  * Changed shorts to ints in parameters.
83  *
84  * Revision 1.11  1994/11/14  17:06:13  john
85  * Took out Key_f12.
86  *
87  * Revision 1.10  1994/11/14  15:54:09  john
88  * Put code in for maybe checking bogus rle data.
89  *
90  * Revision 1.9  1994/11/14  15:51:58  john
91  * Added rle_disable_caching variable to prove the stability of my rle
92  * caching code to any non-believers.
93  *
94  * Revision 1.8  1994/11/10  10:31:20  john
95  * Reduce cache buffers to 16.
96  *
97  * Revision 1.7  1994/11/09  19:53:43  john
98  * Added texture rle caching.
99  *
100  * Revision 1.6  1994/11/09  17:41:44  john
101  * Made a slow version of rle bitblt to svga, modex.
102  *
103  * Revision 1.5  1994/11/09  17:07:50  john
104  * Fixed bug with bitmap that gets bigger with rle.
105  *
106  * Revision 1.4  1994/11/09  16:35:17  john
107  * First version with working RLE bitmaps.
108  *
109  * Revision 1.3  1994/10/26  12:54:47  john
110  * Fixed bug with decode that used rep movsd instead of
111  * rep stosd.
112  *
113  * Revision 1.2  1994/10/06  17:05:25  john
114  * First version of rle stuff.
115  *
116  * Revision 1.1  1994/10/06  16:53:34  john
117  * Initial revision
118  *
119  *
120  */
121
122
123 #ifdef HAVE_CONFIG_H
124 #include <conf.h>
125 #endif
126
127 #ifdef RCS
128 static char rcsid[] = "$Id: rle.c,v 1.8 2002-08-22 02:43:35 btb Exp $";
129 #endif
130
131 #include <stdlib.h>
132 #include <stdio.h>
133 #include <string.h>
134
135 #include "pstypes.h"
136 #include "u_mem.h"
137 #include "mono.h"
138
139
140 #include "gr.h"
141 #include "grdef.h"
142 #include "error.h"
143 //#include "key.h"
144 #include "rle.h"
145
146 #define RLE_CODE        0xE0
147 #define NOT_RLE_CODE    31
148
149 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 );
150
151 #ifndef NO_ASM
152 #ifdef __WATCOMC__
153 int gr_rle_decode_asm( ubyte * src, ubyte * dest );
154 #pragma aux gr_rle_decode_asm parm [esi] [edi] value [edi] modify exact [eax ebx ecx edx esi edi] = \
155 "  cld              " \
156 "   xor ecx, ecx    " \
157 "   cld             " \
158 "   jmp NextByte    " \
159 "                   " \
160 "Unique:            " \
161 "   mov [edi],al    " \
162 "   inc edi         " \
163 "                   " \
164 "NextByte:          " \
165 "   mov al,[esi]    " \
166 "   inc esi         " \
167 "                   " \
168 "   mov ah, al      " \
169 "   and ah, 0xE0    " \
170 "  cmp  ah, 0xE0    " \
171 "   jne   Unique    " \
172 "                   " \
173 "   mov cl, al      " \
174 "   and cl, 31      " \
175 "   je      done    " \
176 "                   " \
177 "   mov al,[esi]    " \
178 "   inc esi         " \
179 "   mov ah, al      " \
180 "   shr ecx,1       " \
181 "   rep stosw       " \
182 "   jnc NextByte    " \
183 "   mov [edi],al    " \
184 "   inc edi         " \
185 "                   " \
186 "   jmp NextByte    " \
187 "                   " \
188 "done:              ";
189
190 void rle_stosb(char *dest, int len, int color);
191 #pragma aux rle_stosb = "cld rep    stosb" parm [edi] [ecx] [eax] modify exact [edi ecx];
192 #elif defined __GNUC__
193 static inline int gr_rle_decode_asm( ubyte * src, ubyte * dest ) {
194    register int __ret;
195    int dummy;
196    __asm__ __volatile__ (
197 "   cld;"
198 "   xorl %%ecx, %%ecx;"
199 "   jmp 1f;"
200 "0:;"
201 "   movb %%al,(%%edi);"
202 "   incl %%edi;"
203 "1:;"
204 "   movb (%%esi), %%al;"
205 "   incl %%esi;"
206 "   movb %%al, %%ah;"
207 "   andb $0xE0, %%ah;"
208 "   cmpb $0xE0, %%ah;"
209 "   jne 0b;"
210 "   movb %%al, %%cl;"
211 "   andb $31, %%cl;"
212 "   je 2f;"
213 "   movb (%%esi), %%al;"
214 "   incl %%esi;"
215 "   movb %%al, %%ah;"
216 "   shrl $1, %%ecx;"
217 "   rep; stosw;"
218 "   jnc 1b;"
219 "   movb %%al, (%%edi);"
220 "   incl %%edi;"
221 "   jmp 1b;"
222 "2:"
223 : "=D" (__ret), "=S" (dummy) : "1" (src), "D" (dest) : "%eax", "%ecx");
224   return __ret;
225 }
226
227 static inline void rle_stosb(char *dest, int len, int color) {
228         int dummy[2];
229    __asm__ __volatile__ (
230     "cld; rep; stosb"
231     : "=D" (dummy[0]), "=c" (dummy[1])
232         : "0" (dest), "1" (len), "a" (color) );
233 }
234 #elif defined _MSC_VER
235 __inline int gr_rle_decode_asm( ubyte * src, ubyte * dest )
236 {
237          int retval;
238         __asm {
239                 mov esi,[src]
240                 mov edi,[dest]
241         xor ecx, ecx
242                 cld
243                 jmp NextByte
244 Unique:
245                 mov [edi], al
246                 inc edi
247 NextByte:
248                 mov al,[esi]
249                 inc esi
250                 mov ah, al
251                 and ah,0xE0
252                 cmp ah,0xE0
253                 jne Unique
254
255                 mov cl, al
256                 and cl, 31
257                 je done
258
259                 mov al, [esi]
260                 inc esi
261                 mov ah, al
262                 shr ecx, 1
263                 rep stosw
264                 jnc NextByte
265                 mov [edi], al
266                 inc edi
267                 jmp NextByte
268 done:
269                 mov [retval],edi
270         }
271         return retval;
272 }
273
274 __inline void rle_stosb(char *dest, int len, int color)
275 {
276   __asm {
277         mov edi,[dest]
278         mov ecx,[len]
279         mov eax,[color]
280         cld
281         rep stosb
282   }
283 }
284
285 #else
286 # undef NO_ASM
287 # define NO_ASM 1
288 /* Well, if inline assembler is not supported for this compiler, we don't
289  **really** want ASM... */
290 #endif
291 #endif
292
293 #ifdef NO_ASM
294 void rle_stosb(ubyte *dest, int len, int color)
295 {
296         int i;
297         for (i=0; i<len; i++ )
298                 *dest++ = color;
299 }
300 #endif
301
302 void gr_rle_decode( ubyte * src, ubyte * dest )
303 {
304 #ifdef NO_ASM
305         int i;
306         ubyte data, count = 0;
307
308         while(1) {
309                 data = *src++;
310                 if ( (data & RLE_CODE) != RLE_CODE ) {
311                         *dest++ = data;
312                 } else {
313                         count = data & NOT_RLE_CODE;
314                         if (count==0) return;
315                         data = *src++;
316                         for (i=0; i<count; i++ )
317                                 *dest++ = data;
318                 }
319         }
320 #else
321     gr_rle_decode_asm( src, dest );
322 #endif
323 }
324
325 // Given pointer to start of one scanline of rle data, uncompress it to
326 // dest, from source pixels x1 to x2.
327 void gr_rle_expand_scanline_masked( ubyte *dest, ubyte *src, int x1, int x2  )
328 {
329         int i = 0;
330         ubyte count=0;
331         ubyte color=0;
332
333         if ( x2 < x1 ) return;
334
335         while ( i < x1 )        {
336                 color = *src++;
337                 if ( color == RLE_CODE ) return;
338                 if ( (color & RLE_CODE)==RLE_CODE )     {
339                         count = color & (~RLE_CODE);
340                         color = *src++;
341                 } else {
342                         // unique
343                         count = 1;
344                 }
345                 i += count;
346         }
347         count = i - x1;
348         i = x1;
349         // we know have '*count' pixels of 'color'.
350         
351         if ( x1+count > x2 )    {
352                 count = x2-x1+1;
353                 if ( color != TRANSPARENCY_COLOR )      rle_stosb( dest, count, color );
354                 return;
355         }
356
357         if ( color != TRANSPARENCY_COLOR )      rle_stosb( dest, count, color );
358         dest += count;
359         i += count;
360
361         while( i <= x2 )                {
362                 color = *src++;
363                 if ( color == RLE_CODE ) return;
364                 if ( (color & RLE_CODE) == (RLE_CODE) ) {
365                         count = color & (~RLE_CODE);
366                         color = *src++;
367                 } else {
368                         // unique
369                         count = 1;
370                 }
371                 // we know have '*count' pixels of 'color'.
372                 if ( i+count <= x2 )    {
373                         if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
374                         i += count;
375                         dest += count;
376                 } else {
377                         count = x2-i+1;
378                         if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
379                         i += count;
380                         dest += count;
381                 }
382
383         }       
384 }
385
386 void gr_rle_expand_scanline( ubyte *dest, ubyte *src, int x1, int x2  )
387 {
388         int i = 0;
389         ubyte count=0;
390         ubyte color=0;
391
392         if ( x2 < x1 ) return;
393
394         while ( i < x1 )        {
395                 color = *src++;
396                 if ( color == RLE_CODE ) return;
397                 if ( (color & RLE_CODE)==RLE_CODE )     {
398                         count = color & (~RLE_CODE);
399                         color = *src++;
400                 } else {
401                         // unique
402                         count = 1;
403                 }
404                 i += count;
405         }
406         count = i - x1;
407         i = x1;
408         // we know have '*count' pixels of 'color'.
409         
410         if ( x1+count > x2 )    {
411                 count = x2-x1+1;
412                 rle_stosb( dest, count, color );
413                 return;
414         }
415
416         rle_stosb( dest, count, color );
417         dest += count;
418         i += count;
419
420         while( i <= x2 )                {
421                 color = *src++;
422                 if ( color == RLE_CODE ) return;
423                 if ( (color & RLE_CODE)==RLE_CODE )     {
424                         count = color & (~RLE_CODE);
425                         color = *src++;
426                 } else {
427                         // unique
428                         count = 1;
429                 }
430                 // we know have '*count' pixels of 'color'.
431                 if ( i+count <= x2 )    {
432                         rle_stosb( dest, count, color );
433                         i += count;
434                         dest += count;
435                 } else {
436                         count = x2-i+1;
437                         rle_stosb( dest, count, color );
438                         i += count;
439                         dest += count;
440                 }
441         }       
442 }
443
444
445 int gr_rle_encode( int org_size, ubyte *src, ubyte *dest )
446 {
447         int i;
448         ubyte c, oc;
449         ubyte count;
450         ubyte *dest_start;
451
452         dest_start = dest;
453         oc = *src++;
454         count = 1;
455
456         for (i=1; i<org_size; i++ )     {
457                 c = *src++;                                                     
458                 if ( c!=oc )    {
459                         if ( count )    {
460                                 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) )        {
461                                         *dest++ = oc;
462                                         Assert( oc != RLE_CODE );
463                                 } else {
464                                         count |= RLE_CODE;
465                                         *dest++ = count;
466                                         *dest++ = oc;
467                                 }
468                         }
469                         oc = c;
470                         count = 0;
471                 }
472                 count++;
473                 if ( count == NOT_RLE_CODE )    {
474                         count |= RLE_CODE;
475                         *dest++=count;
476                         *dest++=oc;
477                         count = 0;
478                 }
479         }
480         if (count)      {
481                 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) )        {
482                         *dest++ = oc;
483                         Assert( oc != RLE_CODE );
484                 } else {
485                         count |= RLE_CODE;
486                         *dest++ = count;
487                         *dest++ = oc;
488                 }
489         }
490         *dest++ = RLE_CODE;
491
492         return dest-dest_start;
493 }
494
495
496 int gr_rle_getsize( int org_size, ubyte *src )
497 {
498         int i;
499         ubyte c, oc;
500         ubyte count;
501         int dest_size=0;
502
503         oc = *src++;
504         count = 1;
505
506         for (i=1; i<org_size; i++ )     {
507                 c = *src++;                                                     
508                 if ( c!=oc )    {
509                         if ( count )    {
510                                 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) )        {
511                                         dest_size++;
512                                 } else {
513                                         dest_size++;
514                                         dest_size++;
515                                 }
516                         }
517                         oc = c;
518                         count = 0;
519                 }
520                 count++;
521                 if ( count == NOT_RLE_CODE )    {
522                         dest_size++;
523                         dest_size++;
524                         count = 0;
525                 }
526         }
527         if (count)      {
528                 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) )        {
529                         dest_size++;
530                 } else {
531                         dest_size++;
532                         dest_size++;
533                 }
534         }
535         dest_size++;
536
537         return dest_size;
538 }
539
540 int gr_bitmap_rle_compress( grs_bitmap * bmp )
541 {
542         int y, d1, d;
543         int doffset;
544         ubyte *rle_data;
545         int large_rle = 0;
546
547         // first must check to see if this is large bitmap.
548
549         for (y=0; y<bmp->bm_h; y++ )    {
550                 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
551                 if (d1 > 255) {
552                         large_rle = 1;
553                         break;
554                 }
555         }
556
557         rle_data=d_malloc( (bmp->bm_w+1) * bmp->bm_h );
558         if (rle_data==NULL) return 0;
559         if (!large_rle)
560                 doffset = 4 + bmp->bm_h;
561         else
562                 doffset = 4 + (2 * bmp->bm_h);          // each row of rle'd bitmap has short instead of byte offset now
563
564         for (y=0; y<bmp->bm_h; y++ )    {
565                 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
566                 if ( ((doffset+d1) > bmp->bm_w*bmp->bm_h) || (d1 > (large_rle?32767:255) ) ) {
567                         d_free(rle_data);
568                         return 0;
569                 }
570                 d = gr_rle_encode( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y], &rle_data[doffset] );
571                 Assert( d==d1 );
572                 doffset += d;
573                 if (large_rle)
574                         *((short *)&(rle_data[(y*2)+4])) = (short)d;
575                 else
576                         rle_data[y+4] = d;
577         }
578         //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 );
579         memcpy(         rle_data, &doffset, 4 );
580         memcpy(         bmp->bm_data, rle_data, doffset );
581         d_free(rle_data);
582         bmp->bm_flags |= BM_FLAG_RLE;
583         if (large_rle)
584                 bmp->bm_flags |= BM_FLAG_RLE_BIG;
585         return 1;
586 }
587
588 #define MAX_CACHE_BITMAPS 32
589
590 typedef struct rle_cache_element {
591         grs_bitmap * rle_bitmap;
592         ubyte * rle_data;
593         grs_bitmap * expanded_bitmap;                   
594         int last_used;
595 } rle_cache_element;
596
597 int rle_cache_initialized = 0;
598 int rle_counter = 0;
599 int rle_next = 0;
600 rle_cache_element rle_cache[MAX_CACHE_BITMAPS];
601
602 int rle_hits = 0;
603 int rle_misses = 0;
604
605 void rle_cache_close(void)
606 {
607         if (rle_cache_initialized)      {
608                 int i;
609                 rle_cache_initialized = 0;
610                 for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
611                         gr_free_bitmap(rle_cache[i].expanded_bitmap);
612                 }
613         }
614 }
615
616 void rle_cache_init()
617 {
618         int i;
619         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
620                 rle_cache[i].rle_bitmap = NULL;
621                 rle_cache[i].expanded_bitmap = gr_create_bitmap( 64, 64 );
622                 rle_cache[i].last_used = 0;
623                 Assert( rle_cache[i].expanded_bitmap != NULL );
624         }       
625         rle_cache_initialized = 1;
626         atexit( rle_cache_close );
627 }
628
629 void rle_cache_flush()
630 {
631         int i;
632         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
633                 rle_cache[i].rle_bitmap = NULL;
634                 rle_cache[i].last_used = 0;
635         }       
636 }
637
638
639
640 grs_bitmap * rle_expand_texture( grs_bitmap * bmp )
641 {
642         int i;
643         int lowest_count, lc;
644         int least_recently_used;
645
646         if (!rle_cache_initialized) rle_cache_init();
647
648         Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) );
649
650         lc = rle_counter;
651         rle_counter++;
652         if ( rle_counter < lc ) {
653                 for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
654                         rle_cache[i].rle_bitmap = NULL;
655                         rle_cache[i].last_used = 0;
656                 }
657         }
658
659 //      if (((rle_counter % 100)==1) && (rle_hits+rle_misses > 0))
660 //              mprintf(( 0, "RLE-CACHE %d%%, H:%d, M:%d\n", (rle_misses*100)/(rle_hits+rle_misses), rle_hits, rle_misses ));
661
662         lowest_count = rle_cache[rle_next].last_used;
663         least_recently_used = rle_next;
664         rle_next++;
665         if ( rle_next >= MAX_CACHE_BITMAPS )
666                 rle_next = 0;
667                 
668         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
669                 if (rle_cache[i].rle_bitmap == bmp)     {
670                         rle_hits++;
671                         rle_cache[i].last_used = rle_counter;
672                         return rle_cache[i].expanded_bitmap;
673                 }
674                 if ( rle_cache[i].last_used < lowest_count )    {
675                         lowest_count = rle_cache[i].last_used;
676                         least_recently_used = i;
677                 }
678         }
679
680         Assert(bmp->bm_w<=64 && bmp->bm_h<=64); //dest buffer is 64x64
681         rle_misses++;
682         rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap );
683         rle_cache[least_recently_used].rle_bitmap = bmp;
684         rle_cache[least_recently_used].last_used = rle_counter;
685         return rle_cache[least_recently_used].expanded_bitmap;
686 }
687
688
689 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 )
690 {
691         unsigned char * dbits;
692         unsigned char * sbits;
693         int i;
694 #ifndef NO_ASM
695         unsigned char * dbits1;
696 #endif
697
698 #ifdef D1XD3D
699         Assert (bmp->iMagic == BM_MAGIC_NUMBER);
700 #endif
701
702         sbits = &bmp->bm_data[4 + bmp->bm_h];
703         dbits = rle_temp_bitmap_1->bm_data;
704
705         rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE);
706
707         for (i=0; i < bmp->bm_h; i++ )    {
708 #ifndef NO_ASM
709                 dbits1=(unsigned char *)gr_rle_decode_asm( sbits, dbits );
710 #else
711                 gr_rle_decode( sbits, dbits );
712 #endif
713                 sbits += (int)bmp->bm_data[4+i];
714                 dbits += bmp->bm_w;
715 #ifndef NO_ASM
716                 Assert( dbits == dbits1 );              // Get John, bogus rle data!
717 #endif
718         }
719 #ifdef D1XD3D
720         gr_set_bitmap_data (rle_temp_bitmap_1, rle_temp_bitmap_1->bm_data);
721 #endif
722 }
723
724 void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2, int masked  )
725 {
726         int i = 0, j;
727         int count=0;
728         ubyte color=0;
729
730         if ( x2 < x1 ) return;
731
732         while ( i < x1 )        {
733                 color = *src++;
734                 if ( color == RLE_CODE ) return;
735                 if ( (color & RLE_CODE) == RLE_CODE )   {
736                         count = color & NOT_RLE_CODE;
737                         color = *src++;
738                 } else {
739                         // unique
740                         count = 1;
741                 }
742                 i += count;
743         }
744         count = i - x1;
745         i = x1;
746         // we know have '*count' pixels of 'color'.
747         
748         if ( x1+count > x2 )    {
749                 count = x2-x1+1;
750                 if (!masked || color != 255)
751                 for ( j=0; j<count; j++ )
752                         gr_bm_pixel( dest, dx++, dy, color );
753                 return;
754         }
755
756         if (masked && color == 255)
757                 dx += count;
758         else
759         for ( j=0; j<count; j++ )
760                 gr_bm_pixel( dest, dx++, dy, color );
761         i += count;
762
763         while( i <= x2 )                {
764                 color = *src++;
765                 if ( color == RLE_CODE ) return;
766                 if ( (color & RLE_CODE) == RLE_CODE )   {
767                         count = color & NOT_RLE_CODE;
768                         color = *src++;
769                 } else {
770                         // unique
771                         count = 1;
772                 }
773                 // we know have '*count' pixels of 'color'.
774                 if ( i+count <= x2 )    {
775                         if (masked && color == 255)
776                                 dx += count;
777                         else
778                         for ( j=0; j<count; j++ )
779                                 gr_bm_pixel( dest, dx++, dy, color );
780                         i += count;
781                 } else {
782                         count = x2-i+1;
783                         if (masked && color == 255)
784                                 dx += count;
785                         else
786                         for ( j=0; j<count; j++ )
787                                 gr_bm_pixel( dest, dx++, dy, color );
788                         i += count;
789                 }
790         }
791 }
792
793 /*
794  * swaps entries 0 and 255 in an RLE bitmap without uncompressing it
795  *
796  * doesn't handle RLE_BIG yet, but neither does anything else...
797  * LEAKS LOTS OF MEMORY!
798  */
799 void rle_swap_0_255(grs_bitmap *bmp)
800 {
801         int i, j;
802         unsigned char *ptr, *ptr2, *temp, *start;
803
804         if (bmp->bm_flags & BM_FLAG_RLE_BIG)
805                 return;
806
807         temp = d_malloc(4 + bmp->bm_h + (bmp->bm_w + 1) * bmp->bm_h);
808
809         *((int *)temp) = 4;
810         ptr = bmp->bm_data + 4 + bmp->bm_h;
811         ptr2 = temp + 4 + bmp->bm_h;
812         for (i = 0; i < bmp->bm_h; i++) {
813                 start = ptr2;
814                 for (j = 0; j < bmp->bm_data[4 + i]; j++) {
815                         if ((ptr[j] & RLE_CODE) != RLE_CODE) {
816                                 if (ptr[j] == 0) {
817                                         *ptr2++ = RLE_CODE | 1;
818                                         *ptr2++ = 255;
819                                 } else
820                                         *ptr2++ = ptr[j];
821                         } else {
822                                 *ptr2++ = ptr[j];
823                                 if ((ptr[j] & NOT_RLE_CODE) == 0)
824                                         break;
825                                 j++;
826                                 if (ptr[j] == 0)
827                                         *ptr2++ = 255;
828                                 else if (ptr[j] == 255)
829                                         *ptr2++ = 0;
830                                 else
831                                         *ptr2++ = ptr[j];
832                         }
833                 }
834                 temp[4 + i] = ptr2 - start;
835                 *((int *)temp) += ptr2 - start;
836                 ptr += bmp->bm_data[4 + i];
837         }
838         bmp->bm_data = temp;
839 }