75% found this document useful (4 votes)
6K views42 pages

Graphics Programming

This document discusses drawing lines in graphics programming using C in 3 different ways: 1) Using the line() function to draw a line between two absolute points. 2) Using moveto() to set the current position and lineto() to draw a line from the current position to another point. 3) Using moverel() to move the current position relative to its current location and linerel() to draw a line relative to the current position. The document provides an example program to demonstrate these three methods.

Uploaded by

api-3837421
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
Download as doc, pdf, or txt
75% found this document useful (4 votes)
6K views42 pages

Graphics Programming

This document discusses drawing lines in graphics programming using C in 3 different ways: 1) Using the line() function to draw a line between two absolute points. 2) Using moveto() to set the current position and lineto() to draw a line from the current position to another point. 3) Using moverel() to move the current position relative to its current location and linerel() to draw a line relative to the current position. The document provides an example program to demonstrate these three methods.

Uploaded by

api-3837421
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1/ 42

20 Graphics Pro-

gramming
All Lines Are Not Same
Stylish Lines
Drawing and Filling Images
Patterns with A Difference
Why Use A bar( )?
Filling Regular and Non-Regular Shapes
Of Palettes and Colors
Outputting Text
Justifying Text
A Bit of Animation
System Metrics
Exercise

627
116 Let Us

C omputer graphics is one of the most powerful and interesting


facet of computers. There is a lot that you can do in graphics
apart from drawing figures of various shapes. All video games,
animation, multimedia predominantly works using computer
graphics. The intention of this chapter is to give you a feel of how
some of these things are achieved in C. The aim is to make you
comfortable with the basic concepts in graphics, introduce you to
the standard library graphics functions and then let you explore on
your own. Instead of discussing each standard library graphics
function in detail I thought it worthwhile to put them to use in a
program. The purpose of these functions, the meaning of the
parameters passed to each function and the way to use these
functions is discussed in Appendix A at the end of this book. Here is
the first program...

# include "graphics.h"
main( )
{
int gd = DETECT, gm, x, y ;
int array[ ] = { 540, 220, 590, 270, 570, 320, 510,
320, 490, 270, 540,
220 } ;

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

x = getmaxx( ) ;
y = getmaxy( ) ;

setcolor ( WHITE ) ;
rectangle ( x / 30, y / 20, x / 5, y / 4 ) ;
outtextxy ( x / 30 + 15, y / 8 + 5, "Rectangle" ) ;

circle ( x / 2, y / 6, 75 ) ;
putpixel ( x / 2, y / 6, WHITE ) ;
Chapter 20: Graphics Programming 117
outtextxy ( x / 2 - textwidth ( "Circle" ) / 2, y / 6 +
10, "Circle" ) ;

arc ( x / 1.2, y / 6, 300, 90, 80 ) ;


outtextxy ( x / 1.2, y / 6, "Arc" ) ;

line ( x / 30, 10 * y / 15, x / 6, 10 * y / 15 ) ;


outtextxy ( x / 30 + 10, 10 * y / 15 + 10, "Line" ) ;

ellipse ( x / 2, 10 * y / 17, 0, 360, 100, 50 ) ;


putpixel ( x / 2, 10 * y / 17, WHITE ) ;
outtextxy ( x / 2 - textwidth ( "Ellipse" ) / 2, 10 * y /
17 + 10, "Ellipse" ) ;

drawpoly ( 6, array ) ;
outtextxy ( 515, 270, "Polygon" ) ;

getch( ) ;
closegraph( ) ;
restorecrtmode( ) ;
}

When we start drawing any graphics on the screen we need a


header file called GRAPHICS.H and a library file called
GRAPHICS.LIB. The header file contains definitions and
explanations of all the functions and constants we’ll need, whereas,
the graphics functions are kept in the graphics library file. Both
these files are provided as part of TURBO C.

First thing that we need to do before we can carry out any drawing
activity is, switch over to the graphics mode. This is not simple,
since depending on the adapter and monitor that is installed on your
computer, only some of the several graphics modes may be
available to you. These modes have been given numbers. Out of all
the modes available, we would like to switch over to the one which
offers the best possible resolution.
118 Let Us

C
Did we say resolution? Well, the number of dots or picture elements
(pixels) available to us on the screen in the graphics mode, is known
as the resolution. The greater the number of dots, the higher the
resolution. Simply put, this means that more the dots available,
clearer would be our picture.

To switch over to the graphics mode that offers the best resolution
we need to call the function initgraph( ). It figures out the best
resolution and puts the number corresponding to that mode in the
variable gm. The gm number tells us which monitor we are using,
and its resolution, the number of video pages it supports and the
colors that are available.

Note that I’ve written the programs in this chapter on a color


monitor driven by a VGA adapter, the maximum resolution of
which is 640 x 480 (i.e. 640 pixels from left to right and 480 pixels
from top to bottom). For other adapters I expect you to make the
necessary changes in the programs.

To understand gd, we have to understand the concept of device


drivers. Device drivers are small programs which talk directly to the
hardware. Since we can’t be machine-dependent at any time, we
need programs we can communicate with in a standardized way.
These programs in turn communicate with the machine. These
intermediary programs are known as device drivers.

Graphics drivers are a subset of device drivers and are applicable


only in the graphics mode. They work in the above fashion to
execute whatever task we have assigned them. Turbo C offers
certain graphics drivers. These are the files with a BGI extension.
Depending on what adapter is used, one of these drivers gets
selected. Our programs have been developed on the VGA adapter.
Thus we need the EGAVGA.BGI file as our graphics driver. In our
program, gd has been assigned the value DETECT, thereby asking
initgraph( ) to figure out which BGI file is needed. This file is then
Chapter 20: Graphics Programming 119
loaded into memory. If we do not initiate gd with DETECT then it is
our responsibility to set up gd and gm with appropriate values.
Since most of the times we don’t want to be bothered with this
responsibility we use the DETECT macro.

So much about the graphics modes and changing over to the


