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);
g
d:=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...