/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// TUTPROG3.CPP - VGA Trainer Program 3 (in Turbo C++ 3.0)                 //
//                                                                         //
// "The VGA Trainer Program" is written by Denthor of Asphyxia. However it //
// was limited to Pascal only in its first run.  All I have done is taken  //
// his original release, translated it to C++ and touched up a few things. //
// I take absolutely no credit for the concepts presented in this code and //
// am NOT the person to ask for help if you are having trouble.            //
//                                                                         //
// Program Notes : This program presents many new concepts, including:     //
//                 Cirle and Line algorithms.                              //
//                                                                         //
//                 If you are compiling this code command line, be sure to //
//                 use the "-ml" parameter (large memory model).           //
//                 Otherwise, the program will compile and link, but will  //
//                 lock up your system.                                    //
//                                                                         //
// Author        : Grant Smith (Denthor) - [email protected]    //
// Translator    : Christopher G. Mann   - [email protected]         //
//                                                                         //
// Last Modified : December 7, 1994                                        //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

//               //
// INCLUDE FILES //
//               //

  #include <conio.h>
			  // getch(), clrscr(), kbhit()
  #include <dos.h>
			  // MK_FP, Geninterrupt()
  #include <math.h>
			  // floor(), ceil(), abs(), sin(), cos()
  #include <iostream.h>
			  // cout, endl, memset(), _fmemset()

//                     //
// FUNCTION PROTOTYPES //
//                     //

  // MODE SETTING FUNCTIONS
  void SetMCGA();
  void SetText();

  // PALLETTE FUNCTIONS
  void Pal    (unsigned char ColorNo,  unsigned char R,
	       unsigned char G,        unsigned char B);
  void PalPlay();

  // SMALL UTILITY FUNCTIONS
  int  sgn    (long a);
  int  round  (long a);

  // DRAWING FUNCTIONS
  void Putpixel (int  x, int  y, unsigned char Col);
  void Line     (int  a, int  b, int   c, int  d, int col);
  void Line2    (int x1, int y1, int  x2, int y2, int col);
  void Circle   (int  X, int  Y, int rad, int col);
  void WaitRetrace();

//                              //
// GLOBAL VARIABLE DECLARATIONS //
//                              //

  // declare a pointer to the offset of VGA memory
  unsigned char *vga = (unsigned char *) MK_FP(0xA000, 0);

  // This declares the PALL variable. 0 to 255 signifies the colors of the
  // pallette, 1 to 3 signifies the Red, Green and Blue values. I am
  // going to use this as a sort of "virtual pallette", and alter it
  // as much as I want, then suddenly bang it to screen. Pall2 is used
  // to "remember" the origional pallette so that we can restore it at
  // the end of the program. */
  unsigned char Pall[256][3], Pall2[256][3];

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                                MAIN FUNCTION                              //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

