\\ Home : Articoli : Stampa
DirectX 10 - Initialize
Di RobyDx (del 03/03/2007 @ 09:35:20, in English, linkato 9736 volte)

Let’s start with first pratical tutorial with DirectX10. Now we will create the standard helloworld: a windows that will only use DirectX to paint the screen.

I suggest to use a little bit C++ before start reading this. My website has been visited for many years by .NET programmers, than i’ll try to explain concepts and structures in simple mode, like .NET, but the basic knowledge of language must be known to continue here.

If you are ready let’s start. At first we must download and install DirectX SDK and set DirectX libraries and references in Visual Studio. If you have installed DirectX Sdk after Visual Studio you can jump this passage. Else, click on Tools->Options and in the menu select Projects and Solutions->VC++ Directories. Here you must set the following paths:

C:\Program Files\Microsoft DirectX SDK (February 2007)\Include  include files

C:\Program Files\Microsoft DirectX SDK (February 2007)\Lib\x86 lib files

The paths will change if you have got another version of SDK, like April 2007, May 2007. You must also remember to change directory from x86 to x64 if you want to work with 64 bit.

At first you must create an empty Win32 Windows. For this, we have to create a new Win32 project, with no pre-created files. (But you can also use an automatic-window generator.)
Now add a new cpp file and paste this code:

#include "windows.h"

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    PAINTSTRUCT ps;
    HDC hdc;

switch (msg)
    {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            EndPaint(hWnd, &ps);
        break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, msg, wParam, lParam);
}

    return 0;
}

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE instance, LPSTR, INT )
{

WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, MsgProc, 0L, 0L,
hInst, LoadIcon(NULL, L"directX.ico"), LoadCursor(NULL,IDC_ARROW), NULL, NULL,
L"DirectX10", NULL };
RegisterClassEx( &wc );

HWND hWnd = CreateWindow(L"DirectX10", L"DirectX10",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, NULL, NULL );

ShowWindow( hWnd, SW_SHOWDEFAULT );

MSG msg={0};

while( WM_QUIT != msg.message )
{
    if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
}

    UnregisterClass( L"DirectX10", wc.hInstance );
    return 0;
}

This piece of code builds up a Win32 application that shows at your screen a window that will remain active until you will not close it.

Now let’s esamine first DirectX10 object: the ID3D10Device interface, that from now, we will call simply Device.

The Device is the most important DirectX10 class, becouse it manages and creates all resource that we will use and than the device class must be the first class created and last to be released.To use that we must include headers and link some libraries. There are various methods, but i like to use pragma comment:

#pragma comment (lib,"d3d10.lib")
#pragma comment (lib,"d3dx10.lib")

And here are the headers

#include
#include

The D3D10 Device, on the contrari of DirectX9, can’t build images alone. In previous DirectX versions, the device contained in himself a memory area called frontbuffer, but in some cases it was called also swap chain. A swap chain manages the rendering of images on the screen. If before we needed to create swap chain to rendering on 2 windows, now we must create a swap chain also to render on a single window, becouse now this one is not included in the device. This structures allows you to manage 1000 interfaces in the same mode. The swap chain is rappresented by IDXGISwapChain

ID3D10Device* device;
IDXGISwapChain* swapChain;

DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof(sd) );
sd.BufferCount=1;
sd.BufferDesc.Width=width;
sd.BufferDesc.Height=height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage= DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = handle;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = !fullscreen;
HRESULT hr= D3D10CreateDeviceAndSwapChain( NULL,  D3D10_DRIVER_TYPE_HARDWARE,  NULL,0,D3D10_SDK_VERSION,  &sd,&swapChain ,&device)

This functions creates in the same time the device and swapchain ( you can see the pointer to this to classes at end of arguments).

If hr is equal to S_OK then the creation succeded. Now i’ll show you in details this piece of code.

