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