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