void main() {

  clrscr();
  cout
    << "This sample program will test out our line and circle algorithms.\n"
    << "In the first part, many circles will be draw creating (hopefully)\n"
    << "a ""tunnel"" effect. I will the rotate the pallete to make it look\n"
    << "nice. I will then draw some lines and rotate the pallette on them\n"
    << "too. Note : I am using the slower (first) line algorithm (in\n"
    << "procedure line2). Change it to Procedure Line and it will be using\n"
    << "the second line routine. NB : For descriptions on how pallette works\n"
    << "have a look at part two of this series; I won''t re-explain it here."
    << endl << endl;
  cout
    << "Remember to send me any work you have done, I am most eager to help."
    << endl << endl;
  cout
    << "Hit any key to continue ...";
  getch();
  SetMCGA();

  // This sets colors 1 to 199 to values between 33 to 63. The MOD
  // function gives you the remainder of a division, ie. 105 mod 10 = 5 }
  for (int loop1=1; loop1<200; loop1++) {
    Pall[loop1][0] = (loop1 % 30) + 33;
    Pall[loop1][1] = 0;
    Pall[loop1][2] = 0;
  }

  WaitRetrace();

  // This sets the true pallette to variable Pall
  for (loop1=1; loop1<200; loop1++)
    Pal(loop1, Pall[loop1][0], Pall[loop1][1], Pall[loop1][2]);

  // This draws 90 circles all with centers at 160,100 with increasing
  // radii and colors.
  for (loop1=1; loop1<91; loop1++)
    Circle(160, 100, loop1, loop1);

  // wait until a key is pressed
  while (!kbhit()) PalPlay();
  // make sure to clear the keyboard buffer
  getch();

  // This draws 199 lines, all starting at 0,1
  for (loop1=1; loop1<200; loop1++)
    Line2 (0,1,319,loop1,loop1);   // *** Replace Line2 with Line to use the
				   // second line algorithm ***

  while (!kbhit()) PalPlay();
  getch();

  getch();

  SetText();

  cout
    << "All done. Okay, so maybe it wasn''t a tunnel effect, but you get the\n"
    << "general idea ;-) This concludes the third sample program in the ASPHYXIA\n"
    << "Training series. You may reach DENTHOR under the name of GRANT SMITH\n"
    << "on the MailBox BBS, or leave a message to ASPHYXIA on the ASPHYXIA BBS\n"
    << "Get the numbers from Roblist, or write to :\n"
    << "             Grant Smith\n"
    << "             P.O. Box 270\n"
    << "             Kloof\n"
    << "             3640\n" << endl;
  cout << "I hope to hear from you soon!" << endl << endl;
  cout << "Hit any key to exit ...";

  getch();
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// SetMCGA() - This function gets you into 320x200x256 mode.               //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void SetMCGA() {
  _AX = 0x0013;
  geninterrupt (0x10);
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// SetText() - This function gets you into text mode.                      //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void SetText() {
  _AX = 0x0003;
  geninterrupt (0x10);
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Pal() - This sets the Red, Green, and Blue values of a certain color.   //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void Pal(unsigned char ColorNo, unsigned char R,
	 unsigned char G,       unsigned char B) {

  outp (0x03C8,ColorNo); // here is the pallette color I want to set
  outp (0x03C9,R);
  outp (0x03C9,G);
  outp (0x03C9,B);

}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// PalPlay() - This function mucks about with our "virtual pallette", then //
//             shoves it to the screen.                                    //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void PalPlay() {

unsigned char Tmp[3];

  // This copies color 199 from our virtual pallette to the Tmp variable.
  _fmemmove(Tmp,Pall[199],3);

  // This moves the entire virtual pallette up one color.
  _fmemmove(Pall[2],Pall[1],199*3);

  // This copies the Tmp variable to the bottom of the virtual pallette.
  // Don't change 0: leave this always black to not change overscan color.
  _fmemmove(Pall[1],Tmp,3);

  WaitRetrace();
  for (int loop1=0;loop1<256;loop1++)
   Pal(loop1,Pall[loop1][0], Pall[loop1][1], Pall[loop1][2]);

}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// sgn() - This function is used by Line() to determine the sign of a long //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

int sgn (long a) {
  if (a > 0) return +1;
  else if (a < 0) return -1;
  else return 0;

}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// round() - This function is used by Line() to round a long to the        //
//           nearest integer.                                              //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

