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:
- 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.
- 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.
- 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.
- 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.
-
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.
|