Home PageDownloadBeginner's ZoneAmateur's ZoneExpert's ZoneTips PageProgramming LinksE-Mail Me

Amateur Zone
Flicker Free Graphics

The first problem you find when trying to write a graphical program with moving objects is flicker. The required process of drawing background, drawing foreground objects and then repeating that process many times a second means that the viewer has a short period when they can see the objects disappear, i.e flicker. To avoid this you must use a system called page or screen flipping (if you already know this technique then skip down to the part that describes how to do it on Windows). This involves having a hidden screen that everything is drawn to, when drawing has finished completely you then display that screen. There are 2 ways to do that, either changing the memory address that the monitor displays to that of the hidden screen or copying over what is on the hidden screen to the visible screen. This is the basic technique that all games and visual programs use.

Screen Flipping Under Windows

Screen flipping is quite easy under Windows, but there are a few restrictions. You cannot change the screen address, this means that the only way to do it is to copy from the hidden screen to the visible using BITBLT. Also you really should allow for all video modes, you cannot change the resolution or colour depth of the screen (without using DirectX or messing up all the desktop icons), so you have to be able react to whatever set-up your program is run on.

The first thing to do is to create the hidden screen, you can do this using Windows API commands or GFA commands, I will use GFA commands for this example as they are simpler for drawing, but APIs are generally better (the equivalents for this bit are CreateCompatibleDC, CreateCompatibleBitmap and SelectObject). You need to create a DC (Device Context) and a bitmap. A DC can be thought of as a frame and the bitmap as a piece of paper, the frame sits over the paper and holds all the tools (objects) that are used when you draw on it. There are many different types of objects, they include the colours (brushes/pens) that will be used to draw and the typeface (font). So here's the code to create a DC and bitmap both compatible with the current screen mode and then select the bitmap into the DC:

DEFWRD "a-z"

OPENW #1,100,100,422,252,%0001110000

HiddenDC=MEMDC(_DC(1))
HiddenBMP=CREATEBMP(400,200)
SETBMP HiddenDC,HiddenBMP
Now you have a hidden screen of size 400x200 to do with what you want. Drawing to it is quite a simple process, if you use API commands then it is really easy, all of them have a parameter of type HDC, just pass HiddenDC for that and drawing will be directed to the HiddenBMP. If you want to use GFA commands then you have to tell GFA where to draw using SETDC:
SETDC HiddenDC&
DEFFILL 0
GRAPHMODE R2_COPYPEN,TRANSPARENT
Now you just need a loop to do the drawing to the hidden screen and then copy that to the visible screen (the window):
bx=200,  by=100
bxv=RAND(2)*2-1,  byv=RAND(2)*2-1
DO
  PEEKEVENT
  EXIT IF _Mess=WM_KEYDOWN OR MENU(1)=4
  RGBCOLOR 0
  PBOX 0,0,400,200
  RGBCOLOR RGB(255,255,255)
  PELLIPSE bx,by,20,20
  BITBLT HiddenDC,0,0,400,200,_DC(1),10,10,SRCCOPY

  ADD bx,bxv
  ADD by,byv
  IF bx>380
    bx=380-(bx-380),  bxv=-bxv
  ELSE  IF bx<20
    bx=20+(20-bx),  bxv=-bxv
  ENDIF
  IF by>180
    by=180-(by-180), byv=-byv
  ELSE IF by<20
    by=20+(20-by), byv=-byv
  ENDIF
LOOP
That's it, you now have a non-flicker animation of a circle bouncing around, it's rubbish but then this is just an example. One thing to always remember to do last is cleanup anything that has been created:
FREEDC HiddenDC
FREEBMP HiddenBMP
CLOSEW #1
Note here that you must free the DC first, you cannot delete an object while it is still selected into a DC.

Click here to download the source code for this example


Windows Messages

Windows is a very complicated thing, you probably know that if you've tinkered with integrating your programs into the Windows environment. At the base of it all is the Windows messaging system. In GFA Basic there are so many ways to read windows messages, MENU(), _Mess and CB all have their advantages. I prefer CB for 90% of messages because wherever in your program messages have occurred, INKEY$, MOUSE or PEEKEVENT it calls the procedure you tell it to.

If you're not familiar with CB it stands for callback.

CB WIN(1),WM_PAINT,evalmsg

This means every time window #1 receives a WM_PAINT message it will call evalmsg. A routine used in CB must be like the following:

PROCEDURE evalmsg(handle&,message&,wordval&,longval%)

Handle& is the window the message is going to. Message& is the message e.g. WM_PAINT, WM_CLOSE etc.. Wordval& and longval% are different for each message, for example for WM_CHAR wordval& is the ASCII code of the key that was pressed. If you don't have the full version of GFA Basic you probably won't have a list of the windows messages. If this is the case maybe you should buy it, but if you haven't decided whether GFA Basic is for you yet the fantastic help file from Dale Bryant has detailed lists of windows messages, you can download it free from his web site. For Windows 95 messages, help files that come with other free programming languages such as Delphi and C++ Builder have got all the messages listed (of course there are no examples in BASIC, they're in C or Pascal). Remember when looking in other help files that GFA Basic doesn't recognise the Windows 3.1 (or newer) messages, API commands or constants, you can access them though, see the expert zone for details of using Windows 95 functions.

Be careful with callbacks, you can get some strange things happening. Don't ever call a PEEKEVENT or the like inside a callback routine, it's an instant, horrible crash. You can return values by using RETVAL. Usually it follows that returning 0 means that you've dealt with the message but some messages are different. For example WM_NCHITTEST returns what part of the window has been clicked on.


Manipulating CONTROLs

There is something about CONTROLs that the help files don't tell you and really makes you look at Windows in a different way when you know it. The fact is that all CONTROLs are windows, in the same way as the browser window you are reading this in is a window. Every time you see a combobox, or an edit box, it is a seperate window. When you know this manipulating CONTROLs is very easy. I find it best to use API commands to manipulate CONTROLs as the GFA equivilents are designed to be used with main windows. So, say you created a dialog and control like this (using the RCS):

DIALOG #0,70,50,300,200,"GFA Basic",$10000000
  CONTROL "Text",100,"button",$50000000,20,20,80,30
ENDDIALOG
SHOWDIALOG #0

Now to disable the button you can use:

~EnableWindow(DLGITEM(0,100),0)

You can move and resize it:

~MoveWindow(DLGITEM(0,100),5,5,100,100,1)

You can hide it:

~ShowWindow(DLGITEM(0,100),SW_HIDE)

And you can get rid of it forever:

~DestroyWindow(DLGITEM(0,100))

You can do almost anything to it that you can do to a window created with OPENW. To find out a lot of commands to manipulate windows have a look in the Windows 3.1 SDK (see downloads page).

There is also a short example of how to create CONTROLs using CreateWindowEx instead of CONTROL in the expert zone. This gives you a lot more control over how they look and act, and allows you to create CONTROLs in dialog boxes after the ENDDIALOG.


If you have any questions about animation, callbacks, Windows messages, CONTROLs or anything else to do with GFA Basic Windows programming you can e-mail me. I'll e-mail you back or if I get lots of the same questions I'll tackle it on this site.

Home PageDownloadBeginner's ZoneAmateur's ZoneExpert's ZoneTips PageProgramming LinksE-Mail Me