/*------------------------------------------------- * set_render_color - cleaner way to set a color * -------------------------------------------------*/ public static void set_render_color(render_color color, float a, float r, float g, float b) { color.a = a; color.r = r; color.g = g; color.b = b; }
/*------------------------------------------------- * resample_argb_bitmap_bilinear - perform texture * sampling via a bilinear filter * -------------------------------------------------*/ static void resample_argb_bitmap_bilinear(PointerU32 dest, u32 drowpixels, u32 dwidth, u32 dheight, PointerU32 source, u32 srowpixels, u32 swidth, u32 sheight, render_color color, u32 dx, u32 dy) //static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) { u32 maxx = swidth << 12; u32 maxy = sheight << 12; u32 r; u32 g; u32 b; u32 a; u32 x; u32 y; /* precompute premultiplied R/G/B/A factors */ r = (u32)(color.r * color.a * 256.0f); g = (u32)(color.g * color.a * 256.0f); b = (u32)(color.b * color.a * 256.0f); a = (u32)(color.a * 256.0f); /* loop over the target vertically */ for (y = 0; y < dheight; y++) { u32 starty = y * dy; /* loop over the target horizontally */ for (x = 0; x < dwidth; x++) { u32 startx = x * dx; rgb_t pix0; rgb_t pix1; rgb_t pix2; rgb_t pix3; u32 sumr; u32 sumg; u32 sumb; u32 suma; u32 nextx; u32 nexty; u32 curx; u32 cury; u32 factor; /* adjust start to the center; note that this math will tend to produce */ /* negative results on the first pixel, which is why we clamp below */ curx = startx + dx / 2 - 0x800; cury = starty + dy / 2 - 0x800; /* compute the neighboring pixel */ nextx = curx + 0x1000; nexty = cury + 0x1000; /* fetch the four relevant pixels */ pix0 = pix1 = pix2 = pix3 = new rgb_t(0); if ((int)cury >= 0 && cury < maxy && (int)curx >= 0 && curx < maxx) { pix0 = new rgb_t(source[(cury >> 12) * srowpixels + (curx >> 12)]); //pix0 = source[(cury >> 12) * srowpixels + (curx >> 12)]; } if ((int)cury >= 0 && cury < maxy && (int)nextx >= 0 && nextx < maxx) { pix1 = new rgb_t(source[(cury >> 12) * srowpixels + (nextx >> 12)]); //pix1 = source[(cury >> 12) * srowpixels + (nextx >> 12)]; } if ((int)nexty >= 0 && nexty < maxy && (int)curx >= 0 && curx < maxx) { pix2 = new rgb_t(source[(nexty >> 12) * srowpixels + (curx >> 12)]); //pix2 = source[(nexty >> 12) * srowpixels + (curx >> 12)]; } if ((int)nexty >= 0 && nexty < maxy && (int)nextx >= 0 && nextx < maxx) { pix3 = new rgb_t(source[(nexty >> 12) * srowpixels + (nextx >> 12)]); //pix3 = source[(nexty >> 12) * srowpixels + (nextx >> 12)]; } /* compute the x/y scaling factors */ curx &= 0xfff; cury &= 0xfff; /* contributions from pixel 0 (top,left) */ factor = (0x1000 - curx) * (0x1000 - cury); sumr = factor * pix0.r(); sumg = factor * pix0.g(); sumb = factor * pix0.b(); suma = factor * pix0.a(); /* contributions from pixel 1 (top,right) */ factor = curx * (0x1000 - cury); sumr += factor * pix1.r(); sumg += factor * pix1.g(); sumb += factor * pix1.b(); suma += factor * pix1.a(); /* contributions from pixel 2 (bottom,left) */ factor = (0x1000 - curx) * cury; sumr += factor * pix2.r(); sumg += factor * pix2.g(); sumb += factor * pix2.b(); suma += factor * pix2.a(); /* contributions from pixel 3 (bottom,right) */ factor = curx * cury; sumr += factor * pix3.r(); sumg += factor * pix3.g(); sumb += factor * pix3.b(); suma += factor * pix3.a(); /* apply scaling */ suma = (suma >> 24) * a / 256; sumr = (sumr >> 24) * r / 256; sumg = (sumg >> 24) * g / 256; sumb = (sumb >> 24) * b / 256; /* if we're translucent, add in the destination pixel contribution */ if (a < 256) { rgb_t dpix = new rgb_t(dest[y * drowpixels + x]); //rgb_t dpix = dest[y * drowpixels + x]; suma += dpix.a() * (256 - a); sumr += dpix.r() * (256 - a); sumg += dpix.g() * (256 - a); sumb += dpix.b() * (256 - a); } /* store the target pixel, dividing the RGBA values by the overall scale factor */ dest[y * drowpixels + x] = new rgb_t((u8)suma, (u8)sumr, (u8)sumg, (u8)sumb); //dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb); } } }
/*------------------------------------------------- * resample_argb_bitmap_average - resample a texture * by performing a true weighted average over * all contributing pixels * -------------------------------------------------*/ static void resample_argb_bitmap_average(PointerU32 dest, u32 drowpixels, u32 dwidth, u32 dheight, PointerU32 source, u32 srowpixels, u32 swidth, u32 sheight, render_color color, u32 dx, u32 dy) //static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) { u64 sumscale = (u64)dx * (u64)dy; u32 r; u32 g; u32 b; u32 a; u32 x; u32 y; /* precompute premultiplied R/G/B/A factors */ r = (u32)(color.r * color.a * 256.0f); g = (u32)(color.g * color.a * 256.0f); b = (u32)(color.b * color.a * 256.0f); a = (u32)(color.a * 256.0f); /* loop over the target vertically */ for (y = 0; y < dheight; y++) { u32 starty = y * dy; /* loop over the target horizontally */ for (x = 0; x < dwidth; x++) { u64 sumr = 0; u64 sumg = 0; u64 sumb = 0; u64 suma = 0; u32 startx = x * dx; u32 xchunk; u32 ychunk; u32 curx; u32 cury; u32 yremaining = dy; /* accumulate all source pixels that contribute to this pixel */ for (cury = starty; yremaining != 0; cury += ychunk) { u32 xremaining = dx; /* determine the Y contribution, clamping to the amount remaining */ ychunk = 0x1000 - (cury & 0xfff); if (ychunk > yremaining) { ychunk = yremaining; } yremaining -= ychunk; /* loop over all source pixels in the X direction */ for (curx = startx; xremaining != 0; curx += xchunk) { u32 factor; /* determine the X contribution, clamping to the amount remaining */ xchunk = 0x1000 - (curx & 0xfff); if (xchunk > xremaining) { xchunk = xremaining; } xremaining -= xchunk; /* total contribution = x * y */ factor = xchunk * ychunk; /* fetch the source pixel */ rgb_t pix = new rgb_t(source[(cury >> 12) * srowpixels + (curx >> 12)]); //rgb_t pix = source[(cury >> 12) * srowpixels + (curx >> 12)]; /* accumulate the RGBA values */ sumr += factor * pix.r(); sumg += factor * pix.g(); sumb += factor * pix.b(); suma += factor * pix.a(); } } /* apply scaling */ suma = (suma / sumscale) * a / 256; sumr = (sumr / sumscale) * r / 256; sumg = (sumg / sumscale) * g / 256; sumb = (sumb / sumscale) * b / 256; /* if we're translucent, add in the destination pixel contribution */ if (a < 256) { rgb_t dpix = new rgb_t(dest[y * drowpixels + x]); //rgb_t dpix = dest[y * drowpixels + x]; suma += dpix.a() * (256 - a); sumr += dpix.r() * (256 - a); sumg += dpix.g() * (256 - a); sumb += dpix.b() * (256 - a); } /* store the target pixel, dividing the RGBA values by the overall scale factor */ dest[y * drowpixels + x] = new rgb_t((u8)suma, (u8)sumr, (u8)sumg, (u8)sumb); //dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb); } } }
/* ----- render utilities ----- */ /*------------------------------------------------- * render_resample_argb_bitmap_hq - perform a high * quality resampling of a texture * -------------------------------------------------*/ public static void render_resample_argb_bitmap_hq(bitmap_argb32 dest, bitmap_argb32 source, render_color color, bool force = false) { if (dest.width() == 0 || dest.height() == 0) { return; } /* adjust the source base */ PointerU32 sbase = source.pix(0); //const u32 *sbase = &source.pix(0); /* determine the steppings */ u32 swidth = (u32)source.width(); u32 sheight = (u32)source.height(); u32 dwidth = (u32)dest.width(); u32 dheight = (u32)dest.height(); u32 dx = (swidth << 12) / dwidth; u32 dy = (sheight << 12) / dheight; /* if the source is higher res than the target, use full averaging */ if (dx > 0x1000 || dy > 0x1000 || force) { resample_argb_bitmap_average(dest.pix(0), (u32)dest.rowpixels(), dwidth, dheight, sbase, (u32)source.rowpixels(), swidth, sheight, color, dx, dy); } else { resample_argb_bitmap_bilinear(dest.pix(0), (u32)dest.rowpixels(), dwidth, dheight, sbase, (u32)source.rowpixels(), swidth, sheight, color, dx, dy); } }
public float b; // blue component (0.0 = none, 1.0 = max) public render_color(render_color other) { this.a = other.a; this.r = other.r; this.g = other.g; this.b = other.b; }
/* ----- render utilities ----- */ /*------------------------------------------------- * render_resample_argb_bitmap_hq - perform a high * quality resampling of a texture * -------------------------------------------------*/ public static void render_resample_argb_bitmap_hq(bitmap_argb32 dest, bitmap_argb32 source, render_color color, bool force = false) { if (dest.width() == 0 || dest.height() == 0) { return; } /* adjust the source base */ //const UINT32 *sbase = &source.pix32(0); RawBuffer sbaseBuf; u32 sbaseOffset = source.pix32(out sbaseBuf, 0); /* determine the steppings */ u32 swidth = (u32)source.width(); u32 sheight = (u32)source.height(); u32 dwidth = (u32)dest.width(); u32 dheight = (u32)dest.height(); u32 dx = (swidth << 12) / dwidth; u32 dy = (sheight << 12) / dheight; //throw new emu_unimplemented(); /* if the source is higher res than the target, use full averaging */ if (dx > 0x1000 || dy > 0x1000 || force) { RawBuffer destBuf; u32 destOffset = dest.pix32(out destBuf, 0); resample_argb_bitmap_average(new RawBufferPointer(destBuf, (int)destOffset), (UInt32)dest.rowpixels(), dwidth, dheight, new RawBufferPointer(sbaseBuf, (int)sbaseOffset), (UInt32)source.rowpixels(), swidth, sheight, color, dx, dy); } else { RawBuffer destBuf; u32 destOffset = dest.pix32(out destBuf, 0); resample_argb_bitmap_bilinear(new RawBufferPointer(destBuf, (int)destOffset), (UInt32)dest.rowpixels(), dwidth, dheight, new RawBufferPointer(sbaseBuf, (int)sbaseOffset), (UInt32)source.rowpixels(), swidth, sheight, color, dx, dy); } }