Blame |
Last modification |
View Log
| RSS feed
#define INITGUID
#include "DDInterface.h"
#include "DDImage.h"
#include "D3DInterface.h"
#include "D3DTester.h"
#include "SexyAppBase.h"
#include "AutoCrit.h"
#include "Graphics.h"
#include "PerfTimer.h"
#include "Debug.h"
#include "DirectXErrorString.h"
#include "MemoryImage.h"
using namespace Sexy;
typedef HRESULT (WINAPI *DirectDrawCreateFunc)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter);
typedef HRESULT (WINAPI *DirectDrawCreateExFunc)(GUID FAR *lpGUID, LPVOID *lplpDD, REFIID iid, IUnknown FAR *pUnkOuter);
extern HMODULE gDDrawDLL;
static DirectDrawCreateFunc gDirectDrawCreateFunc = NULL;
static DirectDrawCreateExFunc gDirectDrawCreateExFunc = NULL;
DDInterface::DDInterface(SexyAppBase* theApp)
{
mApp = theApp;
mPrimarySurface = NULL;
mDrawSurface = NULL;
mSecondarySurface = NULL;
mScreenImage = NULL;
mDD = NULL;
mDD7 = NULL;
mRedAddTable = NULL;
mGreenAddTable = NULL;
mBlueAddTable = NULL;
mInitialized = false;
mVideoOnlyDraw = false;
mScanLineFailCount = 0;
//TODO: Standards, anyone?
mNextCursorX = 0;
mNextCursorY = 0;
mCursorX = 0;
mCursorY = 0;
mInRedraw = false;
//mCursorWidth = 54;
//mCursorHeight = 54;
mCursorWidth = 64;
mCursorHeight = 64;
mCursorImage = NULL;
mOldCursorArea = NULL;
mNewCursorArea = NULL;
mHasOldCursorArea = false;
mOldCursorArea = NULL;
mNewCursorArea = NULL;
mNewCursorAreaImage = NULL;
mOldCursorAreaImage = NULL;
mInitCount = 0;
mRefreshRate = 60;
mMillisecondsPerFrame = 1000/mRefreshRate;
mD3DInterface = new D3DInterface;
mIs3D = false;
mD3DTester = NULL;
gDirectDrawCreateFunc = (DirectDrawCreateFunc)GetProcAddress(gDDrawDLL,"DirectDrawCreate");
gDirectDrawCreateExFunc = (DirectDrawCreateExFunc)GetProcAddress(gDDrawDLL,"DirectDrawCreateEx");
}
DDInterface::~DDInterface()
{
delete [] mRedAddTable;
delete [] mGreenAddTable;
delete [] mBlueAddTable;
Cleanup();
delete mD3DInterface;
delete mD3DTester;
}
std::string DDInterface::ResultToString(int theResult)
{
switch (theResult)
{
case RESULT_OK:
return "RESULT_OK";
case RESULT_FAIL:
return "RESULT_FAIL";
case RESULT_DD_CREATE_FAIL:
return "RESULT_DD_CREATE_FAIL";
case RESULT_SURFACE_FAIL:
return "RESULT_SURFACE_FAIL";
case RESULT_EXCLUSIVE_FAIL:
return "RESULT_EXCLUSIVE_FAIL";
case RESULT_DISPCHANGE_FAIL:
return "RESULT_DISPCHANGE_FAIL";
case RESULT_INVALID_COLORDEPTH:
return "RESULT_INVALID_COLORDEPTH";
default:
return "RESULT_UNKNOWN";
}
}
bool DDInterface::GotDXError(HRESULT theResult, const char *theContext)
{
if (!SUCCEEDED(theResult))
{
std::string anError = GetDirectXErrorString(theResult);
mErrorString = StrFormat("%s: %s",theContext, anError.c_str());
return true;
}
else
return false;
}
DDImage* DDInterface::GetScreenImage()
{
return mScreenImage;
}
HRESULT DDInterface::CreateSurface(DDSURFACEDESC2 *theDesc, LPDIRECTDRAWSURFACE *theSurface, void*)
{
AutoCrit aCrit(mCritSect);
HRESULT aResult;
if (mDD7 != NULL)
{
LPDIRECTDRAWSURFACE7 aSurface;
aResult = mDD7->CreateSurface(theDesc, &aSurface, NULL);
if (!SUCCEEDED(aResult))
return aResult;
aResult = aSurface->QueryInterface(IID_IDirectDrawSurface, (LPVOID*)theSurface);
aSurface->Release();
if (!SUCCEEDED(aResult))
return aResult;
}
else
{
DDSURFACEDESC aDesc;
ZeroMemory(&aDesc,sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = theDesc->dwFlags;
aDesc.dwHeight = theDesc->dwHeight;
aDesc.dwWidth = theDesc->dwWidth;
aDesc.lPitch = theDesc->lPitch;
aDesc.dwBackBufferCount = theDesc->dwBackBufferCount;
aDesc.dwRefreshRate = theDesc->dwRefreshRate;
aDesc.dwAlphaBitDepth = theDesc->dwAlphaBitDepth;
aDesc.dwReserved = theDesc->dwReserved;
aDesc.lpSurface = theDesc->lpSurface;
aDesc.ddpfPixelFormat = theDesc->ddpfPixelFormat;
aDesc.ddsCaps.dwCaps = theDesc->ddsCaps.dwCaps;
aResult = mDD->CreateSurface(&aDesc, theSurface, NULL);
if (!SUCCEEDED(aResult))
return aResult;
}
// Make sure it's 32-bit or 16-bit
DDSURFACEDESC aDesc;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_PIXELFORMAT;
mPrimarySurface->GetSurfaceDesc(&aDesc);
#ifdef OPTIMIZE_SOFTWARE_DRAWING
// If things are stored blue low, green middle, red high, we can optimize a lot of our software rendering based on bit patterns.
// This of course does not matter for native data which is already in the correct order (and can be optimized similarly).
gOptimizeSoftwareDrawing = aDesc.ddpfPixelFormat.dwBBitMask < aDesc.ddpfPixelFormat.dwGBitMask && aDesc.ddpfPixelFormat.dwGBitMask < aDesc.ddpfPixelFormat.dwRBitMask;
#endif
int aNumBits = aDesc.ddpfPixelFormat.dwRGBBitCount;
if (aNumBits!=16 && aNumBits!=32)
{
(*theSurface)->Release();
*theSurface = NULL;
return DDERR_INVALIDPIXELFORMAT;
}
return aResult;
}
void DDInterface::ClearSurface(LPDIRECTDRAWSURFACE theSurface)
{
if (theSurface)
{
DDSURFACEDESC desc;
memset(&desc, 0, sizeof desc);
desc.dwSize = sizeof desc;
HRESULT hr = theSurface->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if ( DD_OK == hr )
{
DWORD pixelSize = desc.ddpfPixelFormat.dwRGBBitCount / 8;
unsigned char* p = (unsigned char*)desc.lpSurface;
for ( DWORD row = 0; row < desc.dwHeight; ++row )
{
memset(p, 0, pixelSize*desc.dwWidth);
p += desc.lPitch;
}
theSurface->Unlock(NULL);
}
}
}
bool DDInterface::Do3DTest(HWND theHWND)
{
if (mD3DTester == NULL)
{
if (mApp->mTest3D || mApp->mAutoEnable3D)
{
mD3DTester = new D3DTester;
mD3DTester->SetVidMemoryConstraints(mApp->mMinVidMemory3D, mApp->mRecommendedVidMemory3D);
mD3DTester->TestD3D(theHWND, mDD7);
if (mApp->mAutoEnable3D && mD3DTester->Is3DRecommended())
mIs3D = true;
if (!mD3DTester->Is3DSupported())
mIs3D = false;
if (mD3DTester->ResultsChanged() && !mD3DTester->Is3DRecommended())
mIs3D = false;
return true;
}
}
return false;
}
int DDInterface::Init(HWND theWindow, bool IsWindowed)
{
AutoCrit anAutoCrit(mCritSect);
mInitialized = false;
/*DDImageSet aReleasedImageSet;
DDImageSet::iterator anItr = mDDImageSet.begin();
while (anItr != mDDImageSet.end())
{
DDImage* aDDImage = *anItr;
if ((aDDImage->mSurface != NULL) || aDDImage->mWantDDSurface || !aDDImage->mKeepBits)
{
aDDImage->DeleteDDSurface();
aReleasedImageSet.insert(aDDImage);
}
++anItr;
}*/
Cleanup();
HRESULT aResult;
DDSURFACEDESC2 aDesc;
if (gDirectDrawCreateExFunc != NULL)
{
aResult = gDirectDrawCreateExFunc(NULL, (LPVOID*)&mDD7, IID_IDirectDraw7, NULL);
if (GotDXError(aResult, "DirectDrawCreateEx"))
return RESULT_DD_CREATE_FAIL;
aResult = mDD7->QueryInterface(IID_IDirectDraw, (LPVOID*)&mDD);
if (GotDXError(aResult, "QueryrInterface IID_IDirectDraw"))
return RESULT_DD_CREATE_FAIL;
}
else
{
aResult = gDirectDrawCreateFunc(NULL, &mDD, NULL);
}
if (Do3DTest(theWindow))
{
if (mD3DTester->ResultsChanged())
mApp->Done3dTesting();
}
RECT aRect;
GetClientRect(theWindow, &aRect);
mHWnd = theWindow;
mWidth = mApp->mWidth;
mHeight = mApp->mHeight;
mAspect.Set(mWidth, mHeight);
mDesktopWidth = GetSystemMetrics(SM_CXSCREEN);
mDesktopHeight = GetSystemMetrics(SM_CYSCREEN);
mDesktopAspect.Set(mDesktopWidth, mDesktopHeight);
mDisplayWidth = mWidth;
mDisplayHeight = mHeight;
mDisplayAspect = mAspect;
mPresentationRect = Rect( 0, 0, mWidth, mHeight );
mApp->mScreenBounds = mPresentationRect;
mFullscreenBits = mApp->mFullscreenBits;
mIsWindowed = IsWindowed;
mHasOldCursorArea = false;
OutputDebug(_S("Application requests %4lu x %4lu [%2d:%2d]\n"), mWidth, mHeight, mAspect.mNumerator, mAspect.mDenominator);
if (GotDXError(aResult, "DirectDrawCreate"))
return RESULT_DD_CREATE_FAIL;
if (IsWindowed)
{
OutputDebug(_S("Hack aspect is [%2d:%2d]\n"), mApp->mWindowAspect.mNumerator, mApp->mWindowAspect.mDenominator);
if ( mApp->mEnableWindowAspect && mAspect < mApp->mWindowAspect )
{
mIsWidescreen = true;
// Setup the window at the hack aspect,
// but with the height requested by the application.
mDisplayWidth = mHeight * mApp->mWindowAspect;
mDisplayHeight = mHeight;
mDisplayAspect = mApp->mWindowAspect;
// resize the window.
RECT rc;
POINT pt;
WINDOWINFO info;
::GetWindowInfo(theWindow, &info);
::GetClientRect(theWindow, &rc);
pt.x = rc.left;
pt.y = rc.top;
::ClientToScreen(theWindow, &pt);
rc.left = pt.x - (mDisplayWidth - mWidth) / 2;
rc.top = pt.y - (mDisplayHeight - mHeight) / 2;
rc.right = rc.left + mDisplayWidth;
rc.bottom = rc.top + mDisplayHeight;
::AdjustWindowRectEx(&rc, info.dwStyle, false, info.dwExStyle);
::MoveWindow(theWindow, max(0, rc.left), max(0, rc.top), rc.right-rc.left, rc.bottom-rc.top, false);
if ( mApp->mWidescreenAware )
{
mWidth = mDisplayWidth;
mHeight = mDisplayHeight;
mAspect = mDisplayAspect;
mPresentationRect.mWidth = mDisplayWidth;
mPresentationRect.mHeight = mDisplayHeight;
mPresentationRect.mX = 0;
mPresentationRect.mY = 0;
}
else
{
// Set the dest rect for drawing the back buffer to the center of
// the wide display.
mPresentationRect.mWidth = mWidth;
mPresentationRect.mHeight = mHeight;
mPresentationRect.mX = ( mDisplayWidth - mPresentationRect.mWidth ) / 2;
mPresentationRect.mY = 0;
}
}
OutputDebug(_S("Window is %4lu x %4lu [%2d:%2d]\n"), mDisplayWidth, mDisplayHeight, mDisplayAspect.mNumerator, mDisplayAspect.mDenominator);
aResult = mDD->SetCooperativeLevel(theWindow, DDSCL_NORMAL);
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_CAPS;
aDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if (mIs3D)
aDesc.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE;
aDesc.dwBackBufferCount = 1;
aResult = CreateSurface(&aDesc, &mPrimarySurface, NULL);
if (aResult==DDERR_INVALIDPIXELFORMAT) // check for non 16 or 32 bit primary surface
return RESULT_INVALID_COLORDEPTH;
else if (GotDXError(aResult, "CreateSurface Windowed Primary"))
return RESULT_SURFACE_FAIL;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
aDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
if (mIs3D)
aDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_3DDEVICE;
aDesc.dwWidth = mWidth;
aDesc.dwHeight = mHeight;
aResult = CreateSurface(&aDesc, &mDrawSurface, NULL);
if (GotDXError(aResult,"CreateSurface Windowed DrawSurface"))
return RESULT_SURFACE_FAIL;
IDirectDrawClipper* aClipper;
aResult = mDD->CreateClipper(0, &aClipper, NULL);
if (GotDXError(aResult,"CreateClipper Windowed")) return RESULT_FAIL;
// Associate the clipper with the window
aResult = aClipper->SetHWnd(0, theWindow);
if (SUCCEEDED(aResult))
aResult = mPrimarySurface->SetClipper(aClipper);
aClipper->Release();
}
else
{
OutputDebug(_S("Desktop is %4lu x %4lu [%2d:%2d]\n"), mDesktopWidth, mDesktopHeight, mDesktopAspect.mNumerator, mDesktopAspect.mDenominator);
if ( mIs3D && mAspect < mDesktopAspect )
{
mIsWidescreen = true;
// Set the display mode to the size of the desktop.
mDisplayWidth = mDesktopWidth;
mDisplayHeight = mDesktopHeight;
mDisplayAspect = mDesktopAspect;
if ( mApp->mWidescreenAware )
{
// Setup the draw buffer(s) at the same aspect ratio as the desktop,
// but with the height requested by the application.
mAspect = mDisplayAspect;
mWidth = mHeight * mAspect;
mPresentationRect.mWidth = mDisplayWidth;
mPresentationRect.mHeight = mDisplayHeight;
mPresentationRect.mX = 0;
mPresentationRect.mY = 0;
}
else
{
// Set the dest rect for drawing the back buffer to the center of
// the wide display.
mPresentationRect.mWidth = mWidth * mDisplayHeight / mHeight;
mPresentationRect.mHeight = mDisplayHeight;
mPresentationRect.mX = ( mDisplayWidth - mPresentationRect.mWidth ) / 2;
mPresentationRect.mY = 0;
}
}
OutputDebug(_S("Display is %4lu x %4lu [%2d:%2d]\n"), mDisplayWidth, mDisplayHeight, mDisplayAspect.mNumerator, mDisplayAspect.mDenominator);
aResult = mDD->SetCooperativeLevel(theWindow, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
if (GotDXError(aResult,"SetCooperativeLevel FullScreen"))
return RESULT_EXCLUSIVE_FAIL;
aResult = mDD->SetDisplayMode(mDisplayWidth, mDisplayHeight, mFullscreenBits);
if (GotDXError(aResult,"SetDisplayMode FullScreen"))
return RESULT_DISPCHANGE_FAIL;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
aDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP |
DDSCAPS_COMPLEX/* |
,DDSCAPS_FRONTBUFFER*/;
aDesc.dwBackBufferCount = 1;
if (mIs3D)
aDesc.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE;
aResult = CreateSurface(&aDesc, &mPrimarySurface, NULL);
if (GotDXError(aResult,"CreateSurface FullScreen Primary"))
return RESULT_SURFACE_FAIL;
DDSCAPS aCaps;
ZeroMemory(&aCaps,sizeof(aCaps));
aCaps.dwCaps = DDSCAPS_BACKBUFFER;
aResult = mPrimarySurface->GetAttachedSurface(&aCaps, &mSecondarySurface);
if (GotDXError(aResult,"GetAttachedSurface"))
return RESULT_SURFACE_FAIL;
if (mIsWidescreen)
{
ClearSurface(mPrimarySurface);
ClearSurface(mSecondarySurface);
}
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
aDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
if (mIs3D)
aDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_3DDEVICE;
aDesc.dwWidth = mWidth;
aDesc.dwHeight = mHeight;
aResult = CreateSurface(&aDesc, &mDrawSurface, NULL);
if (GotDXError(aResult, "CreateSurface FullScreen DrawSurface"))
return RESULT_SURFACE_FAIL;
IDirectDrawClipper* aClipper;
aResult = mDD->CreateClipper(0, &aClipper, NULL);
if (GotDXError(aResult,"CreateClipper FullScreen")) return RESULT_FAIL;
// Associate the clipper with the window
aResult = aClipper->SetHWnd(0, theWindow);
if (SUCCEEDED(aResult))
aResult = mPrimarySurface->SetClipper(aClipper);
aClipper->Release();
if (!mApp->mFullScreenPageFlip)
mDD->FlipToGDISurface();
}
OutputDebug(_S("Draw buffer is %4lu x %4lu [%2d:%2d]\n"), mWidth, mHeight, mAspect.mNumerator, mAspect.mDenominator);
if (FAILED(mDD->GetMonitorFrequency(&mRefreshRate)) || mRefreshRate<60)
{
mApp->mVSyncBroken = true;
mRefreshRate = 60;
}
if (mRefreshRate < 60)
{
mApp->mVSyncBroken = true;
mRefreshRate = 60;
}
else if (mRefreshRate > 100) // We must have at least 1 Update per UpdateF for demo compatibility
{
mApp->mVSyncBroken = true;
mRefreshRate = 100;
}
mMillisecondsPerFrame = 1000/mRefreshRate;
// Create the images needed for cursor stuff
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
aDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
aDesc.dwWidth = mCursorWidth;
aDesc.dwHeight = mCursorHeight;
aResult = CreateSurface(&aDesc, &mOldCursorArea, NULL);
if (GotDXError(aResult, "CreateSurface OldCursorArea"))
return RESULT_SURFACE_FAIL;
aResult = CreateSurface(&aDesc, &mNewCursorArea, NULL);
if (GotDXError(aResult, "CreateSurface NewCursorArea"))
return RESULT_SURFACE_FAIL;
mOldCursorAreaImage = new DDImage(this);
mOldCursorAreaImage->SetSurface(mOldCursorArea);
mOldCursorAreaImage->SetImageMode(false, false);
mNewCursorAreaImage = new DDImage(this);
mNewCursorAreaImage->SetSurface(mNewCursorArea);
mNewCursorAreaImage->SetImageMode(false, false);
// Get data from the primary surface
if (mPrimarySurface != NULL)
{
DDSURFACEDESC aDesc;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
HRESULT aResult = mPrimarySurface->GetSurfaceDesc(&aDesc);
if ((aDesc.ddpfPixelFormat.dwRGBBitCount != 16) &&
(aDesc.ddpfPixelFormat.dwRGBBitCount != 32))
return RESULT_INVALID_COLORDEPTH;
mRGBBits = aDesc.ddpfPixelFormat.dwRGBBitCount;
mRedMask = aDesc.ddpfPixelFormat.dwRBitMask;
mGreenMask = aDesc.ddpfPixelFormat.dwGBitMask;
mBlueMask = aDesc.ddpfPixelFormat.dwBBitMask;
int i;
for (i = 32; i >= 0; i--)
{
if (((mRedMask >> i) & 1) != 0)
mRedShift = i;
if (((mGreenMask >> i) & 1) != 0)
mGreenShift = i;
if (((mBlueMask >> i) & 1) != 0)
mBlueShift = i;
}
for (i = 0; i < 32; i++)
{
if ((i+mRedShift < 32) && ((mRedMask >> (i+mRedShift)) != 0))
mRedBits = i+1;
if ((i+mGreenShift < 32) && ((mGreenMask >> (i+mGreenShift)) != 0))
mGreenBits = i+1;
if ((i+mBlueShift < 32) && ((mBlueMask >> (i+mBlueShift)) != 0))
mBlueBits = i+1;
}
delete [] mRedAddTable;
delete [] mGreenAddTable;
delete [] mBlueAddTable;
int aMaxR = (1<<mRedBits) - 1;
int aMaxG = (1<<mGreenBits) - 1;
int aMaxB = (1<<mBlueBits) - 1;
mRedAddTable = new int[aMaxR*2+1];
mGreenAddTable = new int[aMaxG*2+1];
mBlueAddTable = new int[aMaxB*2+1];
for (i = 0; i < aMaxR*2+1; i++)
mRedAddTable[i] = min(i, aMaxR);
for (i = 0; i < aMaxG*2+1; i++)
mGreenAddTable[i] = min(i, aMaxG);
for (i = 0; i < aMaxB*2+1; i++)
mBlueAddTable[i] = min(i, aMaxB);
// Create the tables that we will use to convert from
// internal color representation to surface representation
for (i = 0; i < 256; i++)
{
mRedConvTable[i] = ((i * mRedMask) / 255) & mRedMask;
mGreenConvTable[i] = ((i * mGreenMask) / 255) & mGreenMask;
mBlueConvTable[i] = ((i * mBlueMask) / 255) & mBlueMask;
}
}
// Generate DDSurfaces for all our... image things
/*anItr = aReleasedImageSet.begin();
while (anItr != aReleasedImageSet.end())
{
DDImage* aDDImage = *anItr;
DDImageSet::iterator aFindItr = mDDImageSet.find(aDDImage);
if (aFindItr != mDDImageSet.end())
{
if (mIs3D)
{
if (aDDImage->mWantPal)
aDDImage->mWantPal = aDDImage->Palletize();
}
else
{
//if (aDDImage->mOnlyKeepDDSurface)
// aDDImage->OnlyKeepDDSurface();
//else if (aDDImage->mWantDDSurface)
// aDDImage->GenerateDDSurface();
}
aDDImage->GenerateExtraBuffers();
}
++anItr;
}*/
SetVideoOnlyDraw(mVideoOnlyDraw);
if(mIs3D)
{
if(!mD3DInterface->InitFromDDInterface(this))
{
mErrorString = "3D init error: ";
mErrorString += D3DInterface::mErrorString;
return RESULT_3D_FAIL;
}
}
mInitCount++;
mInitialized = true;
return RESULT_OK;
}
void DDInterface::SetVideoOnlyDraw(bool videoOnlyDraw)
{
AutoCrit anAutoCrit(mCritSect);
mVideoOnlyDraw = videoOnlyDraw;
if (mSecondarySurface == NULL)
{
DDSURFACEDESC2 aDesc;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
aDesc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
aDesc.dwWidth = mWidth;
aDesc.dwHeight = mHeight;
HRESULT aResult = CreateSurface(&aDesc, &mSecondarySurface, NULL);
if (FAILED(aResult))
mVideoOnlyDraw = false;
}
bool useSecondary = mVideoOnlyDraw;
delete mScreenImage;
mScreenImage = new DDImage(this);
mScreenImage->SetSurface(useSecondary ? mSecondarySurface : mDrawSurface);
mScreenImage->mNoLock = mVideoOnlyDraw;
mScreenImage->mVideoMemory = mVideoOnlyDraw;
mScreenImage->SetImageMode(false, false);
}
void DDInterface::RemapMouse(int& theX, int& theY)
{
if (mInitialized)
{
theX = ( theX - mPresentationRect.mX ) * mWidth / mPresentationRect.mWidth;
theY = ( theY - mPresentationRect.mY ) * mHeight / mPresentationRect.mHeight;
}
}
ulong DDInterface::GetColorRef(ulong theRGB)
{
DDSURFACEDESC aDesc;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
HRESULT aResult = mPrimarySurface->GetSurfaceDesc(&aDesc);
BYTE bRed = (BYTE) ((theRGB >> 16) & 0xFF);
BYTE bGreen = (BYTE) ((theRGB >> 8) & 0xFF);
BYTE bBlue = (BYTE) ((theRGB ) & 0xFF);
ulong aColor;
aColor = ((DWORD(((LONGLONG)bRed * (LONGLONG)aDesc.ddpfPixelFormat.dwRBitMask) / 255) & aDesc.ddpfPixelFormat.dwRBitMask) |
(DWORD(((LONGLONG)bGreen * (LONGLONG)aDesc.ddpfPixelFormat.dwGBitMask) / 255) & aDesc.ddpfPixelFormat.dwGBitMask) |
(DWORD(((LONGLONG)bBlue * (LONGLONG)aDesc.ddpfPixelFormat.dwBBitMask) / 255) & aDesc.ddpfPixelFormat.dwBBitMask));
return aColor;
}
void DDInterface::AddDDImage(DDImage* theDDImage)
{
AutoCrit anAutoCrit(mCritSect);
mDDImageSet.insert(theDDImage);
}
void DDInterface::RemoveDDImage(DDImage* theDDImage)
{
AutoCrit anAutoCrit(mCritSect);
DDImageSet::iterator anItr = mDDImageSet.find(theDDImage);
if (anItr != mDDImageSet.end())
mDDImageSet.erase(anItr);
}
void DDInterface::Remove3DData(MemoryImage* theImage) // for 3d texture cleanup
{
mD3DInterface->RemoveMemoryImage(theImage);
}
void DDInterface::Cleanup()
{
AutoCrit anAutoCrit(mCritSect);
mInitialized = false;
mD3DInterface->Cleanup();
if (mOldCursorAreaImage != NULL)
{
delete mOldCursorAreaImage;
mOldCursorAreaImage = NULL;
}
if (mNewCursorAreaImage != NULL)
{
delete mNewCursorAreaImage;
mNewCursorAreaImage = NULL;
}
if (mOldCursorArea != NULL)
{
mOldCursorArea->Release();
mOldCursorArea = NULL;
}
if (mNewCursorArea != NULL)
{
mNewCursorArea->Release();
mNewCursorArea = NULL;
}
if (mScreenImage != NULL)
{
delete mScreenImage;
mScreenImage = NULL;
}
if (mDrawSurface != NULL)
{
mDrawSurface->Release();
mDrawSurface = NULL;
}
if (mSecondarySurface != NULL)
{
mSecondarySurface->Release();
mSecondarySurface = NULL;
}
if (mPrimarySurface != NULL)
{
mPrimarySurface->Release();
mPrimarySurface = NULL;
}
if (mDD != NULL)
{
mDD->SetCooperativeLevel(mHWnd, DDSCL_NORMAL);
mDD->Release();
mDD = NULL;
}
if (mDD7 != NULL)
{
mDD7->Release();
mDD7 = NULL;
}
}
bool DDInterface::CopyBitmap(LPDIRECTDRAWSURFACE theSurface, HBITMAP theBitmap, int theX, int theY, int theWidth, int theHeight)
{
AutoCrit anAutoCrit(mCritSect);
HRESULT hr;
if (theBitmap == NULL || theSurface == NULL) return false;
// Make sure this surface is restored.
theSurface->Restore();
// Get size of the bitmap
BITMAP bmBitmap;
GetObject(theBitmap, sizeof(bmBitmap), &bmBitmap);
theWidth = (theWidth == 0) ? bmBitmap.bmWidth : theWidth;
theHeight = (theHeight == 0) ? bmBitmap.bmHeight : theHeight;
DDSURFACEDESC aDesc;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
hr = theSurface->GetSurfaceDesc(&aDesc);
if (FAILED(hr)) return false;
// Create memory DC
HDC hdcImage = CreateCompatibleDC(NULL);
if (hdcImage != NULL)
{
// Select bitmap into memory DC
HBITMAP anOldBitmap = (HBITMAP)SelectObject(hdcImage, theBitmap);
// Get surface DC
HDC hdc;
hr = theSurface->GetDC(&hdc);
if (SUCCEEDED(hr))
{
// Copy the bitmap. Use BitBlt, if possible, otherwise use
// StretchBlt
if (theWidth == aDesc.dwWidth && theHeight == aDesc.dwHeight)
{
BitBlt(hdc, 0, 0, theWidth, theHeight, hdcImage, theX, theY, SRCCOPY);
}
else
{
StretchBlt(hdc, 0, 0, aDesc.dwWidth, aDesc.dwHeight, hdcImage,
theX, theY, theWidth, theHeight, SRCCOPY);
}
// Release surface DC
theSurface->ReleaseDC(hdc);
}
// Select old bitmap into the memory DC and delete the DC
SelectObject(hdcImage, anOldBitmap);
DeleteDC(hdcImage);
}
else return false;
return true;
}
extern std::fstream gStreamThing;
bool DDInterface::Redraw(Rect* theClipRect)
{
AutoCrit anAutoCrit(mCritSect);
if (!mInitialized)
return false;
DDBLTFX aBltFX;
ZeroMemory(&aBltFX, sizeof(aBltFX));
aBltFX.dwSize = sizeof(aBltFX);
mInRedraw = true;
if(mIs3D)
{
if (!mD3DInterface->mErrorString.empty())
{
mInRedraw = false;
mIs3D = false;
return false;
}
mD3DInterface->Flush();
}
RECT aDestRect;
RECT aSrcRect;
if (NULL == theClipRect || mIsWidescreen)
{
// ClipRect cannot be supported when the draw surface and
// primary surface are not the same size in widescreen mode.
aDestRect = mPresentationRect.ToRECT();
aSrcRect = Rect(0, 0, mWidth, mHeight).ToRECT();
}
else
{
aDestRect = theClipRect->ToRECT();
aSrcRect = theClipRect->ToRECT();
}
if ( mIsWidescreen )
{
aBltFX.dwDDFX = DDBLTFX_ARITHSTRETCHY;
}
POINT aPoint = {0, 0};
ClientToScreen(mHWnd, &aPoint);
OffsetRect(&aDestRect, aPoint.x, aPoint.y);
DDSURFACEDESC aDesc;
ZeroMemory(&aDesc,sizeof(&aDesc));
aDesc.dwSize=sizeof(aDesc);
mDrawSurface->Lock(NULL,&aDesc,DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY ,0);
mDrawSurface->Unlock(NULL);
if (mIsWindowed)
{
HRESULT aResult;
//DWORD aScanLine;
//mDD->GetScanLine(&aScanLine);
int aScreenHeight = GetSystemMetrics(SM_CYSCREEN);
if (!mVideoOnlyDraw)
{
mCursorX = mNextCursorX;
mCursorY = mNextCursorY;
DrawCursorTo(mDrawSurface, false);
if ((mApp->mWaitForVSync) && (!mApp->mSoftVSyncWait))
{
bool scanLineFail = false;
if (mScanLineFailCount >= 3)
scanLineFail = true;
if (!scanLineFail)
{
int aHalfMarkClient = mApp->mHeight / 2;
int aHalfMarkScreen = aDestRect.top + aHalfMarkClient;
int aBotMarkScreen = aDestRect.top + mHeight;
DWORD aScanLine = 0x7FFFFFFF;
bool wasLess = false;
DWORD aTopStartTick = GetTickCount();
for (;;)
{
aResult = mDD->GetScanLine(&aScanLine);
if (aResult == DD_OK)
{
// Wait until we scan below half way on the window
int aHalfMarkDist = aHalfMarkScreen - aScanLine;
if ((aHalfMarkDist <= 0) || ((int) aScanLine >= aScreenHeight))
{
if (wasLess)
break;
}
else
{
wasLess = true;
}
}
else
{
if (aResult == DDERR_VERTICALBLANKINPROGRESS )
{
if (wasLess)
break;
}
else
{
scanLineFail = true;
break;
}
}
DWORD aTickNow = GetTickCount();
if (aTickNow - aTopStartTick >= 200)
{
// It shouldn't take this long
scanLineFail = true;
break;
}
}
if (!scanLineFail)
{
mScanLineFailCount = 0;
RECT aTopDestRect = {aDestRect.left, aDestRect.top, aDestRect.right, aHalfMarkScreen};
RECT aTopSrcRect = {aSrcRect.left, aSrcRect.top, aSrcRect.right, aHalfMarkClient};
aResult = mPrimarySurface->Blt(&aTopDestRect, mDrawSurface, &aTopSrcRect, DDBLT_WAIT, &aBltFX);
DWORD aLastScanLine = aScanLine;
for (;;)
{
if (SUCCEEDED(mDD->GetScanLine(&aScanLine)))
{
// Wait until we scan below the bottom of the window
int aHalfMarkDist = aBotMarkScreen - aScanLine;
if ((aScanLine < aLastScanLine) || (aHalfMarkDist <= 0))
break;
}
}
RECT aBotDestRect = {aDestRect.left, aHalfMarkScreen, aDestRect.right, aDestRect.bottom};
RECT aBotSrcRect = {aSrcRect.left, aHalfMarkClient, aSrcRect.right, aSrcRect.bottom};
aResult = mPrimarySurface->Blt(&aBotDestRect, mDrawSurface, &aBotSrcRect, DDBLT_WAIT, &aBltFX);
}
else
{
mScanLineFailCount++;
}
}
if (scanLineFail)
{
mDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
aResult = mPrimarySurface->Blt(&aDestRect, mDrawSurface, &aSrcRect, DDBLT_WAIT, &aBltFX);
}
}
else
{
aResult = mPrimarySurface->Blt(&aDestRect, mDrawSurface, &aSrcRect, DDBLT_WAIT, &aBltFX);
}
if (mHasOldCursorArea)
{
// Restore from the drawn surface, incase we don't do a redraw
// of the drawn surface by next Redraw
RestoreOldCursorAreaFrom(mDrawSurface, false);
// Set it back to true so it gets removed from the primary
// surface when we move the mouse
mHasOldCursorArea = true;
}
}
else
{
if ((mApp->mWaitForVSync) && (!mApp->mSoftVSyncWait))
mDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
mCursorX = mNextCursorX;
mCursorY = mNextCursorY;
DrawCursorTo(mSecondarySurface, true);
aResult = mPrimarySurface->Blt(&aDestRect, mSecondarySurface, &aSrcRect, DDBLT_WAIT, &aBltFX);
}
mInRedraw = false;
return !GotDXError(aResult,"Redraw Windowed");
}
else
{
// Don't flip away from the GDI surface during the TryMedia purchasing process
if (!mApp->mNoDefer && mApp->mFullScreenPageFlip)
{
if (!mVideoOnlyDraw)
HRESULT aResult = mSecondarySurface->Blt(&aDestRect, mDrawSurface, &aSrcRect, DDBLT_WAIT, &aBltFX);
mCursorX = mNextCursorX;
mCursorY = mNextCursorY;
DrawCursorTo(mSecondarySurface, true);
HRESULT aResult = mPrimarySurface->Flip(NULL, DDFLIP_WAIT);
mInRedraw = false;
return !GotDXError(aResult,"Redraw FullScreen Flip");
}
else
{
HRESULT aResult = mPrimarySurface->Blt(&aDestRect, mDrawSurface, &aSrcRect, DDBLT_WAIT, &aBltFX);
mInRedraw = false;
return !GotDXError(aResult,"Redraw FullScreen Blt");
}
}
}
void DDInterface::RestoreOldCursorAreaFrom(LPDIRECTDRAWSURFACE theSurface, bool adjust)
{
if ((mHasOldCursorArea) && (mPrimarySurface != NULL))
{
Rect aSexyScreenRect(
mCursorX - (mCursorWidth / 2),
mCursorY - (mCursorHeight / 2),
mCursorWidth,
mCursorHeight);
Rect aClippedScreenRect = aSexyScreenRect.Intersection(Rect(0, 0, mWidth, mHeight));
Rect aSexyLocalRect(
aClippedScreenRect.mX - aSexyScreenRect.mX,
aClippedScreenRect.mY - aSexyScreenRect.mY,
aClippedScreenRect.mWidth,
aClippedScreenRect.mHeight);
if (adjust)
{
POINT aPoint = {0, 0};
ClientToScreen(mHWnd, &aPoint);
aClippedScreenRect.Offset(aPoint.x, aPoint.y);
}
RECT aLocalRect = aSexyLocalRect.ToRECT();
RECT aScreenRect = aClippedScreenRect.ToRECT();
DDBLTFX aBltFX;
ZeroMemory(&aBltFX, sizeof(aBltFX));
aBltFX.dwSize = sizeof(aBltFX);
// From mNewCursorArea to theSurface
HRESULT aResult = theSurface->Blt(&aScreenRect, mOldCursorArea, &aLocalRect, DDBLT_WAIT, &aBltFX);
mHasOldCursorArea = false;
}
}
void DDInterface::DrawCursorTo(LPDIRECTDRAWSURFACE theSurface, bool adjust)
{
if ((mCursorImage != NULL) && (mPrimarySurface != NULL))
{
DDSURFACEDESC aDesc;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
HRESULT aResult = mPrimarySurface->GetSurfaceDesc(&aDesc);
Rect aDestSurfaceRect(0, 0, aDesc.dwWidth, aDesc.dwHeight);
Rect aSexyScreenRect(
mCursorX - (mCursorWidth / 2),
mCursorY - (mCursorHeight / 2),
mCursorWidth,
mCursorHeight);
Rect aClippedScreenRect = aSexyScreenRect.Intersection(mPresentationRect);
Rect aSexyLocalRect(
aClippedScreenRect.mX - aSexyScreenRect.mX,
aClippedScreenRect.mY - aSexyScreenRect.mY,
aClippedScreenRect.mWidth,
aClippedScreenRect.mHeight);
if (adjust)
{
POINT aPoint = {0, 0};
ClientToScreen(mHWnd, &aPoint);
aClippedScreenRect.Offset(aPoint.x, aPoint.y);
}
RECT aLocalRect = aSexyLocalRect.ToRECT();
RECT aScreenRect = aClippedScreenRect.ToRECT();
DDBLTFX aBltFX;
ZeroMemory(&aBltFX, sizeof(aBltFX));
aBltFX.dwSize = sizeof(aBltFX);
// From theSurface to mOldCursorArea
aResult = mOldCursorArea->Blt(&aLocalRect, theSurface, &aScreenRect, DDBLT_WAIT, &aBltFX);
if (aResult != DD_OK)
{
// Try to clip it now. We don't ALWAYS want to clip it, though
Rect aPrevRect = aClippedScreenRect;
aClippedScreenRect = aClippedScreenRect.Intersection(aDestSurfaceRect);
aSexyLocalRect.mX += (aClippedScreenRect.mX - aPrevRect.mX);
aSexyLocalRect.mY += (aClippedScreenRect.mY - aPrevRect.mY);
aSexyLocalRect.mWidth = aClippedScreenRect.mWidth;
aSexyLocalRect.mHeight = aClippedScreenRect.mHeight;
aLocalRect = aSexyLocalRect.ToRECT();
aScreenRect = aClippedScreenRect.ToRECT();
aResult = mOldCursorArea->Blt(&aLocalRect, theSurface, &aScreenRect, DDBLT_WAIT, &aBltFX);
//DBG_ASSERT(aResult == DD_OK);
}
mHasOldCursorArea = aResult == DD_OK;
// Kindof a hack, since we only use this for mDrawSurace
if (theSurface == mDrawSurface && !mIs3D)
{
// Draw directly to the screen image, instead of indirectly through mNewCursorArea
Graphics g(mScreenImage);
g.DrawImage(mCursorImage,
mCursorX - (mCursorWidth / 2) + (mCursorWidth - mCursorImage->mWidth)/2,
mCursorY - (mCursorHeight / 2) + (mCursorHeight - mCursorImage->mHeight)/2);
}
else
{
// From mOldCursorArea to mNewCursorArea
aResult = mNewCursorArea->Blt(&aLocalRect, mOldCursorArea, &aLocalRect, DDBLT_WAIT, &aBltFX);
// Draw image to mNewCursorAreaImage
Graphics aNewCursorAreaG(mNewCursorAreaImage);
aNewCursorAreaG.DrawImage(mCursorImage,
(mCursorWidth - mCursorImage->mWidth)/2,
(mCursorHeight - mCursorImage->mHeight)/2);
// From mNewCursorArea to theSurface
aResult = theSurface->Blt(&aScreenRect, mNewCursorArea, &aLocalRect, DDBLT_WAIT, &aBltFX);
}
}
else
mHasOldCursorArea = false;
}
void DDInterface::MoveCursorTo(LPDIRECTDRAWSURFACE theSurface, bool adjust, int theNewCursorX, int theNewCursorY)
{
DBG_ASSERT(mHasOldCursorArea);
if ((mCursorImage != NULL) && (mPrimarySurface != NULL))
{
DDSURFACEDESC aDesc;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
HRESULT aResult = mPrimarySurface->GetSurfaceDesc(&aDesc);
Rect aDestSurfaceRect(0, 0, aDesc.dwWidth, aDesc.dwHeight);
// OLD RECTANGLES
Rect aSexyScreenRect(
mCursorX - (mCursorWidth / 2),
mCursorY - (mCursorHeight / 2),
mCursorWidth,
mCursorHeight);
Rect aClippedScreenRect = aSexyScreenRect.Intersection(mPresentationRect);
Rect aSexyLocalRect(
aClippedScreenRect.mX - aSexyScreenRect.mX,
aClippedScreenRect.mY - aSexyScreenRect.mY,
aClippedScreenRect.mWidth,
aClippedScreenRect.mHeight);
if (adjust)
{
POINT aPoint = {0, 0};
ClientToScreen(mHWnd, &aPoint);
aClippedScreenRect.Offset(aPoint.x, aPoint.y);
//aClippedScreenRect = aClippedScreenRect.Intersection(aDestSurfaceRect);
}
aSexyLocalRect.mWidth = aClippedScreenRect.mWidth;
aSexyLocalRect.mHeight = aClippedScreenRect.mHeight;
RECT aLocalRect = aSexyLocalRect.ToRECT();
RECT aScreenRect = aClippedScreenRect.ToRECT();
// NEW RECTANGLES
Rect aNewSexyScreenRect(
theNewCursorX - (mCursorWidth / 2),
theNewCursorY - (mCursorHeight / 2),
mCursorWidth,
mCursorHeight);
Rect aNewClippedScreenRect = aNewSexyScreenRect.Intersection(mPresentationRect);
Rect aNewSexyLocalRect(
aNewClippedScreenRect.mX - aNewSexyScreenRect.mX,
aNewClippedScreenRect.mY - aNewSexyScreenRect.mY,
aNewClippedScreenRect.mWidth,
aNewClippedScreenRect.mHeight);
if (adjust)
{
POINT aPoint = {0, 0};
ClientToScreen(mHWnd, &aPoint);
aNewClippedScreenRect.Offset(aPoint.x, aPoint.y);
//aNewClippedScreenRect = aNewClippedScreenRect.Intersection(aDestSurfaceRect);
}
aNewSexyLocalRect.mWidth = aNewClippedScreenRect.mWidth;
aNewSexyLocalRect.mHeight = aNewClippedScreenRect.mHeight;
RECT aNewLocalRect = aNewSexyLocalRect.ToRECT();
RECT aNewScreenRect = aNewClippedScreenRect.ToRECT();
// Do drawing stuff now
DDBLTFX aBltFX;
ZeroMemory(&aBltFX, sizeof(aBltFX));
aBltFX.dwSize = sizeof(aBltFX);
// From theSurface to mNewCursorArea
// It may still have some of the old cursor on it though, since we haven't restored
// that area yet
aResult = mNewCursorArea->Blt(&aNewLocalRect, theSurface, &aNewScreenRect, DDBLT_WAIT, &aBltFX);
if (aResult != DD_OK)
{
// Try to clip it now. We don't ALWAYS want to clip it, though
Rect aPrevRect = aNewClippedScreenRect;
aNewClippedScreenRect = aNewClippedScreenRect.Intersection(aDestSurfaceRect);
aNewSexyLocalRect.mX += (aNewClippedScreenRect.mX - aPrevRect.mX);
aNewSexyLocalRect.mY += (aNewClippedScreenRect.mY - aPrevRect.mY);
aNewSexyLocalRect.mWidth = aNewClippedScreenRect.mWidth;
aNewSexyLocalRect.mHeight = aNewClippedScreenRect.mHeight;
aNewLocalRect = aNewSexyLocalRect.ToRECT();
aNewScreenRect = aNewClippedScreenRect.ToRECT();
aResult = mNewCursorArea->Blt(&aNewLocalRect, theSurface, &aNewScreenRect, DDBLT_WAIT, &aBltFX);
//DBG_ASSERT(aResult == DD_OK);
}
//DBG_ASSERT(aResult == DD_OK);
// Figure out the overlapping area from the source
Rect aCursorAreaRect(0, 0, mCursorWidth, mCursorHeight);
Rect aSexyOrigSrcAreaRect(aCursorAreaRect);
aSexyOrigSrcAreaRect.Offset(theNewCursorX - mCursorX, theNewCursorY - mCursorY);
Rect aSexySrcAreaRect = aSexyOrigSrcAreaRect.Intersection(aCursorAreaRect);
// Does the new cursor area overlap with the old one?
if ((aSexySrcAreaRect.mWidth > 0) || (aSexySrcAreaRect.mHeight > 0))
{
Rect aSexyDestAreaRect(
aSexySrcAreaRect.mX - aSexyOrigSrcAreaRect.mX,
aSexySrcAreaRect.mY - aSexyOrigSrcAreaRect.mY,
aSexySrcAreaRect.mWidth, aSexySrcAreaRect.mHeight);
RECT aSrcAreaRect = aSexySrcAreaRect.ToRECT();
RECT aDestAreaRect = aSexyDestAreaRect.ToRECT();
// Restore old area from new area
// This will give us our new pure OLD buffer
mNewCursorArea->Blt(&aDestAreaRect, mOldCursorArea, &aSrcAreaRect, DDBLT_WAIT, &aBltFX);
//DBG_ASSERT(aResult == DD_OK);
// Draw offset image to mOldCursorAreaImage. This is to avoid flicker
Graphics aOldCursorAreaG(mOldCursorAreaImage);
aOldCursorAreaG.DrawImage(mCursorImage,
theNewCursorX - mCursorX + (mCursorWidth - mCursorImage->mWidth)/2,
theNewCursorY - mCursorY + (mCursorHeight - mCursorImage->mHeight)/2);
}
// Restore the old cursor area
aResult = theSurface->Blt(&aScreenRect, mOldCursorArea, &aLocalRect, DDBLT_WAIT, &aBltFX);
//DBG_ASSERT(aResult == DD_OK);
// The screen is now PURE and restored
// Move the new cursor area to the old one, since this is what we will have to
// use to redraw the old area
RECT aFullAreaRect = {0, 0, mCursorWidth, mCursorHeight};
aResult = mOldCursorArea->Blt(&aFullAreaRect, mNewCursorArea, &aFullAreaRect, DDBLT_WAIT, &aBltFX);
//DBG_ASSERT(aResult == DD_OK);
// Draw image to mNewCursorAreaImage, preparing to draw it to the screen
Graphics aNewCursorAreaG(mNewCursorAreaImage);
aNewCursorAreaG.DrawImage(mCursorImage,
(mCursorWidth - mCursorImage->mWidth)/2,
(mCursorHeight - mCursorImage->mHeight)/2);
// From mNewCursorArea to theSurface
aResult = theSurface->Blt(&aNewScreenRect, mNewCursorArea, &aNewLocalRect, DDBLT_WAIT, &aBltFX);
//DBG_ASSERT(aResult == DD_OK);
// The cursor is now fully moved
mCursorX = theNewCursorX;
mCursorY = theNewCursorY;
}
else
mHasOldCursorArea = false;
}
bool DDInterface::SetCursorImage(Image* theImage)
{
AutoCrit anAutoCrit(mCritSect);
if (mCursorImage != theImage)
{
// Wait until next Redraw or cursor move to draw new cursor
mCursorImage = theImage;
return true;
}
else
return false;
}
void DDInterface::SetCursorPos(int theCursorX, int theCursorY)
{
mNextCursorX = theCursorX;
mNextCursorY = theCursorY;
if (mInRedraw)
return;
AutoCrit anAutoCrit(mCritSect);
if (mHasOldCursorArea)
{
MoveCursorTo(mPrimarySurface, true, theCursorX, theCursorY);
}
else
{
mCursorX = theCursorX;
mCursorY = theCursorY;
DrawCursorTo(mPrimarySurface, true);
}
}