home *** CD-ROM | disk | FTP | other *** search
/ Cutting-Edge 3D Game Programming with C++ / CE3DC++.ISO / BOOK / CHAP12 / PANEL3D.CPP < prev    next >
C/C++ Source or Header  |  1996-04-23  |  36KB  |  1,039 lines

  1. //
  2. // File name: Panel3D.CPP
  3. //
  4. // Description: The support files for the Panel3D.HPP header
  5. //
  6. // Author: John De Goes
  7. //
  8. // Project: Cutting SPoint 3D Game Programming
  9. //
  10.  
  11. #include <Math.H>
  12. #include <Stdlib.H>
  13. #include <String.H>
  14.  
  15. #include "Panel3D.HPP"
  16. #include "LineType.HPP"
  17. #include "FixASM.HPP"
  18. #include "3DCLass.HPP"
  19. #include "LightP.HPP"
  20. #include "TextType.HPP"
  21. #include "PalShade.HPP"
  22.  
  23. // Declare the textures for the polygons:
  24. ImageData TextDat;
  25.  
  26. // Delcare the texture shade look-up table:
  27. ShadeDat TextShade;
  28.  
  29. void inline ClipHLine ( long &X1, long &X2, long &Z, long ZStep,
  30.                         long &U, long UStep, long &V, long VStep,
  31.                         long &I, long IStep )
  32.    {
  33.    long register Step;
  34.    // Clip a horizontal "Z-buffered" line:
  35.    if ( X1 < MINX )
  36.       {
  37.       Step = ( MINX - X1 );
  38.       // Take advantage of the fact that ( a * ( b * f ) / f ) 
  39.       // is equal to ( a * b );
  40.       Z += ZStep * Step;
  41.       U += UStep * Step;
  42.       V += VStep * Step;
  43.       I += IStep * Step;
  44.       X1 = MINX;
  45.       }
  46.    else if ( X1 > MAXX )
  47.            X1 = MAXX;
  48.    if ( X2 < MINX )
  49.       X2 = MINX;
  50.    else if ( X2 > MAXX )
  51.            X2 = MAXX;
  52.    }
  53.  
  54. void Panel3D::CalcRadius ()
  55.    {
  56.    // Calculate the radius of the panel:
  57.  
  58.    // Initialize/Declare variables:
  59.    Point3D TempPoint [ 4 ], Center;
  60.    unsigned int Count;
  61.    double Distance [ 4 ], Dist;
  62.   
  63.    Center.Lx = ( VPoint [ 0 ]->Lx +
  64.                  VPoint [ 1 ]->Lx +
  65.                  VPoint [ 2 ]->Lx +
  66.                  VPoint [ 3 ]->Lx ) / 4.0F;
  67.  
  68.    Center.Ly = ( VPoint [ 0 ]->Ly +
  69.                  VPoint [ 1 ]->Ly +
  70.                  VPoint [ 2 ]->Ly +
  71.                  VPoint [ 3 ]->Ly ) / 4.0F;
  72.  
  73.    Center.Lz = ( VPoint [ 0 ]->Lz +
  74.                  VPoint [ 1 ]->Lz +
  75.                  VPoint [ 2 ]->Lz +
  76.                  VPoint [ 3 ]->Lz ) / 4.0F;
  77.  
  78.    // Translate the panel to the origin and store it in TempPoint:
  79.    for ( Count = 0; Count < 4; Count++ )
  80.        {
  81.        TempPoint [ Count ] = ( *VPoint[ Count ] ) - Center;
  82.        }
  83.  
  84.    // Calculate the distance to each of the vertices:
  85.    for ( Count = 0; Count < 4; Count++ )
  86.        {
  87.        // Calculate distance to the panel:
  88.        Dist = TempPoint [ Count ].Mag ();
  89.        // Store it:
  90.        Distance [ Count ] = Dist;
  91.        }
  92.  
  93.    // Determine the maximum distance:
  94.    Dist = Distance [ 0 ];
  95.    for ( Count = 1; Count < 4; Count++ )
  96.        {
  97.        if ( Distance [ Count ] > Dist )
  98.           Dist = Distance [ Count ];
  99.        }
  100.    Radius = Dist * 1.1;
  101.  
  102.    // Calculate the distance to each of the vertices:
  103.    for ( Count = 0; Count < 4; Count++ )
  104.        {
  105.        // Calculate distance to object ON THE X/Z PLANE!
  106.        Dist = 
  107.        sqrt ( TempPoint [ Count ].Lx * TempPoint [ Count ].Lx +
  108.               TempPoint [ Count ].Lz * TempPoint [ Count ].Lz );
  109.        Distance [ Count ] = Dist;
  110.        }
  111.  
  112.    // Determine the maximum distance:
  113.    Dist = Distance [ 0 ];
  114.    for ( Count = 1; Count < 4; Count++ )
  115.        {
  116.        if ( Distance [ Count ] > Dist )
  117.           Dist = Distance [ Count ];
  118.        }
  119.    // Dist holds the maximum X/Z extent of the panel:
  120.    RadiusXZ = Dist;
  121.  
  122.    // Calculate the distance to each of the vertices:
  123.    for ( Count = 0; Count < 4; Count++ )
  124.        {
  125.        // Calculate distance to object ON THE Y AXIS!
  126.        Dist = TempPoint [ Count ].Ly;
  127.        Distance [ Count ] = Dist;
  128.        }
  129.  
  130.    // Determine the maximum distance:
  131.    Dist = Distance [ 0 ];
  132.    for ( Count = 1; Count < 4; Count++ )
  133.        {
  134.        if ( Distance [ Count ] > Dist )
  135.           Dist = Distance [ Count ];
  136.        }
  137.    // Dist holds the maximum Y extent of the panel:
  138.    RadiusY = Dist;
  139.    }
  140.  
  141. void Panel3D::CalcInten ()
  142.    {
  143.    double Mag = ( sqrt ( Light.X * Light.X +
  144.                          Light.Y * Light.Y +
  145.                          Light.Z * Light.Z ) );
  146.    // Assign a shade based on normal:
  147.    double CosA = ( ( Normal.X - VPoint [ 0 ]->Lx ) * Light.X +
  148.                    ( Normal.Y - VPoint [ 0 ]->Ly ) * Light.Y +
  149.                    ( Normal.Z - VPoint [ 0 ]->Lz ) * Light.Z ) / Mag;
  150.    Color = ( ( CosA * ( double ) COLOR_RANGE ) + COLOR_START );
  151.    }
  152.  
  153. void Panel3D::Project ()
  154.    {
  155.    // Perform front Z-clipping and project the panel's 3-dimensional points 
  156.    // onto the screen:
  157.    SPCount = 4;
  158.    unsigned int Count, OutC = 0, StartI, EndI;
  159.    double UOverZ, VOverZ, OneOverZ;
  160.    Point3D ZClip [ 5 ]; // Maximum of 5 clipped Z points
  161.    Detail3D NewA [ 5 ]; // Maximum of 5 clipped detail values
  162.  
  163.    // Initialize pointer to last vertex:
  164.    StartI = SPCount - 1;
  165.  
  166.    // Loop through all edges of panel using S&H algorithm:
  167.    for ( EndI = 0; EndI < SPCount; EndI++ )
  168.        {
  169.        if ( VPoint [ StartI ]->Wz >= MINZ )
  170.           {
  171.           if ( VPoint [ EndI ]->Wz >= MINZ )
  172.              {
  173.              // Entirely inside front view volume (case 1) - output unchanged 
  174.              // vertex:
  175.              ZClip [ OutC ].Wx = VPoint [ EndI ]->Wx;
  176.              ZClip [ OutC ].Wy = VPoint [ EndI ]->Wy;
  177.              ZClip [ OutC ].Wz = VPoint [ EndI ]->Wz;
  178.  
  179.              // Output unchanged detail values:
  180.              NewA [ OutC ] = Attrib [ EndI ];
  181.  
  182.              // Update index:
  183.              ++OutC;
  184.              }
  185.           else {
  186.                // SPoint is leaving view volume (case 2) -
  187.                // clip using parametric form of line:
  188.                double DeltaZ = ( VPoint [ EndI ]->Wz - VPoint [ StartI ]->Wz );
  189.  
  190.                double t = ( MINZ - VPoint [ StartI ]->Wz ) / DeltaZ;
  191.  
  192.                ZClip [ OutC ].Wx = VPoint [ StartI ]->Wx + ( double )
  193.                                    ( VPoint [ EndI ]->Wx - 
  194.                                      VPoint [ StartI ]->Wx ) * t;
  195.                ZClip [ OutC ].Wy = VPoint [ StartI ]->Wy + ( double )
  196.                                    ( VPoint [ EndI ]->Wy - 
  197.                                      VPoint [ StartI ]->Wy ) * t;
  198.                ZClip [ OutC ].Wz = MINZ;
  199.  
  200.                // Calculate new surface detail values:
  201.                NewA [ OutC ] = Attrib [ StartI ] + 
  202.                                (  ( Attrib [ EndI ] - 
  203.                                     Attrib [ StartI ] ) * t );
  204.                // Update index:
  205.                ++OutC;
  206.                }
  207.           }   
  208.        else {
  209.             if ( VPoint [ EndI ]->Wz >= MINZ ) 
  210.                {
  211.                // SPoint is entering view volume (case 3) - clip
  212.                // using parametric form of line:
  213.                double DeltaZ = ( VPoint [ EndI ]->Wz - VPoint [ StartI ]->Wz );
  214.  
  215.                double t = ( MINZ - VPoint [ StartI ]->Wz ) / DeltaZ;
  216.  
  217.                ZClip [ OutC ].Wx = VPoint [ StartI ]->Wx + ( double )
  218.                                    ( VPoint [ EndI ]->Wx - 
  219.                                      VPoint [ StartI ]->Wx )* t;
  220.             
  221.                ZClip [ OutC ].Wy = VPoint [ StartI ]->Wy + ( double )
  222.                                    ( VPoint [ EndI ]->Wy - 
  223.                                      VPoint [ StartI ]->Wy ) * t;
  224.                ZClip [ OutC ].Wz =  MINZ;
  225.  
  226.                // Calculate new surface detail values:
  227.                NewA [ OutC ] = Attrib [ StartI ] + 
  228.                                (  ( Attrib [ EndI ] - 
  229.                                     Attrib [ StartI ] ) * t );
  230.  
  231.                // Update index:
  232.                ++OutC;
  233.  
  234.                // Add an extra edge to list:
  235.                ZClip [ OutC ].Wx =  VPoint [ EndI ]->Wx;
  236.                ZClip [ OutC ].Wy =  VPoint [ EndI ]->Wy;
  237.                ZClip [ OutC ].Wz =  VPoint [ EndI ]->Wz;
  238.  
  239.                // Add an additional surface detail point to 
  240.                // the list:
  241.                NewA [ OutC ] = Attrib [ EndI ];
  242.  
  243.                // Update index:
  244.                ++OutC;
  245.                }
  246.             else {
  247.                  // No operation is necessary for case 4
  248.                  }
  249.             }   
  250.        // Advance to next vertex:
  251.        StartI = EndI;
  252.        }
  253.  
  254.    // Store the number of vertices in OutC:
  255.    SPCount = ( WORD ) OutC;
  256.  
  257.    // Project panel's points:
  258.    for ( Count = 0; Count < OutC; Count++ )
  259.        {
  260.        OneOverZ = 1.0F / ZClip [ Count ].Wz;
  261.        SPoint [ Count ].X = ZClip [ Count ].Wx * XSCALE *
  262.                             OneOverZ + XCENTER;
  263.        SPoint [ Count ].Y = ZClip [ Count ].Wy * YSCALE *
  264.                             OneOverZ + YCENTER;
  265.        SPoint [ Count ].Z = ( ( double ) OneOverZ *
  266.                             ( ( double ) ( 1 << ZSTEP_PREC ) ) );
  267.  
  268.        UOverZ = ( double ) NewA [ Count ].U * OneOverZ;
  269.        VOverZ = ( double ) NewA [ Count ].V * OneOverZ;
  270.  
  271.        SPoint [ Count ].U = UOverZ * ( double )
  272.                             ( 1 << TSTEP_PREC );
  273.  
  274.        SPoint [ Count ].V = VOverZ * ( double )
  275.                             ( 1 << TSTEP_PREC );
  276.        long NewI = NewA [ Count ].I;
  277.  
  278.        // Perform depth shading:
  279.        NewI = NewI + ZClip [ Count ].Wz / SHADE_DIV;
  280.        if ( NewI > ( SHADE_COUNT - 1 ) )
  281.           NewI = ( SHADE_COUNT - 1 );
  282.        SPoint [ Count ].I = NewI << ISTEP_PREC;
  283.        }
  284.    }
  285.    
  286. void Panel3D::CalcNormal ()
  287.    {
  288.    // Calculate the normal of the panel:
  289.    long double X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3,
  290.                Distance, A, B, C, D;
  291.    Point3D UniqueVerts [ 4 ], TVert;
  292.    unsigned short Count, Range = 0;
  293.    // Create a list of unique vertices:
  294.    for ( Count = 0; Count < 4; Count++ )
  295.        {
  296.        TVert = *VPoint [ Count ];
  297.        if ( Range == 0 )
  298.           UniqueVerts [ Range++ ] = TVert;
  299.        else if ( UniqueVert ( TVert, UniqueVerts, Range ) )
  300.                {
  301.                UniqueVerts [ Range++ ] = TVert;
  302.                }
  303.        }
  304.  
  305.    X1 = UniqueVerts [ 0 ].Lx;
  306.    Y1 = UniqueVerts [ 0 ].Ly;
  307.    Z1 = UniqueVerts [ 0 ].Lz;
  308.  
  309.    X2 = UniqueVerts [ 1 ].Lx;
  310.    Y2 = UniqueVerts [ 1 ].Ly;
  311.    Z2 = UniqueVerts [ 1 ].Lz;
  312.  
  313.    X3 = UniqueVerts [ 2 ].Lx;
  314.    Y3 = UniqueVerts [ 2 ].Ly;
  315.    Z3 = UniqueVerts [ 2 ].Lz;
  316.  
  317.    // Use plane equation to determine plane's orientation:
  318.    A = Y1 * ( Z2 - Z3 ) + Y2 * ( Z3 - Z1 ) + Y3 * ( Z1 - Z2 );
  319.    B = Z1 * ( X2 - X3 ) + Z2 * ( X3 - X1 ) + Z3 * ( X1 - X2 );
  320.    C = X1 * ( Y2 - Y3 ) + X2 * ( Y3 - Y1 ) + X3 * ( Y1 - Y2 );
  321.    D = -X1 * ( Y2 * Z3 - Y3 * Z2 )  -X2 * ( Y3 * Z1 - Y1 * Z3 )
  322.        -X3 * ( Y1 * Z2 - Y2 * Z1 );
  323.  
  324.    // Get the distance to the vector:
  325.    Distance = sqrt ( A*A + B*B + C*C );
  326.  
  327.    // Normalize the normal to 1 and create a point:
  328.    Normal.X = ( A / Distance ) + VPoint [ 0 ]->Lx;
  329.    Normal.Y = ( B / Distance ) + VPoint [ 0 ]->Ly;
  330.    Normal.Z = ( C / Distance ) + VPoint [ 0 ]->Lz;
  331.    Normal.D = ( D );/// Distance );
  332.    Normal.Td = Distance;
  333.    }
  334.  
  335. int inline Panel3D::CalcBFace ()
  336.   {
  337.   // Determine if polygon is a backface:
  338.   int Visible = 1; Invis = 0;
  339.   Point3D V = *VPoint [ 0 ];
  340.   double Direction = ( V.Wx * ( Normal.Tx - VPoint [ 0 ]->Wx ) + 
  341.                        V.Wy * ( Normal.Ty - VPoint [ 0 ]->Wy ) + 
  342.                        V.Wz * ( Normal.Tz - VPoint [ 0 ]->Wz ) );
  343.   if ( Direction > 0.0F )
  344.      {
  345.      // Get the cosine of the angle between the viewer and the polygon 
  346.      // normal:
  347.      Direction /= V.Mag ();
  348.      // Assume panel will remain a time proportional to the angle between
  349.      // the viewer to the polygon normal:
  350.      Invis = ( double ) Direction * ( double ) 25.0F;
  351.      // Set the invisible flag for this frame:
  352.      Visible = 0;
  353.      }
  354.   return Visible;
  355.   }
  356.  
  357.  
  358. int Panel3D::CalcVisible3D ()
  359.   {
  360.   // Perform 3D culling:
  361.  
  362.   // Assume panel is visible:
  363.   int Visible;
  364.  
  365.   // Perform a back-face culling operation:
  366.   Visible = CalcBFace ();
  367.    
  368.   // If panel still visible, perform extent test:
  369.   if ( Visible )
  370.      Visible = CheckExtents ();
  371.   return Visible;
  372.   }
  373.  
  374. long Panel3D::CalcCenterZ ()
  375.    {
  376.    // Calculate the polygon's center Z:
  377.    long SummedComponents = ( double ) VPoint [ 0 ] -> Wz + 
  378.                            ( double ) VPoint [ 1 ] -> Wz +
  379.                            ( double ) VPoint [ 2 ] -> Wz +
  380.                            ( double ) VPoint [ 3 ] -> Wz;
  381.    long CenterZ = ( SummedComponents  >> 2 );
  382.    return CenterZ;
  383.    }
  384.  
  385. int Panel3D::CalcVisible2D ()
  386.   {
  387.   // Perform 2D culling:
  388.  
  389.   // Assume panel is visible:
  390.   long XMinInVis = 0, XMaxInVis = 0, YMinInVis = 0, YMaxInVis = 0;
  391.   long Visible = 1, AveX = 0, AveY = 0, N;
  392.   Invis = 0;
  393.  
  394.   // Make sure the panel has more than two points:
  395.   if ( SPCount < 3 )
  396.      {
  397.      // If not, flag panel as invisible:
  398.      Visible = 0;
  399.  
  400.      // Assume panel will remain invisible for four more frames:
  401.      Invis = 4;
  402.      return Visible;
  403.      }
  404.  
  405.    // Determine location of panel's 2D points:
  406.    for ( N = 0; N < SPCount; N++ )
  407.        {
  408.        if ( SPoint [ N ].X < MINX )
  409.           ++XMinInVis;
  410.  
  411.        if ( SPoint [ N ].X > MAXX )
  412.           ++XMaxInVis;
  413.  
  414.        if ( SPoint [ N ].Y < MINY )
  415.           ++YMinInVis;
  416.  
  417.        if ( SPoint [ N ].Y > MAXY )
  418.           ++YMaxInVis;
  419.  
  420.        AveX += SPoint [ N ].X;
  421.        AveY += SPoint [ N ].Y;
  422.        }
  423.  
  424.    if ( XMinInVis >= SPCount )
  425.       {
  426.       // Assume panel will remain invisible for a time 
  427.       // proportional to the distance from the edge of the 
  428.       // panel to the edge of the viewport:
  429.       AveX /= SPCount;
  430.       Invis = ( WORD ) ( abs ( AveX ) / ( 320 * 30 ) );
  431.       Visible = 0;
  432.       }
  433.    else if ( YMinInVis >= SPCount )
  434.            {
  435.            // Assume panel will remain invisible for a time 
  436.            // proportional to the distance from the edge of the 
  437.            // panel to the edge of the viewport:
  438.            AveY /= SPCount;
  439.            Invis = ( WORD ) ( abs ( AveY ) / ( 200 * 30 ) );
  440.            Visible = 0;
  441.            }
  442.    else if ( XMaxInVis >= SPCount )
  443.            {
  444.            // Assume panel will remain invisible for a time 
  445.            // proportional to the distance from the edge of the 
  446.            // panel to the edge of the viewport:
  447.            AveX /= SPCount;
  448.            Invis = ( WORD ) ( ( AveX - MAXX ) / ( 320 * 30 ) );
  449.            Visible = 0;
  450.            }
  451.    else if ( YMaxInVis >= SPCount )
  452.            {
  453.            // Assume panel will remain invisible for a time 
  454.            // proportional to the distance from the edge of the 
  455.            // panel to the edge of the viewport:
  456.            AveY /= SPCount;
  457.            Invis = ( WORD ) ( ( AveY - MAXY ) / ( 200 * 30 ) );
  458.            Visible = 0;
  459.            }
  460.   return Visible;
  461.   }
  462.    
  463. int Panel3D::CheckExtents ()
  464.   {
  465.   // Determine if panel is in the range of MINZ to MAXZ:
  466.   long Visible = 0, Count;
  467.   double MinZ;
  468.   for ( Count = 0; Count < 4; Count++ )
  469.       {
  470.       if ( VPoint [ Count ]->Wz > MINZ )
  471.          {
  472.          Visible = 1;
  473.          Invis = 0;
  474.          break;
  475.          }
  476.       }
  477.   if ( Visible )
  478.      {
  479.      MinZ = VPoint [ 0 ]->Wz;
  480.      for ( Count = 1; Count < 4; Count++ )
  481.          {
  482.          if ( VPoint [ Count ]->Wz < MinZ )
  483.             MinZ = VPoint [ Count ]->Wz;
  484.          }
  485.      if ( MinZ > MAXZ )
  486.         {
  487.         // Set the invisible flag for this frame:
  488.         Visible = 0;
  489.  
  490.         // Assume panel will remain invisible for a time 
  491.         // proportional to the distance from the viewer:
  492.         Invis = ( WORD ) ( ( MinZ - MAXZ ) / 50 );
  493.         }
  494.      }
  495.   else {
  496.        // Assume panel will remain invisible for a time 
  497.        // proportional to the distance from the viewer:
  498.        Invis = ( WORD ) ( abs ( CalcCenterZ () + MINZ ) / 50 );
  499.        }
  500.   return Visible;
  501.   }
  502.  
  503. void Panel3D::Update ( Matrix3D &M )
  504.    {
  505.    // Transform the normal:
  506.    M.Transform ( Normal );
  507.  
  508.    // Update the invisibility flag:
  509.    if ( Invis > 0 )
  510.       --Invis;
  511.    }
  512.  
  513. void Panel3D::DisplayNorm ( unsigned char *Dest )
  514.    {
  515.    // Display the panel in the screen buffer "Dest":
  516.    unsigned char register *DPtr, *IPtr;
  517.    long register *ZPtr, Z;
  518.    long register Tx, Ty;
  519.    long NewTMask;
  520.    long TxStep, TyStep, IStep, I;
  521.    long Top = 0, N, RightPos, LeftPos, NewRightPos, NewLeftPos, 
  522.         Height, EdgeCount, YIndex, Width, XStart, XEnd,  
  523.         ZStep, U, V, UStep, VStep, IPos,
  524.         RunLoops, Count, Tx1, Ty1, Length, 
  525.         Tx2, Ty2, SubUStep, SubVStep, SubZStep, 
  526.         RZ, PreMultShift;
  527.    const RunLen = 16, RunShift = 4;
  528.    CeilLine LeftSeg, RightSeg;
  529.  
  530.    // Create a pointer to the texture map:
  531.    IPtr = TextDat.TMap [ TextHan ].Image;
  532.  
  533.    EdgeCount = SPCount;
  534.  
  535.    // Pre-multiply the texture mask:
  536.    NewTMask = TMASK * TextDat.TMap [ TextHan ].Width;
  537.  
  538.    switch ( TextDat.TMap [ TextHan ].Width )
  539.           {
  540.           case ( 2 ): PreMultShift = 1; break;
  541.           case ( 4 ): PreMultShift = 2; break;
  542.           case ( 8 ): PreMultShift = 3; break;
  543.           case ( 16 ): PreMultShift = 4; break;
  544.           case ( 32 ): PreMultShift = 5; break;
  545.           case ( 64 ): PreMultShift = 6; break;
  546.           case ( 128 ): PreMultShift = 7; break;
  547.           case ( 256 ): PreMultShift = 8; break;
  548.           case ( 512 ): PreMultShift = 9; break;
  549.           }
  550.  
  551.    // Search for lowest Y coordinate (top of polygon):
  552.    for ( N = 1; N < SPCount; N++ )
  553.        {
  554.        if ( SPoint [ N ].Y < SPoint [ Top ].Y )
  555.           Top = N;
  556.        }
  557.    RightPos = Top;
  558.    LeftPos = Top;
  559.  
  560.    // Calculate the index to the buffer:
  561.    YIndex = SPoint [ Top ].Y * 320;
  562.  
  563.    // Loop for all polygon edges:
  564.    while ( EdgeCount > 0 )
  565.          {
  566.          // Determine if the right side of the polygon needs 
  567.          // (re)initializing:
  568.          if ( RightSeg.Height () <= 0 )
  569.             {
  570.             NewRightPos = RightPos + 1;
  571.             if ( NewRightPos >= SPCount )
  572.                NewRightPos = 0;
  573.             RightSeg.Init ( SPoint [ RightPos ], SPoint [ NewRightPos ] );
  574.             RightPos = NewRightPos;
  575.             --EdgeCount;
  576.             // Perform object-precision clip on top of edge 
  577.             // (if necessary):
  578.             if ( RightSeg.GetY () < MINY )
  579.                {
  580.                RightSeg.ClipTop ( MINY );
  581.                YIndex = MINY * 320;
  582.                }
  583.             }
  584.          // Determine if the left side of the polygon needs 
  585.          // (re)initializing:
  586.          if ( LeftSeg.Height () <= 0 )
  587.             {
  588.             NewLeftPos = LeftPos - 1;
  589.             if ( NewLeftPos < 0 )
  590.                NewLeftPos = ( SPCount - 1 );
  591.             LeftSeg.Init ( SPoint [ LeftPos ], SPoint [ NewLeftPos ] );
  592.             LeftPos = NewLeftPos;
  593.             --EdgeCount;
  594.             // Perform object-precision clip on top of edge 
  595.             // (if necessary):
  596.             if ( LeftSeg.GetY () < MINY )
  597.                {
  598.                LeftSeg.ClipTop ( MINY );
  599.                YIndex = MINY * 320;
  600.                }
  601.             }
  602.          // Subdivide polygon into trapezoid:
  603.          if ( LeftSeg.Height () < RightSeg.Height () )
  604.             {
  605.             Height = LeftSeg.Height ();
  606.             if ( ( LeftSeg.GetY () + Height ) > MAXY )
  607.                {
  608.                Height = MAXY - LeftSeg.GetY ();
  609.                EdgeCount = 0;
  610.                }
  611.             }
  612.          else {
  613.               Height = RightSeg.Height ();
  614.               if ( ( RightSeg.GetY () + Height ) > MAXY )
  615.                  {
  616.                  Height = MAXY - RightSeg.GetY ();
  617.                  EdgeCount = 0;
  618.                  }
  619.               }
  620.  
  621.          // Loop for the height of the trapezoid:
  622.          while ( Height-- > 0 )
  623.                {
  624.                // Calculate initial values:
  625.                XStart = LeftSeg.GetX ();
  626.                XEnd = RightSeg.GetX ();
  627.                Width = XEnd - XStart;
  628.                if ( ( Width > 0 ) && ( XEnd > MINX ) && 
  629.                     ( XStart < MAXX ) )
  630.                   {
  631.                   U = LeftSeg.GetU ();
  632.                   V = LeftSeg.GetV ();
  633.                   Z = LeftSeg.GetZ ();
  634.                   I = LeftSeg.GetI ();
  635.  
  636.                   // Note: The following steps are linear in 
  637.                   // screen space and are constant throughout 
  638.                   // the entire polygon. Given enough Z 
  639.                   // precision (which reduces the efficiency
  640.                   // of the clear-reduction algorithm) they 
  641.                   // can be calculated a single time and 
  642.                   // used throughout the remainder of the 
  643.                   // rasterization:
  644.                   UStep = ( RightSeg.GetU () - LeftSeg.GetU () )
  645.                             / Width;
  646.                   VStep = ( RightSeg.GetV () - LeftSeg.GetV () )
  647.                             / Width;
  648.                   ZStep =  ( RightSeg.GetZ () - LeftSeg.GetZ () )
  649.                             / Width;
  650.                   
  651.                   IStep = ( RightSeg.GetI () - LeftSeg.GetI () )
  652.                             / Width;
  653.  
  654.                   // Clip the scan-line:
  655.                   ClipHLine ( XStart, XEnd, Z, ZStep, U, UStep, 
  656.                               V, VStep, I, IStep );
  657.                   Width = XEnd - XStart;
  658.                   DPtr = &Dest    [ YIndex + XStart ];
  659.                   ZPtr = &ZBuffer [ YIndex + XStart ];
  660.  
  661.                   // Calculate subdivision loops:
  662.                   RunLoops = Width >> RunShift;
  663.  
  664.                   if ( Width > 0 )
  665.                      {
  666.                      // Premultiply steps for subdivision:
  667.                      SubUStep = UStep << RunShift;
  668.                      SubVStep = VStep << RunShift;
  669.                      SubZStep = ZStep << RunShift;
  670.                      }
  671.  
  672.                   // Loop for number of subdivisions:
  673.                   for ( Count = 0; Count < RunLoops; Count++ )
  674.                       {
  675.                       Length = RunLen;
  676.  
  677.                       // Calculate affine mapping coordinates
  678.                       // based on perspective subdivision:
  679.                       RZ  = Z - ZTrans;
  680.                       fixdiv ( Tx1, U, RZ, LSTEP_PREC );
  681.                       fixdiv ( Ty1, V, RZ, LSTEP_PREC );
  682.  
  683.                       // Jump ahead to next subdivision:
  684.                       U  += SubUStep;
  685.                       V  += SubVStep;
  686.                       RZ += SubZStep;
  687.  
  688.                       fixdiv ( Tx2, U, RZ, LSTEP_PREC );
  689.                       fixdiv ( Ty2, V, RZ, LSTEP_PREC );
  690.  
  691.                       TxStep = ( Tx2 - Tx1 ) >> RunShift;
  692.                       TyStep = ( Ty2 - Ty1 ) >> RunShift;
  693.  
  694.                       Tx = Tx1;
  695.                       // Premultiply texture's Y coordinate:
  696.                       Ty = Ty1 << PreMultShift;
  697.  
  698.                       // Premultiply the texture's Y step:
  699.                       TyStep <<= PreMultShift;
  700.  
  701.                       while ( Length-- > 0 )
  702.                             {
  703.                             if ( *ZPtr < Z )
  704.                                {
  705.                                *ZPtr = Z;
  706.                                IPos = ( ( Ty & NewTMask ) + Tx ) 
  707.                                       >> LSTEP_PREC;
  708.                                *DPtr = TextShade.Shade [ 
  709.                                          ( I & IMASK ) 
  710.                                        + IPtr [ IPos ] ];
  711.                                }
  712.                             Z  += ZStep;
  713.                             I  += IStep;
  714.                             Tx += TxStep;
  715.                             Ty += TyStep;
  716.                             ++DPtr;
  717.                             ++ZPtr;
  718.                             }
  719.                       }
  720.                   // Calculate remainder of scan-line left:
  721.                   // to rasterize:
  722.                   Length = Width & ( RunLen - 1 );
  723.                   if ( Length > 0 )
  724.                      {
  725.                      RZ  = Z - ZTrans;
  726.                      fixdiv ( Tx1, U, RZ, LSTEP_PREC );
  727.                      fixdiv ( Ty1, V, RZ, LSTEP_PREC );
  728.  
  729.                      // Jump ahead to next subdivision:
  730.                      U  += ( UStep * Length );
  731.                      V  += ( VStep * Length );
  732.                      RZ += ( ZStep * Length );
  733.  
  734.                      fixdiv ( Tx2, U, RZ, LSTEP_PREC );
  735.                      fixdiv ( Ty2, V, RZ, LSTEP_PREC );
  736.  
  737.                      TxStep = ( Tx2 - Tx1 ) / Length;
  738.                      TyStep = ( Ty2 - Ty1 ) / Length;
  739.  
  740.                      Tx = Tx1;
  741.                      Ty = Ty1;
  742.  
  743.                      // Premultiply the texture's Y coordinate:
  744.                      Ty     <<= PreMultShift;
  745.  
  746.                      // Premultiply the texture's Y step:
  747.                      TyStep <<= PreMultShift;
  748.  
  749.                      while ( Length-- > 0 )
  750.                            {
  751.                            if ( *ZPtr < Z )
  752.                               {
  753.                               *ZPtr = Z;
  754.                               IPos = ( ( Ty & NewTMask ) + Tx ) 
  755.                                       >> LSTEP_PREC;
  756.                               *DPtr = TextShade.Shade [ 
  757.                                          ( I & IMASK )
  758.                                        + IPtr [ IPos ] ];
  759.                               }
  760.                            Z  += ZStep;
  761.                            I  += IStep;
  762.                            Tx += TxStep;
  763.                            Ty += TyStep;
  764.                            ++DPtr;
  765.                            ++ZPtr;
  766.                            }
  767.                      }
  768.                   }
  769.                ++RightSeg;
  770.                ++LeftSeg;
  771.                YIndex += 320;
  772.                }
  773.          }
  774.    }
  775.  
  776. void Panel3D::DisplaySel ( unsigned char *Dest )
  777.    {
  778.       // Display the panel in the screen buffer "Dest":
  779.    unsigned char register *DPtr, *IPtr;
  780.    long register *ZPtr, Z;
  781.    long Tx, Ty, NewTMask, I;
  782.    long TxStep, TyStep, IStep;
  783.    long Top = 0, N, RightPos, LeftPos, NewRightPos, NewLeftPos, 
  784.         Height, EdgeCount, YIndex, Width, XStart, XEnd,  
  785.         ZStep, U, V, UStep, VStep, IPos,
  786.         RunLoops, Count, Tx1, Ty1, Length, 
  787.         Tx2, Ty2, SubUStep, SubVStep, SubZStep, RZ, 
  788.         PreMultShift;
  789.    const RunLen = 16, RunShift = 4;
  790.    CeilLine LeftSeg, RightSeg;
  791.  
  792.    // Create a pointer to the texture map:
  793.    IPtr = TextDat.TMap [ TextHan ].Image;
  794.  
  795.    EdgeCount = SPCount;
  796.  
  797.    // Pre-multiply the texture mask:
  798.    NewTMask = TMASK * TextDat.TMap [ TextHan ].Width;
  799.  
  800.    switch ( TextDat.TMap [ TextHan ].Width )
  801.           {
  802.           case ( 2 ): PreMultShift = 1; break;
  803.           case ( 4 ): PreMultShift = 2; break;
  804.           case ( 8 ): PreMultShift = 3; break;
  805.           case ( 16 ): PreMultShift = 4; break;
  806.           case ( 32 ): PreMultShift = 5; break;
  807.           case ( 64 ): PreMultShift = 6; break;
  808.           case ( 128 ): PreMultShift = 7; break;
  809.           case ( 256 ): PreMultShift = 8; break;
  810.           case ( 512 ): PreMultShift = 9; break;
  811.           }
  812.  
  813.    // Search for lowest Y coordinate (top of polygon):
  814.    for ( N = 1; N < SPCount; N++ )
  815.        {
  816.        if ( SPoint [ N ].Y < SPoint [ Top ].Y )
  817.           Top = N;
  818.        }
  819.    RightPos = Top;
  820.    LeftPos = Top;
  821.  
  822.    // Calculate the index to the buffer:
  823.    YIndex = SPoint [ Top ].Y * 320;
  824.  
  825.    // Loop for all polygon edges:
  826.    while ( EdgeCount > 0 )
  827.          {
  828.          // Determine if the right side of the polygon needs 
  829.          // (re)initializing:
  830.          if ( RightSeg.Height () <= 0 )
  831.             {
  832.             NewRightPos = RightPos + 1;
  833.             if ( NewRightPos >= SPCount )
  834.                NewRightPos = 0;
  835.             RightSeg.Init ( SPoint [ RightPos ], SPoint [ NewRightPos ] );
  836.             RightPos = NewRightPos;
  837.             --EdgeCount;
  838.             // Perform object-precision clip on top of edge 
  839.             // (if necessary):
  840.             if ( RightSeg.GetY () < MINY )
  841.                {
  842.                RightSeg.ClipTop ( MINY );
  843.                YIndex = MINY * 320;
  844.                }
  845.             }
  846.          // Determine if the left side of the polygon needs 
  847.          // (re)initializing:
  848.          if ( LeftSeg.Height () <= 0 )
  849.             {
  850.             NewLeftPos = LeftPos - 1;
  851.             if ( NewLeftPos < 0 )
  852.                NewLeftPos = ( SPCount - 1 );
  853.             LeftSeg.Init ( SPoint [ LeftPos ], SPoint [ NewLeftPos ] );
  854.             LeftPos = NewLeftPos;
  855.             --EdgeCount;
  856.             // Perform object-precision clip on top of edge 
  857.             // (if necessary):
  858.             if ( LeftSeg.GetY () < MINY )
  859.                {
  860.                LeftSeg.ClipTop ( MINY );
  861.                YIndex = MINY * 320;
  862.                }
  863.             }
  864.          // Subdivide polygon into trapezoid:
  865.          if ( LeftSeg.Height () < RightSeg.Height () )
  866.             {
  867.             Height = LeftSeg.Height ();
  868.             if ( ( LeftSeg.GetY () + Height ) > MAXY )
  869.                {
  870.                Height = MAXY - LeftSeg.GetY ();
  871.                EdgeCount = 0;
  872.                }
  873.             }
  874.          else {
  875.               Height = RightSeg.Height ();
  876.               if ( ( RightSeg.GetY () + Height ) > MAXY )
  877.                  {
  878.                  Height = MAXY - RightSeg.GetY ();
  879.                  EdgeCount = 0;
  880.                  }
  881.               }
  882.  
  883.          // Loop for the height of the trapezoid:
  884.          while ( Height-- > 0 )
  885.                {
  886.                // Calculate initial values:
  887.                XStart = LeftSeg.GetX ();
  888.                XEnd = RightSeg.GetX ();
  889.                Width = XEnd - XStart;
  890.                if ( ( Width > 0 ) && ( XEnd > MINX ) && 
  891.                     ( XStart < MAXX ) )
  892.                   {
  893.                   U = LeftSeg.GetU ();
  894.                   V = LeftSeg.GetV ();
  895.                   Z = LeftSeg.GetZ ();
  896.                   I = LeftSeg.GetI ();
  897.  
  898.                   // Note: The following steps are linear in 
  899.                   // screen space and are constant throughout 
  900.                   // the entire polygon. Given enough Z 
  901.                   // precision (which reduces the efficiency
  902.                   // of the clear-reduction algorithm) they 
  903.                   // can be calculated a single time and 
  904.                   // used throughout the remainder of the 
  905.                   // rasterization:
  906.                   UStep = ( RightSeg.GetU () - LeftSeg.GetU () )
  907.                             / Width;
  908.                   VStep = ( RightSeg.GetV () - LeftSeg.GetV () )
  909.                             / Width;
  910.                   ZStep =  ( RightSeg.GetZ () - LeftSeg.GetZ () )
  911.                             / Width;
  912.                   
  913.                   IStep = ( RightSeg.GetI () - LeftSeg.GetI () )
  914.                             / Width;
  915.  
  916.                   // Clip the scan-line:
  917.                   ClipHLine ( XStart, XEnd, Z, ZStep, U, UStep, 
  918.                               V, VStep, I, IStep );
  919.                   Width = XEnd - XStart;
  920.                   DPtr = &Dest    [ YIndex + XStart ];
  921.                   ZPtr = &ZBuffer [ YIndex + XStart ];
  922.  
  923.                   // Calculate subdivision loops:
  924.                   RunLoops = Width >> RunShift;
  925.  
  926.                                     if ( Width > 0 )
  927.                      {
  928.                      // Premultiply steps for subdivision:
  929.                      SubUStep = UStep << RunShift;
  930.                      SubVStep = VStep << RunShift;
  931.                      SubZStep = ZStep << RunShift;
  932.                      }
  933.  
  934.                   // Loop for number of subdivisions:
  935.                   for ( Count = 0; Count < RunLoops; Count++ )
  936.                       {
  937.                       Length = RunLen;
  938.  
  939.                       // Calculate affine mapping coordinates
  940.                       // based on perspective subdivision:
  941.                       RZ  = Z - ZTrans;
  942.                       fixdiv ( Tx1, U, RZ, LSTEP_PREC );
  943.                       fixdiv ( Ty1, V, RZ, LSTEP_PREC );
  944.  
  945.                       // Jump ahead to next subdivision:
  946.                       U  += SubUStep;
  947.                       V  += SubVStep;
  948.                       RZ += SubZStep;
  949.  
  950.                       fixdiv ( Tx2, U, RZ, LSTEP_PREC );
  951.                       fixdiv ( Ty2, V, RZ, LSTEP_PREC );
  952.  
  953.                       TxStep = ( Tx2 - Tx1 ) >> RunShift;
  954.                       TyStep = ( Ty2 - Ty1 ) >> RunShift;
  955.  
  956.                       Tx = Tx1;
  957.                       // Premultiply texture's Y coordinate:
  958.                       Ty = Ty1 << PreMultShift;
  959.  
  960.                       // Premultiply the texture's Y step:
  961.                       TyStep <<= PreMultShift;
  962.  
  963.                       while ( Length-- > 0 )
  964.                             {
  965.                             if ( *ZPtr < Z )
  966.                                {
  967.                                *ZPtr = Z;
  968.                                IPos = ( ( Ty & NewTMask ) + Tx ) 
  969.                                       >> LSTEP_PREC;
  970.                                *DPtr = TextShade.Shade [ 
  971.                                          ( I & IMASK )
  972.                                        + IPtr [ IPos ] ];
  973.                                }
  974.                             Z  += ZStep;
  975.                             I  += IStep;
  976.                             Tx += TxStep;
  977.                             Ty += TyStep;
  978.                             ++DPtr;
  979.                             ++ZPtr;
  980.                             }
  981.                       }
  982.                   // Calculate remainder of scan-line left:
  983.                   // to rasterize:
  984.                   Length = Width & ( RunLen - 1 );
  985.                   if ( Length > 0 )
  986.                      {
  987.                      RZ  = Z - ZTrans;
  988.                      fixdiv ( Tx1, U, RZ, LSTEP_PREC );
  989.                      fixdiv ( Ty1, V, RZ, LSTEP_PREC );
  990.  
  991.                      // Jump ahead to next subdivision:
  992.                      U  += ( UStep * Length );
  993.                      V  += ( VStep * Length );
  994.                      RZ += ( ZStep * Length );
  995.  
  996.                      fixdiv ( Tx2, U, RZ, LSTEP_PREC );
  997.                      fixdiv ( Ty2, V, RZ, LSTEP_PREC );
  998.  
  999.                      TxStep = ( Tx2 - Tx1 ) / Length;
  1000.                      TyStep = ( Ty2 - Ty1 ) / Length;
  1001.  
  1002.                      Tx = Tx1;
  1003.                      Ty = Ty1;
  1004.  
  1005.                      // Premultiply the texture's Y coordinate:
  1006.                      Ty     <<= PreMultShift;
  1007.  
  1008.                      // Premultiply the texture's Y step:
  1009.                      TyStep <<= PreMultShift;
  1010.  
  1011.                      while ( Length-- > 0 )
  1012.                            {
  1013.                            if ( *ZPtr < Z )
  1014.                               {
  1015.                               *ZPtr = Z;
  1016.                               IPos = ( ( Ty & NewTMask ) + Tx ) 
  1017.                                       >> LSTEP_PREC;
  1018.                               *DPtr = TextShade.Shade [ 
  1019.                                          ( I & IMASK )
  1020.                                        + IPtr [ IPos ] ];
  1021.                               }
  1022.                            Z  += ZStep;
  1023.                            I  += IStep;
  1024.                            Tx += TxStep;
  1025.                            Ty += TyStep;
  1026.                            ++DPtr;
  1027.                            ++ZPtr;
  1028.                            }
  1029.                      }
  1030.                   *( DPtr - 1 ) = 1;
  1031.                   Dest [ YIndex + XStart ] = 1;
  1032.                   }
  1033.                ++RightSeg;
  1034.                ++LeftSeg;
  1035.                YIndex += 320;
  1036.                }
  1037.          }
  1038.    }
  1039.