// 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. *********************************************************************/ #ifndef MAME_EMU_DRAWGFXT_IPP #define MAME_EMU_DRAWGFXT_IPP #pragma once /*************************************************************************** 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 inline 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 inline 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 inline 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()) break; // 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 inline 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 inline 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 inline 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 bool wraparound - true 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 inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, const BitmapType &src, s32 startx, s32 starty, s32 incxx, s32 incxy, s32 incyx, s32 incyy, bool 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 inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, const BitmapType &src, s32 startx, s32 starty, s32 incxx, s32 incxy, s32 incyx, s32 incyy, bool 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 inline 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 inline 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