]> icculus.org git repositories - btb/d2x.git/blob - 2d/rle.c
need to swap line size on bigendian machines
[btb/d2x.git] / 2d / rle.c
1 /* $Id: rle.c,v 1.14 2003-03-14 09:19:48 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.14 2003-03-14 09:19:48 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 #include "byteswap.h"
146
147 #define RLE_CODE        0xE0
148 #define NOT_RLE_CODE    31
149
150 #if !defined(NO_ASM) && defined(__WATCOMC__)
151 #define RLE_DECODE_ASM
152
153 ubyte *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 #elif !defined(NO_ASM) && defined(__GNUC__)
191 #define RLE_DECODE_ASM
192
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 #elif !defined(NO_ASM) && defined(_MSC_VER)
228 #define RLE_DECODE_ASM
229
230 __inline int gr_rle_decode_asm( ubyte * src, ubyte * dest )
231 {
232          int retval;
233         __asm {
234                 mov esi,[src]
235                 mov edi,[dest]
236         xor ecx, ecx
237                 cld
238                 jmp NextByte
239 Unique:
240                 mov [edi], al
241                 inc edi
242 NextByte:
243                 mov al,[esi]
244                 inc esi
245                 mov ah, al
246                 and ah,0xE0
247                 cmp ah,0xE0
248                 jne Unique
249
250                 mov cl, al
251                 and cl, 31
252                 je done
253
254                 mov al, [esi]
255                 inc esi
256                 mov ah, al
257                 shr ecx, 1
258                 rep stosw
259                 jnc NextByte
260                 mov [edi], al
261                 inc edi
262                 jmp NextByte
263 done:
264                 mov [retval],edi
265         }
266         return retval;
267 }
268
269 #endif
270
271 #ifdef RLE_DECODE_ASM
272
273 #if 0
274 void gr_rle_decode( ubyte * src, ubyte * dest, int dest_len )
275 {
276         ubyte *dest_end;
277
278         dest_end = (ubyte *)gr_rle_decode_asm( src, dest );
279
280         Assert(dest_end-src < dest_len);
281 }
282 #else
283 void gr_rle_decode( ubyte * src, ubyte * dest )
284 {
285     gr_rle_decode_asm( src, dest );
286 }
287 #endif
288
289 #else // NO_ASM or unknown compiler
290
291 void gr_rle_decode( ubyte * src, ubyte * dest )
292 {
293         int i;
294         ubyte data, count = 0;
295
296         while(1) {
297                 data = *src++;
298                 if ( (data & RLE_CODE) != RLE_CODE ) {
299                         *dest++ = data;
300                 } else {
301                         count = data & NOT_RLE_CODE;
302                         if (count == 0)
303                                 return;
304                         data = *src++;
305                         for (i = 0; i < count; i++)
306                                 *dest++ = data;
307                 }
308         }
309 }
310
311 #endif
312
313 void rle_stosb(char *dest, int len, int color);
314
315 #if !defined(NO_ASM) && defined(__WATCOMC__)
316
317 #pragma aux rle_stosb = "cld rep    stosb" parm [edi] [ecx] [eax] modify exact [edi ecx];
318
319 #elif !defined(NO_ASM) && defined(__GNUC__)
320
321 inline void rle_stosb(char *dest, int len, int color) {
322         int dummy[2];
323    __asm__ __volatile__ (
324     "cld; rep; stosb"
325     : "=D" (dummy[0]), "=c" (dummy[1])
326         : "0" (dest), "1" (len), "a" (color) );
327 }
328
329 #elif !defined(NO_ASM) && defined(_MSC_VER)
330
331 __inline void rle_stosb(char *dest, int len, int color)
332 {
333   __asm {
334         mov edi,[dest]
335         mov ecx,[len]
336         mov eax,[color]
337         cld
338         rep stosb
339   }
340 }
341
342 #else // NO_ASM or unknown compiler
343
344 void rle_stosb(char *dest, int len, int color)
345 {
346         int i;
347         for (i=0; i<len; i++ )
348                 *dest++ = color;
349 }
350
351 #endif
352
353 // Given pointer to start of one scanline of rle data, uncompress it to
354 // dest, from source pixels x1 to x2.
355 void gr_rle_expand_scanline_masked( ubyte *dest, ubyte *src, int x1, int x2  )
356 {
357         int i = 0;
358         ubyte count;
359         ubyte color=0;
360
361         if ( x2 < x1 ) return;
362
363         count = 0;
364         while ( i < x1 )        {
365                 color = *src++;
366                 if ( color == RLE_CODE ) return;
367                 if ( (color & RLE_CODE)==RLE_CODE )     {
368                         count = color & (~RLE_CODE);
369                         color = *src++;
370                 } else {
371                         // unique
372                         count = 1;
373                 }
374                 i += count;
375         }
376         count = i - x1;
377         i = x1;
378         // we know have '*count' pixels of 'color'.
379         
380         if ( x1+count > x2 )    {
381                 count = x2-x1+1;
382                 if ( color != TRANSPARENCY_COLOR )      rle_stosb( dest, count, color );
383                 return;
384         }
385
386         if ( color != TRANSPARENCY_COLOR )      rle_stosb( dest, count, color );
387         dest += count;
388         i += count;
389
390         while( i <= x2 )                {
391                 color = *src++;
392                 if ( color == RLE_CODE ) return;
393                 if ( (color & RLE_CODE) == (RLE_CODE) ) {
394                         count = color & (~RLE_CODE);
395                         color = *src++;
396                 } else {
397                         // unique
398                         count = 1;
399                 }
400                 // we know have '*count' pixels of 'color'.
401                 if ( i+count <= x2 )    {
402                         if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
403                         i += count;
404                         dest += count;
405                 } else {
406                         count = x2-i+1;
407                         if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
408                         i += count;
409                         dest += count;
410                 }
411
412         }       
413 }
414
415 void gr_rle_expand_scanline( ubyte *dest, ubyte *src, int x1, int x2  )
416 {
417         int i = 0;
418         ubyte count;
419         ubyte color=0;
420
421         if ( x2 < x1 ) return;
422
423         count = 0;
424         while ( i < x1 )        {
425                 color = *src++;
426                 if ( color == RLE_CODE ) return;
427                 if ( (color & RLE_CODE)==RLE_CODE )     {
428                         count = color & (~RLE_CODE);
429                         color = *src++;
430                 } else {
431                         // unique
432                         count = 1;
433                 }
434                 i += count;
435         }
436         count = i - x1;
437         i = x1;
438         // we know have '*count' pixels of 'color'.
439         
440         if ( x1+count > x2 )    {
441                 count = x2-x1+1;
442                 rle_stosb( dest, count, color );
443                 return;
444         }
445
446         rle_stosb( dest, count, color );
447         dest += count;
448         i += count;
449
450         while( i <= x2 )                {
451                 color = *src++;
452                 if ( color == RLE_CODE ) return;
453                 if ( (color & RLE_CODE)==RLE_CODE )     {
454                         count = color & (~RLE_CODE);
455                         color = *src++;
456                 } else {
457                         // unique
458                         count = 1;
459                 }
460                 // we know have '*count' pixels of 'color'.
461                 if ( i+count <= x2 )    {
462                         rle_stosb( dest, count, color );
463                         i += count;
464                         dest += count;
465                 } else {
466                         count = x2-i+1;
467                         rle_stosb( dest, count, color );
468                         i += count;
469                         dest += count;
470                 }
471         }
472 }
473
474
475 int gr_rle_encode( int org_size, ubyte *src, ubyte *dest )
476 {
477         int i;
478         ubyte c, oc;
479         ubyte count;
480         ubyte *dest_start;
481
482         dest_start = dest;
483         oc = *src++;
484         count = 1;
485
486         for (i=1; i<org_size; i++ )     {
487                 c = *src++;
488                 if ( c!=oc )    {
489                         if ( count )    {
490                                 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) )        {
491                                         *dest++ = oc;
492                                         Assert( oc != RLE_CODE );
493                                 } else {
494                                         count |= RLE_CODE;
495                                         *dest++ = count;
496                                         *dest++ = oc;
497                                 }
498                         }
499                         oc = c;
500                         count = 0;
501                 }
502                 count++;
503                 if ( count == NOT_RLE_CODE )    {
504                         count |= RLE_CODE;
505                         *dest++=count;
506                         *dest++=oc;
507                         count = 0;
508                 }
509         }
510         if (count)      {
511                 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) )        {
512                         *dest++ = oc;
513                         Assert( oc != RLE_CODE );
514                 } else {
515                         count |= RLE_CODE;
516                         *dest++ = count;
517                         *dest++ = oc;
518                 }
519         }
520         *dest++ = RLE_CODE;
521
522         return dest-dest_start;
523 }
524
525
526 int gr_rle_getsize( int org_size, ubyte *src )
527 {
528         int i;
529         ubyte c, oc;
530         ubyte count;
531         int dest_size=0;
532
533         oc = *src++;
534         count = 1;
535
536         for (i=1; i<org_size; i++ )     {
537                 c = *src++;
538                 if ( c!=oc )    {
539                         if ( count )    {
540                                 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) )        {
541                                         dest_size++;
542                                 } else {
543                                         dest_size++;
544                                         dest_size++;
545                                 }
546                         }
547                         oc = c;
548                         count = 0;
549                 }
550                 count++;
551                 if ( count == NOT_RLE_CODE )    {
552                         dest_size++;
553                         dest_size++;
554                         count = 0;
555                 }
556         }
557         if (count)      {
558                 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) )        {
559                         dest_size++;
560                 } else {
561                         dest_size++;
562                         dest_size++;
563                 }
564         }
565         dest_size++;
566
567         return dest_size;
568 }
569
570 int gr_bitmap_rle_compress( grs_bitmap * bmp )
571 {
572         int y, d1, d;
573         int doffset;
574         ubyte *rle_data;
575         int large_rle = 0;
576
577         // first must check to see if this is large bitmap.
578
579         for (y=0; y<bmp->bm_h; y++ )    {
580                 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
581                 if (d1 > 255) {
582                         large_rle = 1;
583                         break;
584                 }
585         }
586
587         rle_data=d_malloc( (bmp->bm_w+1) * bmp->bm_h );
588         if (rle_data==NULL) return 0;
589         if (!large_rle)
590                 doffset = 4 + bmp->bm_h;
591         else
592                 doffset = 4 + (2 * bmp->bm_h);          // each row of rle'd bitmap has short instead of byte offset now
593
594         for (y=0; y<bmp->bm_h; y++ )    {
595                 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
596                 if ( ((doffset+d1) > bmp->bm_w*bmp->bm_h) || (d1 > (large_rle?32767:255) ) ) {
597                         d_free(rle_data);
598                         return 0;
599                 }
600                 d = gr_rle_encode( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y], &rle_data[doffset] );
601                 Assert( d==d1 );
602                 doffset += d;
603                 if (large_rle)
604                         *((short *)&(rle_data[(y*2)+4])) = (short)d;
605                 else
606                         rle_data[y+4] = d;
607         }
608         //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 );
609         memcpy(         rle_data, &doffset, 4 );
610         memcpy(         bmp->bm_data, rle_data, doffset );
611         d_free(rle_data);
612         bmp->bm_flags |= BM_FLAG_RLE;
613         if (large_rle)
614                 bmp->bm_flags |= BM_FLAG_RLE_BIG;
615         return 1;
616 }
617
618 #define MAX_CACHE_BITMAPS 32
619
620 typedef struct rle_cache_element {
621         grs_bitmap * rle_bitmap;
622         ubyte * rle_data;
623         grs_bitmap * expanded_bitmap;
624         int last_used;
625 } rle_cache_element;
626
627 int rle_cache_initialized = 0;
628 int rle_counter = 0;
629 int rle_next = 0;
630 rle_cache_element rle_cache[MAX_CACHE_BITMAPS];
631
632 int rle_hits = 0;
633 int rle_misses = 0;
634
635 void rle_cache_close(void)
636 {
637         if (rle_cache_initialized)      {
638                 int i;
639                 rle_cache_initialized = 0;
640                 for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
641                         gr_free_bitmap(rle_cache[i].expanded_bitmap);
642                 }
643         }
644 }
645
646 void rle_cache_init()
647 {
648         int i;
649         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
650                 rle_cache[i].rle_bitmap = NULL;
651                 rle_cache[i].expanded_bitmap = gr_create_bitmap( 64, 64 );
652                 rle_cache[i].last_used = 0;
653                 Assert( rle_cache[i].expanded_bitmap != NULL );
654         }
655         rle_cache_initialized = 1;
656         atexit( rle_cache_close );
657 }
658
659 void rle_cache_flush()
660 {
661         int i;
662         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
663                 rle_cache[i].rle_bitmap = NULL;
664                 rle_cache[i].last_used = 0;
665         }
666 }
667
668 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 )
669 {
670         unsigned char * dbits;
671         unsigned char * sbits;
672         int i;
673 #ifdef RLE_DECODE_ASM
674         unsigned char * dbits1;
675 #endif
676
677 #ifdef D1XD3D
678         Assert (bmp->iMagic == BM_MAGIC_NUMBER);
679 #endif
680
681         sbits = &bmp->bm_data[4 + bmp->bm_h];
682         dbits = rle_temp_bitmap_1->bm_data;
683
684         rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE);
685
686         for (i=0; i < bmp->bm_h; i++ )    {
687 #ifdef RLE_DECODE_ASM
688                 dbits1=(unsigned char *)gr_rle_decode_asm( sbits, dbits );
689 #else
690                 gr_rle_decode( sbits, dbits );
691 #endif
692                 sbits += (int)bmp->bm_data[4+i];
693                 dbits += bmp->bm_w;
694 #ifdef RLE_DECODE_ASM
695                 Assert( dbits == dbits1 );              // Get John, bogus rle data!
696 #endif
697         }
698 #ifdef D1XD3D
699         gr_set_bitmap_data (rle_temp_bitmap_1, rle_temp_bitmap_1->bm_data);
700 #endif
701 }
702
703 #if defined(POLY_ACC)
704 grs_bitmap *rle_get_id_sub(grs_bitmap *bmp)
705 {
706         int i;
707
708         for (i=0;i<MAX_CACHE_BITMAPS;i++) {
709                 if (rle_cache[i].expanded_bitmap == bmp) {
710                         return rle_cache[i].rle_bitmap;
711                 }
712         }
713         return NULL;
714 }
715 #endif
716
717
718 grs_bitmap * rle_expand_texture( grs_bitmap * bmp )
719 {
720         int i;
721         int lowest_count, lc;
722         int least_recently_used;
723
724         if (!rle_cache_initialized) rle_cache_init();
725
726         Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) );
727
728         lc = rle_counter;
729         rle_counter++;
730         if ( rle_counter < lc ) {
731                 for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
732                         rle_cache[i].rle_bitmap = NULL;
733                         rle_cache[i].last_used = 0;
734                 }
735         }
736
737 //      if (((rle_counter % 100)==1) && (rle_hits+rle_misses > 0))
738 //              mprintf(( 0, "RLE-CACHE %d%%, H:%d, M:%d\n", (rle_misses*100)/(rle_hits+rle_misses), rle_hits, rle_misses ));
739
740         lowest_count = rle_cache[rle_next].last_used;
741         least_recently_used = rle_next;
742         rle_next++;
743         if ( rle_next >= MAX_CACHE_BITMAPS )
744                 rle_next = 0;
745
746         for (i=0; i<MAX_CACHE_BITMAPS; i++ )    {
747                 if (rle_cache[i].rle_bitmap == bmp)     {
748                         rle_hits++;
749                         rle_cache[i].last_used = rle_counter;
750                         return rle_cache[i].expanded_bitmap;
751                 }
752                 if ( rle_cache[i].last_used < lowest_count )    {
753                         lowest_count = rle_cache[i].last_used;
754                         least_recently_used = i;
755                 }
756         }
757
758         Assert(bmp->bm_w<=64 && bmp->bm_h<=64); //dest buffer is 64x64
759         rle_misses++;
760         rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap );
761         rle_cache[least_recently_used].rle_bitmap = bmp;
762         rle_cache[least_recently_used].last_used = rle_counter;
763         return rle_cache[least_recently_used].expanded_bitmap;
764 }
765
766
767 void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 )
768 {
769         int i = 0, j;
770         int count;
771         ubyte color=0;
772
773         if ( x2 < x1 ) return;
774
775         count = 0;
776         while ( i < x1 )        {
777                 color = *src++;
778                 if ( color == RLE_CODE ) return;
779                 if ( (color & RLE_CODE) == RLE_CODE )   {
780                         count = color & NOT_RLE_CODE;
781                         color = *src++;
782                 } else {
783                         // unique
784                         count = 1;
785                 }
786                 i += count;
787         }
788         count = i - x1;
789         i = x1;
790         // we know have '*count' pixels of 'color'.
791
792         if ( x1+count > x2 )    {
793                 count = x2-x1+1;
794                 for ( j=0; j<count; j++ )
795                         gr_bm_pixel( dest, dx++, dy, color );
796                 return;
797         }
798
799         for ( j=0; j<count; j++ )
800                 gr_bm_pixel( dest, dx++, dy, color );
801         i += count;
802
803         while( i <= x2 )                {
804                 color = *src++;
805                 if ( color == RLE_CODE ) return;
806                 if ( (color & RLE_CODE) == RLE_CODE )   {
807                         count = color & NOT_RLE_CODE;
808                         color = *src++;
809                 } else {
810                         // unique
811                         count = 1;
812                 }
813                 // we know have '*count' pixels of 'color'.
814                 if ( i+count <= x2 )    {
815                         for ( j=0; j<count; j++ )
816                                 gr_bm_pixel( dest, dx++, dy, color );
817                         i += count;
818                 } else {
819                         count = x2-i+1;
820                         for ( j=0; j<count; j++ )
821                                 gr_bm_pixel( dest, dx++, dy, color );
822                         i += count;
823                 }
824         }
825 }
826
827 void gr_rle_expand_scanline_generic_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2  )
828 {
829         int i = 0, j;
830         int count;
831         ubyte color = 0;
832
833         if ( x2 < x1 ) return;
834
835         count = 0;
836         while ( i < x1 )        {
837                 color = *src++;
838                 if ( color == RLE_CODE ) return;
839                 if ( (color & RLE_CODE) == RLE_CODE )   {
840                         count = color & NOT_RLE_CODE;
841                         color = *src++;
842                 } else {
843                         // unique
844                         count = 1;
845                 }
846                 i += count;
847         }
848         count = i - x1;
849         i = x1;
850         // we know have '*count' pixels of 'color'.
851
852         if ( x1+count > x2 )    {
853                 count = x2-x1+1;
854                 if (color != TRANSPARENCY_COLOR) {
855                         for ( j=0; j<count; j++ )
856                                 gr_bm_pixel( dest, dx++, dy, color );
857                 }
858                 return;
859         }
860
861         if ( color != TRANSPARENCY_COLOR ) {
862                 for ( j=0; j<count; j++ )
863                         gr_bm_pixel( dest, dx++, dy, color );
864         } else
865                 dx += count;
866         i += count;
867
868         while( i <= x2 )                {
869                 color = *src++;
870                 if ( color == RLE_CODE ) return;
871                 if ( (color & RLE_CODE) == RLE_CODE )   {
872                         count = color & NOT_RLE_CODE;
873                         color = *src++;
874                 } else {
875                         // unique
876                         count = 1;
877                 }
878                 // we know have '*count' pixels of 'color'.
879                 if ( i+count <= x2 )    {
880                         if ( color != TRANSPARENCY_COLOR ) {
881                                 for ( j=0; j<count; j++ )
882                                         gr_bm_pixel( dest, dx++, dy, color );
883                         } else
884                                 dx += count;
885                         i += count;
886                 } else {
887                         count = x2-i+1;
888                         if ( color != TRANSPARENCY_COLOR ) {
889                                 for ( j=0; j<count; j++ )
890                                         gr_bm_pixel( dest, dx++, dy, color );
891                         } else
892                                 dx += count;
893                         i += count;
894                 }
895         }
896 }
897
898
899 #ifdef __MSDOS__
900 void gr_rle_expand_scanline_svga_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2  )
901 {
902         int i = 0, j;
903         int count;
904         ubyte color;
905         ubyte * vram = (ubyte *)0xA0000;
906         int VideoLocation,page,offset;
907
908         if ( x2 < x1 ) return;
909
910         VideoLocation = (unsigned int)dest->bm_data + (dest->bm_rowsize * dy) + dx;
911         page    = VideoLocation >> 16;
912         offset  = VideoLocation & 0xFFFF;
913
914         gr_vesa_setpage( page );
915
916         if ( (offset + (x2-x1+1)) < 65536 )     {
917                 // We don't cross a svga page, so blit it fast!
918                 gr_rle_expand_scanline_masked( &vram[offset], src, x1, x2 );
919                 return;
920         }
921
922         count = 0;
923         while ( i < x1 )        {
924                 color = *src++;
925                 if ( color == RLE_CODE ) return;
926                 if ( (color & RLE_CODE) == RLE_CODE )   {
927                         count = color & NOT_RLE_CODE;
928                         color = *src++;
929                 } else {
930                         // unique
931                         count = 1;
932                 }
933                 i += count;
934         }
935         count = i - x1;
936         i = x1;
937         // we know have '*count' pixels of 'color'.
938
939         if ( x1+count > x2 )    {
940                 count = x2-x1+1;
941                 if (color != TRANSPARENCY_COLOR) {
942                         for ( j=0; j<count; j++ )       {
943                                 vram[offset++] = color;
944                                 if ( offset >= 65536 ) {
945                                         offset -= 65536;
946                                         page++;
947                                         gr_vesa_setpage(page);
948                                 }
949                         }
950                 }
951                 return;
952         }
953
954         if ( color != TRANSPARENCY_COLOR ) {
955                 for ( j=0; j<count; j++ )       {
956                         vram[offset++] = color;
957                         if ( offset >= 65536 ) {
958                                 offset -= 65536;
959                                 page++;
960                                 gr_vesa_setpage(page);
961                         }
962                 }
963         } else  {
964                 offset += count;
965                 if ( offset >= 65536 ) {
966                         offset -= 65536;
967                         page++;
968                         gr_vesa_setpage(page);
969                 }
970         }
971         i += count;
972
973         while( i <= x2 )                {
974                 color = *src++;
975                 if ( color == RLE_CODE ) return;
976                 if ( (color & RLE_CODE) == RLE_CODE )   {
977                         count = color & NOT_RLE_CODE;
978                         color = *src++;
979                 } else {
980                         // unique
981                         count = 1;
982                 }
983                 // we know have '*count' pixels of 'color'.
984                 if ( i+count <= x2 )    {
985                         if ( color != TRANSPARENCY_COLOR ) {
986                                 for ( j=0; j<count; j++ )       {
987                                         vram[offset++] = color;
988                                         if ( offset >= 65536 ) {
989                                                 offset -= 65536;
990                                                 page++;
991                                                 gr_vesa_setpage(page);
992                                         }
993                                 }
994                         } else  {
995                                 offset += count;
996                                 if ( offset >= 65536 ) {
997                                         offset -= 65536;
998                                         page++;
999                                         gr_vesa_setpage(page);
1000                                 }
1001                         }
1002                         i += count;
1003                 } else {
1004                         count = x2-i+1;
1005                         if ( color != TRANSPARENCY_COLOR ) {
1006                                 for ( j=0; j<count; j++ )       {
1007                                         vram[offset++] = color;
1008                                         if ( offset >= 65536 ) {
1009                                                 offset -= 65536;
1010                                                 page++;
1011                                                 gr_vesa_setpage(page);
1012                                         }
1013                                 }
1014                         } else  {
1015                                 offset += count;
1016                                 if ( offset >= 65536 ) {
1017                                         offset -= 65536;
1018                                         page++;
1019                                         gr_vesa_setpage(page);
1020                                 }
1021                         }
1022                         i += count;
1023                 }
1024         }
1025 }
1026 #endif // __MSDOS__
1027
1028
1029 /*
1030  * swaps entries 0 and 255 in an RLE bitmap without uncompressing it
1031  */
1032 void rle_swap_0_255(grs_bitmap *bmp)
1033 {
1034         int i, j, len, rle_big;
1035         unsigned char *ptr, *ptr2, *temp, *start;
1036         unsigned short line_size;
1037
1038         rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG;
1039
1040         temp = d_malloc(4 + bmp->bm_h + (bmp->bm_w + 1) * bmp->bm_h);
1041
1042         if (rle_big) {                  // set ptrs to first lines
1043                 ptr = bmp->bm_data + 4 + 2 * bmp->bm_h;
1044                 ptr2 = temp + 4 + 2 * bmp->bm_h;
1045         } else {
1046                 ptr = bmp->bm_data + 4 + bmp->bm_h;
1047                 ptr2 = temp + 4 + bmp->bm_h;
1048         }
1049         for (i = 0; i < bmp->bm_h; i++) {
1050                 start = ptr2;
1051                 if (rle_big)
1052                         line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i]));
1053                 else
1054                         line_size = bmp->bm_data[4 + i];
1055                 for (j = 0; j < line_size; j++) {
1056                         if ((ptr[j] & RLE_CODE) != RLE_CODE) {
1057                                 if (ptr[j] == 0) {
1058                                         *ptr2++ = RLE_CODE | 1;
1059                                         *ptr2++ = 255;
1060                                 } else
1061                                         *ptr2++ = ptr[j];
1062                         } else {
1063                                 *ptr2++ = ptr[j];
1064                                 if ((ptr[j] & NOT_RLE_CODE) == 0)
1065                                         break;
1066                                 j++;
1067                                 if (ptr[j] == 0)
1068                                         *ptr2++ = 255;
1069                                 else if (ptr[j] == 255)
1070                                         *ptr2++ = 0;
1071                                 else
1072                                         *ptr2++ = ptr[j];
1073                         }
1074                 }
1075                 if (rle_big)                // set line size
1076                         *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start);
1077                 else
1078                         temp[4 + i] = ptr2 - start;
1079                 ptr += line_size;           // go to next line
1080         }
1081         len = ptr2 - temp;
1082         *((int *)temp) = len;           // set total size
1083         memcpy(bmp->bm_data, temp, len);
1084         d_free(temp);
1085 }