summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/util/bitmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/util/bitmap.c')
-rw-r--r--trunk/src/lib/util/bitmap.c506
1 files changed, 506 insertions, 0 deletions
diff --git a/trunk/src/lib/util/bitmap.c b/trunk/src/lib/util/bitmap.c
new file mode 100644
index 00000000000..860bc5c07ee
--- /dev/null
+++ b/trunk/src/lib/util/bitmap.c
@@ -0,0 +1,506 @@
+/***************************************************************************
+
+ bitmap.c
+
+ Core bitmap routines.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "bitmap.h"
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+#include <new>
+#endif
+
+
+/***************************************************************************
+ BITMAP ALLOCATION/CONFIGURATION
+***************************************************************************/
+
+#ifdef __cplusplus
+
+/*-------------------------------------------------
+ bitmap_t - basic constructor
+-------------------------------------------------*/
+
+bitmap_t::bitmap_t()
+{
+ /* initialize base fields by hand */
+ alloc = NULL;
+ base = NULL;
+ rowpixels = 0;
+ width = 0;
+ height = 0;
+ format = BITMAP_FORMAT_INVALID;
+ bpp = 0;
+ palette = NULL;
+ cliprect.min_x = cliprect.min_y = 0;
+ cliprect.max_x = cliprect.max_y = 0;
+}
+
+
+bitmap_t::bitmap_t(int _width, int _height, bitmap_format _format, int _xslop, int _yslop)
+{
+ /* initialize base fields by hand */
+ alloc = NULL;
+ base = NULL;
+ rowpixels = (_width + 2 * _xslop + 7) & ~7;
+ width = _width;
+ height = _height;
+ format = _format;
+ bpp = bitmap_format_to_bpp(_format);
+ palette = NULL;
+ cliprect.min_x = cliprect.min_y = 0;
+ cliprect.max_x = width - 1;
+ cliprect.max_y = height - 1;
+
+ /* fail if invalid format */
+ if (bpp == 0)
+ throw std::bad_alloc();
+
+ /* allocate memory for the bitmap itself */
+ size_t allocbytes = rowpixels * (height + 2 * _yslop) * bpp / 8;
+ alloc = malloc(allocbytes);
+ if (alloc == NULL)
+ throw std::bad_alloc();
+
+ /* clear to 0 by default */
+ memset(alloc, 0, allocbytes);
+
+ /* compute the base */
+ base = (UINT8 *)alloc + (rowpixels * _yslop + _xslop) * (bpp / 8);
+}
+
+
+bitmap_t::bitmap_t(void *_base, int _width, int _height, int _rowpixels, bitmap_format _format)
+{
+ /* initialize base fields by hand */
+ alloc = NULL;
+ base = _base;
+ rowpixels = _rowpixels;
+ width = _width;
+ height = _height;
+ format = _format;
+ bpp = bitmap_format_to_bpp(_format);
+ palette = NULL;
+ cliprect.min_x = cliprect.min_y = 0;
+ cliprect.max_x = width - 1;
+ cliprect.max_y = height - 1;
+
+ /* fail if invalid format */
+ if (bpp == 0)
+ throw std::bad_alloc();
+}
+
+
+/*-------------------------------------------------
+ ~bitmap_t - basic destructor
+-------------------------------------------------*/
+
+bitmap_t::~bitmap_t()
+{
+ /* dereference the palette */
+ if (palette != NULL)
+ palette_deref(palette);
+
+ /* free any allocated memory */
+ if (alloc != NULL)
+ free(alloc);
+}
+
+
+/*-------------------------------------------------
+ bitmap_alloc -- allocate memory for a new
+ bitmap of the given format
+-------------------------------------------------*/
+
+bitmap_t *bitmap_alloc(int width, int height, bitmap_format format)
+{
+ return new bitmap_t(width, height, format);
+}
+
+
+/*-------------------------------------------------
+ bitmap_alloc_slop -- allocate a new bitmap with
+ additional slop on the borders
+-------------------------------------------------*/
+
+bitmap_t *bitmap_alloc_slop(int width, int height, int xslop, int yslop, bitmap_format format)
+{
+ return new bitmap_t(width, height, format, xslop, yslop);
+}
+
+
+/*-------------------------------------------------
+ bitmap_wrap -- wrap an existing memory buffer
+ as a bitmap
+-------------------------------------------------*/
+
+bitmap_t *bitmap_wrap(void *base, int width, int height, int rowpixels, bitmap_format format)
+{
+ return new bitmap_t(base, width, height, rowpixels, format);
+}
+
+
+/*-------------------------------------------------
+ bitmap_free -- release memory allocated for
+ a bitmap
+-------------------------------------------------*/
+
+void bitmap_free(bitmap_t *bitmap)
+{
+ delete bitmap;
+}
+
+#else
+
+/*-------------------------------------------------
+ bitmap_alloc -- allocate memory for a new
+ bitmap of the given format
+-------------------------------------------------*/
+
+bitmap_t *bitmap_alloc(int width, int height, bitmap_format format)
+{
+ return bitmap_alloc_slop(width, height, 0, 0, format);
+}
+
+
+/*-------------------------------------------------
+ bitmap_alloc_slop -- allocate a new bitmap with
+ additional slop on the borders
+-------------------------------------------------*/
+
+bitmap_t *bitmap_alloc_slop(int width, int height, int xslop, int yslop, bitmap_format format)
+{
+ int bpp = bitmap_format_to_bpp(format);
+ size_t allocbytes;
+ bitmap_t *bitmap;
+ int rowpixels;
+
+ /* fail if invalid format */
+ if (bpp == 0)
+ return NULL;
+
+ /* allocate the bitmap itself */
+ bitmap = (bitmap_t *)malloc(sizeof(*bitmap));
+ if (bitmap == NULL)
+ return NULL;
+ memset(bitmap, 0, sizeof(*bitmap));
+
+ /* round the width to a multiple of 8 and add some padding */
+ rowpixels = (width + 2 * xslop + 7) & ~7;
+
+ /* allocate memory for the bitmap itself */
+ allocbytes = rowpixels * (height + 2 * yslop) * bpp / 8;
+ bitmap->alloc = malloc(allocbytes);
+ if (bitmap->alloc == NULL)
+ {
+ free(bitmap);
+ return NULL;
+ }
+
+ /* clear to 0 by default */
+ memset(bitmap->alloc, 0, allocbytes);
+
+ /* fill in the data */
+ bitmap->format = format;
+ bitmap->width = width;
+ bitmap->height = height;
+ bitmap->bpp = bpp;
+ bitmap->rowpixels = rowpixels;
+ bitmap->base = (UINT8 *)bitmap->alloc + (rowpixels * yslop + xslop) * (bpp / 8);
+ bitmap->cliprect.min_x = 0;
+ bitmap->cliprect.max_x = width - 1;
+ bitmap->cliprect.min_y = 0;
+ bitmap->cliprect.max_y = height - 1;
+
+ return bitmap;
+}
+
+
+/*-------------------------------------------------
+ bitmap_wrap -- wrap an existing memory buffer
+ as a bitmap
+-------------------------------------------------*/
+
+bitmap_t *bitmap_wrap(void *base, int width, int height, int rowpixels, bitmap_format format)
+{
+ int bpp = bitmap_format_to_bpp(format);
+ bitmap_t *bitmap;
+
+ /* fail if invalid format */
+ if (bpp == 0)
+ return NULL;
+
+ /* allocate memory */
+ bitmap = (bitmap_t *)malloc(sizeof(*bitmap));
+ if (bitmap == NULL)
+ return NULL;
+ memset(bitmap, 0, sizeof(*bitmap));
+
+ /* fill in the data */
+ bitmap->format = format;
+ bitmap->width = width;
+ bitmap->height = height;
+ bitmap->bpp = bpp;
+ bitmap->rowpixels = rowpixels;
+ bitmap->base = base;
+ bitmap->cliprect.min_x = 0;
+ bitmap->cliprect.max_x = width - 1;
+ bitmap->cliprect.min_y = 0;
+ bitmap->cliprect.max_y = height - 1;
+
+ return bitmap;
+}
+
+
+/*-------------------------------------------------
+ bitmap_free -- release memory allocated for
+ a bitmap
+-------------------------------------------------*/
+
+void bitmap_free(bitmap_t *bitmap)
+{
+ /* dereference the palette */
+ if (bitmap->palette != NULL)
+ palette_deref(bitmap->palette);
+
+ /* free any allocated memory */
+ if (bitmap->alloc != NULL)
+ free(bitmap->alloc);
+
+ /* free the bitmap */
+ free(bitmap);
+}
+
+#endif
+
+
+/*-------------------------------------------------
+ bitmap_clone_existing -- clone an existing
+ bitmap by copying its fields; the target
+ bitmap does not own the memory
+-------------------------------------------------*/
+
+void bitmap_clone_existing(bitmap_t *bitmap, const bitmap_t *srcbitmap)
+{
+ if (bitmap->alloc != NULL)
+ free(bitmap->alloc);
+ bitmap->alloc = NULL;
+
+ bitmap->base = srcbitmap->base;
+ bitmap->rowpixels = srcbitmap->rowpixels;
+ bitmap->width = srcbitmap->width;
+ bitmap->height = srcbitmap->height;
+ bitmap->format = srcbitmap->format;
+ bitmap->bpp = srcbitmap->bpp;
+ bitmap->palette = srcbitmap->palette;
+ bitmap->cliprect = srcbitmap->cliprect;
+}
+
+
+/*-------------------------------------------------
+ bitmap_set_palette -- associate a palette with
+ a bitmap
+-------------------------------------------------*/
+
+void bitmap_set_palette(bitmap_t *bitmap, palette_t *palette)
+{
+ /* first dereference any existing palette */
+ if (bitmap->palette != NULL)
+ {
+ palette_deref(bitmap->palette);
+ bitmap->palette = NULL;
+ }
+
+ /* then reference any new palette */
+ if (palette != NULL)
+ {
+ palette_ref(palette);
+ bitmap->palette = palette;
+ }
+}
+
+
+
+/***************************************************************************
+ BITMAP DRAWING
+***************************************************************************/
+
+/*-------------------------------------------------
+ bitmap_fill -- fill a bitmap with a solid
+ color
+-------------------------------------------------*/
+
+void bitmap_fill(bitmap_t *dest, const rectangle *cliprect, UINT32 color)
+{
+ rectangle fill = dest->cliprect;
+ int x, y;
+
+ /* if we have a cliprect, intersect with that */
+ if (cliprect != NULL)
+ sect_rect(&fill, cliprect);
+
+ /* early out if nothing to do */
+ if (fill.min_x > fill.max_x || fill.min_y > fill.max_y)
+ return;
+
+ /* based on the bpp go from there */
+ switch (dest->bpp)
+ {
+ case 8:
+ /* 8bpp always uses memset */
+ for (y = fill.min_y; y <= fill.max_y; y++)
+ memset(BITMAP_ADDR8(dest, y, fill.min_x), (UINT8)color, fill.max_x + 1 - fill.min_x);
+ break;
+
+ case 16:
+ /* 16bpp can use memset if the bytes are equal */
+ if ((UINT8)(color >> 8) == (UINT8)color)
+ {
+ for (y = fill.min_y; y <= fill.max_y; y++)
+ memset(BITMAP_ADDR16(dest, y, fill.min_x), (UINT8)color, (fill.max_x + 1 - fill.min_x) * 2);
+ }
+ else
+ {
+ UINT16 *destrow, *destrow0;
+
+ /* Fill the first line the hard way */
+ destrow = BITMAP_ADDR16(dest, fill.min_y, 0);
+ for (x = fill.min_x; x <= fill.max_x; x++)
+ destrow[x] = (UINT16)color;
+
+ /* For the other lines, just copy the first one */
+ destrow0 = BITMAP_ADDR16(dest, fill.min_y, fill.min_x);
+ for (y = fill.min_y + 1; y <= fill.max_y; y++)
+ {
+ destrow = BITMAP_ADDR16(dest, y, fill.min_x);
+ memcpy(destrow, destrow0, (fill.max_x + 1 - fill.min_x) * 2);
+ }
+ }
+ break;
+
+ case 32:
+ /* 32bpp can use memset if the bytes are equal */
+ if ((UINT8)(color >> 8) == (UINT8)color && (UINT16)(color >> 16) == (UINT16)color)
+ {
+ for (y = fill.min_y; y <= fill.max_y; y++)
+ memset(BITMAP_ADDR32(dest, y, fill.min_x), (UINT8)color, (fill.max_x + 1 - fill.min_x) * 4);
+ }
+ else
+ {
+ UINT32 *destrow, *destrow0;
+
+ /* Fill the first line the hard way */
+ destrow = BITMAP_ADDR32(dest, fill.min_y, 0);
+ for (x = fill.min_x; x <= fill.max_x; x++)
+ destrow[x] = (UINT32)color;
+
+ /* For the other lines, just copy the first one */
+ destrow0 = BITMAP_ADDR32(dest, fill.min_y, fill.min_x);
+ for (y = fill.min_y + 1; y <= fill.max_y; y++)
+ {
+ destrow = BITMAP_ADDR32(dest, y, fill.min_x);
+ memcpy(destrow, destrow0, (fill.max_x + 1 - fill.min_x) * 4);
+ }
+ }
+ break;
+
+ case 64:
+ /* 64bpp can use memset if the bytes are equal */
+ if ((UINT8)(color >> 8) == (UINT8)color && (UINT16)(color >> 16) == (UINT16)color)
+ {
+ for (y = fill.min_y; y <= fill.max_y; y++)
+ memset(BITMAP_ADDR64(dest, y, fill.min_x), (UINT8)color, (fill.max_x + 1 - fill.min_x) * 4);
+ }
+ else
+ {
+ UINT64 *destrow, *destrow0;
+
+ /* Fill the first line the hard way */
+ destrow = BITMAP_ADDR64(dest, fill.min_y, 0);
+ for (x = fill.min_x; x <= fill.max_x; x++)
+ destrow[x] = (UINT64)color;
+
+ /* For the other lines, just copy the first one */
+ destrow0 = BITMAP_ADDR64(dest, fill.min_y, fill.min_x);
+ for (y = fill.min_y + 1; y <= fill.max_y; y++)
+ {
+ destrow = BITMAP_ADDR64(dest, y, fill.min_x);
+ memcpy(destrow, destrow0, (fill.max_x + 1 - fill.min_x) * 4);
+ }
+ }
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ BITMAP UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ bitmap_format_to_bpp - given a format, return
+ the bpp
+-------------------------------------------------*/
+
+int bitmap_format_to_bpp(bitmap_format format)
+{
+ /* choose a depth for the format */
+ switch (format)
+ {
+ case BITMAP_FORMAT_INDEXED8:
+ return 8;
+
+ case BITMAP_FORMAT_INDEXED16:
+ case BITMAP_FORMAT_RGB15:
+ case BITMAP_FORMAT_YUY16:
+ return 16;
+
+ case BITMAP_FORMAT_INDEXED32:
+ case BITMAP_FORMAT_RGB32:
+ case BITMAP_FORMAT_ARGB32:
+ return 32;
+
+ case BITMAP_FORMAT_INDEXED64:
+ return 64;
+
+ default:
+ break;
+ }
+ return 0;
+}