137 lines
6.2 KiB
Markdown
137 lines
6.2 KiB
Markdown
------------------------ --------------------------------- --------------------
|
||
[Previous](50-03.html) [Table of Contents](index.html) [Next](50-05.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
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](50-03.html) [Table of Contents](index.html) [Next](50-05.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
* * * * *
|
||
|
||
Graphics Programming Black Book © 2001 Michael Abrash
|