DirectX 9 Overview

 

Graphics

DirectX Graphics is a combination of Direct Draw 2D graphics & Direct 3D 3D graphics.

 

All 2D graphics are now done with Direct3D.

 

Example  First DirectX 9.0 pgm:

/****************************************************************

* shows the user how to setup a windowed directx application

* which clears the window to a blue color

****************************************************************/

#include <windows.h>

 

// include directx9

#include <d3d9.h>

 

// global variables

HINSTANCE hInst;                    // application instance

HWND wndHandle;                     // application window handle

 

LPDIRECT3D9             pD3D;       // the Direct3D Object

LPDIRECT3DDEVICE9       pd3dDevice; // the Direct3D Device

 

// forward declarations

bool initWindow(HINSTANCE hInstance);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

 

// DirectX functions

bool initDirect3D();   

void render(void);

 

int WINAPI WinMain(HINSTANCE hInstance,

                           HINSTANCE hPrevInstance,

                           LPTSTR lpCmdLine, int nCmdShow)

{

  if (!initWindow(hInstance))

  {

    MessageBox(NULL, "Unable to create window", "ERROR", MB_OK);

    return false;

  }

 

  if (!initDirect3D())

  {

    MessageBox(NULL, "Unable to init Direct3D", "ERROR", MB_OK);

    return false;

  }

 

      // Main message loop:

   MSG msg;

   ZeroMemory( &msg, sizeof(msg) );

   while( msg.message!=WM_QUIT )

   {

      if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )

      {

         TranslateMessage( &msg );

         DispatchMessage( &msg );

      }          

      else

      {

         render();

      }

    }

 

      // release the device and the direct3D object

      if( pd3dDevice != NULL)

        pd3dDevice->Release();

 

      if( pD3D != NULL)

        pD3D->Release();

           

      return (int) msg.wParam;

}

 

/*********************************************************************

* initWindow

*********************************************************************/

bool initWindow(HINSTANCE hInstance)

{

      WNDCLASSEX wcex;

 

      wcex.cbSize             = sizeof(WNDCLASSEX);

      wcex.style              = CS_HREDRAW | CS_VREDRAW;

      wcex.lpfnWndProc        = (WNDPROC)WndProc;

      wcex.cbClsExtra         = 0;

      wcex.cbWndExtra         = 0;

      wcex.hInstance          = hInstance;

      wcex.hIcon              = 0;

      wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);

      wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);

      wcex.lpszMenuName       = NULL;

      wcex.lpszClassName      = "DirectXExample";

      wcex.hIconSm            = 0;

      RegisterClassEx(&wcex);

 

      // create the window

      wndHandle = CreateWindow("DirectXExample",

                               "DirectXExample",

                               WS_OVERLAPPEDWINDOW,

                               CW_USEDEFAULT,

                               CW_USEDEFAULT,

                               640,

                               480,

                               NULL,

                               NULL,

                               hInstance,

                               NULL);

   if (!wndHandle)

      return false;

  

   ShowWindow(wndHandle, SW_SHOW);

   UpdateWindow(wndHandle);

 

   return true;

}

 

/*********************************************************************

* WndProc

*********************************************************************/

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

      switch (message)

      {

         case WM_DESTROY:

            PostQuitMessage(0);

            break;

      }

      return DefWindowProc(hWnd, message, wParam, lParam);

}

 

/*********************************************************************

* initDirect3D -- initializes direct3D

*********************************************************************/

bool initDirect3D()

{

      pD3D = NULL;

      pd3dDevice = NULL;

 

      // create the directX object

      if(( pD3D = Direct3DCreate9( D3D_SDK_VERSION )) ==  NULL)

      {

            return false;

      }

 

      // fill the presentation parameters structure

      D3DPRESENT_PARAMETERS d3dpp;

      ZeroMemory( &d3dpp, sizeof(d3dpp) );

      d3dpp.Windowed = TRUE;

      d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

      d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

      d3dpp.BackBufferCount  = 1;

      d3dpp.BackBufferHeight = 480;

      d3dpp.BackBufferWidth  = 640;

      d3dpp.hDeviceWindow    = wndHandle;

 

      // create a default directx device

      if( FAILED( pD3D->CreateDevice( D3DADAPTER_DEFAULT,   

                               D3DDEVTYPE_REF, wndHandle,

                               D3DCREATE_SOFTWARE_VERTEXPROCESSING,

                               &d3dpp, &pd3dDevice ) ) )

     {

        return false;

     }

     return true;

}

 