int round (long a) {
  if ( (a - (int)a) < 0.5) return floor(a);
    else return ceil(a);
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Putpixel() - This puts a pixel on the screen by writing directly to     //
//              memory.                                                    //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void Putpixel (int x, int y, unsigned char Col) {
  memset(vga+(x+(y*320)),Col,1);
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Line() - This draws a line from a,b to c,d of color col.                //
//          This function will be explained in more detail in tut3new.zip  //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void Line(int a, int b, int c, int d, int col) {

  long u,s,v,d1x,d1y,d2x,d2y,m,n;
  int  i;

  u   = c-a;      // x2-x1
  v   = d-b;      // y2-y1
  d1x = sgn(u);   // d1x is the sign of u (x2-x1) (VALUE -1,0,1)
  d1y = sgn(v);   // d1y is the sign of v (y2-y1) (VALUE -1,0,1)
  d2x = sgn(u);   // d2x is the sign of u (x2-x1) (VALUE -1,0,1)
  d2y = 0;
  m   = abs(u);   // m is the distance between x1 and x2
  n   = abs(v);   // n is the distance between y1 and y2

  if (m<=n) {     // if the x distance is greater than the y distance
    d2x = 0;
    d2y = sgn(v); // d2y is the sign of v (x2-x1) (VALUE -1,0,1)
    m   = abs(v); // m is the distance between y1 and y2
    n   = abs(u); // n is the distance between x1 and x2
  }

  s = (int)(m / 2); // s is the m distance (either x or y) divided by 2

  for (i=0;i<round(m);i++) { // repeat this loop until it
			     // is = to m (y or x distance)
    Putpixel(a,b,col);       // plot a pixel at the original x1, y1
    s += n;                  // add n (dis of x or y) to s (dis of x of y)
    if (s >= m) {            // if s is >= m (distance between y1 and y2)
      s -= m;
      a += d1x;
      b += d1y;
    }
    else {
      a += d2x;
      b += d2y;
    }
  }

}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Line2() - This function draws a line from x1,y1 to x2,y2 using the      //
//           first method.                                                 //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void Line2(int x1, int y1, int x2, int y2, int col) {

  int   x, y, xlength, ylength, dx, dy;
  float xslope, yslope;

  xlength = abs(x1-x2);
  if ((x1-x2)  < 0) dx = -1;
  if ((x1-x2) == 0) dx =  0;
  if ((x1-x2)  > 0) dx = +1;

  ylength = abs(y1-y2);
  if ((y1-y2)  < 0) dy = -1;
  if ((y1-y2) == 0) dy =  0;
  if ((y1-y2)  > 0) dy = +1;

  if (dy == 0) {
    if (dx < 0)
      for (x=x1; x<x2+1; x++)
	Putpixel (x,y1,col);
    if (dx > 0)
      for (x=x2; x<x1+1; x++)
	Putpixel (x,y1,col);
  }

  if (dx == 0) {
    if (dy < 0)
      for (y=y1; y<y2+1; y++)
	Putpixel (x1,y,col);
    if (dy > 0)
      for (y=y2; y<y1+1; y++)
	Putpixel (x1,y,col);
  }

  if ((xlength != 0) && (ylength != 0)) {
    xslope = (float)xlength/(float)ylength;
    yslope = (float)ylength/(float)xlength;
  }
  else {
    xslope = 0.0;
    yslope = 0.0;
  }

  if ((xslope != 0) && (yslope != 0) &&
      (yslope/xslope < 1) && (yslope/xslope > -1)) {
    if (dx < 0)
      for (x=x1; x<x2+1; x++) {
	y = round (yslope*x);
	Putpixel (x,y,col);
      }
    if (dx > 0)
      for (x=x2; x<x1+1; x++) {
	y = round (yslope*x);
	Putpixel (x,y,col);
      }
  }
  else {
    if (dy < 0)
      for (y=x1; y<x2+1; y++) {
	x = round (xslope*y);
	Putpixel (x,y,col);
      }
    if (dy > 0)
      for (y=x2; y<x1+1; y++) {
	x = round (xslope*y);
	Putpixel (x,y,col);
      }
  }

}

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Circle() - This draws a circle with center X,Y, with Rad as its radius. //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void Circle(int X, int Y, int rad, int col) {

  float deg = 0;

  do {
    X = round(rad * cos(deg));
    Y = round(rad * sin(deg));
    Putpixel (X+160, Y+100, col);
    deg += 0.005;
  }
  while (deg <= 6.4);

}

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// WaitRetrace() - This waits until you are in a Verticle Retrace.         //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void WaitRetrace() {

  _DX = 0x03DA;

  l1: asm {
	in  al,dx;
	and al,0x08;
	jnz l1;
      }

  l2: asm {
	in  al,dx;
	and al,0x08;
	jz  l2;
      }
}


Hosted by www.Geocities.ws

1