Graphics in DOS

There are 2 different video modes: text mode and graphics mode. Most people start out programming in text mode (whether the C/C++ compiler is running in DOS or Windows). The graphic modes I will cover will only run in DOS.

One good way to start off in graphics is to use BGI (Borland Graphics Interface). BGI runs in DOS and is limited to 16 colors (depending on what type of monitor your using and how you initialized your graphics, most people use (S)VGA now days, but it has support for old ones like EGA and CGA. BGI graphics use the graphics.h library. There are many functions that allow you to draw lines, polygons, circles and so on.

There is also another mode known as Mode 13h, which is faster than BGI and has a screen resolution of 320x200 and allows 256 colors and 1 page for animation. Unlike BGI, mode 13h cannot use the graphics.h library (some functions work, but most don't). But as long as you can plot a pixel, then you can use an algorithm to draw lines, circles, etc. It also helps if you know some ASM (assembly), to write fast, efficient code. Note that only C++ will recognize ASM.


Example Code

Here's some code of how to get into mode 13h (you might have to use different syntax for the ASM functions).


#include <dos.h>
#include <stdlib.h>

#define SCREEN_WIDTH  (unsigned int)320
#define SCREEN_HEIGHT (unsigned int)200

void Plot_Pixel(int x, int y, unsigned char color);
void Set_Video_Mode(int mode);

unsigned char far *video_buffer = (char far *)0xA0000000L;

void Plot_Pixel(int x, int y, unsigned char color)
{
//This function plots a single pixel in the desired color.
//This is very quick because it uses binar shifting to
//accomplish the multiplications.
   video_buffer[((y<<8)+(y<<6))+x] = color;
}

void Set_Video_Mode(int mode)
{
// Use video interrupt 10h to set the video mode to the send value.
   union REGS inregs, outregs;

   inregs.h.ah = 0;
   inregs.h.al = (unsigned char)mode;
   int86(0x10, &inregs, &outregs);
}

void main(void)
{
   // Set the video mode to VGA.
   Set_Video_Mode(VGA256);

   Plot_Pixel(,,);

   // Reset the video mode back to its original text mode.
   Set_Video_Mode(TEXT_MODE);
}

If you are using mode 13h, the clrscr() function will look grey heres code to use "fill the screen", which clears it:


//by IKoulchin
#define screen_ram 0x0A000

// fills the screen in a color
void Fill_screen(int color)
{
asm{
mov AX,screen_ram
mov ES, AX
xor DI,DI
mov CX,32000;
mov AL, BYTE PTR color
mov AH,AL
rep stosw
}// end asm
}// end fillscreen

Here's code to open up a PCX file, note it must be 320x200 and 256 colors, or it will mess up.


//by Lutrosis
#include <dos.h>
#include <stdlib.h>
#include <graphics.h>
#include <stdio.h>
#include <mem.h>

void init_graph()
{
  asm {
    mov AX, 0x0013
    int 0x10
  }
}

void close_graph()
{
  asm {
    mov AX, 0x0003
    int 0x10
  }
}

//Now the pixel-plotting code:
// define this somewhere in your file.
// address of the screen buffer
unsigned char far *video_buffer= (char far *)0xA0000000L;


//unsigned char far* video_buffer=0xA0000000;

// remember, this doesn't clip, so don't draw pixels off-screen
void put_pixel(int x,int y,unsigned char color) {
  video_buffer[y*320+x]=color;
}
// make sure these definitions are in your file somewhere
typedef struct {
  unsigned char red,green,blue;
} RGB_type;

typedef RGB_type palette_type[256];

// You'll need this function too
void set_DAC(char DAC_num,RGB_type new_values)
{
  outportb(0x3c8,DAC_num);
  outportb(0x3c9,new_values.red);
  outportb(0x3c9,new_values.green);
  outportb(0x3c9,new_values.blue);
}

void load_pcx(char *filename,unsigned char far* the_buffer)
{
  FILE *fp;       // the file pointer used to open the PCX file
  int num_bytes,  // number of bytes in current RLE run
      index;      // loop variable
  long count;     // the total number of bytes decompressed
  unsigned char data; // the current pixel data
  palette_type palette;

  if ((fp = fopen(filename,"rb"))==NULL) {
    close_graph();
    printf("\nPCX SYSTEM - Couldn't find file: %s",filename);
    exit(1);
  } // end if couldn't find file
  for (index=0; index < 128; index++) {
    (char)getc(fp);
  } // end for index
  count=0;
  while(count <=64000) {
    data = (unsigned char)getc(fp);
    if (data >=192) {
      num_bytes = data-192;
      data  = (unsigned char)getc(fp);
      while(num_bytes-->0) {
	the_buffer[count++] = data;
      } // end while
    } // end if rle
    else {
      the_buffer[count++] = data;
    } // end else not rle
  } // end while
  fseek(fp,-768L,SEEK_END);
  for (index=0; index<256; index++) {
    palette[index].red   = (unsigned char)(getc(fp) >> 2);
    palette[index].green = (unsigned char)(getc(fp) >> 2);
    palette[index].blue  = (unsigned char)(getc(fp) >> 2);
  } // end for index
  fclose(fp);
  for (index=0; index<256; index++) {
    set_DAC(index,palette[index]);
  } // end for index
} // end PCX_Load

void main()
{
init_graph();
load_pcx("a:\IMAGENAME.pcx", video_buffer);
sleep(10);//delay 10 sec

close_graph();
}

Here's code for a really fast plot pixel


//by Ready4Dis
unsigned char far *screen = (unsigned char far*)0xa0000000l;

#define put_pixel(x, y, col) screen[(y<<6)+(y<<8)+x] = col

Fortunately, loading a bitmap is very simple. The data is backwards but not compressed. Here is a function i wrote which will load bitmaps of 8 bit 16bit 24bit or 32bit. I'm not sure about 1bit and 4 bit though.


//by ShogunTim
char *bmpdata;
int width,heigth,bpp;
bmpdata = bmpload("test.bmp", NULL, 0, NULL, &width,&heigth,&bpp);


char *bmpload(char *fname, FILE *fp, long startpos,
              unsigned char *pal, int *bmpwidth,
              int *bmpheigth, int *bpp)
{
long heigth, width=0, o, compress; short bits;
char *buffer;
int i, z;
char b;
int save=-1;

if (!fp){if (fname) {fp=fopen(fname, "rb");} else {return NULL;}}

fseek(fp, startpos + 22, SEEK_SET); fread(&heigth, 1, 4, fp);
fseek(fp, startpos + 10, SEEK_SET); fread(&o, 1, 4, fp); 
width = (filelength(fileno(fp)) - o) / heigth;
fseek(fp, startpos + 28, SEEK_SET); fread(&bits, 1, 2, fp);
fseek(fp, startpos + 30, SEEK_SET); fread(&compress, 1, 4, fp);

buffer = new char[width*(heigth+2)];
if (!buffer) return NULL;
/*snatch the palette. not needed for 16,24 or 32 bits*/
for (i=0; i<=1020; i+=4)
     {
      for (z=3; z>=1; z--)
       {
        fseek(fp, startpos + 54+i+z-1, SEEK_SET);
        fread(&b, 1, 1, fp);
        if (pal) {pal[++save]=b;}
        }
      }

/*read color data*/
char *tempb = buffer; 
long y;
for (y=heigth-1; y>0; y--) 
     { 
      fseek(fp, startpos + o + (width * y)  -1, SEEK_SET);//find line
      fread(tempb, 1, width, fp);      //read entire line
      tempb+=width;
      }

if (bmpwidth) {*bmpwidth = (int)width/(bits/8);}
if (bmpheigth) {*bmpheigth = (int)heigth;}
if (bpp) {*bpp = (int)bits;}

return buffer;
}