Previous | Table of Contents | Next

LISTING 54.2 DRAWPOBJ.C

    /* Draws all visible faces in the specified polygon-based object. The object
       must have previously been transformed and projected, so that all vertex
       arrays are filled in. Ambient and diffuse shading are supported. */
    #include "polygon.h"

    void DrawPObject(PObject * ObjectToXform)
    {
       int i, j, NumFaces = ObjectToXform->NumFaces, NumVertices;
       int * VertNumsPtr, Spot;
       Face * FacePtr = ObjectToXform->FaceList;
       Point * ScreenPoints = ObjectToXform->ScreenVertexList;
       PointListHeader Polygon;
       Fixedpoint Diffusion;
       ModelColor ColorTemp;
       ModelIntensity IntensityTemp;
       Point3 UnitNormal, *NormalStartpoint, *NormalEndpoint;
       long v1, v2, w1, w2;
       Point Vertices[MAX-POLY-LENGTH];

       /* Draw each visible face (polygon) of the object in turn */
       for (i=0; i<NumFaces; i++, FacePtr++) {
          /* Remember where we can find the start and end of the polygon's
             unit normal in view space, and skip over the unit normal endpoint
             entry. The end and start points of the unit normal to the polygon
             must be the first and second entries in the polgyon's vertex list.
             Note that the second point is also an active polygon vertex */
          VertNumsPtr = FacePtr->VertNums;
          NormalEndpoint = &ObjectToXform->XformedVertexList[*VertNumsPtr++];
          NormalStartpoint = &ObjectToXform->XformedVertexList[*VertNumsPtr];
          /* Copy over the face's vertices from the vertex list */
          NumVertices = FacePtr->NumVerts;
          for (j=0; j<NumVertices; j++)
             Vertices[j] = ScreenPoints[*VertNumsPtr++];
          /* Draw only if outside face showing (if the normal to the polygon
             in screen coordinates points toward the viewer; that is, has a
             positive Z component) */
          v1 = Vertices[1].X - Vertices[0].X;
          w1 = Vertices[NumVertices-1].X - Vertices[0].X;
          v2 = Vertices[1].Y - Vertices[0].Y;
          w2 = Vertices[NumVertices-1].Y - Vertices[0].Y;
          if ((v1*w2 - v2*w1) > 0) {
             /* It is facing the screen, so draw */
             /* Appropriately adjust the extent of the rectangle used to
                erase this object later */
             for (j=0; j<NumVertices; j++) {
                if (Vertices[j].X >
                      ObjectToXform->EraseRect[NonDisplayedPage].Right)
                   if (Vertices[j].X < SCREEN-WIDTH)
                      ObjectToXform->EraseRect[NonDisplayedPage].Right =
                            Vertices[j].X;
                   else ObjectToXform->EraseRect[NonDisplayedPage].Right =
                         SCREEN-WIDTH;
                if (Vertices[j].Y >
                      ObjectToXform->EraseRect[NonDisplayedPage].Bottom)
                   if (Vertices[j].Y < SCREEN-HEIGHT)
                      ObjectToXform->EraseRect[NonDisplayedPage].Bottom =
                            Vertices[j].Y;
                   else ObjectToXform->EraseRect[NonDisplayedPage].Bottom=
                         SCREEN-HEIGHT;
                if (Vertices[j].X <
                      ObjectToXform->EraseRect[NonDisplayedPage].Left)
                   if (Vertices[j].X > 0)
                      ObjectToXform->EraseRect[NonDisplayedPage].Left =
                            Vertices[j].X;
                   else ObjectToXform->EraseRect[NonDisplayedPage].Left=0;
                if (Vertices[j].Y <
                      ObjectToXform->EraseRect[NonDisplayedPage].Top)
                   if (Vertices[j].Y > 0)
                      ObjectToXform->EraseRect[NonDisplayedPage].Top =
                            Vertices[j].Y;
                   else ObjectToXform->EraseRect[NonDisplayedPage].Top=0;
             }
             /* See if there's any shading */
                if (FacePtr->ShadingType == 0) {
                /* No shading in effect, so just draw */
                DRAW-POLYGON(Vertices, NumVertices, FacePtr->ColorIndex, 0, 0);
             } else {
                /* Handle shading */
                /* Do ambient shading, if enabled */
                if (AmbientOn && (FacePtr->ShadingType & AMBIENT-SHADING)) {
                   /* Use the ambient shading component */
                   IntensityTemp = AmbientIntensity;
                } else {
                   SET-INTENSITY(IntensityTemp, 0, 0, 0);
                }
                /* Do diffuse shading, if enabled */
                if (FacePtr->ShadingType & DIFFUSE-SHADING) {
                   /* Calculate the unit normal for this polygon, for use in dot
                      products */
                   UnitNormal.X = NormalEndpoint->X - NormalStartpoint->X;
                   UnitNormal.Y = NormalEndpoint->Y - NormalStartpoint->Y;
                   UnitNormal.Z = NormalEndpoint->Z - NormalStartpoint->Z;
                   /* Calculate the diffuse shading component for each active
                      spotlight */
                   for (Spot=0; Spot<MAX-SPOTS; Spot++) {
                      if (SpotOn[Spot] != 0) {
                         /* Spot is on, so sum, for each color component, the
                            intensity, accounting for the angle of the light rays
                            relative to the orientation of the polygon */
                         /* Calculate cosine of angle between the light and the
                            polygon normal; skip if spot is shining from behind
                            the polygon */
                         if ((Diffusion = DOT-PRODUCT(SpotDirectionView[Spot],
                               UnitNormal)) > 0) {
                            IntensityTemp.Red +=
                                  FixedMul(SpotIntensity[Spot].Red, Diffusion);
                            IntensityTemp.Green +=
                                  FixedMul(SpotIntensity[Spot].Green, Diffusion);
                            IntensityTemp.Blue +=
                                  FixedMul(SpotIntensity[Spot].Blue, Diffusion);
                         }
                      }
                   }
                }
                /* Convert the drawing color to the desired fraction of the
                   brightest possible color */
                IntensityAdjustColor(&ColorTemp, &FacePtr->FullColor,
                      &IntensityTemp);
                /* Draw with the cumulative shading, converting from the general
                   color representation to the best-match color index */
                DRAW-POLYGON(Vertices, NumVertices,
                      ModelColorToColorIndex(&ColorTemp), 0, 0);
             }
          }
       }
    }

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash