//               //
// INCLUDE FILES //
//               //
#include <conio.h>  // clrscr(), getch(), kbhit()
#include <dos.h>    // MK_FP, geninterrupt()
#include <stdio.h>  // fopen(), fread(), fclose(), FILE
#include <string.h> // for the memcpy() function
#include <math.h>       // sin(), cos()
#include <stdlib.h> // exit(), rand()




  #define VGA 0xa0000
  #define MAXLINES 12     // the number of lines in our cube

#define ABS(x) ( ((x) >= 0) ? (x) : (x * -1) )
#define round(x) floor( (x) + 0.5)

//          //
// TYPEDEFS //
//          //

  typedef unsigned char byte;
  typedef unsigned int  word;

  // The data on every point we rotate
  typedef struct {
         float    x;
         float    y;
         float    z;
  } Point;

//           //
// CONSTANTS //
//           //
  const PIE = 3.1415927;

  // The 3-D coordinates of our object ... stored as {X1,Y1,Z1},
  // {X2,Y2,Z2} ... for the two ends of a line
  const int Obj[MAXLINES][2][3] =
    { {{-10,-10,-10}, { 10,-10,-10}}, //  0        .-----2----.
      {{-10,-10,-10}, {-10, 10,-10}}, //  1       /|         /|
      {{-10, 10,-10}, { 10, 10,-10}}, //  2      9 |        A |
      {{ 10,-10,-10}, { 10, 10,-10}}, //  3     /  |       /  |
      {{-10,-10, 10}, { 10,-10, 10}}, //  4    .------6---.   3
      {{-10,-10, 10}, {-10, 10, 10}}, //  5    |   |      |   |
      {{-10, 10, 10}, { 10, 10, 10}}, //  6    |   1      7   |
      {{ 10,-10, 10}, { 10, 10, 10}}, //  7    |   |      |   |
      {{-10,-10, 10}, {-10,-10,-10}}, //  8    5   '----0-|---'
      {{-10, 10, 10}, {-10, 10,-10}}, //  9    |  /       |  /
      {{ 10, 10, 10}, { 10, 10,-10}}, //  A    | 8        | B
      {{ 10,-10, 10}, { 10,-10,-10}}  //  B    |/         |/
    };                                //       `-----4----'



 Point Translated[MAXLINES][2];         // The rotated object
 Point Lines[MAXLINES][2];                      // The base object rotated

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

  float Lookup[360][2];            // Our sin and cos lookup table
  int Xoff, Yoff, Zoff;            // Used for movement of the objects

  char virscr [64000]; // screen is 320x200


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


void SetMCGA(void)
{
                  #pragma aux SetMCGA =   \
                  "mov ax, 0013h",        \
                  "int 10h"               \
                  modify [ax];
}


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

void SetText(void)
{
                  #pragma aux SetText =   \
                  "mov ax, 0003h",        \
                  "int 10h"               \
                  modify [ax];
}




//ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ
// This puts a pixel on the virtual screen by writing directly to memory.

void Putpixel2(unsigned int x, unsigned int y, unsigned char col)
{
        virscr[y*320 + x] = col;
}

//ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ
// This clears the virtual screen to the specified color

void Cls(unsigned char col)
{
        memset((char *) virscr, col, 64000);
}



//ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ



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

void WaitRetrace(void)
  // This waits until you are in a Verticle Retrace ... this means that all
  //  screen manipulation you do only appears on screen in the next verticle
  //  retrace ... this removes most of the "fuzz" that you see on the screen
  //  when changing the pallette. It unfortunately slows down your program
  //  by "synching" your program with your monitor card ... it does mean
  //  that the program will run at almost the same speed on different
  //  speeds of computers which have similar monitors. In our SilkyDemo,
  //  we used a WaitRetrace, and it therefore runs at the same (fairly
  //  fast) speed when Turbo is on or off.

{
  while(inp(0x3DA) & 0x08);
  while(!(inp(0x3DA) & 0x08 ));
}




/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// 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)
{
  // This sets the Red, Green and Blue values of a certain color 

   outp(0x3C8,ColorNo);
   outp(0x3C9,R);
   outp(0x3C9,G);
        outp(0x3C9,B);

}

void GetPal(unsigned char ColorNo, unsigned char *R,unsigned char *G,unsigned char *B)
{
  // This reads the values of the Red, Green and Blue values of a certain
  //  color and returns them to you.


        outp(0x3C7,ColorNo);
        *R = inp(0x3C9);
        *G = inp(0x3C9);
        *B = inp(0x3C9);
}


////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Flip() - This copies the entire screen at "source" to destination.      //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////



void Flip(void)
{
   // This flips the virtual screen to the VGA screen.

  memcpy((char *) VGA,virscr,64000);

}

//ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ
int sgn(float a)
        {

                  if (a>0) return (+1);
                  if (a<0) return (-1);
                  if (a==0) return (0);
                  return 0;

        }
//ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ
void Line(int a,int b,int c,int d,int col)
{
  // This draws a line from a,b to c,d of color col.

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

  float a1=a, b1=b, c1=c, d1=d;

     u = c1 - a1;
     v = d1 - b1;

     d1x= sgn(u);
     d1y= sgn(v);
     d2x= sgn(u);
     d2y= 0;
     m= ABS(u);
     n = ABS(v);

     if ( !(m>n) )
     {
          d2x =0;
          d2y = sgn(v);
          m = ABS(v);
          n = ABS(u);
     }
     s = (int)(m / 2);


     
     for(i=0;i<=round(m);i++)
          {
                         Putpixel2(a,b,col);
                         s = s + n;
                         if (!(s<m))
                         {
                                        s = s - m;
                                        a= a +round(d1x);
                                        b = b + round(d1y);
                         }
                         else
                         {
                                        a = a + round(d2x);
                                        b = b + round(d2y);
                         }
          }

}


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

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



/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// DrawLogo() - This draws 'SNOWMAN' at the top of the screen in little    //
//              balls.                                                     //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void DrawLogo() {

  const byte ball[5][5] = { 0,1,1,1,0,
                                                                         1,4,3,2,1,
                                                                         1,3,3,2,1,
                                                                         1,2,2,2,1,
                                                                         0,1,1,1,0
                                                                  };

  const char *Logo[5] =      {
                                                                          "OOO OOO OOO O O O  O O  OOO OOO",
                                                                          "O   O O O O O O O O O O O O O O",
                                                                          "OOO O O O O O O O O O O OOO O O",
                                                                          "  O O O O O O O O O O O O O O O",
                                                                          "OOO O O OOO  O O  O O O O O O O",
                                                                          };

  int loop1, loop2, loop3, loop4;

  Pal(13, 0,63, 0); // set the color for the cube lines
  Pal( 1, 0, 0,40); // set the colors for the dots
  Pal( 2, 0, 0,45);
  Pal( 3, 0, 0,50);
  Pal( 4, 0, 0,60);

  for (loop1=0; loop1<5; loop1++)        // for each line...
         for (loop2=0; loop2<31; loop2++)       // is it active?
                if (Logo[loop1][loop2] == 'O')
                for (loop3=0; loop3<5; loop3++)        // y coordinate of the ball
                  for (loop4=0; loop4<5; loop4++)        // x coordinate of the ball
                         Putpixel2 ((loop2+1)*10+loop3, (loop1+1)*4+loop4,
                                                  ball[loop3][loop4]);

}

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// SetUpPoints() - This sets the basic offsets of the object, creates the  //
//                 lookup table, and moves the object from a constant to a //
//                 variable.                                               //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void SetUpPoints() {

  int loop1;

  // set the starting offsets of the cube
  Xoff =  160;
  Yoff =  100;
  Zoff = -256;

  // generate the sin() and cos() tables
  for (loop1=0; loop1<361; loop1++) {
         Lookup [loop1][0] = sin(rad(loop1));
         Lookup [loop1][1] = cos(rad(loop1));
  }

  // move the Obj constant array into the Lines array
  for (loop1=0; loop1<MAXLINES; loop1++) {
         Lines[loop1][0].x = Obj[loop1][0][0];
         Lines[loop1][0].y = Obj[loop1][0][1];
         Lines[loop1][0].z = Obj[loop1][0][2];
         Lines[loop1][1].x = Obj[loop1][1][0];
         Lines[loop1][1].y = Obj[loop1][1][1];
         Lines[loop1][1].z = Obj[loop1][1][2];
  }

}

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// RotatePoints() - This rotates object lines by X, Y, and Z.  Then it     //
//                  places the result in Translated.                       //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void RotatePoints (int X,int Y,int Z) {

  int loop1;

  Point temp;


  // for each line...
  for (loop1=0; loop1<MAXLINES; loop1++) {

    // start point of line

    temp.x = Lines[loop1][0].x;
    temp.y = Lookup[X][1]*Lines[loop1][0].y - Lookup[X][0]*Lines[loop1][0].z;
    temp.z = Lookup[X][0]*Lines[loop1][0].y + Lookup[X][1]*Lines[loop1][0].z;
    Translated[loop1][0] = temp;

         if (Y > 0) {
      temp.x = Lookup[Y][1]*Translated[loop1][0].x - Lookup[Y][0]*Translated[loop1][0].y;
      temp.y = Lookup[Y][0]*Translated[loop1][0].x + Lookup[Y][1]*Translated[loop1][0].y;
      temp.z = Translated[loop1][0].z;
      Translated[loop1][0] =temp;
    }

    if (Z > 0) {
      temp.x = Lookup[Z][1] * Translated[loop1][0].x + Lookup[Z][0]*Translated[loop1][0].z;
      temp.y = Translated[loop1][0].y;
      temp.z = (-Lookup[Z][0])*Translated[loop1][0].x + Lookup[Z][1]*Translated[loop1][0].z;
      Translated[loop1][0] = temp;
    }

         // end point of line

    temp.x = Lines[loop1][1].x;
    temp.y = cos(rad(X))*Lines[loop1][1].y - sin(rad(X))*Lines[loop1][1].z;
    temp.z = sin(rad(X))*Lines[loop1][1].y + cos(rad(X))*Lines[loop1][1].z;
    Translated[loop1][1] = temp;

    if (Y > 0) {
      temp.x = cos(rad(X))*Translated[loop1][1].x - sin(rad(Y))*Translated[loop1][1].y;
      temp.y = sin(rad(Y))*Translated[loop1][1].x + cos(rad(Y))*Translated[loop1][1].y;
                temp.z = Translated[loop1][1].z;
      Translated[loop1][1] = temp;
    }

    if (Z > 0) {
      temp.x = cos(rad(Z))*Translated[loop1][1].x + sin(rad(Z))*Translated[loop1][1].z;
      temp.y = Translated[loop1][1].y;
      temp.z = (-sin(rad(Z)))*Translated[loop1][1].x + cos(rad(Z))*Translated[loop1][1].z;
      Translated[loop1][1] = temp;
    }
  }
}

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// DrawPoints() - This draws the translated object to the virtual screen.  //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void DrawPoints() {

  int loop1, nx, ny, nx2, ny2, temp;

  for (loop1=0; loop1<MAXLINES; loop1++) {
         if ((Translated[loop1][0].z+Zoff<0) && (Translated[loop1][1].z+Zoff<0)) {

      // start point of line
      temp = Translated[loop1][0].z + Zoff;
      nx   = ((256*Translated[loop1][0].x) / temp) + Xoff;
      ny   = ((256*Translated[loop1][0].y) / temp) + Yoff;

      // end point of line
      temp = Translated[loop1][1].z + Zoff;
      nx2  = ((256*Translated[loop1][1].x) / temp) + Xoff;
      ny2  = ((256*Translated[loop1][1].y) / temp) + Yoff;

      // check to make sure the line is within bounds
      if ((nx >-1) && (nx <320) && (ny >25) && (ny <200) &&
                         (nx2>-1) && (nx2<320) && (ny2>25) && (ny2<200))
                  Line(nx,ny,nx2,ny2,13);
    }
  }
}

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// ClearPoints() - This clears the translated object from the virtual      //
//                 screen ... believe it or not, this is faster than a     //
//                 straight cls(0,vaddr);                                  //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void ClearPoints() {

  int loop1, nx, ny, nx2, ny2, temp;

  for (loop1=0; loop1<MAXLINES; loop1++) {
    if ((Translated[loop1][0].z+Zoff<0) && (Translated[loop1][1].z+Zoff<0)) {

      // start point of line
      temp = Translated[loop1][0].z + Zoff;
      nx   = ((256*Translated[loop1][0].x) / temp) + Xoff;
                ny   = ((256*Translated[loop1][0].y) / temp) + Yoff;

      // end point of line
      temp = Translated[loop1][1].z + Zoff;
      nx2  = ((256*Translated[loop1][1].x) / temp) + Xoff;
      ny2  = ((256*Translated[loop1][1].y) / temp) + Yoff;

      // check to make sure the line is within bounds
      if ((nx >-1) && (nx <320) && (ny >25) && (ny <200) &&
          (nx2>-1) && (nx2<320) && (ny2>25) && (ny2<200))
                  Line(nx,ny,nx2,ny2,0);
    }
  }
}

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// MoveAround() - This is the main display function.  First it brings the  //
//                object towards the viewer by increasing the Zoff, then   //
//                it passes control to the user.                           //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void MoveAround() {

