Previous | Table of Contents | Next

LISTING 50.5 L50-5.C

    /* Simple 3-D drawing program to view a polygon as it rotates in
       Mode X. View space is congruent with world space, with the
       viewpoint fixed at the origin (0,0,0) of world space, looking in
       the direction of increasingly negative Z. A right-handed
       coordinate system is used throughout.
       Tested with Borland C++ in the small model. */
    #include <conio.h>
    #include <stdio.h>
    #include <dos.h>
    #include <math.h>
    #include “polygon.h”
    void main(void);

    /* Base offset of page to which to draw */
    unsigned int CurrentPageBase = 0;
    /* Clip rectangle; clips to the screen */
    int ClipMinX=0, ClipMinY=0;
    int ClipMaxX=SCREEN_WIDTH, ClipMaxY=SCREEN_HEIGHT;
    /* Rectangle specifying extent to be erased in each page */
    struct Rect EraseRect[2] = { {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT},
       {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT} };
    /* Transformation from polygon’s object space to world space.
       Initially set up to perform no rotation and to move the polygon
       into world space -140 units away from the origin down the Z axis.
       Given the viewing point, -140 down the Z axis means 140 units away
       straight ahead in the direction of view. The program dynamically
       changes the rotation and translation. */
    static double PolyWorldXform[4][4] = {
       {1.0, 0.0, 0.0, 0.0},
       {0.0, 1.0, 0.0, 0.0},
       {0.0, 0.0, 1.0, -140.0},
       {0.0, 0.0, 0.0, 1.0} };
    /* Transformation from world space into view space. In this program,
       the view point is fixed at the origin of world space, looking down
       the Z axis in the direction of increasingly negative Z, so view
       space is identical to world space; this is the identity matrix. */
    static double WorldViewXform[4][4] = {
       {1.0, 0.0, 0.0, 0.0},
       {0.0, 1.0, 0.0, 0.0},
       {0.0, 0.0, 1.0, 0.0},
       {0.0, 0.0, 0.0, 1.0}
    };
    static unsigned int PageStartOffsets[2] =
       {PAGE0_START_OFFSET,PAGE1_START_OFFSET};
    int DisplayedPage, NonDisplayedPage;

    void main() {
       int Done = 0;
       double WorkingXform[4][4];
       static struct Point3 TestPoly[] =
             {{-30,-15,0,1},{0,15,0,1},{10,-5,0,1}};
    #define TEST_POLY_LENGTH   (sizeof(TestPoly)/sizeof(struct Point3))
       double Rotation = M_PI / 60.0; /* initial rotation = 3 degrees */
       union REGS regset;

       Set320x240Mode();
       ShowPage(PageStartOffsets[DisplayedPage = 0]);
       /* Keep rotating the polygon, drawing it to the undisplayed page,
          and flipping the page to show it */
       do {
          CurrentPageBase =    /* select other page for drawing to */
                PageStartOffsets[NonDisplayedPage = DisplayedPage ^ 1];
          /* Modify the object space to world space transformation matrix
             for the current rotation around the Y axis */
          PolyWorldXform[0][0] = PolyWorldXform[2][2] = cos(Rotation);
          PolyWorldXform[2][0] = -(PolyWorldXform[0][2] = sin(Rotation));
          /* Concatenate the object-to-world and world-to-view
             transformations to make a transformation matrix that will
             convert vertices from object space to view space in a single
             operation */
          ConcatXforms(WorldViewXform, PolyWorldXform, WorkingXform);
          /* Clear the portion of the non-displayed page that was drawn
             to last time, then reset the erase extent */
          FillRectangleX(EraseRect[NonDisplayedPage].Left,
                EraseRect[NonDisplayedPage].Top,
                EraseRect[NonDisplayedPage].Right,
                EraseRect[NonDisplayedPage].Bottom, CurrentPageBase, 0);
          EraseRect[NonDisplayedPage].Left =
                EraseRect[NonDisplayedPage].Top = 0x7FFF;
          EraseRect[NonDisplayedPage].Right =
             EraseRect[NonDisplayedPage].Bottom = 0;
          /* Transform the polygon, project it on the screen, draw it */
          XformAndProjectPoly(WorkingXform, TestPoly, TEST_POLY_LENGTH,9);
          /* Flip to display the page into which we just drew */
          ShowPage(PageStartOffsets[DisplayedPage = NonDisplayedPage]);
          /* Rotate 6 degrees farther around the Y axis */
          if ((Rotation += (M_PI/30.0)) >= (M_PI*2)) Rotation -= M_PI*2;
          if (kbhit()) {
             switch (getch()) {
                case 0x1B:     /* Esc to exit */
                   Done = 1; break;
                case ‘A’: case ‘a’:      /* away (-Z) */
                   PolyWorldXform[2][3] -= 3.0; break;
                case ‘T’:      /* towards (+Z). Don’t allow to get too */
                case ‘t’:      /* close, so Z clipping isn’t needed */
                   if (PolyWorldXform[2][3] < -40.0)
                         PolyWorldXform[2][3] += 3.0; break;
                case 0:     /* extended code */
                   switch (getch()) {
                      case 0x4B:  /* left (-X) */
                         PolyWorldXform[0][3] -= 3.0; break;
                      case 0x4D:  /* right (+X) */
                         PolyWorldXform[0][3] += 3.0; break;
                      case 0x48:  /* up (+Y) */
                         PolyWorldXform[1][3] += 3.0; break;
                      case 0x50:  /* down (-Y) */
                         PolyWorldXform[1][3] -= 3.0; break;
                      default:
                         break;
                   }
                   break;
                default:       /* any other key to pause */
                   getch(); break;
             }
          }
       } while (!Done);
       /* Return to text mode and exit */
       regset.x.ax = 0x0003;   /* AL = 3 selects 80x25 text mode */
       int86(0x10, &regset, &regset);
    }

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash