/*************************************************************************** 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 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(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(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(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(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(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(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(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(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(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(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"); } } };