DirectX Tutoriál 1: Začínáme


Co potřebujete

Úvod

Tak Vás vítám v první kapitole DirectX tutoriálu. Tento seriál se bude snažit o to, aby Vám pomohl na první cestě (nebo alespoň první úspěšné) k tvorbě aplikací pomocí DX8. Na začátku stály dva důvody k napsání tohoto seriálu. Za prvé, k DirectX jsem se dostal jako úplný začátečník. Takže jak se budu DX učit, tak se budu snažit předávat své čerstvé znalosti. Za druhé, SDK není to pravé ořechové pro úplného začátečníka ve vývoji aplikací s DX8, ovšem musím zde upozornit, že pro trochu znalého programátora je pak SDK neocenitelné. A navíc na internetu není mnoho materiálu k DX8 pro začátečníky, nemluvě o českých článcích. A ještě poznámka, sám jsem začátečník, takže pokud zde budou nějaké nesrovnalosti, kontaktujte mě prosím na e-adrese directx.kvalitne@email.cz.

COM

Proč se hned na začátku budeme bavit o COMech při nichž vstávají programátorům vlasy hrůzou na hlavě? Protože DirectX je na COMech založen, ale nebojte se, DX je navržen tak, že Vás od COMů v podstatě oddělí. A co je to vlastně COM? Zkrátka, COM (Component Object Model) je v podstatě knihovna metod. Můžete vytvořit COM objekt ve Vašem programu a potom volat metody, které poskytuje. Související metody jsou sdružovány do společných kolekcí. Tyto kolekce jsou přístupny přes interfaces(rozhraní). DirectX poskytuje množství těchto knihoven, které umožňují vytvářet 3D aplikace. A nejlepší na tom je to, jak jsem uvedl výše, že DX za Vás udělá mnoho špinavé práce, takže je nyní opravdu jednoduché začít s DX.

Je toho mnohem víc co dokážou COM, pro bližší informace se podívejte do SDK. Na co byste si měli dát pozor, je uvolnit (anglicky Release) všechny COM objekty/interfaces(rozhraní) než ukončíte program. Uvolňují se v opačném pořadí než byli vytvořeny. Například:

  1. Vytvořit(Create) interface A.
  2. Vytvořit(Create) interface B.
  3. Uvolnit(Release) interface B.
  4. Uvolnit(Release) interface A.

Uvolňujete COM objekty voláním jejich release method.

Page Flipping

Co je to page Flipping? Přeloženo do češtiny to znamená přepínání stránek. Budu ale používat anglický výraz, abych tím nemátl čtenáře anglické dokumentace. Obraz na monitoru (mluvím o CRT, u LCD je to trošku jinak, ale principiálně vzniká stejný efekt jaký popíšu) se vykresluje postupně, tzn. že speciálně naváděný paprsek rozsvěcuje postupně zleva doprava, řádek za řádkem různým jasem body na stínítku, které pak celkově tvoří zobrazovaný obraz. Když paprsek dojede na konec stínítka, sníží se jeho jas na nulu a přesune se zpět do levého horního rohu. Pokud bychom kreslili pořád do stejné paměti, odkud se čtou data pro monitor, působil by obraz rušivě, protože bysme se trefovali tu před paprsek, tu za něj a vznikalo by tzv. sněžení. Od toho je tu page flipping, kdy se počká na moment přesunu paprsku a přepne se jen ukazatel na už vytvořený snímek. Přepínání ukazatelů je mnohem rychlejší než kopírování, ale je také pamětově náročnější. V Direct Graphics (součást DirectX) se toto přepínání provádí voláním jediné metody. Další snímek se vykresluje na skrytou stránku nazývaný "back buffer". Na tuto stránku se v momentě přesunu paprsku přehodí ukazatel a ze zobrazované se stane "back buffer". Tomuto se říká double buffering, protože stránky jsou 2. Samozřejmě stránek "back buffer" může být i víc. Bodově shrnuto:

  1. Ukazatel na aktuální stránku = umístění 1. stránky. Ukazatel na back buffer = umístění 2. stránky.
  2. Budeme kreslit do back buffer (nyní 2.stránka).
  3. Zavoláme metodu na page flipping. Takže nyní je stav: Ukazatel na aktuální stránku = umístění 2. stránky. Ukazatel na back buffer = umístění 1. stránky.
  4. Budeme kreslit do back buffer (nyni 1.stránka).
  5. Zpět na bod 1. A tak pořád dokola.

Devices

Co to je device? Schválně tento výraz stejně jako předchozí nepřekládám, poněvadž si myslím, že by se tím věci více zamotaly. Ale český výraz je zařízení. V podstatě device je Vaše 3D grafická karta (bavíme se nyní o grafice). Můžete vytvořit rozhraní, které bude zpřístupňovat vaše device a umožní Vám kreslit objekty na back buffer.

Herní smyčka

Abysme oddělili pojem smyčka zpráv od naší smyčky, nazvěme ji herní smyčka. Herní smyčka se bude motat tak dlouho, dokud program neskončí. A uvnitř ní se děje toto: jsou vykresleny objekty (tzv. vyrendrovány), provede se logika (umělá inteligence, počítání bodů, atd.) a ošetří se zprávy windows. A pak zase a zase až do ukončení programu.

Tvoříme první projekt

Takže teorii pro začátek nějakou máme a vytvoříme první projekt. Jak nastavíme prostředí se dočtete v jiném článku. Teď si vytvořte nový soubor a nazvěte ho main.cpp

#include <d3d8.h>

LPDIRECT3D8             g_pD3D			= NULL;
LPDIRECT3DDEVICE8       g_pD3DDevice	= NULL;

HRESULT InitialiseD3D(HWND hWnd)
{
   //Jako úplně první věc vytvoříme hlavní D3D objekt. Jestliže se vytvoří korektně,
   //získáme ukazatel na IDirect3D8 interface.
   g_pD3D = Direct3DCreate8(D3D_SDK_VERSION);
   if(g_pD3D == NULL)
   {
      return E_FAIL;
   }

   //Zjistíme aktuální mód zobrazovacího zařízení
   D3DDISPLAYMODE d3ddm;
   if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
   {
      return E_FAIL;
   }

   //Vytvoříme si strukturu pro uschování nastavení našeho device
   D3DPRESENT_PARAMETERS d3dpp; 
   ZeroMemory(&d3dpp, sizeof(d3dpp));

   //Vyplníme strukturu
   //Chceme aby náš program byl v okně a nastavíme back buffer na formát, který
   //odpovídá aktuálnímu zobrazovacímu zařízení
   d3dpp.Windowed	  = TRUE;
   d3dpp.SwapEffect       = D3DSWAPEFFECT_COPY_VSYNC;
   d3dpp.BackBufferFormat = d3ddm.Format;

   //Vytvoříme Direct3D device
   if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, 
             D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice)))
   {
      return E_FAIL;
   }
    
   return S_OK;
}

void Render()
{
   if(g_pD3DDevice == NULL)
   {
      return;
   }

   //Vymažeme back buffer zelenou barvou
   g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0);
    
   //Tady se začíná vytvářet scéna
   g_pD3DDevice->BeginScene();
    
   //Vytváření objektů se bude provádět tady    
   
   //Tady tvorba scény končí
   g_pD3DDevice->EndScene();
    
   //Tímto se provede Page Flipping (popsáno výše). Máme 1 back buffer, takže se
   //budou prohazovat zobrazený obraz se skrytým. Jinak řečeno se zobrazí objekty
   //které jsme vytvořili ve scéně.
   g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}

void CleanUp()
{
   // Všechno musíme uvolnit
   if(g_pD3DDevice != NULL)
   {
      g_pD3DDevice->Release();
      g_pD3DDevice = NULL;
   }

   if(g_pD3D != NULL)
   {
      g_pD3D->Release();
      g_pD3D = NULL;
   }
}

void GameLoop()
{
   //A nyní začne herní smyčka
   MSG msg; 
   BOOL fMessage;


   while(msg.message != WM_QUIT)
   {
      fMessage = PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE);

      if(fMessage)
      {
         //Ošetří se zprávy windows
         TranslateMessage(&msg);
         DispatchMessage(&msg);
      }
      else
      {
         //Nejsou žádné zprávy k ošetření, takže vytvoříme scénu
         Render();
      }
   }
}

//Procedura okna
LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch(msg)
   {
      case WM_DESTROY:
         PostQuitMessage(0);
         return 0;
      case WM_KEYUP: 
         switch (wParam)
         { 
            case VK_ESCAPE:
               //Uživatel stiskl klávesu Esc, takže končíme
               DestroyWindow(hWnd);
               return 0;
         } 
      case WM_PAINT:
         Render();
         ValidateRect( hWnd, NULL );         
         return 0;

    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

//Vstupní bod aplikace
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
{
   //Zaregistrujeme okno
   WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, WinProc, 0L, 0L, 
                    GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                    "DX Tut1", NULL};
   RegisterClassEx(&wc);

   //Vytvoříme okno aplikace
   HWND hWnd = CreateWindow("DX Tut1", "directx.kvalitne.cz: Tutoriál 1", 
                            WS_OVERLAPPEDWINDOW, 50, 50, 500, 500,
                            GetDesktopWindow(), NULL, (HINSTANCE) wc.hInstance, NULL);

   //Inicializujeme Direct3D
   if(SUCCEEDED(InitialiseD3D(hWnd)))
   { 
      //Ukážeme naše okno
      ShowWindow(hWnd, SW_SHOWDEFAULT);
      UpdateWindow(hWnd);

      //Start, čili spustíme herní smyčku
      GameLoop();
   }
    
   CleanUp();

   UnregisterClass("DX Tut1", (HINSTANCE) wc.hInstance);
    
   return 0;
}

Po spuštění dostaneme okno se zeleným pozadím. Já vím, není to moc, ale odněkud se začít musí, ne?

Takže, co se vlastně děje?

WinMain
To je vstupní funkce windows aplikace. Vykonávání programu začíná tady. Zde se zaregistruje, vytvoří a ukáže naše okno. Jakmile je tohle hotovo, inicializujeme Direct3D a spustíme herní smyčku.

WinProc
V této funkci aplikace zpracovává zprávy. V naší aplikaci zpracováváme pouze 3 zprávy: WM_DESTROY, WM_KEYUP a WM_PAINT, všechny ostatní jsou posílány do DefWindowProc, kde se provádí standardní zpracování zpráv.

g_pD3D
Toto je ukazatel na Direct3D8 interface (IDirect3D8). Například pomocí tohoto interface později vytvoříme Direct3D Device.

g_pD3DDevice
Toto je ukazatel na Direct3DDevice8 interface (IDirect3Ddevice8). Tento ukazatel reprezentuje grafickou kartu.

InitialiseD3D
Inicializuje se všechno potřebné pro naší práci. Nejdříve se vytvoří IDirect3D8 objekt. Z tohoto objektu můžeme zjistit aktuální mód zobrazovacího zařízení. Nakonec na základě těchto informací vytvoříme device.

Herní smyčka
Jakmile je naše okno vytvořeno, spustí se herní smyčka. Pokud není žádná zpráva na zpracování, spustí se funkce Render().

Render
Nejdřív vymažeme back buffer a tím je připraven ke kreslení. Potom zavoláme metodu BeginScene našeho device object a tím oznámíme, že chceme nadefinovat scénu. Až pak můžeme začít generovat objekty (více 2. díl seriálu). Jakmile jsme tuto činnost dokončili, zavoláme metodu EndScene a tím oznámíme konec generování. Nakonec provedeme Page Flipping, čímž zobrazíme to co jsme vytvořili v back bufferu.

CleanUp
Jednoduše řečeno uvolňuje všechny naše objekty.

Závěr

Tak, a to je konec 1. dílu seriálu. Vím že program nedělá nic světoborného, ale příště si už vykreslíme nějaké objekty.

Vaše komentáře

Přidat komentář

Přidat komentář

Jméno
E-mail
Komentář:

webzdarma.cz