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 );

  1. 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.


  2. 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!.

  3. Tento parametr musφ b²t nastaven na hodnotuIID_IDirectDraw7. Je identifikßtor rozhranφ COM.

  4. 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 :

  1. hWnd - To jest handle na hlavnφ rßmcovΘ okno û ten se zjistφ velmi jednoduÜe: zavolejte funkci GetSafeHwnd(), kterß vrßtφ platn² handle.

  2. 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∙:

      1. 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∙.

      2. dwHeight - RozliÜenφ ve vertikßlnφm sm∞ru v pixelech. Nastavφme 480 pixel∙.

      3. dwBPP - Hloubka barev v bitech na pixel. Nastavφme 16 bit∙.

      4. 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.

      5. 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.

      Ji°φ Formßnek