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(¤t_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