Initializing DirectGraphics
Tutorial


by Peter Kuchnio
Download the Source

Introduction

This is the first DirectGraphics tutorial in the series and covers the basics, what DirectGraphics is and how to initialize it in fullscreen mode in VB. Later tutorials will cover displaying geometry on the screen and drawing textures.

DirectGraphics is simply D3D from the older versions of DirectX, although in version 8 it has replaced DirectDraw. Don't worry though, D3D can still be used to draw 2D graphics, the technique is simply a little different. D3D is also used to draw 3D graphics and can be used to create amazing 3d graphics.

The basic way to draw anything in D3D is to render some geometry on the screen, the geometry being made up of polygons. This is then textured creating something readily recognizable. All of this will be covered in later tutorials, for now its on to the basics, initializing D3D.

The Code

Declarations

Before writing the code to initialize our display device, we need to declare some important constants and objects. The first thing we need to declare is a Flexible-Vertex-Format (or FVF) constant. The FVF is used to describe the contents of our vertices, or what we are giving D3D to work with. Here we specify whether we are using Transformed and Lit (TL) or Untransformed and Unlit (UU) vertices. The difference between them is that if we are using TL vertices we are telling Direct3D that we are handling our own transformations and lighting. With UU vertices, we let D3D handle that, so we can use the provided camera and matrix transformation functions. For 2D graphics you will want to use TL vertices, and for 3D graphics you will want to use UU vertices.

Next, we will also need to declare our main DirectX8, Direct3D, and Direct3DDevice objects:


Private Const FVF = D3DFVF_XYZRHW Or D3DFVF_TEX1 Or D3DFVF_DIFFUSE Or D3DFVF_SPECULAR

''Main DirectX Object
Dim Dx8 As DirectX8

''Main Direct3D Object
Dim D3D As Direct3D8
''Main Direct3D Device
Dim D3DDevice As Direct3DDevice8



Initialization

Now that we have the declarations out of the way we can finally get to actually initializing D3D. The first step is to declare our Display Mode and D3D Window variables. The Display Mode variable describes our current display mode, ie: resolution and colour depth. The D3D Window is our current viewport, or the screen. In addition to controlling how the screen is drawn, it also controls the number and size of backbuffers attached.


Private Sub InitD3D()
    ''Sub for initializing D3D in fullscreen mode
    
    'Describes the current display mode (ie: resolution, colour depth, etc.)
    Dim DisplayMode As D3DDISPLAYMODE
    'viewport, aka our screen
    Dim D3DWindow As D3DPRESENT_PARAMETERS
    
    ''Bind our objects
    Set Dx8 = New DirectX8



Next, we create our D3D object and fill out the Display Mode and D3D Window information:


''Set the width and height (resolution) of our screen as well
    ''as the colour depth.
    With DisplayMode
        ''Colour Depth
        '16-bit colour depth
        .Format = D3DFMT_R5G6B5
            
        'Set resolution of screen
        .Width = 800
        .Height = 600
    End With
    
    ''Set up Direct3D in fullscreen mode with 1 backbuffer
    With D3DWindow
        .SwapEffect = D3DSWAPEFFECT_FLIP
        .BackBufferCount = 1
        .BackBufferFormat = DisplayMode.Format
        .BackBufferWidth = DisplayMode.Width
        .BackBufferHeight = DisplayMode.Height
        .hDeviceWindow = Form1.hWnd
    End With



With that done, we can initialize our Direct3D Device (the video card). There are several setting that you can use when initializing the graphics card, dealing with how vertices are processed. In the example, the flag D3DCREATE_SOFTWARE_VERTEXPROCESSING is used, this means that vertice info will be calculated in software. It isn't the fastest options, but its supported by all video cards, while the other flags are not. For example, even a relatively recent card like my G400 doesn't support hardware vertex processing, but the GeForce series of cards do. The other flags are: D3DCREATE_HARDWARE_VERTEXPROCESSING (fastest) and D3DCREATE_MIXED_VERTEXPROCESSING.


''Initialize Direct3D device (default graphics adapter)
    ''Other flags for vertex processing are:
    ''D3DCREATE_HARDWARE_VERTEXPROCESSING (fastest but not supported by all cards)
    ''D3DCREATE_MIXED_VERTEXPROCESSING
    Set D3DDevice = D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Form1.hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DWindow) ''Initilize vertex shader 'A vertex shader controls the loading and processing of vertices D3DDevice.SetVertexShader FVF End Sub


D3DADAPTER_DEFAULT refers to the graphics adapter that will be used to output all graphics. The defailt adapter is the Primary Graphics Adapter, this should work on most computers, but it is still important to enumerate the hardware on a user's computer (will be covered in a later tutorial). When we specify D3DDEVTYPE_HAL we are specifying that we will be using the Hardware Acceleration Layer, or just hardware acceleration for 3d graphics. If you want to use software mode, the flag to use is D3DDEVTYPE_REF. Software mode is far, far slower then hardware, but sometimes the user's hardware won't contain the features you require.

The next part specifies the focus window, in this case our main form. Software/Hardware/Mized vertex processing you already know about and the l ast part is just our d3d window.

That's it for initializing. Now we can move on to using the subroutine we just created and beginning rendering (although at this point just a blank screen is drawn)

Rendering

The first thing we do is to call our initializing subroutine and show the current form:


Private Sub Form_Load()
    ''Initialize D3D
    InitD3D
    
    'Show form
    Me.Show
    
    Running = True



Next comes the main rendering loop. To begin rendering, we have to clear the backbuffer and call D3DDevice.BeginScene :


'Main loop
    Do
        DoEvents
    
        ''Clears the backbuffer and begins rendering
        With D3DDevice
           .Clear 0, ByVal 0, D3DCLEAR_TARGET, 0, 1#, 0
            .BeginScene
        End With



After this call you can put all of your rendering code. Its important to only put rendering code between the .BeginScene and .EndScene calls, if you put calculations in here it will slow down the app. Next, after all the rendering is done (although we didn't do any in this example) we have to end the scene and send the contents of the backbuffer to the front buffer (the screen), therefore outputting all that has been drawn to the screen.


    ''Ends rendering and sends the backbuffer to the front buffer
        ''(Displaying all the graphics that have been rendered)
        With D3DDevice
            .EndScene
            .Present ByVal 0, ByVal 0, 0, ByVal 0
        End With
    Loop Until Running = False



Clean-Up

After a DirectX program finished running, it is important to perform some clean-up to release the objects used by DirectX and free up the memory space used by them. We will create a small subroutine for this:


Private Sub UnloadD3D()
    'Perform clean-up by resetting DX objects and clearing memory
    Set D3DDevice = Nothing
    Set D3D = Nothing
    Set Dx8 = Nothing
End Sub



Nothing fancy is done here, we just reset our main objects in reverse order that we declared them.

Conclusion

Well, that's it! You now know how to initialize D3D and begin rendering. Later tutorials in the series will cover how to actually render stuff =) Download the source to see the example in action.