This tutorial is part of a Collection: 03. DirectX 11 - Braynzar Soft Tutorials
rate up
1
rate down
21023
views
bookmark
03. Initializing Direct3D 11

Here we will learn how to set up the direct3d device, and use direct3d to render to the screen! Since this is the bare minimum for directx to work, all lessons from this point on will use this, sometimes with a little modification here or there.

1813 downloads
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 ID3D11DeviceContext 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. IDXGISwapChain* SwapChain; ID3D11Device* d3d11Device; ID3D11DeviceContext* d3d11DevCon; ID3D11RenderTargetView* renderTargetView; float red = 0.0f; float green = 0.0f; float blue = 0.0f; int colormodr = 1; int colormodg = 1; int colormodb = 1; 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. bool InitializeDirect3d11App(HINSTANCE hInstance); void ReleaseObjects(); bool InitScene(); void UpdateScene(); void DrawScene(); In our winMain function, we will call InitializeDirect3d11App, then InitScene. After that we will call our messageloop, and when our message loop is done, we release our objects, then end the program. if(!InitializeDirect3d11App(hInstance)) //Initialize Direct3D { MessageBox(0, L"Direct3D Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitScene()) //Initialize our scene { MessageBox(0, L"Scene Initialization - Failed", L"Error", MB_OK); return 0; } messageloop(); ReleaseObjects(); ##Initializing Direct3D 11## This is our function which will initialize direct3d. It takes one parameter, which is the handle to our applications instance. I will go through it part by part. bool InitializeDirect3dApp(HINSTANCE hInstance) { HRESULT hr; //Describe our Buffer DXGI_MODE_DESC bufferDesc; ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC)); bufferDesc.Width = Width; bufferDesc.Height = Height; bufferDesc.RefreshRate.Numerator = 60; bufferDesc.RefreshRate.Denominator = 1; bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //Describe our SwapChain DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); swapChainDesc.BufferDesc = bufferDesc; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 1; swapChainDesc.OutputWindow = hwnd; swapChainDesc.Windowed = TRUE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; //Create our SwapChain hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon); //Create our BackBuffer ID3D11Texture2D* BackBuffer; hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer ); //Create our Render Target hr = d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView ); BackBuffer->Release(); //Set our Render Target d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, NULL ); return true; } 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: typedef struct DXGI_MODE_DESC { UINT Width; UINT Height; DXGI_RATIONAL RefreshRate; DXGI_FORMAT Format; DXGI_MODE_SCANLINE_ORDER ScanlineOrdering; DXGI_MODE_SCALING Scaling; } DXGI_MODE_DESC, *LPDXGI_MODE_DESC; Where each member is described below: Width - This is the Width of the resolution we are going to use. Height - This is the Height of the resolution we are going to use. RefreshRate - 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. DXGI_MODE_DESC bufferDesc; ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC)); bufferDesc.Width = Width; bufferDesc.Height = Height; bufferDesc.RefreshRate.Numerator = 60; bufferDesc.RefreshRate.Denominator = 1; bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; ##Describing the SwapChain ## ( DXGI_SWAP_CHAIN_DESC ) 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: typedef struct DXGI_SWAP_CHAIN_DESC { DXGI_MODE_DESC BufferDesc; DXGI_SAMPLE_DESC SampleDesc; DXGI_USAGE BufferUsage; UINT BufferCount; HWND OutputWindow; BOOL Windowed; DXGI_SWAP_EFFECT SwapEffect; UINT Flags; } DXGI_SWAP_CHAIN_DESC; Where each member is described below: BufferDesc - 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. DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); swapChainDesc.BufferDesc = bufferDesc; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 1; swapChainDesc.OutputWindow = hwnd; swapChainDesc.Windowed = TRUE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; ##Creating the Device and SwapChain ## ( D3D11CreateDeviceAndSwapChain() ) Next we create the direct3d device, device context, and Swap Chain by calling the direct3d core function D3D11CreateDeviceAndSwapChain(). The functions parameters look like this: HRESULT D3D11CreateDeviceAndSwapChain( __in IDXGIAdapter *pAdapter, __in D3D_DRIVER_TYPE DriverType, __in HMODULE Software, __in UINT Flags, __in const D3D_FEATURE_LEVEL *pFeatureLevels, __in UINT FeatureLevels, __in UINT SDKVersion, __in const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, __out IDXGISwapChain **ppSwapChain, __out ID3D11Device **ppDevice, __out D3D_FEATURE_LEVEL *pFeatureLevel, __out ID3D11DeviceContext **ppImmediateContext ); Where each parameter is described below: pAdapter - This is a pointer to the video adapter to use. We can set NULL to use the default one. DriverType - A D3D_DRIVER_TYPE enumerated type. This says how direct3d will be implimented. We use D3D_DRIVER_TYPE_HARDWARE to say that direct3d will be implimented by the GPU (graphics card). Software - This is an HMODULE handle to a DLL that will be used to impliment software rasterizing. Flags - This is one or more D3D11_CREATE_DEVICE_FLAG types or'ed together. pFeatureLevels - This is a pointer to an array of D3D_FEATURE_LEVEL enumerated types that say what version of directx features to use. Set NULL to use the highest features available. FeatureLevels - This is the number of elements in the pFeatureLevels array. set to NULL. SDKVersion - The version of the DirectX SDK. Use D3D11_SDK_VERSION. pSwapChainDesc - A pointer to the created DXGI_SWAP_CHAIN_DESC structure, which we created above. ppSwapChain - A pointer to an IDXGISwapChain interface to recieve the created SwapChain. ppDevice - A pointer to our direct3d device. pFeatureLevel - This is a pointer to a D3D_FEATURE_LEVEL which will hold the highest feature level available. (Feature levels are used for backwards compatibility) ppImmediateContext - This is a pointer to our ID3D11DeviceContext (device context). Remember the device context will be used for the rendering methods of the device, to support multi-threading and boost performance. hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon); ##Creating the BackBuffer ## ( GetBuffer() ) Next we create our backbuffer which will be used to create our render target view. We call the GetBuffer method of the SwapChain interface: HRESULT GetBuffer( [in] UINT Buffer, [in] REFIID riid, [in, out] void **ppSurface ); Where each parameter is described below: Buffer - Since we set swapChainDesc.SwapEffect to DXGI_SWAP_EFFECT_DISCARD, we only have access to the first buffer, so we set to 0. riid - This is a reference ID to the type of interface to change the back buffer. We use a 2d texture (ID3D11Texture2D). ppSurface - This is a pointer to the BackBuffer we created above, which is the surface we will render to. ID3D11Texture2D* BackBuffer; hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer ); ##Creating the Render Target ## ( ID3D11Device::CreateRenderTargetView() ) Now we create our render target view, which we will send to the output merger stage of the pipeline. We can create our render target view by calling CreateRenderTargetView of our device interface: HRESULT CreateRenderTargetView( [in] ID3D11Resource *pResource, [in] const D3D11_RENDER_TARGET_VIEW_DESC *pDesc, [out] ID3D11RenderTargetView **ppRTView ); Where each parameter is described below: pResource - This is our backbuffer. pDesc - A pointer to a D3D11_RENDER_TARGET_VIEW_DESC structure. We set NULL to create a view that accesses all of the subresources in mipmap level 0. ppRTView - This is a pointer to our ID3D11RenderTargetView interface, renderTargetView. Now that we don't need the backbuffer anymore, we can release it. hr = d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView ); BackBuffer->Release(); ##Set the Render Targets## ( ID3D11DeviceContext::OMSetRenderTargets() ) 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. void OMSetRenderTargets( [in] UINT NumViews, [in] ID3D11RenderTargetView *const **ppRenderTargetViews, [in] ID3D11DepthStencilView *pDepthStencilView ); Where each parameter is described below: NumViews - This is the number of render targets to bind. We only have one. ppRenderTargetViews - This is an array of render target views to bind. pDepthStencilView - This is a pointer to the depth stencil buffer. We do not have one yet, so we set this one to NULL. Thats all for the basic initializing of direct3d 11. d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, NULL ); ##Clean Up## Next we have the other new functions. The first one, ReleaseObjects(), will release all the COM objects we created. Don't forget to do this or you will create a memory leak. void ReleaseObjects() { //Release the COM Objects we created SwapChain->Release(); d3d11Device->Release(); d3dDevCon->Release(); } ##Initialize Scene## 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. void UpdateScene() { //Update the colors of our scene red += colormodr * 0.00005f; green += colormodg * 0.00002f; blue += colormodb * 0.00001f; if(red >= 1.0f || red <= 0.0f) colormodr *= -1; if(green >= 1.0f || green <= 0.0f) colormodg *= -1; if(blue >= 1.0f || blue <= 0.0f) colormodb *= -1; } ##Render Scene## 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. void DrawScene() { //Clear our backbuffer to the updated color D3DXCOLOR bgColor( red, green, blue, 1.0f ); d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor); //Present the backbuffer to the screen SwapChain->Present(0, 0); } 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. int messageloop(){ MSG msg; ZeroMemory(&msg, sizeof(MSG)); while(true) { BOOL PeekMessageL( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else{ ///////////////**************new**************//////////////////// // run game code UpdateScene(); DrawScene(); ///////////////**************new**************//////////////////// } } return msg.wParam; } ##Error Checking:## 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.) #pragma comment (lib, "DXErr.lib") #include <DXErr.h> ... bool InitializeDirect3d11App(HINSTANCE hInstance) { HRESULT hr; //Describe our Buffer DXGI_MODE_DESC bufferDesc; ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC)); bufferDesc.Width = Width; bufferDesc.Height = Height; bufferDesc.RefreshRate.Numerator = 60; bufferDesc.RefreshRate.Denominator = 1; bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //Describe our SwapChain DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); swapChainDesc.BufferDesc = bufferDesc; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 1; swapChainDesc.OutputWindow = hwnd; swapChainDesc.Windowed = TRUE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; //Create our SwapChain hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon); if(FAILED(hr)) { MessageBox(NULL, DXGetErrorDescription(hr), TEXT(" D3D11CreateDeviceAndSwapChain"), MB_OK); return 0; } //Create our BackBuffer ID3D11Texture2D* BackBuffer; hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer ); if(FAILED(hr)) { MessageBox(NULL, DXGetErrorDescription(hr), TEXT("SwapChain->GetBuffer"), MB_OK); return 0; } //Create our Render Target hr = d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView ); BackBuffer->Release(); if(FAILED(hr)) { MessageBox(NULL, DXGetErrorDescription(hr), TEXT("d3d11Device->CreateRenderTargetView"), MB_OK); return 0; } //Set our Render Target d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, NULL ); return true; } ##Exercise:## 1. In this lesson we have created a double buffer. Your exercise is to create a tripple buffer! Here's the full source: ///////////////**************new**************//////////////////// //Include and link appropriate libraries and headers// #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "d3dx11.lib") #pragma comment(lib, "d3dx10.lib") #include <windows.h> #include <d3d11.h> #include <d3dx11.h> #include <d3dx10.h> #include <xnamath.h> //Global Declarations// IDXGISwapChain* SwapChain; ID3D11Device* d3d11Device; ID3D11DeviceContext* d3d11DevCon; ID3D11RenderTargetView* renderTargetView; float red = 0.0f; float green = 0.0f; float blue = 0.0f; int colormodr = 1; int colormodg = 1; int colormodb = 1; ///////////////**************new**************//////////////////// LPCTSTR WndClassName = L"firstwindow"; HWND hwnd = NULL; const int Width = 300; const int Height = 300; ///////////////**************new**************//////////////////// //Function Prototypes// bool InitializeDirect3d11App(HINSTANCE hInstance); void ReleaseObjects(); bool InitScene(); void UpdateScene(); void DrawScene(); ///////////////**************new**************//////////////////// bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed); int messageloop(); LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, //Main windows function HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { if(!InitializeWindow(hInstance, nShowCmd, Width, Height, true)) { MessageBox(0, L"Window Initialization - Failed", L"Error", MB_OK); return 0; } ///////////////**************new**************//////////////////// if(!InitializeDirect3d11App(hInstance)) //Initialize Direct3D { MessageBox(0, L"Direct3D Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitScene()) //Initialize our scene { MessageBox(0, L"Scene Initialization - Failed", L"Error", MB_OK); return 0; } messageloop(); ReleaseObjects(); ///////////////**************new**************//////////////////// return 0; } bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed) { typedef struct _WNDCLASS { UINT cbSize; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS; WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = NULL; wc.cbWndExtra = NULL; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2); wc.lpszMenuName = NULL; wc.lpszClassName = WndClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, L"Error registering class", L"Error", MB_OK | MB_ICONERROR); return 1; } hwnd = CreateWindowEx( NULL, WndClassName, L"Window Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hInstance, NULL ); if (!hwnd) { MessageBox(NULL, L"Error creating window", L"Error", MB_OK | MB_ICONERROR); return 1; } ShowWindow(hwnd, ShowWnd); UpdateWindow(hwnd); return true; } ///////////////**************new**************//////////////////// bool InitializeDirect3d11App(HINSTANCE hInstance) { //Describe our Buffer DXGI_MODE_DESC bufferDesc; ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC)); bufferDesc.Width = Width; bufferDesc.Height = Height; bufferDesc.RefreshRate.Numerator = 60; bufferDesc.RefreshRate.Denominator = 1; bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //Describe our SwapChain DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); swapChainDesc.BufferDesc = bufferDesc; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 1; swapChainDesc.OutputWindow = hwnd; swapChainDesc.Windowed = TRUE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; //Create our SwapChain D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon); //Create our BackBuffer ID3D11Texture2D* BackBuffer; SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer ); //Create our Render Target d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView ); BackBuffer->Release(); //Set our Render Target d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, NULL ); return true; } void ReleaseObjects() { //Release the COM Objects we created SwapChain->Release(); d3d11Device->Release(); d3d11DevCon->Release(); } bool InitScene() { return true; } void UpdateScene() { //Update the colors of our scene red += colormodr * 0.00005f; green += colormodg * 0.00002f; blue += colormodb * 0.00001f; if(red >= 1.0f || red <= 0.0f) colormodr *= -1; if(green >= 1.0f || green <= 0.0f) colormodg *= -1; if(blue >= 1.0f || blue <= 0.0f) colormodb *= -1; } void DrawScene() { //Clear our backbuffer to the updated color D3DXCOLOR bgColor( red, green, blue, 1.0f ); d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor); //Present the backbuffer to the screen SwapChain->Present(0, 0); } ///////////////**************new**************//////////////////// int messageloop(){ MSG msg; ZeroMemory(&msg, sizeof(MSG)); while(true) { BOOL PeekMessageL( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else{ ///////////////**************new**************//////////////////// // run game code UpdateScene(); DrawScene(); ///////////////**************new**************//////////////////// } } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_KEYDOWN: if( wParam == VK_ESCAPE ){ DestroyWindow(hwnd); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); }
Comments
As of windows 8 d3dx11, d3dx10, and xnamath are no longer the preferred way of doing things, and are not included in the windows sdk. so you need to download them and include and link them in project properties. https://msdn.microsoft.com/en-us/library/windows/desktop/ee663275(v=vs.85).aspx
on Jul 03 `16
uncreativename
Thanks for pointing that out uncreativename~
on Jul 03 `16
iedoc
this is how to get around that http://i.stack.imgur.com/oqLmK.png
on Jul 03 `16
uncreativename
I was slightly mistaken about how it's done in my first comment. I'll write out the important parts of what's in that image, since this is the official way to do it, from microsoft, and it worked for me: "D3DX is not considered the canonical API for using Direct3D in Windows 8 and therefore isn't included with the corresponding Windows SDK... For legacy projects... the following steps are necessary to build applications with D3DX using the DirectX SDK. a. Modify the project's VC++ directories as follows to use the right order for SDK headers and libraries. i. open Properties for the project and select the VC++ Directories page. ii. Select All Configurations and All Platforms. iii. Set these directories as follows: - Executable directories, click the edit button, and make sure inherit from parent or project defaults is enabled -Include Directories: $(IncludePath);$(DXSDK_DIR)Inlude -Library Directories: $(LibraryPath);$(DXSDK_DIR)Libx86; click apply. choose the x64 platform set the library directory to: $(LibraryPath);$(DXSDK_DIR)Libx64; When I did this, everything worked fine.
on Jul 03 `16
uncreativename
Is there a repo for exercise answers? Want to make sure I got my solutions correct.
on Jul 13 `16
ericxtang
Why am I cannot compile the project?ERROR:Cannot open the d3dx11.lib
on Oct 27 `16
benyang
have you installed the directx sdk? d3dx11 is not included in the windows kit
on Oct 27 `16
iedoc
i'm trying inicializate the DirectX 11 and i don't get any errors... i do the Render on message loop and the window is clean with the choosed color. but why the memory used is increasing? i'm using Windows 7 with Visual Studio 2017.
on Jan 16 `18
cambalinho
Readers theres 2 important informations that you need to know: 1 - the memory used can go up and down, but depends on Graphics configurations... the balance is the best; 2 - that's normal use several CPU's, because we are using a infinite loop. so we need learn how we can control the FPS: 15. High Resolution Timer. i hope these information can help several people. thank you so much Brayzar and continue with excellent work ;)
on Jan 19 `18
cambalinho
Readers: if you get a Macro Redefinition warnings just do: //disable the warnings: #pragma warning (disable : 4005) #pragma warning (disable : 4838) //add the include files: #include <Windows.h> #include <string> #include <functional> #include <D3D11.h> #include <D3DX11.h> #include <d3dx10.h> #include <xnamath.h> //enabled the warnings for test if we do any Macro Redefinition: #pragma warning(default:4005) #pragma warning(default:4838) i hope these help more the beginners.
on Jan 23 `18
cambalinho
d3d11.h里没有D3DXCOLOR定义了,可以直接用浮点数组代替
on Jan 24 `20
iclosed
D3DXCOLOR bgColor( red, green, blue, 1.0f ); -> float bgColor[4] = { red, green, blue, 1.0f };
on Jan 24 `20
iclosed