/*********************************************************************

* render

*********************************************************************/

void render(void)

{

  // check to make sure we have a valid Direct3D Device

  if( NULL == pd3dDevice ) return;

 

  // Clear the backbuffer to a blue color

  pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,255),

                    1.0f, 0 );

 

  // Present the backbuffer contents to the display

  pd3dDevice->Present( NULL, NULL, NULL, NULL );

}

 

Libraries

To use you must include: d3d9.lib

 

Surfaces

Front & back buffers are automatically created for you in CreateDevice() if you set the backBufferCount & backBufferFormat fields of the D3DPRESENT_PARAMETERS structure parameter.

 

A pointer to the backbuffer is returned by a call to GetBackBuffer().

 

Offscreen surfaces (area of video or system RAM) are created with a call to CreateOffscreenPlainSurface().

 

 

Bitmaps

Loading

Bitmaps are easily load to an offscreen surface by calling the library function: D3DXLoadSurfaceFromFile().

 

Displaying

Once loaded, bitmaps can be blitted to the backbuffer with a call to StretchRect(). This function can also be used to select an area of the surface to blit to another area (instead of the whole bitmap).

 

Example:

;

 

void render(void)

{     // load offscreen surface w/bitmap

      IDirect3DSurface9* surface = NULL;

 

      hResult = D3DXLoadSurfaceFromFile(surface, NULL, NULL,

               filename.c_str(), NULL, D3DX_DEFAULT, 0, NULL);

      if (FAILED(hResult))

     return NULL

     // check to make sure we have a valid Direct3D Device

     if ( NULL == pd3dDevice )

           return;

 

     // Clear the backbuffer to a blue color

     pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET,   

                                        D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

 

     IDirect3DSurface9* backbuffer;

     pd3dDevice-> GetBackBuffer(0,0,  

                     D3DBACKBUFFER_TYPE_MONO, &backbuffer);

 

     HRESULT hResult = pd3dDevice->StretchRect(bkgrd, NULL,

                                          backbuffer, NULL, D3DTEXF_NONE);

     if (hResult != D3D_OK)

          MessageBox(NULL,"failed", "error", MB_OK);

 

     // Present the backbuffer contents to the display

    pd3dDevice->Present( NULL, NULL, NULL, NULL );

}

 

Timing

As an alternative to GetTickCount() – which has a granularity of 10 milliseconds, QueryPerformanceCounter() can be used.

 

Example:

LARGE_INTEGER timeStart, timeEnd, timeLapsed,

                                  timerFreq;

float rate;

 

QueryPerformanceCounter(&timeStart);

 

// do something cool

QueryPerformanceCounter(&timeEnd);

timeLapsed = timeEnd.QuadParttimeStart.QuadPart;

 

rate = timeLapsed / QueryPerformanceFrequency(&timerFreq);

 

 

3D

A point is 3D space (x, y, z) is definded as in openGL except the positive z axis points away from the viewer (left-handed).

 

Defining a point

struct

{ float x, y, z;      // coord

   float r, g, b, a;  // color

} vertex;

 

Vertex Buffer

Area of memory used to create a 3D object. To create one, call CreateVertexBuffer(). Then you need to load your object data into the buffer. First you must call Lock() to enable writing to the buffer. Then you can memcpy() your data to the buffer. Afterwards you will Unlock() the buffer.

 

Drawing the shape

Drawing is a 3 step procedure.

·       Set the stream source. SetStreamSource();

·       Configuring the vertex shader. SetFVF();

·       Drawing to the screen. DrawPrimitive();

 

Drawing a triangle

#include <windows.h>

#include <mmsystem.h>

#include <d3d9.h>

#include <d3dx9tex.h>

#include <string>

using namespace std;

 

HINSTANCE hInst;                    // holds the instance for this app

HWND wndHandle;                           // global window handle

 

LPDIRECT3DVERTEXBUFFER9 g_pVB        = NULL; // Buffer to hold vertices

 

// A structure for our custom vertex type

struct CUSTOMVERTEX

{

    FLOAT x, y, z, rhw;      // The untransformed, 3D position for the vertex

    DWORD color;        // The vertex color

};

 

// Our custom FVF, which describes our custom vertex structure

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)

 

LPDIRECT3D9             pD3D;

LPDIRECT3DDEVICE9       pd3dDevice;

 

////////////////////////////////////////////// forward declarations

bool    initWindow(HINSTANCE hInstance);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

 

// direct3D functions

HRESULT SetupVB();

bool initDirect3D(HWND hwnd);

void shutdown(void);

LPDIRECT3DVERTEXBUFFER9 createVertexBuffer(int size, DWORD usage);

void drawVB(LPDIRECT3DVERTEXBUFFER9 buffer);

 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

{

      // call our function to init and create our window

      if (!initWindow(hInstance))

      {

            MessageBox(NULL, "Unable to create window", "ERROR", MB_OK);

            return false;

      }

 

      // init direct3d

      initDirect3D(wndHandle);

 

      // setup the vertex buffer and add the triangle to it.

      SetupVB();

 

      // Main message loop:

      // Enter the message loop

    MSG msg;

    ZeroMemory( &msg, sizeof(msg) );

    while( msg.message!=WM_QUIT )

    {

            // check for messages

            if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )

        {

                  TranslateMessage( &msg );

            DispatchMessage( &msg );

        }

            // this is called when no messages are pending

            else

            {

                  // call our render function

                  pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

 

                  pd3dDevice->BeginScene();

 

                  // draw the contents of the vertex buffer

                  drawVB(g_pVB);

                 

                  pd3dDevice->EndScene();

 

                  pd3dDevice->Present( NULL, NULL, NULL, NULL ); 

            }

    }

 

      // shutdown the directx manager

      shutdown();

 

      return (int) msg.wParam;

}

 

HRESULT SetupVB()

{

      HRESULT hr;

 

    // Initialize three vertices for rendering a triangle

    CUSTOMVERTEX g_Vertices[] =

    {

        { 320.0f,  50.0f, 0.5f, 1.0f, D3DCOLOR_ARGB(0,255,0,0), }, // x, y, z, rhw, color

        { 250.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_ARGB(0,0,255,0), },

        {  50.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_ARGB(0,0,0,255), },

    };

 

      // Create the vertex buffer

      g_pVB = createVertexBuffer(3*sizeof(CUSTOMVERTEX), D3DFVF_CUSTOMVERTEX);

 

    // Fill the vertex buffer.

    VOID* pVertices;

     

      hr = g_pVB->Lock( 0, sizeof(g_Vertices), (void**)&pVertices, 0 );

      if FAILED (hr)

        return E_FAIL;

 

      // copy the vertices into the buffer

    memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );

 

      // unlock the vertex buffer

    g_pVB->Unlock();

 

    return S_OK;

}

 

bool initDirect3D(HWND hwnd)

{

      HRESULT hr;

 

      if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )

      {

            return false;

      }

 

      D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory( &d3dpp, sizeof(d3dpp) );

    d3dpp.Windowed = TRUE;

    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

      d3dpp.BackBufferCount  = 1;

      d3dpp.BackBufferHeight = 480;

      d3dpp.BackBufferWidth  = 640;

      d3dpp.hDeviceWindow    = hwnd;

 

    hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,

                             D3DCREATE_SOFTWARE_VERTEXPROCESSING,

                             &d3dpp, &pd3dDevice );

      if FAILED (hr)

    {

        return false;

    }

 

      return true;

}

 

LPDIRECT3DVERTEXBUFFER9 createVertexBuffer(int size, DWORD usage)

{

      HRESULT hr;

      LPDIRECT3DVERTEXBUFFER9 buffer;

 

    // Create the vertex buffer.

    hr = pd3dDevice->CreateVertexBuffer( size,

                                         0,

                                                             usage,

                                         D3DPOOL_DEFAULT,

                                                             &buffer,

                                                             NULL );

      if FAILED ( hr)

        return NULL;

   

      return buffer;

}

 

void drawVB(LPDIRECT3DVERTEXBUFFER9 buffer)

{

      pd3dDevice->SetStreamSource( 0, buffer, 0, sizeof(CUSTOMVERTEX) );

    pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );

    pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );

}

 

void shutdown(void)

{

    if( pd3dDevice != NULL)

      {

        pd3dDevice->Release();

            pd3dDevice = NULL;

      }

    if( pD3D != NULL)

      {

        pD3D->Release();

            pD3D = NULL;

      }

}

 

bool initWindow(HINSTANCE hInstance)

{

      WNDCLASSEX wcex;

 

      wcex.cbSize = sizeof(WNDCLASSEX);

      wcex.style              = CS_HREDRAW | CS_VREDRAW;

      wcex.lpfnWndProc  = (WNDPROC)WndProc;

      wcex.cbClsExtra         = 0;

      wcex.cbWndExtra         = 0;

      wcex.hInstance          = hInstance;

      wcex.hIcon              = 0;

      wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);

      wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);

      wcex.lpszMenuName = NULL;

      wcex.lpszClassName      = "DirectXExample";

      wcex.hIconSm            = 0;

      RegisterClassEx(&wcex);

 

      wndHandle = CreateWindow("DirectXExample",

                                           "DirectXExample",

                                           WS_OVERLAPPEDWINDOW,

                                           CW_USEDEFAULT,

                                           CW_USEDEFAULT,

                                           640,

                                           480,

                                           NULL,

                                           NULL,

                                           hInstance,

                                           NULL);

   if (!wndHandle)

      return false;

  

   ShowWindow(wndHandle, SW_SHOW);

   UpdateWindow(wndHandle);

 

   return true;

}

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

      switch (message)

      {

            case WM_DESTROY:

                  PostQuitMessage(0);

                  break;

      }

      return DefWindowProc(hWnd, message, wParam, lParam);

}

 

 

Primitive types

·       point list – a set of points

·       line list -  a set of point pairs defining lines

·       line strip – a set of points defining connected lines

·       triangle list – a set of tupples defining triangles

·       triangle strip – a set of points where each 3 consecutive points define a triangle

·       triangle fan – triangles w/common point

 

To draw primitives you need to encapsulate them in a scene block.

BeginScene()

    // specify primitives

EndScene()

 

 

Transformations

·       D3DXMatrixTranslation()

·       D3DXMatrixRotation()

·       D3DXMatrixScaling()

 

Once you specify your desired transformations you multiply them together using D3DXMatrixMultiply() to create your final transformation matrix. Then you apply it to the rendering pipeline using SetTransformatiom().

 

Camera

Creating the camera projections (matProj) can be done manually (ich!) or by using the helper function D3DXMatrixPerspectiveFov() and setting the projection matrix with SetTransformation(D3DTS_PROJECTION, &matProj).

 

Positioning the camera is done by calling D3DXMatrixLookAtLH().

 

 

Shading

Supports the following shade models:

·       Flat

·       Gouraund

·       Phong

·       Force_dword

 

Objects can be solid or wireframe by calling SetRenderState() to choose.

 

Lighting

Supports the following light modes:

·       Ambient

·       Directional

·       Point

·       Spotlight

 

Each light source will have one or more modes along with properties to set position, direction, attenuation, etc. Use SetLight() to define a light source, SetRenderState() to apply it to the pipeline and LightEnable() to turn it on/off.

 

Materials

Support the following reflections

·       Diffuse

·       Ambient

·       Specular

·       Emissive

 

Texture mapping and meshes are also supported, but I’m not going there in this overview.