/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Bitmap locking routines. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_pixels.h" /* Function: al_lock_bitmap_region */ ALLEGRO_LOCKED_REGION *al_lock_bitmap_region(ALLEGRO_BITMAP *bitmap, int x, int y, int width, int height, int format, int flags) { ALLEGRO_LOCKED_REGION *lr; int bitmap_format = al_get_bitmap_format(bitmap); int bitmap_flags = al_get_bitmap_flags(bitmap); int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); int xc, yc, wc, hc; ASSERT(x >= 0); ASSERT(y >= 0); ASSERT(width >= 0); ASSERT(height >= 0); ASSERT(!_al_pixel_format_is_video_only(format)); if (_al_pixel_format_is_real(format)) { ASSERT(al_get_pixel_block_width(format) == 1); ASSERT(al_get_pixel_block_height(format) == 1); } /* For sub-bitmaps */ if (bitmap->parent) { x += bitmap->xofs; y += bitmap->yofs; bitmap = bitmap->parent; } if (bitmap->locked) return NULL; if (!(bitmap_flags & ALLEGRO_MEMORY_BITMAP) && !(flags & ALLEGRO_LOCK_READONLY)) bitmap->dirty = true; ASSERT(x+width <= bitmap->w); ASSERT(y+height <= bitmap->h); xc = (x / block_width) * block_width; yc = (y / block_height) * block_height; wc = _al_get_least_multiple(x + width, block_width) - xc; hc = _al_get_least_multiple(y + height, block_height) - yc; bitmap->lock_x = xc; bitmap->lock_y = yc; bitmap->lock_w = wc; bitmap->lock_h = hc; bitmap->lock_flags = flags; if (flags == ALLEGRO_LOCK_WRITEONLY && (xc != x || yc != y || wc != width || hc != height)) { /* Unaligned write-only access requires that we fill in the padding * from the texture. * XXX: In principle, this could be done more efficiently. */ flags = ALLEGRO_LOCK_READWRITE; } if (bitmap_flags & ALLEGRO_MEMORY_BITMAP) { int f = _al_get_real_pixel_format(al_get_current_display(), format); if (f < 0) { return NULL; } ASSERT(bitmap->memory); if (format == ALLEGRO_PIXEL_FORMAT_ANY || bitmap_format == format || bitmap_format == f) { bitmap->locked_region.data = bitmap->memory + bitmap->pitch * yc + xc * al_get_pixel_size(bitmap_format); bitmap->locked_region.format = bitmap_format; bitmap->locked_region.pitch = bitmap->pitch; bitmap->locked_region.pixel_size = al_get_pixel_size(bitmap_format); } else { bitmap->locked_region.pitch = al_get_pixel_size(f) * wc; bitmap->locked_region.data = al_malloc(bitmap->locked_region.pitch*hc); bitmap->locked_region.format = f; bitmap->locked_region.pixel_size = al_get_pixel_size(f); if (!(bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY)) { _al_convert_bitmap_data( bitmap->memory, bitmap_format, bitmap->pitch, bitmap->locked_region.data, f, bitmap->locked_region.pitch, xc, yc, 0, 0, wc, hc); } } lr = &bitmap->locked_region; } else { lr = bitmap->vt->lock_region(bitmap, xc, yc, wc, hc, format, flags); if (!lr) { return NULL; } } bitmap->lock_data = lr->data; /* Fixup the data pointer for unaligned access */ lr->data = (char*)lr->data + (x - xc) * lr->pixel_size + (y - yc) * lr->pitch; bitmap->locked = true; return lr; } /* Function: al_lock_bitmap */ ALLEGRO_LOCKED_REGION *al_lock_bitmap(ALLEGRO_BITMAP *bitmap, int format, int flags) { return al_lock_bitmap_region(bitmap, 0, 0, bitmap->w, bitmap->h, format, flags); } /* Function: al_unlock_bitmap */ void al_unlock_bitmap(ALLEGRO_BITMAP *bitmap) { int bitmap_format = al_get_bitmap_format(bitmap); /* For sub-bitmaps */ if (bitmap->parent) { bitmap = bitmap->parent; } if (!(al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP)) { if (_al_pixel_format_is_compressed(bitmap->locked_region.format)) bitmap->vt->unlock_compressed_region(bitmap); else bitmap->vt->unlock_region(bitmap); } else { if (bitmap->locked_region.format != 0 && bitmap->locked_region.format != bitmap_format) { if (!(bitmap->lock_flags & ALLEGRO_LOCK_READONLY)) { _al_convert_bitmap_data( bitmap->locked_region.data, bitmap->locked_region.format, bitmap->locked_region.pitch, bitmap->memory, bitmap_format, bitmap->pitch, 0, 0, bitmap->lock_x, bitmap->lock_y, bitmap->lock_w, bitmap->lock_h); } al_free(bitmap->locked_region.data); } } bitmap->locked = false; } /* Function: al_is_bitmap_locked */ bool al_is_bitmap_locked(ALLEGRO_BITMAP *bitmap) { return bitmap->locked; } /* Function: al_lock_bitmap_blocked */ ALLEGRO_LOCKED_REGION *al_lock_bitmap_blocked(ALLEGRO_BITMAP *bitmap, int flags) { int bitmap_format = al_get_bitmap_format(bitmap); int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); return al_lock_bitmap_region_blocked(bitmap, 0, 0, _al_get_least_multiple(bitmap->w, block_width) / block_width, _al_get_least_multiple(bitmap->h, block_height) / block_height, flags); } /* Function: al_lock_bitmap_region_blocked */ ALLEGRO_LOCKED_REGION *al_lock_bitmap_region_blocked(ALLEGRO_BITMAP *bitmap, int x_block, int y_block, int width_block, int height_block, int flags) { ALLEGRO_LOCKED_REGION *lr; int bitmap_format = al_get_bitmap_format(bitmap); int bitmap_flags = al_get_bitmap_flags(bitmap); int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); ASSERT(x_block >= 0); ASSERT(y_block >= 0); ASSERT(width_block >= 0); ASSERT(height_block >= 0); if (block_width == 1 && block_height == 1 && !_al_pixel_format_is_video_only(bitmap_format)) { return al_lock_bitmap_region(bitmap, x_block, y_block, width_block, height_block, bitmap_format, flags); } /* Currently, this is the only format that gets to this point */ ASSERT(_al_pixel_format_is_compressed(bitmap_format)); ASSERT(!(bitmap_flags & ALLEGRO_MEMORY_BITMAP)); /* For sub-bitmaps */ if (bitmap->parent) { if (bitmap->xofs % block_width != 0 || bitmap->yofs % block_height != 0) { return NULL; } x_block += bitmap->xofs / block_width; y_block += bitmap->yofs / block_height; bitmap = bitmap->parent; } if (bitmap->locked) return NULL; if (!(flags & ALLEGRO_LOCK_READONLY)) bitmap->dirty = true; ASSERT(x_block + width_block <= _al_get_least_multiple(bitmap->w, block_width) / block_width); ASSERT(y_block + height_block <= _al_get_least_multiple(bitmap->h, block_height) / block_height); bitmap->lock_x = x_block * block_width; bitmap->lock_y = y_block * block_height; bitmap->lock_w = width_block * block_width; bitmap->lock_h = height_block * block_height; bitmap->lock_flags = flags; lr = bitmap->vt->lock_compressed_region(bitmap, bitmap->lock_x, bitmap->lock_y, bitmap->lock_w, bitmap->lock_h, flags); if (!lr) { return NULL; } bitmap->locked = true; return lr; } /* vim: set ts=8 sts=3 sw=3 et: */