Graphics Programming

  • November 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Graphics Programming as PDF for free.

More details

  • Words: 8,370
  • Pages: 42
20

Graphics Programming 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

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.

Let Us

120 C

Function

Meaning

putpixel ( x1, y1 ) ; line ( x1, y1, x2,. y2 ) ;

Lits the pixel at ( x1, y1 ) Draws a line from ( x1, y1 ) to ( x2, y2 ) Draws a circle with center ( xc, yc ) and radius rad Draws a rectangle with ( x1, y1) and ( x2, y2 ) as corners Draws an ellipse with ( xc, yc ) 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

circle ( xc, yc, rad ) ; rectangle ( x1, y1, x2, y2 ) ; ellipse ( xc, yc, start, end, xrad, yrad ) ;

arc ( xc, yc, start, end, rad );

Draws an arc with ( xc, yc ) as 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 #include <stdlib.h> #include <stdio.h> #include 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 userdefined. The third parameter specifies the line thickness. The various line styles have been enumerated in ‘graphics.h’ as under: 0 1 2 3 4

Solid Line Dotted Line Center Line (alternating dashes and dots) Dashed Line 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( )

Let Us

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

Let Us

128 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 SOLID_FILL

0 1

Fill with background color Solid fill

LINE_FILL LTSLASH_FILL

2 3

Fill with ------Fill with /////

SLASH_FILL BKSLASH_FILL

4 5

Fill with /////, thick lines Fill with \\\\\, thick lines

LTBKSLASH_FILL HATCH_FILL

6 7

Fill with \\\\\ Light hatch fill

XHATCH_FILL INTERLEAVE_FILL

8 9

Heavy cross-hatch fill Interleaving line fill

WIDE_DOT_FILL

10

Widely spaced dot fill

Chapter 20: Graphics Programming CLOSE_DOT_FILL

11

Closely spaced dot fill

USER_FILL

12

User-defined fill pattern

129

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 { 0x00 }, { 0xFF }, { 0x00 }, { 0x00 } };

131

0x00, 0x00, 0x22, 0x08, 0x00, 0x22, 0x1C, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x3C, 0x7E, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42,

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

C

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 nonintersecting 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

C 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 CENTRE_TEXT

0 1

Horizontal Horizontal and Vertical

RIGHT_TEXT BOTTOM_TEXT

2 0

Horizontal Vertical

Let Us

142 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 #include <stdlib.h> #include <stdio.h> #include 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 ) ;

Let Us

146 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 erasingdrawing-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 passed

Status of image

Resultant image on screen

Memory

Screen

XOR_PUT

Present

Present

Erased

XOR_PUT OR_PUT

Present Present

Absent Present

Drawn Superimposed

OR_PUT COPY_PUT

Present Present

Absent Present

Superimposed Replaced

COPY_PUT

Present

Absent

Replaced

Let Us

148 C 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 #include #include #include #include #include #include

<dos.h> <math.h> <stdio.h> <stdlib.h> <stdarg.h> “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 ; };

Let Us

150 C

int gprintf ( int *xloc, int *yloc, char *fmt, ... ) ; main( ) { struct struct struct struct struct

viewporttype viewinfo ; linesettingstype lineinfo ; fillsettingstype fillinfo ; textsettingstype textinfo ; 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 viewport.

getlinesettings( )

Gets the current line style, pattern and thickness.

getfillsettings( )

Gets information about current fill pattern and color.

gettextsettings( )

Gets information about graphic text font.

the

current

getpalette( )

Gets information about palette’s size and colors.

the

current

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.

the

current

Let Us

154 C getdefaultpalette( )

Gets information about the palette initialised by the driver during initgraph( ).

getmaxmode( )

Returns maximum graphics 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.

mode

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.

Let Us

156 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.

Related Documents

Graphics Programming
November 2019 11
Graphics
November 2019 36
Graphics
May 2020 21
Image & Graphics
June 2020 11