2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
16 * Routines to do run length encoding/decoding
43 #define NOT_RLE_CODE 31
45 #define IS_RLE_CODE(x) (((x) & RLE_CODE) == RLE_CODE)
47 #if !defined(NO_ASM) && defined(__WATCOMC__)
48 #define RLE_DECODE_ASM
50 ubyte *gr_rle_decode_asm( ubyte * src, ubyte * dest );
51 #pragma aux gr_rle_decode_asm parm [esi] [edi] value [edi] modify exact [eax ebx ecx edx esi edi] = \
87 #elif !defined(NO_ASM) && defined(__GNUC__)
88 #define RLE_DECODE_ASM
90 static inline int gr_rle_decode_asm( ubyte * src, ubyte * dest ) {
93 __asm__ __volatile__ (
101 " movb (%%esi), %%al;"
110 " movb (%%esi), %%al;"
116 " movb %%al, (%%edi);"
120 : "=D" (__ret), "=S" (dummy) : "1" (src), "D" (dest) : "%eax", "%ecx");
124 #elif !defined(NO_ASM) && defined(_MSC_VER)
125 #define RLE_DECODE_ASM
127 __inline int gr_rle_decode_asm( ubyte * src, ubyte * dest )
168 #ifdef RLE_DECODE_ASM
171 void gr_rle_decode( ubyte * src, ubyte * dest, int dest_len )
175 dest_end = (ubyte *)gr_rle_decode_asm( src, dest );
177 Assert(dest_end-src < dest_len);
180 void gr_rle_decode( ubyte * src, ubyte * dest )
182 gr_rle_decode_asm( src, dest );
186 #else // NO_ASM or unknown compiler
188 void gr_rle_decode( ubyte * src, ubyte * dest )
191 ubyte data, count = 0;
195 if ( ! IS_RLE_CODE(data) ) {
198 count = data & NOT_RLE_CODE;
202 for (i = 0; i < count; i++)
210 void rle_stosb (unsigned char *dest, int len, int color);
212 #if !defined(NO_ASM) && defined(__WATCOMC__)
214 #pragma aux rle_stosb = "cld rep stosb" parm [edi] [ecx] [eax] modify exact [edi ecx];
216 #elif !defined(NO_ASM) && defined(__GNUC__)
218 inline void rle_stosb (unsigned char *dest, int len, int color) {
220 __asm__ __volatile__ (
222 : "=D" (dummy[0]), "=c" (dummy[1])
223 : "0" (dest), "1" (len), "a" (color) );
226 #elif !defined(NO_ASM) && defined(_MSC_VER)
228 __inline void rle_stosb (unsigned char *dest, int len, int color)
239 #else // NO_ASM or unknown compiler
241 void rle_stosb (unsigned char *dest, int len, int color)
244 for (i=0; i<len; i++ )
250 // Given pointer to start of one scanline of rle data, uncompress it to
251 // dest, from source pixels x1 to x2.
252 void gr_rle_expand_scanline_masked( ubyte *dest, ubyte *src, int x1, int x2 )
258 if ( x2 < x1 ) return;
263 if ( color == RLE_CODE ) return;
264 if ( IS_RLE_CODE(color) ) {
265 count = color & (~RLE_CODE);
275 // we know have '*count' pixels of 'color'.
277 if ( x1+count > x2 ) {
279 if ( color != TRANSPARENCY_COLOR ) rle_stosb( dest, count, color );
283 if ( color != TRANSPARENCY_COLOR ) rle_stosb( dest, count, color );
289 if ( color == RLE_CODE ) return;
290 if ( IS_RLE_CODE(color) ) {
291 count = color & (~RLE_CODE);
297 // we know have '*count' pixels of 'color'.
298 if ( i+count <= x2 ) {
299 if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
304 if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
312 void gr_rle_expand_scanline( ubyte *dest, ubyte *src, int x1, int x2 )
318 if ( x2 < x1 ) return;
323 if ( color == RLE_CODE ) return;
324 if ( IS_RLE_CODE(color) ) {
325 count = color & (~RLE_CODE);
335 // we know have '*count' pixels of 'color'.
337 if ( x1+count > x2 ) {
339 rle_stosb( dest, count, color );
343 rle_stosb( dest, count, color );
349 if ( color == RLE_CODE ) return;
350 if ( IS_RLE_CODE(color) ) {
351 count = color & (~RLE_CODE);
357 // we know have '*count' pixels of 'color'.
358 if ( i+count <= x2 ) {
359 rle_stosb( dest, count, color );
364 rle_stosb( dest, count, color );
372 int gr_rle_encode( int org_size, ubyte *src, ubyte *dest )
383 for (i=1; i<org_size; i++ ) {
387 if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
389 Assert( oc != RLE_CODE );
400 if ( count == NOT_RLE_CODE ) {
408 if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
410 Assert( oc != RLE_CODE );
419 return dest-dest_start;
423 int gr_rle_getsize( int org_size, ubyte *src )
433 for (i=1; i<org_size; i++ ) {
437 if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
448 if ( count == NOT_RLE_CODE ) {
455 if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
467 int gr_bitmap_rle_compress( grs_bitmap * bmp )
474 // first must check to see if this is large bitmap.
476 for (y=0; y<bmp->bm_h; y++ ) {
477 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
484 rle_data=d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) );
485 if (rle_data==NULL) return 0;
487 doffset = 4 + bmp->bm_h;
489 doffset = 4 + (2 * bmp->bm_h); // each row of rle'd bitmap has short instead of byte offset now
491 for (y=0; y<bmp->bm_h; y++ ) {
492 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
493 if ( ((doffset+d1) > bmp->bm_w*bmp->bm_h) || (d1 > (large_rle?32767:255) ) ) {
497 d = gr_rle_encode( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y], &rle_data[doffset] );
501 *((short *)&(rle_data[(y*2)+4])) = (short)d;
505 //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 );
506 memcpy( rle_data, &doffset, 4 );
507 memcpy( bmp->bm_data, rle_data, doffset );
509 bmp->bm_flags |= BM_FLAG_RLE;
511 bmp->bm_flags |= BM_FLAG_RLE_BIG;
515 #define MAX_CACHE_BITMAPS 32
517 typedef struct rle_cache_element {
518 grs_bitmap * rle_bitmap;
520 grs_bitmap * expanded_bitmap;
524 int rle_cache_initialized = 0;
527 rle_cache_element rle_cache[MAX_CACHE_BITMAPS];
532 void rle_cache_close(void)
534 if (rle_cache_initialized) {
536 rle_cache_initialized = 0;
537 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
538 gr_free_bitmap(rle_cache[i].expanded_bitmap);
543 void rle_cache_init()
546 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
547 rle_cache[i].rle_bitmap = NULL;
548 rle_cache[i].expanded_bitmap = gr_create_bitmap( 64, 64 );
549 rle_cache[i].last_used = 0;
550 Assert( rle_cache[i].expanded_bitmap != NULL );
552 rle_cache_initialized = 1;
553 atexit( rle_cache_close );
556 void rle_cache_flush()
559 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
560 rle_cache[i].rle_bitmap = NULL;
561 rle_cache[i].last_used = 0;
565 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 )
567 unsigned char * dbits;
568 unsigned char * sbits;
570 #ifdef RLE_DECODE_ASM
571 unsigned char * dbits1;
574 sbits = &bmp->bm_data[4 + bmp->bm_h];
575 dbits = rle_temp_bitmap_1->bm_data;
577 rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE);
579 for (i=0; i < bmp->bm_h; i++ ) {
580 #ifdef RLE_DECODE_ASM
581 dbits1=(unsigned char *)gr_rle_decode_asm( sbits, dbits );
583 gr_rle_decode( sbits, dbits );
585 sbits += (int)bmp->bm_data[4+i];
587 #ifdef RLE_DECODE_ASM
588 Assert( dbits == dbits1 ); // Get John, bogus rle data!
594 grs_bitmap * rle_expand_texture( grs_bitmap * bmp )
597 int lowest_count, lc;
598 int least_recently_used;
600 if (!rle_cache_initialized) rle_cache_init();
602 Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) );
606 if ( rle_counter < lc ) {
607 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
608 rle_cache[i].rle_bitmap = NULL;
609 rle_cache[i].last_used = 0;
613 // if (((rle_counter % 100)==1) && (rle_hits+rle_misses > 0))
614 // mprintf(( 0, "RLE-CACHE %d%%, H:%d, M:%d\n", (rle_misses*100)/(rle_hits+rle_misses), rle_hits, rle_misses ));
616 lowest_count = rle_cache[rle_next].last_used;
617 least_recently_used = rle_next;
619 if ( rle_next >= MAX_CACHE_BITMAPS )
622 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
623 if (rle_cache[i].rle_bitmap == bmp) {
625 rle_cache[i].last_used = rle_counter;
626 return rle_cache[i].expanded_bitmap;
628 if ( rle_cache[i].last_used < lowest_count ) {
629 lowest_count = rle_cache[i].last_used;
630 least_recently_used = i;
634 Assert(bmp->bm_w<=64 && bmp->bm_h<=64); //dest buffer is 64x64
636 rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap );
637 rle_cache[least_recently_used].rle_bitmap = bmp;
638 rle_cache[least_recently_used].last_used = rle_counter;
639 return rle_cache[least_recently_used].expanded_bitmap;
643 void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 )
649 if ( x2 < x1 ) return;
654 if ( color == RLE_CODE ) return;
655 if ( IS_RLE_CODE(color) ) {
656 count = color & NOT_RLE_CODE;
666 // we know have '*count' pixels of 'color'.
668 if ( x1+count > x2 ) {
670 for ( j=0; j<count; j++ )
671 gr_bm_pixel( dest, dx++, dy, color );
675 for ( j=0; j<count; j++ )
676 gr_bm_pixel( dest, dx++, dy, color );
681 if ( color == RLE_CODE ) return;
682 if ( IS_RLE_CODE(color) ) {
683 count = color & NOT_RLE_CODE;
689 // we know have '*count' pixels of 'color'.
690 if ( i+count <= x2 ) {
691 for ( j=0; j<count; j++ )
692 gr_bm_pixel( dest, dx++, dy, color );
696 for ( j=0; j<count; j++ )
697 gr_bm_pixel( dest, dx++, dy, color );
703 void gr_rle_expand_scanline_generic_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 )
709 if ( x2 < x1 ) return;
714 if ( color == RLE_CODE ) return;
715 if ( IS_RLE_CODE(color) ) {
716 count = color & NOT_RLE_CODE;
726 // we know have '*count' pixels of 'color'.
728 if ( x1+count > x2 ) {
730 if (color != TRANSPARENCY_COLOR) {
731 for ( j=0; j<count; j++ )
732 gr_bm_pixel( dest, dx++, dy, color );
737 if ( color != TRANSPARENCY_COLOR ) {
738 for ( j=0; j<count; j++ )
739 gr_bm_pixel( dest, dx++, dy, color );
746 if ( color == RLE_CODE ) return;
747 if ( IS_RLE_CODE(color) ) {
748 count = color & NOT_RLE_CODE;
754 // we know have '*count' pixels of 'color'.
755 if ( i+count <= x2 ) {
756 if ( color != TRANSPARENCY_COLOR ) {
757 for ( j=0; j<count; j++ )
758 gr_bm_pixel( dest, dx++, dy, color );
764 if ( color != TRANSPARENCY_COLOR ) {
765 for ( j=0; j<count; j++ )
766 gr_bm_pixel( dest, dx++, dy, color );
776 void gr_rle_expand_scanline_svga_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 )
781 ubyte * vram = (ubyte *)0xA0000;
782 int VideoLocation,page,offset;
784 if ( x2 < x1 ) return;
786 VideoLocation = (unsigned int)dest->bm_data + (dest->bm_rowsize * dy) + dx;
787 page = VideoLocation >> 16;
788 offset = VideoLocation & 0xFFFF;
790 gr_vesa_setpage( page );
792 if ( (offset + (x2-x1+1)) < 65536 ) {
793 // We don't cross a svga page, so blit it fast!
794 gr_rle_expand_scanline_masked( &vram[offset], src, x1, x2 );
801 if ( color == RLE_CODE ) return;
802 if ( IS_RLE_CODE(color) ) {
803 count = color & NOT_RLE_CODE;
813 // we know have '*count' pixels of 'color'.
815 if ( x1+count > x2 ) {
817 if (color != TRANSPARENCY_COLOR) {
818 for ( j=0; j<count; j++ ) {
819 vram[offset++] = color;
820 if ( offset >= 65536 ) {
823 gr_vesa_setpage(page);
830 if ( color != TRANSPARENCY_COLOR ) {
831 for ( j=0; j<count; j++ ) {
832 vram[offset++] = color;
833 if ( offset >= 65536 ) {
836 gr_vesa_setpage(page);
841 if ( offset >= 65536 ) {
844 gr_vesa_setpage(page);
851 if ( color == RLE_CODE ) return;
852 if ( IS_RLE_CODE(color) ) {
853 count = color & NOT_RLE_CODE;
859 // we know have '*count' pixels of 'color'.
860 if ( i+count <= x2 ) {
861 if ( color != TRANSPARENCY_COLOR ) {
862 for ( j=0; j<count; j++ ) {
863 vram[offset++] = color;
864 if ( offset >= 65536 ) {
867 gr_vesa_setpage(page);
872 if ( offset >= 65536 ) {
875 gr_vesa_setpage(page);
881 if ( color != TRANSPARENCY_COLOR ) {
882 for ( j=0; j<count; j++ ) {
883 vram[offset++] = color;
884 if ( offset >= 65536 ) {
887 gr_vesa_setpage(page);
892 if ( offset >= 65536 ) {
895 gr_vesa_setpage(page);
906 * swaps entries 0 and 255 in an RLE bitmap without uncompressing it
908 void rle_swap_0_255(grs_bitmap *bmp)
910 int i, j, len, rle_big;
911 unsigned char *ptr, *ptr2, *temp, *start;
912 unsigned short line_size;
914 rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG;
916 temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) );
918 if (rle_big) { // set ptrs to first lines
919 ptr = bmp->bm_data + 4 + 2 * bmp->bm_h;
920 ptr2 = temp + 4 + 2 * bmp->bm_h;
922 ptr = bmp->bm_data + 4 + bmp->bm_h;
923 ptr2 = temp + 4 + bmp->bm_h;
925 for (i = 0; i < bmp->bm_h; i++) {
928 line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i]));
930 line_size = bmp->bm_data[4 + i];
931 for (j = 0; j < line_size; j++) {
932 if ( ! IS_RLE_CODE(ptr[j]) ) {
934 *ptr2++ = RLE_CODE | 1;
940 if ((ptr[j] & NOT_RLE_CODE) == 0)
945 else if (ptr[j] == 255)
951 if (rle_big) // set line size
952 *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start);
954 temp[4 + i] = ptr2 - start;
955 ptr += line_size; // go to next line
958 *((int *)temp) = len; // set total size
959 memcpy(bmp->bm_data, temp, len);
964 * remaps all entries using colormap in an RLE bitmap without uncompressing it
966 void rle_remap(grs_bitmap *bmp, ubyte *colormap)
968 int i, j, len, rle_big;
969 unsigned char *ptr, *ptr2, *temp, *start;
970 unsigned short line_size;
972 rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG;
974 temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) + 30000 );
976 if (rle_big) { // set ptrs to first lines
977 ptr = bmp->bm_data + 4 + 2 * bmp->bm_h;
978 ptr2 = temp + 4 + 2 * bmp->bm_h;
980 ptr = bmp->bm_data + 4 + bmp->bm_h;
981 ptr2 = temp + 4 + bmp->bm_h;
983 for (i = 0; i < bmp->bm_h; i++) {
986 line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i]));
988 line_size = bmp->bm_data[4 + i];
989 for (j = 0; j < line_size; j++) {
990 if ( ! IS_RLE_CODE(ptr[j])) {
991 if (IS_RLE_CODE(colormap[ptr[j]]))
992 *ptr2++ = RLE_CODE | 1; // add "escape sequence"
993 *ptr2++ = colormap[ptr[j]]; // translate
995 *ptr2++ = ptr[j]; // just copy current rle code
996 if ((ptr[j] & NOT_RLE_CODE) == 0)
999 *ptr2++ = colormap[ptr[j]]; // translate
1002 if (rle_big) // set line size
1003 *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start);
1005 temp[4 + i] = ptr2 - start;
1006 ptr += line_size; // go to next line
1009 *((int *)temp) = len; // set total size
1010 memcpy(bmp->bm_data, temp, len);