03 - Starta och Avsluta DirectGraphics
Starta och Avsluta DirectGraphics
Nu har vi vår fina lilla header-fil, innehållande vår "grafik-motor" klass. Då är det väl dax att börja implementera funktionerna.
Skapa källkodsfilen 'Graphics.cpp' och så kan vi ju börja lite enkelt och implementera konstruktorn och destruktorn först.
#include "Graphics.h"
GraphicsEngine::GraphicsEngine()
{
m_pD3D = NULL;
m_pDevice = NULL;
}
GraphicsEngine::~GraphicsEngine()
{
Shutdown();
}
-
Vi börjar med att inkludera vår header-fil som vi gjorde i föregående kapitel. Konstruktorn nollställer bara pekarna så att dom inte pekare på nått. Det gör vi för att när programmet avslutas ska kunna avgöra om pekarna pekar på något och isåfall städa upp det. Destruktorn kör bara medlemsfunktionen 'Shutdown()'.
Ok, då var det dax att implementera själv huvudfunktionen, 'Initialize()'. Den tar en parameter och det är ett 'handle' till det skapade Windows fönstret.
bool GraphicsEngine::Initialize(HWND hWnd)
{
if((m_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
{
return false;
}
-
'Direct3DCreate9()' försöker skapa en instans av huvud-DirectGraphics objektet. Detta objekt används för att skapa sk. devices och mycket annat. Om den lyckas kommer 'm_pD3D' pekaren att peka på den nya instansen av DirectGraphics objektet. Annars returnera den ett false, vilket innebär att funktionen misslyckades.
DirectGraphics Device
En 'device' i DirectGraphics är ett objekt som representerar grafikkortet i din maskin. För att starta upp DirectGraphics måste vi fylla i en struct med massa parametrar, likt wndclass structen för Windows fönster. Den skickar vi sedan som parameter till en medlemsfunktion i 'm_pD3D' objektet som i sin tur skapar en 'device' (förutsatt att alla parametrar är ok).
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = true;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &m_pDevice)))
{
return false;
}
return true;
}
-
För att kunna förstå vad varje utav dessa parametrar gör så bör jag nog förklara ett par koncept först.
Backbuffer och Swapchain
En backbuffer är en minnesbuffer på grafikkortets minne. En swapchain är en kedja utav dessa buffrar. En utav buffrarna i kedjan kallas för front buffern och är den som är främst i kedjan. Det är även den buffern som syns på skärmen. När ditt program ritar saker så ritas dom först till en backbuffer. Sen presenteras backbuffern till front buffer med hjälp av en sk. swap effekt. Denna effekt kan vara att buffrarna byter plats med varandra t.ex.
Bufferformat
Buffrarna är ju egentligen enbart allokerade minnesareor och bufferformat talar helt enkelt om hur mycket minne varje pixel in en buffer ska ta upp. Ett vanlig format är 'D3DFMT_A8R8G8B8' som allokerar 8-bit per färgkomponent (RGB) samt 8-bit för en alpha-kanal, totalt 32-bit per pixel.
Depth och Stencil buffer
En depth buffer (även kallad Z buffer) används för att bestämma på vilket djup i scenen som varje pixel har blivit utritad på. När varje pixel för ett 3d objekt ritas ut som färger i backbuffern så sätts även varje pixels z-djup (förutsatt att man använder en depth buffer) i depthbuffern. Varför vill man använda detta då? Jo, för då kan man effektivt veta om en pixel skall ritas ut eller inte. Eftersom 3d objekt kan ligga framför eller bakom varandra i 3d-rymden. Så har pixeln redan ett z-värde som är framför det den tänker rita ut så struntar den i det.
Stencilbuffrar liknar depthbuffrar en smula. Med en stencilbuffer kan sätta upp ett eget "mönster" som den ska leta efter och antingen neka eller tillåta utritning av pixlar. Detta kan man använda sig utav till effekter bland annat. Jag kommer gå in djupare på stencilbuffrar i senare delar av den här serien.
Nu tänkte jag förklara vad parametrarna betyder. Jag sätter enbart nåra av dom parametrar som finns i 'D3DPRESENT_PARAMETERS', resten får du läsa om i SDK dokumentationen.
- Windowed - true eller false beroende på om du vill köra i fönster-läge eller fullskärm.
- BackBufferFormat - Formatet på backbufferarna. Använd D3DFMT_UNKNOWN om du kör i window-läge för att använda samma format som i Windows.
- EnableAutoDepthStencil - Anger om du vill att den ska skapa en depth och/eller stencil buffer åt dig automatiskt.
- AutoDepthStencilFormat - Formatet för depth/stencil buffern.
- PresentationInterval - Den maximala hastigheten som buffer kedjan kan presentera backbuffrar till front buffern. D3DPRESENT_INTERVAL_IMMEDIATE innebär att den uppdatera så fort den bara kan. Den kan alltså uppdatera flera gånger under en "vertical sync"-cykel. D3DPRESENT_INTERVAL_DEFAULT så kommer den vänta tills "vertical sync" perioden är över och sedan rita. Det innebär att utritningen kommer ske lika ofta som monitorns refresh rate. Det finns fler värden man kan ange här, men dom får du kolla upp i SDK dokumentationen själv.
- hDeviceWindow - Handle till windows fönstret som ska använda sig utav DirectGraphics.
- BackBufferCount - Antalet backbuffrar du vill använda. Man kan öka prestandan på utritningen om man använder fler. Men tänk på att varje buffer tar plats i ditt grafikminne.
- MultiSampleType - Anger hur många multisampling punkter som ska användas. Måste vara D3DMULTISAMPLE_NONE om man inte använder D3DSWAPEFFECT_DISCARD som swap effekt.
- SwapEffect - Hur den hanterar själva utbytet av backbuffrar. D3DSWAPEFFECT_FLIP byter helt enkelt bara plats på backbuffern och front buffern. D3DSWAPEFFECT_COPY kopiera backbuffern till front buffern. D3DSWAPEFFECT_DISCARD tillåter drivern att använda den mest effektiva utbytes metoden för tillfället men kan inte garantera att backbuffrarnas innehåll förblir intakta. Dom två föregående metoderna kan skapa endel "overhead" som man slipper med denna metod.
Sådär, nu är det bara själva 'CreateDevice()' anropet kvar. Jag ska förklara vad parametrarna till funktion, men först bör ni veta vad HAL och REF är.
HAL och REF
HAL står för 'Hardware Abstraction Layer' och är lagret som DirectGraphics använder för att komma åt ditt grafikkort genom. På så sätt kan DirectGraphics använda sig utav dess kraft för utritning och kalkylering av 3D grafik.
REF står för 'Reference Rasterizer' och emulerar alla DirectGraphics funktioner i mjukvara. Detta är väldigt slött, men allt som DirectGraphics är kapabel till kan emuleras via REF. Används mest för att debugga.
HRESULT CreateDevice(UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS *pPresentationParameters,
IDirect3DDevice9 **ppReturnedDeviceInterface
);
-
Så ser funktionshuvudet ut för 'CreateDevice()'.
- Adapter - Anger vilken adapter du vill använda. En adapter är ett grafikkort och eftersom dom flest bara har ett sådant kort i datorn så kan man använda D3DADAPTER_DEFAULT.
- DeviceType - D3DDEVTYPE_HAL eller D3DDEVTYPE_REF.
- hFocusWindow - Ett handle till windows fönstret.
- BehaviorFlags - Ett antal olika flaggor som kan användas vid skapandet av 'device'. Du bör sätta flaggan D3DCREATE_HARDWARE_VERTEXPROCESSING eftersom vi vill att verticar ska processas på hårdvaran.
- pPresentationParameters - Din struct med parametrar.
- ppReturnedDeviceInterface - Den returnerad pekaren till din nyskapade 'device'.
Sådär, inte så farligt svårt va? Nu återstår det bara att rensa upp efter DirectGraphics. Det gör vi i funktionen 'Shutdown()'.
void GraphicsEngine::Shutdown()
{
if(m_pD3D) { m_pD3D->Release(); m_pD3D = NULL; }
if(m_pDevice) { m_pDevice->Release(); m_pDevice = NULL; }
}
-
Detta är grunden för vår motor. Denna kod sätter igång DirectGraphics och städar sedan upp efter sig. Inte så upphetsande kanske, men det måste ju göras.
Det var allt jag tänkte gå igenom nu. I nästa artikel så tänkte jag ta upp vertex och index buffrar, alltså hur man kan få ut trianglar på skärmen.
Ha det så bra tills dess!
Källa: http://blinkenlights.se/