The Basic Way of Drawing


You probably know more about Visual Basic drawing than I do. It’s not that I’m ignorant (though I admit to being weak in math); rather, the simple vector graphics I recommend just aren’t that difficult.


The fade trick I’m about to show you, however, is fun and isn’t what you might expect. You’ve no doubt seen the fade from black to blue on the setup screens of many Microsoft products. Looking at the output, I would have guessed that it was produced with some sort of palette manipulation. It’s not.


The Fade procedure simply draws adjacent lines with increasing color intensity. It uses optional arguments to enable defaults. For example, a simple Fade command with no arguments draws a blue fade from top to bottom of the current form. You can draw the fade on any form or picture box. You can specify red, green, or blue fades or any combination of the three. You can specify a horizontal or vertical fade—or both for a diagonal fade. Here are some examples, using named arguments:

‘ Default black to blue vertical fade on current form
Fade Me
’ Make it blue to black
Fade Me, LightToDark:=False
’ Red horizontal fade on FBlit
Fade FBlit, Red:=True, Horizontal:=True
’ Violet vertical fade on picture box
Fade pbTest(0), Red:=True, Blue:=True
’ Black to white diagonal fade on current form
Fade Me, Horizontal:=True, Vertical:=True, _
Red:=True, Green:=True, Blue:=True

Fade draws the background of the Bit Blast program used later in this chapter (BITBLAST.VBP). You’ll see it in various figures, starting with Figure 7-6 on page 392, but it’s different each time because it is called with random values in the Form_Resize event:

Private Sub Form_Resize()
Fade Me, Red:=Random(0, 1), Green:=Random(0, 1), _
Blue:=Random(0, 1), Horizontal:=Random(0, 1), _
Vertical:=Random(0, 1), LightToDark:=Random(0, 1)
End Sub

The Fade sub (with other effects in FUN.BAS) is long, but it takes only a few lines to do the real work. Most of the code saves and restores properties and handles defaults based on the optional arguments:

Sub Fade(cvsDst As Object, _
Optional Red As Boolean = False, _
Optional Green As Boolean = False, _
Optional Blue As Boolean = True, _
Optional Vertical As Boolean = True, _
Optional Horizontal As Boolean = False, _
Optional LightToDark As Boolean = True)
With cvsDst
‘ Trap errors
On Error Resume Next

‘ Save properties
Dim fAutoRedraw As Boolean, ordDrawStyle As Integer
Dim ordDrawMode As Integer, iDrawWidth As Integer
Dim ordScaleMode As Integer
Dim rScaleWidth As Single, rScaleHeight As Single
fAutoRedraw = .AutoRedraw: iDrawWidth = .DrawWidth
ordDrawStyle = .DrawStyle: ordDrawMode = .DrawMode
rScaleWidth = .ScaleWidth: rScaleHeight = .ScaleHeight
ordScaleMode = .ScaleMode
‘ Err set if object lacks one of previous properties
If Err Then Exit Sub
‘ If you get here, object is OK (Printer lacks AutoRedraw)
fAutoRedraw = .AutoRedraw

‘ Set properties required for fade
.AutoRedraw = True
.DrawWidth = 3 ‘ Must be greater than 1 for dithering
.DrawStyle = vbInsideSolid ‘ vbInvisible gives an interesting effect
.DrawMode = vbCopyPen ‘ Try vbXorPen or vbMaskNotPen
.ScaleMode = vbPixels
.ScaleWidth = 256 * 2: .ScaleHeight = 256 * 2

Dim clr As Long, i As Integer, x As Integer, y As Integer
Dim iRed As Integer, iGreen As Integer, iBlue As Integer
For i = 0 To 255
‘ Set line color
If LightToDark Then
If Red Then iRed = 255 - i
If Blue Then iBlue = 255 - i
If Green Then iGreen = 255 - i
Else
If Red Then iRed = i
If Blue Then iBlue = i
If Green Then iGreen = i
End If
clr = RGB(iRed, iGreen, iBlue)
‘ Draw each line of fade
If Vertical Then
cvsDst.Line (0, y)-(.ScaleWidth, y + 2), clr, BF
y = y + 2
End If
If Horizontal Then
cvsDst.Line (x, 0)-(x + 2, .ScaleHeight), clr, BF
x = x + 2
End If
Next
‘ Put things back the way you found them
.AutoRedraw = fAutoRedraw: .DrawWidth = iDrawWidth
.DrawStyle = ordDrawStyle: .DrawMode = ordDrawMode
.ScaleMode = ordScaleMode
.ScaleWidth = rScaleWidth: .ScaleHeight = rScaleHeight
End With
End Sub

The property settings are crucial to making the fade work accurately and efficiently. For example, fading slows to a crawl if you don’t set AutoRedraw. The vbInsideSolid draw style is the only one that works properly (although vbIn­visible gives an interesting effect). The vbCopyPen draw mode ensures that you overwrite anything on the background rather than interact with it. Setting the scale properties makes it easier to draw in multiples of 256 (the number of color intensities) regardless of the size of the target. All these settings must be saved and restored in case someone else wants to draw on your fade with different settings.


Remember, you’re drawing the fade only to the current size of the target object. If you allow the object to be resized, you’ll need to put Fade in the Resize event. Since Fade is no speed demon, it might be better to make faded forms a fixed size, as the Bit Blast form is.


All the statements in the Fade function take advantage of the With cvsDst block except the Line statements. Visual Basic’s Line, PSet, and Circle statements use a nonstandard format that can’t be represented with a normal method syntax. The language parser would have to contain special-case code to handle these statements in a With block. So far, that code has not been written. The request was postponed in Visual Basic version 4 and then postponed again in version 5.


Although we’re using a naming convention (cvsDst) that implies a canvas type, the actual type is Object—and we’re paying the price with late binding. This is where we could use some public access to Visual Basic’s internal interfaces. I don’t know whether it really exists, and if so, whether they call it ICanvas, IDrawable, or IItsOurSecret, but whatever it’s named, Fade could draw a lot faster if it knew the interface of the object it’s drawing on. I shouldn’t have to write separate FadeForm, FadePictureBox, FadeUserControl, and FadePrinter procedures to get efficient drawing.


Hardcore Drawing


Help is available for all you hardcore programmers who want to draw 3-D shapes in Visual Basic. The OpenGL library is already part of Windows NT, and you can use it on Windows 95 if you get the library through the Win32 Software Developer’s Kit. OpenGL supports three-dimensional drawing with shading, lighting, hidden surface removal, texturing, and who knows what else. I was afraid that if I started playing with it, I’d never finish this book so unfortunately you’re on your own. I know of several people who have used it successfully from Visual Basic.