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