By: Jack Hoxley
Written: May 2000
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.
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).
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
- 8 bit - 256
- 16 bit - 65536
- 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.
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.
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:
'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
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
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.
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
'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.
'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
'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")
'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
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)
' init the surfaces
'This is the main loop. It only runs whilst brunning=true
binit = True
brunning = True
Do While brunning
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
'and windows, if you dont give them time to complete the operation they'll
'adding doevents allows windows to finish doing things that its doing.
'If there is an error we want to close the program
down straight away.
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).
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
'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
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
'the program may try and re-load the surfaces, at which point the "mainsurf"
'will have some information in it. If we try and recreate a surface that
'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
ddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
'An offscreenplain means that
'the user never actually gets to see the surface - it is just an are in
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
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.
Mainsurf = dd.CreateSurfaceFromFile(App.Path & "\backdrop.bmp", ddsd2)
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...
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:
As RECT, ddS As DirectDrawSurface7, srcRect As RECT, flags As CONST_DDBLTFLAGS)
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.
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.
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.
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.
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.
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.
'again, this procedure looks fairly simple - it
'You should try and keep this procedure as short as possible, and as fast
On Local Error GoTo errOut 'If there is an error
don't do anything - just skip
If binit = False Then Exit Sub 'If we haven't initiaised
then don't try anything
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
' this will keep us from trying to blt in case we
lose the surfaces (alt-tab)
bRestore = False
Do Until ExModeActive
bRestore = True
' if we lost and got back the surfaces, then restore
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
'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
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...
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...
'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"
'This line restores you back to your default (windows) resolution.
'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:
Private Sub Form_Click()
'Clicking the form will result in the program
'because the form is maximised (and therefore covers the whole screen)
'where you click is not important.
Private Sub Form_Load()
'Starts the whole program.
Private Sub Form_Paint()
'If windows sends a "paint" message translate
this into a call
'This is used to test if we're in the correct
Dim TestCoopRes As Long
TestCoopRes = dd.TestCooperativeLevel
If (TestCoopRes = DD_OK) Then
ExModeActive = True
ExModeActive = False
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