<<

What's so great about DirectX 7? DirectX provides a single set of with improved access to high-performance hardware, such as 3-D graphics acceleration chips and sound cards. These APIs control low-level functions including 2-D graphics acceleration; input devices such as joysticks, keyboards, and mice; and control of sound output. The components that make up the DirectX Foundation layer consist of DirectDraw, Microsoft , Microsoft DirectInput, Microsoft DirectSound, Microsoft DirectPlay, and Microsoft DirectMusic. Before DirectX, when you created multimedia applications for Windows machines, you had to customize your products so that they worked on the wide variety of hardware devices and configurations available. To alleviate this extra work, DirectX provides a hardware abstraction layer (HAL for short) that uses software drivers to communicate between the software and the hardware. As a result, developers can write a single version of a product with DirectX and it will work regardless of the hardware devices and configurations on the target PC. DirectX also provides tools that get the best possible performance from the machine running the application. It automatically determines the hardware capabilities of the computer and then sets the application's parameters to match. In addition, DirectX can run multimedia features that the system itself doesn't support. To do so, it simulates certain hardware devices through a hardware emulation layer (HEL). For example, a DirectX application that uses 3-D imagery will still run on a machine that doesn't have a 3-D acceleration card, albeit slow, because DirectX simulates the services of a 3-D card. Using DirectDraw graphic images In essence, to create DirectDraw graphics, you create surfaces. Technically, these surfaces represent sections of display memory, but it's easier to think of them as the canvas that holds a graphic--one canvas for each image. You can layer the canvases on top of each other, or hold them in reserve for later. In addition to surfaces, you'll need to frame the graphic in a clipping area. A clip area represents the visible portion of the graphic. You can either show all or just specific portions of the graphic in the clip area. For instance, continuing with the canvas analogy, in a framed photograph, the clip area would be the visible area inside the frame, even though the photo itself extends behind the frame. In , you have the option to narrow this clipped area as much or as little as you want. The term blit refers to the process by which you transfer an image stored entirely in memory onto the screen. To blit in DirectX, you create two surfaces--a blank, primary surface and a secondary, offscreen surface that holds a graphic. After setting the bounding clip area, you transfer the secondary image onto the primary surface. To return to the photograph one last time, the entire process would be analogous to mounting a photo on a canvas, and then cutting a matte to frame the picture and placing it over the top. Of course, as developers we use code instead of Xacto knives, so let's look at the relevant VB objects next. DirectDraw's objects In order to use DirectDraw, you first create an instance of the DirectDraw object, which represents a single display adapter on the computer. To create one or more surfaces, instantiate a DirectDrawSurface7 object, and to instantiate a clip area use the DirectDrawClipper object. Building the example For our example, we'll add a background image to a form. We'll create two DirectDraw surfaces, one blank, and the other containing a BMP picture of a lake. While you could achieve the same affects using either the Picture or Imagebox controls, our example will illustrate the basics you'll need to get started on more advanced projects. To begin, launch a new, standard Visual Basic project. Next, set a reference to the DirectX 7 for Visual Basic Type Library. Right-click on the default form, and select View Code from the shortcut menu. Create an instance of DirectX 7 At this point, we're ready to begin coding. First we need to create an instance of the DirectX7 class. You'll do so no matter which DirectX component you use, as this class is the top-level class of the DxVBLib type library. Enter the following variable declarations to instantiate the DirectX7 class as well as initialize two surfaces and two special types that store information about the surfaces: Option Explicit Dim objDX7 As New DirectX7

