In my first article, you got a good feel for what DirectX 7 is and what it is not. As a fan of out of the frying pan and into the fire, we are going to jump right in. This article, like subsequent articles, is focused on one aspect of DirectX – Namely DirectDraw. As time progresses, Jack Hoxley and I will be bringing you articles on each of the DirectX components.In this article we are going to fly through the initial setup of your project then get down to cases. We are going to take a look at Enumeration, Text methods, and drawing Linear Gradients. Jack Hoxley wrote nearly all of the code in this article. (Email: [email protected])
First add a reference to DirectX then set the properties of Form1 as follows:
Autoredraw=falseborderstyle=0controlbox=falsemaxbutton=falseminbutton=falsescalemode=3 (pixels)windowstate=2 (Maximised)
This is a generalization, as in different instances; you will want a form complete with the captions and everything. (See below for a good example of what I mean.)
I personally am one of those people guilty of just assuming that if a program compiles and runs fine on my box, it will run just about anywhere. We all know that is not the case. When working with high-end graphics, we have to take into account the multitude of resolutions and configurations out there. As with the golf game Links386 that was released a few years back, sometimes we might want to consider adding a utility to help our users fine-tune their graphics settings, or we might want to try to detect the optimal configuration. By taking a look at Enumeration, we can find a good approach resolving this issue.
So, lets get started. Make a new project, (dont forget your reference to the DirectX type libraries) and make a form. In this instance, the caption, etc. does not really matter, so set the general properties however you like. Lastly, add a ComboBox, name it Combo1 and set the Style property to 2.
Put this code in the form:
'(DECLARATIONS)Dim DX As New DirectX7Sub GetDisplayCards()Dim ddEnum As DirectDrawEnumDim strGuid As StringSet ddEnum = DX.GetDDEnum()For i = 1 To ddEnum.GetCount()strGuid = ddEnum.GetGuid(i)GetDisplayModes strGuidNextEnd Sub'The Guid (Graphical User Interface Device) Number 'is used by DirectX to determine what you are talking 'to. Each GFX 'board in your computer will have a different number.Sub GetDisplayModes(sGuid As String)Dim DisplayModesEnum As DirectDrawEnumModesDim ddsd2 As DDSURFACEDESC2Dim dd As DirectDraw7Set dd = DX.DirectDrawCreate(sGuid)dd.SetCooperativeLevel Me.hWnd, DDSCL_NORMAL Set DisplayModesEnum = dd.GetDisplayModesEnum(0, ddsd2)Dim OutPut As StringFor i = 1 To DisplayModesEnum.GetCount()DisplayModesEnum.GetItem i, ddsd2OutPut = Trim(Str(ddsd2.lWidth) & x & Str(ddsd2.lHeight) & x &Str(ddsd2.ddpfPixelFormat.lRGBBitCount))Combo1.AddItem OutPut, 0 Adds the new item to the top of the list:Youll get it in decending Numerical OrderNextSet dd = NothingEnd SubPrivate Sub Form_Load()Me.ShowGetDisplayCardsEnd Sub
You will end up with a list of various resolutions and color depths that your card supports. Obviously, there are a number of ways you can use this information to assist you and those running your programs.
Whether it is an intro screen to your game or you are making a multimedia presentation using DirectX (one fellow I know went all the way in his database app – he made a cube that rotated and exploded the side the user was working on after the correct data was entered) At some point you are going to get the urge to add some dynamic text to your application. Using the text method, you can output text from any string to any location on the screen.
Surface.DrawText X,Y,Text, b as boolean
The Text can be written straight into the line, or from a pre-defined variable. The X,Y specify the top-left corner of the text. b doesnt seem to affect Visual Basic, it is best left to false.
To specify a font other than the system font, use the following code:
'in (Declarations):Global myfont As New StdFont'wherever! (Init_DX or BLT)ddsBack.SetForeColor RGB(255, 255, 255) 'Set the colour of the text.myfont.Name = Terminal 'a system font.myfont.Size = 9myfont.Bold = FalseddsBack.SetFont myfont 'Apply the font to the surface.
You will need to make sure that the end-user has the font you wish to use as well; otherwise Windows will attempt a substitution. Keep in mind that you can make your own font (like in Diablo) using commercial tools such as Macromedias Fontographer or many great font makers scattered over the net.
Gradients are great for title screens, high score screens or even backdrops to presentations and more conventional apps. There are more than a few ways to accomplish this through various API calls slightly creative coding, however, since we are talking about DirectDraw, lets examine a fairly painless way to make a gradient:
'(DECLARATIONS)Option ExplicitDim binit As BooleanDim dx As New DirectX7Dim dd As DirectDraw7Dim Mainsurf As DirectDrawSurface7Dim primary As DirectDrawSurface7Dim backbuffer As DirectDrawSurface7Dim ddsd1 As DDSURFACEDESC2Dim ddsd2 As DDSURFACEDESC2Dim ddsd3 As DDSURFACEDESC2Dim ddsd4 As DDSURFACEDESC2Dim brunning As BooleanDim CurModeActiveStatus As BooleanDim bRestore As BooleanPrivate Type Colour 'This is part of the gradient thing. It defines a new data type 'called Colour, like an 'integer datatype.R As Integer 'This datatype has .R .G .B sub properties.G As IntegerB As IntegerEnd TypeDim S As ColourDim E As Colour 'These 2 are used by the gradient feature, If you'type S. the little drop down menu'will have R,G,B in itSub blt()On Local Error GoTo errOutIf binit = False Then Exit SubDim ddrval As LongStatic i As IntegerDim rMain As RECTStatic tLast As SingleStatic fps As Single'this will keep us from trying to blt in case 'we lose the surfaces (alt-tab)bRestore = FalseDo Until ExModeActiveDoEventsbRestore = TrueLoopDoEventsIf bRestore ThenbRestore = Falsedd.RestoreAllSurfacesInitSurfaces 'must init the surfaces again if they were lostEnd IfrMain.Bottom = ddsd2.lHeightrMain.Right = ddsd2.lWidth'The gradient is drawn onto the MainSurf, which is then copied here:ddrval = backbuffer.BltFast(0, 0, Mainsurf, rMain, DDBLTFAST_WAIT)'Calculate the frame rateIf i = 30 ThenIf tLast <> 0 Then fps = 30 / (Timer - tLast)tLast = Timeri = 0End Ifi = i + 1Call backbuffer.DrawText(10, 10, 640x480x16 Frames per Second + _Format$(fps, #.0), False)Call backbuffer.DrawText(10, 30, Click Screen to Exit, False)'flip the back buffer to the screenprimary.Flip Nothing, DDFLIP_WAITerrOut:End SubSub EndIt()Call dd.RestoreDisplayModeCall dd.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL)EndEnd SubFunction ExModeActive() As BooleanDim TestCoopRes As LongTestCoopRes = dd.TestCooperativeLevelIf (TestCoopRes = DD_OK) ThenExModeActive = TrueElseExModeActive = FalseEnd IfEnd FunctionSub Gradient(SR As Single, _ SG As Single, _ SB As Single, _ ER As Single, _ EG As Single, _ EB As Single, _ SurfaceWidth As Integer, _ SurfaceHeight As Integer)'Make sure this is all on the same line. Youll'understand these variables later.On Error Resume NextS.R = SR: S.G = SG: S.B = SB '}E.R = ER: E.G = EG: E.B = EB '}This just converts the 'variables passed to the sub into the Colour 'dataTypes.Dim d As Colour 'D is the step between colours.d.R = (E.R - S.R) / SurfaceHeightd.G = (E.G - S.G) / SurfaceHeightd.B = (E.B - S.B) / SurfaceHeight'^^ this code works out the difference between each line: 'ie add 0.25 R for each line it draws.Dim c As Colour c.R = S.R: c.G = S.G: c.B = S.B 'This is just a copy of the Start Colour.Dim x As IntegerFor x = 0 To SurfaceHeightMainsurf.SetForeColor RGB(c.R, c.G, c.B) 'Set the forecolour to the colour the gradient needs.Mainsurf.DrawLine 0, x, SurfaceWidth, x 'See above about drawing lines on a DD surface.c.R = c.R + d.Rc.G = c.G + d.Gc.B = c.B + d.BNext xEnd SubSub Init()On Local Error GoTo errOutSet dd = dx.DirectDrawCreate()Me.Show'indicate that we dont need to change display depthCall dd.SetCooperativeLevel(Me.hWnd, DDSCL_FULLSCREEN OrDDSCL_ALLOWMODEX Or DDSCL_EXCLUSIVE) 'Make this on the same line.Call dd.SetDisplayMode(640, 480, 24, 0, DDSDM_DEFAULT) 'Note: in 8Bit mode gradients will look terrible, 'in 24/32 bit they will be completely smooth. Youve got to 'see it to believe it!ddsd1.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNTddsd1.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Or DDSCAPS_FLIP OrDDSCAPS_COMPLEXddsd1.lBackBufferCount = 1Set primary = dd.CreateSurface(ddsd1)Dim caps As DDSCAPS2caps.lCaps = DDSCAPS_BACKBUFFERSet backbuffer = primary.GetAttachedSurface(caps)backbuffer.GetSurfaceDesc ddsd4backbuffer.SetFontTransparency Truebackbuffer.SetForeColor vbGreenInitSurfacesbinit = Truebrunning = TrueDo While brunningbltDoEventsLoop errOut:EndIt End Sub Sub InitSurfaces()Set Mainsurf = Nothingddsd2.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTHddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAINddsd2.lWidth = 640 ddsd4.lWidthddsd2.lHeight = 480 ddsd4.lHeightSet Mainsurf = dd.CreateSurface(ddsd2) 'This creates a surface without abitmap, if nothing is drawn'here you get a copy 'of the windows desktop - messed up thoughGradient 0, 0, 0, 255, 0, 0, 640, 480' PARAMETERS:' The first 3 are the start colour, an RGB value: in this case 0,0,0' The next 3 are the end colour, an RGB value: in this case 255,0,0' The next 2 are the surfaces height & Width: 640x480. 'If you only want part of the screen to be a gradient change these to 'suit your box.End Sub'These bits just link everything together. Youve seen these before.Private Sub Form_Click() EndItEnd SubPrivate Sub Form_Load() InitEnd SubPrivate Sub Form_Paint() bltEnd Sub
Its pretty clear that combining the techniques here can give you theammunition to make a fairly impressive introduction or even a full-blownpresentation that could slaughter anything programs such as PowerPoint couldcreate. As you read this, Jack and I are hard at work on the next articleDirect3D.
To give you some insight as to where we are going with this series, weinvite you to take a sneak preview of our new site at http://www.cason.addr.com. The site should be ready in about a month, right now there are message boards, more tutorials, and we will be adding downloads in the near future. Right here at VB Square we will continue covering each facet of DirectX and culminate with two complete apps – a straight platform game and a business presentation template.