// DX.cpp: implementation of the CDXDraw class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DX.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CDXDraw

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

LPCTSTR GetDDErrorString(HRESULT hr)
{
	switch (hr)
	{
		case DDERR_ALREADYINITIALIZED :			return "DDERR_ALREADYINITIALIZED";
		case DDERR_BLTFASTCANTCLIP :			return "DDERR_BLTFASTCANTCLIP";
		case DDERR_CANNOTATTACHSURFACE :		return "DDERR_CANNOTATTACHSURFACE";
		case DDERR_CANNOTDETACHSURFACE :		return "DDERR_CANNOTDETACHSURFACE";
		case DDERR_CANTCREATEDC :				return "DDERR_CANTCREATEDC";
		case DDERR_CANTDUPLICATE :				return "DDERR_CANTDUPLICATE";
		case DDERR_CANTLOCKSURFACE :			return "DDERR_CANTLOCKSURFACE";
		case DDERR_CANTPAGELOCK :				return "DDERR_CANTPAGELOCK";
		case DDERR_CANTPAGEUNLOCK :				return "DDERR_CANTPAGEUNLOCK";
		case DDERR_CLIPPERISUSINGHWND :			return "DDERR_CLIPPERISUSINGHWND";
		case DDERR_COLORKEYNOTSET :				return "DDERR_COLORKEYNOTSET";
		case DDERR_CURRENTLYNOTAVAIL :			return "DDERR_CURRENTLYNOTAVAIL";
		case DDERR_DCALREADYCREATED :			return "DDERR_DCALREADYCREATED";
		case DDERR_DEVICEDOESNTOWNSURFACE :		return "DDERR_DEVICEDOESNTOWNSURFACE";
		case DDERR_DIRECTDRAWALREADYCREATED :	return "DDERR_DIRECTDRAWALREADYCREATED";
		case DDERR_EXCEPTION :					return "DDERR_EXCEPTION";
		case DDERR_EXCLUSIVEMODEALREADYSET :	return "DDERR_EXCLUSIVEMODEALREADYSET";
		case DDERR_GENERIC :					return "DDERR_GENERIC";
		case DDERR_HEIGHTALIGN :				return "DDERR_HEIGHTALIGN";
		case DDERR_HWNDALREADYSET :				return "DDERR_HWNDALREADYSET";
		case DDERR_HWNDSUBCLASSED :				return "DDERR_HWNDSUBCLASSED";
		case DDERR_IMPLICITLYCREATED :			return "DDERR_IMPLICITLYCREATED";
		case DDERR_INCOMPATIBLEPRIMARY :		return "DDERR_INCOMPATIBLEPRIMARY";
		case DDERR_INVALIDCAPS :				return "DDERR_INVALIDCAPS";
		case DDERR_INVALIDCLIPLIST :			return "DDERR_INVALIDCLIPLIST";
		case DDERR_INVALIDDIRECTDRAWGUID :		return "DDERR_INVALIDDIRECTDRAWGUID";
		case DDERR_INVALIDMODE :				return "DDERR_INVALIDMODE";
		case DDERR_INVALIDOBJECT :				return "DDERR_INVALIDOBJECT";
		case DDERR_INVALIDPARAMS :				return "DDERR_INVALIDPARAMS";
		case DDERR_INVALIDPIXELFORMAT :			return "DDERR_INVALIDPIXELFORMAT";
		case DDERR_INVALIDPOSITION :			return "DDERR_INVALIDPOSITION";
		case DDERR_INVALIDRECT :				return "DDERR_INVALIDRECT";
		case DDERR_INVALIDSURFACETYPE :			return "DDERR_INVALIDSURFACETYPE";
		case DDERR_LOCKEDSURFACES :				return "DDERR_LOCKEDSURFACES";
		case DDERR_MOREDATA :					return "DDERR_MOREDATA";
		case DDERR_NO3D :						return "DDERR_NO3D";
		case DDERR_NOALPHAHW :					return "DDERR_NOALPHAHW";
		case DDERR_NOBLTHW :					return "DDERR_NOBLTHW";
		case DDERR_NOCLIPLIST :					return "DDERR_NOCLIPLIST";
		case DDERR_NOCLIPPERATTACHED :			return "DDERR_NOCLIPPERATTACHED";
		case DDERR_NOCOLORCONVHW :				return "DDERR_NOCOLORCONVHW";
		case DDERR_NOCOLORKEY :					return "DDERR_NOCOLORKEY";
		case DDERR_NOCOLORKEYHW :				return "DDERR_NOCOLORKEYHW";
		case DDERR_NOCOOPERATIVELEVELSET :		return "DDERR_NOCOOPERATIVELEVELSET";
		case DDERR_NODC :						return "DDERR_NODC";
		case DDERR_NODDROPSHW :					return "DDERR_NODDROPSHW";
		case DDERR_NODIRECTDRAWHW :				return "DDERR_NODIRECTDRAWHW";
		case DDERR_NODIRECTDRAWSUPPORT :		return "DDERR_NODIRECTDRAWSUPPORT";
		case DDERR_NOEMULATION :				return "DDERR_NOEMULATION";
		case DDERR_NOEXCLUSIVEMODE :			return "DDERR_NOEXCLUSIVEMODE";
		case DDERR_NOFLIPHW :					return "DDERR_NOFLIPHW";
		case DDERR_NOFOCUSWINDOW :				return "DDERR_NOFOCUSWINDOW";
		case DDERR_NOGDI : return "DDERR_NOGDI";
		case DDERR_NOHWND : return "DDERR_NOHWND";
		case DDERR_NOMIPMAPHW : return "DDERR_NOMIPMAPHW";
		case DDERR_NOMIRRORHW : return "DDERR_NOMIRRORHW";
		case DDERR_NONONLOCALVIDMEM : return "DDERR_NONONLOCALVIDMEM";
		case DDERR_NOOPTIMIZEHW : return "DDERR_NOOPTIMIZEHW";
		case DDERR_NOOVERLAYDEST : return "DDERR_NOOVERLAYDEST";
		case DDERR_NOOVERLAYHW : return "DDERR_NOOVERLAYHW";
		case DDERR_NOPALETTEATTACHED : return "DDERR_NOPALETTEATTACHED";
		case DDERR_NOPALETTEHW : return "DDERR_NOPALETTEHW";
		case DDERR_NORASTEROPHW : return "DDERR_NORASTEROPHW";
		case DDERR_NOROTATIONHW : return "DDERR_NOROTATIONHW";
		case DDERR_NOSTRETCHHW : return "DDERR_NOSTRETCHHW";
		case DDERR_NOT4BITCOLOR : return "DDERR_NOT4BITCOLOR";
		case DDERR_NOT4BITCOLORINDEX : return "DDERR_NOT4BITCOLORINDEX";
		case DDERR_NOT8BITCOLOR : return "DDERR_NOT8BITCOLOR";
		case DDERR_NOTAOVERLAYSURFACE : return "DDERR_NOTAOVERLAYSURFACE";
		case DDERR_NOTEXTUREHW : return "DDERR_NOTEXTUREHW";
		case DDERR_NOTFLIPPABLE : return "DDERR_NOTFLIPPABLE";
		case DDERR_NOTFOUND : return "DDERR_NOTFOUND";
		case DDERR_NOTINITIALIZED : return "DDERR_NOTINITIALIZED";
		case DDERR_NOTLOADED : return "DDERR_NOTLOADED";
		case DDERR_NOTLOCKED : return "DDERR_NOTLOCKED";
		case DDERR_NOTPAGELOCKED : return "DDERR_NOTPAGELOCKED";
		case DDERR_NOTPALETTIZED : return "DDERR_NOTPALETTIZED";
		case DDERR_NOVSYNCHW : return "DDERR_NOVSYNCHW";
		case DDERR_NOZBUFFERHW : return "DDERR_NOZBUFFERHW";
		case DDERR_NOZOVERLAYHW : return "DDERR_NOZOVERLAYHW";
		case DDERR_OUTOFCAPS : return "DDERR_OUTOFCAPS";
		case DDERR_OUTOFMEMORY : return "DDERR_OUTOFMEMORY";
		case DDERR_OUTOFVIDEOMEMORY : return "DDERR_OUTOFVIDEOMEMORY";
		case DDERR_OVERLAYCANTCLIP : return "DDERR_OVERLAYCANTCLIP";
		case DDERR_OVERLAYCOLORKEYONLYONEACTIVE : return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
		case DDERR_OVERLAYNOTVISIBLE : return "DDERR_OVERLAYNOTVISIBLE";
		case DDERR_PALETTEBUSY : return "DDERR_PALETTEBUSY";
		case DDERR_PRIMARYSURFACEALREADYEXISTS : return "DDERR_PRIMARYSURFACEALREADYEXISTS";
		case DDERR_REGIONTOOSMALL : return "DDERR_REGIONTOOSMALL";
		case DDERR_SURFACEALREADYATTACHED : return "DDERR_SURFACEALREADYATTACHED";
		case DDERR_SURFACEALREADYDEPENDENT : return "DDERR_SURFACEALREADYDEPENDENT";
		case DDERR_SURFACEBUSY : return "DDERR_SURFACEBUSY";
		case DDERR_SURFACEISOBSCURED : return "DDERR_SURFACEISOBSCURED";
		case DDERR_SURFACELOST : return "DDERR_SURFACELOST";
		case DDERR_SURFACENOTATTACHED : return "DDERR_SURFACENOTATTACHED";
		case DDERR_TOOBIGHEIGHT : return "DDERR_TOOBIGHEIGHT";
		case DDERR_TOOBIGSIZE : return "DDERR_TOOBIGSIZE";
		case DDERR_TOOBIGWIDTH : return "DDERR_TOOBIGWIDTH";
		case DDERR_UNSUPPORTED : return "DDERR_UNSUPPORTED";
		case DDERR_UNSUPPORTEDFORMAT : return "DDERR_UNSUPPORTEDFORMAT";
		case DDERR_UNSUPPORTEDMASK : return "DDERR_UNSUPPORTEDMASK";
		case DDERR_UNSUPPORTEDMODE : return "DDERR_UNSUPPORTEDMODE";
		case DDERR_VERTICALBLANKINPROGRESS : return "DDERR_VERTICALBLANKINPROGRESS";
		case DDERR_VIDEONOTACTIVE : return "DDERR_VIDEONOTACTIVE";
		case DDERR_WASSTILLDRAWING : return "DDERR_WASSTILLDRAWING";
		case DDERR_WRONGMODE : return "DDERR_WRONGMODE";
		case DDERR_XALIGN : return "DDERR_XALIGN";
		default : return "NONE";
	}
}

CDXDraw::CDXDraw()
{
	m_lpDD = NULL;
	m_lpDDC = NULL;
	m_hWnd = NULL;

	m_fFullScreen = TRUE;
	m_fUseFlip = TRUE;

	m_pDXPrimarySurface = NULL;
	m_pDXBackSurface = NULL;

}

CDXDraw::~CDXDraw()
{
	if (m_pDXBackSurface)
		delete m_pDXBackSurface;
	if (m_pDXPrimarySurface)
		delete m_pDXPrimarySurface;
	if (m_lpDDC)
		m_lpDDC->Release();
	if (m_lpDD)
		m_lpDD->Release();
}

HRESULT CDXDraw::Create()
{
	HRESULT ddrval;
	LPDIRECTDRAW lpDD;

	ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
	if (DD_OK != ddrval)
	{
		AfxMessageBox("DirectDraw개체를 생성할수 없습니다.");
		return ddrval;
	}
	ddrval = lpDD->QueryInterface(IID_IDirectDraw2, (LPVOID *)&m_lpDD);
	lpDD->Release();
	if (DD_OK != ddrval)
	{
		AfxMessageBox("DirectX 3.0 이상이 설치되어 있어야 사용할수 있습니다.");
		return ddrval;
	}
	return DD_OK;
}


BOOL CDXDraw::SetDisplayMode(SDisplayMode * pDisplayMode, BOOL fFullScreen)
{
	m_fFullScreen	= fFullScreen;
	m_hWnd = pDisplayMode->hWnd;

	m_nScreenWidth = pDisplayMode->nWidth;
	m_nScreenHeight = pDisplayMode->nHeight;
	m_nBPP = pDisplayMode->nBPP;

	HRESULT ddrval;

	if (fFullScreen)
	{
		ddrval = m_lpDD->SetCooperativeLevel(pDisplayMode->hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
		if (DD_OK != ddrval)
			return FALSE;
		ddrval = m_lpDD->SetDisplayMode(pDisplayMode->nWidth, pDisplayMode->nHeight, pDisplayMode->nBPP, 0, 0);
		if (DD_OK != ddrval)
			return FALSE;
		m_nDisplayWidth = m_nScreenWidth;
		m_nDisplayHeight = m_nScreenHeight;
	}
	else
	{
		CRect rcWindow;
		rcWindow.SetRect(0, 0, pDisplayMode->nWidth, pDisplayMode->nHeight);

		::AdjustWindowRectEx(rcWindow, GetWindowLong(m_hWnd, GWL_STYLE), FALSE,  GetWindowLong(m_hWnd, GWL_EXSTYLE));

		SetWindowPos(pDisplayMode->hWnd, NULL, 
			(GetSystemMetrics( SM_CXSCREEN )- rcWindow.Width()) /2, 
			(GetSystemMetrics( SM_CYSCREEN )- rcWindow.Height())/2,
			rcWindow.Width(), 
			rcWindow.Height(), 
			SWP_NOZORDER );	

		HDC hdc = GetDC( NULL ); // 화면에 대한 DC를 구한다.
		if (pDisplayMode->nBPP != GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL))
		{
			AfxMessageBox("Mismatch the depth of color");
			ReleaseDC( NULL, hdc );
			return FALSE;
		}
		ReleaseDC( NULL, hdc );

		ddrval = m_lpDD->SetCooperativeLevel(pDisplayMode->hWnd, DDSCL_NORMAL);
		if (DD_OK != ddrval)
			return FALSE;


		m_nDisplayWidth = GetSystemMetrics(SM_CXSCREEN);
		m_nDisplayHeight = GetSystemMetrics(SM_CYSCREEN);
	}
	
	return TRUE;
}


CDXSurface* CDXDraw::CreateSurface(LPDDSURFACEDESC pddsd)
{
	LPDIRECTDRAWSURFACE lpDDS;
	LPDIRECTDRAWSURFACE3 lpDDS3;

	if (m_lpDD->CreateSurface(pddsd, &lpDDS, 0) != DD_OK) 
		return NULL;
	if (lpDDS->QueryInterface(IID_IDirectDrawSurface3, (void **)&lpDDS3) != DD_OK)
	{
		lpDDS->Release();
		return NULL;
	}
	lpDDS->Release();

	
	CDXSurface* pSurface = new CDXSurface;
	pSurface->CreateFromHandle(lpDDS3);

	return pSurface;
}


CDXSurface* CDXDraw::CreatePrimarySurface(int nBackBufCount)
{
	DDSURFACEDESC ddsd;

	ddsd.dwSize = sizeof(DDSURFACEDESC);
	if (nBackBufCount && m_fFullScreen)
	{
		ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
		ddsd.dwBackBufferCount = nBackBufCount;
		m_fUseFlip = TRUE;
	}
	else
	{
		ddsd.dwFlags = DDSD_CAPS;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
		m_fUseFlip = FALSE;
	}

	CDXSurface* pPrimarySurface;
	pPrimarySurface = CreateSurface(&ddsd);

	m_pDXPrimarySurface = pPrimarySurface;
	if (pPrimarySurface != NULL)
	{
		if (!m_fFullScreen)
		{
			if (m_lpDD->CreateClipper( 0, &m_lpDDC, NULL ) != DD_OK)
			{
				delete pPrimarySurface;
				return NULL;
			}
			if (m_lpDDC->SetHWnd( 0, m_hWnd ) != DD_OK )
			{
				m_lpDDC->Release();
				delete pPrimarySurface;
				return NULL;
			}
			if (pPrimarySurface->GetDDS()->SetClipper(m_lpDDC) != DD_OK)
			{
				m_lpDDC->Release();
				delete pPrimarySurface;
				return NULL;
			}
		}
		if (m_fUseFlip)
			m_pDXBackSurface = m_pDXPrimarySurface->GetBackBufferSurface();
		else
			m_pDXBackSurface = CreateSurface(m_nScreenWidth, m_nScreenHeight, DDSCAPS_SYSTEMMEMORY);
	}
	return pPrimarySurface;
}


CDXSurface* CDXDraw::CreateSurface(int nWidth, int nHeight, DWORD dwFlags)
{
	DDSURFACEDESC ddsd;

	ddsd.dwSize = sizeof(DDSURFACEDESC);
	ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
	ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | dwFlags; 
	ddsd.dwWidth = nWidth;
	ddsd.dwHeight = nHeight; 

	return CreateSurface(&ddsd);
}

CDXSurface* CDXDraw::LoadBitmap(LPCSTR szBitmap)
{
	LPDIRECTDRAWSURFACE3 pdds = NULL;
	BITMAPFILEHEADER bmf;
	BITMAPINFOHEADER bmi;

	CFile file;

	if (file.Open(szBitmap, CFile::modeRead | CFile::typeBinary) != FALSE)
	{
		file.Read(&bmf, sizeof(BITMAPFILEHEADER));
		file.Read(&bmi, sizeof(BITMAPINFOHEADER));
		
		CDXSurface* pSurface = CreateSurface(bmi.biWidth, bmi.biHeight, 0);

		if (pSurface)
		{
			LPBYTE pTempBuffer = (LPBYTE)malloc(bmi.biWidth * 3);

			DDSURFACEDESC ddsd = pSurface->Lock();
			int lPitch = ddsd.lPitch;

			LPBYTE pSrc;
			LPWORD pDest;
			int r, g, b;
			for (int i = 0;i < bmi.biHeight;i++)
			{
				pDest = (LPWORD)((LPBYTE)ddsd.lpSurface + ddsd.lPitch * (bmi.biHeight - i - 1));
				pSrc = pTempBuffer;
				file.Read(pTempBuffer, bmi.biWidth * 3);
				for (int j = 0; j < bmi.biWidth; j++)
				{
					b = *pSrc++ >> 3;
					g = *pSrc++ >> 2;
					r = *pSrc++ >> 3;
					*pDest++ = (r << 11) | (g << 5) | b;
				}
			}
			pSurface->Unlock();

			free(pTempBuffer);
			file.Close();
			return pSurface;
		}
		else
		{
			file.Close();
			return NULL;
		}

	}
	return NULL;
}


void CDXDraw::Flip()
{
	if (m_fUseFlip)
		m_pDXPrimarySurface->GetDDS()->Flip(NULL, 0);
	else
	{
		if (!m_fFullScreen)
		{
			CPoint ptLT, ptRB;

			ptLT = CPoint(0, 0);
			ptRB = CPoint(m_nScreenWidth, m_nScreenHeight);

			ClientToScreen(m_hWnd, &ptLT);
			ClientToScreen(m_hWnd, &ptRB);
			m_pDXPrimarySurface->GetDDS()->Blt(CRect(ptLT, ptRB), m_pDXBackSurface->GetDDS(), NULL, 0, NULL);
		}
	}
}


//////////////////////////////////////////////////////////////////////
// CDXSurface

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDXSurface::CDXSurface()
{
	m_lpDDS = NULL;
}

CDXSurface::~CDXSurface()
{
	if (m_lpDDS)
		m_lpDDS->Release();
}


void CDXSurface::CreateFromHandle(LPDIRECTDRAWSURFACE3 lpDDS)
{
	m_lpDDS = lpDDS;
	if (m_lpDDS)
	{
		DDSURFACEDESC ddsd;

		ddsd.dwSize = sizeof(DDSURFACEDESC);
		m_lpDDS->GetSurfaceDesc(&ddsd);

		m_size = CSize(ddsd.dwWidth, ddsd.dwHeight);
	}
}


CDXSurface* CDXSurface::GetBackBufferSurface()
{
	CDXSurface* pSurface;

	LPDIRECTDRAWSURFACE3 pDDSBack;
	DDSCAPS ddscaps;

	ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
	if(m_lpDDS->GetAttachedSurface(&ddscaps, &pDDSBack) != DD_OK) 
		return NULL;
	pSurface = new CDXSurface;
	pSurface->CreateFromHandle(pDDSBack);

	return pSurface;
}


DDSURFACEDESC CDXSurface::Lock()
{
	DDSURFACEDESC ddsd;

	ddsd.dwSize = sizeof(DDSURFACEDESC);
	m_lpDDS->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);

	return ddsd;
}

void CDXSurface::Unlock()
{
	m_lpDDS->Unlock(NULL);
}

void CDXSurface::SetColorKey(DWORD dwColor)
{
	DDCOLORKEY ddColorKey;

	ddColorKey.dwColorSpaceHighValue = 0;
	ddColorKey.dwColorSpaceLowValue = dwColor;

	m_lpDDS->SetColorKey(DDCKEY_SRCBLT, &ddColorKey);
}

HRESULT CDXSurface::Blt(int nX, int nY, CDXSurface* pSrcSurface, CRect rectSrc, DWORD dwFlags)
{
	return 	m_lpDDS->BltFast(nX, nY, pSrcSurface->GetDDS(), rectSrc, DDBLTFAST_WAIT | dwFlags);
}

void CDXSurface::Blt(int nX, int nY, SMemSurface* pSrcSurface, CRect rectSrc)
{
	DDSURFACEDESC ddsd = Lock();
	LPWORD pwSrc, pwDst;
	int nHeight = rectSrc.Height();
	int nWidth = rectSrc.Width() / 2;

	pwSrc = pSrcSurface->m_pwSurface + rectSrc.top * pSrcSurface->m_nWidth + rectSrc.left;
	pwDst = (LPWORD)((LPBYTE)ddsd.lpSurface + nY * ddsd.lPitch + nX * 2);
	int nSrcPitch = (pSrcSurface->m_nWidth - rectSrc.Width()) * 2;
	int nDstPitch = ddsd.lPitch - rectSrc.Width() * 2;
	_asm
	{
		mov		eax, nHeight
		mov		ebx, nSrcPitch
		mov		edx, nDstPitch
		
		mov		esi, pwSrc
		mov		edi, pwDst

	_LoopY:
		mov		ecx, nWidth
		rep		movsd
		
		add		esi, ebx
		add		edi, edx
		
		dec		eax
		jnz		_LoopY
	}
	Unlock();
}


void SMemSurface::FillColor(CRect rect, WORD wFillColor)
{
	int i, j;
	LPWORD pwDest;

	for (i = 0; i < rect.Height(); i++)
	{
		pwDest = m_pwSurface + (rect.top + i) * m_nWidth + rect.left;
		for (j = 0; j < rect.Width(); j++)
			*pwDest++ = wFillColor;
	}

}

void SMemSurface::Blt(int nX, int nY, SMemSurface* pSrcSurface, CRect rectSrc)
{
	LPWORD pwSrc, pwDst;
	int nWidth = rectSrc.Width() / 2;
	int nHeight = rectSrc.Height();
	int nSrcPitch = (pSrcSurface->m_nWidth - rectSrc.Width()) * 2;
	int nDstPitch = (m_nWidth - rectSrc.Width()) * 2;
	
	pwSrc = pSrcSurface->m_pwSurface + rectSrc.top * pSrcSurface->m_nWidth + rectSrc.left;
	pwDst = m_pwSurface + nY * m_nWidth + nX;

	_asm
	{
		mov		eax, nHeight

		mov		ebx, nSrcPitch
		mov		edx, nDstPitch

		mov		esi, pwSrc
		mov		edi, pwDst

	_LoopY:
		mov		ecx, nWidth
		rep		movsd
		add		esi, ebx
		add		edi, edx

		dec		eax
		jnz		_LoopY
	}

	/*
	int	nWidth = rectSrc.Width() / 4;
	_asm
	{
		emms

		mov		eax, nHeight

		mov		ebx, nSrcPitch
		mov		edx, nDstPitch

		mov		esi, pwSrc
		mov		edi, pwDst

	_LoopY:
		mov		ecx, nWidth
	_LoopX:
		movq	mm0, [esi]
		movq	[edi], mm0
		add		esi, 8
		add		edi, 8
		loop	_LoopX

		add		esi, ebx
		add		edi, edx

		dec		eax
		jnz		_LoopY
	}
	*/
}