1 /* $Id: rle.c,v 1.7 2002-08-17 11:19:56 btb 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.
17 * Changed shorts to ints in parameters.
26 static char rcsid[] = "$Id: rle.c,v 1.7 2002-08-17 11:19:56 btb Exp $";
43 //#define RLE_CODE 0xC0
44 //#define NOT_RLE_CODE 63
47 #define NOT_RLE_CODE 31
49 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 );
53 int gr_rle_decode_asm( ubyte * src, ubyte * dest );
54 #pragma aux gr_rle_decode_asm parm [esi] [edi] value [edi] modify exact [eax ebx ecx edx esi edi] = \
90 void rle_stosb(char *dest, int len, int color);
91 #pragma aux rle_stosb = "cld rep stosb" parm [edi] [ecx] [eax] modify exact [edi ecx];
92 #elif defined __GNUC__
93 static inline int gr_rle_decode_asm( ubyte * src, ubyte * dest ) {
96 __asm__ __volatile__ (
101 " movb %%al,(%%edi);"
104 " movb (%%esi), %%al;"
113 " movb (%%esi), %%al;"
119 " movb %%al, (%%edi);"
123 : "=D" (__ret), "=S" (dummy) : "1" (src), "D" (dest) : "%eax", "%ecx");
127 static inline void rle_stosb(char *dest, int len, int color) {
129 __asm__ __volatile__ (
131 : "=D" (dummy[0]), "=c" (dummy[1])
132 : "0" (dest), "1" (len), "a" (color) );
134 #elif defined _MSC_VER
135 __inline int gr_rle_decode_asm( ubyte * src, ubyte * dest )
174 __inline void rle_stosb(char *dest, int len, int color)
188 /* Well, if inline assembler is not supported for this compiler, we don't
189 **really** want ASM... */
194 void rle_stosb(ubyte *dest, int len, int color)
197 for (i=0; i<len; i++ )
202 void gr_rle_decode( ubyte * src, ubyte * dest )
206 ubyte data, count = 0;
210 if ( (data & RLE_CODE) != RLE_CODE ) {
213 count = data & NOT_RLE_CODE;
214 if (count==0) return;
216 for (i=0; i<count; i++ )
221 gr_rle_decode_asm( src, dest );
225 // Given pointer to start of one scanline of rle data, uncompress it to
226 // dest, from source pixels x1 to x2.
227 void gr_rle_expand_scanline_masked( ubyte *dest, ubyte *src, int x1, int x2 )
233 if ( x2 < x1 ) return;
237 if ( color == RLE_CODE ) return;
238 if ( (color & RLE_CODE)==RLE_CODE ) {
239 count = color & (~RLE_CODE);
249 // we know have '*count' pixels of 'color'.
251 if ( x1+count > x2 ) {
253 if ( color != 255 ) rle_stosb( dest, count, color );
257 if ( color != 255 ) rle_stosb( dest, count, color );
263 if ( color == RLE_CODE ) return;
264 if ( (color & RLE_CODE) == (RLE_CODE) ) {
265 count = color & (~RLE_CODE);
271 // we know have '*count' pixels of 'color'.
272 if ( i+count <= x2 ) {
273 if ( color != 255 )rle_stosb( dest, count, color );
278 if ( color != 255 )rle_stosb( dest, count, color );
286 void gr_rle_expand_scanline( ubyte *dest, ubyte *src, int x1, int x2 )
292 if ( x2 < x1 ) return;
296 if ( color == RLE_CODE ) return;
297 if ( (color & RLE_CODE)==RLE_CODE ) {
298 count = color & (~RLE_CODE);
308 // we know have '*count' pixels of 'color'.
310 if ( x1+count > x2 ) {
312 rle_stosb( dest, count, color );
316 rle_stosb( dest, count, color );
322 if ( color == RLE_CODE ) return;
323 if ( (color & RLE_CODE)==RLE_CODE ) {
324 count = color & (~RLE_CODE);
330 // we know have '*count' pixels of 'color'.
331 if ( i+count <= x2 ) {
332 rle_stosb( dest, count, color );
337 rle_stosb( dest, count, color );
345 int gr_rle_encode( int org_size, ubyte *src, ubyte *dest )
356 for (i=1; i<org_size; i++ ) {
360 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) ) {
362 Assert( oc != RLE_CODE );
373 if ( count == NOT_RLE_CODE ) {
381 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) ) {
383 Assert( oc != RLE_CODE );
392 return dest-dest_start;
396 int gr_rle_getsize( int org_size, ubyte *src )
406 for (i=1; i<org_size; i++ ) {
410 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) ) {
421 if ( count == NOT_RLE_CODE ) {
428 if ( (count==1) && ((oc & RLE_CODE)!=RLE_CODE) ) {
440 int gr_bitmap_rle_compress( grs_bitmap * bmp )
447 // first must check to see if this is large bitmap.
449 for (y=0; y<bmp->bm_h; y++ ) {
450 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
457 rle_data=d_malloc( (bmp->bm_w+1) * bmp->bm_h );
458 if (rle_data==NULL) return 0;
460 doffset = 4 + bmp->bm_h;
462 doffset = 4 + (2 * bmp->bm_h); // each row of rle'd bitmap has short instead of byte offset now
464 for (y=0; y<bmp->bm_h; y++ ) {
465 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
466 if ( ((doffset+d1) > bmp->bm_w*bmp->bm_h) || (d1 > (large_rle?32767:255) ) ) {
470 d = gr_rle_encode( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y], &rle_data[doffset] );
474 *((short *)&(rle_data[(y*2)+4])) = (short)d;
478 //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 );
479 memcpy( rle_data, &doffset, 4 );
480 memcpy( bmp->bm_data, rle_data, doffset );
482 bmp->bm_flags |= BM_FLAG_RLE;
484 bmp->bm_flags |= BM_FLAG_RLE_BIG;
488 #define MAX_CACHE_BITMAPS 32
490 typedef struct rle_cache_element {
491 grs_bitmap * rle_bitmap;
493 grs_bitmap * expanded_bitmap;
497 int rle_cache_initialized = 0;
500 rle_cache_element rle_cache[MAX_CACHE_BITMAPS];
505 void rle_cache_close(void)
507 if (rle_cache_initialized) {
509 rle_cache_initialized = 0;
510 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
511 gr_free_bitmap(rle_cache[i].expanded_bitmap);
516 void rle_cache_init()
519 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
520 rle_cache[i].rle_bitmap = NULL;
521 rle_cache[i].expanded_bitmap = gr_create_bitmap( 64, 64 );
522 rle_cache[i].last_used = 0;
523 Assert( rle_cache[i].expanded_bitmap != NULL );
525 rle_cache_initialized = 1;
526 atexit( rle_cache_close );
529 void rle_cache_flush()
532 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
533 rle_cache[i].rle_bitmap = NULL;
534 rle_cache[i].last_used = 0;
540 grs_bitmap * rle_expand_texture( grs_bitmap * bmp )
543 int lowest_count, lc;
544 int least_recently_used;
546 if (!rle_cache_initialized) rle_cache_init();
548 Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) );
552 if ( rle_counter < lc ) {
553 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
554 rle_cache[i].rle_bitmap = NULL;
555 rle_cache[i].last_used = 0;
559 // if (((rle_counter % 100)==1) && (rle_hits+rle_misses > 0))
560 // mprintf(( 0, "RLE-CACHE %d%%, H:%d, M:%d\n", (rle_misses*100)/(rle_hits+rle_misses), rle_hits, rle_misses ));
562 lowest_count = rle_cache[rle_next].last_used;
563 least_recently_used = rle_next;
565 if ( rle_next >= MAX_CACHE_BITMAPS )
568 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
569 if (rle_cache[i].rle_bitmap == bmp) {
571 rle_cache[i].last_used = rle_counter;
572 return rle_cache[i].expanded_bitmap;
574 if ( rle_cache[i].last_used < lowest_count ) {
575 lowest_count = rle_cache[i].last_used;
576 least_recently_used = i;
580 rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap );
581 rle_cache[least_recently_used].rle_bitmap = bmp;
582 rle_cache[least_recently_used].last_used = rle_counter;
583 return rle_cache[least_recently_used].expanded_bitmap;
586 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 )
588 unsigned char * dbits;
589 unsigned char * sbits;
592 unsigned char * dbits1;
596 Assert (bmp->iMagic == BM_MAGIC_NUMBER);
599 sbits = &bmp->bm_data[4 + 64];
600 dbits = rle_temp_bitmap_1->bm_data;
602 rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE);
604 for (i=0; i < 64; i++ ) {
606 gr_rle_decode(sbits,dbits);
608 dbits1=(unsigned char *)gr_rle_decode_asm( sbits, dbits );
610 sbits += (int)bmp->bm_data[4+i];
613 Assert( dbits == dbits1 ); // Get John, bogus rle data!
617 gr_set_bitmap_data (rle_temp_bitmap_1, rle_temp_bitmap_1->bm_data);
622 void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src,
623 int x1, int x2, int masked )
629 if ( x2 < x1 ) return;
633 if ( color == RLE_CODE ) return;
634 if ( (color & RLE_CODE) == RLE_CODE ) {
635 count = color & NOT_RLE_CODE;
645 // we know have '*count' pixels of 'color'.
647 if ( x1+count > x2 ) {
649 if (!masked || color != 255)
650 for ( j=0; j<count; j++ )
651 gr_bm_pixel( dest, dx++, dy, color );
655 if (masked && color == 255)
658 for ( j=0; j<count; j++ )
659 gr_bm_pixel( dest, dx++, dy, color );
664 if ( color == RLE_CODE ) return;
665 if ( (color & RLE_CODE) == RLE_CODE ) {
666 count = color & NOT_RLE_CODE;
672 // we know have '*count' pixels of 'color'.
673 if ( i+count <= x2 ) {
674 if (masked && color == 255)
677 for ( j=0; j<count; j++ )
678 gr_bm_pixel( dest, dx++, dy, color );
682 if (masked && color == 255)
685 for ( j=0; j<count; j++ )
686 gr_bm_pixel( dest, dx++, dy, color );
693 * swaps entries 0 and 255 in an RLE bitmap without uncompressing it
695 * doesn't handle RLE_BIG yet, but neither does anything else...
696 * LEAKS LOTS OF MEMORY!
698 void rle_swap_0_255(grs_bitmap *bmp)
701 unsigned char *ptr, *ptr2, *temp, *start;
703 if (bmp->bm_flags & BM_FLAG_RLE_BIG)
706 temp = d_malloc(4 + bmp->bm_h + (bmp->bm_w + 1) * bmp->bm_h);
709 ptr = bmp->bm_data + 4 + bmp->bm_h;
710 ptr2 = temp + 4 + bmp->bm_h;
711 for (i = 0; i < bmp->bm_h; i++) {
713 for (j = 0; j < bmp->bm_data[4 + i]; j++) {
714 if ((ptr[j] & RLE_CODE) != RLE_CODE) {
716 *ptr2++ = RLE_CODE | 1;
722 if ((ptr[j] & NOT_RLE_CODE) == 0)
727 else if (ptr[j] == 255)
733 temp[4 + i] = ptr2 - start;
734 *((int *)temp) += ptr2 - start;
735 ptr += bmp->bm_data[4 + i];