|
AN INTRODUCTION TO DIRECTX 7.0 USING VISUAL BASIC
by Aditya Kumar Singh Perhaps, all of us will enjoy playing an action game. If you are a programmer,
certainly sometimes a question would have emerged in your mind how the 3D games
are actually programmed. If you go for programming a 3D Game using Turbo C++
graphics library, you will certainly end up lying on a bed in the mental
hospital. C++ was used to create DOS based games when MS-DOS and Windows 3.1 was
gaining popularity. No 3D, No Hardware Accelerations, No special effects etc.
But after the introduction of Windows 95, game programmers complained that
Windows 95 was a poor platform for game development. Microsoft’s answer to the
game programmer’s complaints was the DirectX graphics library. After this,
game-programming industry took a crucial turn and advanced 3D games began to be
developed and today one major reason why homes buy computers is for playing
games.
Anyone who has ever tried using the Win32 API’s BitBlt function to develop a
custom Game will tell you how slow was it. DirectX is a collection of DLLs that
contains functions useful to the game programmer. Using DirectX, you do not need
to detect the user’s graphics card or go for writing a graphics driver. You just
write your game with DirectX libraries and DirectX takes care of everything
else. DirectX allows users to access fast graphics, sound card and input
functions while preventing them from having to test the capabilities of the
user’s computer. If you make a game using DirectX, then DirectX tries to use the
user’s graphics card to perform graphics acceleration. If the user does not have
a graphics card, then DirectX does the acceleration in Software. You barely even
have to think about it.
Though DirectX makes game development easier but still there is a fair amount of
work programming a game. This article provides an introduction to DirectX 7.0
and also how to use DirectX from Visual Basic.
INITIALIZING DIRECTX
Though, DirectX 8.0 and 9.0 has been released but we will use DirectX 7.0
because this article has been targeted for those who have never used DirectX and
DirectX 8.0 and 9.0 are advanced and is difficult for beginners to understand.
Before writing the actual code, start Visual Basic and Create a new Standard EXE
project. Go to Project > References. Scroll down and select “DirectX 7.0 for
Visual Basic Type Library”
In DirectX, we draw objects on Surfaces. There are mainly two surfaces in every
DirectX application - the Primary surface and the BackBuffer. The Primary
surface is the main surface which is displayed on the screen. The BackBuffer is
used for displaying objects on the Primary surface. We draw our objects on the
BackBuffer and then Flip it. Flipping is a process in which the contents of the
Primary surface is written to BackBuffer and the contents of the BackBuffer is
written to the Primary surface. We again draw our next frame on the backbuffer
and again flip it. This process continues until the program exits.
Select Form1 from the project explorer and go to Code View. Now make the
following declarations –
Dim dx As New DirectX7
Dim dd As DirectDraw7
Dim Primary As DirectDrawSurface7
Dim BackBuffer As DirectDrawSurface7
Dim ddsdPrimary As DDSURFACEDESC2
Dim caps As DDSCAPS2
The first variable dx is a instance of the DirectX7 variable itself. The second
declaration dd is a instance of DirectDraw7 Class. All the drawing commands are
issued through the dd object. The Third and the fourth declarations are that of
the primary and the BackBuffer surfaces. DirectDraw surfaces are instances of
the DirectDrawSurface7 class. The other two variables are used to create the
Surfaces.
Now define a sub procedure named init(). This procedure will be responsible for
initializing the objects –
Sub init()
Set dd = dx.DirectDrawCreate("")
Call dd.SetCooperativeLevel(Me.hWnd, DDSCL_FULLSCREEN Or DDSCL_EXCLUSIVE Or
DDSCL_ALLOWREBOOT)
Call dd.SetDisplayMode(640, 480, 16, 0, DDSDM_DEFAULT)
ddsdPrimary.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT
ddsdPrimary.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Or DDSCAPS_FLIP Or
DDSCAPS_COMPLEX
ddsdPrimary.lBackBufferCount = 1
Set Primary = dd.CreateSurface(ddsdPrimary)
caps.lCaps = DDSCAPS_BACKBUFFER
Set BackBuffer = Primary.GetAttachedSurface(caps)
End Sub
In this procedure, we use the dx object and invoke the DirectDrawCreate method
and pass it an empty string to indicate that we wish to use the active display
driver. The value returned from this function is a DirectDraw7 object which we
store in the dd variable. Using the variable dd we can set the cooperative level
we wish to use. The cooperative level will tell how we will access the screen
and how other programs running at the same time will be allowed to access the
screen as well. To set the cooperative level, we use the SetCooperativeLevel
function. The first argument to this function is the handle to the window we
wish to use as our main display window. We passed “Me.hWnd” to return the handle
to the current window. The second argument indicates how the window should act.
We specify DDSCL_FULLSCREEN to show that our application is a full screen
application ( we can use DDSCL_NORMAL if we wish to create a windowed program,
however it is much slower). DDSCL_EXCLUSIVE means that our application should be
the only one with access to the screen. DDSCL_ALLOWREBOOT means that we will
allow the user to use “CTRL-ALT-DEL” incase something goes wrong. Next we use
the SetDisplayMode function to indicate the screen resolution in which our
application will run.
Next we define the primary surface and attach a flippable back buffer to it. For
this we initialize the “ddsdPrimary” object which is a instance of
DDSURFACEDESC2 which stands for Direct Draw Surface Description. With this we
specify how we will like the surface to behave. caps is a DirectDraw
capabilities description used to attach the BackBuffer to the Primary surface.
Now we set up the surface description for the Primary surfaces. The
ddsdPrimary.lFlags property tells that which of the ddsdPrimary values should be
considered while creating the surface. We used both DDSD_CAPS and
DDSD_BACKBUFFERCOUT. Here, DDSD_CAPS causes the ddsdPrimary.ddsCaps.lCaps to be
taken into account and DDSD_BACKBUFFERCOUNT causes the
ddsdPrimary.lBackBufferCount to be taken into account. DDSCAPS_PRIMARYSURFACE
value of ddsdPrimary.ddsCaps.lCaps tells that our surface is the primary
surface. DDSCAPS_FLIP tells that it is a part of the flipping chain.
DDSCAPS_COMPLEX tells that we will attach other surfaces to the Primary surface.
Then we specify ddsdPrimary.lBackBufferCount variable that tells how many
BackBuffers will be attached to the primary surface.
Now when we have created the surface description, it is time to create the
primary surface. We use the CreateSurface(ddsdPrimary) statement. This method
returns a surface based on the description that we pass it as an argument. Since
we’ve passed the description “ddsdPrimary”, we will get a surface just the way
we described it. Now, we have the primary surface set up, we have to attach a
BackBuffer to it. caps.lCaps describes the type of capabilities we could like to
get from the Primary Surface. We pass caps to the primary.GetAttachedSurface
method and we receive a surface that will be able to be used as the BackBuffer.
Now our surfaces have been initialized and ready to be used.
DRAWING TEXT
Now that our surfaces have been set up, we can draw on the surfaces. Now open
the Form_Load event procedure. Add the following lines of Code
Private Sub Form_Load()
Call init
Call clear
Call BackBuffer.DrawBox(1, 1, 639, 479)
Call BackBuffer.DrawText(270, 230, "Hello DirectX", False)
Primary.Flip Nothing, DDFLIP_WAIT
End Sub
The first line calls the init procedure, which initializes DirectX. The second
line clears the Backbuffer. The Third Line is used to draw a Rectangle around
the screen in the BackBuffer. The Fourth Line displays a message “Hello DirectX”
in the Center of the screen in Backbuffer. The Fourth line flips the Primary
surface. In this process the Contents of the BackBuffer is Copied to the Primary
surface and the contents of the Primary surface is copied to the BackBuffer. You
must always remember that the contents of the Primary surface will always be
visible on screen. For those of you who tried to run the program will notice an
error in the “call clear” statement. The clear procedure has not been defined.
Here it is –
Sub clear()
BackBuffer.SetFillColor &H0&
BackBuffer.SetForeColor &H0&
Call BackBuffer.DrawBox(0, 0, 640, 480)
BackBuffer.SetForeColor &HFFFFFF
End Sub
This procedure clears the BackBuffer.
ANIMATING TEXT
Now replace the code in the Form_load event procedure with the following
code-
Private Sub Form_Load()
Call init
For i = 10 To 470
Call clear
Call BackBuffer.DrawBox(1, 1, 639, 479)
Call BackBuffer.DrawText(270, i, "Hello DirectX", False)
Primary.Flip Nothing, DDFLIP_WAIT
Next i
End Sub
The first statement here initializes DirectDraw. Now we drop into a loop which
runs from 10 to 470. The first statement inside the loop Clears the BackBuffer.
The second statement Draws the “Hello DirectX” message at a position 270,I0. The
third statement flips the backbuffer to the primary surface. When the loop
executes the second time, the Message is displayed at 270,11. The third time the
message is displayed at 270, 12 and so on. The fipping occurs so fast that the
Message appears to be dropping from the top of the screen. The animation is so
smooth that you will never be able to achieve such type of animation without
using DirectX.
DRAWING BITMAPS
You cannot draw Bitmaps directly on the BackBuffer. First You need to create a
DirectDraw Surface. Then load the Bitmap to this Surface and then Copy it to the
Backbuffer. To do this, first of all declare a DirectDraw surface to which we
will load our bitmap. –
Dim MainSprite as DirectDrawSurface7
Dim SrcRect as RECT
Dim DestRect as RECT
Now create this Surface by adding the following code -
Sub InitSprite()
Dim ddsdNewSprite As DDSURFACEDESC2
ddsdNewSprite.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT
ddsdNewSprite.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
ddsdNewSprite.lWidth = 640
ddsdNewSprite.lHeight = 480
Set MainSprite = dd.CreateSurfaceFromFile("Hello.bmp", ddsdNewSprite)
With SrcRect
.Bottom = 480
.Right = 640
.Left = 0
.Top = 0
End With
With DestRect
.Bottom = 480
.Right = 640
.Left = 0
.Top = 0
End With
End Sub
We create the surface in the same way as we had created the Primary Surface.
Remember to create a Bitmap image (640 X 480) namely “Hello.bmp”. We define two
rectangles SrcRect and DestRect. This two rectangles will be used to Draw the
Bitmap on the BackBuffer. Using these rectangles we will tell DirectX which
portion of the Bitmap is to be read and where it is to be written on the
BackBuffer. Now once the surface is created what you have to do is to draw it on
our BackBuffer. But before that Call the InitSprite procedure so that we can
load the Bitmap on the BackBuffer. Use the following code in the Form_Load event
procedure –
Private Sub Form_Load()
Call init
Call InitSprite
For i = 10 To 470
Call clear
BackBuffer.Blt DestRect, MainSprite, SrcRect, DDBLT_WAIT
Primary.Flip Nothing, DDFLIP_WAIT
Next I
End Sub
Here, the first two lines must be clear. The third line clears the backbuffer.
The fourth line actually draws the Bitmap on the BackBuffer. The first parameter
tells where to place this Bitmap on the BackBuffer. The second parameter tells
the name of the surface which contains the Bitmap. The third parameter tells the
region from where on the surface to read the bitmap. The fifth line as usual
flips the Primary surface and the BackBuffer. Now run the program. You will see
the Bitmap on the screen.
ANIMATING BITMAPS
It is very easy to animate a Bitmap. Now draw a Bitmap named “Test.bmp” of size
60 X 60. In the above code change the name of the Bitmap from “Hello.bmp” to “Test.bmp”.
Change the size such that the lWidth and lHeight parameters look like this –
ddsdNewSprite.lWidth = 60
ddsdNewSprite.lHeight = 60
Now change the SrcRect and DestRect to the following –
With SrcRect
.Bottom = 60
.Right = 60
.Left = 0
.Top = 0
End With
With DestRect
.Bottom = 60
.Right = 60
.Left = 0
.Top = 0
End With
In order to continuously change the position of the Bitmap, we have to change
the position where the Image will be placed on the BackBuffer. We can do this by
changing the parameters in the DestRect. To do this modify the Form_Load
procedure so hat it looks like this –
Private Sub Form_Load()
Call init
Call InitSprite
For i = 10 To 470
Call clear
With DestRect
.Left = i
.Right = 60 + i
.Top = 30
.Bottom = 90
End With
BackBuffer.Blt DestRect, MainSprite, SrcRect, DDBLT_WAIT
Primary.Flip Nothing, DDFLIP_WAIT
Next I
End Sub
Run the program and you will see “Test.bmp” fading across the screen.
Okay, that was a simple introduction to DirectX. There are many other components
of DirectX such as DirectSound DirectInput etc. The most interesting part of
DirectX is Direct3D using which you can draw 3 Dimensional surfaces. To learn
more about DirectX try to search the internet. A good site where you could find
useful stuff is - http://www.rookscape.com/vbgaming/ . Go to the site and click
on Tutorials to get a list of tutorials. It gives you introduction to DirectX
using VB. You will find good tutorials on DirectInput and DirectSound.
|