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 :

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

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

  3. Nastavenφ p°φznak∙, kterΘ atributy struktury budou platnΘ. V naÜem p°φpad∞ jsou to dssCaps a dwBackBufferCount

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

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

  1. Vynulovßnφ pam∞ti p°ed inicializaci struktury. Viz v²Üe.

  2. Nastavenφ, ₧e vytvß°en² povrch bude zadnφ (back). Vidφte, ₧e nepou₧φvßme strukturu DDSURFACEDESC2, ale jen jejφ Φßst DDSCAPS2.

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

Ji°φ Formßnek