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