Pascal-Programming.info

A step-by-step Pascal tutorial for beginners.

Lesson 12: BGI Graphics

BGI Graphics is an advanced topic and does not need to be covered. Also it entirely based on an old library managed by Borland which is BGI hence the name 'BGI'. Also if you prefer to read this lesson then you should have Turbo Pascal installed on your computer. Graphics lovers will surely be interested in this topic.

In a nutshell, this lesson will cover:

One might require the file egavga.bgi during this graphics tutorial. Click here if you don't have this file (or it is corrupt) and place it in the BGI directory in the Turbo Pascal installation folder.

COPYRIGHT NOTICE: It is assumed that you have bought Turbo Pascal once you have downloaded this file. This file is owned by its respective owners (Borland Company).

IMPORTANT DISCLAIMER: You will download and use this file at your own risk. We don't take any responsability for any damage whatsoever.

Introduction to Graphics

Graphics is a method of representing output material in a more complex, user-friendlier way than the crt. The crt is one of the few turbo pascal units or libraries. Turbo Pascal has a graphics library with which you can represent output material. Before you can call turbo pascal's graphics procedures and functions, you have to include the Graph unit in the Uses section (Eg. Uses Crt, Graph, Overlay, Printers etc...).

Initialising Graphics

Unlike the crt, graphics should be initialised, and it should be initialised at the beginning of the program or just before you start using graphics procedures and functions. This will help the compiler to link to the graphics file. Usually, the default graphics routines used by the Turbo Pascal's compiler is the EGAVGA.BGI. When you initialise the graphics, automatically your computer will use this file to output graphics material.

The famous piece of code, used to initialise the graphics in Turbo Pascal (NOT Dev-PASCAL or Free-Pascal! Dev-Pascal and other compilers do not accept the graph driver and graph mode be declared as integer values. If you have Dev-Pascal then change all the variable types of the 'gd,gm' to smallint! 'Gd, Gm : Smallint;') is shown below:

Program Lesson12_Program1; 
Uses Crt,Graph;

Var 
	GraphicsDriver, GraphicsMode,
    ErrCode : Integer;
 	{two var's are needed for initialisation}

Begin
	Writeln('Initialising Graphics, please wait...');
	GraphicsDriver := Detect;
	InitGraph(GraphicsDriver, GraphicsMode,'');
	
	{IMPORTANT, read the following or otherwise graphics will not work!! ;)}
	
	(* between the inverted commas, type in the path of the graphics BGI file
		(usually 'C:\TP\BGI'),
		OR
		change the dir in the file menu (PRESS Alt+F) 
		and roll down your mouse pointer to the 'change dir' 
		menu; then either type the path to the BGI file, 
		or go to C: -> TP -> BGI *)
	
	ErrCode := GraphResult;
	If GraphResult <> grOK Then { <> means 'not equal to' }
  	Begin
		ClrScr;
		Writeln('Graphics error occured: ',
		GraphErrorMsg(ErrCode));
		Writeln('If a file not found error is displayed above');
		Writeln('then, change the dir from the current');
		Writeln('location to C:\ -> TP -> BGI, from the file menu!');
		Readln;
		Halt(1);
  	End Else
	Begin
		Randomize; 
		SetColor(Random(15) + 1); {Set text colour}
		{Output text at 20 pixels from the top of the screen, 
			and 20 other from the left side of the screen.}
		OutTextXY(20,20,'Welcome to the new generation of Pascal Programming:');
		OutTextXY(20,30,'Pascal Graphics!!');
		OutTextXY(25,70,'You will learn more graphics procedures and');
		OutTextXY(25,80,'functions, later in this lesson :-)');
		Readln;
	End; 
	CloseGraph;
End.

The program above uses the statement:

InitGraph(GraphicsDriver,GraphicsMode,'');

You may find it strange what does the two inverted commas (' ') mean, in the statement shown above. It is the path which redirects the turbo pascal linker to the graphics BGI file. So, in between the inverted commas, you have to enter the path to the graphics driver, or otherwise you will receive an error message. You may leave it blank and let the compiler himself find the BGI file automatically (in the current directory), but when I did this, it never worked!! :-) If you did not change the folder address (C:\TP) after the installation, you may use this path: 'C:\TP\BGI', like this:

