Code recipes
This section contains
programming tips and code recipes for WinGraph. If you have any
questions, please check this section first.
How to compile WinGraph units ?
The source files are
located in \src folder. These are 'wingraph.pas',
'wincrt.pas' and 'winmouse.pas'. They can be compiled directly using
the command line compiler (even after moving the files into another
folder), or using provided batch scripts. In the later case, consult
the file 'compile.txt' for details.
How to use compiler switches in WinGraph ?
In 'wingraph.pas' unit there are three switches that can be played with. 256_COLOR_NAMES
switch defines 256 color name variables that can be used when selecting
colors. If a legacy graphics driver is selected (with 16 or less
colors), better let this switch disabled, since the colors are mapped
incorrectly. INIT_OPENGL switch enables OpenGL drawings in the graphics window, otherwise it can be disabled. HIDE_CONSOLE switch hides temporarily the parent console window (if the program has one) at the time when graphics window is shown.
If the program generates useful output into the console during running
(see topics about console window below) then let this switch disabled.
Note that not all switches mentioned above are enabled by default.
How to use WinGraph units for my project ?
You have two options here:
(a) move the WinGraph source files (see above) into your project folder
and compile them together with your code; (b) compile the WinGraph
units into their default location and move compiled binaries into your
project folder. These binaries have extensions *.o, *.ppu (for FPC) or
*.dcu (for Delphi), and are located in \bin folder. In your program
header write
uses wingraph,wincrt,winmouse;
The units WinCrt and WinMouse are optional (they add keyboard and mouse support to WinGraph).
About WinGraph philosophy
Your main program window might be a console or a GUI one. It doesn't matter, since WinGraph creates its own GUI window with a dedicated thread to manage its messages. It will handle also all keyboard and mouse events, if WinCrt and WinMouse units are included (see above). All these happen only after calling InitGraph routine.
First you should set the dimensions of the window and the number of colors in the palette by playing with drivers and modes. After setting some attributes (color, font, style for lines, filling etc.) you can start drawing as in BP graph unit. After each graphics operation you may check GraphResult to discover if something went wrong.
If you try to port BP legacy code to WinGraph, be careful at the following aspects: routines flagged with (P) or (D) symbol could behave differently (check the arguments), routines flagged with (N) are missing and Crt routines for keyboard handling are emulated by WinCrt unit only after InitGraph. It is a good idea to port the code first for GO32v2 target of the Free Pascal compiler.
Several demos are included to accommodate yourself with the WinGraph programming style.
Significant incompatibilities with BP graph unit
How to initialize the graphics window ?
The simplest code is
gd:=Detect;
InitGraph(gd,gm,'');
<your code here>
repeat until CloseGraphRequest; //this waits for close button to be clicked
CloseGraph;
If WinCrt unit is included, the fourth line can be replaced by
ReadKey; //this waits for any key to be pressed
However, do not use standard ReadLn routine to wait for keyboard inputs (see below) .
How to open a custom-sized window ?
Suppose we want to open a tiny 200 by 100 graphics window. We have
SetWindowSize(200,100);
gd:=nopalette; gm:=mCustom;
InitGraph(gd,gm,'A tiny size window');
<your code here>
repeat
Delay(10); //this gives some rest to the CPU (needs WinCrt unit)
until CloseGraphRequest; //this waits for close button to be clicked
CloseGraph;
What's wrong with ReadLn routine ?
ReadLn routine waits for
input from the parent console window, which is hidden after calling
InitGraph. There is no way to receive inputs.
However, if you want to compile lots of legacy code, you can redefine ReadLn routine as follows
procedure ReadLn;
begin
repeat until (ReadKey=#13);
end;
Now you can use this routine as intended, but WinCrt unit must be included.
How to avoid the parent console window to appear ?
In your main program use the directive
{$APPTYPE GUI}
Note that in Delphi this is the default.
Is the parent console window useful, anyway ?
Sometimes, yes. For
example, in the debug phase of your program. If the parent console
window is not inhibited (see above), you can use the standard routine
WriteLn to output useful things during execution into the console.
Note that in Delphi you should use, in this case, the directive
{$APPTYPE CONSOLE}
How to write text with custom fonts ?
Suppose you want to write text using a specific font, for example 'Verdana' with a font size of 18. Following routine checks if the font is registered into the system and sets text attributes accordingly.
procedure ChangeFont;
var font:smallint;
begin
font:=InstallUserFont('Verdana');
if (font<0) then Exit;
SetTextStyle(font,HorizDir,18);
end;
Note that several fonts are installed by default during initialization. See documentation.
How to perform input and output easily in the graphics window ?
In WinCrt unit there are two routines, ReadBuf and WriteBuf, which do the job nicely. They emulate Read an Write console routines. You have an example here
WriteBuf('Please enter some text here: ');
ReadBuf(t,0);
WriteBuf('You entered: '+t);
How to add keyboard support to my graphical program ?
You should include the unit WinCrt and, in the main loop of the program, call a routine like this one
procedure CkeckKeyboard;
var c:char;
begin
if not(KeyPressed) then Exit;
c:=ReadKey;
case c of
#27:begin //Esc key
<your code here>
end;
<...>
#0:begin //extended keys
c:=ReadKey;
case c of
#75:begin //Left key
<your code here>
end;
<...>
end;
end;
end;
end;
Consult WinGraph documentation for the full list of key codes.
How to add mouse support to my graphical program ?
You should include the unit WinMouse and, in the main loop of the program, call a routine like this one
procedure CkeckMouse;
var me:MouseEventType;
begin
if not(PollMouseEvent(me)) then Exit;
GetMouseEvent(me);
with me do
case action of
MouseActionDown: begin //mouse button pressed
case buttons of
MouseLeftButton: begin //Left button
<your code here>
end;
<...>
end;
end;
<...>
end;
end;
Consult WinGraph documentation for a full description of type MouseEventType.
How to load a BMP image from disk ?
Suppose we have a 24 bits format uncompressed BMP image on file 'image.bmp'. The following routine puts this image on screen, on the top-left corner.
procedure LoadBMP;
var f:file; bitmap:pointer; size:longint;
begin
{$I-} Assign(f,'image.bmp'); Reset(f,1); {$I+}
if (IOResult <> 0) then Exit;
size:=FileSize(f);
GetMem(bitmap,size);
BlockRead(f,bitmap^,size);
Close(f);
PutImage(0,0,bitmap^,NormalPut);
FreeMem(bitmap);
end;
How to capture the window content into a BMP image on disk ?
To capture the entire window content to the file 'image.bmp' use the routine
procedure SaveBMP;
var f:file; bitmap:pointer; size:longint;
begin
{$I-} Assign(f,'image.bmp'); Rewrite(f,1); {$I+}
if (IOResult <> 0) then Exit;
size:=ImageSize(0,0,GetMaxX,GetMaxY);
GetMem(bitmap,size);
GetImage(0,0,GetMaxX,GetMaxY,bitmap^);
BlockWrite(f,bitmap^,size);
Close(f);
FreeMem(bitmap);
end;
How to perform basic animations ?
This consists of two steps:
(a) Suppose we created on screen a sprite image bounded by rectange
(0,0,24,24) and we want to have transparency set over the Black color.
Following code do this job and puts the animation on its first position
on screen
GetAnim(0,0,24,24,Black,anim);
<your code here to prepare background screen>
PutAnim(xnew,ynew,anim,TransPut);
UpdateGraph(UpdateOff); //used to reduce flickering
(b) Next code performs one step of the animation over the screen
Delay(25); //set temporization here
PutAnim(xold,yold,anim,BkgPut);
PutAnim(xnew,ynew,anim,TransPut);
UpdateGraph(UpdateNow);
You should free the animation resources at the end by calling FreeAnim.
How to perform OpenGL animations ?
First, load OpenGL header units with
uses wingraph,{$IFDEF FPC}gl,glu;{$ELSE}opengl;{$ENDIF}
and afterwards perform some initializations
SetOpenGLMode(DirectOn);
<your code here for OpenGL initialization scenery>
Next, it follows the animation loop
repeat
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); //clear OpenGL screen
<your code here for drawing OpenGL scenery>
UpdateGraph(UpdateNow);
until CloseGraphRequest;
Please consult an OpenGL manual for more details.
How to obtain palette effects ?
Suppose we want to show a text on screen progressively to the user (shading efect). Prepare the screen in advance
SetColor(White);
SetRGBPalette(White,1,1,1);
<your code here for writing text>
The text is not visible yet, since it is too dark (but not Black). With the following routine we get the result
procedure ShadingEffect;
var i:byte;
begin
for i:=50 to 250 do
begin
Delay(10); //set temporization here
SetRGBPalette(White,i,i,i);
end;
end;
Note that this works only on palette-based drivers, such as D8bit. See documentation for details.
More code recipes might come...