Main Site Links Resources Tutorials
News VB Gaming Code Downloads DirectX 7
Contact Webmaster VB Programming Product Reviews DirectX 8
  General Multimedia Articles DirectX 9
      Miscellaneous
DirectDraw: FullScreen Mode
By: Jack Hoxley
Written: May 2000

Download: DD_FullScreen.Zip (7kb)

This is the most commonly used method for DirectDraw; all commercial games (that use DirectX) that run in fullscreen mode will use DirectDraw to achieve this.

FullScreen Mode is where your application occupies the entire screen, windowed mode only occupies a small area of the screen. Running in fullscreen mode gives you almost complete control over the computers graphics capabilities. When in fullscreen mode you can set the resolution (how big the screen is, measured in pixels) and the number of colours on screen (the colour depth).

Resolutions are the same as those used by windows, look in the display properties for examples of screen resolutions, or the following list:

  • 320 x 240
  • 640 x 480
  • 800 x 600
  • 1024 x 768

Of course there are many more, some cards support 60+ different display modes (these include colour depth combinations).

Then there is the colour depth. This defines how many colours can be used on the screen at any one time. They follow the simple rule:
More Colours = slower program + better visuals
Less Colours = faster program + worse visuals
Remember this when deciding which display mode you want to use; if you're program is not going to need photo-quality graphics DONT use a hight colour depth. The following list shows the four different colour depths that can be used in fullscreen mode:

  • 8 bit - 256 different colours
  • 16 bit - 65536 different colours
  • 24bit - 16 million different colours *
  • 32bit - 16.7 million different colours *

* There is very little difference between 24 and 32 bit colour depths; experiment with them - sometimes you can tell the difference, others you can't.

Surfaces. This is the last part you need to understand before coding anything. DirectDraw uses a system of surfaces to hold graphical information. Each surface can be a different size, and in the real world just point to an area of memory where the data is stored. These surfaces can hold pictures loaded from pre-drawn picture files, or can be composed using parts of pre-drawn pictures and built in primatives. You will understand more of this later. For now, you need to know only about the PRIMARY buffer and the BACKBUFFER. The primary buffer is always the same size as the screen (which is set using the display modes above), anything that appears on the primary buffer will appear on the user's screen. The backbuffer is where the next frame /screen is composed. The reason for a backbuffer is to stop flickering; the next frame is probably composed of many smaller parts, each of these put together on the backbuffer, then this whole image is copied to the primary buffer; if the image were composed directly onto the primary buffer you would be able to see it drawing each part first.

The Code
This simple tutorial will set up a very basic directdraw application. First it will create the directdraw components, then it will set the display mode and colour depth, then it will create a surface for a picture which will be drawn to the screen.

Part 1: Linking to the DirectX type library
Follow the tutorial on Setting up a directX application

Part 2: Defining the DirectX and DirectDraw Variables
These will all go in the declarations part of the main form:

Option Explicit 'DirectX likes all it's variables to be predefined

Dim binit As Boolean 'A simple flag (true/false) that states whether we've initialised or not. If the initialisation is successful
'this changes to true, the program also checks before doing any drawing if this flag is true. If the initialisation failed and we 'try and draw things we'll get lots of errors...

Dim dx As New DirectX7 'This is the root object. DirectDraw is created from this
Dim dd As DirectDraw7 'This is DirectDraw, all things DirectDraw come from here
Dim Mainsurf As DirectDrawSurface7 'This holds our bitmap
Dim primary As DirectDrawSurface7 'This surface represents the screen - see earlier in the tutorial
Dim backbuffer As DirectDrawSurface7 'This was mentioned earlier on...
Dim ddsd1 As DDSURFACEDESC2 'this describes the primary surface
Dim ddsd2 As DDSURFACEDESC2 'this describes the bitmap that we load
Dim ddsd3 As DDSURFACEDESC2 'this describes the size of the screen

Dim brunning As Boolean
'this is another flag that states whether or not the main game loop is running.
Dim CurModeActiveStatus As Boolean 'This checks that we still have the correct display mode
Dim bRestore As Boolean 'If we don't have the correct display mode then this flag states that we need to restore the display mode

Part 3: Initialise DirectDraw
Now we have all the variables that we need we can start to use them. First off we need to create a DirectDraw object, this is created from the DirectX object. Then we set the display mode. At this point you should see your screen go back and change resolution. After this we create the primary and back buffers. Once the core code has been initialised we mode onto loading the picture into the surface, then into the main game loop. The game loop is an extremely tight loop, this is the basis of a frame rate - the faster this loop goes the faster the frame rate.

Sub Init()
On Local Error GoTo errOut 'If there is an error we end the program.

Set dd = dx.DirectDrawCreate("") 'the ("") means that we want the default driver
Me.Show 'maximises the form and makes sure it's visible


'The first line links the DirectDraw object to our form, It also sets the parameters
'that are to be used - the important ones being DDSCL_FULLSCREEN and DDCSL_EXCLUSIVE. Making it
'exclusive is important, it means that while our application is running nothing else can
'use DirectDraw, and it makes windows give us more time/attention

