1 /* $Id: ibitblt.c,v 1.10 2004-08-28 23:17:45 schaffner 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__
34 static char rcsid[] = "$Id: ibitblt.c,v 1.10 2004-08-28 23:17:45 schaffner Exp $";
37 #ifdef __MSDOS__ //ndef MACINTOSH
45 #include "pa_enabl.h" //$$POLY_ACC
61 #define OPCODE_ADD 0x81
62 #define OPCODE_ESI 0xC6 // Followed by a dword (add esi, ????)
63 #define OPCODE_EDI 0xC7 // Followed by a dword (add edi, ????)
64 #define OPCODE_MOV_ECX 0xB9 // Followed by a dword (mov ecx,????)
65 #define OPCODE_MOVSB 0xA4 // movsb
66 #define OPCODE_16BIT 0x66 // movsw
67 #define OPCODE_MOVSD 0xA5 // movsd
68 #define OPCODE_REP 0xF3 // rep
69 #define OPCODE_RET 0xC3 // ret
70 #define OPCODE_MOV_EAX 0xB8 // mov eax, im dword
71 #define OPCODE_MOV_EBX 0xBB // mov ebx, im dword
72 #define OPCODE_CALL_EBX1 0xFF // call
73 #define OPCODE_CALL_EBX2 0xD3 // ebx
74 #define OPCODE_MOV_EDI 0xBF // mov edi, im dword
77 ubyte *Code_pointer = NULL;
79 int ibitblt_svga_page = 0;
85 void count_block( int ecx )
91 case 1: Code_counter++; ecx = 0; break; // MOVSB
92 case 2: Code_counter+=2; ecx = 0; break; // MOVSW
93 case 3: Code_counter+=3; ecx = 0; break; // MOVSW, MOVSB
94 case 4: Code_counter++; ecx = 0; break; // MOVSD
98 Code_counter++; // MOVSD
107 void move_and_count( int dsource, int ddest, int ecx )
125 linear_address += ddest; // Skip to next block
127 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
128 p2 = (linear_address+ecx) >> 16;
129 if ( p1 != ibitblt_svga_page ) {
131 // MOV EAX, ?, CALL EBX
133 ibitblt_svga_page = p1;
136 Code_counter += 5; // mov edi, ????
142 nbytes = 0xFFFF-o1+1;
143 count_block( nbytes );
146 Code_counter += 7; // mov eax,???? call ebx
148 ibitblt_svga_page = p2;
150 Code_counter += 5; // mov edi, ????
152 nbytes = ecx - nbytes;
154 count_block( nbytes );
156 linear_address += ecx;
162 void draw_block( int ecx )
171 *Code_pointer++ = OPCODE_MOVSB;
176 *Code_pointer++ = OPCODE_16BIT;
177 *Code_pointer++ = OPCODE_MOVSD;
182 *Code_pointer++ = OPCODE_16BIT;
183 *Code_pointer++ = OPCODE_MOVSD;
184 *Code_pointer++ = OPCODE_MOVSB;
189 *Code_pointer++ = OPCODE_MOVSD;
197 *Code_pointer++ = OPCODE_MOVSD;
200 *Code_pointer++ = OPCODE_MOV_ECX;
201 iptr = (int *)Code_pointer;
203 Code_pointer = (ubyte *)iptr;
205 *Code_pointer++ = OPCODE_REP;
206 *Code_pointer++ = OPCODE_MOVSD;
214 void move_and_draw( int dsource, int ddest, int ecx )
223 *Code_pointer++ = OPCODE_ADD;
224 *Code_pointer++ = OPCODE_ESI;
225 iptr = (int *)Code_pointer;
227 Code_pointer = (ubyte *)iptr;
232 *Code_pointer++ = OPCODE_ADD;
233 *Code_pointer++ = OPCODE_EDI;
234 iptr = (int *)Code_pointer;
236 Code_pointer = (ubyte *)iptr;
244 linear_address += ddest; // Skip to next block
246 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
247 p2 = (linear_address+ecx) >> 16;
248 if ( p1 != ibitblt_svga_page ) {
251 *Code_pointer++ = OPCODE_MOV_EAX;
253 memcpy( Code_pointer, &temp, sizeof(int) );
254 Code_pointer += sizeof(int);
256 *Code_pointer++ = OPCODE_CALL_EBX1;
257 *Code_pointer++ = OPCODE_CALL_EBX2;
258 ibitblt_svga_page = p1;
261 temp_offset = 0xA0000 + o1;
262 *Code_pointer++ = OPCODE_MOV_EDI;
263 iptr = (int *)Code_pointer;
264 *iptr++ = temp_offset;
265 Code_pointer = (ubyte *)iptr;
271 nbytes = 0xFFFF-o1+1;
272 draw_block( nbytes );
275 *Code_pointer++ = OPCODE_MOV_EAX;
277 memcpy( Code_pointer, &temp, sizeof(int) );
278 Code_pointer += sizeof(int);
280 *Code_pointer++ = OPCODE_CALL_EBX1;
281 *Code_pointer++ = OPCODE_CALL_EBX2;
282 ibitblt_svga_page = p2;
284 temp_offset = 0xA0000;
285 *Code_pointer++ = OPCODE_MOV_EDI;
286 iptr = (int *)Code_pointer;
287 *iptr++ = temp_offset;
288 Code_pointer = (ubyte *)iptr;
290 nbytes = ecx - nbytes;
292 draw_block( nbytes );
294 linear_address += ecx;
299 //-----------------------------------------------------------------------------------------
300 // Given bitmap, bmp, finds the size of the code
302 int gr_ibitblt_find_code_size_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
306 int draw_mode = MODE_NONE;
307 int source_offset = 0;
309 int num_to_draw, draw_start_source, draw_start_dest;
312 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
316 if ( dest_type == BM_SVGA ) {
317 Code_counter += 1+4; // move ebx, gr_vesa_set_page
318 Code_counter += 1+4; // move eax, 0
319 Code_counter += 2; // call ebx
320 ibitblt_svga_page = 0;
327 esi = source_offset = 0;
328 edi = dest_offset = 0;
329 draw_start_source = draw_start_dest = 0;
331 for ( y=sy; y<sy+sh; y++ ) {
332 for ( x=sx; x<sx+sw; x++ ) {
333 dest_offset = y*mask_bmp->bm_rowsize+x;
334 pixel = mask_bmp->bm_data[dest_offset];
336 switch ( draw_mode) {
338 move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
339 esi = draw_start_source + num_to_draw;
340 edi = draw_start_dest + num_to_draw;
346 draw_mode = MODE_SKIP;
348 switch ( draw_mode) {
351 draw_start_source = source_offset;
352 draw_start_dest = dest_offset;
359 draw_mode = MODE_DRAW;
363 if ( draw_mode == MODE_DRAW ) {
364 move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
365 esi = draw_start_source + num_to_draw;
366 edi = draw_start_dest + num_to_draw;
368 draw_mode = MODE_NONE;
369 source_offset += (srowsize - sw);
371 Code_counter++; // for return
373 //printf( "Code will be %d bytes\n", Code_counter );
375 Code_counter += 16; // for safety was 16
380 int gr_ibitblt_find_code_size( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
382 return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
385 int gr_ibitblt_find_code_size_svga( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
387 return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_SVGA );
390 //-----------------------------------------------------------------------------------------
391 // Given bitmap, bmp, create code that transfers a bitmap of size sw*sh to position
392 // (sx,sy) on top of bmp, only overwritting transparent pixels of the bitmap.
394 ubyte *gr_ibitblt_create_mask_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
398 int draw_mode = MODE_NONE;
399 int source_offset = 0;
401 int num_to_draw, draw_start_source, draw_start_dest;
407 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
409 if ( dest_type == BM_SVGA )
410 code_size = gr_ibitblt_find_code_size_svga( mask_bmp, sx, sy, sw, sh, srowsize );
412 code_size = gr_ibitblt_find_code_size( mask_bmp, sx, sy, sw, sh, srowsize );
414 code = malloc( code_size );
420 if ( dest_type == BM_SVGA ) {
421 // MOV EBX, gr_vesa_setpage
422 *Code_pointer++ = OPCODE_MOV_EBX;
423 temp = (uint)gr_vesa_setpage;
424 memcpy( Code_pointer, &temp, sizeof(int) );
425 Code_pointer += sizeof(int);
427 *Code_pointer++ = OPCODE_MOV_EAX;
429 memcpy( Code_pointer, &temp, sizeof(int) );
430 Code_pointer += sizeof(int);
432 *Code_pointer++ = OPCODE_CALL_EBX1;
433 *Code_pointer++ = OPCODE_CALL_EBX2;
435 ibitblt_svga_page = 0;
441 esi = source_offset = 0;
442 edi = dest_offset = 0;
443 draw_start_source = draw_start_dest = 0;
445 for ( y=sy; y<sy+sh; y++ ) {
446 for ( x=sx; x<sx+sw; x++ ) {
447 dest_offset = y*mask_bmp->bm_rowsize+x;
448 pixel = mask_bmp->bm_data[dest_offset];
450 switch ( draw_mode) {
452 move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
453 esi = draw_start_source + num_to_draw;
454 edi = draw_start_dest + num_to_draw;
460 draw_mode = MODE_SKIP;
462 switch ( draw_mode) {
465 draw_start_source = source_offset;
466 draw_start_dest = dest_offset;
473 draw_mode = MODE_DRAW;
477 if ( draw_mode == MODE_DRAW ) {
478 move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
479 esi = draw_start_source + num_to_draw;
480 edi = draw_start_dest + num_to_draw;
482 draw_mode = MODE_NONE;
483 source_offset += (srowsize - sw);
485 *Code_pointer++ = OPCODE_RET;
487 if ( Code_pointer >= &code[code_size-1] )
488 Error( "ibitblt overwrote allocated code block\n" );
490 //printf( "Code is %d bytes\n", Code_pointer - code );
495 ubyte *gr_ibitblt_create_mask( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
497 return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
500 #if defined(POLY_ACC)
501 unsigned long *pa_emit_blit(int gencode, unsigned long *buf, int w, int h, int sx, int sy, int dx, int dy)
508 buf[0] = (w << 16) | h;
509 buf[1] = (sx << 16) | sy;
510 buf[2] = (dx << 16) | dy;
515 ubyte *gr_ibitblt_create_mask_pa( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
517 unsigned long *ret, *code = 0;
521 Assert(mask_bmp->bm_type == BM_LINEAR15);
527 // make two passes, first pass gets size of output block, second actually creates data.
528 for(pass = 0; pass != 2; ++pass)
530 for (y = sy; y < sy + sh; y++ )
532 // first byte of interest in mask
533 s = (ushort *)(mask_bmp->bm_data + y * mask_bmp->bm_rowsize + sx * PA_BPP);
536 for(; x != sw && (s[x] & 0x8000); ++x) // while opaque...
538 for(n = 0; x != sw && !(s[x] & 0x8000); ++n, ++x) // while transparent...
540 code = pa_emit_blit(pass, code, n, 1, x - n, y - sy, x + sx - n, y);
545 ret = malloc((int)code + sizeof(unsigned long));
546 ret[0] = (int)code / sizeof(unsigned long); // store num unsigned longs in list.
554 ubyte *gr_ibitblt_create_mask_svga( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
556 return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_SVGA );
561 void gr_ibitblt_do_asm(char *start_si, char *start_di, ubyte * code);
562 #pragma aux gr_ibitblt_do_asm parm [esi] [edi] [eax] modify [ecx edi esi eax] = \
569 void gr_ibitblt(grs_bitmap * source_bmp, grs_bitmap * dest_bmp, ubyte * mask )
571 #if defined(POLY_ACC)
572 Assert(source_bmp->bm_type == BM_LINEAR15);
573 pa_ibitblt(source_bmp->bm_data, dest_bmp->bm_data, mask);
576 gr_ibitblt_do_asm( source_bmp->bm_data, dest_bmp->bm_data, mask );
581 void gr_ibitblt_find_hole_size( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
584 #if defined(POLY_ACC)
590 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
592 #if defined(POLY_ACC)
593 Assert(mask_bmp->bm_type == BM_LINEAR15);
597 *minx = mask_bmp->bm_w-1;
599 *miny = mask_bmp->bm_h-1;
602 for ( y=0; y<mask_bmp->bm_h; y++ )
603 for ( x=0; x<mask_bmp->bm_w; x++ ) {
604 #if defined(POLY_ACC)
605 c = *(short *)(mask_bmp->bm_data + mask_bmp->bm_rowsize * y + x * PA_BPP);
606 if (c >= 0) { // hi true means opaque.
608 c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
611 if ( x < *minx ) *minx = x;
612 if ( y < *miny ) *miny = y;
613 if ( x > *maxx ) *maxx = x;
614 if ( y > *maxy ) *maxy = y;
620 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
624 #else /* __MSDOS__ */ // was: /* !MACINTOSH */
626 #include "pa_enabl.h"
634 #if defined(POLY_ACC)
635 #include "poly_acc.h"
641 #define MAX_WIDTH 640
642 #define MAX_SCANLINES 480
645 static short start_points[MAX_SCANLINES][MAX_HOLES];
646 static short hole_length[MAX_SCANLINES][MAX_HOLES];
647 static double *scanline = NULL;
649 void gr_ibitblt(grs_bitmap *src_bmp, grs_bitmap *dest_bmp, ubyte pixel_double)
651 int x, y, sw, sh, srowsize, drowsize, dstart, sy, dy;
653 short *current_hole, *current_hole_length;
657 #if defined(POLY_ACC)
664 srowsize = src_bmp->bm_rowsize;
665 drowsize = dest_bmp->bm_rowsize;
666 src = src_bmp->bm_data;
667 dest = dest_bmp->bm_data;
670 while (start_points[sy][0] == -1) {
676 ubyte *scan = (ubyte *)scanline; // set up for byte processing of scanline
679 for (y = sy; y < sy + sh; y++) {
680 gr_linear_rep_movsd_2x(src, scan, sw); // was: gr_linear_movsd_double(src, scan, sw*2);
681 current_hole = start_points[dy];
682 current_hole_length = hole_length[dy];
683 for (x = 0; x < MAX_HOLES; x++) {
684 if (*current_hole == -1)
686 dstart = *current_hole;
687 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
689 current_hole_length++;
693 current_hole = start_points[dy];
694 current_hole_length = hole_length[dy];
695 for (x = 0;x < MAX_HOLES; x++) {
696 if (*current_hole == -1)
698 dstart = *current_hole;
699 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
701 current_hole_length++;
708 Assert(sw <= MAX_WIDTH);
709 Assert(sh <= MAX_SCANLINES);
710 for (y = sy; y < sy + sh; y++) {
711 for (x = 0; x < MAX_HOLES; x++) {
712 if (start_points[y][x] == -1)
714 dstart = start_points[y][x];
715 gr_linear_movsd(&(src[dstart]), &(dest[dstart]), hole_length[y][x]);
723 #if defined(POLY_ACC)
725 unsigned long *pa_emit_blit(int gencode, unsigned long *buf, int w, int h, int sx, int sy, int dx, int dy)
732 buf[0] = (w << 16) | h;
733 buf[1] = (sx << 16) | sy;
734 buf[2] = (dx << 16) | dy;
739 void gr_ibitblt_create_mask_pa( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
741 unsigned long *ret, *code = 0;
745 Assert(mask_bmp->bm_type == BM_LINEAR15);
751 // make two passes, first pass gets size of output block, second actually creates data.
752 for(pass = 0; pass != 2; ++pass)
754 for (y = sy; y < sy + sh; y++ )
756 // first byte of interest in mask
757 s = (ushort *)(mask_bmp->bm_data + y * mask_bmp->bm_rowsize + sx * PA_BPP);
760 for(; x != sw && (s[x] & 0x8000); ++x) // while opaque...
762 for(n = 0; x != sw && !(s[x] & 0x8000); ++n, ++x) // while transparent...
764 code = pa_emit_blit(pass, code, n, 1, x - n, y - sy, x + sx - n, y);
769 ret = malloc((int)code + sizeof(unsigned long));
770 ret[0] = (int)code / sizeof(unsigned long); // store num unsigned longs in list.
774 // return (ubyte *)ret;
778 void gr_ibitblt_create_mask(grs_bitmap *mask_bmp, int sx, int sy, int sw, int sh, int srowsize)
784 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
786 for (y = 0; y < MAX_SCANLINES; y++) {
787 for (x = 0; x < MAX_HOLES; x++) {
788 start_points[y][x] = -1;
789 hole_length[y][x] = -1;
793 for (y = sy; y < sy+sh; y++) {
796 for (x = sx; x < sx + sw; x++) {
797 if ((mode == FIND_START) && (mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x] == TRANSPARENCY_COLOR)) {
798 start_points[y][count] = x;
800 } else if ((mode == FIND_STOP) && (mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x] != TRANSPARENCY_COLOR)) {
801 hole_length[y][count] = x - start_points[y][count];
806 if (mode == FIND_STOP) {
807 hole_length[y][count] = x - start_points[y][count];
810 Assert(count <= MAX_HOLES);
814 #if defined(POLY_ACC)
816 void gr_ibitblt_find_hole_size_pa( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
821 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
823 Assert(mask_bmp->bm_type == BM_LINEAR15);
826 *minx = mask_bmp->bm_w-1;
828 *miny = mask_bmp->bm_h-1;
831 for ( y=0; y<mask_bmp->bm_h; y++ )
832 for ( x=0; x<mask_bmp->bm_w; x++ ) {
833 c = *(short *)(mask_bmp->bm_data + mask_bmp->bm_rowsize * y + x * PA_BPP);
834 if (c >= 0) { // hi true means opaque.
835 if ( x < *minx ) *minx = x;
836 if ( y < *miny ) *miny = y;
837 if ( x > *maxx ) *maxx = x;
838 if ( y > *maxy ) *maxy = y;
844 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
849 void gr_ibitblt_find_hole_size(grs_bitmap *mask_bmp, int *minx, int *miny, int *maxx, int *maxy)
854 #if defined(POLY_ACC)
856 gr_ibitblt_find_hole_size_pa( mask_bmp, minx, miny, maxx, maxy );
861 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
862 Assert( mask_bmp->bm_flags&BM_FLAG_TRANSPARENT );
864 *minx = mask_bmp->bm_w - 1;
866 *miny = mask_bmp->bm_h - 1;
869 if (scanline == NULL)
870 scanline = (double *)malloc(sizeof(double) * (MAX_WIDTH / sizeof(double)));
872 for (y = 0; y < mask_bmp->bm_h; y++) {
873 for (x = 0; x < mask_bmp->bm_w; x++) {
874 c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
875 if (c == TRANSPARENCY_COLOR) { // don't look for transparancy color here.
877 if (x < *minx) *minx = x;
878 if (y < *miny) *miny = y;
879 if (x > *maxx) *maxx = x;
880 if (y > *maxy) *maxy = y;
887 #endif /* __MSDOS__ */ // was: /* !MACINTOSH */