|  VbdirectX
FAQ 
Author: Arthur
Le Vernoy 
Direct Draw  
Overview 
DirectDraw is a component of the
DirectX drivers. It allows you to
directly access the display memory while
maintaining full compatibility with the
Standard graphics API in the Windows
environment (GDI). DirectDraw allows you
to perform advanced graphics tasks, such
as blitting or accessing transparency
capabilities, without hardware
dependency. 
This FAQ, will explain how to access
DirectDraw with Visual Basic and will
consist of the following articles; 
1. Direct Draw Basics (Tutorial) 
2. ModeX 
3. 8 Bit Mode (Palettes and Stuff...) 
4. 16 Bit Mode 
5. Transparency 
6. Overlays 
7. Playing an AVI file (testing ground
for Overlays) 
8. Algorithms 
9. Questions and Answers 
10. Credits & Acknowledgements 
Direct
Draw Basics  
DirectX through Visual Basic 
To access DirectX through Visual
Basic, youll need a typelib file
describing all the DirectX API or a third
party ActiveX control. You can find a
free (*.tlb) file at the Visual
Basic Area 51 site courtesy of
Patrice Scribe. Please read the FAQ,
disclaimer and other information on his
page to know more about what you can do
with this file. Dont worry, you
wont have to pay for it! 
It is also suggested that you download
the win32.tlb file, this file will give
you access to the Win32 API without
having to copy/paste declarations from
the API Viewer. 
When you downloaded those files, you
must add a reference to them in your
Visual Basic project. See
Project|References menu in the Visual
Basic IDE. 
Basic
Concepts 
Surfaces 
 BackBuffering
Concept
 
 | A surface, or
 DirectDrawSurface object,
 represents a linear area of
 display memory. A surface usually
 resides in the display memory of
 the display card, although
 surfaces can exist in system
 memory. Unless specifically
 instructed otherwise, during the
 creation of the DirectDrawSurface
 object, the DirectDraw object
 will put the DirectDrawSurface
 object wherever the best
 performance can be achieved given
 the requested capabilities.
 DirectDrawSurface objects can
 take advantage of specialized
 processors on display cards, not
 only to perform certain tasks
 faster, but to perform some tasks
 in parallel with the system CPU.[Taken from DirectX 5
 SDK Help file] | 
One way to create fast graphics
drawing is to draw directly on the
screen. Imagine now that one of your
end-users is trying to run your project
under a 286 Computer, your application
might not be able to draw graphics on the
screen at a decent rate. To avoid this,
well draw the entire scene on a
BackBuffer (Basically an
invisible Surface), and then draw this
BackBuffer on to the screen. This is
called BackBuffering. 
 
Initializing
Directdraw 
To use DirectDraw, you first create an
instance of the DirectDraw Object,
which represents the display adapter on
the computer. You then use the interface
methods to manipulate the object. In
addition, you need to create one or more
instances of a DirectDrawSurface
object to be able to display your
application on a graphics surface. 
To create an instance of the
DirectDraw Object, your project must call
the DirectDrawCreate
function. This function contains three
parameters. The first parameter takes a
globally unique identifier (GUID)
that represents the display device. The
GUID, in most cases, is set to Byval
0&, which means DirectDraw
uses the default display driver for the
system. This also means that you
wont have to deal with hardware
stuff. The second parameter is the
DirectDraw object itself. 
[See source code at the end of this
section] 
Next, youll have to determine
the application behavior you want. Is the
app going to be fullscreen or windowed?
Is it going to use exclusive mode? 
Exclusive Mode 
This mode wont let other apps
(or yours
) set a DirectDraw Object
to the same mode. This mode significantly
increases DirectDraw's performance. I
suggest you use this mode always with DDSCL_FULLSCREEN
flag. 
To do this, youll have to call
the SetCooperativeLevel method: 
DirectDraw.SetCooperativeLevel(hWnd as
hWnd, dwFlags as long) 
HWnd is the handle of the Form where
DirectDraw will perform. 
DwFlags are parameters seperated by
the OR operator: 
DDSCL_ALLOWMODEX  
Allows the use of Mode X display
modes. This flag must be used with the
DDSCL_EXCLUSIVE and DDSCL_FULLSCREEN
flags.  
DDSCL_ALLOWREBOOT  
Allows CTRL+ALT+DEL to function while
in exclusive (full-screen) mode.  
DDSCL_EXCLUSIVE  
Requests the exclusive level. This
flag must be used with the
DDSCL_FULLSCREEN flag.  
DDSCL_FULLSCREEN  
Indicates that the exclusive-mode
owner will be responsible for the entire
primary surface. GDI can be ignored. This
flag must be used with the
DDSCL_EXCLUSIVE flag.  
DDSCL_NORMAL  
Indicates that the application will
function as a regular Windows
application. This flag cannot be used
with the DDSCL_ALLOWMODEX,
DDSCL_EXCLUSIVE, or DDSCL_FULLSCREEN
flags.  
DDSCL_NOWINDOWCHANGES 
Indicates that DirectDraw is not
allowed to minimize or restore the
application window on activation. 
i.e:  
Ddraw.SetCooperativeLevel Me.Hwnd,
DDSCL_FULLSCREEN or DDSCL_EXCLUSVE 
(This might be the best way for
DirectDraw to achieve good performance.) 
[See source code at the end of this
section] 
Next, you can change the Display Mode
to fit your application aims using the
SetDisplayMode method. 
SetDisplayMode(dwWidth,dwHeight,dwBPP,dwRefreshRate,dwFlags) 
(All parameters are long values) 
dwWidth: X resolution dwHeight: Y resolution
 dwBPP: BitsPerPixels (8= up to 256
colors; 16= up to 65536 colors..)
 dwRefreshRate: Set to 0; forget it.
 DwFlags: the only flag availlable is
DDSDM_STANDARDVGAMODE, which lets you
switch from ModeX to Mode13, well
see that later.
 
[See source code at the end of this
section] 
ModeX &
Mode13: 
 You could write
directly on the screen (Primary Surface),
but the best way to do it is using at
least one BackBuffer (The sample will use
only one BackBuffer). All the rendering
stuff will be written in a rendering loop
following this scheme:
 
 | DirectDraw supports both Mode
 13 and Mode X display modes. Mode
 13 is the linear unflippable
 320x200 8 bits per pixel
 palettized mode known widely by
 its hexadecimal BIOS mode number:
 13. For more information, see
 Mode 13 Support. Mode X is a
 hybrid display mode derived from
 the standard VGA Mode 13. This
 mode allows the use of up to 256
 kilobytes (KB) of display memory
 (rather than the 64 KB allowed by
 Mode 13) by using the VGA display
 adapter's EGA multiple video
 plane system. On Windows 95,
 DirectDraw provides two Mode X
 modes (320´200´8 and
 320´240´8) for all display
 cards. Some cards also support
 linear low-resolution modes. In
 linear low-resolution modes, the
 primary surface can be locked and
 directly accessed. This is not
 possible in Mode X modes.[Taken from DirectX 5
 SDK HelpFile] | 
 ------- BEGIN CODE ------- 
Do 
 Step
1: Clear the BackBuffer 
 Step
2: Render all surfaces (bitmaps, sprites,
whatever
) 
 Step
3: Render BackBuffer on Primary Surface =
FLIP 
DoEvents 
Loop 
 ------- END CODE ------- 
The BackBuffer is attached
to the Primary Surface, which means it
will have the same behavior. To create
the Primary Surface, your application
will have to call the CreateSurface
function of the DirectDraw Object. 
CAUTION: Do not forget this, trying to
create a surface to hold a bitmap for
instance, before creating the DirectDraw
Object, is a very common newbie mistake. 
DDraw.CreateSurface(ddsd as
DDSURFACEDESC, DDS as
IDirectDrawSurface3, IUnknown as Long) 
Ddsd: DirectDraw Surface Description
(See code below)  
DDS: Surface Object  
IUnknow: Always set to Byval
0& (For future DDraw
enhancement)  
To attach the BackBuffer to the
Primary Surface use the following method: 
PrimarySurface.GetAttachedSurface(ddc
as DDSCAPS, BackBuffer) 
Well, you learned quite a lot of
theoretical stuff, now its time to
jump right in with some practice.
Heres the code: 
  
