Graphics subsystem

Graphics subsystem is a complex software and hardware stack in our personal computer. Clear understanding of this subsystem is often necessary before starting graphics programming. A VGA capable graphics card is a second processor after CPU. Its job is to convert image frame from frame buffer address 0xA0000 to analog VGA signal frames. It is basically a digital to analog converter. It converts 2D pixel array bytes to pixel scan frame and feeds this VGA analog signal to output monitor. It can work in character mode. Character mode works in frame address 0xB8000. Host driver transfers 80x25 character matrix and VGA card puts font image bitmap for each characters. Output of this frame looks character console with 80 characters columns in each lines and total 25 lines.

VGA card has I/O registers and memory mapped frame buffer. Host side graphics program or graphics library can access I/O registers to control many operations. Mode switching and accessing cursor and mouse pointer are the most often used control operations. Frame buffer hardware memory is mapped from 0xA0000 to 0xBFFFF physical address. This is graphics card memory shared between host CPU. Graphics card operates in two modes. Text mode is the simplest one. It consists of a character matrix of 80x25. One character in VGA buffer is represented by an ASCII byte and next byte contains 4bit foreground and 4bit background color. So total 80x25x2 bytes are consumed from 0xB8000.

Graphic mode is different form console mode. It has 640x480 pixels and each pixel consists of 16 colors. 16 colors can be represented by 4bits. VGA splits color planes in 4 different planes. Host driver selects one plane at a time and sets respective bits. It has to access all 4 planes and has to set all respective color bits to complete one pixel operation. VGA card converts pixel bits to color signals and constructs VGA frames. These VGA analog frames then feed to display monitor.

graphic application vga driver BIOS and vgacard output block diagram

There are many ways to interruct with a VGA graphics card. Application can directly access VGA I/O registers and framebuffer. Else it can use BIOS software interrupts or it can use Turbo C BGI graphics driver. BGI driver can talk to BIOS subsystem as well.

What is graphics.h in C? C Graphics library and driver?

Graphics in C is mainly VGA drawing program runs under DOS operating system. TurboC, Borland C are some compilers that provide a software stack for developing graphics-based programs. This graphics programs run under DOS or virtual mode in Windows. These programs should not be confused with Windows graphics programs. They are developed with Win32 APIs and graphics subsystem provided by DirectX, openGL or DRM.

graphics source code compile link run flow chart

A graphics program should include graphics.h using #include statement. This include file is located in \TurboC\Include folder and this is the standard include path for TurboC. This header file includes all the necessary VGA drawing routines needed for a standard graphics program. A program source file in .c format passed to the compiler along with graphics.h header file. graphics.h header file expands via pre-processor and combines with the actual source code. The compiler checks the graphics function prototypes and compiles the source to object file (.obj).

Now the linking process starts with the Object. Graphics.h file contains the prototypes of the graphics routines but the actual definitions are not included. The definition of these graphics calls are provided by the static library file graphics.lib. Graphics.lib are provided by TurboC and located in standard library folder \TurboC\Lib. The linker resolves the definitions and generates an executable file (.exe).

This final executable is DOS executable and requires DOS operating system to run. DOS shell can be run under Win95/98/XP and virtual mode in Windows 8./8.1/10. DosBox, Virtual box and QMU are some alternatives for running DOS OS inside Windows. This executable should be run under DOS shell and during running it looks for DOS runtime driver EGAVGA.BGI graphics driver. The library routine initializes the graphics mode via this graphics library located at \TurboC\BGI folder. Library call returns successful if driver file is loaded from this path. After this graphics library switches the video mode to VGA and handles all the rendering routines.

InitGraph

Turbo C graphics program should start with initializing graphics mode with initgraph. This function must be called in a graphics program. A successful initialization puts output console to VGA graphic mode. VGA mode consists of 640x480 pixels with 16 colors for each pixel. initgraph initializes the graphics system by loading a graphics driver from disk (or validating a registered driver) then putting the system into graphics mode. initgraph also resets all graphics settings (color, palette, current position, viewport, etc.) to their defaults, then resets graphresult to 0.

Declaration:

void initgraph(int *graph_driver, int *graph_mode, const char  *pathtodriver);

Arguments:

  • graph_driver: Integer that specifies the graphics driver to be used. You can give graphdriver a value using a constant of the graphics drivers enumeration type ( DETECT, /* requests autodetection */ CGA, MCGA, EGA, EGA64, EGAMONO, IBM8514,HERCMONO, ATT400, VGA, PC3270,CURRENT_DRIVER)
  • *graph_mode : Integer that specifies the initial graphics mode (unless *graphdriver = DETECT). If *graphdriver = DETECT, initgraph sets *graphmode to the highest resolution available for the detected driver. You can give *graphmode a value using a constant of the graphics_modes enumeration type ( CGA MCGA EGA EGAMONOHI, HERCMONOHI, ATT VGA PC3270 IBM8514)
  • pathtodriver : Specifies the directory path where initgraph looks for graphics drivers (*.BGI) first. If they're not there, initgraph looks in the current directory. If pathtodriver is null, the driver files must be in the current directory. This is also the path settextstyle searches for the stroked character font files (*.CHR).

