Sign Up NOW to get 100 free credits, used to download 3D Models, Textures, Sound Effects and Music!

Lesson 3: Direct3D 11 Initialization

We have one more thing to do to start displaying our crazy minds using DirectX. And that is to Initialize Direct3D. By the end of this lesson, you should have a nice little window with a blue background.We will initialize direct3d here. After we initialize direct3d, all the boring preparation stuff will be over, and we can start drawing things onto the screen! You will need to download the directx sdk from microsofts website. here. Ok, lets get on this thing.

We start this lesson by including the necessary headers, and linking to the necessary libraries. As you can see, we have included the and linked to the d3dx10 library and header file. This is in case we want to use some of the functions types or structures they contain, as direct3d 11 is only an "extension" of direct3d 10. We include xnamath.h because the D3DX math library has been "depricated" for the new xna math library. An example is we will not use D3DXVECTOR3 for a variable containing 3 float values. Instead, we will use the XMFLOAT3.

Here we declare our globals. The first declaration is a COM Interface object. This is our SwapChain, which is used to change the backbuffer to the front buffer, and the front buffer to the back buffer. This is called double buffering. When we render our scene, we are rendering to the backbuffer, so by the time we present the back buffer to the monitor, it will be fully drawn. Otherwise, we will get scanlines, which is when we can see our program drawing our scene to the screen, from the top down usually. The next is an Interface we will use to represent our hardware device (GPU). Now, the line after that, is a new interface that came with directx 11. The ID3D11Device interface was split into two, to help support the new multi-threading features. We will use our ID3D11Device interface object to call all the rendering method, while ID3D11Device will be used to call the rest of the methods that don't have to do with rendering.

I will better explain the reason behind splitting the ID3D11Device into two. DirectX 11 has new multi-threading features, used to speed up the applications. When you are loading something into memory, such as a model, or creating an object, you will call the ID3D11Device object. While the object or model is loading or creating, you can call the ID3D11DeviceContext interface object to continue rendering your scene. This will take away from performance hits when loading models, creating objects, or anything like that. Its not a difficult idea to understand, so i hope you follow what i'm saying.

So, after that, we have another interface object, which is the render target view. Basically, we do not write directly to the screen, but instead write to the render target view, which is a 2d texture (our backbuffer). Then this texture is sent to the output merger stage of the pipeline as our render target, which will then be rendered to the screen.

The next 6 lines are used to change the color of the background, not important to the lesson.

Next we declare our function prototypes. The first function is used to initialize direct3d. The second one is to release the objects we don't need to prevent memory leaks. InitScene is used to set up or scene. Update scene is used to change our scene on a per-frame basis, then the draw scene is used to draw our scene to the screen, and is updated every frame too.

First we create an HRESULT object called hr to use for error checking. I have not included error checking in order to keep the code more clear and condensed, but I will explain at the end of this lesson how you can impliment error checking.

HRESULT hr;

Describing the BackBuffer ( DXGI_MODE_DESC )

