]> icculus.org git repositories - btb/d2x.git/blob - 2d/ibitblt.c
get rid of clipping in ogl_internal_string, causes garbage on windows for some reason.
[btb/d2x.git] / 2d / ibitblt.c
1 /* $Id: ibitblt.c,v 1.10 2004-08-28 23:17:45 schaffner 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  */
28
29 #ifdef HAVE_CONFIG_H
30 #include <conf.h>
31 #endif
32
33 #ifdef RCS
34 static char rcsid[] = "$Id: ibitblt.c,v 1.10 2004-08-28 23:17:45 schaffner Exp $";
35 #endif
36
37 #ifdef __MSDOS__ //ndef MACINTOSH
38
39 #include <conio.h>
40 #include <dos.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include "pa_enabl.h"                   //$$POLY_ACC
46 #include "types.h"
47 #include "gr.h"
48 #include "mem.h"
49 #include "error.h"
50 #include "ibitblt.h"
51 #include "grdef.h"
52
53 #if defined(POLY_ACC)
54 #include "poly_acc.h"
55 #endif
56
57 #define MODE_NONE           0
58 #define MODE_SKIP           1
59 #define MODE_DRAW           2
60
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
75
76
77 ubyte *Code_pointer = NULL;
78 int Code_counter = 0;
79 int ibitblt_svga_page = 0;
80 int is_svga = 0;
81 uint linear_address;
82
83
84
85 void count_block( int ecx )
86 {
87         int blocks;
88
89         while ( ecx > 0 ) {
90                 switch(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
95                 default:
96                         blocks = ecx / 4;
97                         if ( blocks == 1 )
98                                 Code_counter++; // MOVSD
99                         else
100                                 Code_counter+=7;
101                         ecx -= blocks*4;
102                 }
103         }
104 }
105
106
107 void move_and_count( int dsource, int ddest, int ecx )
108 {
109         if ( ecx <= 0 )
110                 return;
111
112         if ( dsource > 0 ) {
113                 // ADD ESI, dsource
114                 Code_counter += 6;
115         }
116         if ( !is_svga ) {
117                 if ( ddest > 0 ) {
118                         // ADD EDI, ddest
119                         Code_counter += 6;
120                 }
121                 count_block( ecx );
122         } else {
123                 int p1, p2, o1;
124
125                 linear_address += ddest;        // Skip to next block
126
127                 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
128                 p2 = (linear_address+ecx) >> 16;
129                 if ( p1 != ibitblt_svga_page ) {
130                         // Set page
131                         // MOV EAX, ?, CALL EBX
132                         Code_counter += 7;
133                         ibitblt_svga_page = p1;
134                 }
135
136                 Code_counter += 5;  // mov edi, ????
137
138                 if ( p1 == p2 ) {
139                         count_block( ecx );
140                 } else {
141                         int nbytes;
142                         nbytes = 0xFFFF-o1+1;
143                         count_block( nbytes );
144                         // set page
145                         // MOV EAX, 0
146                         Code_counter += 7;  // mov eax,???? call ebx
147
148                         ibitblt_svga_page = p2;
149
150                         Code_counter += 5;  // mov edi, ????
151
152                         nbytes = ecx - nbytes;
153                         if (nbytes > 0 )
154                                 count_block( nbytes );
155                 }
156                 linear_address += ecx;
157         }
158 }
159
160
161
162 void draw_block( int ecx )
163 {
164         int blocks;
165         int * iptr;
166
167         while ( ecx > 0 )   {
168                 switch( ecx )   {
169                 case 1:
170                         // MOVSB
171                         *Code_pointer++ = OPCODE_MOVSB;
172                         ecx = 0;
173                         break;
174                 case 2:
175                         // MOVSW
176                         *Code_pointer++ = OPCODE_16BIT;
177                         *Code_pointer++ = OPCODE_MOVSD;
178                         ecx = 0;
179                         break;
180                 case 3:
181                         // MOVSW, MOVSB
182                         *Code_pointer++ = OPCODE_16BIT;
183                         *Code_pointer++ = OPCODE_MOVSD;
184                         *Code_pointer++ = OPCODE_MOVSB;
185                         ecx = 0;
186                         break;
187                 case 4:
188                         // MOVSD
189                         *Code_pointer++ = OPCODE_MOVSD;
190                         ecx = 0;
191                         break;
192                 default:
193                         blocks = ecx / 4;
194
195                         if ( blocks == 1 ) {
196                                 // MOVSD
197                                 *Code_pointer++ = OPCODE_MOVSD;
198                         } else {
199                                 // MOV ECX, blocks
200                                 *Code_pointer++ = OPCODE_MOV_ECX;
201                                 iptr = (int *)Code_pointer;
202                                 *iptr++ = blocks;
203                                 Code_pointer = (ubyte *)iptr;
204                                 // REP MOVSD
205                                 *Code_pointer++ = OPCODE_REP;
206                                 *Code_pointer++ = OPCODE_MOVSD;
207                         }
208                         ecx -= blocks*4;
209                 }
210         }
211 }
212
213
214 void move_and_draw( int dsource, int ddest, int ecx )
215 {
216         int * iptr;
217
218         if ( ecx <= 0 )
219                 return;
220
221         if ( dsource > 0 ) {
222                 // ADD ESI, dsource
223                 *Code_pointer++ = OPCODE_ADD;
224                 *Code_pointer++ = OPCODE_ESI;
225                 iptr = (int *)Code_pointer;
226                 *iptr++ = dsource;
227                 Code_pointer = (ubyte *)iptr;
228         }
229         if ( !is_svga ) {
230                 if ( ddest > 0 ) {
231                         // ADD EDI, ddest
232                         *Code_pointer++ = OPCODE_ADD;
233                         *Code_pointer++ = OPCODE_EDI;
234                         iptr = (int *)Code_pointer;
235                         *iptr++ = ddest;
236                         Code_pointer = (ubyte *)iptr;
237                 }
238                 draw_block( ecx );
239         } else {
240                 unsigned int temp;
241                 int temp_offset;
242                 int p1, p2, o1;
243
244                 linear_address += ddest;        // Skip to next block
245
246                 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
247                 p2 = (linear_address+ecx) >> 16;
248                 if ( p1 != ibitblt_svga_page ) {
249                         // Set page
250                         // MOV EAX, 0
251                         *Code_pointer++ = OPCODE_MOV_EAX;
252                         temp = p1;
253                         memcpy( Code_pointer, &temp, sizeof(int) );
254                         Code_pointer += sizeof(int);
255                         // CALL EBX
256                         *Code_pointer++ = OPCODE_CALL_EBX1;
257                         *Code_pointer++ = OPCODE_CALL_EBX2;
258                         ibitblt_svga_page = p1;
259                 }
260
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;
266
267                 if ( p1 == p2 ) {
268                         draw_block( ecx );
269                 } else {
270                         int nbytes;
271                         nbytes = 0xFFFF-o1+1;
272                         draw_block( nbytes );
273                         // set page
274                         // MOV EAX, 0
275                         *Code_pointer++ = OPCODE_MOV_EAX;
276                         temp = p2;
277                         memcpy( Code_pointer, &temp, sizeof(int) );
278                         Code_pointer += sizeof(int);
279                         // CALL EBX
280                         *Code_pointer++ = OPCODE_CALL_EBX1;
281                         *Code_pointer++ = OPCODE_CALL_EBX2;
282                         ibitblt_svga_page = p2;
283
284                         temp_offset = 0xA0000;
285                         *Code_pointer++ = OPCODE_MOV_EDI;
286                         iptr = (int *)Code_pointer;
287                         *iptr++ = temp_offset;
288                         Code_pointer = (ubyte *)iptr;
289
290                         nbytes = ecx - nbytes;
291                         if (nbytes > 0 )
292                                 draw_block( nbytes );
293                 }
294                 linear_address += ecx;
295         }
296
297 }
298
299 //-----------------------------------------------------------------------------------------
300 // Given bitmap, bmp, finds the size of the code
301
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 )
303 {
304         int x,y;
305         ubyte pixel;
306         int draw_mode = MODE_NONE;
307         int source_offset = 0;
308         int dest_offset = 0;
309         int num_to_draw, draw_start_source, draw_start_dest;
310         int esi, edi;
311
312         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
313
314         Code_counter = 0;
315
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;
321                 linear_address = 0;
322                 is_svga = 1;
323         } else {
324                 is_svga = 0;
325         }
326
327         esi = source_offset = 0;
328         edi = dest_offset = 0;
329         draw_start_source = draw_start_dest = 0;
330
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];
335                         if ( pixel!=255 ) {
336                                 switch ( draw_mode) {
337                                 case MODE_DRAW:
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;
341                                         // fall through!!!
342                                 case MODE_NONE:
343                                 case MODE_SKIP:
344                                         break;
345                                 }
346                                 draw_mode = MODE_SKIP;
347                         } else {
348                                 switch ( draw_mode) {
349                                 case MODE_SKIP:
350                                 case MODE_NONE:
351                                         draw_start_source = source_offset;
352                                         draw_start_dest = dest_offset;
353                                         num_to_draw = 0;
354                                         // fall through
355                                 case MODE_DRAW:
356                                         num_to_draw++;
357                                         break;
358                                 }
359                                 draw_mode = MODE_DRAW;
360                         }
361                         source_offset++;
362                 }
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;
367                 }
368                 draw_mode = MODE_NONE;
369                 source_offset += (srowsize - sw);
370         }
371         Code_counter++;     // for return
372
373         //printf( "Code will be %d bytes\n", Code_counter );
374
375         Code_counter += 16; // for safety was 16
376
377         return Code_counter;
378 }
379
380 int gr_ibitblt_find_code_size( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
381 {
382         return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
383 }
384
385 int gr_ibitblt_find_code_size_svga( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
386 {
387         return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_SVGA );
388 }
389
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.
393
394 ubyte   *gr_ibitblt_create_mask_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
395 {
396         int x,y;
397         ubyte pixel;
398         int draw_mode = MODE_NONE;
399         int source_offset = 0;
400         int dest_offset = 0;
401         int num_to_draw, draw_start_source, draw_start_dest;
402         int esi, edi;
403         int code_size;
404         ubyte *code;
405         uint temp;
406
407         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
408
409         if ( dest_type == BM_SVGA )
410                 code_size = gr_ibitblt_find_code_size_svga( mask_bmp, sx, sy, sw, sh, srowsize );
411         else
412                 code_size = gr_ibitblt_find_code_size( mask_bmp, sx, sy, sw, sh, srowsize );
413
414         code = malloc( code_size );
415         if ( code == NULL )
416                 return NULL;
417
418         Code_pointer = code;
419
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);
426                 // MOV EAX, 0
427                 *Code_pointer++ = OPCODE_MOV_EAX;
428                 temp = 0;
429                 memcpy( Code_pointer, &temp, sizeof(int) );
430                 Code_pointer += sizeof(int);
431                 // CALL EBX
432                 *Code_pointer++ = OPCODE_CALL_EBX1;
433                 *Code_pointer++ = OPCODE_CALL_EBX2;
434
435                 ibitblt_svga_page = 0;
436                 is_svga = 1;
437                 linear_address = 0;
438         } else {
439                 is_svga = 0;
440         }
441         esi = source_offset = 0;
442         edi = dest_offset = 0;
443         draw_start_source = draw_start_dest = 0;
444
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];
449                         if ( pixel!=255 ) {
450                                 switch ( draw_mode) {
451                                 case MODE_DRAW:
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;
455                                         // fall through!!!
456                                 case MODE_NONE:
457                                 case MODE_SKIP:
458                                         break;
459                                 }
460                                 draw_mode = MODE_SKIP;
461                         } else {
462                                 switch ( draw_mode) {
463                                 case MODE_SKIP:
464                                 case MODE_NONE:
465                                         draw_start_source = source_offset;
466                                         draw_start_dest = dest_offset;
467                                         num_to_draw = 0;
468                                         // fall through
469                                 case MODE_DRAW:
470                                         num_to_draw++;
471                                         break;
472                                 }
473                                 draw_mode = MODE_DRAW;
474                         }
475                         source_offset++;
476                 }
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;
481                 }
482                 draw_mode = MODE_NONE;
483                 source_offset += (srowsize - sw);
484         }
485         *Code_pointer++ = OPCODE_RET;
486
487         if ( Code_pointer >= &code[code_size-1] )
488                 Error( "ibitblt overwrote allocated code block\n" );
489
490         //printf( "Code is %d bytes\n", Code_pointer - code );
491
492         return code;
493 }
494
495 ubyte   *gr_ibitblt_create_mask( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
496 {
497         return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
498 }
499
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)
502 {
503         if(w == 0 || h == 0)
504                 return buf;
505
506         if(gencode)
507         {
508                 buf[0] = (w << 16)  | h;
509                 buf[1] = (sx << 16) | sy;
510                 buf[2] = (dx << 16) | dy;
511         }
512         return buf + 3;
513 }
514
515 ubyte   *gr_ibitblt_create_mask_pa( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
516 {
517         unsigned long *ret, *code = 0;
518         int pass, x, y, n;
519         ushort *s;
520
521         Assert(mask_bmp->bm_type == BM_LINEAR15);
522
523         srowsize /= PA_BPP;
524
525         pa_flush();
526
527         // make two passes, first pass gets size of output block, second actually creates data.
528         for(pass = 0; pass != 2; ++pass)
529         {
530                 for (y = sy; y < sy + sh; y++ )
531                 {
532                         // first byte of interest in mask
533                         s = (ushort *)(mask_bmp->bm_data + y * mask_bmp->bm_rowsize + sx * PA_BPP);
534                         for ( x=0; x < sw; )
535                         {
536                                 for(; x != sw && (s[x] & 0x8000); ++x)              // while opaque...
537                                         ;
538                                 for(n = 0; x != sw && !(s[x] & 0x8000); ++n, ++x)   // while transparent...
539                                         ;
540                                 code = pa_emit_blit(pass, code, n, 1, x - n, y - sy, x + sx - n, y);
541                         }
542                 }
543                 if(pass == 0)
544                 {
545                         ret = malloc((int)code + sizeof(unsigned long));
546                         ret[0] = (int)code / sizeof(unsigned long);        // store num unsigned longs in list.
547                         code = ret + 1;
548                 }
549         }
550         return (ubyte *)ret;
551 }
552
553 #else
554 ubyte   *gr_ibitblt_create_mask_svga( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
555 {
556         return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_SVGA );
557 }
558 #endif
559
560
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] = \
563     "pusha"         \
564     "cld"           \
565     "call   eax"    \
566     "popa"
567
568
569 void gr_ibitblt(grs_bitmap * source_bmp, grs_bitmap * dest_bmp, ubyte * mask )
570 {
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);
574 #else
575         if (mask != NULL )
576                 gr_ibitblt_do_asm( source_bmp->bm_data, dest_bmp->bm_data, mask );
577 #endif
578 }
579
580
581 void    gr_ibitblt_find_hole_size( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
582 {
583         int x, y, count=0;
584 #if defined(POLY_ACC)
585         short c;
586 #else
587         ubyte c;
588 #endif
589
590         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
591
592 #if defined(POLY_ACC)
593         Assert(mask_bmp->bm_type == BM_LINEAR15);
594         pa_flush();
595 #endif
596
597         *minx = mask_bmp->bm_w-1;
598         *maxx = 0;
599         *miny = mask_bmp->bm_h-1;
600         *maxy = 0;
601
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.
607 #else
608                         c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
609                         if (c == 255 ) {
610 #endif
611                                 if ( x < *minx ) *minx = x;
612                                 if ( y < *miny ) *miny = y;
613                                 if ( x > *maxx ) *maxx = x;
614                                 if ( y > *maxy ) *maxy = y;
615                                 count++;
616                         }
617                 }
618
619         if ( count == 0 ) {
620                 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
621         }
622 }
623
624 #else /* __MSDOS__ */ // was: /* !MACINTOSH */
625
626 #include "pa_enabl.h"
627 #include "pstypes.h"
628 #include "gr.h"
629 #include "ibitblt.h"
630 #include "error.h"
631 #include "u_mem.h"
632 #include "grdef.h"
633
634 #if defined(POLY_ACC)
635 #include "poly_acc.h"
636 #endif
637
638 #define FIND_START      1
639 #define FIND_STOP       2
640
641 #define MAX_WIDTH       640
642 #define MAX_SCANLINES   480
643 #define MAX_HOLES       5
644
645 static short start_points[MAX_SCANLINES][MAX_HOLES];
646 static short hole_length[MAX_SCANLINES][MAX_HOLES];
647 static double *scanline = NULL;
648
649 void gr_ibitblt(grs_bitmap *src_bmp, grs_bitmap *dest_bmp, ubyte pixel_double)
650 {
651         int x, y, sw, sh, srowsize, drowsize, dstart, sy, dy;
652         ubyte *src, *dest;
653         short *current_hole, *current_hole_length;
654
655 // variable setup
656
657 #if defined(POLY_ACC)
658         if ( PAEnabled )
659                 return;
660 #endif
661
662         sw = src_bmp->bm_w;
663         sh = src_bmp->bm_h;
664         srowsize = src_bmp->bm_rowsize;
665         drowsize = dest_bmp->bm_rowsize;
666         src = src_bmp->bm_data;
667         dest = dest_bmp->bm_data;
668
669         sy = 0;
670         while (start_points[sy][0] == -1) {
671                 sy++;
672                 dest += drowsize;
673         }
674
675         if (pixel_double) {
676                 ubyte *scan = (ubyte *)scanline;    // set up for byte processing of scanline
677
678                 dy = sy;
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)
685                                         break;
686                                 dstart = *current_hole;
687                                 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
688                                 current_hole++;
689                                 current_hole_length++;
690                         }
691                         dy++;
692                         dest += drowsize;
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)
697                                         break;
698                                 dstart = *current_hole;
699                                 gr_linear_movsd(&(scan[dstart]), &(dest[dstart]), *current_hole_length);
700                                 current_hole++;
701                                 current_hole_length++;
702                         }
703                         dy++;
704                         dest += drowsize;
705                         src += srowsize;
706                 }
707         } else {
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)
713                                         break;
714                                 dstart = start_points[y][x];
715                                 gr_linear_movsd(&(src[dstart]), &(dest[dstart]), hole_length[y][x]);
716                         }
717                         dest += drowsize;
718                         src += srowsize;
719                 }
720         }
721 }
722
723 #if defined(POLY_ACC)
724
725 unsigned long *pa_emit_blit(int gencode, unsigned long *buf, int w, int h, int sx, int sy, int dx, int dy)
726 {
727         if(w == 0 || h == 0)
728                 return buf;
729
730         if(gencode)
731         {
732                 buf[0] = (w << 16)  | h;
733                 buf[1] = (sx << 16) | sy;
734                 buf[2] = (dx << 16) | dy;
735         }
736         return buf + 3;
737 }
738
739 void gr_ibitblt_create_mask_pa( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
740 {
741         unsigned long *ret, *code = 0;
742         int pass, x, y, n;
743         ushort *s;
744
745         Assert(mask_bmp->bm_type == BM_LINEAR15);
746
747         srowsize /= PA_BPP;
748
749         pa_flush();
750
751         // make two passes, first pass gets size of output block, second actually creates data.
752         for(pass = 0; pass != 2; ++pass)
753         {
754                 for (y = sy; y < sy + sh; y++ )
755                 {
756                         // first byte of interest in mask
757                         s = (ushort *)(mask_bmp->bm_data + y * mask_bmp->bm_rowsize + sx * PA_BPP);
758                         for ( x=0; x < sw; )
759                         {
760                                 for(; x != sw && (s[x] & 0x8000); ++x)              // while opaque...
761                                         ;
762                                 for(n = 0; x != sw && !(s[x] & 0x8000); ++n, ++x)   // while transparent...
763                                         ;
764                                 code = pa_emit_blit(pass, code, n, 1, x - n, y - sy, x + sx - n, y);
765                         }
766                 }
767
768                 if(pass == 0) {
769                         ret = malloc((int)code + sizeof(unsigned long));
770                         ret[0] = (int)code / sizeof(unsigned long);        // store num unsigned longs in list.
771                         code = ret + 1;
772                 }
773         }
774 //      return (ubyte *)ret;
775 }
776 #endif
777
778 void gr_ibitblt_create_mask(grs_bitmap *mask_bmp, int sx, int sy, int sw, int sh, int srowsize)
779 {
780         int x, y;
781         ubyte mode;
782         int count = 0;
783
784         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
785
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;
790                 }
791         }
792
793         for (y = sy; y < sy+sh; y++) {
794                 count = 0;
795                 mode = FIND_START;
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;
799                                 mode = FIND_STOP;
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];
802                                 count++;
803                                 mode = FIND_START;
804                         }
805                 }
806                 if (mode == FIND_STOP) {
807                         hole_length[y][count] = x - start_points[y][count];
808                         count++;
809                 }
810                 Assert(count <= MAX_HOLES);
811         }
812 }
813
814 #if defined(POLY_ACC)
815
816 void gr_ibitblt_find_hole_size_pa( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
817 {
818         int x, y, count=0;
819         short c;
820
821         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
822
823         Assert(mask_bmp->bm_type == BM_LINEAR15);
824         while(!pa_idle());
825
826         *minx = mask_bmp->bm_w-1;
827         *maxx = 0;
828         *miny = mask_bmp->bm_h-1;
829         *maxy = 0;
830
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;
839                                 count++;
840                         }
841                 }
842
843         if ( count == 0 ) {
844                 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
845         }
846 }
847 #endif
848
849 void gr_ibitblt_find_hole_size(grs_bitmap *mask_bmp, int *minx, int *miny, int *maxx, int *maxy)
850 {
851         ubyte c;
852         int x, y, count = 0;
853
854 #if defined(POLY_ACC)
855         if ( PAEnabled ) {
856                 gr_ibitblt_find_hole_size_pa( mask_bmp, minx, miny, maxx, maxy );
857                 return;
858         }
859 #endif
860
861         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
862         Assert( mask_bmp->bm_flags&BM_FLAG_TRANSPARENT );
863
864         *minx = mask_bmp->bm_w - 1;
865         *maxx = 0;
866         *miny = mask_bmp->bm_h - 1;
867         *maxy = 0;
868
869         if (scanline == NULL)
870                 scanline = (double *)malloc(sizeof(double) * (MAX_WIDTH / sizeof(double)));
871
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.
876                                 count++;
877                                 if (x < *minx) *minx = x;
878                                 if (y < *miny) *miny = y;
879                                 if (x > *maxx) *maxx = x;
880                                 if (y > *maxy) *maxy = y;
881                         }
882                 }
883         }
884         Assert (count);
885 }
886
887 #endif /* __MSDOS__ */ // was: /* !MACINTOSH */