InitGraph(GraphicsDriver,GraphicsMode,'C:\TP\BGI');

After the 'initgraph()' statement, you should inform the user with the problem concerning a graphics error, if the EGAVGA.BGI file is not found. Hope it does not happen to you :-) !! Then, if the user is error-free, then you can start calling graphics procedures and functions from the graphics library (graph). In the example program above, I used only the 'OutTextXY()' statement and the 'SetColor()' statement. However there are many more functions other than these!

At the end of each graphic statments, you have to close the graphics section, by using the 'CloseGraph' statement.

USEFUL INFORMATION: Note that the screen resolution is 640 by 480 pixels (compare this with that of the CRT! - the CRT has a screen resolution of 80 by 25 'pixels' only!)

Passing Records as Arguments

It may become very useful when records are required to be passed through arguments and this will be demonstrated shortly. I will use the same data structure, pass it by reference as a parameter and return the value back through the parameter also.

Type
	Str25    = String[25];
	TBookRec =
			Record
				Title, Author, ISBN : Str25;
				Price : Real;
			End;

Procedure EnterNewBook(var newBook : TBookRec);
Begin
	Writeln('Please enter the book details: ');
	Write('Book Name: ');
	Readln(newBook.Title);
	Write('Author: ');
	Readln(newBook.Author);
	Write('ISBN: ');
	Readln(newBook.ISBN);
	Write('Price: ');
	Readln(newBook.Price);
End;

Procedure DisplayBookDetails(myBookRec : TBookRec);
Begin
	Writeln('Here are the book details:');
	Writeln;
	Writeln('Title:  ', myBookRec.Title);
	Writeln('Author: ', myBookRec.Author);
	Writeln('ISBN:   ', myBookRec.ISBN);
	Writeln('Price:  ', myBookRec.Price);
End;

Var
	bookRec : TBookRec;

Begin
	EnterNewBook(bookRec);
	Writeln('Thanks for entering the book details');
	DisplayBookDetails(bookRec);
	Readln;
End.

Arrays of Records

Records may be stored in arrays and this will become very useful and it is not that difficult to manage. We will use an array of records to store a number of different books and by using this example, it will be immensely indicative to learn how to use them.

In the following example I will use the procedures above to store 10 different books from input and then output only one chosen record to display it back to screen in order to demonstrate how to access a record from an array.

Type
	Str25    = String[25];
	TBookRec =
			Record
				Title, Author, ISBN : Str25;
				Price : Real;
			End;

Procedure EnterNewBook(var newBook : TBookRec);
Begin
	Writeln('Please enter the book details: ');
	Write('Book Name: ');
	Readln(newBook.Title);
	Write('Author: ');
	Readln(newBook.Author);
	Write('ISBN: ');
	Readln(newBook.ISBN);
	Write('Price: ');
	Readln(newBook.Price);
End;

Var
	bookRecArray : Array[1..10] of TBookRec;
	i            : 1..10;

Begin
	For i := 1 to 10 do
		EnterNewBook(bookRecArray[i]);

	Writeln('Thanks for entering the book details');
	Write('Now choose a record to display from 1 to 10: ');
	Readln(i);
	Writeln('Here are the book details of record #',i,':');
	Writeln;
	Writeln('Title:  ', bookRecArray[i].Title);
	Writeln('Author: ', bookRecArray[i].Author);
	Writeln('ISBN:   ', bookRecArray[i].ISBN);
	Writeln('Price:  ', bookRecArray[i].Price);
	Readln;
End.

Note that you can also use arrays within records and this time the square brackets go on with the field name instead of the record. Also you can embed records within records. More dots will be required to access deeper records.

Binary Files and Records

Records can also be stored into files and this could be done by using binary files. I will demonstrate storing records into files by continuing from the previous example. Using binary files could be very handy, fast and more reliable over text files. You can't afford storing hundreths of files by using text files since it becomes confusing and even slower for the computer to process and read/write from/to the file.