The first thing we do in this function is describe our backbuffer. We create a DXGI_MODE_DESC object called bufferDesc. Then we call ZeroMemory to make sure the object is completely cleaned out (in case we don't set all the parameters, and a parameter already has a value in it). Then we fill out our backbuffer description. The DXGI_MODE_DESC structure:

- This is a DXGI_RATIONAL type, describing the refresh rate in hertz. We set ours to 60/1, or 60hz.

Format

- This is a DXGI_FORMAT enumerated type, describing the format of our display. We can use DXGI_FORMAT_R8G8B8A8_UNORM, which is a 32-bit unsigned integer, taking 8 bits for Red, Green, Blue, and Alpha each.

ScanlineOrdering - A DXGI_MODE_SCANLINE_ORDER enumerated type, describing the manner in which the rasterizer will render onto a surface. As we use double buffering, this will not usually be seen, so we can set it to DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED, meaning the order in which the render takes place on a surface does not matter.

Scaling - This is another enumerated type. The DXGI_MODE_SCALING, explaining how an image is stretched to fit a monitors resolution. We can use one of three: DXGI_MODE_SCALING_UNSPECIFIED, which means it is not specified, DXGI_MODE_SCALING_CENTERED, meaning the image is centered on the screen, and no scaling and stretching is done at all, and DXGI_MODE_SCALING_STRETCHED, which will stretch the image to the monitors resolution.

Now that we have our back buffer description filled out, we can move on to describing our SwapChain. We create a DXGI_SWAP_CHAIN_DESC called swapChainDesc, Then we clear it out by calling the ZeroMemory function. After that, we can fill out the description. The structure looks like this:

- This is a DXGI_MODE_DESC structure, which describes the back buffer. We will put the bufferDesc object we just filled out here.

SampleDesc

- This is a DXGI_SAMPLE_DESC structure, which describes the multisampling. If you don't know, multisampling is used to "smooth" out the choppiness in lines and edges, created because pixels on the monitor are not infinetly small. Since pixels are like little blocks, you can see "choppiness" in diagonal lines and edges on a computer screen.

BufferUsage

- A DXGI_USAGE enumerated type describing the access the cpu has to the surface of the back buffer. We specify DXGI_USAGE_RENDER_TARGET_OUTPUT since we will render to it.

BufferCount

- This is the number of back buffers we will use. We set 1 for double buffering, but you can set 2 for triple buffering, or even more if you wanted.

OutputWindow

- This is the handle to our window, hwnd.

Windowed

- This either true or false depending on if we want windowed or full-screen. Set true for windowed, and false for full-screen. (Be carefull exiting out of full-screen. It might freeze your program. A way around this is to set the application to windowed just before you actually exit out of the program)

SwapEffect

- This is a DXGI_SWAP_EFFECT enumerated type, describing what the display driver should do with the front buffer after swapping it to the back buffer. we set DXGI_SWAP_EFFECT_DISCARD to let the display driver decide what the most efficient thing to do with it is.

Flags

- A DXGI_SWAP_CHAIN_FLAG enumerated type. This is an extra flag describing the behavior of the swap chain. The only one that might be usefull right now is DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH, which changes the monitors resolution when swapping between windowed and fullscreen.

And the last thing we do while initializing, is bind the render target view to the output merger stage of the pipeline. This function will also bind our depth/stencil buffer as well, but we have not created one yet, so we set that parameter to NULL.

The InitScene() function will be used to initialize our scene. In a video game, you will probably have many different scenes, so you will probably want to rename them from InitScene(). We will place our objects, load our models, textures, sounds, all that must be done to start off that specific scene.

bool InitScene()
{
return true;
}

Update Scene

Next we have our UpdateScene() function. We will use this function to do all the updating of our scene, like changing objects locations, changing values, anything that changes in our scene will be done here. In this lesson, we will just change the color of our background, so in the update scene function, we will just change the color.

Now we have our DrawScene() function. This is where we will simply render our scene. We should avoid doing any updating in this scene, and keep this function only for drawing our scene. This is where we will change the color of our background. Remember, if you have come from an earlier version of DirectX, like directx 10, all the rendering methods have been moved to the device context interface, so instead of calling d3dDevice like we would have in directx 10, we will call our d3dDeviceContext object to get the ClearRenderTargetView method, since this is a rendering method. We will call d3dDevice for other things that have to do with the GPU, other than rendering. Finally, we present the scene by calling the Present method of our swapchain interface. What this does is swap the front buffer with the back buffer. In the drawscene function, we will render to the backbuffer, then the back buffer is presented when call the Present method.

This is our messageloop() function. Its pretty much the same as when we created our window in the last lesson, but now when there are no messages to be checked, we will first call our UpdateScene() function, to update our scene, then call the DrawScene() function, to draw our scene to the backbuffer and present the backbuffer to the screen.

It will save you time checking for errors in your code when calling functions, as the application may continue running even though a function was not successful. When a function returns, you can check the value of the HRESULT to see how to continue your code. These are the return values of an HRESULT:

S_OK

The function was successful.

E_NOTIMPL

The function was not implimented.

E_NOINTERFACE

The interface is not supported.

E_ABORT

The function aborted.

E_FAIL

The function failed.

E_INVALIDARG

One or more arguments are invalid.

You can display the exact error that was returned by calling the DXGetErrorDescription(HRESULT hResult) function. You will need to link to the "DXErr.lib" library and include the "DXErr.h" header If you want to use this function.

The following is our InitializeDirect3d11App() function with error checking: (You will want to make sure you are NOT in full-screen when the error box pops up. You can do this by going to window mode right before you display the message.)