|
Creating a Direct Draw Application (Tutorial)
| Version Compatibility: |
Visual Basic 5 Visual Basic 6
|
This code has been viewed 118645 times. I
am assuming that you have read, and understand the theory behind
DirectDraw. Choose a tutorial from the table:
| (1)
Starting Your Project |
˙ |
| (2)
Declaring the variables |
| (3)
Create Objects and Set the Display Mode |
| (4)
Create the Surfaces |
| (5)
Create the BLT Code |
| (6) Creating
the Main Loop |
| (7)
Destroying Everything |
| (8)
Running, Debugging and an Overview |
˙
˙
˙
(1)
STARTING YOUR PROJECT
You should now have added a reference for DirectX 7 to your
project. Before getting onto the coding, set these values on Form1:
| autoredraw=false
borderstyle=0 controlbox=false maxbutton=false minbutton=false
scalemode=3 (pixels) windowstate=2 (Maximised) |
This should result
in a blank form with no title bar, no border, and that is
maximised when run. To connect everything up, insert the
following lines in the specified places.
Private Sub
Form_load()
init 'Calls the
initialize sequence when the form is loaded
End Sub
Private Sub Form_Paint()
blt 'Blt when
windows tells your window to refresh itself
End Sub
Private Sub
Form_Click()
EndIt 'End the
program when the user clicks anywhere on 'the screen.
Remember this.
End Sub
|
For preparation,
make a bitmap 640 pixels wide, by 480 pixels high. This picture
will be Blt'ed to the screen in this example. Save your files and
go to step 2.
[TOP]
˙
(2)
DECLARE VARIABLES
Open up the code window for your Form, scroll to the top and open
(Declarations) sub. You can copy and paste this code straight in
there and Visual Basic will do the formatting:
| Option
Explicit Dim binit As
Boolean 'Used by the
program to see if everythings been 'started.
Dim DirectX
As New DirectX7 'Master
Object, Everything is created from this.
Dim ddraw As DirectDraw7 'The
DirectDraw Object, this is created from the DirectX 'Object
Dim MainSurf As DirectDrawSurface7 'The
Surface that will hold our picture.
Dim Primary
As DirectDrawSurface7
Dim Backbuffer As DirectDrawSurface7 'These are
explained in the Theory section.
Dim ddsd1 As DDSURFACEDESC2 'Describes
the Primary Surface
Dim ddsd2 As DDSURFACEDESC2 'Describes
our picture
Dim ddsd4 As DDSURFACEDESC2 'holds
screen information 'Descriptions: These are needed before
you can create a surface. They 'describe it's initial
Height, Width and other information. ddsd stands for 'Direct
Draw Surface Description
Dim brunning
As Boolean 'Check if
the program is still running
Dim CurModeActiveStatus As Boolean 'Used to
check if users computer 'supports the requested display
mode
Dim bRestore As Boolean 'An
error handling flag
|
[TOP]
˙
(3)
CREATE OBJECTS AND SET DISPLAY MODE
Before you see anything happen in your project you need to create
all the objects. You will also need to create 4 "Subs".
To create a sub type "Sub (Sub Name)" in the
declarations section and press Return. Create these 4 subs:
Blt
Init
initsurfaces
endit
You will also need
one function, do this in the same way as creating a sub, except:
"Function (Function name) ". Create a function called
ExModeActive() as boolean. We can now fill in these subs/functions:
Sub_INIT()
Place
the following code in the Init sub you just created:
sub Init()
˙˙˙
On Local Error GoTo errOut˙˙˙˙˙ 'If
there is an error, it closes the 'program
˙˙˙
Set ddraw = directx.DirectDrawCreate("") 'This is
extremely important. 'Nothing can be done before you have
created the DDraw object.
˙˙˙
Me.Show
˙˙˙
'indicate that we dont need to change display depth
˙˙˙
Call ddraw.SetCooperativeLevel(Me.hWnd, DDSCL_FULLSCREEN
Or DDSCL_ALLOWMODEX Or DDSCL_EXCLUSIVE)˙ 'THIS IS
PART OF THE ABOVE LINE. WHEN PASTING IT, MAKE SURE ITS
ALL ON 'THE SAME
LINE
'***SEE NOTE(1)
BELOW
˙˙˙
Call ddraw.SetDisplayMode(640, 480, 16, 0, DDSDM_DEFAULT)
'***SEE NOTE(2)
BELOW
˙˙˙ '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
˙˙˙˙
'ddsd1: the description for the primary buffer. It also
defines that there will be 1 back buffer.
˙˙˙
Set primary = ddraw.CreateSurface(ddsd1)
˙˙˙˙
'Creates the primary surface from the information in ddsd1
˙˙˙
Dim caps As DDSCAPS2
˙˙˙
caps.lCaps = DDSCAPS_BACKBUFFER˙˙˙˙ 'Defines it
as a backbuffer
˙˙˙
Set backbuffer = primary.GetAttachedSurface(caps)˙˙˙ 'Get
the primary surface to create a backbuffer from the caps
'description
˙˙˙
backbuffer.GetSurfaceDesc ddsd4
˙˙˙
'Makes ddsd4 hold all the information on the current
settings: ie height & width
˙˙˙
'Create DrawableSurface class form backbuffer
˙˙˙
backbuffer.SetFontTransparency True˙˙˙ 'Makes any
writting that appear transparent, otherwise you get a
black outline to 'all the text.
˙˙˙
backbuffer.SetForeColor vbGreen˙˙˙˙ 'This makes
the text green, it also makes the line/circle/box methods
green. It can be 'changed at any point, and can be set by
the vb****** colours, or RGB(0-255,0-255,0-255) method if
you need a˙ more 'precise method.
˙˙˙
' init the surfaces This is the sub that you made earlier,
which contains nothing at the moment.
˙˙˙
InitSurfaces
˙˙˙˙
'This sets some flags that are used else-where in the
program.
˙˙˙
binit = True
˙˙˙
brunning = True
˙˙˙
'This is the error handler, if theres an error it will
end everything.
˙errOut:
˙˙˙
EndIt˙ 'Another sub
that you made earlier
End Sub
|
˙
NOTE(1):
The Cooperative level. This lets windows know how important your
program is. Windows, by default, shares the resources between all
the open programs. The cooperative Level is there so you can tell
windows to share resources whilst your program is running or not.
The best example is in DirectSound, when you set the directSound
cooperation to high it wont let any other programs play sounds
when your program is, when set to low, you will get other windows
sounds filtering in with yours.
Games will tend to need to be set to EXCLUSIVE, so that windows
doesn't interfere with it. A simple drawing program can run NON_EXCLUSIVE,
as the user is likely to be doing other things at the same time.
The 3 main modes you will need to know about are:
DDSCL_NORMAL -
Shares with other applications. Best used in multimedia
applications. Also used for windowed mode
DDSCL_EXCLUSIVE - Doesn't share with anything else. Best
used for games
DDSCL_FULLSCREEN - Fullscreen mode, opposite of windowed
mode, where you can see windows in the background.
NOTE(2):
Set Display Mode. This is where you actually see some change, the
example will use a 640x480 fullscreen window, with 16bit colour (65,536
colours). I chose 16 bit colour as most computers will support it,
and it's the middle colour depth. The 0 refers to refresh rate -
Leave this as 0, Visual Basic doesn't like this being changed and
can lead to some permenant damage to your monitor if set too high.
The last bit is the mode:
DDSDM_DEFAULT -
This is the mode you will want to use.
DDSDM_STANDARDVGAMODE -Do not use this, it sets the
display mode to DOS 320x200 in 16 colours. If you use this mode,
set the height/width/colourdepth to 0.
ExModeActive
function
This little function
is used in the BLT code. It returns true or false depending on
whether or not the user's computer supports the requested Display
mode.
function
ExModeActive() as Boolean
˙˙˙
Dim TestCoopRes As Long 'holds
the return value of the test.
˙˙˙
TestCoopRes = ddraw.TestCooperativeLevel 'Tells
DDraw to do the test
˙˙˙
If (TestCoopRes = DD_OK) Then
˙˙˙˙˙˙˙
ExModeActive = True 'everything
is fine
˙˙˙
Else
˙˙˙˙˙˙˙
ExModeActive = False 'this
computer doesn't support this mode
˙˙˙
End If
End Function
|
[TOP]
˙
(4)
CREATE SURFACES
If you run this
program now, all it should do is change the resolution and show a
maximised form, but dont try running it, as it will crash when
you close it. Now we have the init code written, we need
to do the code for initsurfaces sub. You will notice it is
called towards the end of the init sub. Open up the
relevent section in your code window and copy this code:
sub
InitSurfaces()
˙˙˙
Dim FileX as string 'Used to
hold the bitmaps file name.
˙˙˙
Set Mainsurf = Nothing˙ 'Clears
the surface, as an error handler (later on) the program
sometimes needs to re-init the 'surfaces, if it does this
it needs a nice clean surface to start from.
˙˙˙
'load the bitmap into a surface - a picture called demo.bmp
located in the same folder as your project.
˙˙˙
ddsd2.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH
˙˙˙
ddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙
'The above
two lines should be kept the same for any surface. As
DirectX is designed for C++ VB doesn't 'support many of
the low level calls which are started with these lines.
99% of the time this set up will suit your project
˙˙˙
ddsd2.lWidth = ddsd4.lWidth 'Make
the surface the same size as the screen
˙˙˙
ddsd2.lHeight = ddsd4.lHeight˙
˙˙˙˙˙˙˙˙˙˙˙
'The height & width can be specified in pixels, and
can be bigger than the screen. The bitmap will be 'stretched/squashed
to fit these settings. NOTE: a big surface will require
lots of memory, which means low performance and 'potential
crashes on low-spec machines
˙˙˙
FileX = app.path & "\demo.bmp"˙ 'If
you saved your file under a different name, change this
line accordingly
˙˙˙
Set Mainsurf = ddraw.CreateSurfaceFromFile(fileX, ddsd2)˙ 'Create
a new surface from the specified file, based on 'ddsd2's
description
End Sub
|
Now that you have created a surface with a bitmap stored in it,
we need to write something that uses it.
[TOP]
˙
(5)
CREATE THE BLTING CODE
The blt code is the
heart of this program. The blt sub routine copies your picture
onto the screen. On a fast computer (300Mhz+) it will do this 50-60
times a second, i can't imagine how fast it will run on the first
Ghz PC (probably not too far away).This code is quite complex, so
make sure you read the annotation. It also helps if you know
about Paintpicture or BitBlt, this is very similiar
to these functions.
Sub BLT()
˙ On
Local Error GoTo errOut˙˙
'You must have an error handler
˙˙˙
If binit = False Then Exit Sub˙ 'Simple:
dont do anything unless DDraw has been initialized
˙˙˙
Dim ddrval As Long˙ 'DirectDraw
returns a number when it blt's. This is just to hold that
number
˙˙˙
Dim rMain As RECT
˙˙˙
'~~~~~RECTS~~~~~
˙˙˙
'A rect is used to define an area. it has 4 properties:
top,bottom,left,right. They specify the top-left corner
and the 'bottom-right corner. The values are then used
when blting to work out which part of a surface you want
to copy. if you want 'a square 100x100 out of the top
corner of a surface you would right it as so:
'rect.top=0
'rect.left=0
'rect.right=100
'rect.bottom=100
˙˙
' this will keep us from trying to blt in case we lose
the surfaces (alt-tab)
˙˙˙
bRestore = False
˙˙˙
Do Until ExModeActive 'short
way of saying "do until it returns true"
˙˙˙˙˙˙˙
DoEvents 'Lets
windows do other things
˙˙˙˙˙˙˙
bRestore = True
˙˙˙
Loop
˙˙˙
' if we lost and got back the surfaces, then restore them
˙˙˙
DoEvents 'Lets
windows do it's things
˙˙˙
If bRestore Then
˙˙˙˙˙˙˙
bRestore = False
˙˙˙˙˙˙˙
ddraw.RestoreAllSurfaces
˙˙˙˙˙˙˙
InitSurfaces ' must init
the surfaces again if they we're lost. When this happens
the first line of initsurfaces is important
˙˙˙
End If
˙˙˙
'get the area of the bitmap we want to blt (in this case
all of it)
˙˙˙
rMain.Bottom = ddsd2.lHeight
˙˙˙
rMain.Right = ddsd2.lWidth
˙˙˙
'blt to the backbuffer from our˙ surface to
˙˙˙
'the screen surface such that our bitmap
˙˙˙
'appears over the window
˙˙˙
ddrval = backbuffer.BltFast(0, 0, Mainsurf, rMain,
DDBLTFAST_WAIT)˙ 'This
paints the area described by rMain of 'MainSurf onto the
backbuffer at X=0 Y=0.
˙˙˙
'flip the back buffer to the screen
˙˙˙
primary.Flip Nothing, DDFLIP_WAIT˙˙˙ 'This is
where it actually appears to the user
errOut:˙
'In this
case the error handler doesn't close the program, it just
skips redrawing the screen.
End Sub
|
At the moment, your program does not call this function, next we
will create a loop that calls this sub.
[TOP]
(6)
CREATING THE MAIN PROGRAM LOOP
The main programming loop is part of the init sub. I didn't
include it above because it needs a bit of explaining. Paste the
following code into the init sub:
'˙˙˙
InitSurfaces
'˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙
>>>These lines should be before it, but dont
change them. Copy the black text only.˙
'˙˙˙
binit = True
'˙˙˙
brunning = True
˙˙˙ Do
While brunning
˙˙˙˙˙˙˙
blt
˙˙˙˙˙˙˙
DoEvents
˙˙˙
Loop
|
It looks extremely simple, and it is, but I thought I should
explain it properly. Basically, this loop keeps on doing blt
& doevents until brunning=false. Your computer will
try to do this as quickly as possible, this is the basis of a
frame rate: the faster it does this loop, the higher the frame
rate. You should already have completed the blt code, so I
don't need to explain it. The Doevents is the most important part
of a stable loop. Without this your program will crash the
computer after about 5 seconds. DoEvents lets windows do
everything else that it wants too - for example, the user has a
word processor open, the DoEvents lets windows keep that program
happy. Although it appears that we are controlling DirectDraw, we
are in fact sending messages to it, such as telling it too change
the resolution etc; because we keep sending it messages it can
quickly become confused. Everytime we tell it to blt, DDraw has
to do something. DoEvents gives it time to finish blting before
doing another loop. If we didn't let it finish we would get some
weird results.
I hope you
understand that!
[TOP]
˙
(7)
DESTROYING EVERYTHING
To finish off your program we must "un-link" ourselves
from DirectX, this is done by destroying what we have created. It
is only a few lines, but they are very important for a smooth
running application. Copy and paste this code into the endit sub:
Sub EndIt()
˙˙˙ Call
ddraw.RestoreDisplayMode 'sets
the screen resolution back to what it was before the
program was started.
˙˙˙
Call ddraw.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL) 'tells
DirectX that the application is no longer 'EXCLUSIVE. If
we were to just drop the program it would crash, as
DirectX will still be expecting an exclusive application
'to be running
˙˙˙
End 'end the
program
End Sub
|
Now all your code is complete you can run your application. You
should be presented with your picture in a fullscreen window.
Click the mouse to close the program.
[TOP]
˙
(8)
RUNNING, DEBUGGING, AND AN OVERVIEW˙
Running this program
is fairly simple, just remember that you can get some weird
results. I strongly suggest that you save your project AND any
other applications stuff before running it. I have seen some
monumetal crashes from DirectX which have cost me entire projects
and artwork in another program.
You should be
familiar with VB's error window (the one where it describes it,
offers help, or debugs/ends it). If one of these appears during
your project it wont show up - your application will just freeze.
to get around this press F1 - this will minimize your application
and launch the help file. you can then asses the problem. Because
of the error handlers, you shouldn't get any error messages. but
if it keeps on stopping remark the on error........ lines
in blt and init subs. Another useful tip: to stop
your program without there being an error press CTRL+BREAK then F1,
this will pause your program and launch the help file - ignore
the help file and check what your program is doing.....
¸2000 Jack Hoxley -˙All rights
reserved.
The material on this page may be
reproduced as long as credit is˙given to myself
"Jack˙Hoxley"
The author can be e-mailed at jollyjeffers@greenonions.netscapeonline.co.uk.
His web site is http://members.dencity.com/dx4vb/
|