Dim objDD As DirectDraw7 Dim objDDPrimSurf As DirectDrawSurface7 Dim objDDSurf As DirectDrawSurface7 Dim ddsd1 As DDSURFACEDESC2 Dim ddsd2 As DDSURFACEDESC2 Initializing DirectDraw objects We'll use the form's Load() event to initialize the DirectDraw objects. Listing A shows the code we created to do so. Listing A: Form Load() event--initialize DirectDraw Private Sub Form_Load() `Initialization procedure Set objDD = objDX7.DirectDrawCreate("") With objDD .SetCooperativeLevel Me.hWnd, DDSCL_NORMAL ddsd1.lFlags = DDSD_CAPS ddsd1.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Set objDDPrimSurf = .CreateSurface(ddsd1) ddsd2.lFlags = DDSD_CAPS ddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Set objDDSurf = .CreateSurfaceFromFile(App.Path _ & "\lake.bmp", ddsd2) End With End Sub To begin, the code invokes the DirectDrawCreate method to create the DirectDraw object. This method takes only one string argument. When you pass an empty string ("") DirectX creates a DirectDraw object that uses the active display driver. Next, the procedure indicates whether DirectDraw will run as a windowed application or have exclusive access to the display. Since we want to run the application in a window, we used the DDSCL_NORMAL flag, as well as passed the window to use: .SetCooperativeLevel Me.hWnd, DDSCL_NORMAL Creating the surfaces At this point, the code can begin to create the surfaces. First, however, it must create a surface description for each by setting the members of each DDSURFACEDESC2 type. Setting the lflags member to DDSD_CAPS simply indicates that the following ddscaps is valid in this type. The code then sets the lCaps member to DDSCAPS_PRIMARYSURFACE to indicate that DirectDraw should consider this object the primary surface--the blank canvas. To create the actual surface, the procedure invokes the CreateSurface method and passes along the surface description as the argument. The code repeats these same steps for the second surface, except it uses the DDSCAPS_OFFSCREENPLAIN flag to specify a plain, off-screen surface--as opposed to an overlay, texture, z-buffer, front-buffer, back- buffer, or alpha surface. Then the code uses the CreateSurfaceFromFile method to create this surface based on the lake bitmap. Blit the image At this point, the application has created a primary surface and an off-screen surface with a loaded bitmap. To display the bitmap on the screen, we must add code to blit the off-screen surface onto the primary surface. To accomplish this step, we'll use the DirectDrawSurface7 object's blit method, which takes four arguments. Two arguments are of type RECT, which specify the bounding rectangles of the destination and the source surfaces. Listing B contains the procedure we created for the blitting process. Listing B: The blitting procedure Sub BlitIt() Dim ddrval As Long Dim r1 As RECT Dim r2 As RECT objDX7.GetWindowRect Me.hWnd, r1 r2.Bottom = ddsd2.lHeight r2.Right = ddsd2.lWidth ddrval = objDDPrimSurf.blt(r1, objDDSurf, r2, _ DDBLT_WAIT) End Sub Here, the GetWindowRect method fills the r1 RECT structure with the form's dimensions. It uses the offscreen surface's height and width values (lHeight and lWidth) for the r2 type's bottom and right values. Then, it passes these structures into the primary surface's blt method. The last argument of the method, DDBLT_WAIT, tells DirectDraw to wait if the blitter is busy and blit the surface when it becomes available. You can check ddrval variable's value for success or failure. There's no form like home As the last step, add the BlitIt() procedure to the form's Paint() event, and then run the project. When you do, Visual Basic displays the form shown in Figure B. Of course, initially, the form may exhibit some strange behavior. When you first launch it, the menu bar buttons probably aren't visible until you move the mouse pointer over the form's edge. Chances are you don't really want the background image to cover the entire form like this. Instead, you'll only want to cover the inside of the form and leave the borders and title bar alone. To do so, we'll need to create a clip area. Figure B: Our current blit procedure draws the image onto the entire form, borders, title bar, and all.

Create the clippers To display the image in just the usable portion of the form, modify the form's Load() event so that the last few lines look as follows:

Set objDDSurf = .CreateSurfaceFromFile _ (App.Path & "\lake.bmp", ddsd2) Set ddClipper = .CreateClipper(0) ddClipper.SetHWnd Me.hWnd objDDPrimSurf.SetClipper ddClipper End With This code uses the DirectDraw7 object's CreateClipper method to generate the DirectDrawClipper object. As we mentioned earlier, clippers let you blit toselect parts of a surface represented by a bounding rectangle. In our example, we want to contain the blit to the form, so use the SetHWnd method to set the clipper's dimensions to those of the form's. With this clipper in place, run the project again. This time, the form appears as it does in Figure A. Shrinking the image on resize Depending on how you want to use the form, the image still may not work quite right. While DirectDraw scales the image just fine when you resize the form outward, it doesn't change it at all when you shrink the form's boundaries. This behavior results because Visual Basic doesn't trigger the Paint() event when you make the form smaller, so the BlitIt() procedure never gets called. To shrink the image when the form gets resized, add the following code: Private Sub Form_Resize() If oldWidth > Me.ScaleWidth _ Or oldHeight > Me.ScaleHeight Then BlitIt End If oldWidth = Me.ScaleWidth oldHeight = Me.ScaleHeight End Sub Also, add these two variables to the form's general declarations section: Dim oldWidth As Long Dim oldHeight As Long Now, when you run the program and resize the form, Visual Basic tests the current dimensions against the previous ones. If you've shrunk the form, then it initiates the BlitIt() procedure. Now that we have the image in place, let's draw some text on it. Drawing text Each surface object has a DrawText() method that lets you draw a crude bit of text on the image. To use this method, you create a stdFont type, set its attributes, and then use the SetFont() method to assign the font to the surface. To insert text onto our example surface, add: Dim myfont As New StdFont to the general declarations section. Next, enter the procedure from Listing C. Finally, insert a call to AddSurfaceTxt() in the BlitIt() procedure, like so: r2.Right = ddsd2.lWidth AddSurfaceTxt ddrval = objDDPrimSurf.Blt(r1, objDDSurf, _ r2, DDBLT_WAIT) Now, when you run the project, Visual Basic draws the text shown in Figure C. (As we mentioned, it will appear rather crude.) Listing C: Drawing some text Sub AddSurfaceTxt() objDDSurf.SetForeColor vbYellow With myfont .Name = "Times Roman" .Size = 10 .Bold = True .Italic = False End With objDDSurf.SetFont myfont objDDSurf.DrawText 20, 200, _ "No place like Home Software", False End Sub Figure C: The DrawText method creates rudimentary text.

Conclusion The DirectX 7.0 upgrade from Microsoft offers increased power to the VisualBasic developer. In this article, we introduced you to surfaces and blitting.This is a simple overview for the extraordinary features of DirectDraw. The SDK has several VB samples that include advanced topics like sprite animation. Copyright © 2000 Element K Content LLC. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Element K Content LLC is prohibited. Element K is a service mark of Element K LLC.

http://msdn.microsoft.com/en-us/library/aa260827(v=vs.60).aspx http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=39362&lngWId=1