]> icculus.org git repositories - btb/d2x.git/blob - 2d/ibitblt.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / 2d / ibitblt.c
1 /* $Id: ibitblt.c,v 1.12 2005-07-30 09:17:06 chris 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.12 2005-07-30 09:17:06 chris 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 "types.h"
46 #include "gr.h"
47 #include "mem.h"
48 #include "error.h"
49 #include "ibitblt.h"
50 #include "grdef.h"
51
52 #define MODE_NONE           0
53 #define MODE_SKIP           1
54 #define MODE_DRAW           2
55
56 #define OPCODE_ADD          0x81
57 #define OPCODE_ESI          0xC6        // Followed by a dword  (add esi, ????)
58 #define OPCODE_EDI          0xC7        // Followed by a dword  (add edi, ????)
59 #define OPCODE_MOV_ECX      0xB9        // Followed by a dword  (mov ecx,????)
60 #define OPCODE_MOVSB        0xA4        // movsb
61 #define OPCODE_16BIT        0x66        // movsw
62 #define OPCODE_MOVSD        0xA5        // movsd
63 #define OPCODE_REP          0xF3        // rep
64 #define OPCODE_RET          0xC3        // ret
65 #define OPCODE_MOV_EAX      0xB8        // mov eax, im dword
66 #define OPCODE_MOV_EBX      0xBB        // mov ebx, im dword
67 #define OPCODE_CALL_EBX1    0xFF        // call
68 #define OPCODE_CALL_EBX2    0xD3        //      ebx
69 #define OPCODE_MOV_EDI      0xBF        // mov edi, im dword
70
71
72 ubyte *Code_pointer = NULL;
73 int Code_counter = 0;
74 int ibitblt_svga_page = 0;
75 int is_svga = 0;
76 uint linear_address;
77
78
79
80 void count_block( int ecx )
81 {
82         int blocks;
83
84         while ( ecx > 0 ) {
85                 switch(ecx) {
86                 case 1: Code_counter++; ecx = 0; break;     // MOVSB
87                 case 2: Code_counter+=2; ecx = 0; break;    // MOVSW
88                 case 3: Code_counter+=3; ecx = 0; break;    // MOVSW, MOVSB
89                 case 4: Code_counter++; ecx = 0; break;     // MOVSD
90                 default:
91                         blocks = ecx / 4;
92                         if ( blocks == 1 )
93                                 Code_counter++; // MOVSD
94                         else
95                                 Code_counter+=7;
96                         ecx -= blocks*4;
97                 }
98         }
99 }
100
101
102 void move_and_count( int dsource, int ddest, int ecx )
103 {
104         if ( ecx <= 0 )
105                 return;
106
107         if ( dsource > 0 ) {
108                 // ADD ESI, dsource
109                 Code_counter += 6;
110         }
111         if ( !is_svga ) {
112                 if ( ddest > 0 ) {
113                         // ADD EDI, ddest
114                         Code_counter += 6;
115                 }
116                 count_block( ecx );
117         } else {
118                 int p1, p2, o1;
119
120                 linear_address += ddest;        // Skip to next block
121
122                 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
123                 p2 = (linear_address+ecx) >> 16;
124                 if ( p1 != ibitblt_svga_page ) {
125                         // Set page
126                         // MOV EAX, ?, CALL EBX
127                         Code_counter += 7;
128                         ibitblt_svga_page = p1;
129                 }
130
131                 Code_counter += 5;  // mov edi, ????
132
133                 if ( p1 == p2 ) {
134                         count_block( ecx );
135                 } else {
136                         int nbytes;
137                         nbytes = 0xFFFF-o1+1;
138                         count_block( nbytes );
139                         // set page
140                         // MOV EAX, 0
141                         Code_counter += 7;  // mov eax,???? call ebx
142
143                         ibitblt_svga_page = p2;
144
145                         Code_counter += 5;  // mov edi, ????
146
147                         nbytes = ecx - nbytes;
148                         if (nbytes > 0 )
149                                 count_block( nbytes );
150                 }
151                 linear_address += ecx;
152         }
153 }
154
155
156
157 void draw_block( int ecx )
158 {
159         int blocks;
160         int * iptr;
161
162         while ( ecx > 0 )   {
163                 switch( ecx )   {
164                 case 1:
165                         // MOVSB
166                         *Code_pointer++ = OPCODE_MOVSB;
167                         ecx = 0;
168                         break;
169                 case 2:
170                         // MOVSW
171                         *Code_pointer++ = OPCODE_16BIT;
172                         *Code_pointer++ = OPCODE_MOVSD;
173                         ecx = 0;
174                         break;
175                 case 3:
176                         // MOVSW, MOVSB
177                         *Code_pointer++ = OPCODE_16BIT;
178                         *Code_pointer++ = OPCODE_MOVSD;
179                         *Code_pointer++ = OPCODE_MOVSB;
180                         ecx = 0;
181                         break;
182                 case 4:
183                         // MOVSD
184                         *Code_pointer++ = OPCODE_MOVSD;
185                         ecx = 0;
186                         break;
187                 default:
188                         blocks = ecx / 4;
189
190                         if ( blocks == 1 ) {
191                                 // MOVSD
192                                 *Code_pointer++ = OPCODE_MOVSD;
193                         } else {
194                                 // MOV ECX, blocks
195                                 *Code_pointer++ = OPCODE_MOV_ECX;
196                                 iptr = (int *)Code_pointer;
197                                 *iptr++ = blocks;
198                                 Code_pointer = (ubyte *)iptr;
199                                 // REP MOVSD
200                                 *Code_pointer++ = OPCODE_REP;
201                                 *Code_pointer++ = OPCODE_MOVSD;
202                         }
203                         ecx -= blocks*4;
204                 }
205         }
206 }
207
208
209 void move_and_draw( int dsource, int ddest, int ecx )
210 {
211         int * iptr;
212
213         if ( ecx <= 0 )
214                 return;
215
216         if ( dsource > 0 ) {
217                 // ADD ESI, dsource
218                 *Code_pointer++ = OPCODE_ADD;
219                 *Code_pointer++ = OPCODE_ESI;
220                 iptr = (int *)Code_pointer;
221                 *iptr++ = dsource;
222                 Code_pointer = (ubyte *)iptr;
223         }
224         if ( !is_svga ) {
225                 if ( ddest > 0 ) {
226                         // ADD EDI, ddest
227                         *Code_pointer++ = OPCODE_ADD;
228                         *Code_pointer++ = OPCODE_EDI;
229                         iptr = (int *)Code_pointer;
230                         *iptr++ = ddest;
231                         Code_pointer = (ubyte *)iptr;
232                 }
233                 draw_block( ecx );
234         } else {
235                 unsigned int temp;
236                 int temp_offset;
237                 int p1, p2, o1;
238
239                 linear_address += ddest;        // Skip to next block
240
241                 p1 = linear_address >> 16; o1 = linear_address & 0xFFFF;
242                 p2 = (linear_address+ecx) >> 16;
243                 if ( p1 != ibitblt_svga_page ) {
244                         // Set page
245                         // MOV EAX, 0
246                         *Code_pointer++ = OPCODE_MOV_EAX;
247                         temp = p1;
248                         memcpy( Code_pointer, &temp, sizeof(int) );
249                         Code_pointer += sizeof(int);
250                         // CALL EBX
251                         *Code_pointer++ = OPCODE_CALL_EBX1;
252                         *Code_pointer++ = OPCODE_CALL_EBX2;
253                         ibitblt_svga_page = p1;
254                 }
255
256                 temp_offset = 0xA0000 + o1;
257                 *Code_pointer++ = OPCODE_MOV_EDI;
258                 iptr = (int *)Code_pointer;
259                 *iptr++ = temp_offset;
260                 Code_pointer = (ubyte *)iptr;
261
262                 if ( p1 == p2 ) {
263                         draw_block( ecx );
264                 } else {
265                         int nbytes;
266                         nbytes = 0xFFFF-o1+1;
267                         draw_block( nbytes );
268                         // set page
269                         // MOV EAX, 0
270                         *Code_pointer++ = OPCODE_MOV_EAX;
271                         temp = p2;
272                         memcpy( Code_pointer, &temp, sizeof(int) );
273                         Code_pointer += sizeof(int);
274                         // CALL EBX
275                         *Code_pointer++ = OPCODE_CALL_EBX1;
276                         *Code_pointer++ = OPCODE_CALL_EBX2;
277                         ibitblt_svga_page = p2;
278
279                         temp_offset = 0xA0000;
280                         *Code_pointer++ = OPCODE_MOV_EDI;
281                         iptr = (int *)Code_pointer;
282                         *iptr++ = temp_offset;
283                         Code_pointer = (ubyte *)iptr;
284
285                         nbytes = ecx - nbytes;
286                         if (nbytes > 0 )
287                                 draw_block( nbytes );
288                 }
289                 linear_address += ecx;
290         }
291
292 }
293
294 //-----------------------------------------------------------------------------------------
295 // Given bitmap, bmp, finds the size of the code
296
297 int gr_ibitblt_find_code_size_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
298 {
299         int x,y;
300         ubyte pixel;
301         int draw_mode = MODE_NONE;
302         int source_offset = 0;
303         int dest_offset = 0;
304         int num_to_draw, draw_start_source, draw_start_dest;
305         int esi, edi;
306
307         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
308
309         Code_counter = 0;
310
311         if ( dest_type == BM_SVGA ) {
312                 Code_counter += 1+4;    // move ebx, gr_vesa_set_page
313                 Code_counter += 1+4;    // move eax, 0
314                 Code_counter += 2;      // call ebx
315                 ibitblt_svga_page = 0;
316                 linear_address = 0;
317                 is_svga = 1;
318         } else {
319                 is_svga = 0;
320         }
321
322         esi = source_offset = 0;
323         edi = dest_offset = 0;
324         draw_start_source = draw_start_dest = 0;
325
326         for ( y=sy; y<sy+sh; y++ ) {
327                 for ( x=sx; x<sx+sw; x++ ) {
328                         dest_offset = y*mask_bmp->bm_rowsize+x;
329                         pixel = mask_bmp->bm_data[dest_offset];
330                         if ( pixel!=255 ) {
331                                 switch ( draw_mode) {
332                                 case MODE_DRAW:
333                                         move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
334                                         esi = draw_start_source + num_to_draw;
335                                         edi = draw_start_dest + num_to_draw;
336                                         // fall through!!!
337                                 case MODE_NONE:
338                                 case MODE_SKIP:
339                                         break;
340                                 }
341                                 draw_mode = MODE_SKIP;
342                         } else {
343                                 switch ( draw_mode) {
344                                 case MODE_SKIP:
345                                 case MODE_NONE:
346                                         draw_start_source = source_offset;
347                                         draw_start_dest = dest_offset;
348                                         num_to_draw = 0;
349                                         // fall through
350                                 case MODE_DRAW:
351                                         num_to_draw++;
352                                         break;
353                                 }
354                                 draw_mode = MODE_DRAW;
355                         }
356                         source_offset++;
357                 }
358                 if ( draw_mode == MODE_DRAW ) {
359                         move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
360                         esi = draw_start_source + num_to_draw;
361                         edi = draw_start_dest + num_to_draw;
362                 }
363                 draw_mode = MODE_NONE;
364                 source_offset += (srowsize - sw);
365         }
366         Code_counter++;     // for return
367
368         //printf( "Code will be %d bytes\n", Code_counter );
369
370         Code_counter += 16; // for safety was 16
371
372         return Code_counter;
373 }
374
375 int gr_ibitblt_find_code_size( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
376 {
377         return gr_ibitblt_find_code_size_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
378 }
379
380 int gr_ibitblt_find_code_size_svga( 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_SVGA );
383 }
384
385 //-----------------------------------------------------------------------------------------
386 // Given bitmap, bmp, create code that transfers a bitmap of size sw*sh to position
387 // (sx,sy) on top of bmp, only overwritting transparent pixels of the bitmap.
388
389 ubyte   *gr_ibitblt_create_mask_sub( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize, int dest_type )
390 {
391         int x,y;
392         ubyte pixel;
393         int draw_mode = MODE_NONE;
394         int source_offset = 0;
395         int dest_offset = 0;
396         int num_to_draw, draw_start_source, draw_start_dest;
397         int esi, edi;
398         int code_size;
399         ubyte *code;
400         uint temp;
401
402         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
403
404         if ( dest_type == BM_SVGA )
405                 code_size = gr_ibitblt_find_code_size_svga( mask_bmp, sx, sy, sw, sh, srowsize );
406         else
407                 code_size = gr_ibitblt_find_code_size( mask_bmp, sx, sy, sw, sh, srowsize );
408
409         code = malloc( code_size );
410         if ( code == NULL )
411                 return NULL;
412
413         Code_pointer = code;
414
415         if ( dest_type == BM_SVGA ) {
416                 // MOV EBX, gr_vesa_setpage
417                 *Code_pointer++ = OPCODE_MOV_EBX;
418                 temp = (uint)gr_vesa_setpage;
419                 memcpy( Code_pointer, &temp, sizeof(int) );
420                 Code_pointer += sizeof(int);
421                 // MOV EAX, 0
422                 *Code_pointer++ = OPCODE_MOV_EAX;
423                 temp = 0;
424                 memcpy( Code_pointer, &temp, sizeof(int) );
425                 Code_pointer += sizeof(int);
426                 // CALL EBX
427                 *Code_pointer++ = OPCODE_CALL_EBX1;
428                 *Code_pointer++ = OPCODE_CALL_EBX2;
429
430                 ibitblt_svga_page = 0;
431                 is_svga = 1;
432                 linear_address = 0;
433         } else {
434                 is_svga = 0;
435         }
436         esi = source_offset = 0;
437         edi = dest_offset = 0;
438         draw_start_source = draw_start_dest = 0;
439
440         for ( y=sy; y<sy+sh; y++ ) {
441                 for ( x=sx; x<sx+sw; x++ ) {
442                         dest_offset = y*mask_bmp->bm_rowsize+x;
443                         pixel = mask_bmp->bm_data[dest_offset];
444                         if ( pixel!=255 ) {
445                                 switch ( draw_mode) {
446                                 case MODE_DRAW:
447                                         move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
448                                         esi = draw_start_source + num_to_draw;
449                                         edi = draw_start_dest + num_to_draw;
450                                         // fall through!!!
451                                 case MODE_NONE:
452                                 case MODE_SKIP:
453                                         break;
454                                 }
455                                 draw_mode = MODE_SKIP;
456                         } else {
457                                 switch ( draw_mode) {
458                                 case MODE_SKIP:
459                                 case MODE_NONE:
460                                         draw_start_source = source_offset;
461                                         draw_start_dest = dest_offset;
462                                         num_to_draw = 0;
463                                         // fall through
464                                 case MODE_DRAW:
465                                         num_to_draw++;
466                                         break;
467                                 }
468                                 draw_mode = MODE_DRAW;
469                         }
470                         source_offset++;
471                 }
472                 if ( draw_mode == MODE_DRAW ) {
473                         move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
474                         esi = draw_start_source + num_to_draw;
475                         edi = draw_start_dest + num_to_draw;
476                 }
477                 draw_mode = MODE_NONE;
478                 source_offset += (srowsize - sw);
479         }
480         *Code_pointer++ = OPCODE_RET;
481
482         if ( Code_pointer >= &code[code_size-1] )
483                 Error( "ibitblt overwrote allocated code block\n" );
484
485         //printf( "Code is %d bytes\n", Code_pointer - code );
486
487         return code;
488 }
489
490 ubyte   *gr_ibitblt_create_mask( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
491 {
492         return gr_ibitblt_create_mask_sub( mask_bmp, sx, sy, sw, sh, srowsize, BM_LINEAR );
493 }
494
495 ubyte   *gr_ibitblt_create_mask_svga( 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_SVGA );
498 }
499
500
501 void gr_ibitblt_do_asm(char *start_si, char *start_di, ubyte * code);
502 #pragma aux gr_ibitblt_do_asm parm [esi] [edi] [eax] modify [ecx edi esi eax] = \
503     "pusha"         \
504     "cld"           \
505     "call   eax"    \
506     "popa"
507
508
509 void gr_ibitblt(grs_bitmap * source_bmp, grs_bitmap * dest_bmp, ubyte * mask )
510 {
511         if (mask != NULL )
512                 gr_ibitblt_do_asm( source_bmp->bm_data, dest_bmp->bm_data, mask );
513 }
514
515
516 void    gr_ibitblt_find_hole_size( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
517 {
518         int x, y, count=0;
519         ubyte c;
520
521         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
522
523         *minx = mask_bmp->bm_w-1;
524         *maxx = 0;
525         *miny = mask_bmp->bm_h-1;
526         *maxy = 0;
527
528         for ( y=0; y<mask_bmp->bm_h; y++ )
529                 for ( x=0; x<mask_bmp->bm_w; x++ ) {
530                         c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
531                         if (c == 255 ) {
532                                 if ( x < *minx ) *minx = x;
533                                 if ( y < *miny ) *miny = y;
534                                 if ( x > *maxx ) *maxx = x;
535                                 if ( y > *maxy ) *maxy = y;
536                                 count++;
537                         }
538                 }
539
540         if ( count == 0 ) {
541                 Error( "Bitmap for ibitblt doesn't have transparency!\n" );
542         }
543 }
544
545 #else /* __MSDOS__ */ // was: /* !MACINTOSH */
546
547 #include "pstypes.h"
548 #include "gr.h"
549 #include "ibitblt.h"
550 #include "error.h"
551 #include "u_mem.h"
552 #include "grdef.h"
553
554 #define FIND_START      1
555 #define FIND_STOP       2
556
557 #define MAX_WIDTH       640
558 #define MAX_SCANLINES   480
559 #define MAX_HOLES       5
560
561 static short start_points[MAX_SCANLINES][MAX_HOLES];
562 static short hole_length[MAX_SCANLINES][MAX_HOLES];
563 static double *scanline = NULL;
564
565 void gr_ibitblt(grs_bitmap *src_bmp, grs_bitmap *dest_bmp)
566 {
567         int x, y, sw, sh, srowsize, drowsize, dstart, sy;
568         ubyte *src, *dest;
569
570 // variable setup
571
572         sw = src_bmp->bm_w;
573         sh = src_bmp->bm_h;
574         srowsize = src_bmp->bm_rowsize;
575         drowsize = dest_bmp->bm_rowsize;
576         src = src_bmp->bm_data;
577         dest = dest_bmp->bm_data;
578
579         sy = 0;
580         while (start_points[sy][0] == -1) {
581                 sy++;
582                 dest += drowsize;
583         }
584
585         Assert(sw <= MAX_WIDTH);
586         Assert(sh <= MAX_SCANLINES);
587         for (y = sy; y < sy + sh; y++) {
588                 for (x = 0; x < MAX_HOLES; x++) {
589                         if (start_points[y][x] == -1)
590                                 break;
591                         dstart = start_points[y][x];
592                         gr_linear_movsd(&(src[dstart]), &(dest[dstart]), hole_length[y][x]);
593                 }
594                 dest += drowsize;
595                 src += srowsize;
596         }
597 }
598
599 void gr_ibitblt_create_mask(grs_bitmap *mask_bmp, int sx, int sy, int sw, int sh, int srowsize)
600 {
601         int x, y;
602         ubyte mode;
603         int count = 0;
604
605         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
606
607         for (y = 0; y < MAX_SCANLINES; y++) {
608                 for (x = 0; x < MAX_HOLES; x++) {
609                         start_points[y][x] = -1;
610                         hole_length[y][x] = -1;
611                 }
612         }
613
614         for (y = sy; y < sy+sh; y++) {
615                 count = 0;
616                 mode = FIND_START;
617                 for (x = sx; x < sx + sw; x++) {
618                         if ((mode == FIND_START) && (mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x] == TRANSPARENCY_COLOR)) {
619                                 start_points[y][count] = x;
620                                 mode = FIND_STOP;
621                         } else if ((mode == FIND_STOP) && (mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x] != TRANSPARENCY_COLOR)) {
622                                 hole_length[y][count] = x - start_points[y][count];
623                                 count++;
624                                 mode = FIND_START;
625                         }
626                 }
627                 if (mode == FIND_STOP) {
628                         hole_length[y][count] = x - start_points[y][count];
629                         count++;
630                 }
631                 Assert(count <= MAX_HOLES);
632         }
633 }
634
635 void gr_ibitblt_find_hole_size(grs_bitmap *mask_bmp, int *minx, int *miny, int *maxx, int *maxy)
636 {
637         ubyte c;
638         int x, y, count = 0;
639
640         Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
641         Assert( mask_bmp->bm_flags&BM_FLAG_TRANSPARENT );
642
643         *minx = mask_bmp->bm_w - 1;
644         *maxx = 0;
645         *miny = mask_bmp->bm_h - 1;
646         *maxy = 0;
647
648         if (scanline == NULL)
649                 scanline = (double *)malloc(sizeof(double) * (MAX_WIDTH / sizeof(double)));
650
651         for (y = 0; y < mask_bmp->bm_h; y++) {
652                 for (x = 0; x < mask_bmp->bm_w; x++) {
653                         c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
654                         if (c == TRANSPARENCY_COLOR) { // don't look for transparancy color here.
655                                 count++;
656                                 if (x < *minx) *minx = x;
657                                 if (y < *miny) *miny = y;
658                                 if (x > *maxx) *maxx = x;
659                                 if (y > *maxy) *maxy = y;
660                         }
661                 }
662         }
663         Assert (count);
664 }
665
666 #endif /* __MSDOS__ */ // was: /* !MACINTOSH */