Picture Motion--Avoid The Flicker

By Cevahir PARLAK

http://www.macrotech.bigstep.com

mailto:[email protected]

Introduction
This article explains some of the concepts of double buffering, which is used to prevent flicker when drawing onto the screen. It includes Delphi code to show how to implement some of the theories.

Overview
This example application uses a simple approach to buffered graphics and masking using Delphi.Later I will dive into DirectX and explain some ideas about picture motion.

However for a beginner programmer interested in writing games or graphic intensive applications in Delphi , this could be useful. Even if you ultimately want to work in WinG or DirectX, this could be useful for prototyping with. This works just as well for Delphi 1.0. And there is even a way to do this in Visual Basic.

Note that the program's redraw rate is set to 50 milli-seconds. Assuming that your machine can redraw it all in this amount of time, the animation should occur at 20 frames a second. The human visual system works at just over 20 "frames" a second so the movement of the Symbols should appear smooth. ( If I understand it correctly, the human visual system works at half the speed of the brain, which fires at just over 40 cycles a second. )

Buffered Drawing
The idea in buffered drawing is to prepare the screen image in non-visible memory, and then either making that memory visible, or copying from the non-visible memory to visible memory.

Look at what this program has to do each timer event. First it draws the whole wall. Then it draws each symbol, first the symbol's mask, then the symbol's image.

If this was being drawn directly to the screen, the symbols would take on an unpleasant flickering and see-through appearance. This is because some times your eye will be seeing the wall before the symbol is drawn, and other times it will be seeing the symbol. That is, some times you will be seeing the wall beneath the symbol.

By preparing the drawing to an invisible location, and then only drawing the final output to the screen, you only see that part of the wall that is not covered by the symbols.

This approach takes advantage of some of the less apparent features of the Image and PaintBox controls.

How the Buffer Works

What I do is place a visible PaintBox on the form for where I want to show the graphics. I then have an equal sized but invisible (visible=false) Image control. I prepare the graphic output in the invisible Image, which servers as the buffer. I then copy the invisible Image to the visible PaintBox.

The real trick here is using a PaintBox control (in the System control set) as the visible component, and Image control (in the Additional control set) for the invisible controls. For some reason this is the only combination that seems to work, though you could probably use a Forms canvas in place of the PaintBox canvas.

Not only does the CopyRect() method work well here, all the other drawing methods of a canvas can be used in this was.

As the result of this program you will see a strategic B2 Bomber Plane attacking Al Unser Junior at Michigan 500.

First Step

The problem with TImage is that it descends from TGraphicControl (which in turn descends from TControl) which means that it does not reside inside it's own window. TImage, TLabel, and TShape all derive from TGraphicControl. Moving these types of controls around (by changing the Top and Left properties) will cause flicker . This is because when moved, they need constant repainting (unlike TWinControl descendants which don't need constant repainting when moved) to be displayed in the new location. Windows itself knows the location of window controls, but knows nothing about TGraphicControls. It is very analogous to having a posterboard: TWinControls are pinned to the posterboard, while TGraphicControls are drawn on the posterboard. It's really easy to move the pinned controls around by simply unpinning them then changing their location. The controls that are drawn directly to the posterboard need to be erased then redrawn. Does this make sense? So the easiest thing to do is Parent the GraphicControl descendant on a WinControl, and move the WinControl (such as a TPanel). Using a TPanel component, be sure to set the FullRepaint property to false.

At this point I decided to create a component that derived from TwinControl but Borland suggests using TCustomControl which has the OnPaint event.I followed it and created TImageWindow.Moving a TImageWindow over a background image causes less flicker.TImageWindow has a Round property that rounds the image.I will use that property while I explain Rotating Bitmaps Using Scanline.

DownLoad TImageWindow

Second Step

DownLoadBackGroundImages

DownLoad Double Buffering

Third Step

To use DirectX with Delphi you will need DelphiX package.

DownLoad DelphiX Package

Fourth Step

After loading Delphi X you can change TPaintBox with DXPaintBox to convert the project to a DirectX project.

Fifth Step

DownLoadDXBuffering

Sixth Step

To Rotate Bitmaps Download this project.

DownLoad RotateBitmaps

Seventh Step

If you wonder how I created all those background Images in the Double Buffering Projects read these lines carefully.

First I notify you that you don’t need Video Capture Devices to capture videos!!!

Run the Capture program and then open your AVI file.The frames of your AVI will be saved under directory C:\Screen\Screen1.bmp~Screen2.bmp............~Screeni.bmp

I run my Cart Racing and Captured the Bitmaps that way.But there were other cars on the track and it was very difficult to save bitmaps while playing and later I played a replay with the view of front wing and no opponent car running.The bitmaps ( I captured more than 100) I have got that way are similar to RamBmp.bmp.As you see there are many other things in this Bitmap.Now I have to clip the Track part of this pictures and save them to a file.First I opened RawBmp with MSPAINT and by moving mouse I find the position of Rectangle which has the track picture : Rect(201,204,655,544).

I will copy this part of picture to Rect(0,0,655-201,544-204) of another bitmap.At this point We should make

Image1.Width:=655-201;

Image1.Height:=544-204;

Now all I have to do is just copying that part of picture from RawBmp to a new bitmap file.

The source code for that is as follows:

procedure TForm1.ClipBmpClick(Sender: TObject);

var

Bitmap: TBitmap;

MyRect, MyOther: TRect;

begin

MyRect := Rect(201,204,655,544); // rect of source bitmap

MyOther:=Rect(0,0,655-201,544-204); // rect of destination bitmap

Bitmap := TBitmap.Create;

Bitmap.LoadFromFile('c:\Screen\Screen'+IntToStr(i)+'.bmp');

//Image1.Canvas.BrushCopy(MyRect, Bitmap, MyRect, clNone); this creates a transparent bitmap

Image1.Canvas.CopyRect(MyOther,Bitmap.Canvas,MyRect);

Image1.Picture.Bitmap.SaveToFile('C:\Cart1\Michigan'+IntToStr(i)+'.bmp');

Bitmap.Free;

i:=i+1;

end;

The result bitmap is Michigan.bmp.The size of RawBmp is more than 1.5 MB and the size of Michigan.bmp is 302 KB.That is too much for a game program because you will need hundreds of frames for a good game and The size of your program will be very large.For this reason,I added a BmpToJpg routine to convert bitmaps to jpg.

DownLoadCaptureScreen

Hosted by www.Geocities.ws

1