1 /* $Id: rle.c,v 1.4 2002-07-17 21:55:19 bradleyb Exp $ */
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.
15 * Changed shorts to ints in parameters.
24 static char rcsid[] = "$Id: rle.c,v 1.4 2002-07-17 21:55:19 bradleyb Exp $";
41 //#define RLE_CODE 0xC0
42 //#define NOT_RLE_CODE 63
45 #define NOT_RLE_CODE 31
47 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 );
51 int gr_rle_decode_asm( ubyte * src, ubyte * dest );
52 #pragma aux gr_rle_decode_asm parm [esi] [edi] value [edi] modify exact [eax ebx ecx edx esi edi] = \
88 void rle_stosb(char *dest, int len, int color);
89 #pragma aux rle_stosb = "cld rep stosb" parm [edi] [ecx] [eax] modify exact [edi ecx];
90 #elif defined __GNUC__
91 static inline int gr_rle_decode_asm( ubyte * src, ubyte * dest ) {
94 __asm__ __volatile__ (
102 " movb (%%esi), %%al;"
111 " movb (%%esi), %%al;"
117 " movb %%al, (%%edi);"
121 : "=D" (__ret), "=S" (dummy) : "1" (src), "D" (dest) : "%eax", "%ecx");
125 static inline void rle_stosb(char *dest, int len, int color) {
127 __asm__ __volatile__ (
129 : "=D" (dummy[0]), "=c" (dummy[1])
130 : "0" (dest), "1" (len), "a" (color) );
132 #elif defined _MSC_VER
133 __inline int gr_rle_decode_asm( ubyte * src, ubyte * dest )
172 __inline void rle_stosb(char *dest, int len, int color)
186 /* Well, if inline assembler is not supported for this compiler, we don't
187 **really** want ASM... */
192 void rle_stosb(ubyte *dest, int len, int color)
195 for (i=0; i<len; i++ )
200 void gr_rle_decode( ubyte * src, ubyte * dest )
204 ubyte data, count = 0;
208 if ( (data & RLE_CODE) != RLE_CODE ) {
211 count = data & NOT_RLE_CODE;
212 if (count==0) return;
214 for (i=0; i<count; i++ )
219 gr_rle_decode_asm( src, dest );
223 // Given pointer to start of one scanline of rle data, uncompress it to
224 // dest, from source pixels x1 to x2.
225 void gr_rle_expand_scanline_masked( ubyte *dest, ubyte *src, int x1, int x2 )
231 if ( x2 < x1 ) return;
235 if ( color == RLE_CODE ) return;
236 if ( (color & RLE_CODE)==RLE_CODE ) {
237 count = color & (~RLE_CODE);
247 // we know have '*count' pixels of 'color'.
249 if ( x1+count > x2 ) {
251 if ( color != 255 ) rle_stosb( dest, count, color );
255 if ( color != 255 ) rle_stosb( dest, count, color );
261 if ( color == RLE_CODE ) return;
262 if ( (color & RLE_CODE) == (RLE_CODE) ) {
263 count = color & (~RLE_CODE);
269 // we know have '*count' pixels of 'color'.
270 if ( i+count <= x2 ) {
271 if ( color != 255 )rle_stosb( dest, count, color );
276 if ( color != 255 )rle_stosb( dest, count, color );
284 void gr_rle_expand_scanline( ubyte *dest, ubyte *src, int x1, int x2 )
290 if ( x2 < x1 ) return;
294 if ( color == RLE_CODE ) return;
295 if ( (color & RLE_CODE)==RLE_CODE ) {
296 count = color & (~RLE_CODE);
306 // we know have '*count' pixels of 'color'.
308 if ( x1+count > x2 ) {
310 rle_stosb( dest, count, color );
314 rle_stosb( dest, count, color );
320 if ( color == RLE_CODE ) return;
321 if ( (color & RLE_CODE)==RLE_CODE ) {
322 count = color & (~RLE_CODE);
328 // we know have '*count' pixels of 'color'.
329 if ( i+count <= x2 ) {
330 rle_stosb( dest, count, color );
335 rle_stosb( dest, count, color );
343 int gr_rle_encode( int org_size, ubyte *src, ubyte *dest )
354 for (i=1; i<org_size; i++ ) {
358 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) ) {
360 Assert( oc != RLE_CODE );
371 if ( count == NOT_RLE_CODE ) {
379 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) ) {
381 Assert( oc != RLE_CODE );
390 return dest-dest_start;
394 int gr_rle_getsize( int org_size, ubyte *src )
404 for (i=1; i<org_size; i++ ) {
408 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) ) {
419 if ( count == NOT_RLE_CODE ) {
426 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) ) {
438 int gr_bitmap_rle_compress( grs_bitmap * bmp )
444 rle_data=d_malloc( (bmp->bm_w+1)* bmp->bm_h );
445 if (rle_data==NULL) return 0;
446 doffset = 4 + bmp->bm_h;
447 for (y=0; y<bmp->bm_h; y++ ) {
448 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
449 if ( ((doffset+d1) > bmp->bm_w*bmp->bm_h) || (d1 > 255 ) ) {
453 d = gr_rle_encode( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y], &rle_data[doffset] );
458 //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 );
459 memcpy( rle_data, &doffset, 4 );
460 memcpy( bmp->bm_data, rle_data, doffset );
462 bmp->bm_flags |= BM_FLAG_RLE;
466 #define MAX_CACHE_BITMAPS 32
468 typedef struct rle_cache_element {
469 grs_bitmap * rle_bitmap;
471 grs_bitmap * expanded_bitmap;
475 int rle_cache_initialized = 0;
478 rle_cache_element rle_cache[MAX_CACHE_BITMAPS];
483 void rle_cache_close(void)
485 if (rle_cache_initialized) {
487 rle_cache_initialized = 0;
488 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
489 gr_free_bitmap(rle_cache[i].expanded_bitmap);
494 void rle_cache_init()
497 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
498 rle_cache[i].rle_bitmap = NULL;
499 rle_cache[i].expanded_bitmap = gr_create_bitmap( 64, 64 );
500 rle_cache[i].last_used = 0;
501 Assert( rle_cache[i].expanded_bitmap != NULL );
503 rle_cache_initialized = 1;
504 atexit( rle_cache_close );
507 void rle_cache_flush()
510 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
511 rle_cache[i].rle_bitmap = NULL;
512 rle_cache[i].last_used = 0;
518 grs_bitmap * rle_expand_texture( grs_bitmap * bmp )
521 int lowest_count, lc;
522 int least_recently_used;
524 if (!rle_cache_initialized) rle_cache_init();
526 Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) );
530 if ( rle_counter < lc ) {
531 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
532 rle_cache[i].rle_bitmap = NULL;
533 rle_cache[i].last_used = 0;
537 // if (((rle_counter % 100)==1) && (rle_hits+rle_misses > 0))
538 // mprintf(( 0, "RLE-CACHE %d%%, H:%d, M:%d\n", (rle_misses*100)/(rle_hits+rle_misses), rle_hits, rle_misses ));
540 lowest_count = rle_cache[rle_next].last_used;
541 least_recently_used = rle_next;
543 if ( rle_next >= MAX_CACHE_BITMAPS )
546 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
547 if (rle_cache[i].rle_bitmap == bmp) {
549 rle_cache[i].last_used = rle_counter;
550 return rle_cache[i].expanded_bitmap;
552 if ( rle_cache[i].last_used < lowest_count ) {
553 lowest_count = rle_cache[i].last_used;
554 least_recently_used = i;
558 rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap );
559 rle_cache[least_recently_used].rle_bitmap = bmp;
560 rle_cache[least_recently_used].last_used = rle_counter;
561 return rle_cache[least_recently_used].expanded_bitmap;
564 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 )
566 unsigned char * dbits;
567 unsigned char * sbits;
570 unsigned char * dbits1;
574 Assert (bmp->iMagic == BM_MAGIC_NUMBER);
577 sbits = &bmp->bm_data[4 + 64];
578 dbits = rle_temp_bitmap_1->bm_data;
580 rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE);
582 for (i=0; i < 64; i++ ) {
584 gr_rle_decode(sbits,dbits);
586 dbits1=(unsigned char *)gr_rle_decode_asm( sbits, dbits );
588 sbits += (int)bmp->bm_data[4+i];
591 Assert( dbits == dbits1 ); // Get John, bogus rle data!
595 gr_set_bitmap_data (rle_temp_bitmap_1, rle_temp_bitmap_1->bm_data);
600 void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src,
601 int x1, int x2, int masked )
607 if ( x2 < x1 ) return;
611 if ( color == RLE_CODE ) return;
612 if ( (color & RLE_CODE) == RLE_CODE ) {
613 count = color & NOT_RLE_CODE;
623 // we know have '*count' pixels of 'color'.
625 if ( x1+count > x2 ) {
627 if (!masked || color != 255)
628 for ( j=0; j<count; j++ )
629 gr_bm_pixel( dest, dx++, dy, color );
633 if (masked && color == 255)
636 for ( j=0; j<count; j++ )
637 gr_bm_pixel( dest, dx++, dy, color );
642 if ( color == RLE_CODE ) return;
643 if ( (color & RLE_CODE) == RLE_CODE ) {
644 count = color & NOT_RLE_CODE;
650 // we know have '*count' pixels of 'color'.
651 if ( i+count <= x2 ) {
652 if (masked && color == 255)
655 for ( j=0; j<count; j++ )
656 gr_bm_pixel( dest, dx++, dy, color );
660 if (masked && color == 255)
663 for ( j=0; j<count; j++ )
664 gr_bm_pixel( dest, dx++, dy, color );