//  // For some reason, the values we defined Xoff, Yoff, and Zoff to be in
//  // the function SetUpPoints() won't hold until this point.  If you know
//  // the reason, please send it to [email protected]
//  float Xoff =  160;  // redefined
//  float Yoff =  100;  // redefined
//  float Zoff = -256;  // redefined

  int deg=0; int loop1;
  byte ch=1; // assign a dummy value to ch

  Cls(0);

  DrawLogo();

  for (loop1=(-256); loop1<(-39); loop1++) {
         Zoff = loop1 * 2;
         RotatePoints(deg,deg,deg);
         DrawPoints();
         WaitRetrace();
         Flip();
         ClearPoints();
         deg = (deg + 5) % 360;
  }

  do {

         if (kbhit()) {
                ch = getch();
                switch (ch) {
                  // We are not going to use toupper() because if we did, we'd have
                  // to include the whole ctype.h file.  This might take a little more
                  // time, but the program will be smaller.  We already have 7 include
                  // files, and its getting a bit rediculous.
                  case 'A': case 'a': Zoff += 5; break;  // away
                  case 'Z': case 'z': Zoff -= 5; break;  // toward
                  case ',':           Xoff -= 5; break;  // left
                  case '.':           Xoff += 5; break;  // right
                  case 'S': case 's': Yoff -= 5; break;  // down
                  case 'X': case 'x': Yoff += 5; break;  // up
                }
         }
         DrawPoints();
         WaitRetrace();
         Flip();
         ClearPoints();
         RotatePoints(deg,deg,deg);
         deg = (deg + 5) % 360;

         // if the key pressed above was 0 (i.e. a control character) then
         // read the character code
         if (ch == 0) ch = getch();

  } while (ch != 27); // if the escape code was 27 (escape key) then exit
}

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

int main(void) {

  printf(
         "Greetings and salutations! Hope you had a great Christmas and New\n"
         "year! ;-) ... Anyway, this tutorial is on 3-D, so this is what is\n"
         "going to happen ... a wireframe square will come towards you.\n"
         "When it gets close, you get control. ""A"" and ""Z"" control the Z\n"
         "movement, "","" and ""."" control the X movement, and ""S"" and ""X""\n"
         "control the Y movement. I have not included rotation control, but\n"
         "it should be easy enough to put in yourself ... if you have any\n"
         "hassles, leave me mail.\n\n");
  printf(
         "Read the main text file for ideas on improving this code ... and\n"
         "welcome to the world of 3-D!\n\n");
  printf("Hit any key to contine ...\n");
  getch();

  SetMCGA();

  SetUpPoints();
  MoveAround();

  SetText();

  printf(
         "All done. This concludes the eigth sample program in the ASPHYXIA\n"
         "Training series. You may reach DENTHOR under the names of GRANT\n"
         "SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid\n"
         "Connectix BBS user, and occasionally read RSAProg.\n"
         "For discussion purposes, I am also the moderator of the Programming\n"
         "newsgroup on the For Your Eyes Only BBS.\n"
         "The numbers are available in the main text. You may also write to me at:\n"
         "             Grant Smith\n"
         "             P.O. Box 270\n"
         "             Kloof\n"
         "             3640\n"
         "I hope to hear from you soon!\n\n\n");
  printf("Hit any key to exit ...\n");
  getch();
  return (0);
}
Hosted by www.Geocities.ws

1