0% found this document useful (0 votes)
3 views39 pages

Graphics Programming

This document provides an overview of graphics programming in C, covering essential concepts such as drawing shapes, using graphics functions, and managing graphics modes. It introduces standard library functions for drawing lines, shapes, and text, as well as techniques for creating stylish lines and animations. The content is aimed at helping readers understand and utilize graphics capabilities effectively in their programs.

Uploaded by

bondhumilanclub
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views39 pages

Graphics Programming

This document provides an overview of graphics programming in C, covering essential concepts such as drawing shapes, using graphics functions, and managing graphics modes. It introduces standard library functions for drawing lines, shapes, and text, as well as techniques for creating stylish lines and animations. The content is aimed at helping readers understand and utilize graphics capabilities effectively in their programs.

Uploaded by

bondhumilanclub
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd

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
628 Let Us C

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 ) ;
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" ) ;
Chapter 20: Graphics Programming 629
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
[Link]. 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.

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.
630 Let Us C
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 [Link] 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 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
Chapter 20: Graphics Programming 631
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.
632 Let Us C

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
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
Chapter 20: Graphics Programming 633
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. */


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 )" ) ;


634 Let Us C
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 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.
Chapter 20: Graphics Programming 635
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( )
{
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 ) ;
636 Let Us C

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" ) ;

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 ( [Link], [Link], [Link] ) ;

getch( ) ;
Chapter 20: Graphics Programming 637
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.

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
638 Let Us C
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",
"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 )
Chapter 20: Graphics Programming 639
{
y = y + 150 ;
x = 40 ;
}
}

getch( ) ;
closegraph( ) ;
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
640 Let Us C

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
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 ( [Link], [Link] ) ;

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
Chapter 20: Graphics Programming 641
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 ) ;

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 },
{ 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 }
};
642 Let Us C
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 ;
}
}

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( )
Chapter 20: Graphics Programming 643
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" ) ;

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" ) ;
644 Let Us C
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.

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
Chapter 20: Graphics Programming 645
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( ) ;
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 ) ;


646 Let Us C

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( ) ;
}

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 ) ;
Chapter 20: Graphics Programming 647
rectangle ( 0, 20, 639, 479 ) ;
outtextxy ( 200, 10, "Palette demonstration" ) ;

getviewsettings ( &vp ) ;
width = ( [Link] - [Link] ) / 16 ;
height = ( [Link] - [Link] - 20 ) / 16 ;

x=0;
y = 20 ;
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
648 Let Us C
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 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[ ] = {
Chapter 20: Graphics Programming 649
"Default Font Demonstration" ,
Triplex Font Demonstration",
"Small Font Demonstration",
"Sansserif Font Demonstration",
"Gothic Font Demonstration",
"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( ) ;
650 Let Us C
restorecrtmode( ) ;
}

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 651
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
652 Let Us C

BOTTOM_TEXT 0 Vertical
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] ;

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

midx = getmaxx( ) / 2 ;
Chapter 20: Graphics Programming 653
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 )
{
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
654 Let Us C
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 ) ;

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 ;
Chapter 20: Graphics Programming 655
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 ) ;
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( ) ;
}
656 Let Us C
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
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.
Chapter 20: Graphics Programming 657
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

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
658 Let Us C
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",
"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[ ] = {
Chapter 20: Graphics Programming 659
"LeftText", "CenterText", "RightText"
};

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

struct pts
{
int x, y ;
};

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 ;
660 Let Us C
driver = getdrivername( ) ;
mode = getmodename ( gm ) ;
getmoderange ( gd, &low, &high ) ;
gm = getgraphmode( ) ;
maxcolors = getmaxcolor( ) + 1 ;
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 )",[Link],
[Link], [Link], [Link] ) ;
gprintf ( &x, &y, "Clipping: %s", [Link] ? "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[ [Link] ] ) ;
gprintf ( &x, &y, "Line thickness: %d", [Link] ) ;
gprintf ( &x, &y, "Current fill style: %s", fillstyles[ [Link] ] ) ;
gprintf ( &x, &y, "Current fill color: %d", [Link] ) ;
gprintf ( &x, &y, "Current font: %s", fonts[ [Link] ] ) ;
gprintf ( &x, &y, "Text direction: %s", textdirect[ [Link] ] ) ;
gprintf ( &x, &y, "Character size: %d", [Link] ) ;
gprintf ( &x, &y, "Horizontal justify: %s", horizontal[ [Link] ] ) ;
gprintf ( &x, &y, "Vertical justify: %s", vertical[ [Link] ] ) ;
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] ) ;
Chapter 20: Graphics Programming 661
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 ) ;
}

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.
662 Let Us C

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.

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.


Chapter 20: Graphics Programming 663
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.

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.
664 Let Us C
(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.

(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.
Chapter 20: Graphics Programming 665
 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