Call dd.SetCooperativeLevel(Me.hWnd, DDSCL_FULLSCREEN Or DDSCL_ALLOWMODEX Or DDSCL_EXCLUSIVE)
'This is where we actually see a change. It states that we want a display mode
'of 640x480 with 16 bit colour (65526 colours). the fourth argument ("0") is the
'refresh rate. leave this to 0 and DirectX will sort out the best refresh rate. It is advised
'that you don't mess about with this variable. the fifth variable is only used when you
'want to use the more advanced resolutions (usually the lower, older ones)...

Call dd.SetDisplayMode(640, 480, 16, 0, DDSDM_DEFAULT)


'get the screen surface and create a back buffer too
ddsd1.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT
ddsd1.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Or DDSCAPS_FLIP Or DDSCAPS_COMPLEX
ddsd1.lBackBufferCount = 1
Set primary = dd.CreateSurface(ddsd1)

'Get the backbuffer
Dim caps As DDSCAPS2
caps.lCaps = DDSCAPS_BACKBUFFER
Set backbuffer = primary.GetAttachedSurface(caps)
backbuffer.GetSurfaceDesc ddsd3


' init the surfaces
InitSurfaces

'This is the main loop. It only runs whilst brunning=true
binit = True
brunning = True
Do While brunning
blt
DoEvents 'you MUST have a doevents in the loop, otherwise you'll overflow the
'system (which is bad). All your application does is keep sending messages to DirectX
'and windows, if you dont give them time to complete the operation they'll crash.
'adding doevents allows windows to finish doing things that its doing.

Loop


errOut:
'If there is an error we want to close the program down straight away.
EndIt
End Sub

Part 4: Initialising the surfaces
Now that Directdraw has been initialised we need to load the surfaces and pictures into memory. First, you must understand the descriptions used (currently ddsd1-3).

You will have noticed the descriptions that were just used to create the backbuffer and primary buffer, all it is is a data structure that holds information on the surface. Before you create the surface you fill in one of these descriptions, detailing it's characteristics and other details. The characteristics are in the form of constant flags - such as DDSCAPS_PRIMARYSURFACE - this, for example, will tell DirectDraw that you're trying to create a primary surface. There are 100's of different flags that can go in here, too many to cover here. For the moment you should be fine with the current set of flags above, and the ones below. The next part, although not used above, is the size details. You must tell Directdraw how big a surface that you want, this is measured in pixels. When the picture is loaded into the surface directdraw will stretch it to fit the dimensions that you specify, so to get a proper copy of the image you must specify the correct height and width of your image. An example of this can be seen below.

Sub InitSurfaces()
'This procedure may look small, but when you make a program this procedure could
'take a good 60-120 seconds to process, and run into 1000's of lines of code.


Set Mainsurf = Nothing 'Although the first time we call this procedure this
'variable will be empty, it must be cleared. As you'll see in the blt procedure
'the program may try and re-load the surfaces, at which point the "mainsurf" object
'will have some information in it. If we try and recreate a surface that already has
'information in it DirectDraw will crash, because of this we must clear the buffer first.



'load the bitmap into a surface - backdrop.bmp
ddsd2.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH 'default flags
ddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
'An offscreenplain means that
'the user never actually gets to see the surface - it is just an are in memory.

ddsd2.lWidth = ddsd3.lWidth 'the ddsd3 structure already holds the size
'of the screen. We could replace it with 640 and 480 - it would have the same effect

ddsd2.lHeight = ddsd3.lHeight
'this is where the surface is created. You use the DDraw object to create a
'surface from the specified file name using the above description.

Set Mainsurf = dd.CreateSurfaceFromFile(App.Path & "\backdrop.bmp", ddsd2)

End Sub

A note on Backdrop.bmp
You can only use bitmap files when creating a surface. DirectDraw has no support for loading .Jpg or .Gif (or any other) file types. This causes one big problem - file sizes. If you've downloaded the example from this site you'll notice that it is a 2 colour bitmap - this was done to keep the file size down. A full 640x480 bitmap with lots of colours would be around 500kb, the equivalent Jpg would be about 37kb. click here for a tutorial on how to load Jpg's and Gif's into a directdraw surface...

Step 5: Drawing to the screen.
This is the part where we actually see something appear before us. Now is probably a good time to learn about Blitting.

Blitting is the process of copying a whole or part of a surface to another surface. The area that you want to copy from is defined by a rectangle - you state the top-left and the bottom-right corners. There are five different ways of blitting:

  1. Blt(destRect As RECT, ddS As DirectDrawSurface7, srcRect As RECT, flags As CONST_DDBLTFLAGS) As Long
    This is the safer method, but is slightly slower. You must tell the function the destination rectangle and the source rectangle. This is useful, because you can apply basic stretching functions. ie. the source defines a rectangle of size 100x100, the destination rectangle is 200x200 - Directdraw will stretch the 100x100 section to fit a 200x200 section, basically doubling the size.
  2. BltColorFill(destRect As RECT, fillvalue As Long) As Long
    This function doesn't actually copy a picture from or to anywhere. This fills the rectangle area with a colour.
  3. BltFast(dx As Long, dy As Long, ddS As DirectDrawSurface7, srcRect As RECT, trans As CONST_DDBLTFASTFLAGS) As Long
    This method is used the most, simply because it is faster. You can't apply any transformations on this blit - it copies the rectangle to the destination as the same size. This is used in the following code.
  4. BltFx(destRect As RECT, ddS As DirectDrawSurface7, srcRect As RECT, flags As CONST_DDBLTFLAGS, BltFx As DDBLTFX) As Long
    This function is used for applying transformations to the image, such as alpha-blending, mirroring, stretching and many more. It is very simliar to the blt function.
  5. BltToDC(hdc As Long, srcRect As RECT, destRect As RECT)
    This is for interaction between DirectDraw and the Windows graphics functions. If you've used the windows API extensively then you'll have used DC surfaces at some point - this allows you to copy from a directdraw surface to a DC.

This folowing procedure is called on every loop this program makes. It is important that this procedure is error-free and as fast as possible. If there is any sloppy or slow code in this procedure it will slow the whole game down.

Sub blt()
'again, this procedure looks fairly simple - it is!
'You should try and keep this procedure as short as possible, and as fast as possible


On Local Error GoTo errOut 'If there is an error don't do anything - just skip
'the procedure

If binit = False Then Exit Sub 'If we haven't initiaised then don't try anything
'DirectDraw related.


Dim ddrval As Long 'Every drawing procedure returns a value, so we must have a
'variable to hold it. From this value we can check for errors.


Dim rBack As RECT 'a RECT is the rectangle that i've mentioned.



' this will keep us from trying to blt in case we lose the surfaces (alt-tab)
bRestore = False
Do Until ExModeActive
DoEvents
bRestore = True
Loop

' if we lost and got back the surfaces, then restore them
DoEvents
If bRestore Then
bRestore = False
dd.RestoreAllSurfaces 'this just re-allocates memory back to us. we must
'still reload all the surfaces.

InitSurfaces ' must init the surfaces again if they we're lost
End If


'get the area of the screen where our window is
'this sets the rectangle to be the size of the screen.

rBack.Bottom = ddsd3.lHeight
rBack.Right = ddsd3.lWidth

'blt to the backbuffer from our surface to
'the screen surface such that our bitmap
'appears over the window
'This Blits to the screen starting from 0,0 on the screen. the DDBLTFAST_WAIT
'flag tells Directdraw to wait if the blitter is busy at the time of the call.

ddrval = backbuffer.BltFast(0, 0, Mainsurf, rBack, DDBLTFAST_WAIT)


'flip the back buffer to the screen
primary.Flip Nothing, DDFLIP_WAIT
'At this point we have completed one cycle, and we can now see something on screen

errOut: 'Skip everything if there is an error. Don't stick a message box in here - because
'you're likely to be running the program at 100's of frames per second, in just one second the
'program will try and generate 100 message boxes...

End Sub

Step 6: Finishing Touches
You have now done all the hard DirectDraw coding. We now need to put in the finishing touches that make the program useable. The most important part here is shutting down DirectDraw...

Sub EndIt()
'This procedure is called at the end of the loop, or whenever there is an error.
'Although you can get away without these few lines it is a good idea to keep them
'as you can get unpredictable results if you leave windows to "clear-up" after you.

'This line restores you back to your default (windows) resolution.

Call dd.RestoreDisplayMode
'This tells windows/directX that we no longer want exclusive access
'to the graphics features/directdraw

Call dd.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL)
'Stop the program:
End
End Sub

Private Sub Form_Click()
'Clicking the form will result in the program closing down.
'because the form is maximised (and therefore covers the whole screen)
'where you click is not important.

EndIt
End Sub

Private Sub Form_Load()
'Starts the whole program.
Init
End Sub

Private Sub Form_Paint()
'If windows sends a "paint" message translate this into a call
'to DirectDraw.

blt
End Sub

Function ExModeActive() As Boolean
'This is used to test if we're in the correct resolution.
Dim TestCoopRes As Long
TestCoopRes = dd.TestCooperativeLevel
If (TestCoopRes = DD_OK) Then
ExModeActive = True
Else
ExModeActive = False
End If
End Function

FINISHED!

You now have a frame work application for DirectDraw-Fullscreen. This basic application can be easily turned into a fully fledged professional application. All that would require is:
1. More Surfaces
2. A better Blt procedure (that does more things)

This is what I start all my DirectDraw applications on, I load this up and modify it - think of it like a template.

Make sure that you understand ALL of this section - don't expect to go far in DirectDraw/3D without this basic knowledge. Every other tutorial in the Directdraw section (except Windowed mode) will build on this knowledge and this simple structure.

DirectX 4 VB © 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster