summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/rendersw.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/rendersw.c')
-rw-r--r--trunk/src/emu/rendersw.c1970
1 files changed, 1970 insertions, 0 deletions
diff --git a/trunk/src/emu/rendersw.c b/trunk/src/emu/rendersw.c
new file mode 100644
index 00000000000..1cd63727c7c
--- /dev/null
+++ b/trunk/src/emu/rendersw.c
@@ -0,0 +1,1970 @@
+/***************************************************************************
+
+ rendersw.c
+
+ Software-only rasterization system.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+
+#include "emucore.h"
+#include "eminline.h"
+#include "video/rgbutil.h"
+#include "render.h"
+
+
+template<typename _PixelType, int _SrcShiftR, int _SrcShiftG, int _SrcShiftB, int _DstShiftR, int _DstShiftG, int _DstShiftB, bool _NoDestRead = false, bool _BilinearFilter = false>
+class software_renderer
+{
+private:
+ // internal structs
+ struct quad_setup_data
+ {
+ INT32 dudx, dvdx, dudy, dvdy;
+ INT32 startu, startv;
+ INT32 startx, starty;
+ INT32 endx, endy;
+ };
+
+ // internal helpers
+ static inline bool is_opaque(float alpha) { return (alpha >= (_NoDestRead ? 0.5f : 1.0f)); }
+ static inline bool is_transparent(float alpha) { return (alpha < (_NoDestRead ? 0.5f : 0.0001f)); }
+ static inline rgb_t apply_intensity(int intensity, rgb_t color) { return MAKE_RGB((RGB_RED(color) * intensity) >> 8, (RGB_GREEN(color) * intensity) >> 8, (RGB_BLUE(color) * intensity) >> 8); }
+ static inline float round_nearest(float f) { return floor(f + 0.5f); }
+
+ // destination pixels are written based on the values of the template parameters
+ static inline _PixelType dest_assemble_rgb(UINT32 r, UINT32 g, UINT32 b) { return (r << _DstShiftR) | (g << _DstShiftG) | (b << _DstShiftB); }
+ static inline _PixelType dest_rgb_to_pixel(UINT32 r, UINT32 g, UINT32 b) { return dest_assemble_rgb(r >> _SrcShiftR, g >> _SrcShiftG, b >> _SrcShiftB); }
+
+ // source 32-bit pixels are in MAME standardized format
+ static inline UINT32 source32_r(rgb_t pixel) { return (pixel >> (16 + _SrcShiftR)) & (0xff >> _SrcShiftR); }
+ static inline UINT32 source32_g(rgb_t pixel) { return (pixel >> ( 8 + _SrcShiftG)) & (0xff >> _SrcShiftG); }
+ static inline UINT32 source32_b(rgb_t pixel) { return (pixel >> ( 0 + _SrcShiftB)) & (0xff >> _SrcShiftB); }
+
+ // destination pixel masks are based on the template parameters as well
+ static inline UINT32 dest_r(_PixelType pixel) { return (pixel >> _DstShiftR) & (0xff >> _SrcShiftR); }
+ static inline UINT32 dest_g(_PixelType pixel) { return (pixel >> _DstShiftG) & (0xff >> _SrcShiftG); }
+ static inline UINT32 dest_b(_PixelType pixel) { return (pixel >> _DstShiftB) & (0xff >> _SrcShiftB); }
+
+ // generic conversion with special optimization for destinations in the standard format
+ static inline _PixelType source32_to_dest(rgb_t pixel)
+ {
+ if (_SrcShiftR == 0 && _SrcShiftG == 0 && _SrcShiftB == 0 && _DstShiftR == 16 && _DstShiftG == 8 && _DstShiftB == 0)
+ return pixel;
+ else
+ return dest_assemble_rgb(source32_r(pixel), source32_g(pixel), source32_b(pixel));
+ }
+
+
+ //-------------------------------------------------
+ // ycc_to_rgb - convert YCC to RGB; the YCC pixel
+ // contains Y in the LSB, Cb << 8, and Cr << 16
+ // This actually a YCbCr conversion,
+ // details my be found in chapter 6.4 ff of
+ // http://softwarecommunity.intel.com/isn/downloads/softwareproducts/pdfs/346495.pdf
+ // The document also contains the constants below as floats.
+ //-------------------------------------------------
+
+ static inline UINT32 clamp16_shift8(UINT32 x)
+ {
+ return ((INT32(x) < 0) ? 0 : (x > 65535 ? 255: x >> 8));
+ }
+
+ static inline UINT32 ycc_to_rgb(UINT32 ycc)
+ {
+ // original equations:
+ //
+ // C = Y - 16
+ // D = Cb - 128
+ // E = Cr - 128
+ //
+ // R = clip(( 298 * C + 409 * E + 128) >> 8)
+ // G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
+ // B = clip(( 298 * C + 516 * D + 128) >> 8)
+ //
+ // R = clip(( 298 * (Y - 16) + 409 * (Cr - 128) + 128) >> 8)
+ // G = clip(( 298 * (Y - 16) - 100 * (Cb - 128) - 208 * (Cr - 128) + 128) >> 8)
+ // B = clip(( 298 * (Y - 16) + 516 * (Cb - 128) + 128) >> 8)
+ //
+ // R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8)
+ // G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
+ // B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8)
+ //
+ // R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8)
+ // G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
+ // B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8)
+ //
+ // Now combine constants:
+ //
+ // R = clip(( 298 * Y + 409 * Cr - 56992) >> 8)
+ // G = clip(( 298 * Y - 100 * Cb - 208 * Cr + 34784) >> 8)
+ // B = clip(( 298 * Y + 516 * Cb - 70688) >> 8)
+ //
+ // Define common = 298 * y - 56992. This will save one addition
+ //
+ // R = clip(( common + 409 * Cr - 0) >> 8)
+ // G = clip(( common - 100 * Cb - 208 * Cr + 91776) >> 8)
+ // B = clip(( common + 516 * Cb - 13696) >> 8)
+ //
+
+ UINT8 y = ycc;
+ UINT8 cb = ycc >> 8;
+ UINT8 cr = ycc >> 16;
+
+ UINT32 common = 298 * y - 56992;
+ UINT32 r = (common + 409 * cr);
+ UINT32 g = (common - 100 * cb - 208 * cr + 91776);
+ UINT32 b = (common + 516 * cb - 13696);
+
+ // Now clamp and shift back
+ return MAKE_RGB(clamp16_shift8(r), clamp16_shift8(g), clamp16_shift8(b));
+ }
+
+
+ //-------------------------------------------------
+ // get_texel_palette16 - return a texel from a
+ // palettized 16bpp source
+ //-------------------------------------------------
+
+ static inline UINT32 get_texel_palette16(const render_texinfo &texture, INT32 curu, INT32 curv)
+ {
+ if (_BilinearFilter)
+ {
+ INT32 u0 = curu >> 16;
+ INT32 u1 = 1;
+ if (u0 < 0) u0 = u1 = 0;
+ else if (u0 + 1 >= texture.width) u0 = texture.width - 1, u1 = 0;
+ INT32 v0 = curv >> 16;
+ INT32 v1 = texture.rowpixels;
+ if (v0 < 0) v0 = v1 = 0;
+ else if (v0 + 1 >= texture.height) v0 = texture.height - 1, v1 = 0;
+
+ const UINT16 *texbase = reinterpret_cast<const UINT16 *>(texture.base);
+ texbase += v0 * texture.rowpixels + u0;
+
+ rgb_t pix00 = texture.palette[texbase[0]];
+ rgb_t pix01 = texture.palette[texbase[u1]];
+ rgb_t pix10 = texture.palette[texbase[v1]];
+ rgb_t pix11 = texture.palette[texbase[u1 + v1]];
+ return rgb_bilinear_filter(pix00, pix01, pix10, pix11, curu >> 8, curv >> 8);
+ }
+ else
+ {
+ const UINT16 *texbase = reinterpret_cast<const UINT16 *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 16);
+ return texture.palette[texbase[0]];
+ }
+ }
+
+
+ //-------------------------------------------------
+ // get_texel_palette16a - return a texel from a
+ // palettized 16bpp source with alpha
+ //-------------------------------------------------
+
+ static inline UINT32 get_texel_palette16a(const render_texinfo &texture, INT32 curu, INT32 curv)
+ {
+ if (_BilinearFilter)
+ {
+ INT32 u0 = curu >> 16;
+ INT32 u1 = 1;
+ if (u0 < 0) u0 = u1 = 0;
+ else if (u0 + 1 >= texture.width) u0 = texture.width - 1, u1 = 0;
+ INT32 v0 = curv >> 16;
+ INT32 v1 = texture.rowpixels;
+ if (v0 < 0) v0 = v1 = 0;
+ else if (v0 + 1 >= texture.height) v0 = texture.height - 1, v1 = 0;
+
+ const UINT16 *texbase = reinterpret_cast<const UINT16 *>(texture.base);
+ texbase += v0 * texture.rowpixels + u0;
+
+ rgb_t pix00 = texture.palette[texbase[0]];
+ rgb_t pix01 = texture.palette[texbase[u1]];
+ rgb_t pix10 = texture.palette[texbase[v1]];
+ rgb_t pix11 = texture.palette[texbase[u1 + v1]];
+ return rgba_bilinear_filter(pix00, pix01, pix10, pix11, curu >> 8, curv >> 8);
+ }
+ else
+ {
+ const UINT16 *texbase = reinterpret_cast<const UINT16 *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 16);
+ return texture.palette[texbase[0]];
+ }
+ }
+
+
+ //-------------------------------------------------
+ // get_texel_yuy16 - return a texel from a 16bpp
+ // YCbCr source (pixel is returned as Cr-Cb-Y)
+ //-------------------------------------------------
+
+ static inline UINT32 get_texel_yuy16(const render_texinfo &texture, INT32 curu, INT32 curv)
+ {
+ if (_BilinearFilter)
+ {
+ INT32 u0 = curu >> 16;
+ INT32 u1 = 1;
+ if (u0 < 0) u0 = u1 = 0;
+ else if (u0 + 1 >= texture.width) u0 = texture.width - 1, u1 = 0;
+ INT32 v0 = curv >> 16;
+ INT32 v1 = texture.rowpixels;
+ if (v0 < 0) v0 = v1 = 0;
+ else if (v0 + 1 >= texture.height) v0 = texture.height - 1, v1 = 0;
+
+ const UINT16 *texbase = reinterpret_cast<const UINT16 *>(texture.base);
+ texbase += v0 * texture.rowpixels + (u0 & ~1);
+
+ rgb_t pix00, pix01, pix10, pix11;
+ if ((curu & 0x10000) == 0)
+ {
+ rgb_t cbcr = ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16);
+ pix00 = (texbase[0] >> 8) | cbcr;
+ pix01 = (texbase[u1] >> 8) | cbcr;
+ cbcr = ((texbase[v1 + 0] & 0xff) << 8) | ((texbase[v1 + 1] & 0xff) << 16);
+ pix10 = (texbase[v1 + 0] >> 8) | cbcr;
+ pix11 = (texbase[v1 + u1] >> 8) | cbcr;
+ }
+ else
+ {
+ rgb_t cbcr = ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16);
+ pix00 = (texbase[1] >> 8) | cbcr;
+ if (u1 != 0)
+ {
+ cbcr = ((texbase[2] & 0xff) << 8) | ((texbase[3] & 0xff) << 16);
+ pix01 = (texbase[2] >> 8) | cbcr;
+ }
+ else
+ pix01 = pix00;
+ cbcr = ((texbase[v1 + 0] & 0xff) << 8) | ((texbase[v1 + 1] & 0xff) << 16);
+ pix10 = (texbase[v1 + 1] >> 8) | cbcr;
+ if (u1 != 0)
+ {
+ cbcr = ((texbase[v1 + 2] & 0xff) << 8) | ((texbase[v1 + 3] & 0xff) << 16);
+ pix11 = (texbase[v1 + 2] >> 8) | cbcr;
+ }
+ else
+ pix11 = pix10;
+ }
+ return rgb_bilinear_filter(pix00, pix01, pix10, pix11, curu >> 8, curv >> 8);
+ }
+ else
+ {
+ const UINT16 *texbase = reinterpret_cast<const UINT16 *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 17) * 2;
+ return (texbase[(curu >> 16) & 1] >> 8) | ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16);
+ }
+ }
+
+
+ //-------------------------------------------------
+ // get_texel_rgb32 - return a texel from a 32bpp
+ // RGB source
+ //-------------------------------------------------
+
+ static inline UINT32 get_texel_rgb32(const render_texinfo &texture, INT32 curu, INT32 curv)
+ {
+ if (_BilinearFilter)
+ {
+ INT32 u0 = curu >> 16;
+ INT32 u1 = 1;
+ if (u0 < 0) u0 = u1 = 0;
+ else if (u0 + 1 >= texture.width) u0 = texture.width - 1, u1 = 0;
+ INT32 v0 = curv >> 16;
+ INT32 v1 = texture.rowpixels;
+ if (v0 < 0) v0 = v1 = 0;
+ else if (v0 + 1 >= texture.height) v0 = texture.height - 1, v1 = 0;
+
+ const UINT32 *texbase = reinterpret_cast<const UINT32 *>(texture.base);
+ texbase += v0 * texture.rowpixels + u0;
+
+ rgb_t pix00 = texbase[0];
+ rgb_t pix01 = texbase[u1];
+ rgb_t pix10 = texbase[v1];
+ rgb_t pix11 = texbase[u1 + v1];
+ return rgb_bilinear_filter(pix00, pix01, pix10, pix11, curu >> 8, curv >> 8);
+ }
+ else
+ {
+ const UINT32 *texbase = reinterpret_cast<const UINT32 *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 16);
+ return texbase[0];
+ }
+ }
+
+
+ //-------------------------------------------------
+ // get_texel_argb32 - return a texel from a 32bpp
+ // ARGB source
+ //-------------------------------------------------
+
+ static inline UINT32 get_texel_argb32(const render_texinfo &texture, INT32 curu, INT32 curv)
+ {
+ if (_BilinearFilter)
+ {
+ INT32 u0 = curu >> 16;
+ INT32 u1 = 1;
+ if (u0 < 0) u0 = u1 = 0;
+ else if (u0 + 1 >= texture.width) u0 = texture.width - 1, u1 = 0;
+ INT32 v0 = curv >> 16;
+ INT32 v1 = texture.rowpixels;
+ if (v0 < 0) v0 = v1 = 0;
+ else if (v0 + 1 >= texture.height) v0 = texture.height - 1, v1 = 0;
+
+ const UINT32 *texbase = reinterpret_cast<const UINT32 *>(texture.base);
+ texbase += v0 * texture.rowpixels + u0;
+
+ rgb_t pix00 = texbase[0];
+ rgb_t pix01 = texbase[u1];
+ rgb_t pix10 = texbase[v1];
+ rgb_t pix11 = texbase[u1 + v1];
+ return rgba_bilinear_filter(pix00, pix01, pix10, pix11, curu >> 8, curv >> 8);
+ }
+ else
+ {
+ const UINT32 *texbase = reinterpret_cast<const UINT32 *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 16);
+ return texbase[0];
+ }
+ }
+
+
+ //-------------------------------------------------
+ // draw_aa_pixel - draw an antialiased pixel
+ //-------------------------------------------------
+
+ static inline void draw_aa_pixel(_PixelType *dstdata, UINT32 pitch, int x, int y, rgb_t col)
+ {
+ _PixelType *dest = dstdata + y * pitch + x;
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 dr = source32_r(col) + dest_r(dpix);
+ UINT32 dg = source32_g(col) + dest_g(dpix);
+ UINT32 db = source32_b(col) + dest_b(dpix);
+ dr = (dr | -(dr >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ dg = (dg | -(dg >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ db = (db | -(db >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest = dest_assemble_rgb(dr, dg, db);
+ }
+
+
+ //-------------------------------------------------
+ // draw_line - draw a line or point
+ //-------------------------------------------------
+
+ static void draw_line(const render_primitive &prim, _PixelType *dstdata, INT32 width, INT32 height, UINT32 pitch)
+ {
+ // internal tables
+ static UINT32 s_cosine_table[2049];
+
+ // compute the start/end coordinates
+ int x1 = int(prim.bounds.x0 * 65536.0f);
+ int y1 = int(prim.bounds.y0 * 65536.0f);
+ int x2 = int(prim.bounds.x1 * 65536.0f);
+ int y2 = int(prim.bounds.y1 * 65536.0f);
+
+ // handle color and intensity
+ UINT32 col = MAKE_RGB(int(255.0f * prim.color.r * prim.color.a), int(255.0f * prim.color.g * prim.color.a), int(255.0f * prim.color.b * prim.color.a));
+
+ if (PRIMFLAG_GET_ANTIALIAS(prim.flags))
+ {
+ // build up the cosine table if we haven't yet
+ if (s_cosine_table[0] == 0)
+ for (int entry = 0; entry <= 2048; entry++)
+ s_cosine_table[entry] = int(double(1.0 / cos(atan(double(entry) / 2048.0))) * 0x10000000 + 0.5);
+
+ int beam = prim.width * 65536.0f;
+ if (beam < 0x00010000)
+ beam = 0x00010000;
+
+ // draw an anti-aliased line
+ int dx = abs(x1 - x2);
+ int dy = abs(y1 - y2);
+
+ if (dx >= dy)
+ {
+ int sx = ((x1 <= x2) ? 1 : -1);
+ int sy = (dy == 0) ? 0 : div_32x32_shift(y2 - y1, dx, 16);
+ if (sy < 0)
+ dy--;
+ x1 >>= 16;
+ int xx = x2 >> 16;
+ int bwidth = mul_32x32_hi(beam << 4, s_cosine_table[abs(sy) >> 5]);
+ y1 -= bwidth >> 1; // start back half the diameter
+ for (;;)
+ {
+ if (x1 >= 0 && x1 < width)
+ {
+ dx = bwidth; // init diameter of beam
+ dy = y1 >> 16;
+ if (dy >= 0 && dy < height)
+ draw_aa_pixel(dstdata, pitch, x1, dy, apply_intensity(0xff & (~y1 >> 8), col));
+ dy++;
+ dx -= 0x10000 - (0xffff & y1); // take off amount plotted
+ UINT8 a1 = (dx >> 8) & 0xff; // calc remainder pixel
+ dx >>= 16; // adjust to pixel (solid) count
+ while (dx--) // plot rest of pixels
+ {
+ if (dy >= 0 && dy < height)
+ draw_aa_pixel(dstdata, pitch, x1, dy, col);
+ dy++;
+ }
+ if (dy >= 0 && dy < height)
+ draw_aa_pixel(dstdata, pitch, x1, dy, apply_intensity(a1,col));
+ }
+ if (x1 == xx) break;
+ x1 += sx;
+ y1 += sy;
+ }
+ }
+ else
+ {
+ int sy = ((y1 <= y2) ? 1: -1);
+ int sx = (dx == 0) ? 0 : div_32x32_shift(x2 - x1, dy, 16);
+ if (sx < 0)
+ dx--;
+ y1 >>= 16;
+ int yy = y2 >> 16;
+ int bwidth = mul_32x32_hi(beam << 4,s_cosine_table[abs(sx) >> 5]);
+ x1 -= bwidth >> 1; // start back half the width
+ for (;;)
+ {
+ if (y1 >= 0 && y1 < height)
+ {
+ dy = bwidth; // calc diameter of beam
+ dx = x1 >> 16;
+ if (dx >= 0 && dx < width)
+ draw_aa_pixel(dstdata, pitch, dx, y1, apply_intensity(0xff & (~x1 >> 8), col));
+ dx++;
+ dy -= 0x10000 - (0xffff & x1); // take off amount plotted
+ UINT8 a1 = (dy >> 8) & 0xff; // remainder pixel
+ dy >>= 16; // adjust to pixel (solid) count
+ while (dy--) // plot rest of pixels
+ {
+ if (dx >= 0 && dx < width)
+ draw_aa_pixel(dstdata, pitch, dx, y1, col);
+ dx++;
+ }
+ if (dx >= 0 && dx < width)
+ draw_aa_pixel(dstdata, pitch, dx, y1, apply_intensity(a1, col));
+ }
+ if (y1 == yy) break;
+ y1 += sy;
+ x1 += sx;
+ }
+ }
+ }
+ else // use good old Bresenham for non-antialiasing 980317 BW
+ {
+ x1 = (x1 + 0x8000) >> 16;
+ y1 = (y1 + 0x8000) >> 16;
+ x2 = (x2 + 0x8000) >> 16;
+ y2 = (y2 + 0x8000) >> 16;
+
+ int dx = abs(x1 - x2);
+ int dy = abs(y1 - y2);
+ int sx = (x1 <= x2) ? 1 : -1;
+ int sy = (y1 <= y2) ? 1 : -1;
+ int cx = dx / 2;
+ int cy = dy / 2;
+
+ if (dx >= dy)
+ {
+ for (;;)
+ {
+ if (x1 >= 0 && x1 < width && y1 >= 0 && y1 < height)
+ draw_aa_pixel(dstdata, pitch, x1, y1, col);
+ if (x1 == x2) break;
+ x1 += sx;
+ cx -= dy;
+ if (cx < 0)
+ {
+ y1 += sy;
+ cx += dx;
+ }
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ if (x1 >= 0 && x1 < width && y1 >= 0 && y1 < height)
+ draw_aa_pixel(dstdata, pitch, x1, y1, col);
+ if (y1 == y2) break;
+ y1 += sy;
+ cy -= dx;
+ if (cy < 0)
+ {
+ x1 += sx;
+ cy += dy;
+ }
+ }
+ }
+ }
+ }
+
+
+
+ //**************************************************************************
+ // RECT RASTERIZERS
+ //**************************************************************************
+
+ //-------------------------------------------------
+ // draw_rect - draw a solid rectangle
+ //-------------------------------------------------
+
+ static void draw_rect(const render_primitive &prim, _PixelType *dstdata, INT32 width, INT32 height, UINT32 pitch)
+ {
+ render_bounds fpos = prim.bounds;
+ assert(fpos.x0 <= fpos.x1);
+ assert(fpos.y0 <= fpos.y1);
+
+ // clamp to integers
+ INT32 startx = round_nearest(fpos.x0);
+ INT32 starty = round_nearest(fpos.y0);
+ INT32 endx = round_nearest(fpos.x1);
+ INT32 endy = round_nearest(fpos.y1);
+
+ // ensure we fit
+ if (startx < 0) startx = 0;
+ if (startx >= width) startx = width;
+ if (endx < 0) endx = 0;
+ if (endx >= width) endx = width;
+ if (starty < 0) starty = 0;
+ if (starty >= height) starty = height;
+ if (endy < 0) endy = 0;
+ if (endy >= height) endy = height;
+
+ // bail if nothing left
+ if (fpos.x0 > fpos.x1 || fpos.y0 > fpos.y1)
+ return;
+
+ // only support alpha and "none" blendmodes
+ assert(PRIMFLAG_GET_BLENDMODE(prim.flags) == BLENDMODE_NONE ||
+ PRIMFLAG_GET_BLENDMODE(prim.flags) == BLENDMODE_ALPHA);
+
+ // fast case: no alpha
+ if (PRIMFLAG_GET_BLENDMODE(prim.flags) == BLENDMODE_NONE || is_opaque(prim.color.a))
+ {
+ UINT32 r = UINT32(256.0f * prim.color.r);
+ UINT32 g = UINT32(256.0f * prim.color.g);
+ UINT32 b = UINT32(256.0f * prim.color.b);
+ UINT32 pix;
+
+ // clamp R,G,B to 0-256 range
+ if (r > 0xff) { if (INT32(r) < 0) r = 0; else r = 0xff; }
+ if (g > 0xff) { if (INT32(g) < 0) g = 0; else g = 0xff; }
+ if (b > 0xff) { if (INT32(b) < 0) b = 0; else b = 0xff; }
+ pix = dest_rgb_to_pixel(r, g, b);
+
+ // loop over rows
+ for (INT32 y = starty; y < endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + startx;
+
+ // loop over cols
+ for (INT32 x = startx; x < endx; x++)
+ *dest++ = pix;
+ }
+ }
+
+ // alpha and/or coloring case
+ else if (!is_transparent(prim.color.a))
+ {
+ UINT32 rmask = dest_rgb_to_pixel(0xff,0x00,0x00);
+ UINT32 gmask = dest_rgb_to_pixel(0x00,0xff,0x00);
+ UINT32 bmask = dest_rgb_to_pixel(0x00,0x00,0xff);
+ UINT32 r = UINT32(256.0f * prim.color.r * prim.color.a);
+ UINT32 g = UINT32(256.0f * prim.color.g * prim.color.a);
+ UINT32 b = UINT32(256.0f * prim.color.b * prim.color.a);
+ UINT32 inva = UINT32(256.0f * (1.0f - prim.color.a));
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (r > 0xff) { if (INT32(r) < 0) r = 0; else r = 0xff; }
+ if (g > 0xff) { if (INT32(g) < 0) g = 0; else g = 0xff; }
+ if (b > 0xff) { if (INT32(b) < 0) b = 0; else b = 0xff; }
+ if (inva > 0x100) { if (INT32(inva) < 0) inva = 0; else inva = 0x100; }
+
+ // pre-shift the RGBA pieces
+ r = dest_rgb_to_pixel(r, 0, 0) << 8;
+ g = dest_rgb_to_pixel(0, g, 0) << 8;
+ b = dest_rgb_to_pixel(0, 0, b) << 8;
+
+ // loop over rows
+ for (INT32 y = starty; y < endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + startx;
+
+ // loop over cols
+ for (INT32 x = startx; x < endx; x++)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 dr = (r + ((dpix & rmask) * inva)) & (rmask << 8);
+ UINT32 dg = (g + ((dpix & gmask) * inva)) & (gmask << 8);
+ UINT32 db = (b + ((dpix & bmask) * inva)) & (bmask << 8);
+ *dest++ = (dr | dg | db) >> 8;
+ }
+ }
+ }
+ }
+
+
+ //**************************************************************************
+ // 16-BIT PALETTE RASTERIZERS
+ //**************************************************************************
+
+ //-------------------------------------------------
+ // draw_quad_palette16_none - perform
+ // rasterization of a 16bpp palettized texture
+ //-------------------------------------------------
+
+ static void draw_quad_palette16_none(const render_primitive &prim, _PixelType *dstdata, UINT32 pitch, quad_setup_data &setup)
+ {
+ INT32 dudx = setup.dudx;
+ INT32 dvdx = setup.dvdx;
+ INT32 endx = setup.endx;
+
+ // ensure all parameters are valid
+ assert(prim.texture.palette != NULL);
+
+ // fast case: no coloring, no alpha
+ if (prim.color.r >= 1.0f && prim.color.g >= 1.0f && prim.color.b >= 1.0f && is_opaque(prim.color.a))
+ {
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_palette16(prim.texture, curu, curv);
+ *dest++ = source32_to_dest(pix);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+
+ // coloring-only case
+ else if (is_opaque(prim.color.a))
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r);
+ UINT32 sg = UINT32(256.0f * prim.color.g);
+ UINT32 sb = UINT32(256.0f * prim.color.b);
+
+ // clamp R,G,B to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_palette16(prim.texture, curu, curv);
+ UINT32 r = (source32_r(pix) * sr) >> 8;
+ UINT32 g = (source32_g(pix) * sg) >> 8;
+ UINT32 b = (source32_b(pix) * sb) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+
+ // alpha and/or coloring case
+ else if (!is_transparent(prim.color.a))
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r * prim.color.a);
+ UINT32 sg = UINT32(256.0f * prim.color.g * prim.color.a);
+ UINT32 sb = UINT32(256.0f * prim.color.b * prim.color.a);
+ UINT32 invsa = UINT32(256.0f * (1.0f - prim.color.a));
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+ if (invsa > 0x100) { if (INT32(invsa) < 0) invsa = 0; else invsa = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_palette16(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = (source32_r(pix) * sr + dest_r(dpix) * invsa) >> 8;
+ UINT32 g = (source32_g(pix) * sg + dest_g(dpix) * invsa) >> 8;
+ UINT32 b = (source32_b(pix) * sb + dest_b(dpix) * invsa) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+
+ //-------------------------------------------------
+ // draw_quad_palette16_add - perform
+ // rasterization of a 16bpp palettized texture
+ //-------------------------------------------------
+
+ static void draw_quad_palette16_add(const render_primitive &prim, _PixelType *dstdata, UINT32 pitch, quad_setup_data &setup)
+ {
+ INT32 dudx = setup.dudx;
+ INT32 dvdx = setup.dvdx;
+ INT32 endx = setup.endx;
+
+ // ensure all parameters are valid
+ assert(prim.texture.palette != NULL);
+
+ // fast case: no coloring, no alpha
+ if (prim.color.r >= 1.0f && prim.color.g >= 1.0f && prim.color.b >= 1.0f && is_opaque(prim.color.a))
+ {
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_palette16(prim.texture, curu, curv);
+ if ((pix & 0xffffff) != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = source32_r(pix) + dest_r(dpix);
+ UINT32 g = source32_g(pix) + dest_g(dpix);
+ UINT32 b = source32_b(pix) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+
+ // alpha and/or coloring case
+ else
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r * prim.color.a);
+ UINT32 sg = UINT32(256.0f * prim.color.g * prim.color.a);
+ UINT32 sb = UINT32(256.0f * prim.color.b * prim.color.a);
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_palette16(prim.texture, curu, curv);
+ if ((pix & 0xffffff) != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = ((source32_r(pix) * sr) >> 8) + dest_r(dpix);
+ UINT32 g = ((source32_g(pix) * sg) >> 8) + dest_g(dpix);
+ UINT32 b = ((source32_b(pix) * sb) >> 8) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+ }
+
+
+
+ //**************************************************************************
+ // 16-BIT ALPHA PALETTE RASTERIZERS
+ //**************************************************************************
+
+ //-------------------------------------------------
+ // draw_quad_palettea16_alpha - perform
+ // rasterization using standard alpha blending
+ //-------------------------------------------------
+
+ static void draw_quad_palettea16_alpha(const render_primitive &prim, _PixelType *dstdata, UINT32 pitch, quad_setup_data &setup)
+ {
+ INT32 dudx = setup.dudx;
+ INT32 dvdx = setup.dvdx;
+ INT32 endx = setup.endx;
+
+ // ensure all parameters are valid
+ assert(prim.texture.palette != NULL);
+
+ // fast case: no coloring, no alpha
+ if (prim.color.r >= 1.0f && prim.color.g >= 1.0f && prim.color.b >= 1.0f && is_opaque(prim.color.a))
+ {
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_palette16a(prim.texture, curu, curv);
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 invta = 0x100 - ta;
+ UINT32 r = (source32_r(pix) * ta + dest_r(dpix) * invta) >> 8;
+ UINT32 g = (source32_g(pix) * ta + dest_g(dpix) * invta) >> 8;
+ UINT32 b = (source32_b(pix) * ta + dest_b(dpix) * invta) >> 8;
+
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+
+ // alpha and/or coloring case
+ else
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r);
+ UINT32 sg = UINT32(256.0f * prim.color.g);
+ UINT32 sb = UINT32(256.0f * prim.color.b);
+ UINT32 sa = UINT32(256.0f * prim.color.a);
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+ if (sa > 0x100) { if (INT32(sa) < 0) sa = 0; else sa = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_palette16a(prim.texture, curu, curv);
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 invsta = (0x10000 - ta) << 8;
+ UINT32 r = (source32_r(pix) * sr * ta + dest_r(dpix) * invsta) >> 24;
+ UINT32 g = (source32_g(pix) * sg * ta + dest_g(dpix) * invsta) >> 24;
+ UINT32 b = (source32_b(pix) * sb * ta + dest_b(dpix) * invsta) >> 24;
+
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+
+
+ //**************************************************************************
+ // 16-BIT YUY RASTERIZERS
+ //**************************************************************************
+
+ //-------------------------------------------------
+ // draw_quad_yuy16_none - perform
+ // rasterization of a 16bpp YUY image
+ //-------------------------------------------------
+
+ static void draw_quad_yuy16_none(const render_primitive &prim, _PixelType *dstdata, UINT32 pitch, quad_setup_data &setup)
+ {
+ const rgb_t *palbase = prim.texture.palette;
+ INT32 dudx = setup.dudx;
+ INT32 dvdx = setup.dvdx;
+ INT32 endx = setup.endx;
+
+ // fast case: no coloring, no alpha
+ if (prim.color.r >= 1.0f && prim.color.g >= 1.0f && prim.color.b >= 1.0f && is_opaque(prim.color.a))
+ {
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = ycc_to_rgb(get_texel_yuy16(prim.texture, curu, curv));
+ *dest++ = source32_to_dest(pix);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = ycc_to_rgb(get_texel_yuy16(prim.texture, curu, curv));
+ *dest++ = source32_to_dest(pix);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ // coloring-only case
+ else if (is_opaque(prim.color.a))
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r);
+ UINT32 sg = UINT32(256.0f * prim.color.g);
+ UINT32 sb = UINT32(256.0f * prim.color.b);
+
+ // clamp R,G,B to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = ycc_to_rgb(get_texel_yuy16(prim.texture, curu, curv));
+ UINT32 r = (source32_r(pix) * sr) >> 8;
+ UINT32 g = (source32_g(pix) * sg) >> 8;
+ UINT32 b = (source32_b(pix) * sb) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = ycc_to_rgb(get_texel_yuy16(prim.texture, curu, curv));
+ UINT32 r = (source32_r(pix) * sr) >> 8;
+ UINT32 g = (source32_g(pix) * sg) >> 8;
+ UINT32 b = (source32_b(pix) * sb) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ // alpha and/or coloring case
+ else if (!is_transparent(prim.color.a))
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r * prim.color.a);
+ UINT32 sg = UINT32(256.0f * prim.color.g * prim.color.a);
+ UINT32 sb = UINT32(256.0f * prim.color.b * prim.color.a);
+ UINT32 invsa = UINT32(256.0f * (1.0f - prim.color.a));
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+ if (invsa > 0x100) { if (INT32(invsa) < 0) invsa = 0; else invsa = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = ycc_to_rgb(get_texel_yuy16(prim.texture, curu, curv));
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = (source32_r(pix) * sr + dest_r(dpix) * invsa) >> 8;
+ UINT32 g = (source32_g(pix) * sg + dest_g(dpix) * invsa) >> 8;
+ UINT32 b = (source32_b(pix) * sb + dest_b(dpix) * invsa) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = ycc_to_rgb(get_texel_yuy16(prim.texture, curu, curv));
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = (source32_r(pix) * sr + dest_r(dpix) * invsa) >> 8;
+ UINT32 g = (source32_g(pix) * sg + dest_g(dpix) * invsa) >> 8;
+ UINT32 b = (source32_b(pix) * sb + dest_b(dpix) * invsa) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+ }
+
+
+ //**************************************************************************
+ // 32-BIT RGB QUAD RASTERIZERS
+ //**************************************************************************
+
+ //-------------------------------------------------
+ // draw_quad_rgb32 - perform rasterization of
+ // a 32bpp RGB texture
+ //-------------------------------------------------
+
+ static void draw_quad_rgb32(const render_primitive &prim, _PixelType *dstdata, UINT32 pitch, quad_setup_data &setup)
+ {
+ const rgb_t *palbase = prim.texture.palette;
+ INT32 dudx = setup.dudx;
+ INT32 dvdx = setup.dvdx;
+ INT32 endx = setup.endx;
+
+ // fast case: no coloring, no alpha
+ if (prim.color.r >= 1.0f && prim.color.g >= 1.0f && prim.color.b >= 1.0f && is_opaque(prim.color.a))
+ {
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_rgb32(prim.texture, curu, curv);
+ *dest++ = source32_to_dest(pix);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_rgb32(prim.texture, curu, curv);
+ UINT32 r = palbase[(pix >> 16) & 0xff] >> _SrcShiftR;
+ UINT32 g = palbase[(pix >> 8) & 0xff] >> _SrcShiftG;
+ UINT32 b = palbase[(pix >> 0) & 0xff] >> _SrcShiftB;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ // coloring-only case
+ else if (is_opaque(prim.color.a))
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r);
+ UINT32 sg = UINT32(256.0f * prim.color.g);
+ UINT32 sb = UINT32(256.0f * prim.color.b);
+
+ // clamp R,G,B to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_rgb32(prim.texture, curu, curv);
+ UINT32 r = (source32_r(pix) * sr) >> 8;
+ UINT32 g = (source32_g(pix) * sg) >> 8;
+ UINT32 b = (source32_b(pix) * sb) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_rgb32(prim.texture, curu, curv);
+ UINT32 r = (palbase[(pix >> 16) & 0xff] * sr) >> (8 + _SrcShiftR);
+ UINT32 g = (palbase[(pix >> 8) & 0xff] * sg) >> (8 + _SrcShiftG);
+ UINT32 b = (palbase[(pix >> 0) & 0xff] * sb) >> (8 + _SrcShiftB);
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ // alpha and/or coloring case
+ else if (!is_transparent(prim.color.a))
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r * prim.color.a);
+ UINT32 sg = UINT32(256.0f * prim.color.g * prim.color.a);
+ UINT32 sb = UINT32(256.0f * prim.color.b * prim.color.a);
+ UINT32 invsa = UINT32(256.0f * (1.0f - prim.color.a));
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+ if (invsa > 0x100) { if (INT32(invsa) < 0) invsa = 0; else invsa = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_rgb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = (source32_r(pix) * sr + dest_r(dpix) * invsa) >> 8;
+ UINT32 g = (source32_g(pix) * sg + dest_g(dpix) * invsa) >> 8;
+ UINT32 b = (source32_b(pix) * sb + dest_b(dpix) * invsa) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_rgb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] >> _SrcShiftR) * sr + dest_r(dpix) * invsa) >> 8;
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] >> _SrcShiftG) * sg + dest_g(dpix) * invsa) >> 8;
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] >> _SrcShiftB) * sb + dest_b(dpix) * invsa) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+ }
+
+
+ //-------------------------------------------------
+ // draw_quad_rgb32_add - perform
+ // rasterization by using RGB add
+ //-------------------------------------------------
+
+ static void draw_quad_rgb32_add(const render_primitive &prim, _PixelType *dstdata, UINT32 pitch, quad_setup_data &setup)
+ {
+ const rgb_t *palbase = prim.texture.palette;
+ INT32 dudx = setup.dudx;
+ INT32 dvdx = setup.dvdx;
+ INT32 endx = setup.endx;
+
+ // simply can't do this without reading from the dest
+ if (_NoDestRead)
+ return;
+
+ // fast case: no coloring, no alpha
+ if (prim.color.r >= 1.0f && prim.color.g >= 1.0f && prim.color.b >= 1.0f && is_opaque(prim.color.a))
+ {
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = source32_r(pix) + dest_r(dpix);
+ UINT32 g = source32_g(pix) + dest_g(dpix);
+ UINT32 b = source32_b(pix) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = (palbase[(pix >> 16) & 0xff] >> _SrcShiftR) + dest_r(dpix);
+ UINT32 g = (palbase[(pix >> 8) & 0xff] >> _SrcShiftG) + dest_g(dpix);
+ UINT32 b = (palbase[(pix >> 0) & 0xff] >> _SrcShiftB) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ // alpha and/or coloring case
+ else
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r);
+ UINT32 sg = UINT32(256.0f * prim.color.g);
+ UINT32 sb = UINT32(256.0f * prim.color.b);
+ UINT32 sa = UINT32(256.0f * prim.color.a);
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+ if (sa > 0x100) { if (INT32(sa) < 0) sa = 0; else sa = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = ((source32_r(pix) * sr * sa) >> 16) + dest_r(dpix);
+ UINT32 g = ((source32_g(pix) * sg * sa) >> 16) + dest_g(dpix);
+ UINT32 b = ((source32_b(pix) * sb * sa) >> 16) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] * sr * sa) >> (16 + _SrcShiftR)) + dest_r(dpix);
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] * sr * sa) >> (16 + _SrcShiftR)) + dest_g(dpix);
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] * sr * sa) >> (16 + _SrcShiftR)) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+ }
+
+
+
+ //**************************************************************************
+ // 32-BIT ARGB QUAD RASTERIZERS
+ //**************************************************************************
+
+ //-------------------------------------------------
+ // draw_quad_argb32_alpha - perform
+ // rasterization using standard alpha blending
+ //-------------------------------------------------
+
+ static void draw_quad_argb32_alpha(const render_primitive &prim, _PixelType *dstdata, UINT32 pitch, quad_setup_data &setup)
+ {
+ const rgb_t *palbase = prim.texture.palette;
+ INT32 dudx = setup.dudx;
+ INT32 dvdx = setup.dvdx;
+ INT32 endx = setup.endx;
+
+ // fast case: no coloring, no alpha
+ if (prim.color.r >= 1.0f && prim.color.g >= 1.0f && prim.color.b >= 1.0f && is_opaque(prim.color.a))
+ {
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 invta = 0x100 - ta;
+ UINT32 r = (source32_r(pix) * ta + dest_r(dpix) * invta) >> 8;
+ UINT32 g = (source32_g(pix) * ta + dest_g(dpix) * invta) >> 8;
+ UINT32 b = (source32_b(pix) * ta + dest_b(dpix) * invta) >> 8;
+
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 invta = 0x100 - ta;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] >> _SrcShiftR) * ta + dest_r(dpix) * invta) >> 8;
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] >> _SrcShiftG) * ta + dest_g(dpix) * invta) >> 8;
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] >> _SrcShiftB) * ta + dest_b(dpix) * invta) >> 8;
+
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ // alpha and/or coloring case
+ else
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r);
+ UINT32 sg = UINT32(256.0f * prim.color.g);
+ UINT32 sb = UINT32(256.0f * prim.color.b);
+ UINT32 sa = UINT32(256.0f * prim.color.a);
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+ if (sa > 0x100) { if (INT32(sa) < 0) sa = 0; else sa = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 invsta = (0x10000 - ta) << 8;
+ UINT32 r = (source32_r(pix) * sr * ta + dest_r(dpix) * invsta) >> 24;
+ UINT32 g = (source32_g(pix) * sg * ta + dest_g(dpix) * invsta) >> 24;
+ UINT32 b = (source32_b(pix) * sb * ta + dest_b(dpix) * invsta) >> 24;
+
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 invsta = (0x10000 - ta) << 8;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] >> _SrcShiftR) * sr * ta + dest_r(dpix) * invsta) >> 24;
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] >> _SrcShiftG) * sg * ta + dest_g(dpix) * invsta) >> 24;
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] >> _SrcShiftB) * sb * ta + dest_b(dpix) * invsta) >> 24;
+
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+ }
+
+
+ //-------------------------------------------------
+ // draw_quad_argb32_multiply - perform
+ // rasterization using RGB multiply
+ //-------------------------------------------------
+
+ static void draw_quad_argb32_multiply(const render_primitive &prim, _PixelType *dstdata, UINT32 pitch, quad_setup_data &setup)
+ {
+ const rgb_t *palbase = prim.texture.palette;
+ INT32 dudx = setup.dudx;
+ INT32 dvdx = setup.dvdx;
+ INT32 endx = setup.endx;
+
+ // simply can't do this without reading from the dest
+ if (_NoDestRead)
+ return;
+
+ // fast case: no coloring, no alpha
+ if (prim.color.r >= 1.0f && prim.color.g >= 1.0f && prim.color.b >= 1.0f && is_opaque(prim.color.a))
+ {
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = (source32_r(pix) * dest_r(dpix)) >> (8 - _SrcShiftR);
+ UINT32 g = (source32_g(pix) * dest_g(dpix)) >> (8 - _SrcShiftG);
+ UINT32 b = (source32_b(pix) * dest_b(dpix)) >> (8 - _SrcShiftB);
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = (palbase[(pix >> 16) & 0xff] * dest_r(dpix)) >> 8;
+ UINT32 g = (palbase[(pix >> 8) & 0xff] * dest_g(dpix)) >> 8;
+ UINT32 b = (palbase[(pix >> 0) & 0xff] * dest_b(dpix)) >> 8;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ // alpha and/or coloring case
+ else
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r * prim.color.a);
+ UINT32 sg = UINT32(256.0f * prim.color.g * prim.color.a);
+ UINT32 sb = UINT32(256.0f * prim.color.b * prim.color.a);
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = (source32_r(pix) * sr * dest_r(dpix)) >> (16 - _SrcShiftR);
+ UINT32 g = (source32_g(pix) * sg * dest_g(dpix)) >> (16 - _SrcShiftG);
+ UINT32 b = (source32_b(pix) * sb * dest_b(dpix)) >> (16 - _SrcShiftB);
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = (palbase[(pix >> 16) & 0xff] * sr * dest_r(dpix)) >> 16;
+ UINT32 g = (palbase[(pix >> 8) & 0xff] * sg * dest_g(dpix)) >> 16;
+ UINT32 b = (palbase[(pix >> 0) & 0xff] * sb * dest_b(dpix)) >> 16;
+
+ *dest++ = dest_assemble_rgb(r, g, b);
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+ }
+
+
+ //-------------------------------------------------
+ // draw_quad_argb32_add - perform
+ // rasterization by using RGB add
+ //-------------------------------------------------
+
+ static void draw_quad_argb32_add(const render_primitive &prim, _PixelType *dstdata, UINT32 pitch, quad_setup_data &setup)
+ {
+ const rgb_t *palbase = prim.texture.palette;
+ INT32 dudx = setup.dudx;
+ INT32 dvdx = setup.dvdx;
+ INT32 endx = setup.endx;
+
+ // simply can't do this without reading from the dest
+ if (_NoDestRead)
+ return;
+
+ // fast case: no coloring, no alpha
+ if (prim.color.r >= 1.0f && prim.color.g >= 1.0f && prim.color.b >= 1.0f && is_opaque(prim.color.a))
+ {
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = ((source32_r(pix) * ta) >> 8) + dest_r(dpix);
+ UINT32 g = ((source32_g(pix) * ta) >> 8) + dest_g(dpix);
+ UINT32 b = ((source32_b(pix) * ta) >> 8) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 ta = pix >> 24;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] * ta) >> (8 + _SrcShiftR)) + dest_r(dpix);
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] * ta) >> (8 + _SrcShiftG)) + dest_g(dpix);
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] * ta) >> (8 + _SrcShiftB)) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+
+ // alpha and/or coloring case
+ else
+ {
+ UINT32 sr = UINT32(256.0f * prim.color.r);
+ UINT32 sg = UINT32(256.0f * prim.color.g);
+ UINT32 sb = UINT32(256.0f * prim.color.b);
+ UINT32 sa = UINT32(256.0f * prim.color.a);
+
+ // clamp R,G,B and inverse A to 0-256 range
+ if (sr > 0x100) { if (INT32(sr) < 0) sr = 0; else sr = 0x100; }
+ if (sg > 0x100) { if (INT32(sg) < 0) sg = 0; else sg = 0x100; }
+ if (sb > 0x100) { if (INT32(sb) < 0) sb = 0; else sb = 0x100; }
+ if (sa > 0x100) { if (INT32(sa) < 0) sa = 0; else sa = 0x100; }
+
+ // loop over rows
+ for (INT32 y = setup.starty; y < setup.endy; y++)
+ {
+ _PixelType *dest = dstdata + y * pitch + setup.startx;
+ INT32 curu = setup.startu + (y - setup.starty) * setup.dudy;
+ INT32 curv = setup.startv + (y - setup.starty) * setup.dvdy;
+
+ // no lookup case
+ if (palbase == NULL)
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = ((source32_r(pix) * sr * ta) >> 24) + dest_r(dpix);
+ UINT32 g = ((source32_g(pix) * sg * ta) >> 24) + dest_g(dpix);
+ UINT32 b = ((source32_b(pix) * sb * ta) >> 24) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+
+ // lookup case
+ else
+ {
+ // loop over cols
+ for (INT32 x = setup.startx; x < endx; x++)
+ {
+ UINT32 pix = get_texel_argb32(prim.texture, curu, curv);
+ UINT32 ta = (pix >> 24) * sa;
+ if (ta != 0)
+ {
+ UINT32 dpix = _NoDestRead ? 0 : *dest;
+ UINT32 r = ((palbase[(pix >> 16) & 0xff] * sr * ta) >> (24 + _SrcShiftR)) + dest_r(dpix);
+ UINT32 g = ((palbase[(pix >> 8) & 0xff] * sr * ta) >> (24 + _SrcShiftR)) + dest_g(dpix);
+ UINT32 b = ((palbase[(pix >> 0) & 0xff] * sr * ta) >> (24 + _SrcShiftR)) + dest_b(dpix);
+ r = (r | -(r >> (8 - _SrcShiftR))) & (0xff >> _SrcShiftR);
+ g = (g | -(g >> (8 - _SrcShiftG))) & (0xff >> _SrcShiftG);
+ b = (b | -(b >> (8 - _SrcShiftB))) & (0xff >> _SrcShiftB);
+ *dest = dest_assemble_rgb(r, g, b);
+ }
+ dest++;
+ curu += dudx;
+ curv += dvdx;
+ }
+ }
+ }
+ }
+ }
+
+
+ //**************************************************************************
+ // CORE QUAD RASTERIZERS
+ //**************************************************************************
+
+ //-------------------------------------------------
+ // setup_and_draw_textured_quad - perform setup
+ // and then dispatch to a texture-mode-specific
+ // drawing routine
+ //-------------------------------------------------
+
+ static void setup_and_draw_textured_quad(const render_primitive &prim, _PixelType *dstdata, INT32 width, INT32 height, UINT32 pitch)
+ {
+ assert(prim.bounds.x0 <= prim.bounds.x1);
+ assert(prim.bounds.y0 <= prim.bounds.y1);
+
+ // determine U/V deltas
+ float fdudx = (prim.texcoords.tr.u - prim.texcoords.tl.u) / (prim.bounds.x1 - prim.bounds.x0);
+ float fdvdx = (prim.texcoords.tr.v - prim.texcoords.tl.v) / (prim.bounds.x1 - prim.bounds.x0);
+ float fdudy = (prim.texcoords.bl.u - prim.texcoords.tl.u) / (prim.bounds.y1 - prim.bounds.y0);
+ float fdvdy = (prim.texcoords.bl.v - prim.texcoords.tl.v) / (prim.bounds.y1 - prim.bounds.y0);
+
+ // clamp to integers
+ quad_setup_data setup;
+ setup.startx = round_nearest(prim.bounds.x0);
+ setup.starty = round_nearest(prim.bounds.y0);
+ setup.endx = round_nearest(prim.bounds.x1);
+ setup.endy = round_nearest(prim.bounds.y1);
+
+ // ensure we fit
+ if (setup.startx < 0) setup.startx = 0;
+ if (setup.startx >= width) setup.startx = width;
+ if (setup.endx < 0) setup.endx = 0;
+ if (setup.endx >= width) setup.endx = width;
+ if (setup.starty < 0) setup.starty = 0;
+ if (setup.starty >= height) setup.starty = height;
+ if (setup.endy < 0) setup.endy = 0;
+ if (setup.endy >= height) setup.endy = height;
+
+ // compute start and delta U,V coordinates now
+ setup.dudx = round_nearest(65536.0f * float(prim.texture.width) * fdudx);
+ setup.dvdx = round_nearest(65536.0f * float(prim.texture.height) * fdvdx);
+ setup.dudy = round_nearest(65536.0f * float(prim.texture.width) * fdudy);
+ setup.dvdy = round_nearest(65536.0f * float(prim.texture.height) * fdvdy);
+ setup.startu = round_nearest(65536.0f * float(prim.texture.width) * prim.texcoords.tl.u);
+ setup.startv = round_nearest(65536.0f * float(prim.texture.height) * prim.texcoords.tl.v);
+
+ // advance U/V to the middle of the first texel
+ setup.startu += (setup.dudx + setup.dudy) / 2;
+ setup.startv += (setup.dvdx + setup.dvdy) / 2;
+
+ // if we're bilinear filtering, we need to offset u/v by half a texel
+ if (_BilinearFilter)
+ {
+ setup.startu -= 0x8000;
+ setup.startv -= 0x8000;
+ }
+
+ // render based on the texture coordinates
+ switch (prim.flags & (PRIMFLAG_TEXFORMAT_MASK | PRIMFLAG_BLENDMODE_MASK))
+ {
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE):
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA):
+ draw_quad_palette16_none(prim, dstdata, pitch, setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD):
+ draw_quad_palette16_add(prim, dstdata, pitch, setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTEA16) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA):
+ draw_quad_palettea16_alpha(prim, dstdata, pitch, setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_YUY16) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE):
+ draw_quad_yuy16_none(prim, dstdata, pitch, setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE):
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA):
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE):
+ draw_quad_rgb32(prim, dstdata, pitch, setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD):
+ draw_quad_rgb32_add(prim, dstdata, pitch, setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA):
+ draw_quad_argb32_alpha(prim, dstdata, pitch, setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_RGB_MULTIPLY):
+ draw_quad_argb32_multiply(prim, dstdata, pitch, setup);
+ break;
+
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD):
+ draw_quad_argb32_add(prim, dstdata, pitch, setup);
+ break;
+
+ default:
+ fatalerror("Unknown texformat(%d)/blendmode(%d) combo\n", PRIMFLAG_GET_TEXFORMAT(prim.flags), PRIMFLAG_GET_BLENDMODE(prim.flags));
+ break;
+ }
+ }
+
+
+ //**************************************************************************
+ // PRIMARY ENTRY POINT
+ //**************************************************************************
+
+ //-------------------------------------------------
+ // draw_primitives - draw a series of primitives
+ // using a software rasterizer
+ //-------------------------------------------------
+
+public:
+ static void draw_primitives(const render_primitive_list &primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch)
+ {
+ // loop over the list and render each element
+ for (const render_primitive *prim = primlist.first(); prim != NULL; prim = prim->next())
+ switch (prim->type)
+ {
+ case render_primitive::LINE:
+ draw_line(*prim, reinterpret_cast<_PixelType *>(dstdata), width, height, pitch);
+ break;
+
+ case render_primitive::QUAD:
+ if (!prim->texture.base)
+ draw_rect(*prim, reinterpret_cast<_PixelType *>(dstdata), width, height, pitch);
+ else
+ setup_and_draw_textured_quad(*prim, reinterpret_cast<_PixelType *>(dstdata), width, height, pitch);
+ break;
+
+ default:
+ throw emu_fatalerror("Unexpected render_primitive type");
+ }
+ }
+};