abrash-black-book/51-05.md
2013-12-30 20:26:41 +11:00

97 lines
5.3 KiB
Markdown

With the above optimizations, the sample program is certainly adequately
responsive on a 20 MHz 386 (sans 387; I'm sure it's wonderfully
responsive with a math coprocessor). Still, it couldn't quite keep up
with the keyboard when I modified it to read only one key each time
through the loop—and we're talking about only eight vertices here. This
indicates that we're already near the limit of animation complexity
possible with our current approach. It's time to start rethinking that
approach; over two-thirds of the overall time is spent in floating-point
calculations, and it's there that we'll begin to attack the performance
bottleneck we find ourselves up against.
### Incremental Transformation {#Heading5}
Listing 51.4 contains three functions; each concatenates an additional
rotation around one of the three axes to an existing rotation. To
improve performance, only the matrix entries that are affected in a
rotation around each particular axis are recalculated (all but four of
the entries in a single-axis rotation matrix are either 0 or 1, as shown
in Chapter 50). This cuts the number of floating-point multiplies from
the 64 required for the multiplication of two 4x4 matrices to just 12,
and floating point adds from 48 to 6.
Be aware that Listing 51.4 performs an incremental rotation on top of
whatever rotation is already in the matrix. The cube may already have
been turned left, right, up, down, and sideways; regardless, Listing
51.4 just tacks the specified rotation onto whatever already exists. In
this way, the object-to-world transformation matrix contains a history
of all the rotations ever specified by the user, concatenated one after
another onto the original matrix. Potential loss of precision is a
problem associated with using such an approach to represent a very long
concatenation of transformations, especially with fixed-point
arithmetic; that's not a problem for us yet, but we'll run into it
eventually.
**LISTING 51.4 L51-4.C**
/* Routines to perform incremental rotations around the three axes */
#include <math.h>
#include "polygon.h"
/* Concatenate a rotation by Angle around the X axis to the transformation in
XformToChange, placing result back in XformToChange. */
void AppendRotationX(double XformToChange[4][4], double Angle)
{
double Temp10, Temp11, Temp12, Temp20, Temp21, Temp22;
double CosTemp = cos(Angle), SinTemp = sin(Angle);
/* Calculate the new values of the four affected matrix entries */
Temp10 = CosTemp*XformToChange[1][0]+ -SinTemp*XformToChange[2][0];
Temp11 = CosTemp*XformToChange[1][1]+ -SinTemp*XformToChange[2][1];
Temp12 = CosTemp*XformToChange[1][2]+ -SinTemp*XformToChange[2][2];
Temp20 = SinTemp*XformToChange[1][0]+ CosTemp*XformToChange[2][0];
Temp21 = SinTemp*XformToChange[1][1]+ CosTemp*XformToChange[2][1];
Temp22 = SinTemp*XformToChange[1][2]+ CosTemp*XformToChange[2][2];
/* Put the results back into XformToChange */
XformToChange[1][0] = Temp10; XformToChange[1][1] = Temp11;
XformToChange[1][2] = Temp12; XformToChange[2][0] = Temp20;
XformToChange[2][1] = Temp21; XformToChange[2][2] = Temp22;
}
/* Concatenate a rotation by Angle around the Y axis to the transformation in
XformToChange, placing result back in XformToChange. */
void AppendRotationY(double XformToChange[4][4], double Angle)
{
double Temp00, Temp01, Temp02, Temp20, Temp21, Temp22;
double CosTemp = cos(Angle), SinTemp = sin(Angle);
/* Calculate the new values of the four affected matrix entries */
Temp00 = CosTemp*XformToChange[0][0]+ SinTemp*XformToChange[2][0];
Temp01 = CosTemp*XformToChange[0][1]+ SinTemp*XformToChange[2][1];
Temp02 = CosTemp*XformToChange[0][2]+ SinTemp*XformToChange[2][2];
Temp20 = -SinTemp*XformToChange[0][0]+ CosTemp*XformToChange[2][0];
Temp21 = -SinTemp*XformToChange[0][1]+ CosTemp*XformToChange[2][1];
Temp22 = -SinTemp*XformToChange[0][2]+ CosTemp*XformToChange[2][2];
/* Put the results back into XformToChange */
XformToChange[0][0] = Temp00; XformToChange[0][1] = Temp01;
XformToChange[0][2] = Temp02; XformToChange[2][0] = Temp20;
XformToChange[2][1] = Temp21; XformToChange[2][2] = Temp22;
}
/* Concatenate a rotation by Angle around the Z axis to the transformation in
XformToChange, placing result back in XformToChange. */
void AppendRotationZ(double XformToChange[4][4], double Angle)
{
double Temp00, Temp01, Temp02, Temp10, Temp11, Temp12;
double CosTemp = cos(Angle), SinTemp = sin(Angle);
/* Calculate the new values of the four affected matrix entries */
Temp00 = CosTemp*XformToChange[0][0]+ -SinTemp*XformToChange[1][0];
Temp01 = CosTemp*XformToChange[0][1]+ -SinTemp*XformToChange[1][1];
Temp02 = CosTemp*XformToChange[0][2]+ -SinTemp*XformToChange[1][2];
Temp10 = SinTemp*XformToChange[0][0]+ CosTemp*XformToChange[1][0];
Temp11 = SinTemp*XformToChange[0][1]+ CosTemp*XformToChange[1][1];
Temp12 = SinTemp*XformToChange[0][2]+ CosTemp*XformToChange[1][2];
/* Put the results back into XformToChange */
XformToChange[0][0] = Temp00; XformToChange[0][1] = Temp01;
XformToChange[0][2] = Temp02; XformToChange[1][0] = Temp10;
XformToChange[1][1] = Temp11; XformToChange[1][2] = Temp12;
}