**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 #include #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; iRecalcXform || 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; iEraseRect[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; iDrawFunc(ObjectList[i]); /* Flip to display the page into which we just drew */ ShowPage(PageStartOffsets[DisplayedPage = NonDisplayedPage]); /* Move and reorient each object */ for (i=0; iMoveFunc(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, ®set, ®set); 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 #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; iXformToView, (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; } }