Blame |
Last modification |
View Log
| RSS feed
#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;
}