1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      New bitmap routines.
12  *
13  *      By Elias Pschernig and Trent Gamblin.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 /* Title: Bitmap routines
19  */
20 
21 
22 #include <string.h>
23 #include "allegro5/allegro.h"
24 #include "allegro5/internal/aintern.h"
25 #include "allegro5/internal/aintern_bitmap.h"
26 #include "allegro5/internal/aintern_display.h"
27 #include "allegro5/internal/aintern_pixels.h"
28 #include "allegro5/internal/aintern_shader.h"
29 #include "allegro5/internal/aintern_system.h"
30 
31 ALLEGRO_DEBUG_CHANNEL("bitmap")
32 
33 
34 /* Creates a memory bitmap.
35  */
create_memory_bitmap(ALLEGRO_DISPLAY * current_display,int w,int h,int format,int flags)36 static ALLEGRO_BITMAP *create_memory_bitmap(ALLEGRO_DISPLAY *current_display,
37    int w, int h, int format, int flags)
38 {
39    ALLEGRO_BITMAP *bitmap;
40    int pitch;
41 
42    if (_al_pixel_format_is_video_only(format)) {
43       /* Can't have a video-only memory bitmap... */
44       return NULL;
45    }
46 
47    format = _al_get_real_pixel_format(current_display, format);
48 
49    bitmap = al_calloc(1, sizeof *bitmap);
50 
51    pitch = w * al_get_pixel_size(format);
52 
53    bitmap->vt = NULL;
54    bitmap->_format = format;
55 
56    /* If this is really a video bitmap, we add it to the list of to
57     * be converted bitmaps.
58     */
59    bitmap->_flags = flags | ALLEGRO_MEMORY_BITMAP;
60    bitmap->_flags &= ~ALLEGRO_VIDEO_BITMAP;
61    bitmap->w = w;
62    bitmap->h = h;
63    bitmap->pitch = pitch;
64    bitmap->_display = NULL;
65    bitmap->locked = false;
66    bitmap->cl = bitmap->ct = 0;
67    bitmap->cr_excl = w;
68    bitmap->cb_excl = h;
69    al_identity_transform(&bitmap->transform);
70    al_identity_transform(&bitmap->inverse_transform);
71    bitmap->inverse_transform_dirty = false;
72    al_identity_transform(&bitmap->proj_transform);
73    al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, w, h, 1.0);
74    bitmap->parent = NULL;
75    bitmap->xofs = bitmap->yofs = 0;
76    bitmap->memory = al_malloc(pitch * h);
77    bitmap->use_bitmap_blender = false;
78    bitmap->blender.blend_color = al_map_rgba(0, 0, 0, 0);
79 
80    _al_register_convert_bitmap(bitmap);
81    return bitmap;
82 }
83 
84 
85 
destroy_memory_bitmap(ALLEGRO_BITMAP * bmp)86 static void destroy_memory_bitmap(ALLEGRO_BITMAP *bmp)
87 {
88    _al_unregister_convert_bitmap(bmp);
89 
90    if (bmp->memory)
91       al_free(bmp->memory);
92    al_free(bmp);
93 }
94 
95 
96 
_al_create_bitmap_params(ALLEGRO_DISPLAY * current_display,int w,int h,int format,int flags,int depth,int samples)97 ALLEGRO_BITMAP *_al_create_bitmap_params(ALLEGRO_DISPLAY *current_display,
98    int w, int h, int format, int flags, int depth, int samples)
99 {
100    ALLEGRO_SYSTEM *system = al_get_system_driver();
101    ALLEGRO_BITMAP *bitmap;
102    ALLEGRO_BITMAP **back;
103    int64_t mul;
104    bool result;
105 
106    /* Reject bitmaps where a calculation pixel_size*w*h would overflow
107     * int.  Supporting such bitmaps would require a lot more work.
108     */
109    mul = 4 * (int64_t) w * (int64_t) h;
110    if (mul > (int64_t) INT_MAX) {
111       ALLEGRO_WARN("Rejecting %dx%d bitmap\n", w, h);
112       return NULL;
113    }
114 
115    if ((flags & ALLEGRO_MEMORY_BITMAP) ||
116          !current_display ||
117          !current_display->vt ||
118          current_display->vt->create_bitmap == NULL ||
119          _al_vector_size(&system->displays) < 1)
120    {
121       if (flags & ALLEGRO_VIDEO_BITMAP)
122          return NULL;
123 
124       return create_memory_bitmap(current_display, w, h, format, flags);
125    }
126 
127    /* Else it's a display bitmap */
128 
129    bitmap = current_display->vt->create_bitmap(current_display, w, h,
130       format, flags);
131    if (!bitmap) {
132       ALLEGRO_ERROR("failed to create display bitmap\n");
133       return NULL;
134    }
135 
136    bitmap->_display = current_display;
137    bitmap->w = w;
138    bitmap->h = h;
139    bitmap->locked = false;
140    bitmap->cl = 0;
141    bitmap->ct = 0;
142    bitmap->cr_excl = w;
143    bitmap->cb_excl = h;
144    al_identity_transform(&bitmap->transform);
145    al_identity_transform(&bitmap->inverse_transform);
146    bitmap->inverse_transform_dirty = false;
147    al_identity_transform(&bitmap->proj_transform);
148    al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, w, h, 1.0);
149    bitmap->parent = NULL;
150    bitmap->xofs = 0;
151    bitmap->yofs = 0;
152    bitmap->_flags |= ALLEGRO_VIDEO_BITMAP;
153    bitmap->dirty = !(bitmap->_flags & ALLEGRO_NO_PRESERVE_TEXTURE);
154    bitmap->_depth = depth;
155    bitmap->_samples = samples;
156    bitmap->use_bitmap_blender = false;
157    bitmap->blender.blend_color = al_map_rgba(0, 0, 0, 0);
158 
159    /* The display driver should have set the bitmap->memory field if
160     * appropriate; video bitmaps may leave it NULL.
161     */
162 
163    ASSERT(bitmap->pitch >= w * al_get_pixel_size(bitmap->_format));
164    result = bitmap->vt->upload_bitmap(bitmap);
165 
166    if (!result) {
167       al_destroy_bitmap(bitmap);
168       if (flags & ALLEGRO_VIDEO_BITMAP)
169          return NULL;
170       /* With ALLEGRO_CONVERT_BITMAP, just use a memory bitmap instead if
171       * video failed.
172       */
173       return create_memory_bitmap(current_display, w, h, format, flags);
174    }
175 
176    /* We keep a list of bitmaps depending on the current display so that we can
177     * convert them to memory bimaps when the display is destroyed. */
178    back = _al_vector_alloc_back(&current_display->bitmaps);
179    *back = bitmap;
180 
181    return bitmap;
182 }
183 
184 
185 /* Function: al_create_bitmap
186  */
al_create_bitmap(int w,int h)187 ALLEGRO_BITMAP *al_create_bitmap(int w, int h)
188 {
189    ALLEGRO_BITMAP *bitmap;
190 
191    bitmap = _al_create_bitmap_params(al_get_current_display(), w, h,
192       al_get_new_bitmap_format(), al_get_new_bitmap_flags(),
193       al_get_new_bitmap_depth(), al_get_new_bitmap_samples());
194    if (bitmap) {
195       bitmap->dtor_item = _al_register_destructor(_al_dtor_list, "bitmap", bitmap,
196          (void (*)(void *))al_destroy_bitmap);
197    }
198 
199    return bitmap;
200 }
201 
202 
203 /* Function: al_destroy_bitmap
204  */
al_destroy_bitmap(ALLEGRO_BITMAP * bitmap)205 void al_destroy_bitmap(ALLEGRO_BITMAP *bitmap)
206 {
207    if (!bitmap) {
208       return;
209    }
210 
211    /* As a convenience, implicitly untarget the bitmap on the calling thread
212     * before it is destroyed, but maintain the current display.
213     */
214    if (bitmap == al_get_target_bitmap()) {
215       ALLEGRO_DISPLAY *display = al_get_current_display();
216       if (display)
217          al_set_target_bitmap(al_get_backbuffer(display));
218       else
219          al_set_target_bitmap(NULL);
220    }
221 
222    _al_set_bitmap_shader_field(bitmap, NULL);
223 
224    _al_unregister_destructor(_al_dtor_list, bitmap->dtor_item);
225 
226    if (!al_is_sub_bitmap(bitmap)) {
227       ALLEGRO_DISPLAY* disp = _al_get_bitmap_display(bitmap);
228       if (al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) {
229          destroy_memory_bitmap(bitmap);
230          return;
231       }
232 
233       /* Else it's a display bitmap */
234 
235       if (bitmap->locked)
236          al_unlock_bitmap(bitmap);
237 
238       if (bitmap->vt)
239          bitmap->vt->destroy_bitmap(bitmap);
240 
241       if (disp)
242          _al_vector_find_and_delete(&disp->bitmaps, &bitmap);
243 
244       if (bitmap->memory)
245          al_free(bitmap->memory);
246    }
247 
248    al_free(bitmap);
249 }
250 
251 
252 /* Function: al_convert_mask_to_alpha
253  */
al_convert_mask_to_alpha(ALLEGRO_BITMAP * bitmap,ALLEGRO_COLOR mask_color)254 void al_convert_mask_to_alpha(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR mask_color)
255 {
256    ALLEGRO_LOCKED_REGION *lr;
257    int x, y;
258    ALLEGRO_COLOR pixel;
259    ALLEGRO_COLOR alpha_pixel;
260    ALLEGRO_STATE state;
261 
262    if (!(lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ANY, 0))) {
263       ALLEGRO_ERROR("Couldn't lock bitmap.");
264       return;
265    }
266 
267    al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP);
268    al_set_target_bitmap(bitmap);
269 
270    alpha_pixel = al_map_rgba(0, 0, 0, 0);
271 
272    for (y = 0; y < bitmap->h; y++) {
273       for (x = 0; x < bitmap->w; x++) {
274          pixel = al_get_pixel(bitmap, x, y);
275          if (memcmp(&pixel, &mask_color, sizeof(ALLEGRO_COLOR)) == 0) {
276             al_put_pixel(x, y, alpha_pixel);
277          }
278       }
279    }
280 
281    al_unlock_bitmap(bitmap);
282 
283    al_restore_state(&state);
284 }
285 
286 
287 
288 /* Function: al_get_bitmap_width
289  */
al_get_bitmap_width(ALLEGRO_BITMAP * bitmap)290 int al_get_bitmap_width(ALLEGRO_BITMAP *bitmap)
291 {
292    return bitmap->w;
293 }
294 
295 
296 
297 /* Function: al_get_bitmap_height
298  */
al_get_bitmap_height(ALLEGRO_BITMAP * bitmap)299 int al_get_bitmap_height(ALLEGRO_BITMAP *bitmap)
300 {
301    return bitmap->h;
302 }
303 
304 
305 
306 /* Function: al_get_bitmap_format
307  */
al_get_bitmap_format(ALLEGRO_BITMAP * bitmap)308 int al_get_bitmap_format(ALLEGRO_BITMAP *bitmap)
309 {
310    if (bitmap->parent)
311       return bitmap->parent->_format;
312    else
313       return bitmap->_format;
314 }
315 
316 
_al_get_bitmap_memory_format(ALLEGRO_BITMAP * bitmap)317 int _al_get_bitmap_memory_format(ALLEGRO_BITMAP *bitmap)
318 {
319    if (bitmap->parent)
320       return bitmap->parent->_memory_format;
321    else
322       return bitmap->_memory_format;
323 }
324 
325 
326 
327 /* Function: al_get_bitmap_flags
328  */
al_get_bitmap_flags(ALLEGRO_BITMAP * bitmap)329 int al_get_bitmap_flags(ALLEGRO_BITMAP *bitmap)
330 {
331    if (bitmap->parent)
332       return bitmap->parent->_flags;
333    else
334       return bitmap->_flags;
335 }
336 
337 
_al_get_bitmap_display(ALLEGRO_BITMAP * bitmap)338 ALLEGRO_DISPLAY *_al_get_bitmap_display(ALLEGRO_BITMAP *bitmap)
339 {
340    if (bitmap->parent)
341       return bitmap->parent->_display;
342    else
343       return bitmap->_display;
344 }
345 
346 
347 /* Function: al_get_bitmap_depth
348  */
al_get_bitmap_depth(ALLEGRO_BITMAP * bitmap)349 int al_get_bitmap_depth(ALLEGRO_BITMAP *bitmap)
350 {
351    if (bitmap->parent)
352       return bitmap->parent->_depth;
353    else
354       return bitmap->_depth;
355 }
356 
357 
358 /* Function: al_get_bitmap_samples
359  */
al_get_bitmap_samples(ALLEGRO_BITMAP * bitmap)360 int al_get_bitmap_samples(ALLEGRO_BITMAP *bitmap)
361 {
362    if (bitmap->parent)
363       return bitmap->parent->_samples;
364    else
365       return bitmap->_samples;
366 }
367 
368 /* Function: al_get_bitmap_blend_color
369  */
al_get_bitmap_blend_color(void)370 ALLEGRO_COLOR al_get_bitmap_blend_color(void)
371 {
372    ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
373    ALLEGRO_BLENDER *b;
374 
375    ASSERT(bitmap);
376 
377    if (!bitmap->use_bitmap_blender) {
378       /* If no bitmap blender set, use TLS */
379       return al_get_blend_color();
380    }
381 
382    b = &bitmap->blender;
383    return b->blend_color;
384 }
385 
386 /* Function: al_get_bitmap_blender
387  */
al_get_bitmap_blender(int * op,int * src,int * dst)388 void al_get_bitmap_blender(int *op, int *src, int *dst)
389 {
390    al_get_separate_bitmap_blender(op, src, dst, NULL, NULL, NULL);
391 }
392 
393 /* Function: al_get_separate_bitmap_blender
394  */
al_get_separate_bitmap_blender(int * op,int * src,int * dst,int * alpha_op,int * alpha_src,int * alpha_dst)395 void al_get_separate_bitmap_blender(int *op, int *src, int *dst, int *alpha_op, int *alpha_src, int *alpha_dst)
396 {
397    ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
398    ALLEGRO_BLENDER *b;
399 
400    ASSERT(bitmap);
401 
402    if (!bitmap->use_bitmap_blender) {
403       /* If no bitmap blender set, use TLS */
404       al_get_separate_blender(op, src, dst, alpha_op, alpha_src, alpha_dst);
405       return;
406    }
407 
408    b = &bitmap->blender;
409 
410    if (op)
411       *op = b->blend_op;
412 
413    if (src)
414       *src = b->blend_source;
415 
416    if (dst)
417       *dst = b->blend_dest;
418 
419    if (alpha_op)
420       *alpha_op = b->blend_alpha_op;
421 
422    if (alpha_src)
423       *alpha_src = b->blend_alpha_source;
424 
425    if (alpha_dst)
426       *alpha_dst = b->blend_alpha_dest;
427 }
428 
429 /* Function: al_set_bitmap_blend_color
430  */
al_set_bitmap_blend_color(ALLEGRO_COLOR col)431 void al_set_bitmap_blend_color(ALLEGRO_COLOR col)
432 {
433    ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
434    ALLEGRO_BLENDER *b;
435 
436    ASSERT(bitmap);
437 
438    b = &bitmap->blender;
439    b->blend_color = col;
440 }
441 
442 /* Function: al_set_bitmap_blender
443  */
al_set_bitmap_blender(int op,int src,int dest)444 void al_set_bitmap_blender(int op, int src, int dest)
445 {
446    ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
447 
448    ASSERT(bitmap);
449 
450    al_set_separate_bitmap_blender(op, src, dest, op, src, dest);
451 }
452 
453 /* Function: al_set_separate_bitmap_blender
454  */
al_set_separate_bitmap_blender(int op,int src,int dst,int alpha_op,int alpha_src,int alpha_dst)455 void al_set_separate_bitmap_blender(int op, int src, int dst, int alpha_op, int alpha_src, int alpha_dst)
456 {
457    ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
458    ALLEGRO_BLENDER *b;
459 
460    ASSERT(bitmap);
461 
462    bitmap->use_bitmap_blender = true;
463    b = &bitmap->blender;
464    b->blend_op = op;
465    b->blend_source = src;
466    b->blend_dest = dst;
467    b->blend_alpha_op = alpha_op;
468    b->blend_alpha_source = alpha_src;
469    b->blend_alpha_dest = alpha_dst;
470 }
471 
472 /* Function: al_reset_bitmap_blender
473  */
al_reset_bitmap_blender(void)474 void al_reset_bitmap_blender(void)
475 {
476    ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
477 
478    ASSERT(bitmap);
479 
480    bitmap->use_bitmap_blender = false;
481    bitmap->blender.blend_color = al_map_rgba(0, 0, 0, 0);
482 }
483 
484 /* Function: al_set_clipping_rectangle
485  */
al_set_clipping_rectangle(int x,int y,int width,int height)486 void al_set_clipping_rectangle(int x, int y, int width, int height)
487 {
488    ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
489 
490    ASSERT(bitmap);
491 
492    if (x < 0) {
493       width += x;
494       x = 0;
495    }
496    if (y < 0) {
497       height += y;
498       y = 0;
499    }
500    if (x + width > bitmap->w) {
501       width = bitmap->w - x;
502    }
503    if (y + height > bitmap->h) {
504       height = bitmap->h - y;
505    }
506    if (width < 0) {
507       width = 0;
508    }
509    if (height < 0) {
510       height = 0;
511    }
512 
513    bitmap->cl = x;
514    bitmap->ct = y;
515    bitmap->cr_excl = x + width;
516    bitmap->cb_excl = y + height;
517 
518    if (bitmap->vt && bitmap->vt->update_clipping_rectangle) {
519       bitmap->vt->update_clipping_rectangle(bitmap);
520    }
521 }
522 
523 
524 
525 /* Function: al_reset_clipping_rectangle
526  */
al_reset_clipping_rectangle(void)527 void al_reset_clipping_rectangle(void)
528 {
529    ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
530 
531    if (bitmap) {
532       int w = al_get_bitmap_width(bitmap);
533       int h = al_get_bitmap_height(bitmap);
534       al_set_clipping_rectangle(0, 0, w, h);
535    }
536 }
537 
538 
539 
540 /* Function: al_get_clipping_rectangle
541  */
al_get_clipping_rectangle(int * x,int * y,int * w,int * h)542 void al_get_clipping_rectangle(int *x, int *y, int *w, int *h)
543 {
544    ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
545 
546    ASSERT(bitmap);
547 
548    if (x) *x = bitmap->cl;
549    if (y) *y = bitmap->ct;
550    if (w) *w = bitmap->cr_excl - bitmap->cl;
551    if (h) *h = bitmap->cb_excl - bitmap->ct;
552 }
553 
554 
555 
556 /* Function: al_create_sub_bitmap
557  */
al_create_sub_bitmap(ALLEGRO_BITMAP * parent,int x,int y,int w,int h)558 ALLEGRO_BITMAP *al_create_sub_bitmap(ALLEGRO_BITMAP *parent,
559    int x, int y, int w, int h)
560 {
561    ALLEGRO_BITMAP *bitmap;
562 
563    if (parent->parent) {
564       x += parent->xofs;
565       y += parent->yofs;
566       parent = parent->parent;
567    }
568 
569    bitmap = al_calloc(1, sizeof *bitmap);
570    bitmap->vt = parent->vt;
571 
572    /* Sub-bitmap inherits these from the parent.
573     * Leave these unchanged so they can be detected if improperly accessed
574     * directly. */
575    bitmap->_format = 0;
576    bitmap->_flags = 0;
577    bitmap->_display = (ALLEGRO_DISPLAY*)0x1;
578 
579    bitmap->w = w;
580    bitmap->h = h;
581    bitmap->locked = false;
582    bitmap->cl = bitmap->ct = 0;
583    bitmap->cr_excl = w;
584    bitmap->cb_excl = h;
585    al_identity_transform(&bitmap->transform);
586    al_identity_transform(&bitmap->inverse_transform);
587    bitmap->inverse_transform_dirty = false;
588    al_identity_transform(&bitmap->proj_transform);
589    al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, w, h, 1.0);
590    bitmap->shader = NULL;
591    bitmap->parent = parent;
592    bitmap->xofs = x;
593    bitmap->yofs = y;
594    bitmap->memory = NULL;
595 
596    bitmap->dtor_item = _al_register_destructor(_al_dtor_list, "sub_bitmap", bitmap,
597       (void (*)(void *))al_destroy_bitmap);
598 
599    return bitmap;
600 }
601 
602 
603 /* Function: al_reparent_bitmap
604  */
al_reparent_bitmap(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP * parent,int x,int y,int w,int h)605 void al_reparent_bitmap(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP *parent,
606    int x, int y, int w, int h)
607 {
608    ASSERT(bitmap->parent);
609    /* Re-parenting a non-sub-bitmap makes no sense, so in release mode
610     * just ignore it. */
611    if (!bitmap->parent)
612       return;
613 
614    if (parent->parent) {
615       x += parent->xofs;
616       y += parent->yofs;
617       parent = parent->parent;
618    }
619 
620    bitmap->parent = parent;
621    bitmap->xofs = x;
622    bitmap->yofs = y;
623    bitmap->w = w;
624    bitmap->h = h;
625 }
626 
627 
628 /* Function: al_is_sub_bitmap
629  */
al_is_sub_bitmap(ALLEGRO_BITMAP * bitmap)630 bool al_is_sub_bitmap(ALLEGRO_BITMAP *bitmap)
631 {
632    return (bitmap->parent != NULL);
633 }
634 
635 
636 /* Function: al_get_parent_bitmap
637  */
al_get_parent_bitmap(ALLEGRO_BITMAP * bitmap)638 ALLEGRO_BITMAP *al_get_parent_bitmap(ALLEGRO_BITMAP *bitmap)
639 {
640    ASSERT(bitmap);
641    return bitmap->parent;
642 }
643 
644 
645 /* Function: al_get_bitmap_x
646  */
al_get_bitmap_x(ALLEGRO_BITMAP * bitmap)647 int al_get_bitmap_x(ALLEGRO_BITMAP *bitmap)
648 {
649    ASSERT(bitmap);
650    return bitmap->xofs;
651 }
652 
653 
654 /* Function: al_get_bitmap_y
655  */
al_get_bitmap_y(ALLEGRO_BITMAP * bitmap)656 int al_get_bitmap_y(ALLEGRO_BITMAP *bitmap)
657 {
658    ASSERT(bitmap);
659    return bitmap->yofs;
660 }
661 
662 
transfer_bitmap_data(ALLEGRO_BITMAP * src,ALLEGRO_BITMAP * dst)663 static bool transfer_bitmap_data(ALLEGRO_BITMAP *src, ALLEGRO_BITMAP *dst)
664 {
665    ALLEGRO_LOCKED_REGION *dst_region;
666    ALLEGRO_LOCKED_REGION *src_region;
667    int src_format = al_get_bitmap_format(src);
668    int dst_format = al_get_bitmap_format(dst);
669    bool src_compressed = _al_pixel_format_is_compressed(src_format);
670    bool dst_compressed = _al_pixel_format_is_compressed(dst_format);
671    int copy_w = src->w;
672    int copy_h = src->h;
673 
674    if (src_compressed && dst_compressed && src_format == dst_format) {
675       int block_width = al_get_pixel_block_width(src_format);
676       int block_height = al_get_pixel_block_height(src_format);
677       if (!(src_region = al_lock_bitmap_blocked(src, ALLEGRO_LOCK_READONLY)))
678          return false;
679 
680       if (!(dst_region = al_lock_bitmap_blocked(dst, ALLEGRO_LOCK_WRITEONLY))) {
681          al_unlock_bitmap(src);
682          return false;
683       }
684       copy_w = _al_get_least_multiple(copy_w, block_width);
685       copy_h = _al_get_least_multiple(copy_h, block_height);
686       ALLEGRO_DEBUG("Taking fast clone path.\n");
687    }
688    else {
689       int lock_format = ALLEGRO_PIXEL_FORMAT_ANY;
690       /* Go through a non-compressed intermediate */
691       if (src_compressed && !dst_compressed) {
692          lock_format = dst_format;
693       }
694       else if (!src_compressed && dst_compressed) {
695          lock_format = src_format;
696       }
697 
698       if (!(src_region = al_lock_bitmap(src, lock_format, ALLEGRO_LOCK_READONLY)))
699          return false;
700 
701       if (!(dst_region = al_lock_bitmap(dst, lock_format, ALLEGRO_LOCK_WRITEONLY))) {
702          al_unlock_bitmap(src);
703          return false;
704       }
705    }
706 
707    _al_convert_bitmap_data(
708       src_region->data, src_region->format, src_region->pitch,
709       dst_region->data, dst_region->format, dst_region->pitch,
710       0, 0, 0, 0, copy_w, copy_h);
711 
712    al_unlock_bitmap(src);
713    al_unlock_bitmap(dst);
714 
715    return true;
716 }
717 
718 
_al_copy_bitmap_data(const void * src,int src_pitch,void * dst,int dst_pitch,int sx,int sy,int dx,int dy,int width,int height,int format)719 void _al_copy_bitmap_data(
720    const void *src, int src_pitch, void *dst, int dst_pitch,
721    int sx, int sy, int dx, int dy, int width, int height,
722    int format)
723 {
724    int block_width = al_get_pixel_block_width(format);
725    int block_height = al_get_pixel_block_height(format);
726    int block_size = al_get_pixel_block_size(format);
727    const char *src_ptr = src;
728    char *dst_ptr = dst;
729    int y;
730 
731    ASSERT(src);
732    ASSERT(dst);
733    ASSERT(_al_pixel_format_is_real(format));
734    ASSERT(width % block_width == 0);
735    ASSERT(height % block_height == 0);
736    ASSERT(sx % block_width == 0);
737    ASSERT(sy % block_height == 0);
738    ASSERT(dx % block_width == 0);
739    ASSERT(dy % block_height == 0);
740 
741    sx /= block_width;
742    sy /= block_height;
743    dx /= block_width;
744    dy /= block_height;
745    width /= block_width;
746    height /= block_height;
747 
748    if ((src_ptr == dst_ptr) && (src_pitch == dst_pitch)) {
749       return;
750    }
751 
752    src_ptr += sy * src_pitch + sx * block_size;
753    dst_ptr += dy * dst_pitch + dx * block_size;
754 
755    for (y = 0; y < height; y++) {
756       memcpy(dst_ptr, src_ptr, width * block_size);
757       src_ptr += src_pitch;
758       dst_ptr += dst_pitch;
759    }
760 }
761 
_al_convert_bitmap_data(const void * src,int src_format,int src_pitch,void * dst,int dst_format,int dst_pitch,int sx,int sy,int dx,int dy,int width,int height)762 void _al_convert_bitmap_data(
763    const void *src, int src_format, int src_pitch,
764    void *dst, int dst_format, int dst_pitch,
765    int sx, int sy, int dx, int dy, int width, int height)
766 {
767    ASSERT(src);
768    ASSERT(dst);
769    ASSERT(_al_pixel_format_is_real(dst_format));
770 
771    /* Use memcpy if no conversion is needed. */
772    if (src_format == dst_format) {
773       _al_copy_bitmap_data(src, src_pitch, dst, dst_pitch, sx, sy,
774          dx, dy, width, height, src_format);
775       return;
776    }
777 
778    /* Video-only formats don't have conversion functions, so they should have
779     * been taken care of before reaching this location. */
780    ASSERT(!_al_pixel_format_is_video_only(src_format));
781    ASSERT(!_al_pixel_format_is_video_only(dst_format));
782 
783    (_al_convert_funcs[src_format][dst_format])(src, src_pitch,
784       dst, dst_pitch, sx, sy, dx, dy, width, height);
785 }
786 
787 
788 /* Function: al_clone_bitmap
789  */
al_clone_bitmap(ALLEGRO_BITMAP * bitmap)790 ALLEGRO_BITMAP *al_clone_bitmap(ALLEGRO_BITMAP *bitmap)
791 {
792    ALLEGRO_BITMAP *clone;
793    ASSERT(bitmap);
794 
795    clone = al_create_bitmap(bitmap->w, bitmap->h);
796    if (!clone)
797       return NULL;
798    if (!transfer_bitmap_data(bitmap, clone)) {
799       al_destroy_bitmap(clone);
800       return NULL;
801    }
802    return clone;
803 }
804 
805 /* Function: al_backup_dirty_bitmap
806  */
al_backup_dirty_bitmap(ALLEGRO_BITMAP * bitmap)807 void al_backup_dirty_bitmap(ALLEGRO_BITMAP *bitmap)
808 {
809    if (bitmap->vt && bitmap->vt->backup_dirty_bitmap)
810       bitmap->vt->backup_dirty_bitmap(bitmap);
811 }
812 
813 /* vim: set ts=8 sts=3 sw=3 et: */
814