Grafické aplikace ve Visual C++ (4.)
V dnešní lekci si konečně vytvoříme přední a zadní buffer a ukážeme si,
jak přepsat funkci Run() tak, aby prohazovala oba povrchy. Výsledkem aplikace
nebude nic světoborného, protože oba povrchy budou prázdné, ale i tak se
posuneme o notný kus dál.
4.2. Vytvoření předního a zadního bufferu
Minule jsme si říkali, že zapisujeme data pouze do zadního bufferu
(back buffer) tzn. že musíme získat ukazatel na tento buffer. Aby jsme tento
ukazatel mohli získat musíme nejdříve vytvořit přední buffer
(front buffer), protože zadní je součást tzv. flipovací smyčky
nebo také řetězce (flipping chain). DirectDraw poskytuje funkci
CreateSurface() , která je členskou
funkcí objektu DirectDraw, který jsme vytvořili už minule.
HRESULT CreateSurface( LPDDSURFACEDESC lpDDSurfaceDesc,
LPDIRECTDRAWSURFACE FAR *
lplpDDSurface, IUnknown FAR *pUnkOuter);
Tato funkce má tři následující parametry :
-
Ukazatel na strukturu typu DDSURFACEDESC2 ,
ve které jsou uloženy parametry vytvářeného povrchu, viz níže.
-
Ukazatel na ukazatel na vlastního povrch
-
Integrace COM. Prozatím rovno NULL.
Vrací DD_OK pokud je úspěšná jinak některou z návratových hodnot DirectDraw.
Struktura DDSURFACEDESC2
Tato struktura popisuje vlastnosti nového povrch. Ať už vytváříte přední,
či pomocný buffer, budete ji využívat. Obsahuje mnoho atributů, ale my
jich zatím využijeme jen málo. Zde předkládám ty nejdůležitější:
-
DWORD dwSize ......................velikost struktury v bytech
-
DWORD dwFlags ........................udává, které členy jsou platné
-
DWORD dwWidth ........................šířka vytvářeného povrchu v pixelech
-
DWORD dwHeight .......................výška vytvářeného povrchu v pixelech
-
DWORD dwBackBufferCount ...............počet zadních bufferů připojených k přednímu
-
DDSCAPS ddsCaps ..................další struktura určující další vlastnosti
Příklad vytvoření předního bufferu
Do třídy CControl přidejte dvě členské proměnné typu
LPDIRECTDRAWSURFACE7 (IDirectDrawSurface7),
jednu pojmenujte m_lpDDSFront a druhou
m_lpDDSBack. Budou představovat
ukazatele na přední a zadní povrch. Pomocí těchto ukazatelů budete pracovat s
povrchy.
Dále přidejte následující kód do funkce DDInit().
DDSURFACEDESC2 ddsd;
ZeroMemory(&ddsd, sizeof(ddsd)); //1
ddsd.dwSize = sizeof(ddsd); //2
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; //3
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
DDSCAPS_COMPLEX; //4
ddsd.dwBackBufferCount = 1; //5 máme jeden zadní buffer !!!
if((dwResult = m_lpDD->CreateSurface(&ddsd, &m_lpDDSFront, NULL)) != DD_OK) {
TRACE("Cannot create front buffer due %d\n", dwResult);
return dwResult;
} //6
Nyní máme ukazatel na přední buffer : m_lpDDSPrimary
Postup :
-
Vynulování paměti před inicializací struktury. Tento bod není nutný, ale obecně
se doporučuje, protože tak můžete předejít chybám.
-
Inicializace proměné dwSize na velikost struktury.
Naproti bodu 1 je tento krok naprosto nutný. Atribut
dwSize se objeví i u jiných
struktur a vždy se musí inicializovat na správnou velikost struktury.
-
Nastavení příznaků, které atributy struktury budou platné. V našem
případě jsou to dssCaps a dwBackBufferCount
-
Inicializace členu dssCaps Inicializace členu dwBackBufferCount .
Určuje počet zadních bufferů, v našem případě máme jen jeden, ale můžeme jich
použít více (triple buffer). -
Zavolání funkce CreateSurface() se zadanou strukturou.
Konečné vytvoření povrchu, alokování paměti pro povrch a vrácení ukazatele.
K získání ukazatele na zadní buffer je zde ovšem jiná funkce, která
počítá s tím, že je zadní buffer ve flippovací smyčce :
HRESULT GetAttachedSurface( LPDDSCAPS2 lpDDSCaps,
LPDIRECTDRAWSURFACE7 FAR * lplpDDSurface);
Důležité je, že tato funkce je členská funkce rozhraní
IDirectDrawSurface7 a nikoliv (jak tomu bylo dosud)
IDirectDraw7 .
Příklad vytvoření zadního bufferu
DDSCAPS2 ddscaps;
ZeroMemory(&ddscaps, sizeof(ddscaps));//1
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;//2
if((dwResult = m_lpDDSFront->GetAttachedSurface(&ddscaps, &m_lpDDSBack)) != DD_OK)
{
TRACE("Cannot create back buffer due %d\n", dwResult);
return dwResult;
} //3
Postup :
-
Vynulování paměti před inicializaci struktury. Viz výše. -
Nastavení, že vytvářený povrch bude zadní (back).
Vidíte, že nepoužíváme strukturu DDSURFACEDESC2,
ale jen její část DDSCAPS2. -
Získání ukazatele na povrch: m_lpDDSBack .
Všimněte si, že nepoužíváme výše zmíněnou funkci
CreateSurface(), je to z toho důvodu, že vytváříme buffer ve flippovací
smyčce. Povrch je vlastně vytvořen již nahoře a nyní si žádáme jen o ukazatel na
něj.
4.2. Přepsání funkce Run()
Minule jsme si ve třídě aplikace (CDirectDrawApp) připravili funkci
Run(). V dnešní lekci ji upravíme tak, aby volala funkci
UpdateFrame()
třídy CControl, když smyčka zpráv nepřijímá žádné zprávy.
Objekt CControl máte vytvořený buď přímo jako členskou proměnnou
ve třídě aplikace nebo ji můžete vytvořit
globálně a funkci UpdateFrame() vytvořit také jako globální
funkci.
Poté bude vypadat funkce Run() následovně.
int CDirectDrawApp::Run()
{
MSG msg;
while( 1 )
{
if( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
if( !::GetMessage( &msg, NULL, 0, 0 ) )
{
return msg.wParam;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else
{
m_theControl.UpdateFrame();
}
}
}
Nesmíte zapomenout vymazat původní jeden řádek této funkce.
Funkce nyní bude volat funkci UpdateFrame()
jak nejrychleji to půjde – pokud nemá co na práci.
4.3. Funkce UpdateFrame()
Jako poslední v této lekci ještě něco napíšeme do funkce
UpdateFrame() , aby se povrchy skutečně prohazovaly.
void CControl::UpdateFrame()
{
if(m_lpDDSFront) {
m_lpDDSFront->Flip(NULL, DDFLIP_WAIT);
}
}
Zatím zde nemáme žádné ochrany proti ztracení povrchu atd.
Druhý parametr funkce Flip() znamená,
že funkce počká až se ostatní blitovací akce dokončí. Příště funkci dále rozšíříme.
4.4. Závěr
Pokud dnešní aplikaci zkompilujete, mělo
by se vám přepnout rozlišení a obrazovka je zatím bílá.
Prohazování povrchů probíhá, ale není vidět jelikož mají
oba buffery stejný obsah. Někdy se může stát, že v zadním
bufferu zbudou nějaké zbytky oken z Windows, protože při
vytváření povrchu se může alokovat paměť, kterou předtím
používaly Windows a nechaly ji "prasácky" nevymazanou.
Příště si vytvoříme pomocné buffery (off-screen surfaces) v systémové paměti,
do kterých uložíme bitmapy, které potom budeme vykreslovat do zadního bufferu.
Těším se příště nashledanou.
|