/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// TUTPROG6.CPP - VGA Trainer Program 6 (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 demonstrates the advantages of             //
//                 pregenerated arrays.                                    //
//                                                                         //
//                 The Compact memory model (-mc) seems to provide the     //
//                 best results for this tutorial.  Remember, use this     //
//                 memory model when you have little code and lots of      //
//                 data.                                                   //
//                                                                         //
// Author        : Grant Smith (Denthor) - [email protected]    //
// Translator    : Christopher G. Mann   - [email protected]         //
//                                                                         //
// Last Modified : January 4, 1995                                         //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

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

  #include <conio.h>
			   // clrscr(), getch(), kbhit(), gotoxy(),
			   // directvideo
  #include <dos.h>
			   // MK_FP, geninterrupt()
  #include <iostream.h>
			   // cout, memset(), memmove()
  #include <math.h>
			   // sin(), cos()
  #include <stdlib.h>
			   // calloc(), free(), exit()

//           //
// CONSTANTS //
//           //

  const PI = 3.1415927;
  const TABLESIZE = 900;

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

  // UTILITY FUNCTIONS
  void  SetMCGA();
  void  SetText();
  void  Cls(unsigned char Col);
  void  Pal(unsigned char ColorNo, unsigned char R,
	    unsigned char G,       unsigned char B);
  void  Putpixel(int x, int y, unsigned char Col);
  void  WaitRetrace();
  float rad(float theta);

  // MID-LEVEL FUNCTIONS
  void  NormCirc();
  void  LookupCirc();
  void  PalPlay();

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

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

  // This is our temporary pallette.  We only use colors 1 to 20, so we
  // only have variables for those ones.
  unsigned char Pall[18][3];


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

void main() {

  int loop1;

  clrscr();
  cout
    << "Hi there! This program will demonstrate the usefullness of\n"
    << "pregenerated arrays, also known as lookup tables. The program\n"
    << "will first draw a spiral without using a lookup table, rotate\n"
    << "the pallette until a key is pressed, the calculate the lookup\n"
    << "table, then draw the same spiral using the lookup table.\n\n";
  cout
    << "This is merely one example for the wide range of uses of a\n"
    << "lookup table.\n\n";
  cout
    << "Hit any key to contine ...";
  getch();
  SetMCGA();

  // This handy trick allows you to use gotoxy() and cout in graphics mode.
  directvideo = 0;

  // This sets our pallette colors 0 to 17 with red values between 12 to 63.
  for (loop1=0;loop1<18;loop1++) {
    Pall[loop1][0] = ((loop1+1)*3)+9;
    Pall[loop1][1] = 0;
    Pall[loop1][2] = 0;
  }

  WaitRetrace();

  // This sets the true pallette to variable Pall
  for (loop1=0;loop1<18;loop1++)
    // loop+1 (make sure to leave color 0 for black)
    Pal(loop1+1,Pall[loop1][0],Pall[loop1][1],Pall[loop1][2]);

  // This draws a spiral without lookups
  NormCirc();
  while (!kbhit()) PalPlay();
  getch(); // clear the keyboard buffer after kbhit()

  // This draws a spiral with lookups
  LookupCirc();
  while (!kbhit()) PalPlay();
  getch();

  getch();
  SetText();
  cout
    << "All done. This concludes the sixth sample program in the ASPHYXIA\n"
    << "Training series. You may reach DENTHOR under the name of GRANT\n"
    << "SMITH on the MailBox BBS, or leave a message to ASPHYXIA on the\n"
    << "ASPHYXIA BBS. I am also an avid Connectix BBS user.\n"
    << "Get the numbers from Roblist, or write to :\n"
    << "             Grant Smith\n"
    << "             P.O. Box 270\n"
    << "             Kloof\n"
    << "             3640\n"
    << "I hope to hear from you soon!\n\n";
  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);
}

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Cls() - This clears the screen to the specified color.                  //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void Cls(unsigned char Col) {
  memset(vga, Col, 0xffff);
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// 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);

}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Putpixel() - This puts a pixel at X,Y using color Col, on VGA or the    //
//              Virtual Screen;                                            //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

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


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// 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;
      }
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// rad() - This calculates the degrees of an angle.                        //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

float rad(float theta) {
  return ((theta * PI)/180);
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// NormCirc() - This generates a spiral without using a lookup table.      //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void NormCirc() {

  int loop1,x,y;
  float deg,radius;

  gotoxy(1,1);
  cout << "Without pregenerated arrays.";

  for (loop1=60;loop1>42;loop1--) {
    deg = 0.0;
    radius = (float) loop1;

    do {
      x = radius*cos(rad(deg));
      y = radius*sin(rad(deg));
      Putpixel(x+160,y+100,61-loop1);
      deg += 0.4;          // Increase the degree so the circle is round
      radius -= 0.019;     // Decrease the radius for a spiral effect

      // NOTE: If you change this last statement to "radius -= 0.02;" like
      // the Pascal code has it, you will get holes in the spiral.  You
      // get bonus credit if you can tell me why this is.

    }
    while (radius >= 0.0); // continue until the radius is zero (at center)
  }
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// LookupCirc() - This draws a spiral using a lookup table.                //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void LookupCirc() {

  int x, y, pos, loop1;
  float radius, deg;
  float *costbl=NULL, *sintbl=NULL;

  // allocate memory for the two tables
  costbl = (float *) calloc(TABLESIZE,sizeof(float));
  sintbl = (float *) calloc(TABLESIZE,sizeof(float));

  // always check to see if enough memory was allocated
  if ((costbl == NULL) || (sintbl == NULL)) {
    SetText();
    cout << "Insufficient memory for lookup tables, exiting...";
    exit(1);
  }

  Cls(0);
  gotoxy(1,1);
  cout << "Generating variables....";

  // There are 360 degrees in a circle.  If you increase the degrees by 0.4,
  // the number of needed parts of the table is 360/0.4=900. (TABLESIZE)
  //
  // For greater accuracy I increase the degrees by 0.4, because if I
  // increase them by one, holes are left in the final product as a
  // result of the rounding error margin. This means the pregenerated array
  // is bigger, takes up more memory and is slower to calculate, but
  // the finished product looks better.

  deg = 0.0;
  for (loop1=0;loop1<TABLESIZE;loop1++) {
    costbl[loop1] = cos(rad(deg));
    sintbl[loop1] = sin(rad(deg));
    deg += 0.4;
  }

  gotoxy(1,1);
  cout << "With pregenerated arrays.";

  // NOTE: The spiral drawn with this function leaves a small piece missing
  // on the right side.  It looks like a pie with a piece cut out.  You get
  // extra credit if you can tell me why this is.

  for (loop1=60;loop1>42;loop1--) {
    pos = 0;
    radius = loop1;
    do {
      // Note how I am not recalculating sin and cos for each point.
      x = radius*costbl[pos];
      y = radius*sintbl[pos];
      Putpixel(x+160,y+100,61-loop1);
      // Decrease the radius for a spiral effect
      radius -= 0.020;
      // I only made a table from 1 to 900, so it must never exceed that,
      // or the program will probably crash.  Go ahead and increment
      // pos while you are at it (more compact but less readable). :)
      if (++pos > TABLESIZE-1) pos = 0;
    }
    while (radius >= 0.0);
  }

  // Freeing the memory taken up by the tables. This is very important.
  free(costbl);
  free(sintbl);

}


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

void PalPlay() {

  // This is used as a "temporary color" in our pallette
  unsigned char Tmp[3];
  int loop1;

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

  // This moves the entire virtual pallette down one color.
  memmove(Pall[0],Pall[1],17*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.
  memmove(Pall[17],Tmp,3);

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

}
Hosted by www.Geocities.ws

1