summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/drawgfxt.ipp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/drawgfxt.ipp')
-rw-r--r--src/emu/drawgfxt.ipp1911
1 files changed, 1911 insertions, 0 deletions
diff --git a/src/emu/drawgfxt.ipp b/src/emu/drawgfxt.ipp
new file mode 100644
index 00000000000..eb4910ebf78
--- /dev/null
+++ b/src/emu/drawgfxt.ipp
@@ -0,0 +1,1911 @@
+// license:BSD-3-Clause
+// copyright-holders:Nicola Salmoria, Aaron Giles
+/*********************************************************************
+
+ drawgfxt.ipp
+
+ Template function implementing drawgfx core operations. Drivers
+ can use these if they need custom behavior not provided by the
+ existing drawgfx functions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef MAME_EMU_DRAWGFXT_IPP
+#define MAME_EMU_DRAWGFXT_IPP
+
+
+/***************************************************************************
+ PIXEL OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ PIXEL_OP_COPY_OPAQUE - render all pixels
+ regardless of pen, copying directly
+-------------------------------------------------*/
+
+#define PIXEL_OP_COPY_OPAQUE(DEST, SOURCE) \
+do \
+{ \
+ (DEST) = SOURCE; \
+} \
+while (0)
+#define PIXEL_OP_COPY_OPAQUE_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = SOURCE; \
+ (PRIORITY) = 31; \
+} \
+while (0)
+#define PIXEL_OP_COPY_OPAQUE_PRIMASK(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ (DEST) = SOURCE; \
+ (PRIORITY) = ((PRIORITY) & pmask) | pcode; \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_COPY_TRANSPEN - render all pixels
+ except those matching 'transpen', copying
+ directly
+-------------------------------------------------*/
+
+#define PIXEL_OP_COPY_TRANSPEN(DEST, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (srcdata != trans_pen) \
+ (DEST) = SOURCE; \
+} \
+while (0)
+#define PIXEL_OP_COPY_TRANSPEN_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (srcdata != trans_pen) \
+ { \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = SOURCE; \
+ (PRIORITY) = 31; \
+ } \
+} \
+while (0)
+#define PIXEL_OP_COPY_TRANSPEN_PRIMASK(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (srcdata != trans_pen) \
+ { \
+ (DEST) = SOURCE; \
+ (PRIORITY) = ((PRIORITY) & pmask) | pcode; \
+ } \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_COPY_TRANSALPHA - render all pixels
+ except those with an alpha of zero, copying
+ directly
+-------------------------------------------------*/
+
+#define PIXEL_OP_COPY_TRANSALPHA(DEST, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if ((srcdata & 0xff000000) != 0) \
+ (DEST) = SOURCE; \
+} \
+while (0)
+#define PIXEL_OP_COPY_TRANSALPHA_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if ((srcdata & 0xff000000) != 0) \
+ { \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = SOURCE; \
+ (PRIORITY) = 31; \
+ } \
+} \
+while (0)
+#define PIXEL_OP_COPY_TRANSALPHA_PRIMASK(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if ((srcdata & 0xff000000) != 0) \
+ { \
+ (DEST) = SOURCE; \
+ (PRIORITY) = ((PRIORITY) & pmask) | pcode; \
+ } \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_REMAP_OPAQUE - render all pixels
+ regardless of pen, mapping the pen via the
+ 'paldata' array
+-------------------------------------------------*/
+
+#define PIXEL_OP_REMAP_OPAQUE(DEST, SOURCE) \
+do \
+{ \
+ (DEST) = paldata[SOURCE]; \
+} \
+while (0)
+#define PIXEL_OP_REMAP_OPAQUE_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = paldata[SOURCE]; \
+ (PRIORITY) = 31; \
+} \
+while (0)
+#define PIXEL_OP_REMAP_OPAQUE_PRIMASK(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ (DEST) = paldata[SOURCE]; \
+ (PRIORITY) = ((PRIORITY) & pmask) | pcode; \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_REBASE_OPAQUE - render all pixels
+ regardless of pen, adding 'color' to the
+ pen value
+-------------------------------------------------*/
+
+#define PIXEL_OP_REBASE_OPAQUE(DEST, SOURCE) \
+do \
+{ \
+ (DEST) = color + (SOURCE); \
+} \
+while (0)
+#define PIXEL_OP_REBASE_OPAQUE_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = color + (SOURCE); \
+ (PRIORITY) = 31; \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_REMAP_TRANSPEN - render all pixels
+ except those matching 'trans_pen', mapping the
+ pen via the 'paldata' array
+-------------------------------------------------*/
+
+#define PIXEL_OP_REMAP_TRANSPEN(DEST, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (srcdata != trans_pen) \
+ (DEST) = paldata[srcdata]; \
+} \
+while (0)
+#define PIXEL_OP_REMAP_TRANSPEN_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (srcdata != trans_pen) \
+ { \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = paldata[srcdata]; \
+ (PRIORITY) = 31; \
+ } \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_REBASE_TRANSPEN - render all pixels
+ except those matching 'transpen', adding
+ 'color' to the pen value
+-------------------------------------------------*/
+
+#define PIXEL_OP_REBASE_TRANSPEN(DEST, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (srcdata != trans_pen) \
+ (DEST) = color + srcdata; \
+} \
+while (0)
+#define PIXEL_OP_REBASE_TRANSPEN_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (srcdata != trans_pen) \
+ { \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = color + srcdata; \
+ (PRIORITY) = 31; \
+ } \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_REMAP_TRANSMASK - render all pixels
+ except those matching 'trans_mask', mapping the
+ pen via the 'paldata' array
+-------------------------------------------------*/
+
+#define PIXEL_OP_REMAP_TRANSMASK(DEST, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (((trans_mask >> srcdata) & 1) == 0) \
+ (DEST) = paldata[srcdata]; \
+} \
+while (0)
+#define PIXEL_OP_REMAP_TRANSMASK_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (((trans_mask >> srcdata) & 1) == 0) \
+ { \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = paldata[srcdata]; \
+ (PRIORITY) = 31; \
+ } \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_REBASE_TRANSMASK - render all pixels
+ except those matching 'trans_mask', adding
+ 'color' to the pen value
+-------------------------------------------------*/
+
+#define PIXEL_OP_REBASE_TRANSMASK(DEST, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (((trans_mask >> srcdata) & 1) == 0) \
+ (DEST) = color + srcdata; \
+} \
+while (0)
+#define PIXEL_OP_REBASE_TRANSMASK_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (((trans_mask >> srcdata) & 1) == 0) \
+ { \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = color + srcdata; \
+ (PRIORITY) = 31; \
+ } \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_REBASE_TRANSTABLE - look up each pen in
+ 'pentable'; if the entry is DRAWMODE_NONE,
+ don't draw it; if the entry is DRAWMODE_SOURCE,
+ add 'color' to the pen value; if the entry is
+ DRAWMODE_SHADOW, generate a shadow of the
+ destination pixel using 'shadowtable'
+
+ PIXEL_OP_REMAP_TRANSTABLE - look up each pen in
+ 'pentable'; if the entry is DRAWMODE_NONE,
+ don't draw it; if the entry is DRAWMODE_SOURCE,
+ look up the pen via the 'paldata' array; if the
+ entry is DRAWMODE_SHADOW, generate a shadow of
+ the destination pixel using 'shadowtable'
+-------------------------------------------------*/
+
+#define PIXEL_OP_REBASE_TRANSTABLE16(DEST, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ u32 entry = pentable[srcdata]; \
+ if (entry != DRAWMODE_NONE) \
+ { \
+ if (entry == DRAWMODE_SOURCE) \
+ (DEST) = color + srcdata; \
+ else \
+ (DEST) = shadowtable[DEST]; \
+ } \
+} \
+while (0)
+#define PIXEL_OP_REMAP_TRANSTABLE32(DEST, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ u32 entry = pentable[srcdata]; \
+ if (entry != DRAWMODE_NONE) \
+ { \
+ if (entry == DRAWMODE_SOURCE) \
+ (DEST) = paldata[srcdata]; \
+ else \
+ (DEST) = shadowtable[rgb_t(DEST).as_rgb15()]; \
+ } \
+} \
+while (0)
+#define PIXEL_OP_REBASE_TRANSTABLE16_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ u32 entry = pentable[srcdata]; \
+ if (entry != DRAWMODE_NONE) \
+ { \
+ u8 pridata = (PRIORITY); \
+ if (entry == DRAWMODE_SOURCE) \
+ { \
+ if (((1 << (pridata & 0x1f)) & pmask) == 0) \
+ (DEST) = color + srcdata; \
+ (PRIORITY) = 31; \
+ } \
+ else if ((pridata & 0x80) == 0 && ((1 << (pridata & 0x1f)) & pmask) == 0) \
+ { \
+ (DEST) = shadowtable[DEST]; \
+ (PRIORITY) = pridata | 0x80; \
+ } \
+ } \
+} \
+while (0)
+#define PIXEL_OP_REMAP_TRANSTABLE32_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ u32 entry = pentable[srcdata]; \
+ if (entry != DRAWMODE_NONE) \
+ { \
+ u8 pridata = (PRIORITY); \
+ if (entry == DRAWMODE_SOURCE) \
+ { \
+ if (((1 << (pridata & 0x1f)) & pmask) == 0) \
+ (DEST) = paldata[srcdata]; \
+ (PRIORITY) = 31; \
+ } \
+ else if ((pridata & 0x80) == 0 && ((1 << (pridata & 0x1f)) & pmask) == 0) \
+ { \
+ (DEST) = shadowtable[rgb_t(DEST).as_rgb15()]; \
+ (PRIORITY) = pridata | 0x80; \
+ } \
+ } \
+} \
+while (0)
+
+/*-------------------------------------------------
+ PIXEL_OP_REMAP_TRANSPEN_ALPHA - render all
+ pixels except those matching 'transpen',
+ mapping the pen to via the 'paldata' array;
+ the resulting color is RGB alpha blended
+ against the destination using 'alpha'
+-------------------------------------------------*/
+
+#define PIXEL_OP_REMAP_TRANSPEN_ALPHA32(DEST, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (srcdata != trans_pen) \
+ (DEST) = alpha_blend_r32((DEST), paldata[srcdata], alpha_val); \
+} \
+while (0)
+#define PIXEL_OP_REMAP_TRANSPEN_ALPHA32_PRIORITY(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if (srcdata != trans_pen) \
+ { \
+ if (((1 << ((PRIORITY) & 0x1f)) & pmask) == 0) \
+ (DEST) = alpha_blend_r32((DEST), paldata[srcdata], alpha_val); \
+ (PRIORITY) = 31; \
+ } \
+} \
+while (0)
+
+
+/***************************************************************************
+ BASIC DRAWGFX CORE
+***************************************************************************/
+
+/*
+ Input parameters:
+
+ bitmap_t &dest - the bitmap to render to
+ const rectangle &cliprect - a clipping rectangle (assumed to be clipped to the size of 'dest')
+ gfx_element *gfx - pointer to the gfx_element to render
+ u32 code - index of the entry within gfx_element
+ int flipx - non-zero means render right-to-left instead of left-to-right
+ int flipy - non-zero means render bottom-to-top instead of top-to-bottom
+ s32 destx - the top-left X coordinate to render to
+ s32 desty - the top-left Y coordinate to render to
+ bitmap_t &priority - the priority bitmap (if and only if priority is to be applied)
+*/
+
+
+template <typename BitmapType, typename FunctionClass>
+void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, FunctionClass pixel_op)
+{
+ g_profiler.start(PROFILER_DRAWGFX);
+ do {
+ assert(dest.valid());
+ assert(dest.cliprect().contains(cliprect));
+ assert(code < elements());
+
+ // ignore empty/invalid cliprects
+ if (cliprect.empty())
+ break;
+
+ // compute final pixel in X and exit if we are entirely clipped
+ s32 destendx = destx + width() - 1;
+ if (destx > cliprect.right() || destendx < cliprect.left())
+ break;
+
+ // apply left clip
+ s32 srcx = 0;
+ if (destx < cliprect.left())
+ {
+ srcx = cliprect.left() - destx;
+ destx = cliprect.left();
+ }
+
+ // apply right clip
+ if (destendx > cliprect.right())
+ destendx = cliprect.right();
+
+ // compute final pixel in Y and exit if we are entirely clipped
+ s32 destendy = desty + height() - 1;
+ if (desty > cliprect.bottom() || destendy < cliprect.top())
+ break;
+
+ // apply top clip
+ s32 srcy = 0;
+ if (desty < cliprect.top())
+ {
+ srcy = cliprect.top() - desty;
+ desty = cliprect.top();
+ }
+
+ // apply bottom clip
+ if (destendy > cliprect.bottom())
+ destendy = cliprect.bottom();
+
+ // apply X flipping
+ if (flipx)
+ srcx = width() - 1 - srcx;
+
+ // apply Y flipping
+ s32 dy = rowbytes();
+ if (flipy)
+ {
+ srcy = height() - 1 - srcy;
+ dy = -dy;
+ }
+
+ // fetch the source data
+ const u8 *srcdata = get_data(code);
+
+ // compute how many blocks of 4 pixels we have
+ u32 numblocks = (destendx + 1 - destx) / 4;
+ u32 leftovers = (destendx + 1 - destx) - 4 * numblocks;
+
+ // adjust srcdata to point to the first source pixel of the row
+ srcdata += srcy * rowbytes() + srcx;
+
+ // non-flipped 8bpp case
+ if (!flipx)
+ {
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *destptr = &dest.pix(cury, destx);
+ const u8 *srcptr = srcdata;
+ srcdata += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], srcptr[0]);
+ pixel_op(destptr[1], srcptr[1]);
+ pixel_op(destptr[2], srcptr[2]);
+ pixel_op(destptr[3], srcptr[3]);
+
+ srcptr += 4;
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], srcptr[0]);
+ srcptr++;
+ destptr++;
+ }
+ }
+ }
+
+ // flipped 8bpp case
+ else
+ {
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *destptr = &dest.pix(cury, destx);
+ const u8 *srcptr = srcdata;
+ srcdata += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], srcptr[ 0]);
+ pixel_op(destptr[1], srcptr[-1]);
+ pixel_op(destptr[2], srcptr[-2]);
+ pixel_op(destptr[3], srcptr[-3]);
+
+ srcptr -= 4;
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], srcptr[0]);
+ srcptr--;
+ destptr++;
+ }
+ }
+ }
+ } while (0);
+ g_profiler.stop();
+}
+
+
+template <typename BitmapType, typename PriorityType, typename FunctionClass>
+void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, PriorityType &priority, FunctionClass pixel_op)
+{
+ g_profiler.start(PROFILER_DRAWGFX);
+ do {
+ assert(dest.valid());
+ assert(priority.valid());
+ assert(dest.cliprect().contains(cliprect));
+ assert(code < elements());
+
+ // ignore empty/invalid cliprects
+ if (cliprect.empty())
+ break;
+
+ // compute final pixel in X and exit if we are entirely clipped
+ s32 destendx = destx + width() - 1;
+ if (destx > cliprect.right() || destendx < cliprect.left())
+ break;
+
+ // apply left clip
+ s32 srcx = 0;
+ if (destx < cliprect.left())
+ {
+ srcx = cliprect.left() - destx;
+ destx = cliprect.left();
+ }
+
+ // apply right clip
+ if (destendx > cliprect.right())
+ destendx = cliprect.right();
+
+ // compute final pixel in Y and exit if we are entirely clipped
+ s32 destendy = desty + height() - 1;
+ if (desty > cliprect.bottom() || destendy < cliprect.top())
+ break;
+
+ // apply top clip
+ s32 srcy = 0;
+ if (desty < cliprect.top())
+ {
+ srcy = cliprect.top() - desty;
+ desty = cliprect.top();
+ }
+
+ // apply bottom clip
+ if (destendy > cliprect.bottom())
+ destendy = cliprect.bottom();
+
+ // apply X flipping
+ if (flipx)
+ srcx = width() - 1 - srcx;
+
+ // apply Y flipping
+ s32 dy = rowbytes();
+ if (flipy)
+ {
+ srcy = height() - 1 - srcy;
+ dy = -dy;
+ }
+
+ // fetch the source data
+ const u8 *srcdata = get_data(code);
+
+ // compute how many blocks of 4 pixels we have
+ u32 numblocks = (destendx + 1 - destx) / 4;
+ u32 leftovers = (destendx + 1 - destx) - 4 * numblocks;
+
+ // adjust srcdata to point to the first source pixel of the row
+ srcdata += srcy * rowbytes() + srcx;
+
+ // non-flipped 8bpp case
+ if (!flipx)
+ {
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *priptr = &priority.pix(cury, destx);
+ auto *destptr = &dest.pix(cury, destx);
+ const u8 *srcptr = srcdata;
+ srcdata += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ pixel_op(destptr[1], priptr[1], srcptr[1]);
+ pixel_op(destptr[2], priptr[2], srcptr[2]);
+ pixel_op(destptr[3], priptr[3], srcptr[3]);
+
+ srcptr += 4;
+ destptr += 4;
+ priptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ srcptr++;
+ destptr++;
+ priptr++;
+ }
+ }
+ }
+
+ // flipped 8bpp case
+ else
+ {
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *priptr = &priority.pix(cury, destx);
+ auto *destptr = &dest.pix(cury, destx);
+ const u8 *srcptr = srcdata;
+ srcdata += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[ 0]);
+ pixel_op(destptr[1], priptr[1], srcptr[-1]);
+ pixel_op(destptr[2], priptr[2], srcptr[-2]);
+ pixel_op(destptr[3], priptr[3], srcptr[-3]);
+
+ srcptr -= 4;
+ destptr += 4;
+ priptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ srcptr--;
+ destptr++;
+ priptr++;
+ }
+ }
+ }
+ } while (0);
+ g_profiler.stop();
+}
+
+
+
+/***************************************************************************
+ BASIC DRAWGFXZOOM CORE
+***************************************************************************/
+
+/*
+ Input parameters:
+
+ bitmap_t &dest - the bitmap to render to
+ const rectangle &cliprect - a clipping rectangle (assumed to be clipped to the size of 'dest')
+ gfx_element *gfx - pointer to the gfx_element to render
+ u32 code - index of the entry within gfx_element
+ int flipx - non-zero means render right-to-left instead of left-to-right
+ int flipy - non-zero means render bottom-to-top instead of top-to-bottom
+ s32 destx - the top-left X coordinate to render to
+ s32 desty - the top-left Y coordinate to render to
+ u32 scalex - the 16.16 scale factor in the X dimension
+ u32 scaley - the 16.16 scale factor in the Y dimension
+ bitmap_t &priority - the priority bitmap (if and only if priority is to be applied)
+*/
+
+
+template <typename BitmapType, typename FunctionClass>
+void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 scalex, u32 scaley, FunctionClass pixel_op)
+{
+ g_profiler.start(PROFILER_DRAWGFX);
+ do {
+ assert(dest.valid());
+ assert(dest.cliprect().contains(cliprect));
+
+ // ignore empty/invalid cliprects
+ if (cliprect.empty())
+ break;
+
+ // compute scaled size
+ u32 dstwidth = (scalex * width() + 0x8000) >> 16;
+ u32 dstheight = (scaley * height() + 0x8000) >> 16;
+ if (dstwidth < 1 || dstheight < 1)
+ break;
+
+ // compute 16.16 source steps in dx and dy
+ s32 dx = (width() << 16) / dstwidth;
+ s32 dy = (height() << 16) / dstheight;
+
+ // compute final pixel in X and exit if we are entirely clipped
+ s32 destendx = destx + dstwidth - 1;
+ if (destx > cliprect.right() || destendx < cliprect.left())
+ break;
+
+ // apply left clip
+ s32 srcx = 0;
+ if (destx < cliprect.left())
+ {
+ srcx = (cliprect.left() - destx) * dx;
+ destx = cliprect.left();
+ }
+
+ // apply right clip
+ if (destendx > cliprect.right())
+ destendx = cliprect.right();
+
+ // compute final pixel in Y and exit if we are entirely clipped
+ s32 destendy = desty + dstheight - 1;
+ if (desty > cliprect.bottom() || destendy < cliprect.top())
+ {
+ g_profiler.stop();
+ return;
+ }
+
+ // apply top clip
+ s32 srcy = 0;
+ if (desty < cliprect.top())
+ {
+ srcy = (cliprect.top() - desty) * dy;
+ desty = cliprect.top();
+ }
+
+ // apply bottom clip
+ if (destendy > cliprect.bottom())
+ destendy = cliprect.bottom();
+
+ // apply X flipping
+ if (flipx)
+ {
+ srcx = (dstwidth - 1) * dx - srcx;
+ dx = -dx;
+ }
+
+ // apply Y flipping
+ if (flipy)
+ {
+ srcy = (dstheight - 1) * dy - srcy;
+ dy = -dy;
+ }
+
+ // fetch the source data
+ const u8 *srcdata = get_data(code);
+
+ // compute how many blocks of 4 pixels we have
+ u32 numblocks = (destendx + 1 - destx) / 4;
+ u32 leftovers = (destendx + 1 - destx) - 4 * numblocks;
+
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *destptr = &dest.pix(cury, destx);
+ const u8 *srcptr = srcdata + (srcy >> 16) * rowbytes();
+ s32 cursrcx = srcx;
+ srcy += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+ pixel_op(destptr[1], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+ pixel_op(destptr[2], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+ pixel_op(destptr[3], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+ destptr++;
+ }
+ }
+ } while (0);
+ g_profiler.stop();
+}
+
+
+template <typename BitmapType, typename PriorityType, typename FunctionClass>
+void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 scalex, u32 scaley, PriorityType &priority, FunctionClass pixel_op)
+{
+ g_profiler.start(PROFILER_DRAWGFX);
+ do {
+ assert(dest.valid());
+ assert(priority.valid());
+ assert(dest.cliprect().contains(cliprect));
+
+ // ignore empty/invalid cliprects
+ if (cliprect.empty())
+ break;
+
+ // compute scaled size
+ u32 dstwidth = (scalex * width() + 0x8000) >> 16;
+ u32 dstheight = (scaley * height() + 0x8000) >> 16;
+ if (dstwidth < 1 || dstheight < 1)
+ break;
+
+ // compute 16.16 source steps in dx and dy
+ s32 dx = (width() << 16) / dstwidth;
+ s32 dy = (height() << 16) / dstheight;
+
+ // compute final pixel in X and exit if we are entirely clipped
+ s32 destendx = destx + dstwidth - 1;
+ if (destx > cliprect.right() || destendx < cliprect.left())
+ break;
+
+ // apply left clip
+ s32 srcx = 0;
+ if (destx < cliprect.left())
+ {
+ srcx = (cliprect.left() - destx) * dx;
+ destx = cliprect.left();
+ }
+
+ // apply right clip
+ if (destendx > cliprect.right())
+ destendx = cliprect.right();
+
+ // compute final pixel in Y and exit if we are entirely clipped
+ s32 destendy = desty + dstheight - 1;
+ if (desty > cliprect.bottom() || destendy < cliprect.top())
+ {
+ g_profiler.stop();
+ return;
+ }
+
+ // apply top clip
+ s32 srcy = 0;
+ if (desty < cliprect.top())
+ {
+ srcy = (cliprect.top() - desty) * dy;
+ desty = cliprect.top();
+ }
+
+ // apply bottom clip
+ if (destendy > cliprect.bottom())
+ destendy = cliprect.bottom();
+
+ // apply X flipping
+ if (flipx)
+ {
+ srcx = (dstwidth - 1) * dx - srcx;
+ dx = -dx;
+ }
+
+ // apply Y flipping
+ if (flipy)
+ {
+ srcy = (dstheight - 1) * dy - srcy;
+ dy = -dy;
+ }
+
+ // fetch the source data
+ const u8 *srcdata = get_data(code);
+
+ // compute how many blocks of 4 pixels we have
+ u32 numblocks = (destendx + 1 - destx) / 4;
+ u32 leftovers = (destendx + 1 - destx) - 4 * numblocks;
+
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *priptr = &priority.pix(cury, destx);
+ auto *destptr = &dest.pix(cury, destx);
+ const u8 *srcptr = srcdata + (srcy >> 16) * rowbytes();
+ s32 cursrcx = srcx;
+ srcy += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+ pixel_op(destptr[1], priptr[1], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+ pixel_op(destptr[2], priptr[2], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+ pixel_op(destptr[3], priptr[3], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+
+ destptr += 4;
+ priptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[cursrcx >> 16]);
+ cursrcx += dx;
+ destptr++;
+ priptr++;
+ }
+ }
+ } while (0);
+ g_profiler.stop();
+}
+
+
+
+/***************************************************************************
+ BASIC COPYBITMAP CORE
+***************************************************************************/
+
+/*
+ Input parameters:
+
+ bitmap_t &dest - the bitmap to copy to
+ bitmap_t &src - the bitmap to copy from (must be same bpp as dest)
+ const rectangle &cliprect - a clipping rectangle (assumed to be clipped to the size of 'dest')
+ int flipx - non-zero means render right-to-left instead of left-to-right
+ int flipy - non-zero means render bottom-to-top instead of top-to-bottom
+ s32 destx - the top-left X coordinate to copy to
+ s32 desty - the top-left Y coordinate to copy to
+ bitmap_t &priority - the priority bitmap (if and only if priority is to be applied)
+*/
+
+template <typename BitmapType, typename FunctionClass>
+void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, FunctionClass pixel_op)
+{
+ g_profiler.start(PROFILER_COPYBITMAP);
+ do {
+ assert(dest.valid());
+ assert(src.valid());
+ assert(dest.cliprect().contains(cliprect));
+
+ // ignore empty/invalid cliprects
+ if (cliprect.empty())
+ break;
+
+ // standard setup; dx counts bytes in X, dy counts pixels in Y
+ s32 dx = 1;
+ s32 dy = src.rowpixels();
+
+ // compute final pixel in X and exit if we are entirely clipped
+ s32 destendx = destx + src.width() - 1;
+ if (destx > cliprect.right() || destendx < cliprect.left())
+ break;
+
+ // apply left clip
+ s32 srcx = 0;
+ if (destx < cliprect.left())
+ {
+ srcx = cliprect.left() - destx;
+ destx = cliprect.left();
+ }
+
+ // apply right clip
+ if (destendx > cliprect.right())
+ destendx = cliprect.right();
+
+ // compute final pixel in Y and exit if we are entirely clipped
+ s32 destendy = desty + src.height() - 1;
+ if (desty > cliprect.bottom() || destendy < cliprect.top())
+ break;
+
+ // apply top clip
+ s32 srcy = 0;
+ if (desty < cliprect.top())
+ {
+ srcy = cliprect.top() - desty;
+ desty = cliprect.top();
+ }
+
+ // apply bottom clip
+ if (destendy > cliprect.bottom())
+ destendy = cliprect.bottom();
+
+ // apply X flipping
+ if (flipx)
+ {
+ srcx = src.width() - 1 - srcx;
+ dx = -dx;
+ }
+
+ // apply Y flipping
+ if (flipy)
+ {
+ srcy = src.height() - 1 - srcy;
+ dy = -dy;
+ }
+
+ // compute how many blocks of 4 pixels we have
+ u32 numblocks = (destendx + 1 - destx) / 4;
+ u32 leftovers = (destendx + 1 - destx) - 4 * numblocks;
+
+ // compute the address of the first source pixel of the first row
+ const auto *srcdata = &src.pix(srcy, srcx);
+
+ // non-flipped case
+ if (!flipx)
+ {
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *destptr = &dest.pix(cury, destx);
+ const auto *srcptr = srcdata;
+ srcdata += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], srcptr[0]);
+ pixel_op(destptr[1], srcptr[1]);
+ pixel_op(destptr[2], srcptr[2]);
+ pixel_op(destptr[3], srcptr[3]);
+
+ srcptr += 4;
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], srcptr[0]);
+ srcptr++;
+ destptr++;
+ }
+ }
+ }
+
+ // flipped case
+ else
+ {
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *destptr = &dest.pix(cury, destx);
+ const auto *srcptr = srcdata;
+ srcdata += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], srcptr[ 0]);
+ pixel_op(destptr[1], srcptr[-1]);
+ pixel_op(destptr[2], srcptr[-2]);
+ pixel_op(destptr[3], srcptr[-3]);
+
+ srcptr -= 4;
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], srcptr[0]);
+ srcptr--;
+ destptr++;
+ }
+ }
+ }
+ } while (0);
+ g_profiler.stop();
+}
+
+
+template <typename BitmapType, typename PriorityType, typename FunctionClass>
+void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, PriorityType &priority, FunctionClass pixel_op)
+{
+ g_profiler.start(PROFILER_COPYBITMAP);
+ do {
+ assert(dest.valid());
+ assert(src.valid());
+ assert(priority.valid());
+ assert(dest.cliprect().contains(cliprect));
+
+ // ignore empty/invalid cliprects
+ if (cliprect.empty())
+ break;
+
+ // standard setup; dx counts bytes in X, dy counts pixels in Y
+ s32 dx = 1;
+ s32 dy = src.rowpixels();
+
+ // compute final pixel in X and exit if we are entirely clipped
+ s32 destendx = destx + src.width() - 1;
+ if (destx > cliprect.right() || destendx < cliprect.left())
+ break;
+
+ // apply left clip
+ s32 srcx = 0;
+ if (destx < cliprect.left())
+ {
+ srcx = cliprect.left() - destx;
+ destx = cliprect.left();
+ }
+
+ // apply right clip
+ if (destendx > cliprect.right())
+ destendx = cliprect.right();
+
+ // compute final pixel in Y and exit if we are entirely clipped
+ s32 destendy = desty + src.height() - 1;
+ if (desty > cliprect.bottom() || destendy < cliprect.top())
+ break;
+
+ // apply top clip
+ s32 srcy = 0;
+ if (desty < cliprect.top())
+ {
+ srcy = cliprect.top() - desty;
+ desty = cliprect.top();
+ }
+
+ // apply bottom clip
+ if (destendy > cliprect.bottom())
+ destendy = cliprect.bottom();
+
+ // apply X flipping
+ if (flipx)
+ {
+ srcx = src.width() - 1 - srcx;
+ dx = -dx;
+ }
+
+ // apply Y flipping
+ if (flipy)
+ {
+ srcy = src.height() - 1 - srcy;
+ dy = -dy;
+ }
+
+ // compute how many blocks of 4 pixels we have
+ u32 numblocks = (destendx + 1 - destx) / 4;
+ u32 leftovers = (destendx + 1 - destx) - 4 * numblocks;
+
+ // compute the address of the first source pixel of the first row
+ const auto *srcdata = &src.pix(srcy, srcx);
+
+ // non-flipped case
+ if (!flipx)
+ {
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *priptr = &priority.pix(cury, destx);
+ auto *destptr = &dest.pix(cury, destx);
+ const auto *srcptr = srcdata;
+ srcdata += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ pixel_op(destptr[1], priptr[1], srcptr[1]);
+ pixel_op(destptr[2], priptr[2], srcptr[2]);
+ pixel_op(destptr[3], priptr[3], srcptr[3]);
+
+ srcptr += 4;
+ destptr += 4;
+ priptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ srcptr++;
+ destptr++;
+ priptr++;
+ }
+ }
+ }
+
+ // flipped case
+ else
+ {
+ // iterate over pixels in Y
+ for (s32 cury = desty; cury <= destendy; cury++)
+ {
+ auto *priptr = &priority.pix(cury, destx);
+ auto *destptr = &dest.pix(cury, destx);
+ const auto *srcptr = srcdata;
+ srcdata += dy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[ 0]);
+ pixel_op(destptr[1], priptr[1], srcptr[-1]);
+ pixel_op(destptr[2], priptr[2], srcptr[-2]);
+ pixel_op(destptr[3], priptr[3], srcptr[-3]);
+
+ srcptr -= 4;
+ destptr += 4;
+ priptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ srcptr--;
+ destptr++;
+ priptr++;
+ }
+ }
+ }
+ } while (0);
+ g_profiler.stop();
+}
+
+
+
+/***************************************************************************
+ BASIC COPYROZBITMAP CORE
+***************************************************************************/
+
+/*
+ Input parameters:
+
+ bitmap_t &dest - the bitmap to copy to
+ bitmap_t &src - the bitmap to copy from (must be same bpp as dest)
+ const rectangle &cliprect - a clipping rectangle (assumed to be clipped to the size of 'dest')
+ s32 destx - the 16.16 source X position at destination pixel (0,0)
+ s32 desty - the 16.16 source Y position at destination pixel (0,0)
+ s32 incxx - the 16.16 amount to increment in source X for each destination X pixel
+ s32 incyx - the 16.16 amount to increment in source Y for each destination X pixel
+ s32 incxy - the 16.16 amount to increment in source X for each destination Y pixel
+ s32 incyy - the 16.16 amount to increment in source Y for each destination Y pixel
+ int wraparound - non-zero means wrap when hitting the edges of the source
+ bitmap_t &priority - the priority bitmap (if and only if priority is to be applied)
+*/
+
+template <typename BitmapType, typename FunctionClass>
+void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, const BitmapType &src, s32 startx, s32 starty, s32 incxx, s32 incxy, s32 incyx, s32 incyy, int wraparound, FunctionClass pixel_op)
+{
+ g_profiler.start(PROFILER_COPYBITMAP);
+
+ assert(dest.valid());
+ assert(dest.valid());
+ assert(dest.cliprect().contains(cliprect));
+ assert(!wraparound || (src.width() & (src.width() - 1)) == 0);
+ assert(!wraparound || (src.height() & (src.height() - 1)) == 0);
+
+ // ignore empty/invalid cliprects
+ if (cliprect.empty())
+ {
+ g_profiler.stop();
+ return;
+ }
+
+ // compute fixed-point 16.16 size of the source bitmap
+ u32 srcfixwidth = src.width() << 16;
+ u32 srcfixheight = src.height() << 16;
+
+ // advance the starting coordinates to the top-left of the cliprect
+ startx += cliprect.left() * incxx + cliprect.top() * incyx;
+ starty += cliprect.left() * incxy + cliprect.top() * incyy;
+
+ // compute how many blocks of 4 pixels we have
+ u32 numblocks = cliprect.width() / 4;
+ u32 leftovers = cliprect.width() - 4 * numblocks;
+
+ // if incxy and incyx are 0, then we aren't rotating, just zooming
+ if (incxy == 0 && incyx == 0)
+ {
+ // zoom-only, non-wraparound case
+ if (!wraparound)
+ {
+ // iterate over pixels in Y
+ for (s32 cury = cliprect.top(); cury <= cliprect.bottom(); cury++)
+ {
+ auto *destptr = &dest.pix(cury, cliprect.left());
+ s32 srcx = startx;
+ s32 srcy = starty;
+
+ starty += incyy;
+
+ // check srcy for the whole row at once
+ if (u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16);
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[0], srcptr[srcx >> 16]);
+ srcx += incxx;
+
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[1], srcptr[srcx >> 16]);
+ srcx += incxx;
+
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[2], srcptr[srcx >> 16]);
+ srcx += incxx;
+
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[3], srcptr[srcx >> 16]);
+ srcx += incxx;
+
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[0], srcptr[srcx >> 16]);
+ srcx += incxx;
+ destptr++;
+ }
+ }
+ }
+ }
+
+ // zoom-only, wraparound case
+ else
+ {
+ // convert srcfixwidth/height into a mask and apply
+ srcfixwidth--;
+ srcfixheight--;
+ startx &= srcfixwidth;
+ starty &= srcfixheight;
+
+ // iterate over pixels in Y
+ for (s32 cury = cliprect.top(); cury <= cliprect.bottom(); cury++)
+ {
+ auto *destptr = &dest.pix(cury, cliprect.left());
+ const auto *srcptr = &src.pix(starty >> 16);
+ s32 srcx = startx;
+
+ starty = (starty + incyy) & srcfixheight;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+
+ pixel_op(destptr[1], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+
+ pixel_op(destptr[2], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+
+ pixel_op(destptr[3], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ destptr++;
+ }
+ }
+ }
+ }
+
+ // full rotation case
+ else
+ {
+ // full rotation, non-wraparound case
+ if (!wraparound)
+ {
+ // iterate over pixels in Y
+ for (s32 cury = cliprect.top(); cury <= cliprect.bottom(); cury++)
+ {
+ auto *destptr = &dest.pix(cury, cliprect.left());
+ s32 srcx = startx;
+ s32 srcy = starty;
+
+ startx += incyx;
+ starty += incyy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[0], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[1], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[2], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[3], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[0], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+ destptr++;
+ }
+ }
+ }
+
+ // zoom-only, wraparound case
+ else
+ {
+ // convert srcfixwidth/height into a mask and apply
+ srcfixwidth--;
+ srcfixheight--;
+ startx &= srcfixwidth;
+ starty &= srcfixheight;
+
+ // iterate over pixels in Y
+ for (s32 cury = cliprect.top(); cury <= cliprect.bottom(); cury++)
+ {
+ auto *destptr = &dest.pix(cury, cliprect.left());
+ s32 srcx = startx;
+ s32 srcy = starty;
+
+ startx = (startx + incyx) & srcfixwidth;
+ starty = (starty + incyy) & srcfixheight;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[0], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+
+ srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[1], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+
+ srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[2], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+
+ srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[3], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[0], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+ destptr++;
+ }
+ }
+ }
+ }
+ g_profiler.stop();
+}
+
+
+template <typename BitmapType, typename PriorityType, typename FunctionClass>
+void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, const BitmapType &src, s32 startx, s32 starty, s32 incxx, s32 incxy, s32 incyx, s32 incyy, int wraparound, PriorityType &priority, FunctionClass pixel_op)
+{
+ g_profiler.start(PROFILER_COPYBITMAP);
+
+ assert(dest.valid());
+ assert(dest.valid());
+ assert(priority.valid());
+ assert(dest.cliprect().contains(cliprect));
+ assert(!wraparound || (src.width() & (src.width() - 1)) == 0);
+ assert(!wraparound || (src.height() & (src.height() - 1)) == 0);
+
+ // ignore empty/invalid cliprects
+ if (cliprect.empty())
+ {
+ g_profiler.stop();
+ return;
+ }
+
+ // compute fixed-point 16.16 size of the source bitmap
+ u32 srcfixwidth = src.width() << 16;
+ u32 srcfixheight = src.height() << 16;
+
+ // advance the starting coordinates to the top-left of the cliprect
+ startx += cliprect.left() * incxx + cliprect.top() * incyx;
+ starty += cliprect.left() * incxy + cliprect.top() * incyy;
+
+ // compute how many blocks of 4 pixels we have
+ u32 numblocks = cliprect.width() / 4;
+ u32 leftovers = cliprect.width() - 4 * numblocks;
+
+ // if incxy and incyx are 0, then we aren't rotating, just zooming
+ if (incxy == 0 && incyx == 0)
+ {
+ // zoom-only, non-wraparound case
+ if (!wraparound)
+ {
+ // iterate over pixels in Y
+ for (s32 cury = cliprect.top(); cury <= cliprect.bottom(); cury++)
+ {
+ auto *priptr = &priority.pix(cury, cliprect.left());
+ auto *destptr = &dest.pix(cury, cliprect.left());
+ s32 srcx = startx;
+ s32 srcy = starty;
+
+ starty += incyy;
+
+ // check srcy for the whole row at once
+ if (u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16);
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[0], priptr[0], srcptr[srcx >> 16]);
+ srcx += incxx;
+
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[1], priptr[1], srcptr[srcx >> 16]);
+ srcx += incxx;
+
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[2], priptr[2], srcptr[srcx >> 16]);
+ srcx += incxx;
+
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[3], priptr[3], srcptr[srcx >> 16]);
+ srcx += incxx;
+
+ destptr += 4;
+ priptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ if (u32(srcx) < srcfixwidth)
+ pixel_op(destptr[0], priptr[0], srcptr[srcx >> 16]);
+ srcx += incxx;
+ destptr++;
+ priptr++;
+ }
+ }
+ }
+ }
+
+ // zoom-only, wraparound case
+ else
+ {
+ // convert srcfixwidth/height into a mask and apply
+ srcfixwidth--;
+ srcfixheight--;
+ startx &= srcfixwidth;
+ starty &= srcfixheight;
+
+ // iterate over pixels in Y
+ for (s32 cury = cliprect.top(); cury <= cliprect.bottom(); cury++)
+ {
+ auto *priptr = &priority.pix(cury, cliprect.left());
+ auto *destptr = &dest.pix(cury, cliprect.left());
+ const auto *srcptr = &src.pix(starty >> 16);
+ s32 srcx = startx;
+
+ starty = (starty + incyy) & srcfixheight;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+
+ pixel_op(destptr[1], priptr[1], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+
+ pixel_op(destptr[2], priptr[2], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+
+ pixel_op(destptr[3], priptr[3], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+
+ destptr += 4;
+ priptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[srcx >> 16]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ destptr++;
+ priptr++;
+ }
+ }
+ }
+ }
+
+ // full rotation case
+ else
+ {
+ // full rotation, non-wraparound case
+ if (!wraparound)
+ {
+ // iterate over pixels in Y
+ for (s32 cury = cliprect.top(); cury <= cliprect.bottom(); cury++)
+ {
+ auto *priptr = &priority.pix(cury, cliprect.left());
+ auto *destptr = &dest.pix(cury, cliprect.left());
+ s32 srcx = startx;
+ s32 srcy = starty;
+
+ startx += incyx;
+ starty += incyy;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[1], priptr[1], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[2], priptr[2], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[3], priptr[3], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+
+ destptr += 4;
+ priptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ if (u32(srcx) < srcfixwidth && u32(srcy) < srcfixheight)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ }
+ srcx += incxx;
+ srcy += incxy;
+ destptr++;
+ priptr++;
+ }
+ }
+ }
+
+ // zoom-only, wraparound case
+ else
+ {
+ // convert srcfixwidth/height into a mask and apply
+ srcfixwidth--;
+ srcfixheight--;
+ startx &= srcfixwidth;
+ starty &= srcfixheight;
+
+ // iterate over pixels in Y
+ for (s32 cury = cliprect.top(); cury <= cliprect.bottom(); cury++)
+ {
+ auto *priptr = &priority.pix(cury, cliprect.left());
+ auto *destptr = &dest.pix(cury, cliprect.left());
+ s32 srcx = startx;
+ s32 srcy = starty;
+
+ startx = (startx + incyx) & srcfixwidth;
+ starty = (starty + incyy) & srcfixheight;
+
+ // iterate over unrolled blocks of 4
+ for (s32 curx = 0; curx < numblocks; curx++)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+
+ srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[1], priptr[1], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+
+ srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[2], priptr[2], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+
+ srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[3], priptr[3], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+
+ destptr += 4;
+ priptr += 4;
+ }
+
+ // iterate over leftover pixels
+ for (s32 curx = 0; curx < leftovers; curx++)
+ {
+ const auto *srcptr = &src.pix(srcy >> 16, srcx >> 16);
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ srcx = (srcx + incxx) & srcfixwidth;
+ srcy = (srcy + incxy) & srcfixheight;
+ destptr++;
+ priptr++;
+ }
+ }
+ }
+ }
+ g_profiler.stop();
+}
+
+
+
+/***************************************************************************
+ BASIC DRAWSCANLINE CORE
+***************************************************************************/
+
+/*
+ Input parameters:
+
+ bitmap_t &bitmap - the bitmap to copy to
+ s32 destx - the X coordinate to copy to
+ s32 desty - the Y coordinate to copy to
+ s32 length - the total number of pixels to copy
+ const UINTx *srcptr - pointer to memory containing the source pixels
+ bitmap_t &priority - the priority bitmap (if and only if priority is to be applied)
+*/
+
+template <typename BitmapType, typename SourceType, typename FunctionClass>
+void drawscanline_core(BitmapType &bitmap, s32 destx, s32 desty, s32 length, const SourceType *srcptr, FunctionClass pixel_op)
+{
+ assert(bitmap.valid());
+ assert(destx >= 0);
+ assert(destx + length <= bitmap.width());
+ assert(desty >= 0);
+ assert(desty < bitmap.height());
+ assert(srcptr != nullptr);
+
+ auto *destptr = &bitmap.pix(desty, destx);
+
+ // iterate over unrolled blocks of 4
+ while (length >= 4)
+ {
+ pixel_op(destptr[0], srcptr[0]);
+ pixel_op(destptr[1], srcptr[1]);
+ pixel_op(destptr[2], srcptr[2]);
+ pixel_op(destptr[3], srcptr[3]);
+
+ length -= 4;
+ srcptr += 4;
+ destptr += 4;
+ }
+
+ // iterate over leftover pixels
+ while (length-- > 0)
+ {
+ pixel_op(destptr[0], srcptr[0]);
+ srcptr++;
+ destptr++;
+ }
+}
+
+
+template <typename BitmapType, typename SourceType, typename PriorityType, typename FunctionClass>
+void drawscanline_core(BitmapType &bitmap, s32 destx, s32 desty, s32 length, const SourceType *srcptr, PriorityType &priority, FunctionClass pixel_op)
+{
+ assert(bitmap.valid());
+ assert(destx >= 0);
+ assert(destx + length <= bitmap.width());
+ assert(desty >= 0);
+ assert(desty < bitmap.height());
+ assert(srcptr != nullptr);
+ assert(priority.valid());
+
+ auto *priptr = &priority.pix(desty, destx);
+ auto *destptr = &bitmap.pix(desty, destx);
+
+ // iterate over unrolled blocks of 4
+ while (length >= 4)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ pixel_op(destptr[1], priptr[1], srcptr[1]);
+ pixel_op(destptr[2], priptr[2], srcptr[2]);
+ pixel_op(destptr[3], priptr[3], srcptr[3]);
+
+ length -= 4;
+ srcptr += 4;
+ destptr += 4;
+ priptr += 4;
+
+ // iterate over leftover pixels
+ while (length-- > 0)
+ {
+ pixel_op(destptr[0], priptr[0], srcptr[0]);
+ srcptr++;
+ destptr++;
+ priptr++;
+ }
+ }
+}
+
+
+#endif // MAME_EMU_DRAWGFXT_IPP