1 /* $Id: rle.c,v 1.6 2002-08-15 08:53:11 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.6 2002-08-15 08:53:11 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 )
446 rle_data=d_malloc( (bmp->bm_w+1)* bmp->bm_h );
447 if (rle_data==NULL) return 0;
448 doffset = 4 + bmp->bm_h;
449 for (y=0; y<bmp->bm_h; y++ ) {
450 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
451 if ( ((doffset+d1) > bmp->bm_w*bmp->bm_h) || (d1 > 255 ) ) {
455 d = gr_rle_encode( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y], &rle_data[doffset] );
460 //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 );
461 memcpy( rle_data, &doffset, 4 );
462 memcpy( bmp->bm_data, rle_data, doffset );
464 bmp->bm_flags |= BM_FLAG_RLE;
468 #define MAX_CACHE_BITMAPS 32
470 typedef struct rle_cache_element {
471 grs_bitmap * rle_bitmap;
473 grs_bitmap * expanded_bitmap;
477 int rle_cache_initialized = 0;
480 rle_cache_element rle_cache[MAX_CACHE_BITMAPS];
485 void rle_cache_close(void)
487 if (rle_cache_initialized) {
489 rle_cache_initialized = 0;
490 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
491 gr_free_bitmap(rle_cache[i].expanded_bitmap);
496 void rle_cache_init()
499 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
500 rle_cache[i].rle_bitmap = NULL;
501 rle_cache[i].expanded_bitmap = gr_create_bitmap( 64, 64 );
502 rle_cache[i].last_used = 0;
503 Assert( rle_cache[i].expanded_bitmap != NULL );
505 rle_cache_initialized = 1;
506 atexit( rle_cache_close );
509 void rle_cache_flush()
512 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
513 rle_cache[i].rle_bitmap = NULL;
514 rle_cache[i].last_used = 0;
520 grs_bitmap * rle_expand_texture( grs_bitmap * bmp )
523 int lowest_count, lc;
524 int least_recently_used;
526 if (!rle_cache_initialized) rle_cache_init();
528 Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) );
532 if ( rle_counter < lc ) {
533 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
534 rle_cache[i].rle_bitmap = NULL;
535 rle_cache[i].last_used = 0;
539 // if (((rle_counter % 100)==1) && (rle_hits+rle_misses > 0))
540 // mprintf(( 0, "RLE-CACHE %d%%, H:%d, M:%d\n", (rle_misses*100)/(rle_hits+rle_misses), rle_hits, rle_misses ));
542 lowest_count = rle_cache[rle_next].last_used;
543 least_recently_used = rle_next;
545 if ( rle_next >= MAX_CACHE_BITMAPS )
548 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
549 if (rle_cache[i].rle_bitmap == bmp) {
551 rle_cache[i].last_used = rle_counter;
552 return rle_cache[i].expanded_bitmap;
554 if ( rle_cache[i].last_used < lowest_count ) {
555 lowest_count = rle_cache[i].last_used;
556 least_recently_used = i;
560 rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap );
561 rle_cache[least_recently_used].rle_bitmap = bmp;
562 rle_cache[least_recently_used].last_used = rle_counter;
563 return rle_cache[least_recently_used].expanded_bitmap;
566 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 )
568 unsigned char * dbits;
569 unsigned char * sbits;
572 unsigned char * dbits1;
576 Assert (bmp->iMagic == BM_MAGIC_NUMBER);
579 sbits = &bmp->bm_data[4 + 64];
580 dbits = rle_temp_bitmap_1->bm_data;
582 rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE);
584 for (i=0; i < 64; i++ ) {
586 gr_rle_decode(sbits,dbits);
588 dbits1=(unsigned char *)gr_rle_decode_asm( sbits, dbits );
590 sbits += (int)bmp->bm_data[4+i];
593 Assert( dbits == dbits1 ); // Get John, bogus rle data!
597 gr_set_bitmap_data (rle_temp_bitmap_1, rle_temp_bitmap_1->bm_data);
602 void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src,
603 int x1, int x2, int masked )
609 if ( x2 < x1 ) return;
613 if ( color == RLE_CODE ) return;
614 if ( (color & RLE_CODE) == RLE_CODE ) {
615 count = color & NOT_RLE_CODE;
625 // we know have '*count' pixels of 'color'.
627 if ( x1+count > x2 ) {
629 if (!masked || color != 255)
630 for ( j=0; j<count; j++ )
631 gr_bm_pixel( dest, dx++, dy, color );
635 if (masked && color == 255)
638 for ( j=0; j<count; j++ )
639 gr_bm_pixel( dest, dx++, dy, color );
644 if ( color == RLE_CODE ) return;
645 if ( (color & RLE_CODE) == RLE_CODE ) {
646 count = color & NOT_RLE_CODE;
652 // we know have '*count' pixels of 'color'.
653 if ( i+count <= x2 ) {
654 if (masked && color == 255)
657 for ( j=0; j<count; j++ )
658 gr_bm_pixel( dest, dx++, dy, color );
662 if (masked && color == 255)
665 for ( j=0; j<count; j++ )
666 gr_bm_pixel( dest, dx++, dy, color );
673 * swaps entries 0 and 255 in an RLE bitmap without uncompressing it
675 * doesn't handle RLE_BIG yet, but neither does anything else...
676 * LEAKS LOTS OF MEMORY!
678 void rle_swap_0_255(grs_bitmap *bmp)
681 unsigned char *ptr, *ptr2, *temp, *start;
683 if (bmp->bm_flags & BM_FLAG_RLE_BIG)
686 temp = d_malloc(4 + bmp->bm_h + (bmp->bm_w + 1) * bmp->bm_h);
689 ptr = bmp->bm_data + 4 + bmp->bm_h;
690 ptr2 = temp + 4 + bmp->bm_h;
691 for (i = 0; i < bmp->bm_h; i++) {
693 for (j = 0; j < bmp->bm_data[4 + i]; j++) {
694 if ((ptr[j] & RLE_CODE) != RLE_CODE) {
696 *ptr2++ = RLE_CODE | 1;
702 if ((ptr[j] & NOT_RLE_CODE) == 0)
707 else if (ptr[j] == 255)
713 temp[4 + i] = ptr2 - start;
714 *((int *)temp) += ptr2 - start;
715 ptr += bmp->bm_data[4 + i];