Previous | Table of Contents | Next

LISTING 52.1 L52-1.C

    /* 3-D animation program to rotate 12 cubes. Uses fixed point. All C code
       tested with Borland C++ in C compilation mode and the small model. */

    #include <conio.h>
    #include <dos.h>
    #include “polygon.h”

    /* 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;
    static unsigned int PageStartOffsets[2] =
       {PAGE0_START_OFFSET,PAGE1_START_OFFSET};
    int DisplayedPage, NonDisplayedPage;
    int RecalcAllXforms = 1, NumObjects = 0;
    Xform WorldViewXform;   /* initialized from floats */
    /* pointers to objects */
    Object *ObjectList[MAX_OBJECTS];

    void main() {
       int Done = 0, i;
       Object *ObjectPtr;
       union REGS regset;

       InitializeFixedPoint(); /* set up fixed-point data */
       InitializeCubes();      /* set up cubes and add them to object list; other
                                  objects would be initialized now, if there were any */
       Set320x240Mode();       /* set the screen to mode X */
       ShowPage(PageStartOffsets[DisplayedPage = 0]);
       /* Keep transforming the cube, drawing it to the undisplayed page,
          and flipping the page to show it */
       do {
          /* For each object, regenerate viewing info, if necessary */
          for (i=0; i<NumObjects; i++) {
             if ((ObjectPtr = ObjectList[i])->RecalcXform ||
                   RecalcAllXforms) {
                ObjectPtr->RecalcFunc(ObjectPtr);
                ObjectPtr->RecalcXform = 0;
             }
          }
          RecalcAllXforms = 0;
          CurrentPageBase =    /* select other page for drawing to */
                PageStartOffsets[NonDisplayedPage = DisplayedPage ^ 1];
          /* For each object, clear the portion of the non-displayed page
             that was drawn to last time, then reset the erase extent */
          for (i=0; i<NumObjects; i++) {
             ObjectPtr = ObjectList[i];
             FillRectangleX(ObjectPtr->EraseRect[NonDisplayedPage].Left,
                ObjectPtr->EraseRect[NonDisplayedPage].Top,
                ObjectPtr->EraseRect[NonDisplayedPage].Right,
                ObjectPtr->EraseRect[NonDisplayedPage].Bottom,
                CurrentPageBase, 0);
             ObjectPtr->EraseRect[NonDisplayedPage].Left =
                  ObjectPtr->EraseRect[NonDisplayedPage].Top = 0x7FFF;
             ObjectPtr->EraseRect[NonDisplayedPage].Right =
                   ObjectPtr->EraseRect[NonDisplayedPage].Bottom = 0;
          }
          /* Draw all objects */
          for (i=0; i<NumObjects; i++)
             ObjectList[i]->DrawFunc(ObjectList[i]);
          /* Flip to display the page into which we just drew */
          ShowPage(PageStartOffsets[DisplayedPage = NonDisplayedPage]);
          /* Move and reorient each object */
          for (i=0; i<NumObjects; i++)
             ObjectList[i]->MoveFunc(ObjectList[i]);
          if (kbhit())
             if (getch() == 0x1B) Done = 1;   /* Esc to exit */
       } while (!Done);
       /* Return to text mode and exit */
       regset.x.ax = 0x0003;   /* AL = 3 selects 80x25 text mode */
       int86(0x10, &regset, &regset);
       exit(1);
    }

LISTING 52.2 L52-2.C

    /* Transforms all vertices in the specified polygon-based object into view
       space, then perspective projects them to screen space and maps them to screen
       coordinates, storing results in the object. Recalculates object->view
       transformation because only if transform changes would we bother
       to retransform the vertices. */

    #include <math.h>
    #include “polygon.h”

    void XformAndProjectPObject(PObject * ObjectToXform)
    {
       int i, NumPoints = ObjectToXform->NumVerts;
       Point3 * Points = ObjectToXform->VertexList;
       Point3 * XformedPoints = ObjectToXform->XformedVertexList;
       Point3 * ProjectedPoints = ObjectToXform->ProjectedVertexList;
       Point * ScreenPoints = ObjectToXform->ScreenVertexList;

       /* Recalculate the object->view transform */
       ConcatXforms(WorldViewXform, ObjectToXform->XformToWorld,
                    ObjectToXform->XformToView);
       /* Apply that new transformation and project the points */
       for (i=0; i<NumPoints; i++, Points++, XformedPoints++,
             ProjectedPoints++, ScreenPoints++) {
          /* Transform to view space */
          XformVec(ObjectToXform->XformToView, (Fixedpoint *) Points,
                (Fixedpoint *) XformedPoints);
          /* Perspective-project to screen space */
          ProjectedPoints->X =
                FixedMul(FixedDiv(XformedPoints->X, XformedPoints->Z),
                DOUBLE_TO_FIXED(PROJECTION_RATIO * (SCREEN_WIDTH/2)));
          ProjectedPoints->Y =
                FixedMul(FixedDiv(XformedPoints->Y, XformedPoints->Z),
                DOUBLE_TO_FIXED(PROJECTION_RATIO * (SCREEN_WIDTH/2)));
          ProjectedPoints->Z = XformedPoints->Z;
          /* Convert to screen coordinates. The Y coord is negated to flip from
             increasing Y being up to increasing Y being down, as expected by polygon
             filler. Add in half the screen width and height to center on screen. */
          ScreenPoints->X = ((int) ((ProjectedPoints->X +
                DOUBLE_TO_FIXED(0.5)) >> 16)) + SCREEN_WIDTH/2;
          ScreenPoints->Y = (-((int) ((ProjectedPoints->Y +
                DOUBLE_TO_FIXED(0.5)) >> 16))) + SCREEN_HEIGHT/2;
       }
    }

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash