Nejprve tedy vlo₧me zcela novou knihovnu. Z menu File vyberte volbu New. Na dialogu zvolte kartu Projects a oznaΦte MFC AppWizard (dll). Pot°ebujeme toti₧ vytvo°it rozÜφ°enou knihovnu MFC. Op∞t nezapome≥te zaÜkrtnout volbu Add to current project a do polφΦka Project name vepiÜte Display. Na dialogu AppWizardu zvolte MFC Extension DLL a stiskn∞te tlaΦφtko Finish. Do ClassView p°ibude projekt Display, kter² se nastavφ jako aktivnφ - oznaΦte tedy jako aktivnφ projekt Game.
Nynφ nastavme vzßjemnΘ vazby mezi projekty. Z menu Project vyberte volbu Dependencies. Na dialogu nastavte, aby projekt Game byl zßvisl² na projektu Display takto:
Dßle zeditujme nastavenφ novΘho projektu, abychom mohli pou₧φt knihovnu Common.dll a aby se soubor Display.dll vytvß°el v Debug a Release celΘho projektu. Vyu₧ijeme kontextovΘho menu ClassView. Prav²m tlaΦφtkem klikn∞te na projekt Display a vyberte polo₧ku Settings. Na dialogu nastavte toto nastavenφ:
Nastavenφ samoz°ejm∞ prove∩te i pro Release. VÜimn∞te si, ₧e nastavenφ je vlastn∞ stejnΘ jako v projektu Game (navφc jsou p°idanΘ knihovny pot°ebnΘ pro DirectDraw, ale to u₧ znßme). Po kompilaci p°ibude do adresß°e Debug Φi Release knihovna Display.dll.
Knihovna bude obsahovat n∞kolik t°φd:
Proto₧e CDisplay je zßvislß na CSurface, vytvo°me nejprve t°φdu CSurface:
CSurface |
||
╚lenskΘ prom∞nnΘ |
|
|
Typ |
Nßzev |
Popis |
BOOL |
m_bInit |
Prom∞nnß je TRUE pokud je objekt povrchu °ßdn∞ zinicializovßn. Pak lze volat dalÜφ metody jako Blt() apod. |
BOOL |
m_bColorKey |
Prom∞nnß je TRUE pokud se povrch mß vykreslovat se zapnut²m color key (zkrßtka zda-li mß Φi nemß CK). |
DWORD |
m_dwWidth |
èφ°ka povrchu v pixelech. Velikost povrchu je urΦena velikostφ bitmapy, kterou do povrchu nahrßvßme (viz metody Create()) |
DWORD |
m_dwHeight |
V²Üka povrchu v pixelech. |
CString |
m_csBitmap |
╪et∞zec, do n∞ho₧ ulo₧φme cestu k bitmap∞ v datovΘm souboru. To se bude hodit, a₧ bude pot°eba povrch obnovit. |
LPDIRECTDRAWSURFACE7 |
m_lpDDSurface |
Ukazatel na vlastnφ objekt povrchu (rozhranφ IDirectDrawSurface7) |
CDisplay* |
m_pDisplay |
Pomocn² ukazatel na objekt CDisplay. |
Metody |
|
|
Nßvratovß hodnota |
Nßzev s parametry |
Popis |
HRESULT |
Create(DWORD, DWORD, UINT) |
Nßsledujφcφ t°i funkce inicializujφ objekt povrchu - liÜφ se pouze parametry. Prvnφ verze mß jako prvnφ dva parametry po₧adovanou velikost povrchu. T°etφ parametr je urΦuje dalÜφ vlastnosti povrchu nap°. CK apod. |
HRESULT |
Create(CString, UINT) |
Druhß verze mß prvnφ parametr °et∞zec s ·plnou cestou bitmapy v datovΘm souboru. Povrch mß velikost bitmapy a bitmapa je takΘ nahrßna do povrchu. Druh² parametr je stejn² jako u p°edchozφ funkce Create(). |
HRESULT |
Create(LPDIRECTDRAWSURFACE7) |
T°etφ a poslednφ funkce Create() je vlastn∞ kopφrovacφ konstruktor. Vytvo°φ nov² povrch pomocφ ji₧ existujφcφho povrchu - ud∞lß kompletnφ kopii. Jednu z t∞chto funkcφ je t°eba zavolat, aby bylo mo₧nΘ volat ostatnφ metody. |
HRESULT | Blt(CRect, CRect, CSurface*) | Nßsledujφcφ funkce zajiÜ¥ujφ vykreslovßnφ do aktußlnφho povrchu bu∩ z jinΘho povrchu nebo jednolitΘ v²pln∞. Prvnφ verze mß dva parametry typu CRect, co₧ jsou obdΘlnφky, ze kter²ch a do kter²ch se kopφruje p°φsluÜnß Φßst povrchu urΦenΘho t°etφm parametrem. |
HRESULT | Blt(CRect, COLORREF) | Druhß verze vyplnφ obdΘlnφk zadan² prvnφm parametrem spojitou barvou definovanou druh²m parametrem. |
HRESULT | CopyBitmap(CString) | Tato funkce slou₧φ ke kopφrovßnφ bitmapy ze souboru do p°edem vytvo°enΘho povrchu. Vyu₧φvß se p°i obnov∞ povrchu apod. |
DWORD | Height() | Vracφ v²Üku povrchu. |
DWORD | Width() | Vracφ Üφ°ku povrchu. |
BOOL | IsColorKey() | Vracφ TRUE pokud povrch je s CK, jinak FALSE. |
BOOL | IsInit() | Vracφ stav prom∞nnΘ m_bInit. |
BOOL | IsValid() | Vracφ stav prom∞n²ch m_bInit a zßrove≥ ukazatele this (viz. dßle). |
LPDIRECTDRAWSURFACE7* | GetSurface() | Vracφ p°φmo ukazatel na povrch DirectDraw. |
void | SetColorKey() | Nastavφ prom∞nnou m_bIsColorKey na TRUE (zapne CK) |
HRESULT | Restore(BOOL) | Obnovφ povrch p°i ztrßt∞. Parametr urΦuje zda-li povrch bude obnoven a napln∞n p∙vodnφ bitmapu nebo jen obnoven. |
HRESULT | Release() | Uvolnφ pam∞¥ povrchu a zruÜφ objekt. Tato metoda nenφ pot°eba volat explicitn∞, proto₧e se volß z destruktoru. |
LPDIRECTDRAWSURFACE7 | operator LPDIRECTDRAWSURFACE7() | P°etφ₧en² operßtor. Objekt CSurface p∙jde p°etypovat na LPDIRECTDRAWSURFACE7. |
Konstruktor a destruktor t°φdy neuvßdφm, proto₧e to beru jako samoz°ejmost.
Deklarace t°φdy nenφ slo₧itß:
class AFX_EXT_CLASS CSurface
{
private:
LPDIRECTDRAWSURFACE7 m_lpDDSurface;
CDisplay *m_pDisplay;
BOOL m_bInit;
BOOL m_bColorKey;
DWORD m_dwWidth;
DWORD m_dwHeight;
CString m_csBitmap;
public:
//
// Create functions
HRESULT Create(DWORD dwWidth, DWORD
dwHeight, UINT nFlags = DDFLG_COLORKEY);
HRESULT Create(CString strBMP, UINT
nFlags = DDFLG_COLORKEY);
HRESULT Create(LPDIRECTDRAWSURFACE7
lpSurface);
//
HRESULT Release();
HRESULT Restore(BOOL bFill = false);
HRESULT SetColorKey();
//
// Copy bitmap to surface
HRESULT CopyBitmap(CString csBitmap);
//
// Inline functions
LPDIRECTDRAWSURFACE7 GetSurface();
BOOL IsInit() {return m_bInit;}
BOOL IsColorKey() {return m_bColorKey;}
DWORD Width() {return m_dwWidth;}
DWORD Height() {return m_dwHeight;}
BOOL IsValid();
//
// Blitting functions
HRESULT Blt(CRect rcDestin, CRect rcSource, CSurface* surSource);
HRESULT Blt(CRect rcDestin, COLORREF
Color);
//
// Overloaded operator to return
pointer to surface
operator LPDIRECTDRAWSURFACE7() {return m_lpDDSurface;};
public:
CSurface();
~CSurface();
};
Na deklaraci nenφ nic zvlßÜtnφho ani p°ekvapivΘho snad krom∞ makra AFX_EXT_CLASS, o kterΘm ji₧ byla takΘ °eΦ.
Nynφ se podφvejme na konstruktor a destruktor t°φdy:
CSurface::CSurface()
{
m_bInit = false;
m_bColorKey = false;
m_dwHeight = 0;
m_dwWidth = 0;
m_pDisplay = disGetDisplay();
SAFE_NULL(m_lpDDSurface);
}
CSurface::~CSurface()
{
if(m_bInit) { //if you do not call
release() before destruct object
Release(); //call
now
}
}
Op∞t zde nenφ nic novΘho. VÜimn∞te si volßnφ uvol≥ovacφ funkce v destruktoru (viz. v²Üe). Funkce disGetDisplay() vracφ p°φmo objekt CDisplay. Je to globßln∞ vytvo°enß funkce, o kterΘ bude °eΦ pozd∞ji.
Proberme implementace zbyl²ch funkcφ:
HRESULT CSurface::Create(DWORD dwWidth,
DWORD dwHeight, UINT nFlags)
{
HRESULT dwReturn = 1;// 1...ERROR_ALREADYINIT;
DDSURFACEDESC2 ddsd;
//
// Is surface already created? Is initialized display system?
if(m_bInit || !m_pDisplay) {
DXTRACE("Cannot create surface
because it is already created or the display system is not initialized.");
return dwReturn;
}
//
// Check if the input param are valid
ASSERT(dwWidth > 0 && dwHeight > 0);
//
// Create a DirectDrawSurface for this bitmap
ZeroMemory( &ddsd, sizeof(ddsd) );
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
m_dwWidth = ddsd.dwWidth = dwWidth;
m_dwHeight = ddsd.dwHeight = dwHeight;
//
// Creation of the new surface
dwReturn = m_pDisplay->GetDirectDraw()->CreateSurface(&ddsd,
&m_lpDDSurface, NULL);
//
// Try to create surface in RAM if video is full
if(dwReturn == DDERR_OUTOFVIDEOMEMORY) {
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN
| DDSCAPS_SYSTEMMEMORY;
dwReturn = m_pDisplay->GetDirectDraw()->CreateSurface(&ddsd,
&m_lpDDSurface, NULL);
}
if(DD_OK != dwReturn) {
DXERR("Cannot create the surface due",
dwReturn);
return dwReturn;
}
m_bInit = true;
return dwReturn;
}
Tuto funkci si probereme trochu podrobn∞ji. Nejprve zjistφme platnost ukazatele m_pDisplay a to, zda-li povrch u₧ nebyl jednou inicializovßn. PotΘ zkontrolujeme vstupnφ parametry. Dßle plnφme strukturu DDSURFACEDESC2, jak jsme byli zvyklφ - nastavφme off-screen surface, Üφ°ku v²Üku a typ pam∞ti v p°φpad∞, ₧e video pam∞¥ je plnß. Vytvo°φme vlastnφ povrch. P°i ne·sp∞chu zkusφme jeÜt∞ povrch vytvo°it v RAM mφsto video pam∞ti. A to je vÜe. Detailnφ popis v²Üe uveden²ch °ßdk∙ najdete v n∞kolika p°edchßzejφcφch lekcφch.
HRESULT CSurface::Create(CString strBMP,
UINT nFlags)
{
HRESULT dwRet = 1;// = ERROR_NOINIT;
DWORD dwSize;
DWORD dwWritten;
LPBYTE lpData;
HANDLE hFile = NULL;
BITMAP bm;
HBITMAP hBitmap;
CString strTempFile = _T("C:\\surface.tmp");
HDC hdcImage;
HDC hdc = NULL;
//
// Is surface initialized ?
// Is bitmap valid?
// Is display initialized?
if(m_bInit || strBMP.IsEmpty() || !m_pDisplay) {
DXTRACE("General error has been
occured while surface was created.");
return dwRet;
}
//
// Save internal copy of bitmap path
m_csBitmap = strBMP;
//
// Find file in storage
if((dwRet = stgGetFile3(strBMP, &lpData, dwSize)) != S_OK) {
DXERR("Cannot find specified bitmap
is storage due", dwRet);
return dwRet;
}
//create temporary file
hFile = (HANDLE)CreateFile(strTempFile,
GENERIC_WRITE ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY,
NULL);
if(hFile == INVALID_HANDLE_VALUE) {
dwRet = GetLastError();
DXERR("Cannot create temporary file
due", dwRet);
delete [] lpData;
return dwRet;
}
//
// Write bitmap data to file
WriteFile(hFile, lpData, dwSize, &dwWritten, NULL);
if(dwWritten != dwSize) {
dwRet = GetLastError();
DXERR("Cannot write data to temporary
file due", dwRet);
CloseHandle((HANDLE)hFile);
DeleteFile(strTempFile);
delete [] lpData;
return dwRet;
}
//
// Close temporary file
CloseHandle((HANDLE)hFile);
//
// Get bitmap handle
hBitmap = (HBITMAP)LoadImage(NULL, strTempFile, IMAGE_BITMAP,
0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
if (hBitmap == NULL) {
dwRet = GetLastError();
DXERR("Cannot create bitmap handle
due", dwRet);
DeleteFile(strTempFile);
delete [] lpData;
return dwRet;
}
//
// Get size of the bitmap
if(!GetObject(hBitmap, sizeof(BITMAP), &bm))
{
dwRet = GetLastError();
DXERR("Cannot get info about bitmap
due", dwRet);
DeleteFile(strTempFile);
delete [] lpData;
return dwRet;
}
//
// Create surface
if(ERROR_SUCCESS != (dwRet = Create(bm.bmWidth, bm.bmHeight,
nFlags))) {
DXERR("Cannot create surface due",
dwRet);
DeleteFile(strTempFile);
delete [] lpData;
return dwRet;
}
//
// Make sure this surface is restored.
Restore();
//
// Create DC for our bitmap
hdcImage = CreateCompatibleDC(NULL);
if (!hdcImage) {
dwRet = GetLastError();
DXERR("Cannot create compatible DC
due", dwRet);
DeleteFile(strTempFile);
delete [] lpData;
return dwRet;
}
//
// Select bitmap intoa a memoryDC so we can use it.
SelectObject(hdcImage, hBitmap);
//
// Get DC to surface
if ((dwRet = m_lpDDSurface->GetDC(&hdc)) != DD_OK)
{
DXERR("Cannot get surface DC due",
dwRet);
return dwRet;
}
//
// Blit bitmap to GDI surface
if(0 == StretchBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight,
hdcImage, 0, 0, bm.bmWidth , bm.bmHeight, SRCCOPY))
{
dwRet = GetLastError();
DXERR("Cannot blit bitmap to surface
due", dwRet);
return dwRet;
}
//
// Release DC
if(DD_OK != (dwRet = m_lpDDSurface->ReleaseDC(hdc))) {
DXERR("Cannot release surface DC due",
dwRet);
return dwRet;
}
//
// If we want to set color key, set it now
if(nFlags & DDFLG_COLORKEY) {
dwRet = SetColorKey();
}
//
//release handle to GDI object and handle to DC
DeleteDC(hdcImage);
DeleteObject(hBitmap);
DeleteFile(strTempFile);
delete [] lpData;
return dwRet;
}
Tato funkce koneΦn∞ obsahuje n∞jakΘ novinky, tak₧e si ji p°iblφ₧φme jeÜt∞ vφce. Funkce op∞t obsahuje kontroly zda-li je povrch neinicializovßn a zda-li je inicializovßn objekt CDisplay. Idea funkce je takovß, ₧e nejprve nahrajeme bitmapu z datovΘho souboru, potΘ vytvo°φme doΦasn² soubor, do kterΘho bitmapu nahrajeme, dßle zφskßme rozm∞ry bitmapy, vytvo°φme povrch podle t∞chto rozm∞r∙ a nakopφrujeme bitmapu do povrchu. Je to celkem kostrbat² zp∙sob, ale funguje to! Funkcφ stgGetFile3() nahrajeme po₧adovanou bitmapu z datovΘho souboru do pam∞¥ovΘho bufferu.Funkce mß t°i parametry: cesta k bitmap∞, ukazatel na ukazatel na buffer a velikost bufferu. Buffer je alokovßn a₧ uvnit° funkce a parametr dwSize potΘ obsahuje velikost souboru. PotΘ vytvo°φme nov² soubor pomocφ API funkce CreateFile() a zapφÜeme obsah pam∞¥ovΘho souboru do souboru na disku. Dßle vyu₧φvßme API funkce k zφskßnφ rozm∞r∙ bitmapy. Kdy₧ znßme rozm∞ry, m∙₧eme koneΦn∞ vytvo°it povrch funkcφ Create(DWORD,DWORD,UINT). Nakonec zb²vß zkopφrovat bitmapu do povrchu. To provedeme na ·rovni DC s bitmapou a DC povrchu. Pokud si to u₧ivatel p°eje, nastavφme CK a na ·pln² zßv∞r uvolnφme vÜechnu alokovanou pam∞¥.
A koneΦn∞ je tu t°etφ verze funkce Create():
HRESULT CSurface::Create(LPDIRECTDRAWSURFACE7
lpSurface)
{
DDSURFACEDESC2 ddsd;
ddsd.dwSize = sizeof(ddsd);
HRESULT dwReturn = 1;//
= ERROR_INIT or INVALID SURFACE;
if(lpSurface && !m_bInit) {
dwReturn = lpSurface->GetSurfaceDesc(&ddsd);
if(dwReturn != DD_OK) {
DXERR("You
may pass invalid surface. Cannot get info about due", dwReturn);
return
dwReturn;
}
//
// Init member fuction according
existing surface
m_lpDDSurface = lpSurface;
m_dwHeight = ddsd.dwHeight;
m_dwWidth = ddsd.dwWidth;
m_bColorKey = ddsd.dwFlags & DDSD_CKSRCBLT;
m_bInit = true;
m_csBitmap = _S_EMPTY;
}
return dwReturn;
}
Vypadß p°esn∞ jako kopφrovacφ konstruktor. Na zaΦßtku zjistφme informace o povrchu danΘm vstupnφm parametrem funkce. V druhΘ Φßsti funkce inicializujeme ostatnφ atributy t°φdy CSurface. Povrch ovÜem z∙stane prßzdn² (bez bitmapy).
Dßle probereme mo₧nß nejslo₧it∞jÜφ funkci t°φdy, funkci CopyBitmap():
HRESULT CSurface::CopyBitmap(CString
csBitmap)
{
HRESULT dwReturn = 1;//
= ERROR_NOINIT or BITMAP NAME IS INVALID;
DWORD dwSize;
DWORD dwWritten;
LPBYTE lpData;
HANDLE hFile = NULL;
BITMAP bm;
HBITMAP hBitmap;
CString strTempFile = _T("C:\\surface.tmp");
HDC hdcImage;
HDC hdc = NULL;
HBITMAP hOld;
//
// If display initialized and storage opened
if(!csBitmap.IsEmpty()
&& m_bInit) {
//
// Try to find file in storage
dwReturn = stgGetFile3(csBitmap, &lpData, dwSize);
if(dwReturn != ERROR_SUCCESS) {
DXERR("Cannot
get file from storage due:", dwReturn);
return
dwReturn;
}
//
// Create temporary file
hFile = (HANDLE)CreateFile(strTempFile,
GENERIC_WRITE ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY,
NULL);
if(hFile == INVALID_HANDLE_VALUE) {
dwReturn =
GetLastError();
DXERR("Cannot
create temporary file due:", dwReturn);
delete []
lpData;
return
dwReturn;
}
//
// Write bitmap data to the temporary
file
WriteFile(hFile, lpData, dwSize, &dwWritten, NULL);
if(dwWritten != dwSize) {
dwReturn =
GetLastError();
DXERR("Cannot
write data due:", dwReturn);
CloseHandle((HANDLE)hFile);
delete []
lpData;
DeleteFile(strTempFile);
return
dwReturn;
}
//
// Close it
CloseHandle((HANDLE)hFile);
//
// Get bitmap handle
// Try to load bitmap from file
hBitmap = (HBITMAP)LoadImage(NULL, strTempFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
if (hBitmap == NULL) {
dwReturn =
GetLastError();
DXERR("Cannot
get bitmap handle due:", dwReturn);
delete []
lpData;
DeleteFile(strTempFile);
return
dwReturn;
}
//
// Get size of the bitmap
if(!GetObject(hBitmap, sizeof(BITMAP), &bm))
{
dwReturn =
GetLastError();
DXERR("Cannot
get bitmap information due:", dwReturn);
delete []
lpData;
DeleteObject(hBitmap);
DeleteFile(strTempFile);
return
dwReturn;
}
//
// Create DC for our bitmap
hdcImage = CreateCompatibleDC(NULL);
if (!hdcImage) {
dwReturn =
GetLastError();
DXERR("Cannot
create temporary DC due:", dwReturn);
delete []
lpData;
DeleteObject(hBitmap);
DeleteFile(strTempFile);
return
dwReturn;
}
//
// Select bitmap into a memoryDC so
we can use it.
hOld = (HBITMAP) SelectObject(hdcImage, hBitmap);
//
// Get DC of DD surface
if ((dwReturn = m_lpDDSurface->GetDC(&hdc)) == DD_OK)
{
//
// Blit
bitmap to GDI surface
StretchBlt(hdc, 0, 0, Width(), Height(), hdcImage, 0, 0, bm.bmWidth , bm.bmHeight,
SRCCOPY);
if(DD_OK != (dwReturn
= m_lpDDSurface->ReleaseDC(hdc)))
{
DXERR("Cannot release surface DC due:", dwReturn);
}
//
// If we want
to set color key, set it now else exit with OK
if(m_bColorKey) {
dwReturn = SetColorKey();
if(dwReturn != ERROR_SUCCESS) {
DXERR("Cannot set CK on surface due:", dwReturn);
}
}
//
//release
handle to GDI object and handle to DC
DeleteDC(hdcImage);
DeleteObject(hBitmap);
DeleteFile(strTempFile);
delete []
lpData;
}
if(dwReturn != DD_OK) {
DXERR("Cannot
get surface DC due:", dwReturn);
delete []
lpData;
DeleteObject(hBitmap);
DeleteDC(hdcImage);
DeleteFile(strTempFile);
return
dwReturn;
}
}
return dwReturn;
}
Funkce funguje podobn∞ jako druhß verze Create().
Nejprve vytßhneme bitmapu z datovΘho souboru, ale potΘ ji nakopφrujeme do
povrchu, kter² byl p°edem vytvo°en tzn., ₧e nealokujeme dalÜφ pam∞¥ pro povrch.
Proto₧e kopφrovßnφ bitmapy se provßdφ na ·rovni DC (kontext∙ za°φzenφ) povrchu a
DC s bitmapou, pou₧ijeme funkci StretchBlt(). Tato
funkce provede vykreslenφ (vΦetn∞ roztßhnutφ Φφ smrÜt∞nφ bitmapy) z jednoho DC
do jinΘho (parametry jsou dost podobnΘ funkci Blt()
DirectDraw s tφm rozdφlem, ₧e mφsto povrch∙ se pou₧φvajφ DC). Na konci funkce je
d∙le₧itΘ uvoln∞nφ pam∞ti!
Povrch jsme vytvo°ili musφme ho ovÜem i uvolnit. K tomu slou₧φ funkce Release(), kterß se volß z destruktoru:
HRESULT CSurface::Release()
{
SAFE_RELEASE(m_lpDDSurface);
//safe release surface
m_bInit = false;
//and reset all member variable
m_bColorKey = false;
m_dwHeight = 0;
m_dwWidth = 0;
return ERROR_SUCCESS;
}
T∞lo funkce je velice krßtkΘ a srozumitelnΘ. D∙le₧itΘ je uvoln∞nφ rozhranφ
povrchu DirectDraw.
Z minulΘho projektu si jist∞ vzpomφnßte na obnovu povrch∙ po ztrßt∞ focusu okna. Nßsledujφcφ funkce Restore() zajistφ kompletnφ obnovu povrchu vΦetn∞ vypln∞nφ povrchu p∙vodnφ bitmapou, pokud si to u₧ivatel p°eje:
HRESULT CSurface::Restore(BOOL
bFill)
{
HRESULT dwReturn = 1;//
1...ERROR_NOINIT;
if(m_bInit) {
//
// Try tu restore surface
dwReturn = m_lpDDSurface->Restore();
if(dwReturn != DD_OK) {
DXERR("Cannot
restore surface due", dwReturn);
return
dwReturn;
}
if(bFill) {
//
// Refill
surface by bitmap
dwReturn =
CopyBitmap(m_csBitmap);
}
}
return dwReturn;
}
Jedin² vstupnφ parametr urΦuje, zda-li se povrch naplnφ Φi nenaplnφ p∙vodnφ
bitmapou. Jinak na funkce nenφ nic zajφmavΘho. Nejprve obnovφme (realokujeme)
povrch pomocφ funkce Restore() (stejn∞ jsme to
d∞lali i v minulΘm projektu). PotΘ vyu₧ijeme funkce
CopyBitmap() k napln∞nφ povrchu p∙vodnφ bitmapou. To je vÜe!
K nastavenφ Color Key pou₧φvßme funkci SetColorKey():
HRESULT CSurface::SetColorKey()
{
HRESULT dwReturn = 1;
DWORD dwPixel;
DDSURFACEDESC2 ddsd;
DDCOLORKEY ddck;
if(m_bInit) {
//
// Now lock the surface so we can
read back the converted color
ddsd.dwSize = sizeof(ddsd);
dwReturn = GetSurface()->Lock( NULL,
&ddsd, DDLOCK_WAIT, NULL );
if(dwReturn != DD_OK) {
DXERR("Cannot
lock surface to set color key due", dwReturn);
return
dwReturn;
}
//
// Get first pixel
dwPixel = *(DWORD *) ddsd.lpSurface;
//
// Mask it to bpp
if(ddsd.ddpfPixelFormat.dwRGBBitCount
< 32) {
dwPixel &= (1
<< ddsd.ddpfPixelFormat.dwRGBBitCount) - 1;
}
//
// Unlock surface
GetSurface()->Unlock(NULL);
//
// Set color values
ddck.dwColorSpaceLowValue = ddck.dwColorSpaceHighValue
= dwPixel;
//
// Set color key on surface
dwReturn = m_lpDDSurface->SetColorKey(DDCKEY_SRCBLT, &ddck);
if(dwReturn != DD_OK) {
DXERR("Cannot
set color key on surface due", dwReturn);
}
if(dwReturn == DD_OK) {
m_bColorKey =
true;
}
}
return dwReturn;
}
Funkce vybere prvnφ pixel bitmapy a barvu tohoto pixelu nastavφ jako transparentnφ. Abychom mohli p°istoupit p°φmo k povrchu, musφme tento povrch "uzamknout" funkcφ Lock(), kterß zßrove≥ inicializuje ukazatel na pole pixel∙. PotΘ p°eΦteme barevnou informaci prvnφho pixelu a povrch odemkneme funkcφ Unlock(). Zbytek metody je zcela z°ejm², nastavenφ CK jsme probrali v minul²ch lekcφch.
Nßsledujφcφ funkce vracφ p°φmo ukazatel na povrch DirectDraw:
LPDIRECTDRAWSURFACE7
CSurface::GetSurface()
{
//
// Is surface initialized ?
if(m_bInit) {
return m_lpDDSurface;
}
return NULL;
}
Tuto funkci vyu₧ijeme pokud pot°ebuje p°φmo pracovat s povrchem DirectDraw (nap°φklad
jako parametr n∞kter²ch funkcφ).
Funkce IsValid() testuje platnost povrchu a objektu CSurface:
BOOL CSurface::IsValid()
{
if(m_lpDDSurface && IsInit()) {
return TRUE;
}
else {
return FALSE;
}
}
Od IsInit() se liÜφ prßv∞ v testovßnφ platnosti povrchu. BezpeΦn∞jÜφ je tedy pou₧φvat metodu IsValid().
Jako poslednφ si proberme pßr funkcφ Blt(). Mß dv∞ verze. Prvnφ kopφruje obsah povrchu do jinΘho povrchu a druhß vypl≥uje aktußlnφ povrch spojitou barvou:
HRESULT CSurface::Blt(CRect
rcDestin, CRect rcSource, CSurface* surSource)
{
HRESULT dwResult = 1; // 1 means: NO INIT
//
// Check if the destination surface is valid
if(IsValid() && surSource->IsValid()) {
//
// Blit with color key
if(surSource->IsColorKey()) {
while(1) {
dwResult = GetSurface()->Blt(&rcDestin, surSource->GetSurface(), &rcSource,
DDBLT_KEYSRC, NULL);
if(dwResult != DDERR_WASSTILLDRAWING) {
break;
}
}
}
//
// Blit without color key
else {
while(1) {
dwResult = GetSurface()->Blt(&rcDestin, surSource->GetSurface(), &rcSource, 0,
NULL);
if(dwResult != DDERR_WASSTILLDRAWING) {
break;
}
}
}
if(DD_OK != dwResult) {
DXERR("Cannot
blit solid rect due", dwResult);
}
}
return dwResult;
}
Na funkci nenφ nic slo₧itΘho. RozliÜujeme zda-li je pou₧it CK Φi nikoliv. VÜimn∞te si takΘ pou₧itφ funkce GetSurface(). Vykreslovßnφ zkouÜφme tak dlouho dokud Blt() nevracφ n∞co jinΘho ne₧ DDERR_WASSTILLDRAWING. Tento k≤d funkce vracφ tehdy, kdy₧ jeÜt∞ nejsou dokonΦeny p°edchozφ kreslφcφ operace. VÜe ostatnφ znßme z minul²ch lekcφ.
Druhß verze je jeÜt∞ jednoduÜÜφ:
HRESULT CSurface::Blt(CRect
rcDestin, COLORREF Color)
{
HRESULT dwResult = 1; // 1 means: NOT INIT
DDBLTFX fx;
//
// Check if the destination surface is valid
if(IsValid()) {
//
// Fill DDBLTFX structure valid date
fx.dwSize = sizeof(fx);
fx.dwFillColor = Color;
//
// Blitting...
while(1) {
dwResult =
GetSurface()->Blt(&rcDestin, NULL, NULL, DDBLT_COLORFILL, &fx);
if(dwResult
!= DDERR_WASSTILLDRAWING) {
break;
}
}
if(DD_OK != dwResult) {
DXERR("Cannot
blit solid rect due", dwResult);
}
}
return dwResult;
}
Nepot°ebujeme zde ₧ßdn² zdrojov² povrch ani obdΘlnφk. Naplnφme strukturu DDBLTFX tak, aby funkce Blt() vyplnila oblast urΦenou cφlov²m obdΘlnφkem rcDestin spojitou barvou Color.
DneÜnφ lekce byla trochu delÜφ, ale doufßm, ₧e jste vÜechno pochopili. Stihli jsme implementovat pouze t°φdu CSurface, ale v p°φkladu, kter² p°iklßdßm naleznete kompletnφ knihovnu Display.dll. Zbytek dod∞lßme v p°φÜtφ lekci (aspo≥ doufßm). P°φklad si stßhn∞te ze sekce Downloads. Navφc v adresß°i Release najdete program Storage3, kter² pou₧ijete p°i vytvß°enφ datov²ch soubor∙. Zkuste si otev°φt datov² soubor pou₧it² v projektu data.dat a uvidφte, jak program funguje.
Pokud by Vßm p°ece jen n∞co uniklo, staΦφ napsat a jß se k tomu vrßtφm.
T∞Üφm se p°φÜt∞ nashledanou.