Closegraph

Closegraph does the termination of graphics mode and puts console mode again to text mode. A graphics program should have a closegraph function at the end of graphics. Otherwise DOS screen will not go to text mode after running the program.

void         closegraph(void);
Here, closegraph() is called after getch() since screen should not clear until user hits a key.

#include<graphics.h>
#include<string.h>
#include<stdio.h>

int main (int argc, char *argv[])
{
  int gd = DETECT, gm;
  initgraph(&gd, &gm, "C:\\TC\\BGI");
  strcpy(str, getdrivername());
  if(getgraphmode() == 2) {
    strcat(str, " 640x480 16 color");
  }
  outtextxy(0, 0, str);
  getch();
  closegraph();
  return 0;
}

Additional functions:

void detectgraph (int  *graphdriver,int  *graphmode);
int  getgraphmode(void);
char *getmodename( int mode_number );
void  getmoderange(int graphdriver, int  *lomode, int  *himode);
int   getmaxmode(void);
int  getmaxcolor(void);
int  getmaxx(void);
int  getmaxy(void);
void  setgraphmode(int mode);

Graph Error handling

Above program does not contain any error handling cases. It may possible that initgraph may fail. There could be many reasons and one of the main reason is the absence of EGAVGA.BGI runtime library driver. graphresult returns the error code which graph subsystem encountered in the last call. An equivalent error string for each error code can be obtained passing the error code to grapherrormsg. It returns a human understandable error message for the error code. This is necessary to explain the error to the user.


#include<graphics.h>
#include<conio.h>

int main(int argc, char *argv[])
{
  int gd=DETECT, gm, gresult;
  initgraph(&gd, &gm, ""); /*path is incorrect*/
  gresult = graphresult();
  if(gresult != 0) {
    printf("initgraph error %d %s\n", gresult, grapherrormsg(gresult));
    return -1;
  }
  getch();
  closegraph();
 }
initgraph error -3 Device driver file not found (EGAVGA.BGI)

To run this program, you need graphics.h header file, graphics.lib library file and Graphics driver (TC\BGI\EGAVGA.BGI file) in the program folder. These files are part of Turbo C package. In all our programs we used 640x480 VGA monitor and graphics driver used is EGAVGA.BGI. So all the programs are according to that specification. You need to make necessary changes to your programs according to your screen resolution.

Here is list of error code and their explanations

  • grOk 0 No error
  • grNoInitGraph -1 (BGI) graphics not installed
  • grNotDetected -2 Graphics hardware not detected
  • grFileNotFound -3 Device driver file not found (EGAVGA.BGI)
  • grInvalidDriver -4 Invalid device driver file (EGAVGA.BGI)
  • grNoLoadMem -5 Not enough memory to load driver
  • grNoScanMem -6 Out of memory in scan fill
  • grNoFloodMem -7 Out of memory in flood fill
  • grFontNotFound -8 Font file not found ()
  • grNoFontMem -9 Not enough memory to load font
  • grInvalidMode -10 Invalid graphics mode for selected driver
  • grError -11 Graphics error
  • grIOerror -12 Graphics I/O error
  • grInvalidFont -13 Invalid font file ()
  • grInvalidFontNum -14 Invalid font number
  • grError15 -15 Graphics error (65521)
  • grError16 -16 Invalid Printer Initialize
  • grError17 -17 Printer Module Not Linked
  • grInvalidVersion -18 Invalid File Version Number

int graphresult (void);
char * grapherrormsg (int errorcode);
void graphdefaults (void);

Colors

Graphic mode in Turbo C has maximum 16 colors. Color range depends on the mode. Other modes can have 2, 4, 8, 256 colors. Color values are defined as enum COLOR and the values are-

  • BLACK
  • BLUE,
  • GREEN,
  • CYAN,
  • RED,
  • MAGENTA,
  • BROWN,
  • LIGHTGRAY,
  • DARKGRAY,
  • LIGHTBLUE,
  • LIGHTGREEN,
  • LIGHTCYAN,
  • LIGHTRED,
  • LIGHTMAGENTA,
  • YELLOW,
  • WHITE
Colors are used for applying foreground and background color in drawing lines, circle, rectangle etc. They can be used for setting color pallet and texture of filling graphical objcets.

void setbkcolor(int color);
void setcolor(int color);
int  getbkcolor(void);
int  getcolor(void);
int  getmaxcolor(void);
void setpalette(int colornum, int color);

Lines

Line drawings are the fundamental steps for any simple graphic objects. Graphic library provides standalone line drawing as well as drawing outer lines of basic shapes. We can modify line style and width. Here are the list of possibilities. Line Style:

  • SOLID_LINE = 0
  • DOTTED_LINE = 1
  • CENTER_LINE = 2
  • DASHED_LINE = 3
  • USERBIT_LINE = 4
Line width:
  • NORM_WIDTH = 1
  • THICK_WIDTH = 3

void setlinestyle(int linestyle, unsigned upattern, int thickness);
void getlinesettings(struct linesettingstype  *lineinfo);
void line(int x1, int y1, int x2, int y2);
void linerel(int dx, int dy);
void lineto(int x, int y);
void moverel(int dx, int dy);
void moveto(int x, int y);

Texture and filling

Graphical shapes and background can be filled with color and textures. Graphic library provides fill routines to do this work. Below are the list of fill patterns

  • EMPTY_FILL - fills area in background color
  • SOLID_FILL - fills area in solid fill color
  • LINE_FILL - fills area with horizontal lines/
  • LTSLASH_FILL - fills area with /// like lines
  • SLASH_FILL - fills area with /// like thick lines
  • BKSLASH_FILL - fills area with \\\ like thick lines
  • LTBKSLASH_FILL - fills area with \\\ like lines
  • HATCH_FILL -light hatch fill
  • XHATCH_FILL - heavy cross hatch fill
  • INTERLEAVE_FILL - interleaving line fill
  • WIDE_DOT_FILL - Widely spaced dot fill
  • CLOSE_DOT_FILL - Closely spaced dot fill
  • USER_FILL - user defined fill
void fillellipse( int x, int y, int xradius, int yradius );
void fillpoly(int numpoints, const int  *polypoints);
void floodfill(int x, int y, int border);
void setfillpattern(const char  *upattern, int color);
void setfillstyle(int pattern, int color);
void getfillpattern(char  *pattern);
void getfillsettings(struct fillsettingstype  *fillinfo);

Text display

Graphic library also provides Text display with outtext. Text display requires fonts to be installed and some fonts are installed by default. Font names:

  • DEFAULT_FONT = 0,
  • TRIPLEX_FONT = 1,
  • SMALL_FONT = 2,
  • SANS_SERIF_FONT = 3,
  • GOTHIC_FONT= 4,
  • SCRIPT_FONT= 5,
  • SIMPLEX_FONT = 6,
  • TRIPLEX_SCR_FONT = 7,
  • COMPLEX_FONT = 8,
  • EUROPEAN_FONT = 9,
  • BOLD_FONT = 10
Text alignment/justification:
  • LEFT_TEXT = 0,
  • CENTER_TEXT = 1,
  • RIGHT_TEXT = 2,
  • TOP_TEXT = 2
Text Direction:
  • HORIZ_DIR 0
  • VERT_DIR 1
Text Size:
Font size can be given from 1 to n. User defined fonts takes USER_CHAR_SIZE 0.

void settextjustify(int horiz, int vert);
void settextstyle(int font, int direction, int charsize);
void setusercharsize(int multx, int divx, int multy, int divy);
int  textheight(const char  *textstring);
int  textwidth(const char  *textstring);
void outtext(const char  *textstring);
void outtextxy(int x, int y, const char  *textstring);

Basic Shapes

Circle, ellipse, rectangle, cube etc are basic shapes. Function names and their arguments are self explanatory.

void circle(int x, int y, int radius);
void ellipse(int x, int y, int stangle, int endangle, int xradius, int yradius);
void rectangle(int left, int top, int right, int bottom);

Extended shapes

Bar chart, 3D bar chart, poly shape, pie chart, sectors etc are extended shapes. Function names and their arguments are self explanatory.

void  arc(int x, int y, int stangle, int endangle, int radius);
void  bar(int left, int top, int right, int bottom);
void  bar3d(int left, int top, int right, int bottom, int depth, int topflag);
void  drawpoly(int numpoints, const int  *polypoints);
void  pieslice(int x, int y, int stangle, int endangle, int radius);
void  sector( int X, int Y, int StAngle, int EndAngle, int XRadius, int YRadius );

Image drawing

Image bit block transfer functions are to copy image from one location to another. getimage function copies image to byte stream and putimage transfers byte image to screen location. Bitblock image putting operations are -

  • COPY_PUT,
  • XOR_PUT,
  • OR_PUT,
  • AND_PUT,
  • NOT_PUT
void getimage(int left, int top, int right, int bottom, void  *bitmap);
void putimage(int left, int top, const void  *bitmap, int op);
unsigned imagesize(int left, int top, int right, int bottom);

Utility functions

void  cleardevice(void);
void  clearviewport(void);
void  _graphfreemem(void  *ptr, unsigned size);
void  *   _graphgetmem(unsigned size);
void  getarccoords(struct arccoordstype  *arccoords);
void  getaspectratio(int  *xasp, int  *yasp);
struct palettetype  *   getdefaultpalette( void );
unsigned     getpixel(int x, int y);
void  getpalette(struct palettetype  *palette);
int      getpalettesize( void );
void  gettextsettings(struct textsettingstype  *texttypeinfo);
void  getviewsettings(struct viewporttype  *viewport);
int      getx(void);
int      gety(void);
int      installuserdriver( const char  *name,int huge (*detect)(void) );
int      installuserfont( const char  *name );
void  putpixel(int x, int y, int color);
void  restorecrtmode(void);
void  setactivepage(int page);
void  setallpalette(const struct palettetype  *palette);
void  setaspectratio( int xasp, int yasp );
unsigned setgraphbufsize(unsigned bufsize);
void  setrgbpalette(int colornum, int red, int green, int blue);
void  setviewport(int left, int top, int right, int bottom,
int clip);
void  setvisualpage(int page);
void  setwritemode( int mode );

Demo Application

#include<graphics.h>
#include<conio.h>
#include<stdio.h>
 
 int  main(int argc, char *argv[])
 {
     int gd=DETECT, gm, gresult;
     int poly[]={531,361, 578,382, 578,421, 531,441, 483,422, 483,380, 531,361 };
     char str[50];
     initgraph(&gd, &gm, "C:\\tc\\BGI");
     gresult = graphresult();
     if(gresult != 0){
        printf("error %d %s\n", gresult, grapherrormsg(gresult)); return;
     }
     strcpy(str, getdrivername());
     if(getgraphmode() == 2) strcat(str, " 640x480 16 color");
     outtextxy(0, 0, str);
     setcolor(BLUE);
     line(0, 160, 639, 160);
     line(0, 320, 639, 320);
     line(213, 0, 213, 479);
     line(426, 0, 426, 479);
     setcolor(RED);
     circle(106,80,50);
     setfillstyle(SOLID_FILL, LIGHTRED);
     floodfill(106,80, RED);
     outtextxy(72,143, "Circle");
     rectangle(250,20,390,135);
     setfillstyle(LINE_FILL, BLUE);
     floodfill(260, 25, RED);
     outtextxy(279,143, "Rectangle");
     setfillstyle(LTSLASH_FILL, CYAN);
     ellipse(530, 80,0,340, 80,50);
     fillellipse(530,80,80,50);
     outtextxy(495, 143, "Ellipse");
     setfillstyle(SOLID_FILL, LIGHTMAGENTA);
     setlinestyle(SOLID_LINE, 1, 1);
     setcolor(WHITE);
     bar(27,224,67,290);
     bar(72,200,116,290);
     bar(123,183,167,290);
     setcolor(RED);
     outtextxy(72,300,"Bar Graphs");
     settextstyle(SANS_SERIF_FONT, LEFT_TEXT, 1);
     outtextxy(240,180,"Font SANS SERIF");
     setfillstyle(SOLID_FILL, LIGHTGREEN);
     settextstyle(GOTHIC_FONT, LEFT_TEXT, 1);
     outtextxy(240,210,"Font GOTHIC");
     settextstyle(SCRIPT_FONT, LEFT_TEXT, 1);
     outtextxy(240,230,"Font SCRIPT");
     settextstyle(SIMPLEX_FONT, LEFT_TEXT, 1);
     outtextxy(240,250,"Font SIMPLEX");
     setfillstyle(SOLID_FILL, LIGHTGREEN);
     settextstyle(DEFAULT_FONT, LEFT_TEXT, 1);

     bar3d(440+27,224,440+67,290, 10, 10);
     bar3d(440+72,200,440+116,290, 10, 10);
     bar3d(440+123,183,440+167,290, 10, 10);
     setcolor(RED);
     outtextxy(490,300,"3D Bar graphs");
     setfillstyle(INTERLEAVE_FILL, LIGHTBLUE);
     pieslice(300,400, 10, 280, 40);
     setcolor(RED);
     outtextxy(280,463,"Pie slice");
     setfillstyle(CLOSE_DOT_FILL, LIGHTBLUE);
     sector(110, 400, 30, 300, 50,50);
     setcolor(RED);
     outtextxy(72, 463, "Sector");
     setfillstyle(HATCH_FILL, BROWN);
     setcolor(WHITE);
     drawpoly(7, poly);
     floodfill(530,400, WHITE);
     setcolor(RED);
     outtextxy(500, 463, "Polygon");
     getch();
     closegraph();
 }

Output

graphic application demo

About our authors: Team EQA

You have viewed 1 page out of 252. Your C learning is 0.00% complete. Login to check your learning progress.

#