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