At first i’ve created a CHAIN_DESC structure to descrive the application type that i want to build. I’ve set the backbuffer number, the memory area in which graphics is stored before it will be sent to screen. Then i’ve set the width, height of rendering area (that usually it’s equal to screen dimension), the color format (R8G8B8A8 means a 32bit format with the alpha element). Other parameters are refresh rate, the use of backbuffer of first swap chain. The most important is the Output Windows, that rapresents the handle of windows in which we want to draw.
At last we have got the quality and the windowed flag that let us choose if we want or not the fullscreen. Finally we call the funciont D3D10CreateDeviceAndSwapChain to create device and swap chain. An very util flag is D3D10_DRIVER_TYPE_HARDWARE that remember us that we want to use the videocard to rendering, but there are also other chooses. If we choose software rendering, our applications will run also with videocard not compatible with DirectX10, but the performances never will be enought to create something of nice. Another option is D3D10_DRIVER_TYPE_NULL that let us to create a null device that cannot draw anything, let you use classes and d3d10 functions to manage files, for examples. The last parameter is NULL and means that we want to use the main video card. After i’ll show you how to choose your videocard.

With this code we have created a device, the DirectX10 controller, and the swap chain that send to video all images. But we must create a thing yet: the backbuffer. The backbuffer, as showed before, it’s a memory area in which DirectX10 works. Anything that we are going to show on our screen will be elaborated here. Only when all will be ready for the show, will be sent to the screen.
Now let’s understand how to create and set a BackBuffer

ID3D10RenderTargetView* renderTargetView;

ID3D10Texture2D *pBackBuffer;
HRESULT hr= swapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID*)&pBackBuffer ) ;
HRESULT hr = device->CreateRenderTargetView( pBackBuffer, NULL, &renderTargetView );
pBackBuffer->Release();

The procedure, in this case, consist in take the void backbuffer from the swapchain and from this create a render target. Render target it’s another memory area linked with backbuffer, and, as his name says, it’s a place in which device will render. After we have created the target we can release backbuffer and set the new render target to the device.

device->OMSetRenderTargets( 1, &renderTargetView, NULL);

Last setting it’s viewport, the area in which we will render on the backbuffer

D3D10_VIEWPORT vp;
vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
device->RSSetViewports( 1, &vp );

Done, the device it’s created. Do not warry if you have not understood something. In next tutorials i will go deep in this arguments.

Now we must find a point that it’s executed many times to rendering in real time mode. Infact the rendering it’s an operation that it’s executed 100 times for second. The best place it’s in the message cycle management.

while( WM_QUIT != msg.message )
{
    if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    else
        Render();
}

Render(); will be the the function in which we will use D3D10 to render. Now our application: fill the backbuffer with a color and send to video.

float ClearColor[4] = { 0, 0, 1, 0};
device->ClearRenderTargetView(this->renderTargetView,ClearColor);

swapChain->Present(0,0);

Simple and quick. We create a float array with 4 colors( red, green, blue and alpha) and we use it in the clear function. The present() function will send the backbuffer to the screen. The color value are between 0 and 1. In the example the color will be blue. These 3 istructions will be inserted in a Render function. In this mode all this code will be executed many times. Perheaps this function will be executed 4000 times for seconds, then 4000 FPS. This value will decrease with the use of first functions.

When you have finished the application the code will go out from while cycle. Then you have to destroy all resource ( in C++ you must do this every time)

device->ClearState();
renderTargetView->Release();
swapChain->Release();
device->Release();

The memory now it’s free, and the application it’s terminated. In next tutorial i’ll explain better some notices that, mabye, you have not understand. You can ever use D3D10 help that it’s very rich of informations.

Here is a demo you can study to understand how DirectX 10 really works.

Tips: if you click alt+enter the application will go automatically fullscreen. This before required much code and works in DirectX9. In next tutorial we will se better the device initialization.

Demo

A special thanks goes to Vincent who translate this lesson.