' ------- BEGIN CODE ------- 
'-------------- 
' DECLARATIONS: 
'-------------- 
Public DDraw
as IDirectDraw2 
Public
PrimarySurface as IDirectDrawSurface3 
Public
BackBuffer as IDirectDrawSurface3 
'
------------------------------------------- 
' Paste this code in the Load Event of
a Form 
'
------------------------------------------- 
Dim ddsd As
DDSURFACEDESC, ddc As DDSCAPS 
If DDraw Is
Nothing Then 
DirectDrawCreate
ByVal 0&, DDraw, Nothing 
End If 
Set
BackBuffer = Nothing 
Set
PrimarySurface = Nothing 
' This will
set your window border to 0.none (need
Win32.tlb) 
Win32.SetWindowLong
Me.hWnd, Win32.GWL_STYLE, Win32.WS_POPUP
Or Win32.WS_VISIBLE 
Win32.SetWindowPos
Me.hWnd, Win32.HWND_TOPMOST, 0, 0, 0, 0,
Win32.SWP_NOMOVE Or Win32.SWP_NOSIZE 
' Set DDraw
Behaviour 
DDraw.SetCooperativeLevel
Me.hWnd, DDSCL_EXCLUSIVE Or
DDSCL_FULLSCREEN 
' Change
display Mode 
DDrawObj.SetDisplayMode
ResX, ResY, BPP, 0, 0 
' DirectDraw
Surface Description 
With ddsd 
.dwSize =
Len(ddsd) ' Do never forget this line! 
.dwFlags =
DDSD_CAPS Or DDSD_BACKBUFFERCOUNT 
.dwBackBufferCount
= 1 ' You can try with 2 or 3 
.DDSCAPS.dwCaps
= DDSCAPS_PRIMARYSURFACE Or DDSCAPS_FLIP
Or DDSCAPS_COMPLEX Or
DDSCAPS_SYSTEMMEMORY 
End With 
' Creates the
Primary Surface with ddsd description 
DDraw.CreateSurface
ddsd, PrimarySurface, Nothing 
' Attaches
the BackBuffer to the Primary surface 
ddc.dwCaps =
DDSCAPS_BACKBUFFER 
PrimarySurface.GetAttachedSurface
ddc, BackBuffer 
' ------- END CODE ------- 
Load a bitmap
on a surface 
You might want to load a bitmap file
on a surface to be displayed through
DirectDraw. Well create two
reusable functions: 
1. CreateSimpleSurface 
2. CreateSurfaceFromBitmap 
Why? Well, one of these days you might
also want to create a surface and write
directly to it, without loading any file
on it. So were going to call CreateSimpleSurface
in the CreateSurfaceFromBitmap
code. 
' ------- BEGIN CODE ------- 
Function
CreateSimpleSurface(DDrawObj as
IDirectDraw2, nWidth As Long, nHeight As
Long) As IDirectDrawSurface3 
If nWidth
<= 0 Then Exit Function 
If nHeight
<= 0 Then Exit Function 
Dim ddsd As
DDSURFACEDESC 
Dim dds As
IDirectDrawSurface3 
With ddsd 
.dwSize =
Len(ddsd) 
.dwFlags =
DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH 
.DDSCAPS.dwCaps
= DDSCAPS_OFFSCREENPLAIN Or
DDSCAPS_SYSTEMMEMORY 
.dwWidth =
nWidth 
.dwHeight =
nHeight 
End With 
DDrawObj.CreateSurface
ddsd, dds, Nothing 
Set
CreateSimpleSurface = dds 
Set dds =
Nothing 
End Function 
' ------- END CODE ------- 
As you can see, its using
basically the same code as for creating
the Primary Surface. However, the ddsd
description of the surface is quite
different. We wont explain it for
the moment, because its quite
useless now. You will note the presence
of the DDSCAPS_SYSTEMMEMORY
flag in the ddsd.DDSCAPS.dwCaps
property. This flag will tell DirectDraw
that youre emulating Video RAM
(VRAM) into the RAM. Its slower but
solves a lot of problems. The best way to
optimize DirectDraw performance is to try
to create a surface using VRAM. To do
that simply change the flag
DDSCAPS_SYSTEMMEMORY by
DDSCAPS_VIDEOMEMORY. If the CreateSurface
method sends Visual Basic an Error called
DDERR_OUTOFMEMORY (referenced in
directx.tlb) then use RAM instead. 
Now, lets deal with the CreateSurfaceFromBitmap
Function. As mentioned above, this
function will call the
CreateSimpleSurface described above to
create the DirectDraw surface. This
function will be able to load BMP, GIF
and JPEG files. 
' ------- BEGIN CODE ------- 
Function
CreateSurfaceFromBitmap(Filename as
String) as IDirectDrawSurface3 
' Does
Filename exists? 
If
dir$(Filename) = "" then exit
function 
' Is it
really a BMP, JPEG or GIF file 
Dim hFile as
Long, TmpByte as Byte 
hFile =
FreeFile 
Open Filename
for Binary as hFile 
Get hFile, 1,
TmpByte 
If TmpByte =
66 or TmpByte = 71 Or TmpByte = 255 Then 
Else 
Exit Function 
End If 
Close hFile 
Dim frm As
Form, PictureWidth As Long, PictureHeight
As Long, Picture As StdPicture,
hdcPicture As Long, hdcSurface As Long,
DDS as IDirectDrawSurface3 
' Load The
File 
Set frm =
Screen.ActiveForm 
Set Picture =
LoadPicture(Filename) 
PictureWidth
= frm.ScaleX(Picture.Width, vbHimetric,
vbPixels) 
PictureHeight
= frm.ScaleY(Picture.Height, vbHimetric,
vbPixels) 
' Create the
Surface 
Set DDS =
CreateSimpleSurface(PictureWidth,
PictureHeight) 
hdcPicture =
Win32.CreateCompatibleDC(ByVal 0&) 
Win32.SelectObject
hdcPicture, Picture.Handle 
DDS.Restore 
DDS.GetDC
hdcSurface 
Win32.StretchBlt
hdcSurface, 0, 0, PictureWidth,
PictureHeight, hdcPicture, 0, 0,
PictureWidth, PictureHeight, SRCCOPY 
DDS.ReleaseDC
hdcSurface 
Win32.DeleteDC
hdcPicture 
Set
CreateSurfaceFromBitmap = DDS 
End Function 
' ------- END CODE ------- 
Remember the Rendering loop? 
To clear the BackBuffer(Or any other
Surface), youll have to perform a
blit on this surface 
' ------- BEGIN CODE ------- 
Sub
Clear(Surface as IDirectDrawSurface3,
Color as Long) 
Dim FX As
DDBLTFX 
With FX 
.dwSize =
Len(fx) 
.dwFillColor
= Color 
End With 
' Fill the
Whole Surface with the same Color 
BackBuffer.Blt
ByVal 0&, Nothing, ByVal 0&,
DDBLT_COLORFILL, FX 
End Sub 
' ------- END CODE ------- 
To clear the backBuffer use this line
of code: 
' ------- BEGIN CODE ------- 
Clear
BackBuffer, 0 
' ------- END CODE ------- 
For those how dont know what a
RECT is, Heres the explaination: 
A RECT is a user-type used to
store a Rectangle position: 
Public Type RECTLeft as Integer
 Right as Integer
 Top as Integer
 Bottom as Integer
 End Type
 
