Previous | Table of Contents | Next

The other 2-D element we need is some way to erase the polygon at its old location before it’s moved and redrawn. We’ll do that by remembering the bounding rectangle of the polygon each time it’s drawn, then erasing by clearing that area with a rectangle fill.

With the 2-D side of the picture well under control, we’re ready to concentrate on the good stuff. Listings 50.2 through 50.5 are the sample 3-D animation program. Listing 50.2 provides matrix multiplication functions in a straightforward fashion. Listing 50.3 transforms, projects, and draws polygons. Listing 50.4 is the general header file for the program, and Listing 50.5 is the main animation program.

Other modules required are: Listings 47.1 and 47.6 from Chapter 47 (Mode X mode set, rectangle fill); Listing 49.6 from Chapter 49; Listing 39.4 from Chapter 39 (polygon edge scan); and the FillConvexPolygon() function from Listing 38.1 in Chapter 38. All necessary code modules, along with a project file, are present in the subdirectory for this chapter on the listings disk, whether they were presented in this chapter or some earlier chapter. This will be the case for the next several chapters as well, where listings from previous chapters are referenced. This scheme may crowd the listings diskette a little bit, but it will certainly reduce confusion!

LISTING 50.2 L50-2.C

    /* Matrix arithmetic functions.
       Tested with Borland C++ in the small model. */

    /* Matrix multiplies Xform by SourceVec, and stores the result in
       DestVec. Multiplies a 4x4 matrix times a 4x1 matrix; the result
       is a 4x1 matrix, as follows:
       --     --     -- --     -- --
       |       |     | 4 |     | 4 |
       |  4x4  |  X  | x |  =  | x |
       |       |     | 1 |     | 1 |
       --     --     -- --     -- -- */
    void XformVec(double Xform[4][4], double * SourceVec,
       double * DestVec)
    {
       int i,j;

       for (i=0; i<4; i++) {
          DestVec[i] = 0;
          for (j=0; j<4; j++)
             DestVec[i] += Xform[i][j] * SourceVec[j];
       }
    }

    /* Matrix multiplies SourceXform1 by SourceXform2 and stores the
       result in DestXform. Multiplies a 4x4 matrix times a 4x4 matrix;
       the result is a 4x4 matrix, as follows:
       --     --     --     --     --     --
       |       |     |       |     |       |
       |  4x4  |  X  |  4x4  |  =  |  4x4  |
       |       |     |       |     |       |
       --     --     --     --     --     -- */
    void ConcatXforms(double SourceXform1[4][4], double SourceXform2[4][4],
       double DestXform[4][4])
    {
       int i,j,k;

       for (i=0; i<4; i++) {
          for (j=0; j<4; j++) {
             DestXform[i][j] = 0;
             for (k=0; k<4; k++)
                DestXform[i][j] += SourceXform1[i][k] * SourceXform2[k][j];
          }
       }
    }

LISTING 50.3 L50-3.C

    /* Transforms convex polygon Poly (which has PolyLength vertices),
       performing the transformation according to Xform (which generally
       represents a transformation from object space through world space
       to view space), then projects the transformed polygon onto the
       screen and draws it in color ???Color. Also updates the extent of the
       rectangle (EraseRect) that’s used to erase the screen later.
       Tested with Borland C++ in the small model. */
    #include “polygon.h”

    void XformAndProjectPoly(double Xform[4][4], struct Point3 * Poly,
       int PolyLength, int Color)
    {
       int i;
       struct Point3 XformedPoly[MAX_POLY_LENGTH];
       struct Point ProjectedPoly[MAX_POLY_LENGTH];
       struct PointListHeader Polygon;

       /* Transform to view space, then project to the screen */
       for (i=0; i<PolyLength; i++) {
          /* Transform to view space */
          XformVec(Xform, (double *)&Poly[i], (double *)&XformedPoly[i]);
          /* Project the X & Y coordinates to the screen, rounding to the
             nearest integral coordinates. The Y coordinate is negated to
             flip from view space, where increasing Y is up, to screen
             space, where increasing Y is down. Add in half the screen
             width and height to center on the screen */
          ProjectedPoly[i].X = ((int) (XformedPoly[i].X/XformedPoly[i].Z *
                PROJECTION_RATIO*(SCREEN_WIDTH/2.0)+0.5))+SCREEN_WIDTH/2;
          ProjectedPoly[i].Y = ((int) (XformedPoly[i].Y/XformedPoly[i].Z *
                -1.0 * PROJECTION_RATIO * (SCREEN_WIDTH / 2.0) + 0.5)) +
                SCREEN_HEIGHT/2;
          /* Appropriately adjust the extent of the rectangle used to
             erase this page later */
             if (ProjectedPoly[i].X > EraseRect[NonDisplayedPage].Right)
              if (ProjectedPoly[i].X < SCREEN_WIDTH)
                EraseRect[NonDisplayedPage].Right = ProjectedPoly[i].X;
              else EraseRect[NonDisplayedPage].Right = SCREEN_WIDTH;
             if (ProjectedPoly[i].Y > EraseRect[NonDisplayedPage].Bottom)
              if (ProjectedPoly[i].Y < SCREEN_HEIGHT)
                EraseRect[NonDisplayedPage].Bottom = ProjectedPoly[i].Y;
              else EraseRect[NonDisplayedPage].Bottom = SCREEN_HEIGHT;
             if (ProjectedPoly[i].X < EraseRect[NonDisplayedPage].Left)
              if (ProjectedPoly[i].X > 0)
                EraseRect[NonDisplayedPage].Left = ProjectedPoly[i].X;
              else EraseRect[NonDisplayedPage].Left = 0;
             if (ProjectedPoly[i].Y < EraseRect[NonDisplayedPage].Top)
              if (ProjectedPoly[i].Y > 0)
                EraseRect[NonDisplayedPage].Top = ProjectedPoly[i].Y;
              else EraseRect[NonDisplayedPage].Top = 0;
       }
       /* Draw the polygon */
       DRAW_POLYGON(ProjectedPoly, PolyLength, Color, 0, 0);
    }

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash