125 lines
5.7 KiB
Markdown
125 lines
5.7 KiB
Markdown
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);
|
|
}
|