appropriate graphics mode. Two things happen the moment we
change over to the graphics mode. Firstly, the cursor disappears
since the graphics modes do not support the conventional cursor.
Secondly, a coordinate system is established whereby the top left
corner of the screen is treated as origin (0, 0). As usual, the x-axis
goes horizontally across, and the y-axis goes vertically downward.

The basic tools we’ll need for drawing shapes are functions like
putpixel( ), line( ), circle( ), ellipse( ), arc( ) and drawpoly( ). All
these functions have been used in our program. Their general form
is shown in Figure 20.1. Before drawing the rectangle we have used
two functions getmaxx( ) and getmaxy( ). These fetch the
maximum x and y coordinates for the chosen graphics mode.
120 Let Us

Function Meaning

putpixel ( x1, y1 ) ; Lits the pixel at ( x1, y1 )


line ( x1, y1, x2,. y2 ) ; Draws a line from ( x1, y1 ) to
( x2, y2 )
circle ( xc, yc, rad ) ; Draws a circle with center
( xc, yc ) and radius rad
rectangle ( x1, y1, x2, y2 ) ; Draws a rectangle with ( x1, y1)
and ( x2, y2 ) as corners
ellipse ( xc, yc, start, end, Draws an ellipse with ( xc, yc )
xrad, yrad ) ; as center with xrad and yrad as
x and y radius. If start is 0 and
end is 180 only the upper half of
the ellipse is drawn
arc ( xc, yc, start, end, Draws an arc with ( xc, yc ) as
rad ); center, rad as radius and start
and end as the starting and
ending angles

Figure 20.1

All Lines Are Not Same


In the previous program we drew a line using the line( ) function.
The coordinates passed to this functions were with respect to the
origin (0, 0), represented by the pixel at the top-left corner of the
screen. Another way to draw a line is to use a combination of two
Chapter 20: Graphics Programming 121
functions moveto( ) and lineto( ). The moveto( ) function moves
the C.P. to the specified coordinates. What is this C.P.? It stands for
Current Position. When we initialize the graphics system C.P. is at
the origin. On executing some drawing functions C.P. changes,
whereas in others it doesn’t. For example, after drawing a line using
the line( ) function C.P. doesn’t change, whereas, on drawing a line
using the function lineto( ) the C.P. changes to the end point of the
line drawn.

It is also possible to draw a line relative to a particular point on the


screen using the linerel( ) function. The coordinates passed to
linerel( ) specify where we want the line to end using the said point
as our origin. To reach the starting point we can use either the
function moveto( ) or moverel( ). The first function moves the C.P.
to the given coordinates with (0, 0) as the origin, whereas, the
second moves the C.P. by a relative distance from its current
position. The following program uses the three methods mentioned
above to draw lines on the screen.

#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
main( )
{
int gd = DETECT, gm ;
char msg[80] ;

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

outtextxy ( 100, 0, "Demonstration of Moveto,


Lineto, Moverel, Linerel" ) ;
rectangle ( 0, 10, 639, 479 ) ;

line ( 100, 50, 100, 350 ) ; /* draws a line */

moveto ( 300, 50 ) ; /* moves the C.P. */


122 Let Us

C
lineto ( 300, 350 ) ; /* draws a line up to the point
*/

moverel ( 200, -300 ) ; /* moves the C.P. by relative


distance from its
current position */
linerel ( 0, 300 ) ; /* draws a line from the C.P. to a
point a relative
distance away from the current value
of C.P. */

outtextxy ( 104, 50, "( 100, 50 )" ) ;


outtextxy ( 104, 350, "( 100, 350 )" ) ;
outtextxy ( 90, 375, "Line" ) ;

outtextxy ( 304, 50, "( 300, 50 )" ) ;


outtextxy ( 304, 350, "( 300, 350 )" ) ;
outtextxy ( 280, 375, "Moveto, Lineto" ) ;

outtextxy ( 504, 50, "( 500, 50 )" ) ;


outtextxy ( 504, 350, "( 500, 350 )" ) ;
outtextxy ( 480, 375, "Moverel, Linerel" ) ;

getch( ) ;
closegraph( ) ;
restorecrtmode( ) ;
}

This program draws three lines. The first line has been drawn using
the usual line( ) function. The second one has been drawn using the
moveto( ), lineto( ) functions. Note that for drawing this line we
have reached our starting point (300, 50) by calling the moveto( )
function and then drawn a line up to (300, 350) using the lineto( )
function. This shifts the C.P. to (300, 350). The third line is drawn
Chapter 20: Graphics Programming 123
by first shifting the C.P. from its current position by a relative
distance of 200 pixels to the right and 300 pixels up using the
moverel( ) function. Next the line is drawn using the function
linerel( ), once again using the relative distances.

Stylish Lines
So far we have drawn only solid lines. However, situations may
demand to draw lines with other line styles. For example, we may
use dashed lines to indicate hidden edges of an object, or center
lines to indicate center lines of a circle, and so on. Turbo C provides
four different line styles to draw solid, dotted, center and dashed
lines. These styles can be used to draw either normal or thick lines.
It also permits us to use a line style created by us to draw the lines.

To be able to draw lines of different styles we must use the function


setlinestyle( ). Its prototype looks like this:

setlinestyle ( type, pattern, thickness ) ;

The first parameter specifies the type of line (solid, dashed, etc.).
The second parameter is applicable only if the line style is user-
defined. The third parameter specifies the line thickness. The
various line styles have been enumerated in ‘graphics.h’ as under:
0 Solid Line
1 Dotted Line
2 Center Line (alternating dashes and dots)
3 Dashed Line
4 User-defined Line
The thickness parameter can take the value 1 or 3. The former
corresponds to a line thickness of one pixel (normal), the latter to a
thickness of three pixels (thick). Let us now use this information to
draw lines of different styles.

# include "graphics.h"
main( )
124 Let Us

C
{
int gd = DETECT, gm, maxy, x, style ;
char str[40] ;
struct linesettingstype ls ;

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

maxy = getmaxy( ) ;

setcolor ( WHITE ) ;
outtextxy ( 10, 20, "Normal width" ) ;

x = 20 ;
for ( style = 0 ; style <= 4 ; style++ )
{
setlinestyle ( style, 0, 1 ) ;

if ( style == 0 )
getlinesettings ( &ls ) ; /* save line setting */

if ( style == 4 )
{
setlinestyle ( 4, 15, 1 ) ;
line ( x, 50, x, maxy - 50 ) ;
}
else
line ( x, 50, x, maxy - 50 ) ;

itoa ( style, str, 10 ) ;


outtextxy ( x, maxy - 20, str ) ;
x = x + 50 ;
}

outtextxy ( 375, 20, "Thick width" ) ;


Chapter 20: Graphics Programming 125
x = 375 ;
for ( style = 0 ; style <= 4 ; style++ )
{
setlinestyle ( style, 0, 3 ) ;
if ( style == 4 )
{
setlinestyle ( 4, 15, 3 ) ;
line ( x, 50, x, maxy - 50 ) ;
}
else
line ( x, 50, x, maxy - 50 ) ;

itoa ( style, str, 10 ) ;


outtextxy ( x, maxy - 20, str ) ;
x = x + 50 ;
}

/* restore line settings */


setlinestyle ( ls.linestyle, ls.upattern, ls.thickness ) ;

getch( ) ;
closegraph( ) ;
restorecrtmode( ) ;
}

Here we have drawn ten lines, five of these have a thickness of 1


pixel, whereas, the other five have a thickness of 3 pixels. In each
set, four lines are of available line styles and one is of user-defined
style. To define our own style for drawing a line we have to build a
16-bit pattern. In this pattern whenever a bit is 1, the corresponding
pixel in the line is drawn in the current drawing color. For example,
a solid line corresponds to a pattern of FFFFh (all pixels drawn),
while a dashed line can correspond to a pattern of 3333h or 0F0Fh.
In our program we have used the pattern with a value 0005h.
126 Let Us

C
After setting the style to solid and thickness to 1 we have saved the
current line settings in a linesettingstype structure by calling the
function getlinesettings( ). This function stores the style, pattern
and thickness in the linesettingstype structure which is defined in
‘graphics.h’ as follows:

struct linesettingstype
{
int linestyle ;
unsigned upattern ;
int thickness ;
};

The settings saved using getlinesettings( ) have been restored once


all lines have been drawn, by calling the setlinestyle( ) function.

Drawing and Filling Images


With the basics over, let us now get into more complicated stuff.
Stuff which would permit us to draw bars and then fill them up with
different patterns. Here is a program which shows how this can be
achieved...

# include "graphics.h"
main( )
{
int gd = DETECT, gm, maxx, maxy, x = 40, y = 40,
fst ;
char str[40] ;
char *pattern[ ] = {
"EMPTY_FILL", "SOLID_FILL",
"LINE_FILL", "LTSLASH_FILL",
"SLASH_FILL",
"BKSLASH_FILL", "LTBKSLASH_FILL",
Chapter 20: Graphics Programming 127
"HATCH_FILL", "XHATCH_FILL",
"INTERLEAVE_FILL",
"WIDE_DOT_FILL",
"CLOSE_DOT_FILL", "USER_FILL"
};

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

maxx = getmaxx( ) ;
maxy = getmaxy( ) ;
rectangle ( 0, 10, maxx, maxy ) ;

setcolor ( WHITE ) ;
outtextxy ( 175, 0, "Pre-defined Fill styles" ) ;

/* display different predefined fill styles */


for ( fst = 0 ; fst < 12 ; fst++ )
{
setfillstyle ( fst, MAGENTA ) ;
bar ( x, y, x + 80, y + 80 ) ;
rectangle ( x, y, x + 80, y + 80 ) ;

itoa ( fst, str, 10 ) ;


outtextxy ( x, y + 100, str ) ;
outtextxy ( x, y + 110, pattern[fst] ) ;

x = x + 150 ;
if ( x > 490 )
{
y = y + 150 ;
x = 40 ;
}
}

getch( ) ;
closegraph( ) ;
128 Let Us

C
restorecrtmode( ) ;
}

In this program we have drawn 12 rectangles and filled them with


the available fill patterns. To achieve this we have first used the
bar( ) function to fill a rectangular area with a pattern and then
enclosed it by calling the rectangle( ) function. Note that the bar( )
function doesn’t draw the boundary but fills the interior with the
current fill pattern and current fill color, whereas the rectangle( )
function draws the rectangle in current color but doesn’t fill the
insides of it.

The following figure shows the fill patterns defined in ‘graphics.h’


along with their enumerated integer values:

Name Value Description

EMPTY_FILL 0 Fill with background color


SOLID_FILL 1 Solid fill
LINE_FILL 2 Fill with -------
LTSLASH_FILL 3 Fill with /////
SLASH_FILL 4 Fill with /////, thick lines
BKSLASH_FILL 5 Fill with \\\\\, thick lines
LTBKSLASH_FILL 6 Fill with \\\\\
HATCH_FILL 7 Light hatch fill
XHATCH_FILL 8 Heavy cross-hatch fill
INTERLEAVE_FILL 9 Interleaving line fill
WIDE_DOT_FILL 10 Widely spaced dot fill
Chapter 20: Graphics Programming 129
CLOSE_DOT_FILL 11 Closely spaced dot fill
USER_FILL 12 User-defined fill pattern

Figure 20.2

If we want, we can save the current fill pattern and current fill color
through statements given below:

struct fillsettingstype old ;


getfillsettings ( &old ) ;

The fillsettingstype structure has been defined in ‘graphics.h’ as


follows:

struct fillsettingstype
{
int pattern ;
int color ;
};

If saved earlier, the fill pattern and the fill color can be restored
through a call to setfillstyle( ):

setfillstyle ( old.pattern, old.color ) ;

Patterns with A Difference


In the previous program we have used the standard fill patterns to
fill the rectangles. Let us now see how to make use of user-defined
fill patterns. To use the predefined fill patterns we had used the
function setfillstyle( ). Likewise, to use the user-defined fill patterns
we need to use the function setfillpattern( ). Its prototype looks like
this...

void far setfillpattern ( char *pattern, int color ) ;


130 Let Us

C
The first parameter is a pointer to a sequence of 8 bytes, with each
byte corresponding to 8 pixels in the pattern. Whenever a bit in a
pattern byte is set to 1, the corresponding pixel will be plotted. The
second parameter specifies the color in which the pattern would be
drawn.

In the following program we have stored 12 patterns in an array and


then drawn rectangles and filled them with these patterns in
magenta color.

# include "graphics.h"
main( )
{
int gd = DETECT, gm, maxx, maxy, x = 40, y = 40,
fst ;
char str[40] ;
char patterns[ ][8] =
{
{ 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55 },
{ 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC,
0xCC },
{ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F,
0x0F },
{ 0x00, 0x10, 0x28, 0x44, 0x28, 0x10, 0x00,
0x00 },
{ 0x00, 0x70, 0x20, 0x27, 0x24, 0x24, 0x07,
0x00 },
{ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
0x00 },
{ 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00,
0x00 },
{ 0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,
0x00 },
Chapter 20: Graphics Programming 131
{ 0x00, 0x00, 0x22, 0x08, 0x00, 0x22, 0x1C,
0x00 },
{ 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x3C, 0x7E,
0xFF },
{ 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00,
0x00 },
{ 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42,
0x00 }
};

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

maxx = getmaxx( ) ;
maxy = getmaxy( ) ;
rectangle ( 0, 10, maxx, maxy ) ;

setcolor ( WHITE ) ;
outtextxy ( 175, 0, "User-defined Fill styles" ) ;

/* display different user-defined fill styles */


for ( fst = 0 ; fst < 12 ; fst++ )
{
setfillpattern ( &patterns[fst][0], MAGENTA ) ;
bar ( x, y, x + 80, y + 80 ) ;
rectangle ( x, y, x + 80, y + 80 ) ;

itoa ( fst, str, 10 ) ;


outtextxy ( x, y + 100, str ) ;

x = x + 150 ;
if ( x > 490 )
{
y = y + 150 ;
x = 40 ;
}
}
132 Let Us

C
getch( ) ;
closegraph( ) ;
restorecrtmode( ) ;
}

Why Use A bar( )?


In the last program we first filled a pattern in a rectangular area by
calling the bar( ) function and then enclosed it in a rectangle by
calling the rectangle( ) function. Is this really necessary? Can we
not combine the operations? We can, by using the floodfill( )
function. This function needs three parameters: the x and y
coordinates of a point and color. The function starts to fill the screen
from the specified point till it encounters a closed boundary of the
specified color.

In the following program we have drawn three rectangles and filled


the first two with a standard pattern and the last with a user-defined
pattern. While building the first rectangle we have drawn the
rectangle through the rectangle( ) function (instead of bar( )).

Next we have set the fill pattern and fill color by calling the function
setfillstyle( ). Then using this fill style and color we have filled the
rectangle using the floodfill( ) function. The other two rectangles
and their patterns have been constructed as in the last program.

# include "graphics.h"
main( )
{
int gd = DETECT, gm, maxx, maxy ;
char pattern[ ] = { 0x00, 0x70, 0x20, 0x27, 0x24,
0x24, 0x07, 0x00 } ;

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;


Chapter 20: Graphics Programming 133
maxx = getmaxx( ) ;
maxy = getmaxy( ) ;
rectangle ( 0, 10, maxx, maxy ) ;

setcolor ( WHITE ) ;
outtextxy ( 175, 0, "color shapes and patterns" ) ;

setcolor ( WHITE ) ;
rectangle ( 80, 150, 180, 250 ) ;

setfillstyle ( SOLID_FILL, RED ) ;


floodfill ( 81, 151, WHITE ) ;
outtextxy ( 100, 300, "floodfill" ) ;

setfillstyle ( BKSLASH_FILL, RED ) ;


bar ( 250, 150, 350, 250 ) ;
rectangle ( 250, 150, 350, 250 ) ;
outtextxy ( 250, 300, "setfillstyle" ) ;
outtextxy ( 230, 320, "(using std. pattern)" ) ;

setfillpattern ( pattern, RED ) ;


bar ( 420, 150, 520, 250 ) ;
rectangle ( 420, 150, 520, 250 ) ;
outtextxy ( 420, 300, "setfillpattern" ) ;
outtextxy ( 420, 320, "(using user-defined)" ) ;

getch( ) ;
closegraph( ) ;
restorecrtmode( ) ;
}

Note that while using the floodfill( ) function one must make sure
that the right color is specified or else the function will seek a
boundary you don’t want.
134 Let Us

Filling Regular and Non-Regular Shapes


To fill regular shapes like polygons and ellipses there exist standard
library functions like fillpoly( ) and fillellipse( ). These functions
fill the polygon (or ellipse) with the current fill style and current fill
color that may have been set up by calling setfillstyle( ) or
setfillpattern( ). However, if we are to fill non-regular shapes like
the intersecting area between an overlapping triangle and circle, we
have to once again take recourse to the floodfill( ) function.

The following program draws an ellipse and a triangle and fills them
by calling the fillellipse( ) and fillpoly( ) functions. Next it draws
an overlapping triangle and circle and fills the intersecting and non-
intersecting areas by repeatedly calling the floodfill( ) function. The
parameters passed to fillellipse( ) include coordinates of the center,
x-radius and y-radius. The parameters passed to drawpoly( ) and
fillpoly( ) are same—the number of points used to build the
polygon and the base address of the array containing the coordinates
of these points.

# include "graphics.h"
main( )
{
int gd = DETECT, gm, maxx, maxy, x = 600, y =
450 ;
int array[ ] = { 350, 180, 400, 80, 450, 180, 350,
180 } ;

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

maxx = getmaxx( ) ;
maxy = getmaxy( ) ;
Chapter 20: Graphics Programming 135
rectangle ( 0, 20, maxx, maxy ) ;
setcolor ( WHITE ) ;
outtextxy ( 150, 10, "Fill Figures using different
functions" ) ;
ellipse ( x / 4, 10 * y / 35, 0, 360, 100, 50 ) ;

outtextxy ( x / 4 - textwidth ( "Ellipse" ) / 2, 10 * y /


24 + 10, "Ellipse" ) ;
setfillstyle ( SOLID_FILL, RED ) ;
fillellipse ( x / 4, 10 * y / 35, 100, 50 ) ;

drawpoly ( 4, array ) ;
fillpoly ( 4, array ) ;
outtextxy ( 370, 200, "Polygon" ) ;

circle ( 280, 320, 70 ) ;


line ( 190, 350, 370, 350 ) ;
moveto ( 190, 350 ) ;
linerel ( 100, -120 ) ;
linerel ( 80, 120 ) ;
outtextxy ( 210, 410, "User-defined figure" ) ;

floodfill ( 280, 320, WHITE ) ;

setfillstyle ( SOLID_FILL, BLUE ) ;


floodfill ( 192, 349, WHITE ) ;
floodfill ( 368, 349, WHITE ) ;
floodfill ( 290, 231, WHITE ) ;

setfillstyle ( SOLID_FILL, DARKGRAY ) ;


floodfill ( 240, 289, WHITE ) ;
floodfill ( 330, 289, WHITE ) ;
floodfill ( 280, 351, WHITE ) ;

getch( ) ;
closegraph( ) ;
restorecrtmode( ) ;
136 Let Us

C
}

Of Palettes and Colors


In Chapter 15 we saw how VGA generates colors. Let us now put
that theory into practice. Here is a program which does this...

#include "graphics.h"
#include "stdlib.h"
main( )
{
int gd = DETECT, gm, i, j, x, y, color, startcolor,
height, width ;
struct palettetype palette ;
struct viewporttype vp ;

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

getpalette ( &palette ) ;

rectangle ( 0, 20, 639, 479 ) ;


outtextxy ( 200, 10, "Palette demonstration" ) ;

getviewsettings ( &vp ) ;
width = ( vp.right - vp.left ) / 16 ;
height = ( vp.bottom - vp.top - 20 ) / 16 ;

x=0;
y = 20 ;
Chapter 20: Graphics Programming 137
startcolor = 0 ;

for ( j = 0 ; j <= 15 ; j++ )


{
color = startcolor ;
for ( i = 0 ; i <= 15 ; i++ )
{
setfillstyle ( SOLID_FILL, color++ ) ;
bar ( x, y, x + width, y + height ) ;
x = x + width + 1 ;
}
startcolor++ ;
x=0;
y += height + 1 ;
}
getch( ) ;

while ( !kbhit( ) )
setpalette ( random ( 16 ), random ( 65 ) ) ;

setallpalette ( &palette ) ;

getch( ) ;
closegraph( ) ;
restorecrtmode( ) ;
}

To begin with, we have determined the drawing area available to us


by calling the function getviewsettings( ). This function fills the
elements of the structure viewporttype with the coordinates of the
current viewport (drawing area). Using these coordinates we have
calculated the height and width of the rectangles that we propose to
draw on the screen. Next, we have drawn 16 rows and 16 columns
of rectangles using a pair of for loops. The rectangles have been
drawn using the bar( ) function which uses the fill pattern and fill
color as set by a call to the function setfillstyle( ). To ensure that the
first rectangle in each row has a different color we have used the
138 Let Us

C
variables color and startcolor. Once the screen is filled with 256
rectangles, using the setpalette( ) function we have changed the
color values. Which color number gets changed to what color value
is decided at random since we have generated both the numbers
using the random( ) function. The colors keep getting changed in a
while loop till we do not interrupt the process by pressing a key.
Once we hit a key the control goes outside the while loop,
whereupon we change all the colors to their original values (which
we have earlier saved in the palettetype structure by calling
getpalette( ) function) through the function setallpalette( ).

Note that we have not redrawn any of the rectangles. We have only
changed the color values in the palette. By doing so, all rectangles
on the screen which had the earlier color values are changed to
reflect the new color values in the palette.

Outputting Text
So far we have outputted text using the function outtextxy( ).
However, there is more to outputting text than what we have
covered. The following program would put the whole issue in the
right perspective.

# include "graphics.h"
main( )
{
int gd = DETECT, gm, x = 10, y, i, j ;
char str[ ] = "Fonts" ;
char *demo[ ] = {
"Default Font Demonstration" ,
Triplex Font Demonstration",
"Small Font Demonstration",
"Sansserif Font Demonstration",
"Gothic Font Demonstration",
Chapter 20: Graphics Programming 139
"Script Font Demonstration",
"Simplex Font Demonstration",
"Triplex Script Font Demonstration",
"Complex Font Demonstration",
"European Font Demonstration",
"Bold Font Demonstration"
};

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

setcolor ( WHITE ) ;

for ( i = 0 ; i <= 10 ; i++ )


{
rectangle ( 0, 20, 639, 479 ) ;
settextstyle ( 0, 0, 1 ) ;
outtextxy ( 150, 10, demo[i] ) ;

y = 30 ;
for ( j = 1 ; j <= 4 ; j++ )
{
settextstyle ( i, HORIZ_DIR, j ) ;
outtextxy ( 10, y, str ) ;
y += ( textheight ( str ) + 10 ) ;
}

settextstyle ( i, VERT_DIR, 0 ) ;
setusercharsize ( 2, 1, 3, 2 ) ;
outtextxy ( 10, y, str ) ;

getch( ) ;
clearviewport( ) ;
}

closegraph( ) ;
restorecrtmode( ) ;
}
140 Let Us

In the earlier programs when we used the outtextxy( ) function the


text got printed using a default font, direction and point size. The
function settextstyle( ) enables us to change the font, direction and
character size. Turbo C provides us with ten fonts in addition to the
default font. These are Triplex, Small, Sans serif, Gothic, Script,
Simplex, Triplex Script, Complex, European and Bold. We can
output the text either horizontally (default) or vertically. And we can
choose any one of the 10 point sizes of characters. For point size 1
each character is displayed in a 8 x 8 pixel rectangle. If the point
size is 2 then the character is displayed using 16 x 16 pixel
rectangle and so on.

The general form of settextstyle( ) function is given below,

settextstyle ( font, direction, point size ) ;

In our program we have kept the direction of output horizontal and


changed the font and the point size through a pair of loops. To
determine the position at which the text is to be outputted each time
through the loop, we have used the function textheight( ) which
determines the height of a string as per the current font. Instead of
using all the 10 point sizes we have run the inner loop only four
times do demonstrate four point sizes.

Once outside the inner for loop we have used the


setusercharsize( ) function to use a user-defined point size. This
function gives you finer control over the size of the text. Its
prototype looks like this...

setusercharsize ( int multx, int divx, int multy, int divy )


;

The parameters passed to this function help us to specify factors by


which the width and height are scaled. The default width is scaled
Chapter 20: Graphics Programming 141
by multx : divx, and the default height is scaled by multy : divy.
For example, to make the text twice as wide and 50% taller than the
default, we have set,

multx = 2 ; divx = 1 ;
multy = 3 ; divy = 2 ;

Justifying Text
Not only can we control the font, direction and point size of the text
that is drawn on the screen in the graphics mode, we can also
exercise control over its orientation (justification) with respect to
C.P. Justification of text simply means positioning it with reference
to C.P. Remember that each character occupies a block of pixels.
Using the settextjustify( ) function we can align this block
horizontally or vertically such that C.P. is at the top, center or
bottom of this block (for vertical justification) and to the left, center
or right of this block (for horizontal justification). The default
justification settings are LEFT_TEXT (for horizontal) and
TOP_TEXT (for vertical). This means the block of character(s)
would be to the left of C.P. and below it. The other settings and their
values as enumerated in the file ‘graphics.h’ are shown in Figure
20.3.

Name Value Description

LEFT_TEXT 0 Horizontal
CENTRE_TEXT 1 Horizontal and Vertical
RIGHT_TEXT 2 Horizontal
BOTTOM_TEXT 0 Vertical
142 Let Us

C
TOP_TEXT 2 Vertical

Figure 20.3
The following program shows all possible combinations of vertical
and horizontal justification for displaying a string of text.

#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
void cross ( int x, int y ) ;

/* horizontal text justification settings */


char *horizontal[ ] = {
"LEFT_TEXT",
"CENTER_TEXT",
"RIGHT_TEXT"
};

/* vertical text justification settings */


char *vertical[ ] = {
"BOTTOM_TEXT",
"CENTER_TEXT",
"TOP_TEXT"
};

main( )
{
int gd = DETECT, gm ;
int midx, midy, i, j ;
char msg[80] = "Hello, Good Morning" ;
char msg1[80], msg2[80] ;
Chapter 20: Graphics Programming 143
initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

midx = getmaxx( ) / 2 ;
midy = getmaxy( ) / 2 ;

/* loop through text justifications */


for ( i = LEFT_TEXT ; i <= RIGHT_TEXT ; i++ )
{
for ( j = BOTTOM_TEXT ; j <= TOP_TEXT ; j++ )
{
cleardevice( ) ;
cross ( midx, midy ) ; /* create cross hairs on
the screen */
settextjustify ( i, j ) ; /* set the text
justification */
outtextxy ( midx, midy, msg ) ; /* output the
message */
settextjustify ( LEFT_TEXT, TOP_TEXT ) ;
outtextxy ( 100, 350, "HORIZONTAL
JUSTIFICATION = " );
sprintf ( msg1, "%s", horizontal[i] ) ;
outtextxy ( 320, 350, msg1 ) ;
outtextxy ( 100, 400, "VERTICAL
JUSTIFICATION = " ) ;
sprintf ( msg2, "%s", vertical[j] ) ;
outtextxy ( 320, 400, msg2 ) ;

getch( ) ;
}
}

closegraph( ) ;
restorecrtmode( ) ;
}

/* draw a "+" at (x, y) */


void cross ( int x, int y )
144 Let Us

C
{
line ( x - 20, y, x + 20, y ) ;
line ( x, y - 20, x, y + 20 ) ;
}

A Bit of Animation
Drawing images is all right, what if we want to move them on the
screen? This can be achieved through two functions getimage( )
and putimage( ). The former reads any specified image from the
screen, and the latter places it at a predetermined subsequent
location, giving the illusion of movement. The following program
shows how these functions can be used in tandem to move a ball on
the screen.

# include "graphics.h"
# include "alloc.h"
main( )
{
int gd = DETECT, gm, area, x = 25, y = 25, ch,
xdirn = 1, ydirn = 1 ;
int maxx, maxy ;
char *buff ;

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

setcolor ( WHITE ) ;
setfillstyle ( SOLID_FILL, RED ) ;
circle ( 50, 50, 25 ) ;
floodfill ( 50, 50, WHITE ) ;

area = imagesize ( 25, 25, 75, 75 ) ;


buff = malloc ( area ) ;
getimage ( 25, 25, 75, 75, buff ) ;
Chapter 20: Graphics Programming 145
maxx = getmaxx( ) ;
maxy = getmaxy( ) ;
rectangle ( 0, 20, maxx, maxy ) ;
outtextxy ( 250, 10, “Animation” ) ;

while ( 1 )
{
if ( kbhit( ) )
{
ch = getch( ) ;

/* if ENTER is hit reverse the direction of


movement */
if ( ch =='\r' )
{
xdirn *= -1 ;
ydirn *= -1 ;
}
else
{
if ( ch == 27 )
break ;
}
}

putimage ( x, y, buff, XOR_PUT ) ;


delay ( 0 ) ;
x = x + ( xdirn * 5 ) ;
y = y + ( ydirn * 2 ) ;
putimage ( x, y, buff, XOR_PUT ) ;

/* check if ball touches horizontal boundaries */


if ( x > maxx - 50 || x < 0 )
{
sound ( 50 ) ;
delay ( 10 ) ;
146 Let Us

C
nosound( ) ;
xdirn *= -1 ;
}

/* check if ball touches vertical boundaries */


if ( y > maxy - 50 || y < 20 )
{
sound ( 50 ) ;
delay ( 10 ) ;
nosound( ) ;
ydirn *= -1 ;
}
}

getch( ) ;
closegraph( ) ;
restorecrtmode( ) ;
}

To begin with, we have drawn a circle and filled it with a


SOLID_FILL pattern in RED color. After this we wish to capture
the image of this filled circle in memory. For this we need to know
how many bytes would be required to store the image in memory.
We get this by calling imagesize( ), which returns the bytes
required to store an image in memory. The parameters passed to
imagesize( ) are the top-left and bottom-right corners of the
rectangle enclosing the circle (or the image to be stored).

The next step is to allocate memory, which is done by calling the


function malloc( ). The pointer returned by malloc( ) is stored in
the variable buff.

Then the function getimage( ) is called which requires five


parameters, the first four being the coordinates of the top-left and
bottom-right corners of the block, and the last being the address of
Chapter 20: Graphics Programming 147
the memory location from where getimage( ) will start storing the
image.

The function putimage( ) is the other side of the coin. It requires


four parameters—the first two are the coordinates of the top-left
corner of the block, the third is the address in memory from where
the image is to be retrieved, and the fourth specifies how the image
should be displayed.

Having picked up the image in memory we should now erase the


image from its original place and place it at a new location. This
cycle should be repeated several times so that we get the impression
of a ball moving on the screen. To implement this cycle of erasing-
drawing-erasing we have employed a while loop. Every time
through the loop, the first call to putimage( ) erases the ball and the
second call draws it at a new position.

How come the same putimage( ) can sometimes draw the image
and at other times erase it? The value of the fourth argument
supplied to putimage( ) decides whether it would draw or erase.
The value of this argument and its significance is given in the Figure
20.4.

Argument Status of image Resultant image on


passed screen

Memory Screen
XOR_PUT Present Present Erased
XOR_PUT Present Absent Drawn
OR_PUT Present Present Superimposed
OR_PUT Present Absent Superimposed
COPY_PUT Present Present Replaced
COPY_PUT Present Absent Replaced
148 Let Us

Figure 20.4

The variables xdirn and ydirn are used to change the trajectory of
movement of ball. Anytime enter key is hit the direction in which the
ball is traversing is reversed. Anytime the ball hits the boundary, the
sound( ) function is used to activate the speaker followed by
nosound( ) to stop the sound. delay( ) serves the purpose of letting
the speaker beep for sometime before it is shut out by nosound( ).

System Metrics
If we draw a line, by default it is drawn as a solid line in white color.
If we display text then by default it is drawn in DEFAULT_FONT,
horizontally with each character built out of a matrix of 8 x 8 pixels.
The text displayed, by default, is justified to the left horizontally and
to the top vertically. Likewise, if we draw a rectangle using a bar( )
function, it is filled with a default pattern in default color. The point
that I am trying to make is there are a lot of default values that the
graphics library functions assume. Can we not find all these default
settings through a program? We can, and that too in as simple a
manner as shown below:

#include <dos.h>
#include <math.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include “graphics.h”

char *fonts[ ] = {
"DefaultFont", "TriplexFont", "SmallFont",
Chapter 20: Graphics Programming 149
"SansSerifFont", "GothicFont",
"ScriptFont",
"SimplexFont", "TriplexScriptFont",
"ComplexFont", "EuropeanFont",
"BoldFont"
};

char *linestyles[ ] = {
"SolidLn", "DottedLn", "CenterLn",
"DashedLn", "UserBitLn"
};

char *fillstyles[ ] = {
"EmptyFill", "SolidFill", "LineFill",
"LtSlashFill", "SlashFill", "BkSlashFill",
"LtBkSlashFill", "HatchFill", "XHatchFill",
"InterleaveFill", "WideDotFill",
"CloseDotFill"
};

char *textdirect[ ] = {
"HorizDir", "VertDir"s
};

char *horizontal[ ] = {
"LeftText", "CenterText", "RightText"
};

char *vertical[ ] = {
"BottomText", "CenterText", "TopText"
};

struct pts
{
int x, y ;
};
150 Let Us

C
int gprintf ( int *xloc, int *yloc, char *fmt, ... ) ;

main( )
{
struct viewporttype viewinfo ;
struct linesettingstype lineinfo ;
struct fillsettingstype fillinfo ;
struct textsettingstype textinfo ;
struct palettetype palette, far *pal ;

float aspectratio ;
int maxx, maxy, maxcolors, errorcode, xasp, yasp,
low, high ;

char *driver, *mode ;


int x, y, gd = DETECT, gm, i ;

initgraph ( &gd, &gm, "c:\\tc\\bgi" ) ;

rectangle ( 0, 20, 639, 479 ) ;


outtextxy ( 200, 10, "system metrics" ) ;

getviewsettings ( &viewinfo ) ;
getlinesettings ( &lineinfo ) ;
getfillsettings ( &fillinfo ) ;
gettextsettings ( &textinfo ) ;
getpalette ( &palette ) ;
getaspectratio ( &xasp, &yasp ) ;
aspectratio = xasp / yasp ;
driver = getdrivername( ) ;
mode = getmodename ( gm ) ;
getmoderange ( gd, &low, &high ) ;
gm = getgraphmode( ) ;
maxcolors = getmaxcolor( ) + 1 ;
Chapter 20: Graphics Programming 151
pal = getdefaultpalette( ) ;

x = 20 ;
y = 30 ;

settextjustify ( LEFT_TEXT, TOP_TEXT ) ;

gprintf ( &x, &y, "Graphics device: %-20s (%d)",


driver, gd ) ;
gprintf ( &x, &y, "Graphics mode: %-20s (%d)",
mode, gm ) ;
gprintf ( &x, &y, "Max Mode Number: %d",
getmaxmode( ) ) ; gprintf ( &x, &y, "Mode Range is:
%d to %d", low, high ) ;
gprintf ( &x, &y, "Screen resolution: ( 0, 0, %d, %d )
", getmaxx( ),
getmaxy( ) ) ;
gprintf ( &x, &y, "Current view port: ( %d, %d, %d,
%d )",iewinfo.left,
viewinfo.top, viewinfo.right, viewinfo.bottom )
;
gprintf ( &x, &y, "Clipping: %s", viewinfo.clip ? "ON"
: "OFF" ) ;
gprintf ( &x, &y, "sAspect Ratio: %f", aspectratio ) ;
gprintf ( &x, &y, "Current position: ( %d, %d )",
get( ), gety( ) ) ;
gprintf ( &x, &y, "Colors available: %d", maxcolors )
;
gprintf ( &x, &y, "Current color: %d", getcolor( ) ) ;
gprintf( &x, &y, "Current BkColor: %d", getbkcolor( )
);
gprintf ( &x, &y, "Line style: %s", linestyles[
lineinfo.linestyle ] ) ;
gprintf ( &x, &y, "Line thickness: %d",
lineinfo.thickness ) ;
gprintf ( &x, &y, "Current fill style: %s", fillstyles[
fillinfo.pattern ] ) ;
152 Let Us

C
gprintf ( &x, &y, "Current fill color: %d", fillinfo.color
);
gprintf ( &x, &y, "Current font: %s", fonts[
textinfo.font ] ) ;
gprintf ( &x, &y, "Text direction: %s", textdirect[
textinfo.direction ] ) ;
gprintf ( &x, &y, "Character size: %d",
textinfo.charsize ) ;
gprintf ( &x, &y, "Horizontal justify: %s", horizontal[
textinfo.horiz ] ) ;
gprintf ( &x, &y, "Vertical justify: %s", vertical[
textinfo.vert ] ) ;
gprintf ( &x, &y, "Palette size: %d", getpalettesize( )
);

for ( i = 0 ; i <= 15 ; i++ )


gprintf ( &x, &y, "value of color[%d] = %d", i, pal
-> colors[i] ) ;

getch( ) ;
closegraph( ) ;
restorecrtmode( ) ;
}

int gprintf ( int *x, int *y, char *fmt, ... )


{
va_list ptr ;
char str[140] ;

va_start ( ptr, fmt ) ;


vsprintf ( str, fmt, ptr ) ;
outtextxy ( *x, *y, str ) ;
*y = *y + textheight ( "H" ) + 2 ;
va_end ( ptr ) ;
Chapter 20: Graphics Programming 153
}

The purpose of each standard library graphics function used in this


program to extract the default values of various parameters is as
follows:

Function Description

getviewsettings( ) Gets information about the current


viewport.

getlinesettings( ) Gets the current line style, pattern and


thickness.

getfillsettings( ) Gets information about current fill pattern


and color.

gettextsettings( ) Gets information about the current


graphic text font.

getpalette( ) Gets information about the current


palette’s size and colors.

getaspectratio( ) Gets the aspect-ratio values in x and y


aspect factors.

getdrivername( ) Returns a pointer to the name of the


current graphics driver.

getmodename( ) Returns the name of the specified


graphics mode.

getmoderange( ) Gets the range of modes for a given


graphics driver.

getgraphmode( ) Returns the current graphics mode.

getmaxcolor( ) Returns maximum color value.


154 Let Us

C
getdefaultpalette( ) Gets information about the palette initi-
alised by the driver during initgraph( ).

getmaxmode( ) Returns maximum graphics mode


number for the current driver.

getmaxx( ) Returns maximum x screen coordinate.

getmaxy( ) Returns maximum y screen coordinate.

getx( ) Returns the x coordinate of the current


graphics position.

gety( ) Returns the y coordinate of the current


graphics position.

getcolor( ) Returns the current drawing color.

getbkcolor( ) Returns the current background color.

getpalettesize( ) Returns the size of the palette.

In this program the text has been outputted on the screen using the
user defined function gprintf( ). This function works similar to
printf( ) except that it is capable of displaying output in graphics
mode. The advantage of this function is that it can collect a variable
number of arguments. Each time it is called we have passed to it the
position where the text is to be outputted on the screen, the format
string and a list of variables whose values are to be printed. The
macros va_start, va_list, va_end are defined in the file ‘stdarg.h’.
Out of these, the va_start macro is used to set up a pointer to the
format string. Next, the string to be outputted is written to the string
str[ ] by calling the vsprintf( ) function. The contents of the string
are then displayed on the screen using the usual outtextxy( )
function.
Chapter 20: Graphics Programming 155
Exercise
[A] State True or False:

(a) There are no keywords in C to carry out any drawing activity.


(b) The functions provided in graphics library would very from one
compiler to another.
(c) If we were to carry out drawing under Unix we would have to
adapt a different strategy than the one mentioned in this
chapter.
(d) Any shape drawn on the screen can be animated using the
getimage( ) & putimage( ) functions.
(e) Unless we call initgraph( ) we cannot draw anything on the
screen.
(f) Purpose of initgraph( ) is to load suitable graphics driver.
(g) It is mandatory to call closegraph( ) at the end of any graphics
program.
(h) Using printf( ) we can write text in a suitable font in graphics
mode.
(i) restorecrtmode( ) restores the pre-initgraph( ) display mode.
(j) Turbo C’s graphics library does not incorporate 3D
functionality.
(k) For the character written on the screen in graphics mode there
exists an ASCII value and a color Byte in VDU memory.

[B] Answer the following:

(a) Write a program to draw a human shape on the screen and


animate it in any of the four directions using the arrow keys.
(b) Draw a cube on the screen with three of its faces visible.
Ensure that each face is drawn in a different color.
(c) Write a program to draw the following figure. Each closed
region in the figure should be filled with a different color.
156 Let Us

C
(d) Write a program to draw a line interactively. Interactive line
drawing involves the following:
− Creating a plus shaped cursor.
− Managing the movement of the cursor using arrow keys,
Pgup, PgDn, Home and End.
− On positioning the cursor at a suitable place, if enter is hit
the point where the cursor was positioned should be treated
as the starting point of the line.
− Now the cursor should disappear and as arrow keys, PgUp,
PgDn, Home or End are hit the line drawing should begin.
− For every key hit the earlier line should get erased and a
new one should get drawn.
− Line should be made permanent when Enter key is hit.
(e) Write a function to consttruct a button similar to the one that
you often see in Windows. To this function you should pass
size of the button, position of the button, color of the button,
the text to be displayed on it and the font of the text.

You might also like