In the following example I will use a file of the book record I have created and then store as many books as I want in the file using the binary file system. Watch carefully how I will create the file of record and how I will perform the file I/O for the binary file system. Also, I will make use of special built in functions that help me position the file pointer to the record I want.

Note that with binary files, only Read and Write are allowed to read/write fro/to a file.

Type
	Str25    = String[25];
	TBookRec = 
			Record
				Title, Author, ISBN : Str25;
				Price : Real;
			End;

Procedure EnterNewBook(var newBook : TBookRec);
Begin
	Writeln('Please enter the book details: ');
	Write('Book Name: ');
	Readln(newBook.Title);
	Write('Author: ');
	Readln(newBook.Author);
	Write('ISBN: ');
	Readln(newBook.ISBN);
	Write('Price: ');
	Readln(newBook.Price);
End;

Var
	bookRecArray : Array[1..10] of TBookRec;
	tempBookRec  : TBookRec;
	bookRecFile  : File of TBookRec;
	i            : 1..10;

Begin
	Assign(bookRecFile, 'bookrec.dat');
	ReWrite(bookRecFile);

	For i := 1 to 10 do
	Begin
		EnterNewBook(bookRecArray[i]);
		{ bookRecArray[i] now contains the book details }
		Write(bookRecFile, bookRecArray[i]);
	End;

	Close(bookRecFile);
	Writeln('Thanks for entering the book details.');
	Writeln('They are saved in a file!');
	Write('Now choose a record to display from 1 to 10: ');
	Readln(i);
	ReSet(bookRecFile);
	Seek(bookRecFile, i-1);
	Read(bookRecFile, tempBookRec);
	Close(bookRecFile);
	Writeln('Here are the book details of record #',i,':');
	Writeln;
	Writeln('Title:  ', tempBookRec.Title);
	Writeln('Author: ', tempBookRec.Author);
	Writeln('ISBN:   ', tempBookRec.ISBN);
	Writeln('Price:  ', tempBookRec.Price);
	Readln;
End.

The example program above demonstrated the use of the seek function. It's role is to place the file pointer to the desired position. The first component of the file is marked as 0. So you have to keep in mind that if you have a counter starting from 1, you have to decrement it by 1 to obtain the actual record you want.

The seek function is very important and has an important role in binary file system. Here are some uses of the function and how it can be used effectively to obtain a particular position of the file.

Special Uses of the Seek Function

Seek the first record of the file

Seek(myFile, 0);

Seek the last record of the file

Seek(myFile, FileSize(myFile)-1);

Seek one position beyond the last record

Seek(myFile, FileSize(myFile));

Seek to the next position of the file from the current

Seek(myFile, FilePos(myFile)+1);

When trying to access from a file position that is beyonf the file limits, a runtime error is automatically raised. Try to avoid this type of error. This may be caused because you might have looped through the file and kept on looping beyond its limits. Note that Seek(myFile, -1) is a typical runtime error becuase -1 position does not exist. 0 is the least and the first record in the file. Note that FilePos is also very useful and it returns the current positon of the file. Please note that FileSize returns the number of components in the specified file and not the size in Bytes. If the file is empty, 0 is the returned value. On the other hand, if the file contains 5 records (ie. 0 to 4), 5 is returned.

The structure of a binary file is just like blocks being stored contiguosly in a line. Think of boxes being placed one adjacent the other and each one of them has data. There is a space between this boxes that indicates the file positon and we can easily depict this fact below.

0 BookRec0 1 BookRec1 2 BookRec2 3 BookRec3 4 BookRec4
  ^              

The first row is the actual file showing the indexes of each record block and the second row shows the file pointer ie. the file position. The current file position shown in the illustration above is relevant to Seek(myFile, 1). Now you have been assured that the number 1 record of a file is not the first record of the file. After the last record, there is an EOF marker that indicates the end of the file and it is not legal to go beyond this point except for only one position to allow appending ie. Seek(myFile, FileSize(myFile)).

Spread The Word!

Have Your Say