AllAPI Network - The KPD-Team

 
Allapi Network
 API-Guide
 ApiViewer

 API List

 
API Resources
 Tips & Tricks
 VB Tutorials
 Error Lookup
 
Misc Stuff
 VB examples
 VB Tools
 VB Links
 Top Downloads
 
This Site
 Search Engine
 Contact Form
 

Donate to AllAPI.net

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, you’ll 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. Don’t worry, you won’t 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

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]

BackBuffering Concept

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, we’ll 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 won’t have to deal with hardware stuff. The second parameter is the DirectDraw object itself.

[See source code at the end of this section]

Next, you’ll 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 won’t 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, you’ll 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, we’ll see that later.

[See source code at the end of this section]

ModeX & Mode13:

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]

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:

‘ ------- 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 it’s time to jump right in with some practice. Here’s 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. We’ll 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 we’re 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, it’s using basically the same code as for creating the Primary Surface. However, the ddsd description of the surface is quite different. We won’t explain it for the moment, because it’s 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 you’re emulating Video RAM (VRAM) into the RAM. It’s 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, let’s 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), you’ll 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 don’t know what a RECT is, Here’s the explaination:

A RECT is a user-type used to store a Rectangle position:

Public Type RECT
Left 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 you’re trying to blit outside the Surface RECT (Outside The screen’s edges), DirectDraw won’t display anything. The following piece of code, will fix this problem by manipulating the Destination & Source RECTS.

I won’t explain this, it’s just logic and doesn’t have anything to do with DirectDraw in it-self.

The Surface won’t be displayed if you’re 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, that’s the end of this tutorial folks. If you can do this (and if you understand it), you’ll 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, that’s the only way to learn it. Don’t forget that DirectX is a Low-level API -it won’t forgive any mistakes!

Note: All this coding material has been tested, and should work quite well. It’s not really optimized, but should be much faster than GDI.

Back to Tutorials - Main

 

 


Copyright © 1998-2007, The Mentalis.org Team - Privacy statement
Did you find a bug on this page? Tell us!
This site is located at http://allapi.mentalis.org/