GrafickΘ aplikace ve Visual C++ (3.)
V tΘto lekci si koneΦn∞ povφme o zßkladnφch pojmech a principech DirectDraw. V prvnφ Φßsti si
rozebereme d∙le₧itΘ pojmy jako jsou nap°φklad povrchy (surfaces) a v druhΘ Φßsti vßm vysv∞tlφm,
jak vlastn∞ DirectDraw pracuje. Nakonec si ukß₧eme konkretnφ p°φklad, jak vytvo°it objekt DirectDraw
a nastavφme dalÜφ vlastnosti aplikace. Popisuju zde jen re₧im fullscreen (celoobrazovkov² re₧im),
ale DirectDraw samoz°ejm∞ pracuje i v okn∞.
3.1. Zßkladnφ pojmy
Zßkladem ka₧dΘ aplikace zalo₧enΘ na principu DirectDraw je jeden objekt typu IDirectDraw7
(je to vlastn∞ ukazatel na rozhranφ COM),
pomocφ kterΘho vytvo°φte vÜechny ostatnφ objekty pot°ebnΘ pro kreslenφ apod. Tak₧e prvnφ, co musφte
ud∞lat je, ₧e vytvo°φte tento objekt.
Sprite je vlastn∞ vßmi vykreslovan² obrßzek. Sprite je v∞tÜinou
vytvo°en z bitmapy, kterou naΦtete z externφho souboru. Pokud budete mφt
pohybujφcφ se letadlo, prßv∞ letadlo bude sprite.
DalÜφ velmi d∙le₧itou souΦßstφ je tzv. povrch (surface). Povrch je vlastn∞ buffer tzn. kousek
pam∞ti, bu∩ ve video pam∞ti nebo v systΘmovΘ RAM. Je to n∞co podobnΘho jako kontext za°φzenφ (DC - viz minulß lekce).
Do tohoto bufferu zapisujete data, kterΘ poslΘze vidφte na monitoru v podob∞ obrßzku.
Pokud budete pou₧φvat 8-bitovou barevnou hloubku tzn. 256 barev, m∞li byste
vytvo°it objekt palety. Pak je tento objekt velice d∙le₧it², jinak se
bitmapy zobrazφ chybn∞ (majφ prohßzenΘ barvy a n∞kterΘ barvy dokonce chybφ). Program, kter² pracuje
v 16-bitech (65 tisφc barev) ₧ßdnou paletu nepot°ebuje, ale b∞₧φ pomaleji, tak₧e pokud
nevlastnφte moc vykonn² poΦφtaΦ doporuΦuji pou₧φvat 8-bit∙.
DalÜφm u₧iteΦn²m objektem je tzv. clipper. Abyste pochopili jak pracuje musφte znßt
nßsledujφcφ lßtku. Prozatφm vßm musφ staΦit, ₧e zajiÜ¥uje tzv. clipping, co₧ u₧ jste
mo₧nß slyÜeli. JednoduÜe °eΦeno Clipper zabra≥uje vykreslovßnφ sprit∙ mimo monitor.
3.2. Zßkladnφ principy DirectDraw
Jak jsem se ji₧ zmφnil DirectDraw, dokß₧e vykreslovat pouze ve 2D tzn., ₧e vÜechny
povrchy jsou plochΘ (majφ dv∞ sou°adnice x a y). BitovΘ kopφrovßnφ mezi povrchy, co₧ je
vlastn∞ kopφrovßnφ
jednotliv²ch bit∙ vaÜich bitmap, se v terminologii DirectDraw naz²vß blitting
(bit block transfer - p°enos bloku bit∙).
Mßme dva zßkladnφ povrchy :
-
Front surface (FS)
-
Back surface (BS)
Front surface (p°ednφ povrch) je, jak napovφdß nßzev, ten povrch, kter² je prßv∞
vid∞t na monitoru. Back surface (zadnφ povrch) je ukryt n∞kde v pam∞ti jakoby za
FS. D∙le₧itΘ je, ₧e v₧dy zapisujete jen do BS nikdy do FS. Kdybyste toti₧ zapisovali
do FS p°φmo, docφlili byste podobnΘho efektu jako u GDI.
Tak₧e vy zapφÜete n∞jakΘ data do BS, ale co dßl?
DirectDraw mß jistou funkci, kterß dokß₧e oba povrchy prohodit. Tak₧e FS je pak
vzadu a nenφ vid∞t a BS je vp°edu a normßln∞ viditeln². Toto prohozenφ je velmi
rychlΘ tak₧e lidskΘ oko ho samoz°ejm∞ nepost°ehne. Funkce navφc v₧dy poΦkß na tu
kratiΦkou dobu, kdy se paprsek monitoru p°esouvß z pravΘho dolnφho rohu do levΘho hornφho,
tak₧e vlastn∞ nemßte ₧ßdnou Üanci post°ehnout n∞jakΘ problikßvßnφ ani kdybyste se rozkrßjeli.
Tomuto systΘmu prohazovßnφ povrch∙ se °φkß flipping. Flipping toti₧ prohazuje ukazatele na
oba povrchy a nepou₧φvß
b∞₧n² blitting, kter² se pou₧φvß pro p°enos bit∙ mezi povrchy a kter² je Φasov∞ mnohem nßroΦn∞jÜφ.
Velikost t∞chto dvou buffer∙ zßle₧φ na rozliÜenφ, kterΘ prßv∞ pou₧φvßte.
Tyto buffery se zßsadn∞ vytvß°φ ve video pam∞ti, kterß je rychlejÜφ
ne₧ systΘmovß RAM, zvlßÜt∞ u modernφch grafick²ch karet.
Dßle si v∞tÜinou vytvß°φte tzv. OffScreen surfaces, co₧ jsou povrchy, kterΘ
jsou mimo flipovacφ smyΦku. Tyto povrchy pou₧φvßme pro bitmapy, kterΘ teprve
budeme chtφt zobrazit tzn. jako pomocnΘ buffery. Z t∞chto povrch∙ se pak
blitujφ data do BS. Tyto buffery se vytvß°ejφ v RAM a tudφ₧ mohou b²t v∞tÜφ
ne₧ FS a BS. Ve skuteΦnosti se vßm nepoda°φ ve video pam∞ti vytvo°it buffer,
kter² je v∞tÜφ ne₧ FS. Leda₧e mßte grafickou kartu, kterß mß hodn∞ pam∞ti a
podporuje funkci Wide surfaces (ÜirokΘ povrchy).
Cel² systΘm vypadß nßsledovn∞ :
Pokud budete mφt rozliÜenφ 640x480 a 8-bit∙ barev (256 barev) FS vßm zabere
p°esn∞ 640 x 480 (plus n∞jakΘ informace o povrchu), co₧ je asi 300 kB pam∞ti tzn.
₧e kdy₧ vytvo°φte FS a BS musφte
mφt alespo≥ 600 kB video pam∞ti na grafickΘ kart∞. Pokud tomu tak nenφ, budete
muset vytvo°it BS v RAM, ale to se siln∞ nedoporuΦuje. Samoz°ejm∞ pokud zv²Üφte
rozliÜenφ nebo hloubku barev, pam∞¥ovΘ nßroky se rovn∞₧ zv²Üφ, tak₧e na to pozor.
DneÜnφ grafickΘ karty mφvajφ b∞₧n∞ alespo≥ 16 MB pam∞ti a tam se vßm to vejde s p°ehledem.
Dßle je mo₧no vytvo°it vφce BS nap°φklad dva, pak se systΘmu °φkß Triple buffering
(mßme celkem t°i buffery : dva back + jeden front) a to u₧ jste urΦit∞ slyÜeli.
Ka₧dß aplikace DirectDraw pracuje tak, ₧e se sna₧φ prohazovat oba povrchy jak
nejrychleji to jde a p°itom se obΦas n∞co zapφÜe do BS. Prohazovacφ funkce Φekß
a₧ se dokreslφ vÜechny blittovacφ operace, tak₧e se nemusφte bßt, ₧e by se n∞co
nedokreslilo nebo snad dokonce problikßvalo! ╚φm vφce toho vykreslujete, tφm
je prohazovßnφ pomalejÜφ.
Jak ale za°φdit toto rychlΘ prohazovßnφ?
UrΦit∞ nezkouÜejte psßt nekoneΦnou smyΦku for(;;) , proto₧e pak by se aplikace
zablokovala a nep°ijφmala by ₧ßdnΘ zprßvy Windows a ty budeme pot°ebovat.
T°φda CWinApp mß Φlenskou funkci Run() , kterß
spouÜtφ smyΦku zprßv. Vy tuto funkci
m∙₧ete p°epsat a upravit tak, ₧e aplikace normßln∞ zpracovßvß zprßvy Windows (windows
messages), ale navφc volß vaÜi funkci, kterß obnovuje obraz a prohazuje povrchy. Toto
provßdφ pouze pokud nemß, co na prßci tzn., ₧e nep°ichßzejφ ₧ßdnΘ zprßvy od Windows.
3.3. Objekt DirectDraw
Tak₧e te∩ ji₧ vφme, ₧e ka₧dß
aplikace zalo₧enß na DirectDraw mß jeden objekt
typu IDirectDraw7 .
Jak ale tento objekt vytvo°φme?
Za prvΘ musφme
vlo₧it hlaviΦkov² soubor ddraw.h (nejlΘpe do souboru
StdAfx.h ) a za druhΘ p°ilinkovat dynamickΘ knihovny
ddraw.dll a dxguid.dll .
Knihovny se vklßdajφ v menu Project/Settings.
Na kart∞ Link se do polφΦka Object/library modules vlo₧φ
ddraw.lib a dxguid.lib .
To je vÜe. Te∩ nßm kompilßtor automaticky vlo₧φ
hlaviΦkov² soubor ddraw.h a linker p°ilinkuje knihovnu
ddraw.dll a dxguid.dll .
Poznßmka: Pro nφ₧e uvedenen² k≤d musφte
mφt nainstalovanΘ DirectX SDK 8.0, kterΘ bylo na °ijnovΘm ChipCD.
Dßle zkontrolujte v Options VC++, ₧e na kart∞ Directories, je
cesta k hlaviΦkov²m soubor∙m naistalovanΘho SDK, pokud ne, musφte
polo₧ku p°idat sami.
Nynφ m∙₧eme pou₧φt globßlnφ funkci DirectDrawCreateEx() k vytvo°enφ objektu DirectDraw.
Funkce mß nßsledujφcφ deklaraci :
HRESULT DirectDrawCreateEx( GUID FAR *lpGUID, LPVOID *lplpDD, REFIID iid, IUnknown FAR *pUnkOuter );
-
Prvnφ parametr je globßlnφ unikßtnφ identifikßtor grafickΘho ovladaΦe.
Pokud zadßte NULL , program vybere souΦasn² grafick² ovladaΦ.
Navφc m∙₧ete zadat tyto hodnoty :
-
DDCREATE_EMULATIONONLY û vyu₧φvß se pouze softwarovß
emulace tzn. ₧e nenφ
podporovßno ₧ßdnΘ hardwarovΘ urychlovßnφ
-
DDCREATE_HARDWAREONLY û vyu₧φvß se pouze hardwarovΘ
vybavenφ grafickΘ karty,
pokud karta nepodporuje danΘ prvky, funkce vracφ
DDERR_UNSUPPORTED .
-
Druh² parametr je ukazatel na ukazatel na objekt DirectDraw, kter² chceme vytvo°it.
Ve t°φd∞ CControl si deklarujeme Φlenskou prom∞nou typu
LPDIRECTDRAW7 m_lpDD , co₧ je ukazatel
na DirectDraw. Tento ukazatel potom dosadφme jako druh² parametr funkce. Pozor! Je to
ukazatel na ukazatel!.
-
Tento parametr musφ b²t nastaven na hodnotuIID_IDirectDraw7 .
Je identifikßtor rozhranφ COM.
-
T°etφ parametr je pro integraci programovßnφ technologiφ COM (Component
Object Model).
Nynφ funkce vracφ chybu pokud zadßte n∞co jinΘho ne₧ NULL .
3.4. Nastavenφ dalÜφch vlastnostφ aplikace
Pomocφ ukazatele na objekt DirectDraw nastavφme, jak se bude naÜe
aplikace chovat v∙Φi jin²m program∙m Windows a
jakΘ rozliÜenφ a hloubku barev budeme pou₧φvat.
Spoluprßcφ s ostatnφmi programy zajiÜ¥uje tato funkce:
HRESULT SetCooperativeLevel(HWND hWnd, DWORD dwFlags);
Funkce mß nßsledujφcφ dva parametry :
-
hWnd - To jest handle na hlavnφ rßmcovΘ okno û ten se zjistφ velmi jednoduÜe:
zavolejte funkci GetSafeHwnd() , kterß vrßtφ platn² handle.
-
dwFlags - P°φznaky, kterΘ popisujφ, jak se vaÜe
aplikace chovß k ostatnφm. Mohou se samoz°ejm∞
kombinovat. My pou₧ijeme nßsledujφcφ :
-
DDSCL_EXCLUSIVE û zajistφ, ₧e aplikace mß v²hradnφ prßvo. Tento p°φznak
musφ b²t pou₧it s DDSCL_FULLSCREEN
-
DDSCL_FULLSCREEN û indikuje, ₧e aplikace bude fullscreen (celoobrazovkovß).
Musφ b²t samoz°ejm∞ pou₧it s DDSCL_EXCLUSIVE .
-
DDSCL_ALLOWREBOOT û povoluje klßvesovou zkratku Ctrl + Alt + Delete p°i
v²hradnφm re₧imu tzn. ₧e m∙₧ete z aplikace vyskoΦit p°es Sprßvce ·loh. To je d∙le₧itΘ,
kdy₧ nevφte jestli vßm aplikace nßhodou neshodφ Windows.
P°φznak∙ je mnohem vφc, ale my si vystaΦφme s t∞mito t°emi.
Druh²m velice d∙le₧it²m nastavenφm je rozliÜenφ a hloubka barev.
Dßle tedy nastavφme grafick² re₧im pomocφ tΘto funkce:
HRESULT SetDisplayMode(DWORD dwWidth,
DWORD dwHeight,
DWORD dwBPP,
DWORD dwRefreshRate,
DWORD dwFlags);
Tato funkce mß p∞t parametr∙:
-
dwWidth - RozliÜenφ v horizontßlnφm sm∞ru v pixelech.
M∙₧ete hodnotu naΦφst z registr∙, z ini souboru nebo si definovat konstanty v souboru.
Mo₧nostφ je spoustu a zale₧φ na vßs, jakou se vyberete. V p°φkladu definuji konstantu 640 pixel∙.
-
dwHeight - RozliÜenφ ve vertikßlnφm sm∞ru v pixelech. Nastavφme 480 pixel∙.
-
dwBPP - Hloubka barev v bitech na pixel. Nastavφme 16 bit∙.
-
dwRefreshRate - Obnovovacφ frekvence monitoru. Zde m∙₧ete nastavit obnovovacφ
frekvenci se kterou se bude vßÜ monitor obnovovat. ProblΘm je v tom, ₧e pokud nastavφte natvrdo n∞jakΘ
Φφslo, nemusφ (a taky nejspφÜ nebude) program b∞hat na jinΘm poΦφtaΦi, proto₧e ne vÜechny monitory
zvlßdajφ vaÜe nastavenφ. Kdy₧ zadßte 0, pou₧ije standardnφ nastavenφ DirectDraw (toto nastavenφ se dß
nastavit v DXDiag). Tak₧e nastavte 0.
-
dwFlags - P°φznaky pro budoucφ pou₧itφ:) Nastavte 0.
3.5. P°φklad
Nynφ dßme vÜechny novΘ poznatky dohromady.
Ve t°etφm kurzu o VC++ jste vytvo°ili t°φdu CControl, kde vytvo°te Φlenskou funkci t°eba
DDInit(HWND hWnd) .
Budete ji volat vzßp∞tφ za funkcφ WinInit() z
InitInstance() a p°edßte ji handle vaÜeho okna.
Ve t°φd∞ CControl takΘ vytvo°te Φlenskou prom∞nnou
m_lpDD typu LPDIRECTDRAW7 a nadefinujte
konstanty RES_X = 640, RES_Y = 480 a RES_BITDEPTH = 16 .
HRESULT CControl::DDInit(HWND hWnd)
{
HRESULT dwResult;
// DirectDraw object creation
dwResult = DirectDrawCreateEx(NULL, (void**)&m_lpDD, IID_DirectDraw7, NULL);
if(dwResult != DD_OK) {
TRACE("Cannot create direct draw object due %d\n", dwResult);
return dwResult;
}
// Setting cooperative level
dwResult = m_lpDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE|
DDSCL_FULLSCREEN|
DDSCL_ALLOWREBOOT);
if(dwResult != DD_OK) {
TRACE("Cannot set cooperative level due %d\n", dwResult);
return dwResult;
}
// Setting display mode
dwResult = m_lpDD->SetDisplayMode(RES_X,RES_Y, RES_BITDEPTH, 0, 0);
if(dwResult != DD_OK) {
TRACE("Cannot set display mode due %d\n", dwResult);
return dwResult;
}
return dwResult;
}
4 . Zßv∞r
Aplikace z dneÜnφ lekce akorßt p°epne rozliÜenφ, nic vφc.
P°φst∞ si vytvo°φme front a back buffer a vytvo°φme flipovacφ smyΦku.
T∞Üφm se p°φÜt∞ nashledanou.
|