Files
lime/project/include/renderer/common/SimpleSurface.h
2013-11-27 18:05:59 -08:00

284 lines
7.7 KiB
C++

#ifndef RENDERER_SIMPLE_SURFACE_H
#define RENDERER_SIMPLE_SURFACE_H
#include "renderer/common/Surface.h"
namespace lime {
class SimpleSurface : public Surface {
public:
SimpleSurface (int inWidth, int inHeight, PixelFormat inPixelFormat, int inByteAlign = 4, int inGPUPixelFormat = -1);
virtual void BlitChannel (const RenderTarget &outTarget, const Rect &inSrcRect, int inPosX, int inPosY, int inSrcChannel, int inDestChannel) const;
virtual void BlitTo (const RenderTarget &outTarget, const Rect &inSrcRect,int inPosX, int inPosY, BlendMode inBlend, const BitmapCache *inMask, uint32 inTint = 0xffffff) const;
virtual void colorTransform (const Rect &inRect, ColorTransform &inTransform);
virtual void StretchTo (const RenderTarget &outTarget, const Rect &inSrcRect, const DRect &inDestRect) const;
virtual void setAlphaMode (AlphaMode am) { mAlphaMode = am; }
virtual void setGPUFormat (PixelFormat pf) { mGPUPixelFormat = pf; }
void applyFilter (Surface *inSrc, const Rect &inRect, ImagePoint inOffset, Filter *inFilter);
RenderTarget BeginRender (const Rect &inRect, bool inForHitTest);
void Clear (uint32 inColour, const Rect *inRect);
Surface *clone ();
void createHardwareSurface ();
void destroyHardwareSurface ();
void dispose ();
void dumpBits ();
void EndRender ();
void getColorBoundsRect(int inMask, int inCol, bool inFind, Rect &outRect);
uint32 getPixel (int inX, int inY);
void getPixels (const Rect &inRect, uint32 *outPixels, bool inIgnoreOrder = false, bool inLittleEndian = false);
void multiplyAlpha ();
void noise (unsigned int randomSeed, unsigned int low, unsigned int high, int channelOptions, bool grayScale);
void scroll (int inDX, int inDY);
void setPixel (int inX, int inY, uint32 inRGBA, bool inAlphaToo = false);
void setPixels (const Rect &inRect, const uint32 *intPixels, bool inIgnoreOrder = false, bool inLittleEndian = false);
void unmultiplyAlpha ();
void Zero ();
PixelFormat Format () const { return mPixelFormat; }
AlphaMode GetAlphaMode () const { return mAlphaMode; }
const uint8 *GetBase () const { return mBase; }
int GetStride () const { return mStride; }
int GPUFormat () const { return mGPUPixelFormat; }
int Height () const { return mHeight; }
int Width () const { return mWidth; }
protected:
~SimpleSurface ();
AlphaMode mAlphaMode;
uint8 *mBase;
int mGPUPixelFormat;
int mHeight;
PixelFormat mPixelFormat;
int mStride;
int mWidth;
private:
SimpleSurface (const SimpleSurface &inRHS);
void operator = (const SimpleSurface &inRHS);
};
enum {
CHAN_ALPHA = 0x0008,
CHAN_BLUE = 0x0004,
CHAN_GREEN = 0x0002,
CHAN_RED = 0x0001
};
template<bool SWAP, bool SRC_ALPHA, bool DEST_ALPHA>
void TStretchTo (const SimpleSurface *inSrc, const RenderTarget &outTarget, const Rect &inSrcRect, const DRect &inDestRect) {
Rect irect (inDestRect.x + 0.5, inDestRect.y + 0.5, inDestRect.x1 () + 0.5, inDestRect.y1 () + 0.5, true);
Rect out = irect.Intersect (outTarget.mRect);
if (!out.Area ())
return;
int dsx_dx = (inSrcRect.w << 16) / inDestRect.w;
int dsy_dy = (inSrcRect.h << 16) / inDestRect.h;
#ifndef STRETCH_BILINEAR
// (Dx - inDestRect.x) * dsx_dx = ( Sx- inSrcRect.x )
// Start first sample at out.x+0.5, and subtract 0.5 so src(1) is between first and second pixel
//
// Sx = (out.x+0.5-inDestRect.x)*dsx_dx + inSrcRect.x - 0.5
//int sx0 = (int)((out.x-inDestRect.x*inSrcRect.w/inDestRect.w)*65536) +(inSrcRect.x<<16);
//int sy0 = (int)((out.y-inDestRect.y*inSrcRect.h/inDestRect.h)*65536) +(inSrcRect.y<<16);
int sx0 = (int)((out.x + 0.5 - inDestRect.x) * dsx_dx + (inSrcRect.x << 16));
int sy0 = (int)((out.y + 0.5 - inDestRect.y) * dsy_dy + (inSrcRect.y << 16));
for (int y = 0; y < out.h; y++) {
ARGB *dest = (ARGB *)outTarget.Row (y + out.y) + out.x;
int y_ = (sy0 >> 16);
const ARGB *src = (const ARGB *)inSrc->Row (y_);
sy0 += dsy_dy;
int sx = sx0;
for (int x = 0; x < out.w; x++) {
ARGB s (src[sx >> 16]);
sx += dsx_dx;
if (SWAP) s.SwapRB ();
if (!SRC_ALPHA) {
if (DEST_ALPHA)
s.a = 255;
*dest++ = s;
} else {
if (!s.a)
dest++;
else if (s.a == 255)
*dest++ = s;
else if (DEST_ALPHA)
dest++->QBlendA (s);
else
dest++->QBlend (s);
}
}
}
#else
// todo - overflow testing
// (Dx - inDestRect.x) * dsx_dx = ( Sx- inSrcRect.x )
// Start first sample at out.x+0.5, and subtract 0.5 so src(1) is between first and second pixel
//
// Sx = (out.x+0.5-inDestRect.x)*dsx_dx + inSrcRect.x - 0.5
int sx0 = (((((out.x - inDestRect.x) << 8) + 0x80) * (inSrcRect.w / inDestRect.w)) << 8) + (inSrcRect.x << 16) - 0x8000;
int sy0 = (((((out.y - inDestRect.y) << 8) + 0x80) * (inSrcRect.h / inDestRect.h)) << 8) + (inSrcRect.y << 16) - 0x8000;
int last_y = inSrcRect.y1 () - 1;
ARGB s;
s.a = 255;
for (int y = 0; y < out.h; y++) {
ARGB *dest = (ARGB *)outTarget.Row (y + out.y) + out.x;
int y_ = (sy0 >> 16);
int y_frac = sy0 & 0xffff;
const ARGB *src0 = (const ARGB *)inSrc->Row (y_);
const ARGB *src1 = (const ARGB *)inSrc->Row (y_ < last_y ? y_ + 1 : y_);
sy0 += dsy_dy;
int sx = sx0;
for (int x = 0; x < out.w; x++) {
int x_ = sx >> 16;
int x_frac = sx & 0xffff;
ARGB s00 (src0[x_]);
ARGB s01 (src0[x_ + 1]);
ARGB s10 (src1[x_]);
ARGB s11 (src1[x_ + 1]);
int c0_0 = s00.c0 + (((s01.c0 - s00.c0) * x_frac) >> 16);
int c0_1 = s10.c0 + (((s11.c0 - s10.c0) * x_frac) >> 16);
s.c0 = c0_0 + (((c0_1 - c0_0) * y_frac) >> 16);
int c1_0 = s00.c1 + (((s01.c1 - s00.c1) * x_frac) >> 16);
int c1_1 = s10.c1 + (((s11.c1 - s10.c1) * x_frac) >> 16);
s.c1 = c1_0 + (((c1_1 - c1_0) * y_frac) >> 16);
int c2_0 = s00.c2 + (((s01.c2 - s00.c2) * x_frac) >> 16);
int c2_1 = s10.c2 + (((s11.c2 - s10.c2) * x_frac) >> 16);
s.c2 = c2_0 + (((c2_1 - c2_0) * y_frac) >> 16);
sx += dsx_dx;
if (SWAP) s.SwapRB ();
if (!SRC_ALPHA) {
*dest++ = s;
} else {
int a_x0 = s00.a + (((s01.a - s00.a) * x_frac) >> 16);
int a_x1 = s10.a + (((s11.a - s10.a) * x_frac) >> 16);
s.a = a_x0 + (((a_x1 - a_x0) * y_frac) >> 16);
if (!s.a)
dest++;
else if (s.a == 255)
*dest++ = s;
else if (DEST_ALPHA)
dest++->QBlendA (s);
else
dest++->QBlend (s);
}
}
}
#endif
}
/* A MINSTD pseudo-random number generator.
*
* This generates a pseudo-random number sequence equivalent to std::minstd_rand0 from the C++11 standard library, which
* is the generator that Flash uses to generate noise for BitmapData.noise().
*
* It is reimplemented here because std::minstd_rand0 is not available in earlier versions of C++.
*
* MINSTD was originally suggested in "A pseudo-random number generator for the System/360", P.A. Lewis, A.S. Goodman,
* J.M. Miller, IBM Systems Journal, Vol. 8, No. 2, 1969, pp. 136-146 */
class MinstdGenerator {
public:
MinstdGenerator (unsigned int seed) {
if (seed == 0) {
x = 1U;
} else {
x = seed;
}
}
unsigned int operator () () {
const unsigned int a = 16807U;
const unsigned int m = (1U << 31) - 1;
unsigned int lo = a * (x & 0xffffU);
unsigned int hi = a * (x >> 16);
lo += (hi & 0x7fffU) << 16;
if (lo > m) {
lo &= m;
++lo;
}
lo += hi >> 15;
if (lo > m) {
lo &= m;
++lo;
}
x = lo;
return x;
}
private:
unsigned int x;
};
}
#endif