Monday, April 03, 2006

C++/DOS: Video Programming with Turbo C++

I decided to build off of the Assembly example demonstrated here to show the same basic program written in a higher-level language. This program will make the same sprawling palette, then fade it out to black. The program was written in Turbo C++ 1.01, which is available for free under Borlands Antique Software Museum.

//dos.h is used to for the interupt calling functions, registers structure,
//and for input/output functions
#include < dos.h >

int main()
{
     //Used to store the palette entries. This could have easily
     //been done as a 3 dimensional array, but I feel conceptually
     //it is easier to use 3 seperate arrays for red, blue, and green
     unsigned char red[256], blue[256], green[256];

     //A far pointer used to work directly with the VGA screen memory
     //unsigned char far *VGA = (unsigned char *)MK_FP(0xA000, 0); //alternate declaration
     unsigned char far *VGA = (unsigned char *) 0xA0000000L;

     //counters, make sure they are unsigned
     unsigned int x, y, z;

     //used to represent the CPU registers, provided by dos.h
     union REGS regs;

     //set the registers for Interupt 10h, function 0, mode 13h
     //and call the interrupt to set the video mode to 320x200 256 colors
     regs.h.ah = 0;
     regs.h.al = 0x13;
     int86(0x10, ®s, &regs);

     //load the sprawling palette onto the screen
     for (x = 0; x < 200; x++)
          for (y = 0; y < 320; y++)
               //since the palette is only 256 colors, loop back
               //to the first color after 320
               if (y < 256)
                    VGA[(x * 320) + y] = y;
               else
                    VGA[(x * 320) + y] = y - 320;

     //Now load the palette into memory. This will allow
     //us to manipulate the palette in memory and load into
     //the palette rather than having to read, change, then write
     //from the video ports
     for (x = 0; x < 255; x++)
     {
          //port 3c7 signals palette read from port 3c9
          outp(0x3c7, x);

          red[x] = inp(0x3c9);
          green[x] = inp(0x3c9);
          blue[x] = inp(0x3c9);
     }

     //What this will do is fade red out first, then blue, then green
      //X controls which color is fading, y controls the intensity, and
      //z is controlling which palette entry we are changing
      for (x = 0; x < 3; x++)
           for (y = 0; y < 64; y++)
                for (z = 1; z < 255; z++)
               {
                    //based on the color to fade, subtract that color
                    switch (x)
                    {
                         case 0:
                              if (red[z] > 0)
                                    red[z]--;
                               break;
                         case 1:
                              if (green[z] > 0)
                                   green[z]--;
                              break;
                         case 2:
                              if (blue[z] > 0)
                                   blue[z]--;
                               break;
                         } //end switch

                    //port 3c8 signals 3c9 to recieve a new palette
                    //entry for color z
                    outp(0x3c8, z);
                    outp(0x3c9, red[z]);
                    outp(0x3c9, green[z]);
                    outp(0x3c9, blue[z]);
               } //end for

     //switch screen mode back to 80x25 text
     regs.h.ah = 0;
     regs.h.al = 0x3;
     int86(0x10, ®s, &regs);

     return 0;
}

The program touches on a few interesting points. It demonstrates how to communicate with hardware ports using the old DOS architecture and Turbo C++. It also demonstrates how pointers can be used to directly access hardware memory points, such as the VGA memory. It also demonstrates how to call DOS and hardware interrupts in a higher-level language using the dos.h header file. Something like this could have been written in assembler, however it would have been very difficult. In my next article, I will show how C++ and inline assembly can be used to accomplish the same task.

2 comments:

Vivek said...

can i control the external fan or bulb by c/c++ prog..i.e on or off..
if yes then help me..
vkgupta2807@gmail.com

John Ward said...

Yes. Its pretty easy to do. With an old school DOS program like this, your basically just going to write out the parallel port to trigger a simple switch circuit that is either powered by a relay or a transistor. If its done with a transistor, the input from your parallel port is going into the base. Plenty of documentation on using a transistor as a switch out there.