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
39 #define NOT_RLE_CODE 31
41 #define IS_RLE_CODE(x) (((x) & RLE_CODE) == RLE_CODE)
43 #if !defined(NO_ASM) && defined(__WATCOMC__)
44 #define RLE_DECODE_ASM
46 ubyte *gr_rle_decode_asm( ubyte * src, ubyte * dest );
47 #pragma aux gr_rle_decode_asm parm [esi] [edi] value [edi] modify exact [eax ebx ecx edx esi edi] = \
83 #elif !defined(NO_ASM) && defined(__GNUC__)
84 #define RLE_DECODE_ASM
86 static inline int gr_rle_decode_asm( ubyte * src, ubyte * dest ) {
89 __asm__ __volatile__ (
97 " movb (%%esi), %%al;"
106 " movb (%%esi), %%al;"
112 " movb %%al, (%%edi);"
116 : "=D" (__ret), "=S" (dummy) : "1" (src), "D" (dest) : "%eax", "%ecx");
120 #elif !defined(NO_ASM) && defined(_MSC_VER)
121 #define RLE_DECODE_ASM
123 __inline int gr_rle_decode_asm( ubyte * src, ubyte * dest )
164 #ifdef RLE_DECODE_ASM
167 void gr_rle_decode( ubyte * src, ubyte * dest, int dest_len )
171 dest_end = (ubyte *)gr_rle_decode_asm( src, dest );
173 Assert(dest_end-src < dest_len);
176 void gr_rle_decode( ubyte * src, ubyte * dest )
178 gr_rle_decode_asm( src, dest );
182 #else // NO_ASM or unknown compiler
184 void gr_rle_decode( ubyte * src, ubyte * dest )
187 ubyte data, count = 0;
191 if ( ! IS_RLE_CODE(data) ) {
194 count = data & NOT_RLE_CODE;
198 for (i = 0; i < count; i++)
206 void rle_stosb (unsigned char *dest, int len, int color);
208 #if !defined(NO_ASM) && defined(__WATCOMC__)
210 #pragma aux rle_stosb = "cld rep stosb" parm [edi] [ecx] [eax] modify exact [edi ecx];
212 #elif !defined(NO_ASM) && defined(__GNUC__)
214 inline void rle_stosb (unsigned char *dest, int len, int color) {
216 __asm__ __volatile__ (
218 : "=D" (dummy[0]), "=c" (dummy[1])
219 : "0" (dest), "1" (len), "a" (color) );
222 #elif !defined(NO_ASM) && defined(_MSC_VER)
224 __inline void rle_stosb (unsigned char *dest, int len, int color)
235 #else // NO_ASM or unknown compiler
237 void rle_stosb (unsigned char *dest, int len, int color)
240 for (i=0; i<len; i++ )
246 // Given pointer to start of one scanline of rle data, uncompress it to
247 // dest, from source pixels x1 to x2.
248 void gr_rle_expand_scanline_masked( ubyte *dest, ubyte *src, int x1, int x2 )
254 if ( x2 < x1 ) return;
259 if ( color == RLE_CODE ) return;
260 if ( IS_RLE_CODE(color) ) {
261 count = color & (~RLE_CODE);
271 // we know have '*count' pixels of 'color'.
273 if ( x1+count > x2 ) {
275 if ( color != TRANSPARENCY_COLOR ) rle_stosb( dest, count, color );
279 if ( color != TRANSPARENCY_COLOR ) rle_stosb( dest, count, color );
285 if ( color == RLE_CODE ) return;
286 if ( IS_RLE_CODE(color) ) {
287 count = color & (~RLE_CODE);
293 // we know have '*count' pixels of 'color'.
294 if ( i+count <= x2 ) {
295 if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
300 if ( color != TRANSPARENCY_COLOR )rle_stosb( dest, count, color );
308 void gr_rle_expand_scanline( ubyte *dest, ubyte *src, int x1, int x2 )
314 if ( x2 < x1 ) return;
319 if ( color == RLE_CODE ) return;
320 if ( IS_RLE_CODE(color) ) {
321 count = color & (~RLE_CODE);
331 // we know have '*count' pixels of 'color'.
333 if ( x1+count > x2 ) {
335 rle_stosb( dest, count, color );
339 rle_stosb( dest, count, color );
345 if ( color == RLE_CODE ) return;
346 if ( IS_RLE_CODE(color) ) {
347 count = color & (~RLE_CODE);
353 // we know have '*count' pixels of 'color'.
354 if ( i+count <= x2 ) {
355 rle_stosb( dest, count, color );
360 rle_stosb( dest, count, color );
368 int gr_rle_encode( int org_size, ubyte *src, ubyte *dest )
379 for (i=1; i<org_size; i++ ) {
383 if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
385 Assert( oc != RLE_CODE );
396 if ( count == NOT_RLE_CODE ) {
404 if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
406 Assert( oc != RLE_CODE );
415 return (int)(dest - dest_start);
419 int gr_rle_getsize( int org_size, ubyte *src )
429 for (i=1; i<org_size; i++ ) {
433 if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
444 if ( count == NOT_RLE_CODE ) {
451 if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
463 int gr_bitmap_rle_compress( grs_bitmap * bmp )
470 // first must check to see if this is large bitmap.
472 for (y=0; y<bmp->bm_h; y++ ) {
473 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
480 rle_data=d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) );
481 if (rle_data==NULL) return 0;
483 doffset = 4 + bmp->bm_h;
485 doffset = 4 + (2 * bmp->bm_h); // each row of rle'd bitmap has short instead of byte offset now
487 for (y=0; y<bmp->bm_h; y++ ) {
488 d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] );
489 if ( ((doffset+d1) > bmp->bm_w*bmp->bm_h) || (d1 > (large_rle?32767:255) ) ) {
493 d = gr_rle_encode( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y], &rle_data[doffset] );
497 *((short *)&(rle_data[(y*2)+4])) = (short)d;
501 //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 );
502 memcpy( rle_data, &doffset, 4 );
503 memcpy( bmp->bm_data, rle_data, doffset );
505 bmp->bm_flags |= BM_FLAG_RLE;
507 bmp->bm_flags |= BM_FLAG_RLE_BIG;
511 #define MAX_CACHE_BITMAPS 32
513 typedef struct rle_cache_element {
514 grs_bitmap * rle_bitmap;
516 grs_bitmap * expanded_bitmap;
517 unsigned int last_used;
520 int rle_cache_initialized = 0;
521 unsigned int rle_counter = 0;
523 rle_cache_element rle_cache[MAX_CACHE_BITMAPS];
528 void rle_cache_close(void)
530 if (rle_cache_initialized) {
532 rle_cache_initialized = 0;
533 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
534 gr_free_bitmap(rle_cache[i].expanded_bitmap);
539 void rle_cache_init()
542 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
543 rle_cache[i].rle_bitmap = NULL;
544 rle_cache[i].expanded_bitmap = gr_create_bitmap( 64, 64 );
545 rle_cache[i].last_used = 0;
546 Assert( rle_cache[i].expanded_bitmap != NULL );
548 rle_cache_initialized = 1;
549 atexit( rle_cache_close );
552 void rle_cache_flush()
555 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
556 rle_cache[i].rle_bitmap = NULL;
557 rle_cache[i].last_used = 0;
561 void rle_expand_texture_sub( grs_bitmap * bmp, grs_bitmap * rle_temp_bitmap_1 )
563 unsigned char * dbits;
564 unsigned char * sbits;
566 #ifdef RLE_DECODE_ASM
567 unsigned char * dbits1;
570 sbits = &bmp->bm_data[4 + bmp->bm_h];
571 dbits = rle_temp_bitmap_1->bm_data;
573 rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE);
575 for (i=0; i < bmp->bm_h; i++ ) {
576 #ifdef RLE_DECODE_ASM
577 dbits1=(unsigned char *)gr_rle_decode_asm( sbits, dbits );
579 gr_rle_decode( sbits, dbits );
581 sbits += (int)bmp->bm_data[4+i];
583 #ifdef RLE_DECODE_ASM
584 Assert( dbits == dbits1 ); // Get John, bogus rle data!
590 grs_bitmap * rle_expand_texture( grs_bitmap * bmp )
593 unsigned int lowest_count, lc;
594 int least_recently_used;
596 if (!rle_cache_initialized) rle_cache_init();
598 Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) );
602 if ( rle_counter < lc ) {
603 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
604 rle_cache[i].rle_bitmap = NULL;
605 rle_cache[i].last_used = 0;
609 // if (((rle_counter % 100)==1) && (rle_hits+rle_misses > 0))
610 // mprintf(( 0, "RLE-CACHE %d%%, H:%d, M:%d\n", (rle_misses*100)/(rle_hits+rle_misses), rle_hits, rle_misses ));
612 lowest_count = rle_cache[rle_next].last_used;
613 least_recently_used = rle_next;
615 if ( rle_next >= MAX_CACHE_BITMAPS )
618 for (i=0; i<MAX_CACHE_BITMAPS; i++ ) {
619 if (rle_cache[i].rle_bitmap == bmp) {
621 rle_cache[i].last_used = rle_counter;
622 return rle_cache[i].expanded_bitmap;
624 if ( rle_cache[i].last_used < lowest_count ) {
625 lowest_count = rle_cache[i].last_used;
626 least_recently_used = i;
630 Assert(bmp->bm_w<=64 && bmp->bm_h<=64); //dest buffer is 64x64
632 rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap );
633 rle_cache[least_recently_used].rle_bitmap = bmp;
634 rle_cache[least_recently_used].last_used = rle_counter;
635 return rle_cache[least_recently_used].expanded_bitmap;
639 void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 )
645 if ( x2 < x1 ) return;
650 if ( color == RLE_CODE ) return;
651 if ( IS_RLE_CODE(color) ) {
652 count = color & NOT_RLE_CODE;
662 // we know have '*count' pixels of 'color'.
664 if ( x1+count > x2 ) {
666 for ( j=0; j<count; j++ )
667 gr_bm_pixel( dest, dx++, dy, color );
671 for ( j=0; j<count; j++ )
672 gr_bm_pixel( dest, dx++, dy, color );
677 if ( color == RLE_CODE ) return;
678 if ( IS_RLE_CODE(color) ) {
679 count = color & NOT_RLE_CODE;
685 // we know have '*count' pixels of 'color'.
686 if ( i+count <= x2 ) {
687 for ( j=0; j<count; j++ )
688 gr_bm_pixel( dest, dx++, dy, color );
692 for ( j=0; j<count; j++ )
693 gr_bm_pixel( dest, dx++, dy, color );
699 void gr_rle_expand_scanline_generic_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 )
705 if ( x2 < x1 ) return;
710 if ( color == RLE_CODE ) return;
711 if ( IS_RLE_CODE(color) ) {
712 count = color & NOT_RLE_CODE;
722 // we know have '*count' pixels of 'color'.
724 if ( x1+count > x2 ) {
726 if (color != TRANSPARENCY_COLOR) {
727 for ( j=0; j<count; j++ )
728 gr_bm_pixel( dest, dx++, dy, color );
733 if ( color != TRANSPARENCY_COLOR ) {
734 for ( j=0; j<count; j++ )
735 gr_bm_pixel( dest, dx++, dy, color );
742 if ( color == RLE_CODE ) return;
743 if ( IS_RLE_CODE(color) ) {
744 count = color & NOT_RLE_CODE;
750 // we know have '*count' pixels of 'color'.
751 if ( i+count <= x2 ) {
752 if ( color != TRANSPARENCY_COLOR ) {
753 for ( j=0; j<count; j++ )
754 gr_bm_pixel( dest, dx++, dy, color );
760 if ( color != TRANSPARENCY_COLOR ) {
761 for ( j=0; j<count; j++ )
762 gr_bm_pixel( dest, dx++, dy, color );
772 void gr_rle_expand_scanline_svga_masked( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 )
777 ubyte * vram = (ubyte *)0xA0000;
778 int VideoLocation,page,offset;
780 if ( x2 < x1 ) return;
782 VideoLocation = (unsigned int)dest->bm_data + (dest->bm_rowsize * dy) + dx;
783 page = VideoLocation >> 16;
784 offset = VideoLocation & 0xFFFF;
786 gr_vesa_setpage( page );
788 if ( (offset + (x2-x1+1)) < 65536 ) {
789 // We don't cross a svga page, so blit it fast!
790 gr_rle_expand_scanline_masked( &vram[offset], src, x1, x2 );
797 if ( color == RLE_CODE ) return;
798 if ( IS_RLE_CODE(color) ) {
799 count = color & NOT_RLE_CODE;
809 // we know have '*count' pixels of 'color'.
811 if ( x1+count > x2 ) {
813 if (color != TRANSPARENCY_COLOR) {
814 for ( j=0; j<count; j++ ) {
815 vram[offset++] = color;
816 if ( offset >= 65536 ) {
819 gr_vesa_setpage(page);
826 if ( color != TRANSPARENCY_COLOR ) {
827 for ( j=0; j<count; j++ ) {
828 vram[offset++] = color;
829 if ( offset >= 65536 ) {
832 gr_vesa_setpage(page);
837 if ( offset >= 65536 ) {
840 gr_vesa_setpage(page);
847 if ( color == RLE_CODE ) return;
848 if ( IS_RLE_CODE(color) ) {
849 count = color & NOT_RLE_CODE;
855 // we know have '*count' pixels of 'color'.
856 if ( i+count <= x2 ) {
857 if ( color != TRANSPARENCY_COLOR ) {
858 for ( j=0; j<count; j++ ) {
859 vram[offset++] = color;
860 if ( offset >= 65536 ) {
863 gr_vesa_setpage(page);
868 if ( offset >= 65536 ) {
871 gr_vesa_setpage(page);
877 if ( color != TRANSPARENCY_COLOR ) {
878 for ( j=0; j<count; j++ ) {
879 vram[offset++] = color;
880 if ( offset >= 65536 ) {
883 gr_vesa_setpage(page);
888 if ( offset >= 65536 ) {
891 gr_vesa_setpage(page);
902 * swaps entries 0 and 255 in an RLE bitmap without uncompressing it
904 void rle_swap_0_255(grs_bitmap *bmp)
906 int i, j, len, rle_big;
907 unsigned char *ptr, *ptr2, *temp, *start;
908 unsigned short line_size;
910 rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG;
912 temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) );
914 if (rle_big) { // set ptrs to first lines
915 ptr = bmp->bm_data + 4 + 2 * bmp->bm_h;
916 ptr2 = temp + 4 + 2 * bmp->bm_h;
918 ptr = bmp->bm_data + 4 + bmp->bm_h;
919 ptr2 = temp + 4 + bmp->bm_h;
921 for (i = 0; i < bmp->bm_h; i++) {
924 line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i]));
926 line_size = bmp->bm_data[4 + i];
927 for (j = 0; j < line_size; j++) {
928 if ( ! IS_RLE_CODE(ptr[j]) ) {
930 *ptr2++ = RLE_CODE | 1;
936 if ((ptr[j] & NOT_RLE_CODE) == 0)
941 else if (ptr[j] == 255)
947 if (rle_big) // set line size
948 *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start);
950 temp[4 + i] = ptr2 - start;
951 ptr += line_size; // go to next line
953 len = (int)(ptr2 - temp);
954 *((int *)temp) = len; // set total size
955 memcpy(bmp->bm_data, temp, len);
960 * remaps all entries using colormap in an RLE bitmap without uncompressing it
962 void rle_remap(grs_bitmap *bmp, ubyte *colormap)
964 int i, j, len, rle_big;
965 unsigned char *ptr, *ptr2, *temp, *start;
966 unsigned short line_size;
968 rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG;
970 temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) + 30000 );
972 if (rle_big) { // set ptrs to first lines
973 ptr = bmp->bm_data + 4 + 2 * bmp->bm_h;
974 ptr2 = temp + 4 + 2 * bmp->bm_h;
976 ptr = bmp->bm_data + 4 + bmp->bm_h;
977 ptr2 = temp + 4 + bmp->bm_h;
979 for (i = 0; i < bmp->bm_h; i++) {
982 line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i]));
984 line_size = bmp->bm_data[4 + i];
985 for (j = 0; j < line_size; j++) {
986 if ( ! IS_RLE_CODE(ptr[j])) {
987 if (IS_RLE_CODE(colormap[ptr[j]]))
988 *ptr2++ = RLE_CODE | 1; // add "escape sequence"
989 *ptr2++ = colormap[ptr[j]]; // translate
991 *ptr2++ = ptr[j]; // just copy current rle code
992 if ((ptr[j] & NOT_RLE_CODE) == 0)
995 *ptr2++ = colormap[ptr[j]]; // translate
998 if (rle_big) // set line size
999 *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start);
1001 temp[4 + i] = ptr2 - start;
1002 ptr += line_size; // go to next line
1004 len = (int)(ptr2 - temp);
1005 *((int *)temp) = len; // set total size
1006 memcpy(bmp->bm_data, temp, len);