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