DirectX 7 Tutorials
This is my DirectX 7 Tutorial written for CSC 455 - Structures of Programming Languages. This tutorial covers various aspects of
DirectX including: DirectDraw and DirectSound. First up, DirectDraw...
DirectDraw Tutorial
Definition: DirectDraw provides a way for software developers to access the display's attributes - including the size of the desktop and how
many colors can be displayed at once - and the display's features, such as playing back video, displaying images and bitmaps, and so on.
DirectDraw is not a graphics library, in that it cannot draw lines, polygons, or text, but it is still nonetheless invaluable for all of today's 3D
games.
Under DirectDraw, I will be explaining (or trying to anyways :) ) how certain features in DirectDraw work. But first, we need to get
some of the basics of graphics down first. There are two words that need to be explained: Surfaces and Blitting. A surface in
DirectDraw is a rectangular piece of memory, located either on the video card itself or in system memory. This memory is used to store
graphically related data. Blitting is the process of transferring one surface, called the source, to another, called the destination. With that
out of the way, we can get on to DirectDraw!!!
There are two ways to run DirectDraw in any program, Full Screen Mode or Windowed Mode. Let's take a look at Full Screen Mode first:
Full Screen Mode:
This would be some sample code in Visual Basic 6.0 for a Full Screen Mode application:
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 |
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 |
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
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
errOut:
'Please please please please don't put any message box in
here!!! This is running around 100 frames per second meaning that windows
will 'try to open
100 message boxes per second!!!
End Sub
Function ExModeActive() As Boolean
'This functions responds to the question: Are we in
the right resolution???
Dim TestCoopRes As Long
TestCoopRes = dd.TestCooperativeLevel
If (TestCoopRes = DD_OK) Then
ExModeActive = True
Else
ExModeActive = False
End If
End Function
There are five main things we are doing here. Defining the variable of DirectX and DirectDraw. Initializing DirectDraw.
Initializing the surfaces or bitmaps. Drawing those surfaces to the screen using DirectDraw functions. And finally, adding
finishing touches so that it runs a little faster and smoother. Windowed mode is a bit more intricate, because we must
keep track of the window size and if the picture should stretch or not and a few other variables. Windowed mode will not
be shown here. If you like the above tutorial then look for others from Jack Hoxley who I give a big thanks to in helping
me learn DirectDraw with his tutorials. His website is www.cse.unsw.edu.au/~atan164/ddraw_print.html
Many other things can be done with DirectDraw including finding out what device the computer using your application is using to display
its video, drawing primitave pictures, and even using basic animation. Unfortunately, DirectDraw does not get into the 3D aspects of
game programming, however, Direct3D does. Although, I did not have enough time to learn any Direct3D, I enjoyed my DirectDraw
experience in Visual Basic very much and plan on learing DirectX thoroughly in the future.
DirectSound Tutorial
Definition: DirectSound can play, mix, and apply effects to sounds on a variety of hardware devices. Many programmers rely on
DirectSound for all of their sound output.
The only thing I managed to get out of DirectSound is how to output a wav file. Fortunately, this is fairly easy:
Set DS = DX.DirectSoundCreate("") 'Checking for Errors: If Err.Number <> 0 Then |
DsDesc.lFlags =
DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLPAN Or DSBCAPS_CTRLVOLUME Or
DSBCAPS_STATIC 'The sound must
be set to PCM on the following line or else we get some really nasty
errors with big sharp pointy 'teeth!!!!
DsWave.nFormatTag = WAVE_FORMAT_PCM
|
Sub PlaySound() DsBuffer.Play DSBPLAY_LOOPING 'Looping = A lot, Default = Once End Sub Sub StopSound() DsBuffer.Stop 'Stop the Sound DsBuffer.SetCurrentPosition 0 'Start back at the beginning of the wav. End Sub |
Well, that's about all there is to making a wav file play in DirectSound. If you want to play more, just create more using the
CreateSoundBufferFromFile function on each buffer you create and assign a different wav file everytime. Hope you enjoy.
Big thanks to Jack Hoxley for his tutorial help. Also, I used 3D Game Programming in C++ text by John De Goes for these tutorials for
help with some of the definitions. Great book for referencing DirectX components, functions and aspects for C++. Pick that one up for a
good read on DirectX. Hopefully, I'll have the chance to update this later and give even more info on all the rest of DirectX and its
components. See ya later...