1 /* $Id: ibitblt.c,v 1.7 2003-10-25 01:44:23 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-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
18 * Rountines to copy a bitmap on top of another bitmap, but
19 * only copying to pixels that are transparent.
21 * Routines to to inverse bitblitting -- well not really.
22 * We don't inverse bitblt like in the PC, but this code
23 * does set up a structure that blits around the cockpit
25 * d2x uses the "Mac" version for everything except __MSDOS__
28 * Revision 1.3 1995/09/13 11:43:22 allender
29 * start on optimizing cockpit copy code
31 * Revision 1.2 1995/09/07 10:16:57 allender
32 * fixed up cockpit and rearview hole blitting
34 * Revision 1.1 1995/08/18 15:50:48 allender
38 * Routines to copy a bitmap on top of another bitmap, but
39 * only copying to pixels that are transparent.
42 * Revision 1.6 1994/11/28 17:07:29 john
43 * Took out some unused functions in linear.asm, moved
44 * gr_linear_movsd from linear.asm to bitblt.c, made sure that
45 * the code in ibiblt.c sets the direction flags before rep movsing.
47 * Revision 1.5 1994/11/18 22:50:22 john
48 * Changed shorts to ints in parameters.
50 * Revision 1.4 1994/11/09 16:35:16 john
51 * First version with working RLE bitmaps.
53 * Revision 1.3 1994/10/03 17:18:05 john
54 * Fixed bug with edi not getting intialized to zero
57 * Revision 1.2 1994/05/31 11:10:55 john
58 * *** empty log message ***
60 * Revision 1.1 1994/05/30 16:08:27 john
70 static char rcsid[] = "$Id: ibitblt.c,v 1.7 2003-10-25 01:44:23 btb Exp $";
73 #ifdef __MSDOS__ //ndef MACINTOSH
81 #include "pa_enabl.h" //$$POLY_ACC
97 #define OPCODE_ADD 0x81
98 #define OPCODE_ESI 0xC6 // Followed by a dword (add esi, ????)
99 #define OPCODE_EDI 0xC7 // Followed by a dword (add edi, ????)
100 #define OPCODE_MOV_ECX 0xB9 // Followed by a dword (mov ecx,????)
101 #define OPCODE_MOVSB 0xA4 // movsb
102 #define OPCODE_16BIT 0x66 // movsw
103 #define OPCODE_MOVSD 0xA5 // movsd
104 #define OPCODE_REP 0xF3 // rep
105 #define OPCODE_RET 0xC3 // ret
106 #define OPCODE_MOV_EAX 0xB8 // mov eax, im dword
107 #define OPCODE_MOV_EBX 0xBB // mov ebx, im dword
108 #define OPCODE_CALL_EBX1 0xFF // call
109 #define OPCODE_CALL_EBX2 0xD3 // ebx
110 #define OPCODE_MOV_EDI 0xBF // mov edi, im dword
113 ubyte *Code_pointer = NULL;
114 int Code_counter = 0;
115 int ibitblt_svga_page = 0;
121 void count_block( int ecx )
127 case 1: Code_counter++; ecx = 0; break; // MOVSB
128 case 2: Code_counter+=2; ecx = 0; break; // MOVSW
129 case 3: Code_counter+=3; ecx = 0; break; // MOVSW, MOVSB
130 case 4: Code_counter++; ecx = 0; break; // MOVSD
134 Code_counter++; // MOVSD
143 void move_and_count( int dsource, int ddest, int ecx )
161 linear_address += ddest; // Skip to next block
163 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
164 p2 = (linear_address+ecx) >> 16;
165 if ( p1 != ibitblt_svga_page ) {
167 // MOV EAX, ?, CALL EBX
169 ibitblt_svga_page = p1;
172 Code_counter += 5; // mov edi, ????
178 nbytes = 0xFFFF-o1+1;
179 count_block( nbytes );
182 Code_counter += 7; // mov eax,???? call ebx
184 ibitblt_svga_page = p2;
186 Code_counter += 5; // mov edi, ????
188 nbytes = ecx - nbytes;
190 count_block( nbytes );
192 linear_address += ecx;
198 void draw_block( int ecx )
207 *Code_pointer++ = OPCODE_MOVSB;
212 *Code_pointer++ = OPCODE_16BIT;
213 *Code_pointer++ = OPCODE_MOVSD;
218 *Code_pointer++ = OPCODE_16BIT;
219 *Code_pointer++ = OPCODE_MOVSD;
220 *Code_pointer++ = OPCODE_MOVSB;
225 *Code_pointer++ = OPCODE_MOVSD;
233 *Code_pointer++ = OPCODE_MOVSD;
236 *Code_pointer++ = OPCODE_MOV_ECX;
237 iptr = (int *)Code_pointer;
239 Code_pointer = (ubyte *)iptr;
241 *Code_pointer++ = OPCODE_REP;
242 *Code_pointer++ = OPCODE_MOVSD;
250 void move_and_draw( int dsource, int ddest, int ecx )
259 *Code_pointer++ = OPCODE_ADD;
260 *Code_pointer++ = OPCODE_ESI;
261 iptr = (int *)Code_pointer;
263 Code_pointer = (ubyte *)iptr;
268 *Code_pointer++ = OPCODE_ADD;
269 *Code_pointer++ = OPCODE_EDI;
270 iptr = (int *)Code_pointer;
272 Code_pointer = (ubyte *)iptr;
280 linear_address += ddest; // Skip to next block
282 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
283 p2 = (linear_address+ecx) >> 16;
284 if ( p1 != ibitblt_svga_page ) {
287 *Code_pointer++ = OPCODE_MOV_EAX;
289 memcpy( Code_pointer, &temp, sizeof(int) );
290 Code_pointer += sizeof(int);
292 *Code_pointer++ = OPCODE_CALL_EBX1;
293 *Code_pointer++ = OPCODE_CALL_EBX2;
294 ibitblt_svga_page = p1;
297 temp_offset = 0xA0000 + o1;
298 *Code_pointer++ = OPCODE_MOV_EDI;
299 iptr = (int *)Code_pointer;
300 *iptr++ = temp_offset;
301 Code_pointer = (ubyte *)iptr;
307 nbytes = 0xFFFF-o1+1;
308 draw_block( nbytes );
311 *Code_pointer++ = OPCODE_MOV_EAX;
313 memcpy( Code_pointer, &temp, sizeof(int) );
314 Code_pointer += sizeof(int);
316 *Code_pointer++ = OPCODE_CALL_EBX1;
317 *Code_pointer++ = OPCODE_CALL_EBX2;
318 ibitblt_svga_page = p2;
320 temp_offset = 0xA0000;
321 *Code_pointer++ = OPCODE_MOV_EDI;
322 iptr = (int *)Code_pointer;
323 *iptr++ = temp_offset;
324 Code_pointer = (ubyte *)iptr;
326 nbytes = ecx - nbytes;
328 draw_block( nbytes );
330 linear_address += ecx;
335 //-----------------------------------------------------------------------------------------
336 // Given bitmap, bmp, finds the size of the code
338 int gr_ibitblt_find_code_size_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
342 int draw_mode = MODE_NONE;
343 int source_offset = 0;
345 int num_to_draw, draw_start_source, draw_start_dest;
348 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
352 if ( dest_type == BM_SVGA ) {
353 Code_counter += 1+4; // move ebx, gr_vesa_set_page
354 Code_counter += 1+4; // move eax, 0
355 Code_counter += 2; // call ebx
356 ibitblt_svga_page = 0;
363 esi = source_offset = 0;
364 edi = dest_offset = 0;
365 draw_start_source = draw_start_dest = 0;
367 for ( y=sy; y<sy+sh; y++ ) {
368 for ( x=sx; x<sx+sw; x++ ) {
369 dest_offset = y*mask_bmp->bm_rowsize+x;
370 pixel = mask_bmp->bm_data[dest_offset];
372 switch ( draw_mode) {
374 move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
375 esi = draw_start_source + num_to_draw;
376 edi = draw_start_dest + num_to_draw;
382 draw_mode = MODE_SKIP;
384 switch ( draw_mode) {
387 draw_start_source = source_offset;
388 draw_start_dest = dest_offset;
395 draw_mode = MODE_DRAW;
399 if ( draw_mode == MODE_DRAW ) {
400 move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
401 esi = draw_start_source + num_to_draw;
402 edi = draw_start_dest + num_to_draw;
404 draw_mode = MODE_NONE;
405 source_offset += (srowsize - sw);
407 Code_counter++; // for return
409 //printf( "Code will be %d bytes\n", Code_counter );
411 Code_counter += 16; // for safety was 16
416 int gr_ibitblt_find_code_size( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
418 return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
421 int gr_ibitblt_find_code_size_svga( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
423 return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_SVGA );
426 //-----------------------------------------------------------------------------------------
427 // Given bitmap, bmp, create code that transfers a bitmap of size sw*sh to position
428 // (sx,sy) on top of bmp, only overwritting transparent pixels of the bitmap.
430 ubyte *gr_ibitblt_create_mask_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
434 int draw_mode = MODE_NONE;
435 int source_offset = 0;
437 int num_to_draw, draw_start_source, draw_start_dest;
443 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
445 if ( dest_type == BM_SVGA )
446 code_size = gr_ibitblt_find_code_size_svga( mask_bmp, sx, sy, sw, sh, srowsize );
448 code_size = gr_ibitblt_find_code_size( mask_bmp, sx, sy, sw, sh, srowsize );
450 code = malloc( code_size );
456 if ( dest_type == BM_SVGA ) {
457 // MOV EBX, gr_vesa_setpage
458 *Code_pointer++ = OPCODE_MOV_EBX;
459 temp = (uint)gr_vesa_setpage;
460 memcpy( Code_pointer, &temp, sizeof(int) );
461 Code_pointer += sizeof(int);
463 *Code_pointer++ = OPCODE_MOV_EAX;
465 memcpy( Code_pointer, &temp, sizeof(int) );
466 Code_pointer += sizeof(int);
468 *Code_pointer++ = OPCODE_CALL_EBX1;
469 *Code_pointer++ = OPCODE_CALL_EBX2;
471 ibitblt_svga_page = 0;
477 esi = source_offset = 0;
478 edi = dest_offset = 0;
479 draw_start_source = draw_start_dest = 0;
481 for ( y=sy; y<sy+sh; y++ ) {
482 for ( x=sx; x<sx+sw; x++ ) {
483 dest_offset = y*mask_bmp->bm_rowsize+x;
484 pixel = mask_bmp->bm_data[dest_offset];
486 switch ( draw_mode) {
488 move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
489 esi = draw_start_source + num_to_draw;
490 edi = draw_start_dest + num_to_draw;
496 draw_mode = MODE_SKIP;
498 switch ( draw_mode) {
501 draw_start_source = source_offset;
502 draw_start_dest = dest_offset;
509 draw_mode = MODE_DRAW;
513 if ( draw_mode == MODE_DRAW ) {
514 move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
515 esi = draw_start_source + num_to_draw;
516 edi = draw_start_dest + num_to_draw;
518 draw_mode = MODE_NONE;
519 source_offset += (srowsize - sw);
521 *Code_pointer++ = OPCODE_RET;
523 if ( Code_pointer >= &code[code_size-1] )
524 Error( "ibitblt overwrote allocated code block\n" );
526 //printf( "Code is %d bytes\n", Code_pointer - code );
531 ubyte *gr_ibitblt_create_mask( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
533 return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
536 #if defined(POLY_ACC)
537 ulong *pa_emit_blit(int gencode, ulong *buf, int w, int h, int sx, int sy, int dx, int dy)
544 buf[0] = (w << 16) | h;
545 buf[1] = (sx << 16) | sy;
546 buf[2] = (dx << 16) | dy;
551 ubyte *gr_ibitblt_create_mask_pa( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
553 ulong *ret, *code = 0;
557 Assert(mask_bmp->bm_type == BM_LINEAR15);
563 // make two passes, first pass gets size of output block, second actually creates data.
564 for(pass = 0; pass != 2; ++pass)
566 for (y = sy; y < sy + sh; y++ )
568 // first byte of interest in mask
569 s = (ushort *)(mask_bmp->bm_data + y * mask_bmp->bm_rowsize + sx * PA_BPP);
572 for(; x != sw && (s[x] & 0x8000); ++x) // while opaque...
574 for(n = 0; x != sw && !(s[x] & 0x8000); ++n, ++x) // while transparent...
576 code = pa_emit_blit(pass, code, n, 1, x - n, y - sy, x + sx - n, y);
581 ret = malloc((int)code + sizeof(ulong));
582 ret[0] = (int)code / sizeof(ulong); // store num ulongs in list.
590 ubyte *gr_ibitblt_create_mask_svga( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
592 return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_SVGA );
597 void gr_ibitblt_do_asm(char *start_si, char *start_di, ubyte * code);
598 #pragma aux gr_ibitblt_do_asm parm [esi] [edi] [eax] modify [ecx edi esi eax] = \
605 void gr_ibitblt(grs_bitmap * source_bmp, grs_bitmap * dest_bmp, ubyte * mask )
607 #if defined(POLY_ACC)
608 Assert(source_bmp->bm_type == BM_LINEAR15);
609 pa_ibitblt(source_bmp->bm_data, dest_bmp->bm_data, mask);
612 gr_ibitblt_do_asm( source_bmp->bm_data, dest_bmp->bm_data, mask );
617 void gr_ibitblt_find_hole_size( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
620 #if defined(POLY_ACC)
626 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
628 #if defined(POLY_ACC)
629 Assert(mask_bmp->bm_type == BM_LINEAR15);
633 *minx = mask_bmp->bm_w-1;
635 *miny = mask_bmp->bm_h-1;
638 for ( y=0; y<mask_bmp->bm_h; y++ )
639 for ( x=0; x<mask_bmp->bm_w; x++ ) {
640 #if defined(POLY_ACC)
641 c = *(short *)(mask_bmp->bm_data + mask_bmp->bm_rowsize * y + x * PA_BPP);
642 if (c >= 0) { // hi true means opaque.
644 c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
647 if ( x < *minx ) *minx = x;
648 if ( y < *miny ) *miny = y;
649 if ( x > *maxx ) *maxx = x;
650 if ( y > *maxy ) *maxy = y;
656 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
660 #else /* __MSDOS__ */ // was: /* !MACINTOSH */
662 #include "pa_enabl.h"
670 #if defined(POLY_ACC)
671 #include "poly_acc.h"
677 #define MAX_WIDTH 640
678 #define MAX_SCANLINES 480
681 static short start_points[MAX_SCANLINES][MAX_HOLES];
682 static short hole_length[MAX_SCANLINES][MAX_HOLES];
683 static double *scanline = NULL;
685 void gr_ibitblt(grs_bitmap *src_bmp, grs_bitmap *dest_bmp, ubyte pixel_double)
687 int x, y, sw, sh, srowsize, drowsize, dstart, sy, dy;
689 short *current_hole, *current_hole_length;
693 #if defined(POLY_ACC)
700 srowsize = src_bmp->bm_rowsize;
701 drowsize = dest_bmp->bm_rowsize;
702 src = src_bmp->bm_data;
703 dest = dest_bmp->bm_data;
706 while (start_points[sy][0] == -1) {
712 ubyte *scan = (ubyte *)scanline; // set up for byte processing of scanline
715 for (y = sy; y < sy + sh; y++) {
716 gr_linear_rep_movsd_2x(src, scan, sw); // was: gr_linear_movsd_double(src, scan, sw*2);
717 current_hole = start_points[dy];
718 current_hole_length = hole_length[dy];
719 for (x = 0; x < MAX_HOLES; x++) {
720 if (*current_hole == -1)
722 dstart = *current_hole;
723 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
725 current_hole_length++;
729 current_hole = start_points[dy];
730 current_hole_length = hole_length[dy];
731 for (x = 0;x < MAX_HOLES; x++) {
732 if (*current_hole == -1)
734 dstart = *current_hole;
735 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
737 current_hole_length++;
744 Assert(sw <= MAX_WIDTH);
745 Assert(sh <= MAX_SCANLINES);
746 for (y = sy; y < sy + sh; y++) {
747 for (x = 0; x < MAX_HOLES; x++) {
748 if (start_points[y][x] == -1)
750 dstart = start_points[y][x];
751 gr_linear_movsd(&(src[dstart]), &(dest[dstart]), hole_length[y][x]);
759 #if defined(POLY_ACC)
761 ulong *pa_emit_blit(int gencode, ulong *buf, int w, int h, int sx, int sy, int dx, int dy)
768 buf[0] = (w << 16) | h;
769 buf[1] = (sx << 16) | sy;
770 buf[2] = (dx << 16) | dy;
775 void gr_ibitblt_create_mask_pa( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
777 ulong *ret, *code = 0;
781 Assert(mask_bmp->bm_type == BM_LINEAR15);
787 // make two passes, first pass gets size of output block, second actually creates data.
788 for(pass = 0; pass != 2; ++pass)
790 for (y = sy; y < sy + sh; y++ )
792 // first byte of interest in mask
793 s = (ushort *)(mask_bmp->bm_data + y * mask_bmp->bm_rowsize + sx * PA_BPP);
796 for(; x != sw && (s[x] & 0x8000); ++x) // while opaque...
798 for(n = 0; x != sw && !(s[x] & 0x8000); ++n, ++x) // while transparent...
800 code = pa_emit_blit(pass, code, n, 1, x - n, y - sy, x + sx - n, y);
805 ret = malloc((int)code + sizeof(ulong));
806 ret[0] = (int)code / sizeof(ulong); // store num ulongs in list.
810 // return (ubyte *)ret;
814 void gr_ibitblt_create_mask(grs_bitmap *mask_bmp, int sx, int sy, int sw, int sh, int srowsize)
820 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
822 for (y = 0; y < MAX_SCANLINES; y++) {
823 for (x = 0; x < MAX_HOLES; x++) {
824 start_points[y][x] = -1;
825 hole_length[y][x] = -1;
829 for (y = sy; y < sy+sh; y++) {
832 for (x = sx; x < sx + sw; x++) {
833 if ((mode == FIND_START) && (mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x] == TRANSPARENCY_COLOR)) {
834 start_points[y][count] = x;
836 } else if ((mode == FIND_STOP) && (mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x] != TRANSPARENCY_COLOR)) {
837 hole_length[y][count] = x - start_points[y][count];
842 if (mode == FIND_STOP) {
843 hole_length[y][count] = x - start_points[y][count];
846 Assert(count <= MAX_HOLES);
850 #if defined(POLY_ACC)
852 void gr_ibitblt_find_hole_size_pa( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
857 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
859 Assert(mask_bmp->bm_type == BM_LINEAR15);
862 *minx = mask_bmp->bm_w-1;
864 *miny = mask_bmp->bm_h-1;
867 for ( y=0; y<mask_bmp->bm_h; y++ )
868 for ( x=0; x<mask_bmp->bm_w; x++ ) {
869 c = *(short *)(mask_bmp->bm_data + mask_bmp->bm_rowsize * y + x * PA_BPP);
870 if (c >= 0) { // hi true means opaque.
871 if ( x < *minx ) *minx = x;
872 if ( y < *miny ) *miny = y;
873 if ( x > *maxx ) *maxx = x;
874 if ( y > *maxy ) *maxy = y;
880 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
885 void gr_ibitblt_find_hole_size(grs_bitmap *mask_bmp, int *minx, int *miny, int *maxx, int *maxy)
890 #if defined(POLY_ACC)
892 gr_ibitblt_find_hole_size_pa( mask_bmp, minx, miny, maxx, maxy );
897 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
898 Assert( mask_bmp->bm_flags&BM_FLAG_TRANSPARENT );
900 *minx = mask_bmp->bm_w - 1;
902 *miny = mask_bmp->bm_h - 1;
905 if (scanline == NULL)
906 scanline = (double *)malloc(sizeof(double) * (MAX_WIDTH / sizeof(double)));
908 for (y = 0; y < mask_bmp->bm_h; y++) {
909 for (x = 0; x < mask_bmp->bm_w; x++) {
910 c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
911 if (c == TRANSPARENCY_COLOR) { // don't look for transparancy color here.
913 if (x < *minx) *minx = x;
914 if (y < *miny) *miny = y;
915 if (x > *maxx) *maxx = x;
916 if (y > *maxy) *maxy = y;
923 #endif /* __MSDOS__ */ // was: /* !MACINTOSH */