ARTICLE - DRAWING IN MEMORY
- an intermediate-advanced graphics tutorial
- copyright 2002, Alyce Watson

Home

Paths and File Names
Observed online
Resources for the beginner
Graphics Drawing Rules
beginner's guide to API and DLL
Drawing IN MEMORY
Radiobuttons via API
NumbWord
Working with Comboboxes

It is not currently possible to draw on a hidden graphicbox, then transfer the image from the hidden graphicbox to a visible graphicbox. If it were possible, it would be achieved by using GETBMP on the hidden graphicbox to get a named Liberty BASIC bitmap, then using DRAWBMP on that named bitmap to draw it into the visible box. Since this will not work, the alternative is to use GDI functions to do the drawing in memory.

Drawing with the Graphics Device Interface (GDI) is a subject that would easily fill an entire book. This tutorial is NOT a tutorial on drawing with GDI. It presents a method to draw in memory, then place the image on the screen in Liberty BASIC. It doesn't attempt to explain the individual GDI drawing functions.

It is assumed that the reader understands the fundamentals of making Windows API calls. For more information on making API calls, and for using GDI functions, please examine one of the many Windows API reference books that are available in libraries and bookstores, or check the Microsoft Developers Network Library here:

http://msdn.microsoft.com/library

You may also check my website and electronic books:

http://iquizme.0catch.com/lb/
http://iquizme.0catch.com/lb/lbw3/master.html
http://iquizme.0catch.com/lb/using/index.html


THE DEVICE CONTEXT
GDI doesn't draw on a window, it draws on a device context (DC). A DC is an interface used by GDI so that Windows can draw on any of the variety of hardware that might be installed on a computer. Windows can also draw on a memory device context, and that is what we'll use for this method.

MEMORY DRAWING - STEP BY STEP
Here is an outline of the steps we'll be using.

- create a window with a graphicbox
- put the pen DOWN in the graphicbox
- use GetBmp to get a Liberty BASIC bitmap from the graphicbox
- obtain the handle of the graphicbox with the hwnd() function
- obtain the handle of the Liberty BASIC bitmap with the hbmp() function
- get a DC for the graphicbox with GetDC
- create a memory DC with CreateCompatibleDC
- select the LB bitmap into the memory DC with SelectObject
- issue GDI drawing commands to the memory DC
- select the default bitmap back into the memory DC, freeing the LB bitmap
- use DRAWBMP to display the bitmap in the graphicbox - flushing if desired
- as many times as needed, select the bitmap into the memory
DC, draw on it with GDI functions, deselect it from the memory DC and display with DRAWBMP

When the program ends:
- delete the created DC with DeleteDC
- release the graphicbox DC with ReleaseDC
- delete the LB bitmap with UNLOADBMP

MEMORY DRAWING - THE THEORY
Using the GETBMP command allows us to get a named, Liberty BASIC bitmap that we can display with DRAWBMP or save with BMPSAVE. We can get a Windows handle to this bitmap with the HBMP() function. Once we have a Windows handle, we can select the bitmap into a memory device context and use GDI functions to draw on it. After deselecting the LB bitmap out of the memory device context, we can draw the altered bitmap in our graphicbox with DRAWBMP or we can save it to disk with BMPSAVE.


USING GDI - THE DISADVANTAGES
The most obvious disadvantage of drawing with GDI rather than using Liberty BASIC's own drawing commands is that the API drawing functions are more complicated, and they require device contexts to be gotten, created, released and destroyed. Using GDI also requires that pens, brushes and fonts be created, selected into the device context, and destroyed when they are no longer needed.

USING GDI - THE ADVANTAGES
Using GDI functions allows us to draw in memory, which presents many possibilities, such as flicker-free animation, and the ability to draw many objects before allowing the user to view them. In other words, the drawings can be presented as a finished picture, and the user doesn't see each step as it is drawn. There is one other big advantage to using GDI functions. There are many more graphics possibilities with GDI functions than with Liberty BASIC drawing commands. There are functions to floodfill, to create other objects such as arcs and round rectangles, to draw text that is filled with patterns, to draw with different RASTER OPERATIONS (this is how sprites are done) and on and on.

DRAWING IN MEMORY - A SIMPLE SAMPLE
The following code will run in Liberty BASIC 3.x. It is well commented.

nomainwin

'graphicbox size includes borders,
'so requires 202x202 graphicbox to
'display a drawing area 200x200
graphicbox #1.g, 10,10,202,202

open "Memory Drawing" for window_nf as #1
#1 "trapclose [quit]"
#1.g "down"

'use getbmp to get an LB bitmap
#1.g "getbmp mem 0 0 200 200"

h=hwnd(#1.g)    'handle of graphicbox
hMem=hbmp("mem")'handle of LB bitmap

'get a device context for graphicbox
CallDLL #user32, "GetDC",_
h As long,_ 'handle of graphicbox
hDC As long 'returns device context

'create a device context in memory
'that has the same attributes as the
'device context for the graphicbox
CallDLL #gdi32,"CreateCompatibleDC",_
hDC As long,_   'device context of graphicbox
memDC As long   'returns memory device context

'select the LB bitmap into the
'memory device context
CallDLL #gdi32,"SelectObject",_
memDC As long,_     'handle of memory DC
hMem As long,_      'handle of LB bitmap
oldObject As long   'returns handle of previous
                    'bitmap in DC

'draw some graphics with GDI functions:
CallDLL #gdi32, "Rectangle",_
memDC As long,_     'memory DC
10 As long,_        'upper left x
10 As long,_        'upper left y
60 As long,_        'lower right x
80 As long,_        'lower right y
r As boolean

'next call requires this struct
struct Point, x as long, y as long

'same as LB's PLACE command
CallDLL #gdi32, "MoveToEx",_
memDC As long,_     'memory DC
40 As long,_        'x
20 As long,_        'y
Point As struct,_   'returns previous x and y
r As boolean

'same as LB's GOTO command
CallDLL #gdi32, "LineTo",_
memDC As long,_     'memory DC
140 As long,_       'x
70 As long,_        'y
r As boolean

'fill a string variable
t$="Memory Drawing"

'get length of variable
ln=len(t$)

'draw the text
CallDLL #gdi32, "TextOutA",_
memDC As long,_     'memory DC
10 As long,_        'x location
130 As long,_       'y location
t$ As ptr,_         'string of text
ln As long,_        'length of string
r As long

'you must deselect the bitmap from
'the memory DC each time you want to
'display it with DRAWBMP
'
'select the previous bitmap back
'into the memory DC to do this
CallDLL #gdi32,"SelectObject",_
memDC As long,_     'memory DC
oldObject As long,_ 'original bmp in memDC
hMem As long        'returns bmp to deselect

'now, simply draw it with DRAWBMP
'and flush
#1.g "drawbmp mem 0 0; flush"

wait

[quit]
'be sure to unload the bmp
unloadbmp "mem"

'release the DC for the graphicbox
CallDLL#user32,"ReleaseDC",_
h As long,_     'graphicbox handle
hDC As long,_   'DC handle
result As long

'delete the memory DC from memory
CallDLL #gdi32, "DeleteDC",_
memDC As long,_ 'memory DC handle
r As boolean

close #1:end