300 likes | 511 Views
CSE 380 – Computer Game Programming Graphics Device Management. Tennis for Two, 1958, by William Higinbotham, Brookhaven National Lab. What is a 2D game graphically speaking?. Basically 2 things: Texture rendering (images) Text rendering Rendering textures & text is easy
E N D
CSE 380 – Computer Game ProgrammingGraphics Device Management Tennis for Two, 1958, by William Higinbotham, Brookhaven National Lab
What is a 2D game graphically speaking? • Basically 2 things: • Texture rendering (images) • Text rendering • Rendering textures & text is easy • Efficiently managing the data of the game is not
DirectX • Windows API for making games • Microsoft says “The power of multimedia in Windows, DirectX gives you the best possible experience with graphics, sound, music, and 3-D animation.” • API in MSDN: • http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_m/directx/directx9m.asp
DirectX Architecture Windows Win32 Application Direct3D XAudio … Software emulation HEL: Hardware Emulation Layer HAL: Hardware Abstraction Layer Hardware: Audio, Video, Input, Storage …
DirectX Devices • Represent hardware • Direct3D device is the graphics processor • Graphics cards can render fast • So, we call DirectX methods • they are implemented on the GPU • What if you don’t have a GPU? • you can’t play
Challenge to PC game programmers • Every gamer has a different machine • Different graphics cards, which means: • different available screen resolutions • different available color models • You want to reach a broad audience • What’s the end result? • a headache • a lot of code devoted to dealing with these differences
What’s a color model? • A format for storing color on the graphics card • Many different formats • Ex: • 32 ARGB • 8 bits for Alpha • 8 bits for Red • 8 bits for Green • 8 bits for Blue
What does a GPU have? • A grid of pixels • match the current screen resolution • when we force to screen it ends up on monitor • Memory for additional visual data • ex: textures • Implementations of efficient graphics processing algorithms
Strategy for creating graphics devices • Pick a common resolution, ex: 1024 X 768 • Pick a common color model, ex: 32 XRGB • When the application starts: • check to make sure the player’s graphics card has these capabilities • What if the player doesn’t have our desired format? • have backup choices • tell the player to come back when they have a better computer
Creating a D3D Graphics Device • Make a Direct3D object (LPDIRECT3D9) • Get all the available GPU display modes (D3DDISPLAYMODE) • Pick one and use it to fill in the setup parameters (D3DPRESENT_PARAMETERS) • Use parameters to create a graphics device (LPDIRECT3DDEVICE9) • Use the graphics device to make a sprite handler (LPD3DXSPRITE) • More on using this in a minute
Setup Direct3D Methods • CreateDevice • Direct3DCreate9 • EnumAdapterModes • GetAdapterModeCount • … • These can tell us about the capabilities of the GPU
Making a Direct3D Object • Let’s us make other stuff LPDIRECT3D9 d3d; … d3d = Direct3DCreate9(D3D_SDK_VERSION); • How about getting the available modes? • each color mode is numbered • lets look for all modes in 1-1000 range (way overkill)
Getting all display modes vector<D3DDISPLAYMODE*> *displayOptions = new vector<D3DDISPLAYMODE*>(); int adapterCounter = 1; D3DFORMAT format; while (adapterCounter < 1000) { format = D3DFORMAT(adapterCounter); int numAdapters = d3d->GetAdapterModeCount( D3DADAPTER_DEFAULT, format); D3DDISPLAYMODE *displayModes = new D3DDISPLAYMODE[numAdapters]; for (int i = 0; i < numAdapters; i++) { d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, format, i, &displayModes[i]); displayOptions->push_back(&displayModes[i]); } adapterCounter++; }
Does it have our desired format? bool hasMode = false; vector<D3DDISPLAYMODE*>::iterator iterator; iterator = displayOptions->begin(); while ((iterator != displayOptions->end()) && !hasMode) { D3DDISPLAYMODE *testMode = (*iterator); if ((testMode->Format == DEFAULT_COLOR_MODE) && (testMode->Width == DEFAULT_SCREEN_WIDTH) && (testMode->Height == DEFAULT_SCREEN_HEIGHT)) hasMode = true; iterator++; } • Now we can make our graphics device & sprite handler
LPDIRECT3DDEVICE9 graphicsDevice; D3DPRESENT_PARAMETERS presentParameters; LPD3DXSPRITE spriteHandler; … ZeroMemory(&presentParameters,sizeof(presentParameters)); presentParameters.Windowed = true; presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; presentParameters.hDeviceWindow = hWnd; presentParameters.BackBufferFormat = formatToUse; presentParameters.BackBufferWidth = screenWidthToUse; presentParameters.BackBufferHeight = screenHeightToUse; HRESULT result = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, presentParameters.hDeviceWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING, &presentParameters, &graphicsDevice); result = D3DXCreateSprite(graphicsDevice, &spriteHandler);
So what? • LPD3DXSPRITE can draw 2D images • LPDIRECT3DDEVICE9 can draw text • To draw text we need a LPD3DXFONT
Making a font object LPD3DXFONT textFont; … HRESULT result = D3DXCreateFont( graphicsDevice, 20, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_MODERN, TEXT(""), &textFont );
Oh, and we need to load images • For this, we need a color key. What’s that? • color ignored while loading an image • Why would this be useful? • game shapes aren’t all rectangular • Important methods: • D3DXGetImageInfoFromFile • D3DXCreateTextureFromFileEx • Let’s use them:
D3DXIMAGE_INFO info; HRESULT result = D3DXGetImageInfoFromFile(fileName, &info); if (result == S_OK) { D3DCOLOR colorKey = D3DCOLOR_XRGB(96, 128, 224); LPDIRECT3DTEXTURE9 textureToLoad; result = D3DXCreateTextureFromFileEx( graphicsDevice, fileName, info.Width, info.Height, 1, D3DPOOL_DEFAULT, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, texture, D3DX_DEFAULT, D3DX_DEFAULT, colorKey, &info, NULL, &textureToLoad );
Now we want to draw them • There is a bit of overhead in rendering a single texture • Solution? • pool that overhead • called batch texture rendering
Each Frame • clear screen • reserve the GPU for rendering • start sprite batch • render all textures • render text • end sprite batch • unreserve the GPU • force the GPU to the screen
Rendering a frame graphicsDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(96, 96, 96), 1.0f, 0); graphicsDevice->BeginScene(); spriteHandler->Begin(D3DXSPRITE_ALPHABLEND); result = spriteHandler->Draw( texture, imageRect, NULL, &position, alphaColor); result = textFont->DrawText ( spriteHandler, L"Render this Text", -1, &textRect, DT_LEFT, D3DCOLOR_XRGB(96, 96, 96) ); spriteHandler->End(); graphicsDevice->EndScene(); graphicsDevice->Present(NULL, NULL, NULL, NULL);
Did you get all that? • Believe me, you’ll get used to it
Texture Management • Skilled game programmers recycle images • Think of a tiled game background • the same images duplicated many times • Efficient Solution: texture manager • When you load a level: • load one of each needed image into a level texture manager • for rendering, refer to image indices in texture manager
What might a texture manager do? • Store all textures • Store all names of texture files & paths map<wstring, LPDIRECT3DTEXTURE9> textures; • Provide methods for: • loading, accessing, reloading, etc.
We might also want a string table vector<wstring> stringTable; • Why? • ints take up less memory than wstrings • So how do we use it? • when initializing game items use image index • game items store stringTable index to represent texture • when time to draw, ask stringTable for string at index • swap string for texture in texture manager
We’ll use 2 TextureManagers • One for the GUI • One for the Level • Why use 2?
Windowed vs Fullscreen mode • Windowed: • Can minimize, maximize, hit “x” to close, etc. • Share GPU • Share all resources • Fullscreen • you get the resources • how do we get out? • Game control (exit game for example) • ALT-TAB
The Evil ALT-TAB • When in Full-Screen mode: • What happens when someone ALT-TABS? • We lose the graphics device • How do we get it back? • Someone needs to ALT-TAB back • How can we deal with this? • Check to see if our game has the GPU every single frame
HRESULT result = graphicsDevice->TestCooperativeLevel(); if (SUCCEEDED(result)) { // RENDER THE GAME HERE } else if (result == D3DERR_DEVICELOST) { // SOME OTHER APPLICATION HAS THE GPU, MAYBE // AN ALT-TAB, WE JUST HAVE TO KEEP TRYING TO // GET IT BACK Sleep(100); } else if (result == D3DERR_DEVICENOTRESET) { // YAY! WE GOT THE GPU BACK, MAYBE SOMEONE ALT-TABBED BACK // RESET THE GRAPHICS CARD AND RELOAD ALL THE TEXTURES if (FAILED(graphicsDevice->Reset(&presentParameters))) // RELOAD ALL IMAGES }