]> icculus.org git repositories - btb/d2x.git/blob - 2d/ibitblt.c
use gr_linear_rep_movsd_2x instead of almost identical gr_linear_movsd_double. Better...
[btb/d2x.git] / 2d / ibitblt.c
1 /* $Id: ibitblt.c,v 1.7 2003-10-25 01:44:23 btb Exp $ */
2 /*
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.
13 */
14
15 /*
16  *
17  * "PC" Version:
18  * Rountines to copy a bitmap on top of another bitmap, but
19  * only copying to pixels that are transparent.
20  * "Mac" Version:
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
24  *
25  * d2x uses the "Mac" version for everything except __MSDOS__
26  *
27  * Old Log: ibitblt.c
28  * Revision 1.3  1995/09/13  11:43:22  allender
29  * start on optimizing cockpit copy code
30  *
31  * Revision 1.2  1995/09/07  10:16:57  allender
32  * fixed up cockpit and rearview hole blitting
33  *
34  * Revision 1.1  1995/08/18  15:50:48  allender
35  * Initial revision
36  *
37  * PC version:
38  * Routines to copy a bitmap on top of another bitmap, but
39  * only copying to pixels that are transparent.
40  *
41  * Old Log:
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.
46  *
47  * Revision 1.5  1994/11/18  22:50:22  john
48  * Changed shorts to ints in parameters.
49  *
50  * Revision 1.4  1994/11/09  16:35:16  john
51  * First version with working RLE bitmaps.
52  *
53  * Revision 1.3  1994/10/03  17:18:05  john
54  * Fixed bug with edi not getting intialized to zero
55  * in create_mask.
56  *
57  * Revision 1.2  1994/05/31  11:10:55  john
58  * *** empty log message ***
59  *
60  * Revision 1.1  1994/05/30  16:08:27  john
61  * Initial revision
62  *
63  */
64
65 #ifdef HAVE_CONFIG_H
66 #include <conf.h>
67 #endif
68
69 #ifdef RCS
70 static char rcsid[] = "$Id: ibitblt.c,v 1.7 2003-10-25 01:44:23 btb Exp $";
71 #endif
72
73 #ifdef __MSDOS__ //ndef MACINTOSH
74
75 #include <conio.h>
76 #include <dos.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80
81 #include "pa_enabl.h"                   //$$POLY_ACC
82 #include "types.h"
83 #include "gr.h"
84 #include "mem.h"
85 #include "error.h"
86 #include "ibitblt.h"
87 #include "grdef.h"
88
89 #if defined(POLY_ACC)
90 #include "poly_acc.h"
91 #endif
92
93 #define MODE_NONE           0
94 #define MODE_SKIP           1
95 #define MODE_DRAW           2
96
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
111
112
113 ubyte *Code_pointer = NULL;
114 int Code_counter = 0;
115 int ibitblt_svga_page = 0;
116 int is_svga = 0;
117 uint linear_address;
118
119
120
121 void count_block( int ecx )
122 {
123         int blocks;
124
125         while ( ecx > 0 ) {
126                 switch(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
131                 default:
132                         blocks = ecx / 4;
133                         if ( blocks == 1 )
134                                 Code_counter++; // MOVSD
135                         else
136                                 Code_counter+=7;
137                         ecx -= blocks*4;
138                 }
139         }
140 }
141
142
143 void move_and_count( int dsource, int ddest, int ecx )
144 {
145         if ( ecx <= 0 )
146                 return;
147
148         if ( dsource > 0 ) {
149                 // ADD ESI, dsource
150                 Code_counter += 6;
151         }
152         if ( !is_svga ) {
153                 if ( ddest > 0 ) {
154                         // ADD EDI, ddest
155                         Code_counter += 6;
156                 }
157                 count_block( ecx );
158         } else {
159                 int p1, p2, o1;
160
161                 linear_address += ddest;        // Skip to next block
162
163                 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
164                 p2 = (linear_address+ecx) >> 16;
165                 if ( p1 != ibitblt_svga_page ) {
166                         // Set page
167                         // MOV EAX, ?, CALL EBX
168                         Code_counter += 7;
169                         ibitblt_svga_page = p1;
170                 }
171
172                 Code_counter += 5;  // mov edi, ????
173
174                 if ( p1 == p2 ) {
175                         count_block( ecx );
176                 } else {
177                         int nbytes;
178                         nbytes = 0xFFFF-o1+1;
179                         count_block( nbytes );
180                         // set page
181                         // MOV EAX, 0
182                         Code_counter += 7;  // mov eax,???? call ebx
183
184                         ibitblt_svga_page = p2;
185
186                         Code_counter += 5;  // mov edi, ????
187
188                         nbytes = ecx - nbytes;
189                         if (nbytes > 0 )
190                                 count_block( nbytes );
191                 }
192                 linear_address += ecx;
193         }
194 }
195
196
197
198 void draw_block( int ecx )
199 {
200         int blocks;
201         int * iptr;
202
203         while ( ecx > 0 )   {
204                 switch( ecx )   {
205                 case 1:
206                         // MOVSB
207                         *Code_pointer++ = OPCODE_MOVSB;
208                         ecx = 0;
209                         break;
210                 case 2:
211                         // MOVSW
212                         *Code_pointer++ = OPCODE_16BIT;
213                         *Code_pointer++ = OPCODE_MOVSD;
214                         ecx = 0;
215                         break;
216                 case 3:
217                         // MOVSW, MOVSB
218                         *Code_pointer++ = OPCODE_16BIT;
219                         *Code_pointer++ = OPCODE_MOVSD;
220                         *Code_pointer++ = OPCODE_MOVSB;
221                         ecx = 0;
222                         break;
223                 case 4:
224                         // MOVSD
225                         *Code_pointer++ = OPCODE_MOVSD;
226                         ecx = 0;
227                         break;
228                 default:
229                         blocks = ecx / 4;
230
231                         if ( blocks == 1 ) {
232                                 // MOVSD
233                                 *Code_pointer++ = OPCODE_MOVSD;
234                         } else {
235                                 // MOV ECX, blocks
236                                 *Code_pointer++ = OPCODE_MOV_ECX;
237                                 iptr = (int *)Code_pointer;
238                                 *iptr++ = blocks;
239                                 Code_pointer = (ubyte *)iptr;
240                                 // REP MOVSD
241                                 *Code_pointer++ = OPCODE_REP;
242                                 *Code_pointer++ = OPCODE_MOVSD;
243                         }
244                         ecx -= blocks*4;
245                 }
246         }
247 }
248
249
250 void move_and_draw( int dsource, int ddest, int ecx )
251 {
252         int * iptr;
253
254         if ( ecx <= 0 )
255                 return;
256
257         if ( dsource > 0 ) {
258                 // ADD ESI, dsource
259                 *Code_pointer++ = OPCODE_ADD;
260                 *Code_pointer++ = OPCODE_ESI;
261                 iptr = (int *)Code_pointer;
262                 *iptr++ = dsource;
263                 Code_pointer = (ubyte *)iptr;
264         }
265         if ( !is_svga ) {
266                 if ( ddest > 0 ) {
267                         // ADD EDI, ddest
268                         *Code_pointer++ = OPCODE_ADD;
269                         *Code_pointer++ = OPCODE_EDI;
270                         iptr = (int *)Code_pointer;
271                         *iptr++ = ddest;
272                         Code_pointer = (ubyte *)iptr;
273                 }
274                 draw_block( ecx );
275         } else {
276                 unsigned int temp;
277                 int temp_offset;
278                 int p1, p2, o1;
279
280                 linear_address += ddest;        // Skip to next block
281
282                 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
283                 p2 = (linear_address+ecx) >> 16;
284                 if ( p1 != ibitblt_svga_page ) {
285                         // Set page
286                         // MOV EAX, 0
287                         *Code_pointer++ = OPCODE_MOV_EAX;
288                         temp = p1;
289                         memcpy( Code_pointer, &temp, sizeof(int) );
290                         Code_pointer += sizeof(int);
291                         // CALL EBX
292                         *Code_pointer++ = OPCODE_CALL_EBX1;
293                         *Code_pointer++ = OPCODE_CALL_EBX2;
294                         ibitblt_svga_page = p1;
295                 }
296
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;
302
303                 if ( p1 == p2 ) {
304                         draw_block( ecx );
305                 } else {
306                         int nbytes;
307                         nbytes = 0xFFFF-o1+1;
308                         draw_block( nbytes );
309                         // set page
310                         // MOV EAX, 0
311                         *Code_pointer++ = OPCODE_MOV_EAX;
312                         temp = p2;
313                         memcpy( Code_pointer, &temp, sizeof(int) );
314                         Code_pointer += sizeof(int);
315                         // CALL EBX
316                         *Code_pointer++ = OPCODE_CALL_EBX1;
317                         *Code_pointer++ = OPCODE_CALL_EBX2;
318                         ibitblt_svga_page = p2;
319
320                         temp_offset = 0xA0000;
321                         *Code_pointer++ = OPCODE_MOV_EDI;
322                         iptr = (int *)Code_pointer;
323                         *iptr++ = temp_offset;
324                         Code_pointer = (ubyte *)iptr;
325
326                         nbytes = ecx - nbytes;
327                         if (nbytes > 0 )
328                                 draw_block( nbytes );
329                 }
330                 linear_address += ecx;
331         }
332
333 }
334
335 //-----------------------------------------------------------------------------------------
336 // Given bitmap, bmp, finds the size of the code
337
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 )
339 {
340         int x,y;
341         ubyte pixel;
342         int draw_mode = MODE_NONE;
343         int source_offset = 0;
344         int dest_offset = 0;
345         int num_to_draw, draw_start_source, draw_start_dest;
346         int esi, edi;
347
348         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
349
350         Code_counter = 0;
351
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;
357                 linear_address = 0;
358                 is_svga = 1;
359         } else {
360                 is_svga = 0;
361         }
362
363         esi = source_offset = 0;
364         edi = dest_offset = 0;
365         draw_start_source = draw_start_dest = 0;
366
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];
371                         if ( pixel!=255 ) {
372                                 switch ( draw_mode) {
373                                 case MODE_DRAW:
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;
377                                         // fall through!!!
378                                 case MODE_NONE:
379                                 case MODE_SKIP:
380                                         break;
381                                 }
382                                 draw_mode = MODE_SKIP;
383                         } else {
384                                 switch ( draw_mode) {
385                                 case MODE_SKIP:
386                                 case MODE_NONE:
387                                         draw_start_source = source_offset;
388                                         draw_start_dest = dest_offset;
389                                         num_to_draw = 0;
390                                         // fall through
391                                 case MODE_DRAW:
392                                         num_to_draw++;
393                                         break;
394                                 }
395                                 draw_mode = MODE_DRAW;
396                         }
397                         source_offset++;
398                 }
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;
403                 }
404                 draw_mode = MODE_NONE;
405                 source_offset += (srowsize - sw);
406         }
407         Code_counter++;     // for return
408
409         //printf( "Code will be %d bytes\n", Code_counter );
410
411         Code_counter += 16; // for safety was 16
412
413         return Code_counter;
414 }
415
416 int gr_ibitblt_find_code_size( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
417 {
418         return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
419 }
420
421 int gr_ibitblt_find_code_size_svga( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
422 {
423         return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_SVGA );
424 }
425
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.
429
430 ubyte   *gr_ibitblt_create_mask_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
431 {
432         int x,y;
433         ubyte pixel;
434         int draw_mode = MODE_NONE;
435         int source_offset = 0;
436         int dest_offset = 0;
437         int num_to_draw, draw_start_source, draw_start_dest;
438         int esi, edi;
439         int code_size;
440         ubyte *code;
441         uint temp;
442
443         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
444
445         if ( dest_type == BM_SVGA )
446                 code_size = gr_ibitblt_find_code_size_svga( mask_bmp, sx, sy, sw, sh, srowsize );
447         else
448                 code_size = gr_ibitblt_find_code_size( mask_bmp, sx, sy, sw, sh, srowsize );
449
450         code = malloc( code_size );
451         if ( code == NULL )
452                 return NULL;
453
454         Code_pointer = code;
455
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);
462                 // MOV EAX, 0
463                 *Code_pointer++ = OPCODE_MOV_EAX;
464                 temp = 0;
465                 memcpy( Code_pointer, &temp, sizeof(int) );
466                 Code_pointer += sizeof(int);
467                 // CALL EBX
468                 *Code_pointer++ = OPCODE_CALL_EBX1;
469                 *Code_pointer++ = OPCODE_CALL_EBX2;
470
471                 ibitblt_svga_page = 0;
472                 is_svga = 1;
473                 linear_address = 0;
474         } else {
475                 is_svga = 0;
476         }
477         esi = source_offset = 0;
478         edi = dest_offset = 0;
479         draw_start_source = draw_start_dest = 0;
480
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];
485                         if ( pixel!=255 ) {
486                                 switch ( draw_mode) {
487                                 case MODE_DRAW:
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;
491                                         // fall through!!!
492                                 case MODE_NONE:
493                                 case MODE_SKIP:
494                                         break;
495                                 }
496                                 draw_mode = MODE_SKIP;
497                         } else {
498                                 switch ( draw_mode) {
499                                 case MODE_SKIP:
500                                 case MODE_NONE:
501                                         draw_start_source = source_offset;
502                                         draw_start_dest = dest_offset;
503                                         num_to_draw = 0;
504                                         // fall through
505                                 case MODE_DRAW:
506                                         num_to_draw++;
507                                         break;
508                                 }
509                                 draw_mode = MODE_DRAW;
510                         }
511                         source_offset++;
512                 }
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;
517                 }
518                 draw_mode = MODE_NONE;
519                 source_offset += (srowsize - sw);
520         }
521         *Code_pointer++ = OPCODE_RET;
522
523         if ( Code_pointer >= &code[code_size-1] )
524                 Error( "ibitblt overwrote allocated code block\n" );
525
526         //printf( "Code is %d bytes\n", Code_pointer - code );
527
528         return code;
529 }
530
531 ubyte   *gr_ibitblt_create_mask( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
532 {
533         return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
534 }
535
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)
538 {
539         if(w == 0 || h == 0)
540                 return buf;
541
542         if(gencode)
543         {
544                 buf[0] = (w << 16)  | h;
545                 buf[1] = (sx << 16) | sy;
546                 buf[2] = (dx << 16) | dy;
547         }
548         return buf + 3;
549 }
550
551 ubyte   *gr_ibitblt_create_mask_pa( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
552 {
553         ulong *ret, *code = 0;
554         int pass, x, y, n;
555         ushort *s;
556
557         Assert(mask_bmp->bm_type == BM_LINEAR15);
558
559         srowsize /= PA_BPP;
560
561         pa_flush();
562
563         // make two passes, first pass gets size of output block, second actually creates data.
564         for(pass = 0; pass != 2; ++pass)
565         {
566                 for (y = sy; y < sy + sh; y++ )
567                 {
568                         // first byte of interest in mask
569                         s = (ushort *)(mask_bmp->bm_data + y * mask_bmp->bm_rowsize + sx * PA_BPP);
570                         for ( x=0; x < sw; )
571                         {
572                                 for(; x != sw && (s[x] & 0x8000); ++x)              // while opaque...
573                                         ;
574                                 for(n = 0; x != sw && !(s[x] & 0x8000); ++n, ++x)   // while transparent...
575                                         ;
576                                 code = pa_emit_blit(pass, code, n, 1, x - n, y - sy, x + sx - n, y);
577                         }
578                 }
579                 if(pass == 0)
580                 {
581                         ret = malloc((int)code + sizeof(ulong));
582                         ret[0] = (int)code / sizeof(ulong);        // store num ulongs in list.
583                         code = ret + 1;
584                 }
585         }
586         return (ubyte *)ret;
587 }
588
589 #else
590 ubyte   *gr_ibitblt_create_mask_svga( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
591 {
592         return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_SVGA );
593 }
594 #endif
595
596
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] = \
599     "pusha"         \
600     "cld"           \
601     "call   eax"    \
602     "popa"
603
604
605 void gr_ibitblt(grs_bitmap * source_bmp, grs_bitmap * dest_bmp, ubyte * mask )
606 {
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);
610 #else
611         if (mask != NULL )
612                 gr_ibitblt_do_asm( source_bmp->bm_data, dest_bmp->bm_data, mask );
613 #endif
614 }
615
616
617 void    gr_ibitblt_find_hole_size( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
618 {
619         int x, y, count=0;
620 #if defined(POLY_ACC)
621         short c;
622 #else
623         ubyte c;
624 #endif
625
626         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
627
628 #if defined(POLY_ACC)
629         Assert(mask_bmp->bm_type == BM_LINEAR15);
630         pa_flush();
631 #endif
632
633         *minx = mask_bmp->bm_w-1;
634         *maxx = 0;
635         *miny = mask_bmp->bm_h-1;
636         *maxy = 0;
637
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.
643 #else
644                         c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
645                         if (c == 255 ) {
646 #endif
647                                 if ( x < *minx ) *minx = x;
648                                 if ( y < *miny ) *miny = y;
649                                 if ( x > *maxx ) *maxx = x;
650                                 if ( y > *maxy ) *maxy = y;
651                                 count++;
652                         }
653                 }
654
655         if ( count == 0 ) {
656                 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
657         }
658 }
659
660 #else /* __MSDOS__ */ // was: /* !MACINTOSH */
661
662 #include "pa_enabl.h"
663 #include "pstypes.h"
664 #include "gr.h"
665 #include "ibitblt.h"
666 #include "error.h"
667 #include "u_mem.h"
668 #include "grdef.h"
669
670 #if defined(POLY_ACC)
671 #include "poly_acc.h"
672 #endif
673
674 #define FIND_START      1
675 #define FIND_STOP       2
676
677 #define MAX_WIDTH       640
678 #define MAX_SCANLINES   480
679 #define MAX_HOLES       5
680
681 static short start_points[MAX_SCANLINES][MAX_HOLES];
682 static short hole_length[MAX_SCANLINES][MAX_HOLES];
683 static double *scanline = NULL;
684
685 void gr_ibitblt(grs_bitmap *src_bmp, grs_bitmap *dest_bmp, ubyte pixel_double)
686 {
687         int x, y, sw, sh, srowsize, drowsize, dstart, sy, dy;
688         ubyte *src, *dest;
689         short *current_hole, *current_hole_length;
690
691 // variable setup
692
693 #if defined(POLY_ACC)
694         if ( PAEnabled )
695                 return;
696 #endif
697
698         sw = src_bmp->bm_w;
699         sh = src_bmp->bm_h;
700         srowsize = src_bmp->bm_rowsize;
701         drowsize = dest_bmp->bm_rowsize;
702         src = src_bmp->bm_data;
703         dest = dest_bmp->bm_data;
704
705         sy = 0;
706         while (start_points[sy][0] == -1) {
707                 sy++;
708                 dest += drowsize;
709         }
710
711         if (pixel_double) {
712                 ubyte *scan = (ubyte *)scanline;    // set up for byte processing of scanline
713
714                 dy = sy;
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)
721                                         break;
722                                 dstart = *current_hole;
723                                 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
724                                 current_hole++;
725                                 current_hole_length++;
726                         }
727                         dy++;
728                         dest += drowsize;
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)
733                                         break;
734                                 dstart = *current_hole;
735                                 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
736                                 current_hole++;
737                                 current_hole_length++;
738                         }
739                         dy++;
740                         dest += drowsize;
741                         src += srowsize;
742                 }
743         } else {
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)
749                                         break;
750                                 dstart = start_points[y][x];
751                                 gr_linear_movsd(&(src[dstart]), &(dest[dstart]), hole_length[y][x]);
752                         }
753                         dest += drowsize;
754                         src += srowsize;
755                 }
756         }
757 }
758
759 #if defined(POLY_ACC)
760
761 ulong *pa_emit_blit(int gencode, ulong *buf, int w, int h, int sx, int sy, int dx, int dy)
762 {
763         if(w == 0 || h == 0)
764                 return buf;
765
766         if(gencode)
767         {
768                 buf[0] = (w << 16)  | h;
769                 buf[1] = (sx << 16) | sy;
770                 buf[2] = (dx << 16) | dy;
771         }
772         return buf + 3;
773 }
774
775 void gr_ibitblt_create_mask_pa( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
776 {
777         ulong *ret, *code = 0;
778         int pass, x, y, n;
779         ushort *s;
780
781         Assert(mask_bmp->bm_type == BM_LINEAR15);
782
783         srowsize /= PA_BPP;
784
785         pa_flush();
786
787         // make two passes, first pass gets size of output block, second actually creates data.
788         for(pass = 0; pass != 2; ++pass)
789         {
790                 for (y = sy; y < sy + sh; y++ )
791                 {
792                         // first byte of interest in mask
793                         s = (ushort *)(mask_bmp->bm_data + y * mask_bmp->bm_rowsize + sx * PA_BPP);
794                         for ( x=0; x < sw; )
795                         {
796                                 for(; x != sw && (s[x] & 0x8000); ++x)              // while opaque...
797                                         ;
798                                 for(n = 0; x != sw && !(s[x] & 0x8000); ++n, ++x)   // while transparent...
799                                         ;
800                                 code = pa_emit_blit(pass, code, n, 1, x - n, y - sy, x + sx - n, y);
801                         }
802                 }
803
804                 if(pass == 0) {
805                         ret = malloc((int)code + sizeof(ulong));
806                         ret[0] = (int)code / sizeof(ulong);        // store num ulongs in list.
807                         code = ret + 1;
808                 }
809         }
810 //      return (ubyte *)ret;
811 }
812 #endif
813
814 void gr_ibitblt_create_mask(grs_bitmap *mask_bmp, int sx, int sy, int sw, int sh, int srowsize)
815 {
816         int x, y;
817         ubyte mode;
818         int count = 0;
819
820         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
821
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;
826                 }
827         }
828
829         for (y = sy; y < sy+sh; y++) {
830                 count = 0;
831                 mode = FIND_START;
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;
835                                 mode = FIND_STOP;
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];
838                                 count++;
839                                 mode = FIND_START;
840                         }
841                 }
842                 if (mode == FIND_STOP) {
843                         hole_length[y][count] = x - start_points[y][count];
844                         count++;
845                 }
846                 Assert(count <= MAX_HOLES);
847         }
848 }
849
850 #if defined(POLY_ACC)
851
852 void gr_ibitblt_find_hole_size_pa( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
853 {
854         int x, y, count=0;
855         short c;
856
857         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
858
859         Assert(mask_bmp->bm_type == BM_LINEAR15);
860         while(!pa_idle());
861
862         *minx = mask_bmp->bm_w-1;
863         *maxx = 0;
864         *miny = mask_bmp->bm_h-1;
865         *maxy = 0;
866
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;
875                                 count++;
876                         }
877                 }
878
879         if ( count == 0 ) {
880                 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
881         }
882 }
883 #endif
884
885 void gr_ibitblt_find_hole_size(grs_bitmap *mask_bmp, int *minx, int *miny, int *maxx, int *maxy)
886 {
887         ubyte c;
888         int x, y, count = 0;
889
890 #if defined(POLY_ACC)
891         if ( PAEnabled ) {
892                 gr_ibitblt_find_hole_size_pa( mask_bmp, minx, miny, maxx, maxy );
893                 return;
894         }
895 #endif
896
897         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
898         Assert( mask_bmp->bm_flags&BM_FLAG_TRANSPARENT );
899
900         *minx = mask_bmp->bm_w - 1;
901         *maxx = 0;
902         *miny = mask_bmp->bm_h - 1;
903         *maxy = 0;
904
905         if (scanline == NULL)
906                 scanline = (double *)malloc(sizeof(double) * (MAX_WIDTH / sizeof(double)));
907
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.
912                                 count++;
913                                 if (x < *minx) *minx = x;
914                                 if (y < *miny) *miny = y;
915                                 if (x > *maxx) *maxx = x;
916                                 if (y > *maxy) *maxy = y;
917                         }
918                 }
919         }
920         Assert (count);
921 }
922
923 #endif /* __MSDOS__ */ // was: /* !MACINTOSH */