1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Blitting functions.
12  *
13  *      By Shawn Hargreaves.
14  *
15  *      Dithering code by James Hyman.
16  *
17  *      Transparency preserving code by Elias Pschernig.
18  *
19  *      See readme.txt for copyright information.
20  */
21 
22 
23 #include <string.h>
24 #include "allegro.h"
25 #include "allegro/internal/aintern.h"
26 
27 
28 
29 /* get_replacement_mask_color:
30  *  Helper function to get a replacement color for the bitmap's mask color.
31  */
get_replacement_mask_color(BITMAP * bmp)32 static int get_replacement_mask_color(BITMAP *bmp)
33 {
34    int depth, c, g = 0;
35 
36    depth = bitmap_color_depth(bmp);
37 
38    if (depth == 8) {
39       if (rgb_map)
40          return rgb_map->data[31][1][31];
41       else
42          return bestfit_color(_current_palette, 63, 1, 63);
43    }
44    else {
45       do
46          c = makecol_depth(depth, 255, ++g, 255);
47       while (c == bitmap_mask_color(bmp));
48 
49       return c;
50    }
51 }
52 
53 
54 
55 /* blit_from_256:
56  *  Expands 256 color images onto a truecolor destination.
57  */
blit_from_256(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)58 static void blit_from_256(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
59 {
60    #ifdef ALLEGRO_COLOR8
61 
62    int *dest_palette_color;
63    uintptr_t s, d;
64    unsigned char *ss;
65    int x, y, c, rc;
66 
67    /* lookup table avoids repeated color format conversions */
68    if (_color_conv & COLORCONV_KEEP_TRANS) {
69       dest_palette_color = _AL_MALLOC_ATOMIC(256*sizeof(int));
70       memcpy(dest_palette_color, _palette_expansion_table(bitmap_color_depth(dest)), 256*sizeof(int));
71 
72       rc = get_replacement_mask_color(dest);
73 
74       dest_palette_color[MASK_COLOR_8] = bitmap_mask_color(dest);
75 
76       for (c=0; c<256; c++) {
77          if ((c != MASK_COLOR_8) &&
78              (dest_palette_color[c] == bitmap_mask_color(dest)))
79             dest_palette_color[c] = rc;
80       }
81    }
82    else
83       dest_palette_color = _palette_expansion_table(bitmap_color_depth(dest));
84 
85    /* worker macro */
86    #define EXPAND_BLIT(bits, dsize)                                          \
87    {                                                                         \
88       if (is_memory_bitmap(src)) {                                           \
89          /* fast version when reading from memory bitmap */                  \
90          bmp_select(dest);                                                   \
91                                                                              \
92          for (y=0; y<h; y++) {                                               \
93             ss = src->line[s_y+y] + s_x;                                     \
94             d = bmp_write_line(dest, d_y+y) + d_x*dsize;                     \
95                                                                              \
96             for (x=0; x<w; x++) {                                            \
97                bmp_write##bits(d, dest_palette_color[*ss]);                  \
98                ss++;                                                         \
99                d += dsize;                                                   \
100             }                                                                \
101          }                                                                   \
102                                                                              \
103          bmp_unwrite_line(dest);                                             \
104       }                                                                      \
105       else {                                                                 \
106          /* slower version when reading from the screen */                   \
107          for (y=0; y<h; y++) {                                               \
108             s = bmp_read_line(src, s_y+y) + s_x;                             \
109             d = bmp_write_line(dest, d_y+y) + d_x*dsize;                     \
110                                                                              \
111             for (x=0; x<w; x++) {                                            \
112                bmp_select(src);                                              \
113                c = bmp_read8(s);                                             \
114                                                                              \
115                bmp_select(dest);                                             \
116                bmp_write##bits(d, dest_palette_color[c]);                    \
117                                                                              \
118                s++;                                                          \
119                d += dsize;                                                   \
120             }                                                                \
121          }                                                                   \
122                                                                              \
123          bmp_unwrite_line(src);                                              \
124          bmp_unwrite_line(dest);                                             \
125       }                                                                      \
126    }
127 
128    /* expand the above macro for each possible output depth */
129    switch (bitmap_color_depth(dest)) {
130 
131       #ifdef ALLEGRO_COLOR16
132       case 15:
133       case 16:
134          EXPAND_BLIT(16, sizeof(int16_t));
135          break;
136       #endif
137 
138       #ifdef ALLEGRO_COLOR24
139       case 24:
140          EXPAND_BLIT(24, 3);
141          break;
142       #endif
143 
144       #ifdef ALLEGRO_COLOR32
145       case 32:
146          EXPAND_BLIT(32, sizeof(int32_t));
147          break;
148       #endif
149    }
150 
151    if (_color_conv & COLORCONV_KEEP_TRANS)
152       _AL_FREE(dest_palette_color);
153 
154    #endif
155 }
156 
157 
158 
159 /* worker macro for converting between two color formats, possibly with dithering */
160 #define CONVERT_BLIT_EX(sbits, ssize, dbits, dsize, MAKECOL)                 \
161 {                                                                            \
162    if (_color_conv & COLORCONV_KEEP_TRANS) {                                 \
163       int rc = get_replacement_mask_color(dest);                             \
164       int src_mask = bitmap_mask_color(src);                                 \
165       int dest_mask = bitmap_mask_color(dest);                               \
166                                                                              \
167       for (y=0; y<h; y++) {                                                  \
168 	 s = bmp_read_line(src, s_y+y) + s_x*ssize;                          \
169 	 d = bmp_write_line(dest, d_y+y) + d_x*dsize;                        \
170                                                                              \
171          for (x=0; x<w; x++) {                                               \
172             bmp_select(src);                                                 \
173             c = bmp_read##sbits(s);                                          \
174                                                                              \
175             if (c == src_mask)                                               \
176                c = dest_mask;                                                \
177             else {                                                           \
178 	       r = getr##sbits(c);                                           \
179 	       g = getg##sbits(c);                                           \
180 	       b = getb##sbits(c);                                           \
181                c = MAKECOL;                                                  \
182                if (c == dest_mask)                                           \
183 		 c = rc;			\
184             }                                                                \
185                                                                              \
186             bmp_select(dest);                                                \
187             bmp_write##dbits(d, c);                                          \
188                                                                              \
189             s += ssize;                                                      \
190             d += dsize;                                                      \
191          }                                                                   \
192       }                                                                      \
193    }                                                                         \
194    else {                                                                    \
195       for (y=0; y<h; y++) {                                                  \
196 	 s = bmp_read_line(src, s_y+y) + s_x*ssize;                          \
197 	 d = bmp_write_line(dest, d_y+y) + d_x*dsize;                        \
198                                                                              \
199          for (x=0; x<w; x++) {                                               \
200             bmp_select(src);                                                 \
201             c = bmp_read##sbits(s);                                          \
202                                                                              \
203             r = getr##sbits(c);                                              \
204             g = getg##sbits(c);                                              \
205             b = getb##sbits(c);                                              \
206                                                                              \
207             bmp_select(dest);                                                \
208             bmp_write##dbits(d, MAKECOL);                                    \
209                                                                              \
210             s += ssize;                                                      \
211             d += dsize;                                                      \
212          }                                                                   \
213       }                                                                      \
214    }                                                                         \
215                                                                              \
216    bmp_unwrite_line(src);                                                    \
217    bmp_unwrite_line(dest);                                                   \
218 }
219 
220 #define CONVERT_BLIT(sbits, ssize, dbits, dsize) \
221    CONVERT_BLIT_EX(sbits, ssize, dbits, dsize, makecol##dbits(r, g, b))
222 #define CONVERT_DITHER_BLIT(sbits, ssize, dbits, dsize) \
223    CONVERT_BLIT_EX(sbits, ssize, dbits, dsize, \
224                    makecol##dbits##_dither(r, g, b, x, y))
225 
226 
227 
228 #if (defined ALLEGRO_COLOR8) || (defined ALLEGRO_GFX_HAS_VGA)
229 
230 /* dither_blit:
231  *  Blits with Floyd-Steinberg error diffusion.
232  */
dither_blit(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)233 static void dither_blit(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
234 {
235    int prev_drawmode = _drawing_mode;
236    int *errline[3];
237    int *errnextline[3];
238    int errpixel[3];
239    int v[3], e[3], n[3];
240    int x, y, i;
241    int c, nc, rc;
242 
243    /* allocate memory for the error buffers */
244    for (i=0; i<3; i++) {
245       errline[i] = _AL_MALLOC_ATOMIC(sizeof(int) * w);
246       errnextline[i] = _AL_MALLOC_ATOMIC(sizeof(int) * w);
247    }
248 
249    /* free the buffers if there was an error allocating one */
250    for (i=0; i<3; i++) {
251       if ((!errline[i]) || (!errnextline[i]))
252       goto getout;
253    }
254 
255    /* initialize the error buffers */
256    for (i=0; i<3; i++) {
257       memset(errline[i], 0, sizeof(int) * w);
258       memset(errnextline[i], 0, sizeof(int) * w);
259       errpixel[i] = 0;
260    }
261 
262    /* get the replacement color */
263    rc = get_replacement_mask_color(dest);
264 
265    _drawing_mode = DRAW_MODE_SOLID;
266 
267    /* dither!!! */
268    for (y =0; y<h; y++) {
269       for (x =0; x<w; x++) {
270          /* get the colour from the source bitmap */
271          c = getpixel(src, s_x+x, s_y+y);
272          v[0] = getr_depth(bitmap_color_depth(src), c);
273          v[1] = getg_depth(bitmap_color_depth(src), c);
274          v[2] = getb_depth(bitmap_color_depth(src), c);
275 
276          /* add the error from previous pixels */
277          for (i=0; i<3; i++) {
278             n[i] = v[i] + errline[i][x] + errpixel[i];
279 
280             if (n[i] > 255)
281                n[i] = 255;
282 
283             if (n[i] < 0)
284                n[i] = 0;
285          }
286 
287          /* find the nearest matching colour */
288          nc = makecol8(n[0], n[1], n[2]);
289          if (_color_conv & COLORCONV_KEEP_TRANS) {
290             if (c == bitmap_mask_color(src))
291                putpixel(dest, d_x+x, d_y+y, bitmap_mask_color(dest));
292             else if (nc == bitmap_mask_color(dest))
293                putpixel(dest, d_x+x, d_y+y, rc);
294             else
295                putpixel(dest, d_x+x, d_y+y, nc);
296          }
297          else {
298             putpixel(dest, d_x+x, d_y+y, nc);
299          }
300          v[0] = getr8(nc);
301          v[1] = getg8(nc);
302          v[2] = getb8(nc);
303 
304          /* calculate the error and store it */
305          for (i=0; i<3; i++) {
306             e[i] = n[i] - v[i];
307             errpixel[i] = (int)((e[i] * 3)/8);
308             errnextline[i][x] += errpixel[i];
309 
310             if (x != w-1)
311                errnextline[i][x+1] = (int)(e[i]/4);
312          }
313       }
314 
315       /* update error buffers */
316       for (i=0; i<3; i++) {
317          memcpy(errline[i], errnextline[i], sizeof(int) * w);
318          memset(errnextline[i], 0, sizeof(int) * w);
319       }
320    }
321 
322    _drawing_mode = prev_drawmode;
323 
324  getout:
325 
326    for (i=0; i<3; i++) {
327       if (errline[i])
328          _AL_FREE(errline[i]);
329 
330       if (errnextline[i])
331          _AL_FREE(errnextline[i]);
332    }
333 }
334 
335 #endif
336 
337 
338 
339 /* blit_from_15:
340  *  Converts 15 bpp images onto some other destination format.
341  */
blit_from_15(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)342 static void blit_from_15(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
343 {
344    #ifdef ALLEGRO_COLOR16
345 
346    int x, y, c, r, g, b;
347    uintptr_t s, d;
348 
349    switch (bitmap_color_depth(dest)) {
350 
351       #ifdef ALLEGRO_COLOR8
352       case 8:
353          if (_color_conv & COLORCONV_DITHER_PAL)
354             dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h);
355          else
356             CONVERT_BLIT(15, sizeof(int16_t), 8, 1)
357          break;
358       #endif
359 
360       case 16:
361          CONVERT_BLIT(15, sizeof(int16_t), 16, sizeof(int16_t))
362          break;
363 
364       #ifdef ALLEGRO_COLOR24
365       case 24:
366          CONVERT_BLIT(15, sizeof(int16_t), 24, 3)
367          break;
368       #endif
369 
370       #ifdef ALLEGRO_COLOR32
371       case 32:
372          CONVERT_BLIT(15, sizeof(int16_t), 32, sizeof(int32_t))
373          break;
374       #endif
375    }
376 
377    #endif
378 }
379 
380 
381 
382 /* blit_from_16:
383  *  Converts 16 bpp images onto some other destination format.
384  */
blit_from_16(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)385 static void blit_from_16(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
386 {
387    #ifdef ALLEGRO_COLOR16
388 
389    int x, y, c, r, g, b;
390    uintptr_t s, d;
391 
392    switch (bitmap_color_depth(dest)) {
393 
394       #ifdef ALLEGRO_COLOR8
395       case 8:
396          if (_color_conv & COLORCONV_DITHER_PAL)
397             dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h);
398          else
399             CONVERT_BLIT(16, sizeof(int16_t), 8, 1)
400          break;
401       #endif
402 
403       case 15:
404          CONVERT_BLIT(16, sizeof(int16_t), 15, sizeof(int16_t))
405          break;
406 
407       #ifdef ALLEGRO_COLOR24
408       case 24:
409          CONVERT_BLIT(16, sizeof(int16_t), 24, 3)
410          break;
411       #endif
412 
413       #ifdef ALLEGRO_COLOR32
414       case 32:
415          CONVERT_BLIT(16, sizeof(int16_t), 32, sizeof(int32_t))
416          break;
417       #endif
418    }
419 
420    #endif
421 }
422 
423 
424 
425 /* blit_from_24:
426  *  Converts 24 bpp images onto some other destination format.
427  */
blit_from_24(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)428 static void blit_from_24(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
429 {
430    #ifdef ALLEGRO_COLOR24
431 
432    int x, y, c, r, g, b;
433    uintptr_t s, d;
434 
435    switch (bitmap_color_depth(dest)) {
436 
437       #ifdef ALLEGRO_COLOR8
438       case 8:
439          if (_color_conv & COLORCONV_DITHER_PAL)
440             dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h);
441          else
442             CONVERT_BLIT(24, 3, 8, 1);
443          break;
444       #endif
445 
446       #ifdef ALLEGRO_COLOR16
447       case 15:
448          if (_color_conv & COLORCONV_DITHER_HI)
449             CONVERT_DITHER_BLIT(24, 3, 15, sizeof(int16_t))
450          else
451             CONVERT_BLIT(24, 3, 15, sizeof(int16_t))
452          break;
453 
454       case 16:
455          if (_color_conv & COLORCONV_DITHER_HI)
456             CONVERT_DITHER_BLIT(24, 3, 16, sizeof(int16_t))
457          else
458             CONVERT_BLIT(24, 3, 16, sizeof(int16_t))
459          break;
460       #endif
461 
462       #ifdef ALLEGRO_COLOR32
463       case 32:
464          CONVERT_BLIT(24, 3, 32, sizeof(int32_t))
465          break;
466       #endif
467    }
468 
469    #endif
470 }
471 
472 
473 
474 /* blit_from_32:
475  *  Converts 32 bpp images onto some other destination format.
476  */
blit_from_32(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)477 static void blit_from_32(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
478 {
479    #ifdef ALLEGRO_COLOR32
480 
481    int x, y, c, r, g, b;
482    uintptr_t s, d;
483 
484    switch (bitmap_color_depth(dest)) {
485 
486       #ifdef ALLEGRO_COLOR8
487       case 8:
488          if (_color_conv & COLORCONV_DITHER_PAL)
489             dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h);
490          else
491             CONVERT_BLIT(32, sizeof(int32_t), 8, 1)
492          break;
493       #endif
494 
495       #ifdef ALLEGRO_COLOR16
496       case 15:
497          if (_color_conv & COLORCONV_DITHER_HI)
498             CONVERT_DITHER_BLIT(32, sizeof(int32_t), 15, sizeof(int16_t))
499          else
500             CONVERT_BLIT(32, sizeof(int32_t), 15, sizeof(int16_t))
501          break;
502 
503       case 16:
504          if (_color_conv & COLORCONV_DITHER_HI)
505             CONVERT_DITHER_BLIT(32, sizeof(int32_t), 16, sizeof(int16_t))
506          else
507             CONVERT_BLIT(32, sizeof(int32_t), 16, sizeof(int16_t))
508          break;
509       #endif
510 
511       #ifdef ALLEGRO_COLOR24
512       case 24:
513          CONVERT_BLIT(32, sizeof(int32_t), 24, 3)
514          break;
515       #endif
516    }
517 
518    #endif
519 }
520 
521 
522 
523 /* blit_to_or_from_modex:
524  *  Converts between truecolor and planar mode-X bitmaps. This function is
525  *  painfully slow, but I don't think it is something that people will need
526  *  to do very often...
527  */
blit_to_or_from_modex(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)528 static void blit_to_or_from_modex(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
529 {
530    #ifdef ALLEGRO_GFX_HAS_VGA
531 
532    int x, y, c, r, g, b;
533    int src_depth = bitmap_color_depth(src);
534    int dest_depth = bitmap_color_depth(dest);
535 
536    int prev_drawmode = _drawing_mode;
537    _drawing_mode = DRAW_MODE_SOLID;
538 
539    if ((src_depth != 8) && (_color_conv & COLORCONV_DITHER_PAL))
540       dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h);
541    else {
542       for (y=0; y<h; y++) {
543          for (x=0; x<w; x++) {
544             c = getpixel(src, s_x+x, s_y+y);
545             r = getr_depth(src_depth, c);
546             g = getg_depth(src_depth, c);
547             b = getb_depth(src_depth, c);
548             c = makecol_depth(dest_depth, r, g, b);
549             putpixel(dest, d_x+x, d_y+y, c);
550          }
551       }
552    }
553 
554    _drawing_mode = prev_drawmode;
555 
556    #endif
557 }
558 
559 
560 
561 /* blit_between_formats:
562  *  Blits an (already clipped) region between two bitmaps of different
563  *  color depths, doing the appopriate format conversions.
564  */
_blit_between_formats(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)565 void _blit_between_formats(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
566 {
567    if ((is_planar_bitmap(src)) || (is_planar_bitmap(dest))) {
568       blit_to_or_from_modex(src, dest, s_x, s_y, d_x, d_y, w, h);
569    }
570    else {
571       switch (bitmap_color_depth(src)) {
572 
573 	 case 8:
574 	    blit_from_256(src, dest, s_x, s_y, d_x, d_y, w, h);
575 	    break;
576 
577 	 case 15:
578 	    blit_from_15(src, dest, s_x, s_y, d_x, d_y, w, h);
579 	    break;
580 
581 	 case 16:
582 	    blit_from_16(src, dest, s_x, s_y, d_x, d_y, w, h);
583 	    break;
584 
585 	 case 24:
586 	    blit_from_24(src, dest, s_x, s_y, d_x, d_y, w, h);
587 	    break;
588 
589 	 case 32:
590 	    blit_from_32(src, dest, s_x, s_y, d_x, d_y, w, h);
591 	    break;
592       }
593    }
594 }
595 
596 
597 
598 /* blit_to_self:
599  *  Blits an (already clipped) region between two areas of the same bitmap,
600  *  checking which way around to do the blit.
601  */
blit_to_self(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)602 static void blit_to_self(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
603 {
604    unsigned long sx, sy, dx, dy;
605    BITMAP *tmp;
606 
607    if (dest->id & BMP_ID_NOBLIT) {
608       /* with single-banked cards we have to use a temporary bitmap */
609       tmp = create_bitmap(w, h);
610       if (tmp) {
611          src->vtable->blit_to_memory(src, tmp, s_x, s_y, 0, 0, w, h);
612          dest->vtable->blit_from_memory(tmp, dest, 0, 0, d_x, d_y, w, h);
613          destroy_bitmap(tmp);
614       }
615    }
616    else {
617       /* check which way round to do the blit */
618       sx = s_x + src->x_ofs;
619       sy = s_y + src->y_ofs;
620 
621       dx = d_x + dest->x_ofs;
622       dy = d_y + dest->y_ofs;
623 
624       if ((sx+w <= dx) || (dx+w <= sx) || (sy+h <= dy) || (dy+h <= sy))
625          dest->vtable->blit_to_self(src, dest, s_x, s_y, d_x, d_y, w, h);
626       else if ((sy > dy) || ((sy == dy) && (sx > dx)))
627          dest->vtable->blit_to_self_forward(src, dest, s_x, s_y, d_x, d_y, w, h);
628       else if ((sx != dx) || (sy != dy))
629          dest->vtable->blit_to_self_backward(src, dest, s_x, s_y, d_x, d_y, w, h);
630    }
631 }
632 
633 
634 
635 /* helper for clipping a blit rectangle */
636 #define BLIT_CLIP()                                                          \
637    /* check for ridiculous cases */                                          \
638    if ((s_x >= src->w) || (s_y >= src->h) ||                                 \
639        (d_x >= dest->cr) || (d_y >= dest->cb))                               \
640       return;                                                                \
641                                                                              \
642    /* clip src left */                                                       \
643    if (s_x < 0) {                                                            \
644       w += s_x;                                                              \
645       d_x -= s_x;                                                            \
646       s_x = 0;                                                               \
647    }                                                                         \
648                                                                              \
649    /* clip src top */                                                        \
650    if (s_y < 0) {                                                            \
651       h += s_y;                                                              \
652       d_y -= s_y;                                                            \
653       s_y = 0;                                                               \
654    }                                                                         \
655                                                                              \
656    /* clip src right */                                                      \
657    if (s_x+w > src->w)                                                       \
658       w = src->w - s_x;                                                      \
659                                                                              \
660    /* clip src bottom */                                                     \
661    if (s_y+h > src->h)                                                       \
662       h = src->h - s_y;                                                      \
663                                                                              \
664    /* clip dest left */                                                      \
665    if (d_x < dest->cl) {                                                     \
666       d_x -= dest->cl;                                                       \
667       w += d_x;                                                              \
668       s_x -= d_x;                                                            \
669       d_x = dest->cl;                                                        \
670    }                                                                         \
671                                                                              \
672    /* clip dest top */                                                       \
673    if (d_y < dest->ct) {                                                     \
674       d_y -= dest->ct;                                                       \
675       h += d_y;                                                              \
676       s_y -= d_y;                                                            \
677       d_y = dest->ct;                                                        \
678    }                                                                         \
679                                                                              \
680    /* clip dest right */                                                     \
681    if (d_x+w > dest->cr)                                                     \
682       w = dest->cr - d_x;                                                    \
683                                                                              \
684    /* clip dest bottom */                                                    \
685    if (d_y+h > dest->cb)                                                     \
686       h = dest->cb - d_y;                                                    \
687                                                                              \
688    /* bottle out if zero size */                                             \
689    if ((w <= 0) || (h <= 0))                                                 \
690       return;
691 
692 
693 
694 /* blit:
695  *  Copies an area of the source bitmap to the destination bitmap. s_x and
696  *  s_y give the top left corner of the area of the source bitmap to copy,
697  *  and d_x and d_y give the position in the destination bitmap. w and h
698  *  give the size of the area to blit. This routine respects the clipping
699  *  rectangle of the destination bitmap, and will work correctly even when
700  *  the two memory areas overlap (ie. src and dest are the same).
701  */
blit(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)702 void blit(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
703 {
704    ASSERT(src);
705    ASSERT(dest);
706    BLIT_CLIP();
707 
708    if (src->vtable->color_depth != dest->vtable->color_depth) {
709       /* need to do a color conversion */
710       dest->vtable->blit_between_formats(src, dest, s_x, s_y, d_x, d_y, w, h);
711    }
712    else if (is_same_bitmap(src, dest)) {
713       /* special handling for overlapping regions */
714       blit_to_self(src, dest, s_x, s_y, d_x, d_y, w, h);
715    }
716    else if (is_video_bitmap(dest)) {
717       /* drawing onto video bitmaps */
718       if (is_video_bitmap(src))
719          dest->vtable->blit_to_self(src, dest, s_x, s_y, d_x, d_y, w, h);
720       else if (is_system_bitmap(src))
721          dest->vtable->blit_from_system(src, dest, s_x, s_y, d_x, d_y, w, h);
722       else
723          dest->vtable->blit_from_memory(src, dest, s_x, s_y, d_x, d_y, w, h);
724    }
725    else if (is_system_bitmap(dest)) {
726       /* drawing onto system bitmaps */
727       if (is_video_bitmap(src))
728          src->vtable->blit_to_system(src, dest, s_x, s_y, d_x, d_y, w, h);
729       else if (is_system_bitmap(src))
730          dest->vtable->blit_to_self(src, dest, s_x, s_y, d_x, d_y, w, h);
731       else
732          dest->vtable->blit_from_memory(src, dest, s_x, s_y, d_x, d_y, w, h);
733    }
734    else {
735       /* drawing onto memory bitmaps */
736       if ((is_video_bitmap(src)) || (is_system_bitmap(src)))
737          src->vtable->blit_to_memory(src, dest, s_x, s_y, d_x, d_y, w, h);
738       else
739          dest->vtable->blit_to_self(src, dest, s_x, s_y, d_x, d_y, w, h);
740    }
741 }
742 
743 END_OF_FUNCTION(blit);
744 
745 
746 
747 /* masked_blit:
748  *  Version of blit() that skips zero pixels. The source must be a memory
749  *  bitmap, and the source and dest regions must not overlap.
750  */
masked_blit(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)751 void masked_blit(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
752 {
753    ASSERT(src);
754    ASSERT(dest);
755    ASSERT(src->vtable->color_depth == dest->vtable->color_depth);
756 
757    BLIT_CLIP();
758 
759    dest->vtable->masked_blit(src, dest, s_x, s_y, d_x, d_y, w, h);
760 }
761