The Following Step in the rendering
loop is Blitting Capabilities, that is to
say, to be able to draw those surfaces
previously created on the BackBuffer.
This can be done using the Blt method of
the BackBuffer. 
Please note that if youre trying
to blit outside the Surface RECT (Outside
The screens edges), DirectDraw
wont display anything. The
following piece of code, will fix this
problem by manipulating the Destination
& Source RECTS. 
I wont explain this, its
just logic and doesnt have anything
to do with DirectDraw in it-self. 
 
The Surface wont be displayed if
youre not using the code below. 
' ------- BEGIN CODE ------- 
Sub
Draw(BackBuffer as IDirectDrawSurface3,
BackBufferWidth as Long, _ 
BackBufferHeight
as Long, Surface as IDirectDrawSurface3,
PosX as Long, _ 
PosY as Long,
nWidth as Long, nHeight as Long) 
Dim SrcRect
As RECT, DestRect As RECT, fx As DDBLTFX,
BltFlag As Long 
' Update
RECTS  
' Standard
Way... 
With SrcRect 
.Left = 0 
.Right =
nWidth 
.Top = 0 
.Bottom =
nHeight 
End With 
With DestRect 
.Left = PosX 
.Top = PosY 
.Right =
.Left + nWidth 
.Bottom =
.Top + nHeight 
End With 
' Check
Boundaries 
If PosX <
0 Then 
DestRect.Left
= 0 
SrcRect.Left
= - PosX 
End If 
If PosY <
0 Then 
DestRect.Top
= 0 
SrcRect.Top =
- PosY 
End If 
If
DestRect.Right > BackBufferWidth Then 
SrcRect.Right
= SrcRect.Right - (DestRect.Right -
BackBufferWidth) 
DestRect.Right
= BackBufferWidth 
End If 
If
DestRect.Bottom > BackBufferHeight
Then 
SrcRect.Bottom
= SrcRect.Bottom - (DestRect.Bottom -
BackBufferHeight) 
DestRect.Bottom
= BackBufferHeight 
End If 
' BLIT 
With FX 
.dwSize =
Len(FX) 
.dwROP =
Win32.SRCCOPY 
End With 
BackBuffer.Blt
DestRect, Surface, SrcRect, DDBLT_WAIT Or
DDBLT_ROP, FX 
End Sub 
' ------- END CODE ------- 
In this piece of code, transparency is
not supported. See Transparency chapter
for more information. 
The Last part of the rendering loop is
to Blit the BackBuffer on the Primary
Surface. 
' ------- BEGIN CODE ------- 
Sub Flip  
Dim dds As
IDirectDrawSurface3 
Set dds =
PrimarySurface 
dds.Flip
Nothing, DDFLIP_WAIT 
Set dds =
Nothing 
If Err.Number
= DDERR_SURFACELOST Or Err.Number =
DDERR_SURFACELOST - &H100000 Then 
BackBuffer.Restore 
PrimarySurface.Restore 
End If 
Err.Clear 
End Sub 
' ------- END CODE ------- 
And Last but not least: You must
destroy any Surfaces or DirectDraw
Objects created by setting them to
Nothing, Ortherwise your application will
crash. 
On the KeyPress Event of the Form
paste the following code: 
' ------- BEGIN CODE ------- 
If KeyAscii =
27 then ' IF ESC KEY IS PRESSED 
Unload Me 
End if 
' ------- END CODE ------- 
Then, in The Unload Event of your
Form: 
' ------- BEGIN CODE ------- 
DDraw.FlipToGDISurface 
' Restore
Display Mode 
DDraw.RestoreDisplayMode 
' Restore
Thread to Windows 
DDraw.SetCooperativeLevel
0, DDSCL_NORMAL 
' Destroy
Surfaces 
Set
BackBuffer = Nothing 
Set
PrimarySurface = Nothing 
Set DDraw =
Nothing 
' CAUTION: 
' If you have
any other surfaces created with
CreateSimpleSurface 
' or
CreateSurfaceFromBitmap then type this
line of code: 
' 
' Set Surface
= Nothing 
' 
' where
Surface is the DirectDraw Surface Object
you want to destroy  
' ------- END CODE ------- 
Well, thats the end of this
tutorial folks. If you can do this (and
if you understand it), youll know
enough of the DirectDraw features to do a
good job. Try to type all of this sample
code without the help of this file,
thats the only way to learn it.
Dont forget that DirectX is a
Low-level API -it wont forgive any
mistakes! 
Note: All this coding material has
been tested, and should work quite well.
Its not really optimized, but
should be much faster than GDI.  
Back
to Tutorials - Main 
     |