home *** CD-ROM | disk | FTP | other *** search
/ Cutting-Edge 3D Game Programming with C++ / CE3DC++.ISO / BOOK / CHAP03 / EXTRA / 3DCLASS.CPP < prev    next >
C/C++ Source or Header  |  1995-10-24  |  19KB  |  662 lines

  1. //
  2. // File name: 3Dclass.CPP
  3. //
  4. // Description: The support file for Polydemo
  5. //
  6. // Author: John De Goes
  7. //
  8. // Project: Cutting Edge 3D Game Programming
  9. //
  10.  
  11. // ------------------------------------------------------------
  12. // | Global include files:                                    |
  13. // ------------------------------------------------------------
  14.  
  15. #include <Math.h>
  16. #include <CType.h>
  17. #include <Conio.h>
  18. #include <Stdio.h>
  19. #include <Stdlib.h>
  20. #include <Iostream.h>
  21.  
  22. // ------------------------------------------------------------
  23. // | Local includes:                                          |
  24. // ------------------------------------------------------------
  25.  
  26. #include "3DClass.HPP"
  27.  
  28. // ------------------------------------------------------------
  29. // | Global variables/constants:                              |
  30. // ------------------------------------------------------------
  31.  
  32. double CosTable [ DEGREECOUNT ];
  33. double SinTable [ DEGREECOUNT ];
  34.  
  35. // ------------------------------------------------------------
  36. // | Local structs/classes:                                   |
  37. // ------------------------------------------------------------
  38.  
  39. // A structure representing a screen edge:
  40. struct EdgeScreen {
  41. long X;
  42. } Left [ 200 ], Right [ 200 ];   
  43.    
  44. // ------------------------------------------------------------
  45. // | Function section:                                        |
  46. // ------------------------------------------------------------
  47.  
  48. void inline CalcFloorRemainder ( long Numerator, long Denominator,
  49.                                    long &Floor, long &Remainder )
  50.    {
  51.    // If Numerator is less than zero, result will not
  52.    // be handled properly; calulate the corrected
  53.    // values:
  54.    if ( Numerator < 0 )
  55.       {
  56.       // Calculate a temporary floor:
  57.       Floor = -((-Numerator) / Denominator);
  58.  
  59.       // Calculate the remainder of Numerator / Denominator
  60.       Remainder = (-Numerator) % Denominator;
  61.  
  62.       if ( Remainder )
  63.          {
  64.          --Floor; Remainder = Denominator - Remainder;
  65.          }
  66.       }
  67.    // Else Numerator is positive; result handled
  68.    // properly:
  69.    else {
  70.         Floor = Numerator / Denominator;
  71.         Remainder = Numerator % Denominator;
  72.         }
  73.    }                
  74.  
  75.  
  76. // Initiate math function - calculates trig tables:
  77. void InitMath()
  78.     {
  79.     long double Unit = (long double)( PI * 2.0F ) / 
  80.               (long double)DEGREECOUNT;
  81.     for ( unsigned int i = 0; i < DEGREECOUNT; i++ )
  82.          {
  83.        long double Degree = (long double)i;
  84.          CosTable[i] = cos ( Unit * Degree );
  85.          SinTable[i] = sin ( Unit * Degree );
  86.          }
  87.     }
  88.  
  89.  
  90. // Function designed to get a word from a file:
  91. char *GetWord ( FILE *File, char *String )
  92.    {
  93.    int NextChar = fgetc ( File );
  94.    int Index = 0;
  95.    // Skip the spaces:
  96.    while ( isspace ( NextChar ) )
  97.      {
  98.      NextChar = fgetc ( File );
  99.      if ( NextChar == EOF )
  100.         {
  101.         String [ Index ] = NULL;
  102.         return NULL;
  103.         }
  104.      }
  105.    // Record the characters:
  106.    while ( !isspace ( NextChar ) )
  107.      {
  108.      String [ Index++ ] = ( char ) NextChar;
  109.      NextChar = fgetc ( File );
  110.      if ( NextChar == EOF )
  111.         {
  112.         String [ Index ] = NULL;
  113.         return NULL;
  114.         }
  115.      }
  116.    String [ Index ] = NULL;      
  117.    return String;
  118.    }   
  119.  
  120. // Function designed to count the number of triangles
  121. // in a RAW file:
  122. int CountTriangles ( char *FileName )
  123.   {
  124.   char Dummy [ 100 ];
  125.   unsigned int VertCount = 0;
  126.   FILE *File;
  127.   if ( ( File = fopen ( FileName, "rt" ) ) == 0 )
  128.      return 0;
  129.   while ( GetWord ( File, Dummy ) != NULL )
  130.         ++VertCount;
  131.   fclose ( File );
  132.   unsigned int TriCount = VertCount / 9; // Nine verts per 
  133.   return TriCount;                        // triangle
  134.   }    
  135.  
  136. void inline ClipX1X2 ( long &X1, long &X2 )
  137.    {
  138.    // Clip a horizontal line:
  139.    if ( X1 < 0 )
  140.       X1 = 0;
  141.    if ( X1 > 319 )
  142.       X1 = 319;
  143.    if ( X2 < 0 )
  144.       X2 = 0;   
  145.    if ( X2 > 319 )
  146.      X2 = 319;
  147.    }
  148.  
  149. void inline ClipY1Y2 ( long &Y1, long &Y2 )
  150.    {
  151.    // Clip a vertical line:
  152.    if ( Y1 < 0 )
  153.       Y1 = 0;
  154.    if ( Y1 > 199 )
  155.       Y1 = 199;
  156.    if ( Y2 < 0 )
  157.       Y2 = 0;
  158.    if ( Y2 > 199 )
  159.       Y2 = 199;   
  160.    }
  161.    
  162. // Function designed to step along polygon edge:
  163. void inline PolyEdge::Step ()
  164.    {
  165.    X += StepX; Y += StepY;
  166.    ErrorTerm += Numerator;
  167.    if ( ErrorTerm >= Denominator )
  168.       {
  169.       ++X;
  170.       ErrorTerm -= Denominator;
  171.       }
  172.    --EdgeHeight;
  173.    }
  174.    
  175. // Function designed to initialize stepping values for
  176. // a polygon edge:
  177. void PolyEdge::Initialize ( ScreenVertex &P1, 
  178.                              ScreenVertex &P2 )
  179.    {
  180.    long Width = P2.X - P1.X;
  181.    Y = P1.Y; StepY = 1;
  182.    EdgeHeight = P2.Y - P1.Y;
  183.    // Make sure the polygon edge has a definite height
  184.    // before we make some rather complex calculations:
  185.    if ( EdgeHeight > 0 )
  186.       {
  187.       CalcFloorRemainder ( -1, EdgeHeight, X, ErrorTerm);
  188.       X += P1.X + 1;
  189.       CalcFloorRemainder ( Width, EdgeHeight, StepX, Numerator );
  190.       Denominator = EdgeHeight;
  191.       }
  192.    }  
  193.    
  194. // Function designed to set matrix to identity matrix:
  195. void Matrix3D::Initialize ()
  196.    {
  197.    Matrix[0][0] = 1;  Matrix[0][1] = 0;  Matrix[0][2] = 0;  Matrix[0][3] = 0;
  198.    Matrix[1][0] = 0;  Matrix[1][1] = 1;  Matrix[1][2] = 0;  Matrix[1][3] = 0;
  199.    Matrix[2][0] = 0;  Matrix[2][1] = 0;  Matrix[2][2] = 1;  Matrix[2][3] = 0;
  200.    Matrix[3][0] = 0;  Matrix[3][1] = 0;  Matrix[3][2] = 0;  Matrix[3][3] = 1;
  201.    }
  202.    
  203. // Function that merges two matrices - try to avoid calling this function
  204. // very often.
  205. void Matrix3D::MergeMatrix ( double NewMatrix [ 4 ] [ 4 ] )
  206.    {
  207.    // Multiply NewMatirx by Matrix; store result in TempMatrix
  208.    double TempMatrix [ 4 ] [ 4 ];
  209.     for (short unsigned int i = 0; i < 4; i++)
  210.          for (short unsigned int j = 0; j < 4; j++) 
  211.               TempMatrix[i][j] = (Matrix[i][0] * NewMatrix[0][j])
  212.                             + (Matrix[i][1] * NewMatrix[1][j])
  213.                             + (Matrix[i][2] * NewMatrix[2][j])
  214.                             + (Matrix[i][3] * NewMatrix[3][j]);
  215.    // Copy TempMatrix to Matrix
  216.    for (i = 0; i < 4; i++)
  217.        {
  218.        Matrix[i][0] = TempMatrix[i][0];
  219.        Matrix[i][1] = TempMatrix[i][1];
  220.        Matrix[i][2] = TempMatrix[i][2];
  221.        Matrix[i][3] = TempMatrix[i][3];
  222.        }
  223.    }
  224.    
  225. // Function designed to merge rotation matrices with master
  226. // matrix:
  227. void  Matrix3D::Rotate ( int Xa, int Ya, int Za )
  228.    {
  229.    Xr = Xa; Yr = Ya; Zr = Za;
  230.    double Rmat [ 4 ] [ 4 ];
  231.  
  232.    // Initialize Z rotation matrix - Note: we perform Z
  233.    // rotation first to align the 3D Z axis with the 2D Z axis.
  234.    Rmat[0][0]=COS(Za);  Rmat[0][1]=SIN(Za);  Rmat[0][2]=0;    Rmat[0][3]=0;
  235.    Rmat[1][0]=-SIN(Za); Rmat[1][1]=COS(Za);  Rmat[1][2]=0;    Rmat[1][3]=0;
  236.    Rmat[2][0]=0;        Rmat[2][1]=0;        Rmat[2][2]=1;    Rmat[2][3]=0;
  237.    Rmat[3][0]=0;        Rmat[3][1]=0;        Rmat[3][2]=0;    Rmat[3][3]=1;
  238.  
  239.    // Merge matrix with master matrix:
  240.    MergeMatrix ( Rmat );
  241.    
  242.    // Initialize X rotation matrix:
  243.    Rmat[0][0]=1;  Rmat[0][1]=0;        Rmat[0][2]=0;       Rmat[0][3]=0;
  244.    Rmat[1][0]=0;  Rmat[1][1]=COS(Xa);  Rmat[1][2]=SIN(Xa); Rmat[1][3]=0;
  245.    Rmat[2][0]=0;  Rmat[2][1]=-SIN(Xa); Rmat[2][2]=COS(Xa); Rmat[2][3]=0;
  246.    Rmat[3][0]=0;  Rmat[3][1]=0;        Rmat[3][2]=0;       Rmat[3][3]=1;
  247.  
  248.    // Merge matrix with master matrix:
  249.    MergeMatrix ( Rmat );
  250.  
  251.    // Initialize Y rotation matrix:
  252.    Rmat[0][0]=COS(Ya); Rmat[0][1]=0;   Rmat[0][2]=-SIN(Ya); Rmat[0][3]=0;
  253.    Rmat[1][0]=0;       Rmat[1][1]=1;   Rmat[1][2]=0;        Rmat[1][3]=0;
  254.    Rmat[2][0]=SIN(Ya); Rmat[2][1]=0;   Rmat[2][2]=COS(Ya);  Rmat[2][3]=0;
  255.    Rmat[3][0]=0;       Rmat[3][1]=0;   Rmat[3][2]=0;        Rmat[3][3]=1;
  256.  
  257.    // Merge matrix with master matrix:
  258.    MergeMatrix ( Rmat );
  259.    }
  260.    
  261. // Function designed to merge translation matrix with master
  262. // matrix:
  263. void  Matrix3D::Translate ( double Xt, double Yt, double Zt )
  264.    {
  265.    double Tmat [ 4 ] [ 4 ];
  266.  
  267.    // Initialize translation matrix:
  268.    Tmat[0][0]=1;  Tmat[0][1]=0;  Tmat[0][2]=0;  Tmat[0][3]=0;
  269.    Tmat[1][0]=0;  Tmat[1][1]=1;  Tmat[1][2]=0;  Tmat[1][3]=0;
  270.    Tmat[2][0]=0;  Tmat[2][1]=0;  Tmat[2][2]=1;  Tmat[2][3]=0;
  271.    Tmat[3][0]=Xt; Tmat[3][1]=Yt; Tmat[3][2]=Zt; Tmat[3][3]=1;
  272.  
  273.    // Merge matrix with master matrix:
  274.    MergeMatrix ( Tmat );
  275.    }
  276.    
  277. // Function designed to merge scaling matrix with master
  278. // matrix:
  279. void  Matrix3D::Scale ( double Xs, double Ys, double Zs )
  280.    {
  281.    double Smat [ 4 ] [ 4 ];
  282.    
  283.    // Initialize scaling matrix:
  284.    Smat[0][0] = Xs; Smat[0][1] = 0;  Smat[0][2] = 0;  Smat[0][3] = 0;
  285.    Smat[1][0] = 0;  Smat[1][1] = Ys; Smat[1][2] = 0;  Smat[1][3] = 0;
  286.    Smat[2][0] = 0;  Smat[2][1] = 0;  Smat[2][2] = Zs; Smat[2][3] = 0;
  287.    Smat[3][0] = 0;  Smat[3][1] = 0;  Smat[3][2] = 0;  Smat[3][3] = 1;
  288.  
  289.    // Merge matrix with master matrix:
  290.    MergeMatrix ( Smat );
  291.    }
  292.  
  293. // Function designed to merge shearing matrix with master
  294. // matrix - warps true x, y values:
  295. void  Matrix3D::Shear ( double Xs, double Ys )
  296.    {
  297.    double Smat [ 4 ] [ 4 ];
  298.    
  299.    // Initialize shearing matrix:
  300.    Smat[0][0] = 1;  Smat[0][1] = 0;  Smat[0][2] = Xs;  Smat[0][3] = 0;
  301.    Smat[1][0] = 0;  Smat[1][1] = 1;  Smat[1][2] = Ys;  Smat[1][3] = 0;
  302.    Smat[2][0] = 0;  Smat[2][1] = 0;  Smat[2][2] = 1;   Smat[2][3] = 0;
  303.    Smat[3][0] = 0;  Smat[3][1] = 0;  Smat[3][2] = 0;   Smat[3][3] = 1;
  304.  
  305.    // Merge matrix with master matrix:
  306.    MergeMatrix ( Smat );
  307.    }
  308.  
  309. // Function designed to multiply a vertex by the master
  310. // matrix:   
  311. Vertex inline &Matrix3D::Transform ( Vertex &V )
  312.    {
  313.    // Initialize temporary variables:
  314.    double OldX = V.Wx;
  315.    double OldY = V.Wy;
  316.    double OldZ = V.Wz;
  317.  
  318.    // Transform vertex by master matrix:
  319.    V.Wx = ( (  OldX * Matrix[0][0]) )
  320.           + ( (OldY * Matrix[1][0]) )
  321.           + ( (OldZ * Matrix[2][0]) )
  322.           + Matrix[3][0];
  323.  
  324.    V.Wy = (   (OldX * Matrix[0][1]) )
  325.           + ( (OldY * Matrix[1][1]) )
  326.           + ( (OldZ * Matrix[2][1]) )
  327.           + Matrix[3][1];
  328.  
  329.    V.Wz = (   (OldX * Matrix[0][2]) )
  330.           + ( (OldY * Matrix[1][2]) )
  331.           + ( (OldZ * Matrix[2][2]) )
  332.           + Matrix[3][2];
  333.    return V;
  334.    }
  335.    
  336. // Function designed to multiply a vector by the master
  337. // matrix:   
  338. Vector inline &Matrix3D::Transform ( Vector &V )
  339.    {
  340.    // Initialize temporary variables:
  341.    double OldX = V.X;
  342.    double OldY = V.Y;
  343.    double OldZ = V.Z;
  344.      
  345.    // Rotate normal around Z axis:
  346.    V.X = OldX * COS ( Zr ) - OldY * SIN ( Zr );
  347.    V.Y = OldX * SIN ( Zr ) + OldY * COS ( Zr );
  348.    
  349.    // Rotate normal around X axis:
  350.    OldY = V.Y;
  351.    V.Y = OldY * COS ( Xr ) - OldZ * SIN ( Xr );
  352.    V.Z = OldY * SIN ( Xr ) + OldZ * COS ( Xr );
  353.    
  354.    // Rotate normal around Y axis:
  355.    OldX = V.X; OldZ = V.Z;
  356.    V.X = OldZ * SIN ( Yr ) + OldX * COS ( Yr );
  357.    V.Z = OldZ * COS ( Yr ) - OldX * SIN ( Yr );
  358.    
  359.    return V;
  360.    }
  361.  
  362. // Function designed to multiply a triangle's vertices by matrix
  363. // "Matrix":
  364. void Triangle::Transform ( Matrix3D &Matrix )
  365.    {
  366.    // Transform the surface normal:
  367.    Matrix.Transform ( Normal );
  368.  
  369.    // Update the triangle's vertices:
  370.    Matrix.Transform ( VPoint [ 0 ] );
  371.    Matrix.Transform ( VPoint [ 1 ] );
  372.    Matrix.Transform ( VPoint [ 2 ] );
  373.    }
  374.    
  375. // Function designed to determine if triangle is a back-
  376. // face:
  377. void Triangle::Backface ()
  378.    {
  379.    const TRUE = 1, FALSE = 0;
  380.    double VX = ( VPoint [ 0 ].Wx );
  381.    double VY = ( VPoint [ 0 ].Wy );
  382.    double VZ = ( VPoint [ 0 ].Wz );
  383.    
  384.    double CosA = ( VX * Normal.X + VY * Normal.Y + 
  385.                    VZ * Normal.Z );
  386.    if ( CosA > 0.0F )
  387.       Visible = FALSE;
  388.  
  389.    else Visible = TRUE;
  390.    }
  391.   
  392. // Function designed to calculate a polygon normal:  
  393. void Triangle::CalculateNormal ()
  394.    {
  395.    long double X1 = VPoint [0].Wx;
  396.    long double Y1 = VPoint [0].Wy;
  397.    long double Z1 = VPoint [0].Wz;
  398.  
  399.    long double X2 = VPoint [1].Wx;
  400.    long double Y2 = VPoint [1].Wy;
  401.    long double Z2 = VPoint [1].Wz;
  402.  
  403.    long double X3 = VPoint [2].Wx;
  404.    long double Y3 = VPoint [2].Wy;
  405.    long double Z3 = VPoint [2].Wz;
  406.  
  407.    // Use plane equation to determine plane's orientation:
  408.    long double A = Y1 * ( Z2 - Z3 ) + Y2 * ( Z3 - Z1 ) + Y3 * ( Z1 - Z2 );
  409.    long double B = Z1 * ( X2 - X3 ) + Z2 * ( X3 - X1 ) + Z3 * ( X1 - X2 );
  410.    long double C = X1 * ( Y2 - Y3 ) + X2 * ( Y3 - Y1 ) + X3 * ( Y1 - Y2 );
  411.    
  412.    long double Distance = sqrt ( A*A + B*B + C*C );
  413.    
  414.    // Normalize the normal:
  415.    Normal.X = A / Distance;
  416.    Normal.Y = B / Distance;
  417.    Normal.Z = C / Distance;
  418.    }
  419.   
  420. // Function designed to load a triangle from a 
  421. // RAW file:
  422. int Triangle::Load ( FILE *File )
  423.   {
  424.   int RValue = 1;
  425.   char String [ 100 ];
  426.   // Load nine floating-point values:
  427.   for ( unsigned int Index = 0; Index < 3; Index++ )
  428.       {
  429.       VPoint [ Index ].Wx = atof ( GetWord ( File, String ) );
  430.       VPoint [ Index ].Wy = atof ( GetWord ( File, String ) );
  431.       VPoint [ Index ].Wz = atof ( GetWord ( File, String ) );
  432.       if ( String == NULL )
  433.          {
  434.          RValue = 0;
  435.          break;
  436.          }
  437.       }
  438.   
  439.   // Assign a random shade of gray to the triangle:
  440.   Color = ( unsigned char ) ( random ( 5 ) + 20 );
  441.   
  442.   // Calculate triangle's normal:
  443.   CalculateNormal ();
  444.  
  445.   return RValue;
  446.   }
  447.  
  448. // Function designed to project a triangle onto
  449. // the viewport:  
  450. void Triangle::Project ()
  451.    {
  452.    for ( unsigned int Count = 0; Count < 3; Count++ )
  453.        {
  454.        double X = VPoint [ Count ].Wx;
  455.        double Y = VPoint [ Count ].Wy;
  456.        double Z = VPoint [ Count ].Wz;
  457.        // If Z is less than or equal to zero...
  458.        if ( Z <= 0.0F )
  459.           {
  460.           // ...cheat! No one will ever know...
  461.           Z = 1.0F;
  462.           }
  463.        // Perform perspective projection:
  464.        double OneOverZ = 1.0F / Z;
  465.        SPoint [ Count ].X = X * 120.0F * OneOverZ + 160;
  466.        SPoint [ Count ].Y = Y * -120.0F * OneOverZ + 100;
  467.        }
  468.    }
  469.  
  470.   
  471. // Function designed to draw a triangle on a linear buffer:
  472. void Triangle::Rasterize ( unsigned char *Dest )
  473.    {
  474.    PolyEdge ScanEdge;
  475.    // Assume element 0 is top/bottom of polygon:
  476.  
  477.    long TopE = 0, BotE = 0, VertCount = 3, Vert1, Vert2;
  478.    long Top, Bot, X1, X2, Width, YIndex, Y, Temp, Check;
  479.    unsigned Height, Yh;
  480.    
  481.    // Assume SPoint[0] is top/bottom of polygon:
  482.    long TopY = SPoint [ 0 ].Y, BotY = SPoint [ 0 ].Y;              
  483.  
  484.    // Attempt to verify previous assumptions:
  485.    for ( Check = 1; Check < VertCount; Check++ )
  486.        {
  487.        if ( TopY > SPoint [ Check ].Y )
  488.           {
  489.           TopY = SPoint [ Check ].Y;
  490.           TopE = Check;
  491.           }
  492.        else if ( BotY < SPoint [ Check ].Y )
  493.                {
  494.                BotY = SPoint [ Check ].Y;
  495.                BotE = Check;
  496.                }
  497.        }
  498.  
  499.    Vert1 = TopE, Vert2 = TopE - 1;
  500.    
  501.    // Check for wrap:
  502.    if ( Vert2 < 0 )
  503.       Vert2 = (VertCount - 1);
  504.       
  505.    // Scan convert the left polygon edge:
  506.    while ( Vert1 != BotE )
  507.          {
  508.          ScanEdge.Initialize ( SPoint [ Vert1 ], 
  509.                                 SPoint [ Vert2 ] );
  510.          Height = ScanEdge.Height ();
  511.          // Loop for the height of the polygon edge:
  512.          for ( Yh = 0; Yh < Height; Yh++ )
  513.              {
  514.              Y = ScanEdge.GetY ();
  515.              // If the scanline's on the scren....
  516.              if ( Y >= 0 )
  517.                 {
  518.                 if ( Y <= 199 )
  519.                    {
  520.                    // ...record it:
  521.                    Left [ Y ].X = ScanEdge.GetX ();
  522.                    }
  523.                 else break;
  524.                 }   
  525.              ++ScanEdge;
  526.              }
  527.          Temp = Vert1;
  528.          Vert1 = Vert2;
  529.          Vert2 = Temp - 1;
  530.          // Check for wrap:
  531.          if ( Vert2 < 0 )
  532.             Vert2 = (VertCount - 1);
  533.          }
  534.       
  535.    Vert1 = TopE, Vert2 = ( TopE + 1 );
  536.    
  537.    // Check for wrap:
  538.    if ( Vert2 > ( VertCount - 1 ) )
  539.       Vert2 = 0;
  540.       
  541.    // Scan convert the right polygon edge:
  542.    while ( Vert1 != BotE )
  543.          {
  544.          ScanEdge.Initialize ( SPoint [ Vert1 ], 
  545.                                 SPoint [ Vert2 ] );
  546.          Height = ScanEdge.Height ();
  547.          // Loop for the height of the polygon edge:
  548.          for ( Yh = 0; Yh < Height; Yh++ )
  549.              {
  550.              Y = ScanEdge.GetY ();
  551.              // If the scanline's on the screen....
  552.              if ( Y >= 0 )
  553.                 {
  554.                 if ( Y <= 199 )
  555.                    {
  556.                    // ...record it:
  557.                    Right [ Y ].X = ScanEdge.GetX ();
  558.                    }
  559.                 else break;   
  560.                 }
  561.              ++ScanEdge;
  562.              }
  563.          Temp = Vert1;
  564.          Vert1 = Vert2;
  565.          Vert2 = ( Temp + 1 );
  566.          // Check for wrap:
  567.          if ( Vert2 > ( VertCount - 1 ) )
  568.             Vert2 = 0;
  569.          }
  570.  
  571.    Top = TopY; Bot = BotY;
  572.  
  573.    // Clip the top and bottom coordinates:
  574.    ClipY1Y2 ( Top, Bot );
  575.  
  576.    // Locate the Y start of the first scanline:
  577.    YIndex = Top * 320;
  578.  
  579.    // Loop for the height of the polygon:
  580.    for ( Y = Top; Y < Bot; Y++ )
  581.        {
  582.        // Find the coordinates of the left and right
  583.        // polygons edges:
  584.        X1 = Left [ Y ].X;
  585.        X2 = Right [ Y ].X;
  586.  
  587.        // Clip same:
  588.        ClipX1X2 ( X1, X2 );
  589.  
  590.        // Determine the width of the scanline:
  591.        Width = ( X2 - X1 );
  592.  
  593.        // Make sure there's something to draw:
  594.        if ( Width > 0 )
  595.           {
  596.           // Draw the scanline:
  597.           unsigned int Index = YIndex + X1;
  598.           setmem ( Dest + Index, Width, Color );         
  599.           }
  600.               
  601.        // Increment the buffer index:
  602.        YIndex += 320;
  603.        }
  604.    }
  605.  
  606.  
  607. // Function designed to display a triangle on a linear buffer:
  608. void inline Triangle::Display ( unsigned char *Buffer )
  609.    {
  610.    Backface ();
  611.    if ( Visible )
  612.       {
  613.       Project ();
  614.       Rasterize ( Buffer );
  615.       }
  616.    }
  617.   
  618. // Function designed to load an entire triangle world:
  619. int TriangleWorld::Load ( char *FileName )
  620.   {
  621.   FILE *File;
  622.   TriCount = CountTriangles ( FileName );
  623.   if ( TriCount <= 0 )
  624.      return 0;
  625.   if ( ( File = fopen ( FileName, "rt" ) ) == 0 )
  626.      return 0;
  627.   if ( ( World = new Triangle [ TriCount ] ) == 0 )
  628.      {
  629.      fclose ( File );
  630.      return 0;
  631.      }
  632.   for ( unsigned int Count = 0; Count < TriCount; Count++ )
  633.       {
  634.       if ( !World [ Count ].Load ( File ) )
  635.          {
  636.          fclose ( File );
  637.          delete [] World;
  638.          return 0;
  639.          }
  640.       }
  641.   fclose ( File );
  642.   return 1;    
  643.   }
  644.  
  645. // Function designed to transform an entire triangle world:  
  646. void TriangleWorld::Transform ( Matrix3D &Matrix )
  647.    {
  648.    for ( unsigned int Count = 0; Count < TriCount; Count++ )
  649.        {
  650.        World [ Count ].Transform ( Matrix );
  651.        }
  652.    }
  653.  
  654. // Function designed to display an entire world:
  655. void TriangleWorld::Display ( unsigned char *Buffer )
  656.    {
  657.    for ( unsigned int Count = 0; Count < TriCount; Count++ )
  658.        {
  659.        World [ Count ].Display ( Buffer );
  660.        }
  661.    }
  662.