summaryrefslogtreecommitdiff
path: root/osframework/source/SexyAppFramework/MemoryImage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'osframework/source/SexyAppFramework/MemoryImage.cpp')
-rw-r--r--osframework/source/SexyAppFramework/MemoryImage.cpp1918
1 files changed, 1918 insertions, 0 deletions
diff --git a/osframework/source/SexyAppFramework/MemoryImage.cpp b/osframework/source/SexyAppFramework/MemoryImage.cpp
new file mode 100644
index 0000000..fcf8258
--- /dev/null
+++ b/osframework/source/SexyAppFramework/MemoryImage.cpp
@@ -0,0 +1,1918 @@
+#include "MemoryImage.h"
+
+#include "SexyAppBase.h"
+#include "Graphics.h"
+#include "NativeDisplay.h"
+#include "Debug.h"
+#include "Quantize.h"
+#include "PerfTimer.h"
+#include "SWTri.h"
+
+#include <math.h>
+
+using namespace Sexy;
+
+#ifdef OPTIMIZE_SOFTWARE_DRAWING
+bool gOptimizeSoftwareDrawing = false;
+#endif
+
+
+// Disable macro redefinition warning
+#pragma warning(disable:4005)
+
+MemoryImage::MemoryImage()
+{
+ mApp = gSexyAppBase;
+
+ Init();
+}
+
+MemoryImage::MemoryImage(SexyAppBase* theApp)
+{
+ mApp = theApp;
+ Init();
+}
+
+MemoryImage::MemoryImage(const MemoryImage& theMemoryImage) :
+ Image(theMemoryImage),
+ mApp(theMemoryImage.mApp),
+ mHasAlpha(theMemoryImage.mHasAlpha),
+ mHasTrans(theMemoryImage.mHasTrans),
+ mBitsChanged(theMemoryImage.mBitsChanged),
+ mIsVolatile(theMemoryImage.mIsVolatile),
+ mPurgeBits(theMemoryImage.mPurgeBits),
+ mWantPal(theMemoryImage.mWantPal),
+ mD3DFlags(theMemoryImage.mD3DFlags),
+ mBitsChangedCount(theMemoryImage.mBitsChangedCount),
+ mD3DData(NULL)
+{
+ bool deleteBits = false;
+
+ MemoryImage* aNonConstMemoryImage = (MemoryImage*) &theMemoryImage;
+
+ if ((theMemoryImage.mBits == NULL) && (theMemoryImage.mColorTable == NULL))
+ {
+ // Must be a DDImage with only a DDSurface
+ aNonConstMemoryImage->GetBits();
+ deleteBits = true;
+ }
+
+ if (theMemoryImage.mBits != NULL)
+ {
+ mBits = new ulong[mWidth*mHeight + 1];
+ mBits[mWidth*mHeight] = MEMORYCHECK_ID;
+ memcpy(mBits, theMemoryImage.mBits, (mWidth*mHeight + 1)*sizeof(ulong));
+ }
+ else
+ mBits = NULL;
+
+ if (deleteBits)
+ {
+ // Remove the temporary source bits
+ delete [] aNonConstMemoryImage->mBits;
+ aNonConstMemoryImage->mBits = NULL;
+ }
+
+ if (theMemoryImage.mColorTable != NULL)
+ {
+ mColorTable = new ulong[256];
+ memcpy(mColorTable, theMemoryImage.mColorTable, 256*sizeof(ulong));
+ }
+ else
+ mColorTable = NULL;
+
+ if (theMemoryImage.mColorIndices != NULL)
+ {
+ mColorIndices = new uchar[mWidth*mHeight];
+ memcpy(mColorIndices, theMemoryImage.mColorIndices, mWidth*mHeight*sizeof(uchar));
+ }
+ else
+ mColorIndices = NULL;
+
+ if (theMemoryImage.mNativeAlphaData != NULL)
+ {
+ if (theMemoryImage.mColorTable == NULL)
+ {
+ mNativeAlphaData = new ulong[mWidth*mHeight];
+ memcpy(mNativeAlphaData, theMemoryImage.mNativeAlphaData, mWidth*mHeight*sizeof(ulong));
+ }
+ else
+ {
+ mNativeAlphaData = new ulong[256];
+ memcpy(mNativeAlphaData, theMemoryImage.mNativeAlphaData, 256*sizeof(ulong));
+ }
+ }
+ else
+ mNativeAlphaData = NULL;
+
+ if (theMemoryImage.mRLAlphaData != NULL)
+ {
+ mRLAlphaData = new uchar[mWidth*mHeight];
+ memcpy(mRLAlphaData, theMemoryImage.mRLAlphaData, mWidth*mHeight);
+ }
+ else
+ mRLAlphaData = NULL;
+
+ if (theMemoryImage.mRLAdditiveData != NULL)
+ {
+ mRLAdditiveData = new uchar[mWidth*mHeight];
+ memcpy(mRLAdditiveData, theMemoryImage.mRLAdditiveData, mWidth*mHeight);
+ }
+ else
+ mRLAdditiveData = NULL;
+
+ mApp->AddMemoryImage(this);
+}
+
+MemoryImage::~MemoryImage()
+{
+ mApp->RemoveMemoryImage(this);
+
+ delete [] mBits;
+ delete [] mNativeAlphaData;
+ delete [] mRLAlphaData;
+ delete [] mRLAdditiveData;
+ delete [] mColorIndices;
+ delete [] mColorTable;
+}
+
+void MemoryImage::Init()
+{
+ mBits = NULL;
+ mColorTable = NULL;
+ mColorIndices = NULL;
+
+ mNativeAlphaData = NULL;
+ mRLAlphaData = NULL;
+ mRLAdditiveData = NULL;
+ mHasTrans = false;
+ mHasAlpha = false;
+ mBitsChanged = false;
+ mForcedMode = false;
+ mIsVolatile = false;
+
+ mD3DData = NULL;
+ mD3DFlags = 0;
+ mBitsChangedCount = 0;
+
+ mPurgeBits = false;
+ mWantPal = false;
+
+ mApp->AddMemoryImage(this);
+}
+
+void MemoryImage::BitsChanged()
+{
+ mBitsChanged = true;
+ mBitsChangedCount++;
+
+ delete [] mNativeAlphaData;
+ mNativeAlphaData = NULL;
+
+ delete [] mRLAlphaData;
+ mRLAlphaData = NULL;
+
+ delete [] mRLAdditiveData;
+ mRLAdditiveData = NULL;
+
+ // Verify secret value at end to protect against overwrite
+ if (mBits != NULL)
+ {
+ DBG_ASSERTE(mBits[mWidth*mHeight] == MEMORYCHECK_ID);
+ }
+}
+
+void MemoryImage::NormalDrawLine(double theStartX, double theStartY, double theEndX, double theEndY, const Color& theColor)
+{
+ double aMinX = min(theStartX, theEndX);
+ double aMinY = min(theStartY, theEndY);
+ double aMaxX = max(theStartX, theEndX);
+ double aMaxY = max(theStartY, theEndY);
+
+ ulong aRMask = 0xFF0000;
+ ulong aGMask = 0x00FF00;
+ ulong aBMask = 0x0000FF;
+ ulong aRRoundAdd = aRMask >> 1;
+ ulong aGRoundAdd = aGMask >> 1;
+ ulong aBRoundAdd = aBMask >> 1;
+
+ DWORD *aSurface = GetBits();
+
+ if (true)//(mLockedSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 32)
+ {
+ if (theColor.mAlpha == 255)
+ {
+ ulong aColor = 0xFF000000 |
+ ((((theColor.mRed * aRMask) + aRRoundAdd) >> 8) & aRMask) |
+ ((((theColor.mGreen * aGMask) + aGRoundAdd) >> 8) & aGMask) |
+ ((((theColor.mBlue * aBMask) + aBRoundAdd) >> 8) & aBMask);
+
+ double dv = theEndY - theStartY;
+ double dh = theEndX - theStartX;
+ int minG, maxG, G, DeltaG1, DeltaG2;
+ double swap;
+ int inc = 1;
+ int aCurX;
+ int aCurY;
+ int aRowWidth = mWidth;
+ int aRowAdd = aRowWidth;;
+
+ if (abs(dv) < abs(dh))
+ {
+ // Mostly horizontal
+ if (dh < 0)
+ {
+ dh = -dh;
+ dv = -dv;
+ swap = theEndY;
+ theEndY = theStartY;
+ theStartY = swap;
+ swap = theEndX;
+ theEndX = theStartX;
+ theStartX = swap;
+ }
+ if (dv < 0)
+ {
+ dv = -dv;
+ inc = -1;
+ aRowAdd = -aRowAdd;
+ }
+
+ ulong* aDestPixels = ((ulong*) aSurface) + ((int) theStartY * aRowWidth) + (int) theStartX;
+ *aDestPixels = aColor;
+ aDestPixels++;
+
+ aCurY = theStartY;
+ aCurX = theStartX + 1;
+
+ G = 2 * dv - dh;
+ DeltaG1 = 2 * (dv - dh);
+ DeltaG2 = 2 * dv;
+
+ G += DeltaG2 * (theStartY - (int) theStartY);
+
+ while (aCurX <= theEndX)
+ {
+ if (G > 0)
+ {
+ G += DeltaG1;
+ aCurY += inc;
+ aDestPixels += aRowAdd;
+
+ if (aCurX<aMinX || aCurY<aMinY || aCurX>aMaxX || aCurY>aMaxY)
+ break;
+ }
+ else
+ G += DeltaG2;
+
+ *aDestPixels = aColor;
+
+ aCurX++;
+ aDestPixels++;
+ }
+ }
+ else
+ {
+ // Mostly vertical
+ if ( dv < 0 )
+ {
+ dh = -dh;
+ dv = -dv;
+ swap = theEndY;
+ theEndY = theStartY;
+ theStartY = swap;
+ swap = theEndX;
+ theEndX = theStartX;
+ theStartX = swap;
+ }
+
+ if (dh < 0)
+ {
+ dh = -dh;
+ inc = -1;
+ }
+
+ ulong* aDestPixels = ((ulong*) aSurface) + ((int) theStartY * aRowWidth) + (int) theStartX;
+ *aDestPixels = aColor;
+ aDestPixels += aRowAdd;
+
+ aCurX = theStartX;
+ aCurY = theStartY + 1;
+
+ G = 2 * dh - dv;
+ minG = maxG = G;
+ DeltaG1 = 2 * ( dh - dv );
+ DeltaG2 = 2 * dh;
+
+ G += DeltaG2 * (theStartX - (int) theStartX);
+
+ while (aCurY <= theEndY)
+ {
+ if ( G > 0 )
+ {
+ G += DeltaG1;
+ aCurX += inc;
+ aDestPixels += inc;
+
+ if (aCurX<aMinX || aCurY<aMinY || aCurX>aMaxX || aCurY>aMaxY)
+ break;
+ }
+ else
+ G += DeltaG2;
+
+ *aDestPixels = aColor;
+
+ aCurY++;
+ aDestPixels += aRowAdd;
+ }
+ }
+ }
+ else
+ {
+ ulong src = 0xFF000000 |
+ ((((((theColor.mRed * theColor.mAlpha + 0x80) >> 8) * aRMask) + aRRoundAdd) >> 8) & aRMask) |
+ ((((((theColor.mGreen * theColor.mAlpha + 0x80) >> 8) * aGMask) + aGRoundAdd) >> 8) & aGMask) |
+ ((((((theColor.mBlue * theColor.mAlpha + 0x80) >> 8) * aBMask) + aBRoundAdd) >> 8) & aBMask);
+ int oma = 256 - theColor.mAlpha;
+
+ double dv = theEndY - theStartY;
+ double dh = theEndX - theStartX;
+ int minG, maxG, G, DeltaG1, DeltaG2;
+ double swap;
+ int inc = 1;
+ int aCurX;
+ int aCurY;
+ int aRowWidth = mWidth;
+ int aRowAdd = aRowWidth;
+
+ if (abs(dv) < abs(dh))
+ {
+ // Mostly horizontal
+ if (dh < 0)
+ {
+ dh = -dh;
+ dv = -dv;
+ swap = theEndY;
+ theEndY = theStartY;
+ theStartY = swap;
+ swap = theEndX;
+ theEndX = theStartX;
+ theStartX = swap;
+ }
+ if (dv < 0)
+ {
+ dv = -dv;
+ inc = -1;
+ aRowAdd = -aRowAdd;
+ }
+
+ ulong* aDestPixels = ((ulong*) aSurface) + ((int) theStartY * aRowWidth) + (int) theStartX;
+ ulong dest = *aDestPixels;
+ *(aDestPixels++) = src +
+ (((((dest & aRMask) * oma) + aRRoundAdd) >> 8) & aRMask) +
+ (((((dest & aGMask) * oma) + aGRoundAdd) >> 8) & aGMask) +
+ (((((dest & aBMask) * oma) + aBRoundAdd) >> 8) & aBMask);
+
+ aCurY = theStartY;
+ aCurX = theStartX + 1;
+
+ G = 2 * dv - dh;
+ DeltaG1 = 2 * (dv - dh);
+ DeltaG2 = 2 * dv;
+
+ G += DeltaG2 * (theStartX - (int) theStartX);
+
+ while (aCurX <= theEndX)
+ {
+ if (G > 0)
+ {
+ G += DeltaG1;
+ aCurY += inc;
+ aDestPixels += aRowAdd;
+
+ if (aCurX<aMinX || aCurY<aMinY || aCurX>aMaxX || aCurY>aMaxY)
+ break;
+ }
+ else
+ G += DeltaG2;
+
+ dest = *aDestPixels;
+ *(aDestPixels++) = src +
+ (((((dest & aRMask) * oma) + aRRoundAdd) >> 8) & aRMask) +
+ (((((dest & aGMask) * oma) + aGRoundAdd) >> 8) & aGMask) +
+ (((((dest & aBMask) * oma) + aBRoundAdd) >> 8) & aBMask);
+
+ aCurX++;
+ }
+ }
+ else
+ {
+ // Mostly vertical
+ if ( dv < 0 )
+ {
+ dh = -dh;
+ dv = -dv;
+ swap = theEndY;
+ theEndY = theStartY;
+ theStartY = swap;
+ swap = theEndX;
+ theEndX = theStartX;
+ theStartX = swap;
+ }
+
+ if (dh < 0)
+ {
+ dh = -dh;
+ inc = -1;
+ }
+
+ ulong* aDestPixels = ((ulong*) aSurface) + ((int) theStartY * aRowWidth) + (int) theStartX;
+ ulong dest = *aDestPixels;
+ *aDestPixels = src +
+ (((((dest & aRMask) * oma) + aRRoundAdd) >> 8) & aRMask) +
+ (((((dest & aGMask) * oma) + aGRoundAdd) >> 8) & aGMask) +
+ (((((dest & aBMask) * oma) + aBRoundAdd) >> 8) & aBMask);
+ aDestPixels += aRowAdd;
+
+ aCurX = theStartX;
+ aCurY = theStartY + 1;
+
+ G = 2 * dh - dv;
+ minG = maxG = G;
+ DeltaG1 = 2 * ( dh - dv );
+ DeltaG2 = 2 * dh;
+
+ G += DeltaG2 * (theStartX - (int) theStartX);
+
+ while (aCurY <= theEndY)
+ {
+ if ( G > 0 )
+ {
+ G += DeltaG1;
+ aCurX += inc;
+ aDestPixels += inc;
+
+ if (aCurX<aMinX || aCurY<aMinY || aCurX>aMaxX || aCurY>aMaxY)
+ break;
+ }
+ else
+ G += DeltaG2;
+
+ dest = *aDestPixels;
+ *aDestPixels = src +
+ (((((dest & aRMask) * oma) + aRRoundAdd) >> 8) & aRMask) +
+ (((((dest & aGMask) * oma) + aGRoundAdd) >> 8) & aGMask) +
+ (((((dest & aBMask) * oma) + aBRoundAdd) >> 8) & aBMask);
+
+ aCurY++;
+ aDestPixels += aRowAdd;
+ }
+ }
+ }
+ }
+}
+
+void MemoryImage::AdditiveDrawLine(double theStartX, double theStartY, double theEndX, double theEndY, const Color& theColor)
+{
+ double aMinX = min(theStartX, theEndX);
+ double aMinY = min(theStartY, theEndY);
+ double aMaxX = max(theStartX, theEndX);
+ double aMaxY = max(theStartY, theEndY);
+
+ ulong aRMask = 0xFF0000;
+ ulong aGMask = 0x00FF00;
+ ulong aBMask = 0x0000FF;
+ int aRedShift = 16;
+ int aGreenShift = 8;
+ int aBlueShift = 0;
+
+ ulong aRRoundAdd = aRMask >> 1;
+ ulong aGRoundAdd = aGMask >> 1;
+ ulong aBRoundAdd = aBMask >> 1;
+
+ uchar* aMaxTable = mApp->mAdd8BitMaxTable;
+ DWORD *aSurface = GetBits();
+
+ if (true)//(mLockedSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 32)
+ {
+ ulong rc = ((theColor.mRed * theColor.mAlpha) / 255);
+ ulong gc = ((theColor.mGreen * theColor.mAlpha) / 255);
+ ulong bc = ((theColor.mBlue * theColor.mAlpha) / 255);
+
+ double dv = theEndY - theStartY;
+ double dh = theEndX - theStartX;
+ int minG, maxG, G, DeltaG1, DeltaG2;
+ double swap;
+ int inc = 1;
+ int aCurX;
+ int aCurY;
+ int aRowWidth = mWidth;
+ int aRowAdd = aRowWidth;
+
+ if (abs(dv) < abs(dh))
+ {
+ // Mostly horizontal
+ if (dh < 0)
+ {
+ dh = -dh;
+ dv = -dv;
+ swap = theEndY;
+ theEndY = theStartY;
+ theStartY = swap;
+ swap = theEndX;
+ theEndX = theStartX;
+ theStartX = swap;
+ }
+
+ if (dv < 0)
+ {
+ dv = -dv;
+ inc = -1;
+ aRowAdd = -aRowAdd;
+ }
+
+ ulong* aDestPixels = ((ulong*) aSurface) + ((int) theStartY * aRowWidth) + (int) theStartX;
+ ulong dest = *aDestPixels;
+
+ int r = aMaxTable[((dest & aRMask) >> aRedShift) + rc];
+ int g = aMaxTable[((dest & aGMask) >> aGreenShift) + gc];
+ int b = aMaxTable[((dest & aBMask) >> aBlueShift) + bc];
+
+ *(aDestPixels++) =
+ 0xFF000000 |
+ (r << aRedShift) |
+ (g << aGreenShift) |
+ (b << aBlueShift);
+
+ aCurY = theStartY;
+ aCurX = theStartX + 1;
+
+ G = 2 * dv - dh;
+ DeltaG1 = 2 * (dv - dh);
+ DeltaG2 = 2 * dv;
+
+ while (aCurX <= theEndX)
+ {
+ if (G > 0)
+ {
+ G += DeltaG1;
+ aCurY += inc;
+ aDestPixels += aRowAdd;
+
+ if (aCurX<aMinX || aCurY<aMinY || aCurX>aMaxX || aCurY>aMaxY)
+ break;
+ }
+ else
+ G += DeltaG2;
+
+ dest = *aDestPixels;
+
+ r = aMaxTable[((dest & aRMask) >> aRedShift) + rc];
+ g = aMaxTable[((dest & aGMask) >> aGreenShift) + gc];
+ b = aMaxTable[((dest & aBMask) >> aBlueShift) + bc];
+
+ *(aDestPixels++) =
+ 0xFF000000 |
+ (r << aRedShift) |
+ (g << aGreenShift) |
+ (b << aBlueShift);
+
+ aCurX++;
+ }
+ }
+ else
+ {
+ // Mostly vertical
+ if ( dv < 0 )
+ {
+ dh = -dh;
+ dv = -dv;
+ swap = theEndY;
+ theEndY = theStartY;
+ theStartY = swap;
+ swap = theEndX;
+ theEndX = theStartX;
+ theStartX = swap;
+ }
+
+ if (dh < 0)
+ {
+ dh = -dh;
+ inc = -1;
+ }
+
+ ulong* aDestPixels = ((ulong*) aSurface) + ((int) theStartY * mWidth) + (int) theStartX;
+
+ ulong dest = *aDestPixels;
+
+ int r = aMaxTable[((dest & aRMask) >> aRedShift) + rc];
+ int g = aMaxTable[((dest & aGMask) >> aGreenShift) + gc];
+ int b = aMaxTable[((dest & aBMask) >> aBlueShift) + bc];
+
+ *aDestPixels =
+ 0xFF000000 |
+ (r << aRedShift) |
+ (g << aGreenShift) |
+ (b << aBlueShift);
+
+ aDestPixels += aRowAdd;
+
+ aCurX = theStartX;
+ aCurY = theStartY + 1;
+
+ G = 2 * dh - dv;
+ minG = maxG = G;
+ DeltaG1 = 2 * ( dh - dv );
+ DeltaG2 = 2 * dh;
+ while (aCurY <= theEndY)
+ {
+ if ( G > 0 )
+ {
+ G += DeltaG1;
+ aCurX += inc;
+ aDestPixels += inc;
+
+ if (aCurX<aMinX || aCurY<aMinY || aCurX>aMaxX || aCurY>aMaxY)
+ break;
+ }
+ else
+ G += DeltaG2;
+
+ dest = *aDestPixels;
+
+ r = aMaxTable[((dest & aRMask) >> aRedShift) + rc];
+ g = aMaxTable[((dest & aGMask) >> aGreenShift) + gc];
+ b = aMaxTable[((dest & aBMask) >> aBlueShift) + bc];
+
+ *aDestPixels =
+ 0xFF000000 |
+ (r << aRedShift) |
+ (g << aGreenShift) |
+ (b << aBlueShift);
+
+ aCurY++;
+ aDestPixels += aRowAdd;
+ }
+ }
+ }
+}
+
+
+void MemoryImage::DrawLine(double theStartX, double theStartY, double theEndX, double theEndY, const Color& theColor, int theDrawMode)
+{
+ if (theStartY == theEndY)
+ {
+ int aStartX = min(theStartX, theEndX);
+ int aEndX = max(theStartX, theEndX);
+
+ FillRect(Rect(aStartX, theStartY, aEndX-aStartX+1, theEndY-theStartY+1), theColor, theDrawMode);
+ return;
+ }
+ else if (theStartX == theEndX)
+ {
+ int aStartY = min(theStartY, theEndY);
+ int aEndY = max(theStartY, theEndY);
+
+ FillRect(Rect(theStartX, aStartY, theEndX-theStartX+1, aEndY-aStartY+1), theColor, theDrawMode);
+ return;
+ }
+
+ switch (theDrawMode)
+ {
+ case Graphics::DRAWMODE_NORMAL:
+ NormalDrawLine(theStartX, theStartY, theEndX, theEndY, theColor);
+ break;
+ case Graphics::DRAWMODE_ADDITIVE:
+ AdditiveDrawLine(theStartX, theStartY, theEndX, theEndY, theColor);
+ break;
+ }
+
+ BitsChanged();
+}
+
+void MemoryImage::NormalDrawLineAA(double theStartX, double theStartY, double theEndX, double theEndY, const Color& theColor)
+{
+ ulong* aBits = GetBits();
+ ulong color = theColor.ToInt();
+
+ int aX0 = (int)theStartX, aX1 = (int)theEndX;
+ int aY0 = (int)theStartY, aY1 = (int)theEndY;
+ int aXinc = 1;
+ if (aY0 > aY1)
+ {
+ int aTempX = aX0, aTempY = aY0;
+ aX0 = aX1; aY0 = aY1;
+ aX1 = aTempX; aY1 = aTempY;
+ double aTempXd = theStartX, aTempYd = theStartY;
+ theStartX = theEndX; theStartY = theEndY;
+ theEndX = aTempXd; theEndY = aTempYd;
+ }
+
+ int dx = aX1 - aX0;
+ int dy = aY1 - aY0;
+ double dxd = theEndX - theStartX;
+ double dyd = theEndY - theStartY;
+ if (dx < 0)
+ {
+ dx = -dx;
+ aXinc = -1;
+ dxd = -dxd;
+ }
+
+ if (theColor.mAlpha != 255)
+ {
+ #define PIXEL_TYPE ulong
+ #define CALC_WEIGHT_A(w) (((w) * (theColor.mAlpha+1)) >> 8)
+ #define BLEND_PIXEL(p) \
+ {\
+ int aDestAlpha = dest >> 24;\
+ int aNewDestAlpha = aDestAlpha + ((255 - aDestAlpha) * a) / 255;\
+ a = 255 * a / aNewDestAlpha;\
+ oma = 256 - a;\
+ *(p) = (aNewDestAlpha << 24) |\
+ ((((color & 0xFF0000) * a + (dest & 0xFF0000) * oma) >> 8) & 0xFF0000) |\
+ ((((color & 0x00FF00) * a + (dest & 0x00FF00) * oma) >> 8) & 0x00FF00) |\
+ ((((color & 0x0000FF) * a + (dest & 0x0000FF) * oma) >> 8) & 0x0000FF);\
+ }
+ const int STRIDE = mWidth;
+
+ #include "GENERIC_DrawLineAA.inc"
+
+ #undef PIXEL_TYPE
+ #undef CALC_WEIGHT_A
+ #undef BLEND_PIXEL
+ }
+ else
+ {
+ #define PIXEL_TYPE ulong
+ #define CALC_WEIGHT_A(w) (w)
+ #define BLEND_PIXEL(p) \
+ {\
+ int aDestAlpha = dest >> 24;\
+ int aNewDestAlpha = aDestAlpha + ((255 - aDestAlpha) * a) / 255;\
+ a = 255 * a / aNewDestAlpha;\
+ oma = 256 - a;\
+ *(p) = (aNewDestAlpha << 24) |\
+ ((((color & 0xFF0000) * a + (dest & 0xFF0000) * oma) >> 8) & 0xFF0000) |\
+ ((((color & 0x00FF00) * a + (dest & 0x00FF00) * oma) >> 8) & 0x00FF00) |\
+ ((((color & 0x0000FF) * a + (dest & 0x0000FF) * oma) >> 8) & 0x0000FF);\
+ }
+ const int STRIDE = mWidth;
+
+ #include "GENERIC_DrawLineAA.inc"
+
+ #undef PIXEL_TYPE
+ #undef CALC_WEIGHT_A
+ #undef BLEND_PIXEL
+ }
+
+
+ BitsChanged();
+}
+
+void MemoryImage::AdditiveDrawLineAA(double theStartX, double theStartY, double theEndX, double theEndY, const Color& theColor)
+{
+}
+
+void MemoryImage::DrawLineAA(double theStartX, double theStartY, double theEndX, double theEndY, const Color& theColor, int theDrawMode)
+{
+ if (theStartY == theEndY)
+ {
+ int aStartX = min(theStartX, theEndX);
+ int aEndX = max(theStartX, theEndX);
+
+ FillRect(Rect(aStartX, theStartY, aEndX-aStartX+1, theEndY-theStartY+1), theColor, theDrawMode);
+ return;
+ }
+ else if (theStartX == theEndX)
+ {
+ int aStartY = min(theStartY, theEndY);
+ int aEndY = max(theStartY, theEndY);
+
+ FillRect(Rect(theStartX, aStartY, theEndX-theStartX+1, aEndY-aStartY+1), theColor, theDrawMode);
+ return;
+ }
+
+ switch (theDrawMode)
+ {
+ case Graphics::DRAWMODE_NORMAL:
+ NormalDrawLineAA(theStartX, theStartY, theEndX, theEndY, theColor);
+ break;
+ case Graphics::DRAWMODE_ADDITIVE:
+ AdditiveDrawLineAA(theStartX, theStartY, theEndX, theEndY, theColor);
+ break;
+ }
+
+ BitsChanged();
+}
+
+
+void MemoryImage::CommitBits()
+{
+ //if (gDebug)
+ // mApp->CopyToClipboard("+MemoryImage::CommitBits");
+
+ if ((mBitsChanged) && (!mForcedMode))
+ {
+ // Analyze
+ if (mBits != NULL)
+ {
+ mHasTrans = false;
+ mHasAlpha = false;
+
+ int aSize = mWidth*mHeight;
+ ulong* ptr = mBits;
+
+ for (int i = 0; i < aSize; i++)
+ {
+ uchar anAlpha = (uchar) (*ptr++ >> 24);
+
+ if (anAlpha == 0)
+ mHasTrans = true;
+ else if (anAlpha != 255)
+ mHasAlpha = true;
+ }
+ }
+ else if (mColorTable != NULL)
+ {
+ mHasTrans = false;
+ mHasAlpha = false;
+
+ int aSize = 256;
+ ulong* ptr = mColorTable;
+
+ for (int i = 0; i < aSize; i++)
+ {
+ uchar anAlpha = (uchar) (*ptr++ >> 24);
+
+ if (anAlpha == 0)
+ mHasTrans = true;
+ else if (anAlpha != 255)
+ mHasAlpha = true;
+ }
+ }
+ else
+ {
+ mHasTrans = true;
+ mHasAlpha = false;
+ }
+
+ mBitsChanged = false;
+ }
+
+ //if (gDebug)
+ // mApp->CopyToClipboard("-MemoryImage::CommitBits");
+}
+
+void MemoryImage::SetImageMode(bool hasTrans, bool hasAlpha)
+{
+ mForcedMode = true;
+ mHasTrans = hasTrans;
+ mHasAlpha = hasAlpha;
+}
+
+void MemoryImage::SetVolatile(bool isVolatile)
+{
+ mIsVolatile = isVolatile;
+}
+
+void* MemoryImage::GetNativeAlphaData(NativeDisplay *theDisplay)
+{
+ if (mNativeAlphaData != NULL)
+ return mNativeAlphaData;
+
+ CommitBits();
+
+ const int rRightShift = 16 + (8-theDisplay->mRedBits);
+ const int gRightShift = 8 + (8-theDisplay->mGreenBits);
+ const int bRightShift = 0 + (8-theDisplay->mBlueBits);
+
+ const int rLeftShift = theDisplay->mRedShift;
+ const int gLeftShift = theDisplay->mGreenShift;
+ const int bLeftShift = theDisplay->mBlueShift;
+
+ const int rMask = theDisplay->mRedMask;
+ const int gMask = theDisplay->mGreenMask;
+ const int bMask = theDisplay->mBlueMask;
+
+ if (mColorTable == NULL)
+ {
+ ulong* aSrcPtr = GetBits();
+
+ ulong* anAlphaData = new ulong[mWidth*mHeight];
+
+ ulong* aDestPtr = anAlphaData;
+ int aSize = mWidth*mHeight;
+ for (int i = 0; i < aSize; i++)
+ {
+ ulong val = *(aSrcPtr++);
+
+ int anAlpha = val >> 24;
+
+ ulong r = ((val & 0xFF0000) * (anAlpha+1)) >> 8;
+ ulong g = ((val & 0x00FF00) * (anAlpha+1)) >> 8;
+ ulong b = ((val & 0x0000FF) * (anAlpha+1)) >> 8;
+
+ *(aDestPtr++) =
+ (((r >> rRightShift) << rLeftShift) & rMask) |
+ (((g >> gRightShift) << gLeftShift) & gMask) |
+ (((b >> bRightShift) << bLeftShift) & bMask) |
+ (anAlpha << 24);
+ }
+
+ mNativeAlphaData = anAlphaData;
+ }
+ else
+ {
+ ulong* aSrcPtr = mColorTable;
+
+ ulong* anAlphaData = new ulong[256];
+
+ for (int i = 0; i < 256; i++)
+ {
+ ulong val = *(aSrcPtr++);
+
+ int anAlpha = val >> 24;
+
+ ulong r = ((val & 0xFF0000) * (anAlpha+1)) >> 8;
+ ulong g = ((val & 0x00FF00) * (anAlpha+1)) >> 8;
+ ulong b = ((val & 0x0000FF) * (anAlpha+1)) >> 8;
+
+ anAlphaData[i] =
+ (((r >> rRightShift) << rLeftShift) & rMask) |
+ (((g >> gRightShift) << gLeftShift) & gMask) |
+ (((b >> bRightShift) << bLeftShift) & bMask) |
+ (anAlpha << 24);
+ }
+
+
+ mNativeAlphaData = anAlphaData;
+ }
+
+ return mNativeAlphaData;
+}
+
+
+uchar* MemoryImage::GetRLAlphaData()
+{
+ CommitBits();
+
+ if (mRLAlphaData == NULL)
+ {
+ mRLAlphaData = new uchar[mWidth*mHeight];
+
+ if (mColorTable == NULL)
+ {
+ ulong* aSrcPtr;
+ if (mNativeAlphaData != NULL)
+ aSrcPtr = (ulong*) mNativeAlphaData;
+ else
+ aSrcPtr = GetBits();
+
+ #define NEXT_SRC_COLOR (*(aSrcPtr++))
+
+ #include "MI_GetRLAlphaData.inc"
+
+ #undef NEXT_SRC_COLOR
+ }
+ else
+ {
+ uchar* aSrcPtr = mColorIndices;
+ ulong* aColorTable = mColorTable;
+
+ #define NEXT_SRC_COLOR (aColorTable[*(aSrcPtr++)])
+
+ #include "MI_GetRLAlphaData.inc"
+
+ #undef NEXT_SRC_COLOR
+ }
+ }
+
+ return mRLAlphaData;
+}
+
+uchar* MemoryImage::GetRLAdditiveData(NativeDisplay *theNative)
+{
+ if (mRLAdditiveData == NULL)
+ {
+ if (mColorTable == NULL)
+ {
+ ulong* aBits = (ulong*) GetNativeAlphaData(theNative);
+
+ mRLAdditiveData = new uchar[mWidth*mHeight];
+
+ uchar* aWPtr = mRLAdditiveData;
+ ulong* aRPtr = aBits;
+
+ if (mWidth==1)
+ {
+ memset(aWPtr,1,mHeight);
+ }
+ else
+ {
+ for (int aRow = 0; aRow < mHeight; aRow++)
+ {
+ int aRCount = 1;
+ int aRLCount = 1;
+
+ int aLastAClass = (((*aRPtr++) & 0xFFFFFF) != 0) ? 1 : 0;
+
+ while (aRCount < mWidth)
+ {
+ aRCount++;
+
+ int aThisAClass = (((*aRPtr++) & 0xFFFFFF) != 0) ? 1 : 0;
+
+ if ((aThisAClass != aLastAClass) || (aRCount == mWidth))
+ {
+ if (aThisAClass == aLastAClass)
+ aRLCount++;
+
+ for (int i = aRLCount; i > 0; i--)
+ {
+ if (i >= 255)
+ *aWPtr++ = 255;
+ else
+ *aWPtr++ = i;
+ }
+
+ if ((aRCount == mWidth) && (aThisAClass != aLastAClass))
+ *aWPtr++ = 1;
+
+ aLastAClass = aThisAClass;
+ aRLCount = 1;
+ }
+ else
+ {
+ aRLCount++;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ ulong* aNativeColorTable = (ulong*) GetNativeAlphaData(theNative);
+
+ mRLAdditiveData = new uchar[mWidth*mHeight];
+
+ uchar* aWPtr = mRLAdditiveData;
+ uchar* aRPtr = mColorIndices;
+
+ if (mWidth==1)
+ {
+ memset(aWPtr,1,mHeight);
+ }
+ else
+ {
+ for (int aRow = 0; aRow < mHeight; aRow++)
+ {
+ int aRCount = 1;
+ int aRLCount = 1;
+
+ int aLastAClass = (((aNativeColorTable[*aRPtr++]) & 0xFFFFFF) != 0) ? 1 : 0;
+
+ while (aRCount < mWidth)
+ {
+ aRCount++;
+
+ int aThisAClass = (((aNativeColorTable[*aRPtr++]) & 0xFFFFFF) != 0) ? 1 : 0;
+
+ if ((aThisAClass != aLastAClass) || (aRCount == mWidth))
+ {
+ if (aThisAClass == aLastAClass)
+ aRLCount++;
+
+ for (int i = aRLCount; i > 0; i--)
+ {
+ if (i >= 255)
+ *aWPtr++ = 255;
+ else
+ *aWPtr++ = i;
+ }
+
+ if ((aRCount == mWidth) && (aThisAClass != aLastAClass))
+ *aWPtr++ = 1;
+
+ aLastAClass = aThisAClass;
+ aRLCount = 1;
+ }
+ else
+ {
+ aRLCount++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return mRLAdditiveData;
+}
+
+void MemoryImage::PurgeBits()
+{
+ mPurgeBits = true;
+
+ if (mApp->Is3DAccelerated())
+ {
+ // Due to potential D3D threading issues we have to defer the texture creation
+ // and therefore the actual purging
+ if (mD3DData == NULL)
+ return;
+ }
+ else
+ {
+ if ((mBits == NULL) && (mColorIndices == NULL))
+ return;
+
+ GetNativeAlphaData(gSexyAppBase->mDDInterface);
+ }
+
+ delete [] mBits;
+ mBits = NULL;
+
+ if (mD3DData != NULL)
+ {
+ delete [] mColorIndices;
+ mColorIndices = NULL;
+
+ delete [] mColorTable;
+ mColorTable = NULL;
+ }
+}
+
+void MemoryImage::DeleteSWBuffers()
+{
+ if ((mBits == NULL) && (mColorIndices == NULL))
+ GetBits();
+
+ delete [] mNativeAlphaData;
+ mNativeAlphaData = NULL;
+
+ delete [] mRLAdditiveData;
+ mRLAdditiveData = NULL;
+
+ delete [] mRLAlphaData;
+ mRLAlphaData = NULL;
+}
+
+void MemoryImage::Delete3DBuffers()
+{
+ mApp->Remove3DData(this);
+}
+
+void MemoryImage::DeleteExtraBuffers()
+{
+ DeleteSWBuffers();
+ Delete3DBuffers();
+}
+
+void MemoryImage::ReInit()
+{
+ // Fix any un-palletizing
+ if (mWantPal)
+ Palletize();
+
+ if (mPurgeBits)
+ PurgeBits();
+}
+
+void MemoryImage::DeleteNativeData()
+{
+ if ((mBits == NULL) && (mColorIndices == NULL))
+ GetBits(); // We need to keep the bits around
+
+ delete [] mNativeAlphaData;
+ mNativeAlphaData = NULL;
+
+ delete [] mRLAdditiveData;
+ mRLAdditiveData = NULL;
+}
+
+void MemoryImage::SetBits(ulong* theBits, int theWidth, int theHeight, bool commitBits)
+{
+ if (theBits != mBits)
+ {
+ delete [] mColorIndices;
+ mColorIndices = NULL;
+
+ delete [] mColorTable;
+ mColorTable = NULL;
+
+ if (theWidth != mWidth || theHeight != mHeight)
+ {
+ delete [] mBits;
+ mBits = new ulong[theWidth*theHeight + 1];
+ mWidth = theWidth;
+ mHeight = theHeight;
+ }
+ memcpy(mBits, theBits, mWidth*mHeight*sizeof(ulong));
+ mBits[mWidth*mHeight] = MEMORYCHECK_ID;
+
+ BitsChanged();
+ if (commitBits)
+ CommitBits();
+ }
+}
+
+void MemoryImage::Create(int theWidth, int theHeight)
+{
+ delete [] mBits;
+ mBits = NULL;
+
+ mWidth = theWidth;
+ mHeight = theHeight;
+
+ // All zeros --> trans + alpha
+ mHasTrans = true;
+ mHasAlpha = true;
+
+ BitsChanged();
+}
+
+ulong* MemoryImage::GetBits()
+{
+ if (mBits == NULL)
+ {
+ int aSize = mWidth*mHeight;
+
+ mBits = new ulong[aSize+1];
+ mBits[aSize] = MEMORYCHECK_ID;
+
+ if (mColorTable != NULL)
+ {
+ for (int i = 0; i < aSize; i++)
+ mBits[i] = mColorTable[mColorIndices[i]];
+
+ delete [] mColorIndices;
+ mColorIndices = NULL;
+
+ delete [] mColorTable;
+ mColorTable = NULL;
+
+ delete [] mNativeAlphaData;
+ mNativeAlphaData = NULL;
+ }
+ else if (mNativeAlphaData != NULL)
+ {
+ NativeDisplay* aDisplay = gSexyAppBase->mDDInterface;
+
+ const int rMask = aDisplay->mRedMask;
+ const int gMask = aDisplay->mGreenMask;
+ const int bMask = aDisplay->mBlueMask;
+
+ const int rLeftShift = aDisplay->mRedShift + (aDisplay->mRedBits);
+ const int gLeftShift = aDisplay->mGreenShift + (aDisplay->mGreenBits);
+ const int bLeftShift = aDisplay->mBlueShift + (aDisplay->mBlueBits);
+
+ ulong* aDestPtr = mBits;
+ ulong* aSrcPtr = mNativeAlphaData;
+
+ int aSize = mWidth*mHeight;
+ for (int i = 0; i < aSize; i++)
+ {
+ ulong val = *(aSrcPtr++);
+
+ int anAlpha = val >> 24;
+
+ ulong r = (((((val & rMask) << 8) / (anAlpha+1)) & rMask) << 8) >> rLeftShift;
+ ulong g = (((((val & gMask) << 8) / (anAlpha+1)) & gMask) << 8) >> gLeftShift;
+ ulong b = (((((val & bMask) << 8) / (anAlpha+1)) & bMask) << 8) >> bLeftShift;
+
+ *(aDestPtr++) = (r << 16) | (g << 8) | (b) | (anAlpha << 24);
+ }
+ }
+ else if ((mD3DData == NULL) || (!mApp->mDDInterface->mD3DInterface->RecoverBits(this)))
+ {
+ ZeroMemory(mBits, aSize*sizeof(ulong));
+ }
+ }
+
+ return mBits;
+}
+
+void MemoryImage::FillRect(const Rect& theRect, const Color& theColor, int theDrawMode)
+{
+ ulong src = theColor.ToInt();
+
+ ulong* aBits = GetBits();
+
+ int oldAlpha = src >> 24;
+
+ if (oldAlpha == 0xFF)
+ {
+ for (int aRow = theRect.mY; aRow < theRect.mY+theRect.mHeight; aRow++)
+ {
+ ulong* aDestPixels = &aBits[aRow*mWidth+theRect.mX];
+
+ for (int i = 0; i < theRect.mWidth; i++)
+ *aDestPixels++ = src;
+ }
+ }
+ else
+ {
+ for (int aRow = theRect.mY; aRow < theRect.mY+theRect.mHeight; aRow++)
+ {
+ ulong* aDestPixels = &aBits[aRow*mWidth+theRect.mX];
+
+ for (int i = 0; i < theRect.mWidth; i++)
+ {
+ ulong dest = *aDestPixels;
+
+ int aDestAlpha = dest >> 24;
+ int aNewDestAlpha = aDestAlpha + ((255 - aDestAlpha) * oldAlpha) / 255;
+
+ int newAlpha = 255 * oldAlpha / aNewDestAlpha;
+
+ int oma = 256 - newAlpha;
+
+#ifdef OPTIMIZE_SOFTWARE_DRAWING
+ *(aDestPixels++) = (aNewDestAlpha << 24) |
+ ((((dest & 0xFF00FF) * oma + (src & 0xFF00FF) * newAlpha) >> 8) & 0xFF00FF) |
+ ((((dest & 0x00FF00) * oma + (src & 0x00FF00) * newAlpha) >> 8) & 0x00FF00);
+#else
+ *(aDestPixels++) = (aNewDestAlpha << 24) |
+ ((((dest & 0x0000FF) * oma) >> 8) + (((src & 0x0000FF) * newAlpha) >> 8) & 0x0000FF) |
+ ((((dest & 0x00FF00) * oma) >> 8) + (((src & 0x00FF00) * newAlpha) >> 8) & 0x00FF00) |
+ ((((dest & 0xFF0000) * oma) >> 8) + (((src & 0xFF0000) * newAlpha) >> 8) & 0xFF0000);
+#endif
+ }
+ }
+ }
+
+ BitsChanged();
+}
+
+void MemoryImage::ClearRect(const Rect& theRect)
+{
+ ulong* aBits = GetBits();
+
+ for (int aRow = theRect.mY; aRow < theRect.mY+theRect.mHeight; aRow++)
+ {
+ ulong* aDestPixels = &aBits[aRow*mWidth+theRect.mX];
+
+ for (int i = 0; i < theRect.mWidth; i++)
+ *aDestPixels++ = 0;
+ }
+
+ BitsChanged();
+}
+
+void MemoryImage::Clear()
+{
+ ulong* ptr = GetBits();
+ if (ptr != NULL)
+ {
+ for (int i = 0; i < mWidth*mHeight; i++)
+ *ptr++ = 0;
+
+ BitsChanged();
+ }
+}
+
+void MemoryImage::AdditiveBlt(Image* theImage, int theX, int theY, const Rect& theSrcRect, const Color& theColor)
+{
+ theImage->mDrawn = true;
+
+ MemoryImage* aSrcMemoryImage = dynamic_cast<MemoryImage*>(theImage);
+
+ uchar* aMaxTable = mApp->mAdd8BitMaxTable;
+
+ if (aSrcMemoryImage != NULL)
+ {
+ if (aSrcMemoryImage->mColorTable == NULL)
+ {
+ ulong* aSrcBits = aSrcMemoryImage->GetBits();
+
+ #define NEXT_SRC_COLOR (*(aSrcPtr++))
+ #define SRC_TYPE ulong
+
+ #include "MI_AdditiveBlt.inc"
+
+ #undef NEXT_SRC_COLOR
+ #undef SRC_TYPE
+ }
+ else
+ {
+ ulong* aColorTable = aSrcMemoryImage->mColorTable;
+ uchar* aSrcBits = aSrcMemoryImage->mColorIndices;
+
+ #define NEXT_SRC_COLOR (aColorTable[*(aSrcPtr++)])
+ #define SRC_TYPE uchar
+
+ #include "MI_AdditiveBlt.inc"
+
+ #undef NEXT_SRC_COLOR
+ #undef SRC_TYPE
+ }
+
+ BitsChanged();
+ }
+}
+
+void MemoryImage::NormalBlt(Image* theImage, int theX, int theY, const Rect& theSrcRect, const Color& theColor)
+{
+ theImage->mDrawn = true;
+
+ MemoryImage* aSrcMemoryImage = dynamic_cast<MemoryImage*>(theImage);
+
+ if (aSrcMemoryImage != NULL)
+ {
+ if (aSrcMemoryImage->mColorTable == NULL)
+ {
+ ulong* aSrcPixelsRow = ((ulong*) aSrcMemoryImage->GetBits()) + (theSrcRect.mY * theImage->mWidth) + theSrcRect.mX;
+
+ #define NEXT_SRC_COLOR (*(aSrcPtr++))
+ #define READ_SRC_COLOR (*(aSrcPtr))
+ #define EACH_ROW ulong* aSrcPtr = aSrcPixelsRow
+
+ #include "MI_NormalBlt.inc"
+
+ #undef NEXT_SRC_COLOR
+ #undef READ_SRC_COLOR
+ #undef EACH_ROW
+ }
+ else
+ {
+ ulong* aColorTable = aSrcMemoryImage->mColorTable;
+ uchar* aSrcPixelsRow = aSrcMemoryImage->mColorIndices + (theSrcRect.mY * theImage->mWidth) + theSrcRect.mX;
+
+ #define NEXT_SRC_COLOR (aColorTable[*(aSrcPtr++)])
+ #define READ_SRC_COLOR (aColorTable[*(aSrcPtr)])
+ #define EACH_ROW uchar* aSrcPtr = aSrcPixelsRow
+
+ #include "MI_NormalBlt.inc"
+
+ #undef NEXT_SRC_COLOR
+ #undef READ_SRC_COLOR
+ #undef EACH_ROW
+ }
+
+ BitsChanged();
+ }
+}
+
+void MemoryImage::Blt(Image* theImage, int theX, int theY, const Rect& theSrcRect, const Color& theColor, int theDrawMode)
+{
+ theImage->mDrawn = true;
+
+ DBG_ASSERTE((theColor.mRed >= 0) && (theColor.mRed <= 255));
+ DBG_ASSERTE((theColor.mGreen >= 0) && (theColor.mGreen <= 255));
+ DBG_ASSERTE((theColor.mBlue >= 0) && (theColor.mBlue <= 255));
+ DBG_ASSERTE((theColor.mAlpha >= 0) && (theColor.mAlpha <= 255));
+
+ switch (theDrawMode)
+ {
+ case Graphics::DRAWMODE_NORMAL:
+ NormalBlt(theImage, theX, theY, theSrcRect, theColor);
+ break;
+ case Graphics::DRAWMODE_ADDITIVE:
+ AdditiveBlt(theImage, theX, theY, theSrcRect, theColor);
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+void MemoryImage::BltF(Image* theImage, float theX, float theY, const Rect& theSrcRect, const Rect &theClipRect, const Color& theColor, int theDrawMode)
+{
+ theImage->mDrawn = true;
+
+ BltRotated(theImage,theX,theY,theSrcRect,theClipRect,theColor,theDrawMode,0,0,0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+bool MemoryImage::BltRotatedClipHelper(float &theX, float &theY, const Rect &theSrcRect, const Rect &theClipRect, double theRot, FRect &theDestRect, float theRotCenterX, float theRotCenterY)
+{
+ // Clipping Code (this used to be in Graphics::DrawImageRotated)
+ float aCos = cosf(theRot);
+ float aSin = sinf(theRot);
+
+ // Map the four corners and find the bounding rectangle
+ float px[4] = { 0, theSrcRect.mWidth, theSrcRect.mWidth, 0 };
+ float py[4] = { 0, 0, theSrcRect.mHeight, theSrcRect.mHeight };
+ float aMinX = 10000000;
+ float aMaxX = -10000000;
+ float aMinY = 10000000;
+ float aMaxY = -10000000;
+
+ for (int i=0; i<4; i++)
+ {
+ float ox = px[i] - theRotCenterX;
+ float oy = py[i] - theRotCenterY;
+
+ px[i] = (theRotCenterX + ox*aCos + oy*aSin) + theX;
+ py[i] = (theRotCenterY + oy*aCos - ox*aSin) + theY;
+
+ if (px[i] < aMinX)
+ aMinX = px[i];
+ if (px[i] > aMaxX)
+ aMaxX = px[i];
+ if (py[i] < aMinY)
+ aMinY = py[i];
+ if (py[i] > aMaxY)
+ aMaxY = py[i];
+ }
+
+
+
+ FRect aClipRect(theClipRect.mX,theClipRect.mY,theClipRect.mWidth,theClipRect.mHeight);
+
+ FRect aDestRect = FRect(aMinX, aMinY, aMaxX-aMinX, aMaxY-aMinY).Intersection(aClipRect);
+ if ((aDestRect.mWidth <= 0) || (aDestRect.mHeight <= 0)) // nothing to draw
+ return false;
+
+ theDestRect = aDestRect;
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+bool MemoryImage::StretchBltClipHelper(const Rect &theSrcRect, const Rect &theClipRect, const Rect &theDestRect, FRect &theSrcRectOut, Rect &theDestRectOut)
+{
+ theDestRectOut = Rect(theDestRect.mX , theDestRect.mY, theDestRect.mWidth, theDestRect.mHeight).Intersection(theClipRect);
+
+ double aXFactor = theSrcRect.mWidth / (double) theDestRect.mWidth;
+ double aYFactor = theSrcRect.mHeight / (double) theDestRect.mHeight;
+
+ theSrcRectOut = FRect(theSrcRect.mX + (theDestRectOut.mX - theDestRect.mX)*aXFactor,
+ theSrcRect.mY + (theDestRectOut.mY - theDestRect.mY)*aYFactor,
+ theSrcRect.mWidth + (theDestRectOut.mWidth - theDestRect.mWidth)*aXFactor,
+ theSrcRect.mHeight + (theDestRectOut.mHeight - theDestRect.mHeight)*aYFactor);
+
+ return theSrcRectOut.mWidth>0 && theSrcRectOut.mHeight>0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+bool MemoryImage::StretchBltMirrorClipHelper(const Rect &theSrcRect, const Rect &theClipRect, const Rect &theDestRect, FRect &theSrcRectOut, Rect &theDestRectOut)
+{
+ theDestRectOut = Rect(theDestRect.mX, theDestRect.mY, theDestRect.mWidth, theDestRect.mHeight).Intersection(theClipRect);
+
+ double aXFactor = theSrcRect.mWidth / (double) theDestRect.mWidth;
+ double aYFactor = theSrcRect.mHeight / (double) theDestRect.mHeight;
+
+ int aTotalClip = theDestRect.mWidth - theDestRectOut.mWidth;
+ int aLeftClip = theDestRectOut.mX - theDestRect.mX;
+ int aRightClip = aTotalClip-aLeftClip;
+
+ theSrcRectOut = FRect(theSrcRect.mX + (aRightClip)*aXFactor,
+ theSrcRect.mY + (theDestRectOut.mY - theDestRect.mY)*aYFactor,
+ theSrcRect.mWidth + (theDestRectOut.mWidth - theDestRect.mWidth)*aXFactor,
+ theSrcRect.mHeight + (theDestRectOut.mHeight - theDestRect.mHeight)*aYFactor);
+
+ return theSrcRectOut.mWidth>0 && theSrcRectOut.mHeight>0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+void MemoryImage::BltRotated(Image* theImage, float theX, float theY, const Rect &theSrcRect, const Rect& theClipRect, const Color& theColor, int theDrawMode, double theRot, float theRotCenterX, float theRotCenterY)
+{
+ theImage->mDrawn = true;
+
+ // This BltRotatedClipHelper clipping used to happen in Graphics::DrawImageRotated
+ FRect aDestRect;
+ if (!BltRotatedClipHelper(theX, theY, theSrcRect, theClipRect, theRot, aDestRect,theRotCenterX,theRotCenterY))
+ return;
+
+ MemoryImage* aMemoryImage = dynamic_cast<MemoryImage*>(theImage);
+ uchar* aMaxTable = mApp->mAdd8BitMaxTable;
+
+ if (aMemoryImage != NULL)
+ {
+ if (aMemoryImage->mColorTable == NULL)
+ {
+ ulong* aSrcBits = aMemoryImage->GetBits() + theSrcRect.mX + theSrcRect.mY*theSrcRect.mWidth;
+
+ #define SRC_TYPE ulong
+ #define READ_COLOR(ptr) (*(ptr))
+
+ if (theDrawMode == Graphics::DRAWMODE_NORMAL)
+ {
+ #include "MI_BltRotated.inc"
+ }
+ else
+ {
+ #include "MI_BltRotated_Additive.inc"
+ }
+
+ #undef SRC_TYPE
+ #undef READ_COLOR
+ }
+ else
+ {
+ ulong* aColorTable = aMemoryImage->mColorTable;
+ uchar* aSrcBits = aMemoryImage->mColorIndices + theSrcRect.mX + theSrcRect.mY*theSrcRect.mWidth;
+
+ #define SRC_TYPE uchar
+ #define READ_COLOR(ptr) (aColorTable[*(ptr)])
+
+ if (theDrawMode == Graphics::DRAWMODE_NORMAL)
+ {
+ #include "MI_BltRotated.inc"
+ }
+ else
+ {
+ #include "MI_BltRotated_Additive.inc"
+ }
+
+ #undef SRC_TYPE
+ #undef READ_COLOR
+ }
+
+ BitsChanged();
+ }
+}
+
+void MemoryImage::SlowStretchBlt(Image* theImage, const Rect& theDestRect, const FRect& theSrcRect, const Color& theColor, int theDrawMode)
+{
+ theImage->mDrawn = true;
+
+ // This thing was a pain to write. I bet i could have gotten something just as good
+ // from some Graphics Gems book.
+
+ ulong* aDestEnd = GetBits() + (mWidth * mHeight);
+
+ MemoryImage* aSrcMemoryImage = dynamic_cast<MemoryImage*>(theImage);
+
+ if (aSrcMemoryImage != NULL)
+ {
+ if (aSrcMemoryImage->mColorTable == NULL)
+ {
+ ulong* aSrcBits = aSrcMemoryImage->GetBits();
+
+ #define SRC_TYPE ulong
+ #define READ_COLOR(ptr) (*(ptr))
+
+ #include "MI_SlowStretchBlt.inc"
+
+ #undef SRC_TYPE
+ #undef READ_COLOR
+ }
+ else
+ {
+ ulong* aColorTable = aSrcMemoryImage->mColorTable;
+ uchar* aSrcBits = aSrcMemoryImage->mColorIndices;
+
+ #define SRC_TYPE uchar
+ #define READ_COLOR(ptr) (aColorTable[*(ptr)])
+
+ #include "MI_SlowStretchBlt.inc"
+
+ #undef SRC_TYPE
+ #undef READ_COLOR
+ }
+
+ BitsChanged();
+ }
+}
+
+//TODO: Make the special version
+void MemoryImage::FastStretchBlt(Image* theImage, const Rect& theDestRect, const FRect& theSrcRect, const Color& theColor, int theDrawMode)
+{
+ theImage->mDrawn = true;
+
+ MemoryImage* aSrcMemoryImage = dynamic_cast<MemoryImage*>(theImage);
+
+ if (aSrcMemoryImage != NULL)
+ {
+ ulong* aDestPixelsRow = ((ulong*) GetBits()) + (theDestRect.mY * mWidth) + theDestRect.mX;
+ ulong* aSrcPixelsRow = (ulong*) aSrcMemoryImage->GetBits();;
+
+ double aSrcY = theSrcRect.mY;
+
+ double anAddX = theSrcRect.mWidth / theDestRect.mWidth;
+ double anAddY = theSrcRect.mHeight / theDestRect.mHeight;
+
+ if (theColor == Color::White)
+ {
+ for (int y = 0; y < theDestRect.mHeight; y++)
+ {
+ double aSrcX = theSrcRect.mX;
+
+ ulong* aDestPixels = aDestPixelsRow;
+
+ for (int x = 0; x < theDestRect.mWidth; x++)
+ {
+ aSrcX += anAddX;
+
+ ulong* aSrcPixels = aSrcPixelsRow + ((int) aSrcX) + (aSrcMemoryImage->mWidth * ((int) aSrcY));
+ ulong src = *aSrcPixels;
+
+ ulong dest = *aDestPixels;
+
+ int a = src >> 24;
+
+ if (a != 0)
+ {
+ int aDestAlpha = dest >> 24;
+ int aNewDestAlpha = aDestAlpha + ((255 - aDestAlpha) * a) / 255;
+
+ a = 255 * a / aNewDestAlpha;
+
+ int oma = 256 - a;
+
+ *(aDestPixels++) = (aNewDestAlpha << 24) |
+ ((((dest & 0x0000FF) * oma) >> 8) + (((src & 0x0000FF) * a) >> 8) & 0x0000FF) |
+ ((((dest & 0x00FF00) * oma) >> 8) + (((src & 0x00FF00) * a) >> 8) & 0x00FF00) |
+ ((((dest & 0xFF0000) * oma) >> 8) + (((src & 0xFF0000) * a) >> 8) & 0xFF0000);
+ }
+ else
+ aDestPixels++;
+ }
+
+ aDestPixelsRow += mWidth;
+ aSrcY += anAddY;
+ }
+ }
+ else
+ {
+ }
+ }
+
+ BitsChanged();
+}
+
+void MemoryImage::StretchBlt(Image* theImage, const Rect& theDestRect, const Rect& theSrcRect, const Rect& theClipRect, const Color& theColor, int theDrawMode, bool fastStretch)
+{
+ theImage->mDrawn = true;
+
+ Rect aDestRect;
+ FRect aSrcRect;
+
+ if (!StretchBltClipHelper(theSrcRect, theClipRect, theDestRect, aSrcRect, aDestRect))
+ return;
+
+ if (fastStretch)
+ FastStretchBlt(theImage, aDestRect, aSrcRect, theColor, theDrawMode);
+ else
+ SlowStretchBlt(theImage, aDestRect, aSrcRect, theColor, theDrawMode);
+}
+
+void MemoryImage::BltMatrixHelper(Image* theImage, float x, float y, const SexyMatrix3 &theMatrix, const Rect& theClipRect, const Color& theColor, int theDrawMode, const Rect &theSrcRect, void *theSurface, int theBytePitch, int thePixelFormat, bool blend)
+{
+ MemoryImage *anImage = dynamic_cast<MemoryImage*>(theImage);
+ if (anImage==NULL)
+ return;
+
+ float w2 = theSrcRect.mWidth/2.0f;
+ float h2 = theSrcRect.mHeight/2.0f;
+
+ float u0 = (float)theSrcRect.mX/theImage->mWidth;
+ float u1 = (float)(theSrcRect.mX + theSrcRect.mWidth)/theImage->mWidth;
+ float v0 = (float)theSrcRect.mY/theImage->mHeight;
+ float v1 = (float)(theSrcRect.mY + theSrcRect.mHeight)/theImage->mHeight;
+
+ SWHelper::XYZStruct aVerts[4] =
+ {
+ { -w2, -h2, u0, v0, 0xFFFFFFFF },
+ { w2, -h2, u1, v0, 0xFFFFFFFF },
+ { -w2, h2, u0, v1, 0xFFFFFFFF },
+ { w2, h2, u1, v1, 0xFFFFFFFF }
+ };
+
+ for (int i=0; i<4; i++)
+ {
+ SexyVector3 v(aVerts[i].mX, aVerts[i].mY, 1);
+ v = theMatrix*v;
+ aVerts[i].mX = v.x + x - 0.5f;
+ aVerts[i].mY = v.y + y - 0.5f;
+ }
+
+ SWHelper::SWDrawShape(aVerts, 4, anImage, theColor, theDrawMode, theClipRect, theSurface, theBytePitch, thePixelFormat, blend,false);
+}
+
+void MemoryImage::BltMatrix(Image* theImage, float x, float y, const SexyMatrix3 &theMatrix, const Rect& theClipRect, const Color& theColor, int theDrawMode, const Rect &theSrcRect, bool blend)
+{
+ theImage->mDrawn = true;
+
+ DWORD *aSurface = GetBits();
+ int aPitch = mWidth*4;
+ int aFormat = 0x8888;
+ if (mForcedMode && !mHasAlpha && !mHasTrans)
+ aFormat = 0x888;
+
+ BltMatrixHelper(theImage,x,y,theMatrix,theClipRect,theColor,theDrawMode,theSrcRect,aSurface,aPitch,aFormat,blend);
+ BitsChanged();
+}
+
+void MemoryImage::BltTrianglesTexHelper(Image *theTexture, const TriVertex theVertices[][3], int theNumTriangles, const Rect &theClipRect, const Color &theColor, int theDrawMode, void *theSurface, int theBytePitch, int thePixelFormat, float tx, float ty, bool blend)
+{
+ MemoryImage *anImage = dynamic_cast<MemoryImage*>(theTexture);
+// if (anImage==NULL)
+// return;
+
+ int aColor = theColor.ToInt();
+ for (int i=0; i<theNumTriangles; i++)
+ {
+ bool vertexColor = false;
+
+ SWHelper::XYZStruct aVerts[3];
+ for (int j=0; j<3; j++)
+ {
+ aVerts[j].mX = theVertices[i][j].x + tx;
+ aVerts[j].mY = theVertices[i][j].y + ty;
+ aVerts[j].mU = theVertices[i][j].u;
+ aVerts[j].mV = theVertices[i][j].v;
+ aVerts[j].mDiffuse = theVertices[i][j].color;
+
+ if (aVerts[j].mDiffuse!=0)
+ vertexColor = true;
+ }
+
+ SWHelper::SWDrawShape(aVerts, 3, anImage, theColor, theDrawMode, theClipRect, theSurface, theBytePitch, thePixelFormat, blend, vertexColor);
+ }
+
+}
+
+void MemoryImage::FillScanLinesWithCoverage(Span* theSpans, int theSpanCount, const Color& theColor, int theDrawMode, const BYTE* theCoverage, int theCoverX, int theCoverY, int theCoverWidth, int theCoverHeight)
+{
+ ulong* theBits = GetBits();
+ ulong src = theColor.ToInt();
+ for (int i = 0; i < theSpanCount; ++i)
+ {
+ Span* aSpan = &theSpans[i];
+ int x = aSpan->mX - theCoverX;
+ int y = aSpan->mY - theCoverY;
+
+ ulong* aDestPixels = &theBits[aSpan->mY*mWidth + aSpan->mX];
+ const BYTE* aCoverBits = &theCoverage[y*theCoverWidth+x];
+ for (int w = 0; w < aSpan->mWidth; ++w)
+ {
+ int cover = *aCoverBits++ + 1;
+ int a = (cover * theColor.mAlpha) >> 8;
+ int oma;
+ ulong dest = *aDestPixels;
+
+ if (a > 0)
+ {
+ int aDestAlpha = dest >> 24;
+ int aNewDestAlpha = aDestAlpha + ((255 - aDestAlpha) * a) / 255;
+
+ a = 255 * a / aNewDestAlpha;
+ oma = 256 - a;
+ *(aDestPixels++) = (aNewDestAlpha << 24) |
+ ((((dest & 0x0000FF) * oma + (src & 0x0000FF) * a) >> 8) & 0x0000FF) |
+ ((((dest & 0x00FF00) * oma + (src & 0x00FF00) * a) >> 8) & 0x00FF00) |
+ ((((dest & 0xFF0000) * oma + (src & 0xFF0000) * a) >> 8) & 0xFF0000);
+ }
+ }
+ }
+ BitsChanged();
+}
+
+void MemoryImage::BltTrianglesTex(Image *theTexture, const TriVertex theVertices[][3], int theNumTriangles, const Rect& theClipRect, const Color &theColor, int theDrawMode, float tx, float ty, bool blend)
+{
+ theTexture->mDrawn = true;
+
+ DWORD *aSurface = GetBits();
+
+ int aPitch = mWidth*4;
+ int aFormat = 0x8888;
+ if (mForcedMode && !mHasAlpha && !mHasTrans)
+ aFormat = 0x888;
+
+ BltTrianglesTexHelper(theTexture,theVertices,theNumTriangles,theClipRect,theColor,theDrawMode,aSurface,aPitch,aFormat,tx,ty,blend);
+ BitsChanged();
+}
+
+bool MemoryImage::Palletize()
+{
+ CommitBits();
+
+ if (mColorTable != NULL)
+ return true;
+
+ GetBits();
+
+ if (mBits == NULL)
+ return false;
+
+ mColorIndices = new uchar[mWidth*mHeight];
+ mColorTable = new ulong[256];
+
+ if (!Quantize8Bit(mBits, mWidth, mHeight, mColorIndices, mColorTable))
+ {
+ delete [] mColorIndices;
+ mColorIndices = NULL;
+
+ delete [] mColorTable;
+ mColorTable = NULL;
+
+ mWantPal = false;
+
+ return false;
+ }
+
+ delete [] mBits;
+ mBits = NULL;
+
+ delete [] mNativeAlphaData;
+ mNativeAlphaData = NULL;
+
+ mWantPal = true;
+
+ return true;
+}