1 /* $Id: ibitblt.c,v 1.11 2005-07-30 01:51:42 chris 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.11 2005-07-30 01:51:42 chris Exp $";
37 #ifdef __MSDOS__ //ndef MACINTOSH
56 #define OPCODE_ADD 0x81
57 #define OPCODE_ESI 0xC6 // Followed by a dword (add esi, ????)
58 #define OPCODE_EDI 0xC7 // Followed by a dword (add edi, ????)
59 #define OPCODE_MOV_ECX 0xB9 // Followed by a dword (mov ecx,????)
60 #define OPCODE_MOVSB 0xA4 // movsb
61 #define OPCODE_16BIT 0x66 // movsw
62 #define OPCODE_MOVSD 0xA5 // movsd
63 #define OPCODE_REP 0xF3 // rep
64 #define OPCODE_RET 0xC3 // ret
65 #define OPCODE_MOV_EAX 0xB8 // mov eax, im dword
66 #define OPCODE_MOV_EBX 0xBB // mov ebx, im dword
67 #define OPCODE_CALL_EBX1 0xFF // call
68 #define OPCODE_CALL_EBX2 0xD3 // ebx
69 #define OPCODE_MOV_EDI 0xBF // mov edi, im dword
72 ubyte *Code_pointer = NULL;
74 int ibitblt_svga_page = 0;
80 void count_block( int ecx )
86 case 1: Code_counter++; ecx = 0; break; // MOVSB
87 case 2: Code_counter+=2; ecx = 0; break; // MOVSW
88 case 3: Code_counter+=3; ecx = 0; break; // MOVSW, MOVSB
89 case 4: Code_counter++; ecx = 0; break; // MOVSD
93 Code_counter++; // MOVSD
102 void move_and_count( int dsource, int ddest, int ecx )
120 linear_address += ddest; // Skip to next block
122 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
123 p2 = (linear_address+ecx) >> 16;
124 if ( p1 != ibitblt_svga_page ) {
126 // MOV EAX, ?, CALL EBX
128 ibitblt_svga_page = p1;
131 Code_counter += 5; // mov edi, ????
137 nbytes = 0xFFFF-o1+1;
138 count_block( nbytes );
141 Code_counter += 7; // mov eax,???? call ebx
143 ibitblt_svga_page = p2;
145 Code_counter += 5; // mov edi, ????
147 nbytes = ecx - nbytes;
149 count_block( nbytes );
151 linear_address += ecx;
157 void draw_block( int ecx )
166 *Code_pointer++ = OPCODE_MOVSB;
171 *Code_pointer++ = OPCODE_16BIT;
172 *Code_pointer++ = OPCODE_MOVSD;
177 *Code_pointer++ = OPCODE_16BIT;
178 *Code_pointer++ = OPCODE_MOVSD;
179 *Code_pointer++ = OPCODE_MOVSB;
184 *Code_pointer++ = OPCODE_MOVSD;
192 *Code_pointer++ = OPCODE_MOVSD;
195 *Code_pointer++ = OPCODE_MOV_ECX;
196 iptr = (int *)Code_pointer;
198 Code_pointer = (ubyte *)iptr;
200 *Code_pointer++ = OPCODE_REP;
201 *Code_pointer++ = OPCODE_MOVSD;
209 void move_and_draw( int dsource, int ddest, int ecx )
218 *Code_pointer++ = OPCODE_ADD;
219 *Code_pointer++ = OPCODE_ESI;
220 iptr = (int *)Code_pointer;
222 Code_pointer = (ubyte *)iptr;
227 *Code_pointer++ = OPCODE_ADD;
228 *Code_pointer++ = OPCODE_EDI;
229 iptr = (int *)Code_pointer;
231 Code_pointer = (ubyte *)iptr;
239 linear_address += ddest; // Skip to next block
241 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
242 p2 = (linear_address+ecx) >> 16;
243 if ( p1 != ibitblt_svga_page ) {
246 *Code_pointer++ = OPCODE_MOV_EAX;
248 memcpy( Code_pointer, &temp, sizeof(int) );
249 Code_pointer += sizeof(int);
251 *Code_pointer++ = OPCODE_CALL_EBX1;
252 *Code_pointer++ = OPCODE_CALL_EBX2;
253 ibitblt_svga_page = p1;
256 temp_offset = 0xA0000 + o1;
257 *Code_pointer++ = OPCODE_MOV_EDI;
258 iptr = (int *)Code_pointer;
259 *iptr++ = temp_offset;
260 Code_pointer = (ubyte *)iptr;
266 nbytes = 0xFFFF-o1+1;
267 draw_block( nbytes );
270 *Code_pointer++ = OPCODE_MOV_EAX;
272 memcpy( Code_pointer, &temp, sizeof(int) );
273 Code_pointer += sizeof(int);
275 *Code_pointer++ = OPCODE_CALL_EBX1;
276 *Code_pointer++ = OPCODE_CALL_EBX2;
277 ibitblt_svga_page = p2;
279 temp_offset = 0xA0000;
280 *Code_pointer++ = OPCODE_MOV_EDI;
281 iptr = (int *)Code_pointer;
282 *iptr++ = temp_offset;
283 Code_pointer = (ubyte *)iptr;
285 nbytes = ecx - nbytes;
287 draw_block( nbytes );
289 linear_address += ecx;
294 //-----------------------------------------------------------------------------------------
295 // Given bitmap, bmp, finds the size of the code
297 int gr_ibitblt_find_code_size_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
301 int draw_mode = MODE_NONE;
302 int source_offset = 0;
304 int num_to_draw, draw_start_source, draw_start_dest;
307 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
311 if ( dest_type == BM_SVGA ) {
312 Code_counter += 1+4; // move ebx, gr_vesa_set_page
313 Code_counter += 1+4; // move eax, 0
314 Code_counter += 2; // call ebx
315 ibitblt_svga_page = 0;
322 esi = source_offset = 0;
323 edi = dest_offset = 0;
324 draw_start_source = draw_start_dest = 0;
326 for ( y=sy; y<sy+sh; y++ ) {
327 for ( x=sx; x<sx+sw; x++ ) {
328 dest_offset = y*mask_bmp->bm_rowsize+x;
329 pixel = mask_bmp->bm_data[dest_offset];
331 switch ( draw_mode) {
333 move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
334 esi = draw_start_source + num_to_draw;
335 edi = draw_start_dest + num_to_draw;
341 draw_mode = MODE_SKIP;
343 switch ( draw_mode) {
346 draw_start_source = source_offset;
347 draw_start_dest = dest_offset;
354 draw_mode = MODE_DRAW;
358 if ( draw_mode == MODE_DRAW ) {
359 move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
360 esi = draw_start_source + num_to_draw;
361 edi = draw_start_dest + num_to_draw;
363 draw_mode = MODE_NONE;
364 source_offset += (srowsize - sw);
366 Code_counter++; // for return
368 //printf( "Code will be %d bytes\n", Code_counter );
370 Code_counter += 16; // for safety was 16
375 int gr_ibitblt_find_code_size( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
377 return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
380 int gr_ibitblt_find_code_size_svga( 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_SVGA );
385 //-----------------------------------------------------------------------------------------
386 // Given bitmap, bmp, create code that transfers a bitmap of size sw*sh to position
387 // (sx,sy) on top of bmp, only overwritting transparent pixels of the bitmap.
389 ubyte *gr_ibitblt_create_mask_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
393 int draw_mode = MODE_NONE;
394 int source_offset = 0;
396 int num_to_draw, draw_start_source, draw_start_dest;
402 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
404 if ( dest_type == BM_SVGA )
405 code_size = gr_ibitblt_find_code_size_svga( mask_bmp, sx, sy, sw, sh, srowsize );
407 code_size = gr_ibitblt_find_code_size( mask_bmp, sx, sy, sw, sh, srowsize );
409 code = malloc( code_size );
415 if ( dest_type == BM_SVGA ) {
416 // MOV EBX, gr_vesa_setpage
417 *Code_pointer++ = OPCODE_MOV_EBX;
418 temp = (uint)gr_vesa_setpage;
419 memcpy( Code_pointer, &temp, sizeof(int) );
420 Code_pointer += sizeof(int);
422 *Code_pointer++ = OPCODE_MOV_EAX;
424 memcpy( Code_pointer, &temp, sizeof(int) );
425 Code_pointer += sizeof(int);
427 *Code_pointer++ = OPCODE_CALL_EBX1;
428 *Code_pointer++ = OPCODE_CALL_EBX2;
430 ibitblt_svga_page = 0;
436 esi = source_offset = 0;
437 edi = dest_offset = 0;
438 draw_start_source = draw_start_dest = 0;
440 for ( y=sy; y<sy+sh; y++ ) {
441 for ( x=sx; x<sx+sw; x++ ) {
442 dest_offset = y*mask_bmp->bm_rowsize+x;
443 pixel = mask_bmp->bm_data[dest_offset];
445 switch ( draw_mode) {
447 move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
448 esi = draw_start_source + num_to_draw;
449 edi = draw_start_dest + num_to_draw;
455 draw_mode = MODE_SKIP;
457 switch ( draw_mode) {
460 draw_start_source = source_offset;
461 draw_start_dest = dest_offset;
468 draw_mode = MODE_DRAW;
472 if ( draw_mode == MODE_DRAW ) {
473 move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
474 esi = draw_start_source + num_to_draw;
475 edi = draw_start_dest + num_to_draw;
477 draw_mode = MODE_NONE;
478 source_offset += (srowsize - sw);
480 *Code_pointer++ = OPCODE_RET;
482 if ( Code_pointer >= &code[code_size-1] )
483 Error( "ibitblt overwrote allocated code block\n" );
485 //printf( "Code is %d bytes\n", Code_pointer - code );
490 ubyte *gr_ibitblt_create_mask( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
492 return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
495 ubyte *gr_ibitblt_create_mask_svga( 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_SVGA );
501 void gr_ibitblt_do_asm(char *start_si, char *start_di, ubyte * code);
502 #pragma aux gr_ibitblt_do_asm parm [esi] [edi] [eax] modify [ecx edi esi eax] = \
509 void gr_ibitblt(grs_bitmap * source_bmp, grs_bitmap * dest_bmp, ubyte * mask )
512 gr_ibitblt_do_asm( source_bmp->bm_data, dest_bmp->bm_data, mask );
516 void gr_ibitblt_find_hole_size( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
521 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
523 *minx = mask_bmp->bm_w-1;
525 *miny = mask_bmp->bm_h-1;
528 for ( y=0; y<mask_bmp->bm_h; y++ )
529 for ( x=0; x<mask_bmp->bm_w; x++ ) {
530 c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
532 if ( x < *minx ) *minx = x;
533 if ( y < *miny ) *miny = y;
534 if ( x > *maxx ) *maxx = x;
535 if ( y > *maxy ) *maxy = y;
541 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
545 #else /* __MSDOS__ */ // was: /* !MACINTOSH */
557 #define MAX_WIDTH 640
558 #define MAX_SCANLINES 480
561 static short start_points[MAX_SCANLINES][MAX_HOLES];
562 static short hole_length[MAX_SCANLINES][MAX_HOLES];
563 static double *scanline = NULL;
565 void gr_ibitblt(grs_bitmap *src_bmp, grs_bitmap *dest_bmp, ubyte pixel_double)
567 int x, y, sw, sh, srowsize, drowsize, dstart, sy, dy;
569 short *current_hole, *current_hole_length;
575 srowsize = src_bmp->bm_rowsize;
576 drowsize = dest_bmp->bm_rowsize;
577 src = src_bmp->bm_data;
578 dest = dest_bmp->bm_data;
581 while (start_points[sy][0] == -1) {
587 ubyte *scan = (ubyte *)scanline; // set up for byte processing of scanline
590 for (y = sy; y < sy + sh; y++) {
591 gr_linear_rep_movsd_2x(src, scan, sw); // was: gr_linear_movsd_double(src, scan, sw*2);
592 current_hole = start_points[dy];
593 current_hole_length = hole_length[dy];
594 for (x = 0; x < MAX_HOLES; x++) {
595 if (*current_hole == -1)
597 dstart = *current_hole;
598 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
600 current_hole_length++;
604 current_hole = start_points[dy];
605 current_hole_length = hole_length[dy];
606 for (x = 0;x < MAX_HOLES; x++) {
607 if (*current_hole == -1)
609 dstart = *current_hole;
610 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
612 current_hole_length++;
619 Assert(sw <= MAX_WIDTH);
620 Assert(sh <= MAX_SCANLINES);
621 for (y = sy; y < sy + sh; y++) {
622 for (x = 0; x < MAX_HOLES; x++) {
623 if (start_points[y][x] == -1)
625 dstart = start_points[y][x];
626 gr_linear_movsd(&(src[dstart]), &(dest[dstart]), hole_length[y][x]);
634 void gr_ibitblt_create_mask(grs_bitmap *mask_bmp, int sx, int sy, int sw, int sh, int srowsize)
640 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
642 for (y = 0; y < MAX_SCANLINES; y++) {
643 for (x = 0; x < MAX_HOLES; x++) {
644 start_points[y][x] = -1;
645 hole_length[y][x] = -1;
649 for (y = sy; y < sy+sh; y++) {
652 for (x = sx; x < sx + sw; x++) {
653 if ((mode == FIND_START) && (mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x] == TRANSPARENCY_COLOR)) {
654 start_points[y][count] = x;
656 } else if ((mode == FIND_STOP) && (mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x] != TRANSPARENCY_COLOR)) {
657 hole_length[y][count] = x - start_points[y][count];
662 if (mode == FIND_STOP) {
663 hole_length[y][count] = x - start_points[y][count];
666 Assert(count <= MAX_HOLES);
670 void gr_ibitblt_find_hole_size(grs_bitmap *mask_bmp, int *minx, int *miny, int *maxx, int *maxy)
675 Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
676 Assert( mask_bmp->bm_flags&BM_FLAG_TRANSPARENT );
678 *minx = mask_bmp->bm_w - 1;
680 *miny = mask_bmp->bm_h - 1;
683 if (scanline == NULL)
684 scanline = (double *)malloc(sizeof(double) * (MAX_WIDTH / sizeof(double)));
686 for (y = 0; y < mask_bmp->bm_h; y++) {
687 for (x = 0; x < mask_bmp->bm_w; x++) {
688 c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
689 if (c == TRANSPARENCY_COLOR) { // don't look for transparancy color here.
691 if (x < *minx) *minx = x;
692 if (y < *miny) *miny = y;
693 if (x > *maxx) *maxx = x;
694 if (y > *maxy) *maxy = y;
701 #endif /* __MSDOS__ */ // was: /* !MACINTOSH */