home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / WD_SRC.ZIP / SOURCE / DRAW.CPP < prev    next >
C/C++ Source or Header  |  1995-01-12  |  26KB  |  963 lines

  1. #include "..\Source\LastWolf.hpp"
  2.  
  3.  
  4. // What the fixed-point numbers are shifted by (as extra precision) for the VLine routines.
  5. #define TEXTURE_FIX    5
  6.  
  7. #define CLIP_Z    FIX(2)
  8. #define    MAX_X_CLIPS    200
  9.  
  10. // A lookup table for the parallaxing sky.
  11. MDWordArray parallaxLookup;
  12.  
  13. // Top and bottom Y for all the Lines.
  14. Fixed topY = FIX(-84);
  15. Fixed bottomY = FIX(36);
  16.         
  17. // Used when projecting coordinates.
  18. WORD centerX = 160;
  19. WORD centerY = 100;
  20.  
  21. // The transformation stuff.
  22. Fixed playerAngleSine, playerAngleCosine;
  23. Fixed translateX, translateY;
  24. Angle transAngle;
  25.  
  26.  
  27. // What you scale the world by horizontally .. xViewSlope and xViewSlopeAngle depend on it!
  28. WORD xWorldScale=160;
  29.  
  30. // World Y scale.
  31. WORD yWorldScale;
  32.  
  33. // The slope of the viewing angle ... used to cut off excess lines.
  34. // Equation to get slope = (screenMaxX / xWorldScale)
  35. // NOTE:  This is an x/y slope, because x has the possibility of being zero.
  36. // Also, screenMaxX = half the screen (160).
  37. Fixed xViewSlope = (Fixed)(1.0F * 16384.0F);
  38.  
  39. // xViewSlopeAngle = atan( 1/xViewSlope ).
  40. Angle xViewAngle = 128;
  41.  
  42.  
  43. // Variables for the screen X clipping table.
  44. X_Clip    clipSpace[MAX_X_CLIPS];
  45. WORD nClipsUsed;
  46.  
  47. X_Clip headNode, tailNode;
  48.  
  49.  
  50. void dr_InitTables()
  51. {
  52.     Angle i;
  53.     float ArcTangent, ArcCosine;
  54.     
  55.     // Fill in SIN_TABLE[].
  56.     for( i=0; i < ANGLE_RES; i++ )
  57.         SIN_TABLE[i] = (Fixed)(sin(((float)i * 6.28) / ANGLE_RES) * FIXED_ONE);
  58.  
  59.     // Fill in ATAN_TABLE[].
  60.     for( i=0; i < ANGLE_RES; i++ )
  61.     {
  62.         ArcTangent = atan((float)i / (float)ANGLE_RES);
  63.         ATAN_TABLE[i] = (Angle)((ArcTangent * (float)ANGLE_RES) / 6.28F);
  64.     }
  65.     
  66.     // Fill in ACOS_TABLE[].
  67.     for( i=0; i < ANGLE_RES; i++ )
  68.     {
  69.         ArcCosine = acos( (float)i / (float)ANGLE_RES );
  70.         ACOS_TABLE[i] = (ArcCosine * FIXED_ONE);
  71.     }
  72.     
  73.     // Set up the X_Clip stuff.
  74.     headNode.pNext = &tailNode;
  75.     tailNode.pNext = &tailNode;
  76. }
  77.  
  78. void dr_GenerateLookups()
  79. {
  80.     Fixed parallaxX;
  81.     DWORD x;
  82.     Texture *pSky;
  83.     
  84.     // Generate the parallaxing sky lookup table.
  85.     pSky = tx_GetTexture( curLevel.idCurSky );
  86.     
  87.     parallaxLookup.SetSize( s_DrawWidth );
  88.     for( x=s_MinX; x < s_MaxX; x++ )
  89.     {
  90.         parallaxX = FIXED_ONE - (FIX( (x-s_MinX)-(s_DrawWidth/2) ) / ((s_DrawWidth*2) / 3));
  91.         parallaxX = SIN_TABLE[ (parallaxX >> (FIXED_SHIFT-8)) + 255 ];
  92.         parallaxX = parallaxX >> pSky->xTextureShift;
  93.         
  94.         parallaxLookup.Set( x-s_MinX, parallaxX );
  95.     }
  96. }            
  97.  
  98. void dr_DrawScreen()
  99. {
  100.     // Setup misc. variables.
  101.     nClipsUsed = 0;
  102.  
  103.     headNode.x = s_MinX;
  104.     headNode.pNext = &tailNode;
  105.  
  106.     tailNode.x = s_MaxX;
  107.     tailNode.pNext = &tailNode;
  108.     
  109.     // Re-computer all the viewing parameters.
  110.     centerX = s_MinX + ((s_MaxX - s_MinX)/2);
  111.     centerY = s_MinY + ((s_MaxY - s_MinY)/2);
  112.     
  113.     yWorldScale = s_DrawHeight / 2;
  114.     xWorldScale = s_DrawWidth / 2;
  115.     xViewSlope = FIX(centerX) / (s_DrawWidth/2);
  116.  
  117.     
  118.     dr_SetupTransformation(&player);
  119.     bsp_TraverseAndDrawTree(curLevel.pRootLine);
  120.  
  121.     return;
  122. }
  123.  
  124.  
  125. void dr_SetupTransformation( Player *pPlayer )
  126. {
  127.     playerAngleSine = SAFE_SIN(pPlayer->facingAngle);
  128.     playerAngleCosine = SAFE_COS(pPlayer->facingAngle);
  129.  
  130.     transAngle = (pPlayer->facingAngle - PI) & ANGLE_MASK;
  131.  
  132.     translateX = -pPlayer->xPos;
  133.     translateY = -pPlayer->yPos;
  134. }
  135.  
  136.  
  137. DrawReturn dr_DrawWall( CLine *pWall, SideDir viewSide )
  138. {
  139.     ProcessWall Wall;
  140.  
  141.     Wall.pLine = pWall;
  142.     Wall.pPlayer = &player;
  143.     Wall.viewSide = viewSide;
  144.     Wall.bTextureInitted = FALSE;
  145.     
  146.     // Get the wall into the player's viewspace to project it.
  147.     if( !dr_TransformWall( &Wall ) )
  148.         return WallOffScreen;
  149.  
  150.     // Clip it against the y=CLIP_Z Line.
  151.     if( !dr_ClipWall( &Wall ) )
  152.         return WallOffScreen;
  153.     
  154.     // Project it to get all the screen coordinates.
  155.     if( !dr_ProjectWall( &Wall ) )
  156.         return WallOffScreen;
  157.     
  158.     // Clip the wall's x coordinates against the current clip stuff.
  159.     return dr_TableClipAndDrawWall( &Wall );
  160. }
  161.  
  162.  
  163. SideDir dr_PruneTree( CLine *pLine )
  164. {
  165. // Check if the wall is off AND it doesn't touch the viewing angles, in which case it has
  166. // a whole invisible subtree.
  167.  
  168.     // TEMPORARY:  Return intercept until this routine is implemented.
  169.     pLine=pLine;
  170.     return Intersect;
  171.  
  172. }
  173.  
  174.  
  175. BOOL dr_TransformWall( ProcessWall *pWall )
  176. {
  177.     WORD localX1, localY1, localX2, localY2;
  178.     WORD texOriginX, texOriginY, texHorzX, texHorzY;
  179.         
  180.     
  181.     // Rotate the Line's coordinates.
  182.     localX1 = pWall->pLine->pPoint1->localX + translateX;
  183.     localY1 = pWall->pLine->pPoint1->localY + translateY;
  184.     localX2 = pWall->pLine->pPoint2->localX + translateX;
  185.     localY2 = pWall->pLine->pPoint2->localY + translateY;
  186.     
  187.     pWall->x1 = ((localX1 * playerAngleCosine) - (localY1 * playerAngleSine));
  188.     pWall->y1 = ((localX1 * playerAngleSine) + (localY1 * playerAngleCosine));
  189.     pWall->x2 = ((localX2 * playerAngleCosine) - (localY2 * playerAngleSine));
  190.     pWall->y2 = ((localX2 * playerAngleSine) + (localY2 * playerAngleCosine));
  191.  
  192.     pWall->normalX = FMul(pWall->pLine->A, playerAngleCosine) - FMul(pWall->pLine->B, playerAngleSine) + translateX;
  193.     pWall->normalY = FMul(pWall->pLine->A, playerAngleSine) + FMul(pWall->pLine->B, playerAngleCosine) + translateY;
  194.  
  195.     
  196.     // Fill in texture mapping stuff.
  197.     texOriginX = pWall->pLine->texOriginX + translateX;
  198.     texOriginY = pWall->pLine->texOriginY + translateY;
  199.     texHorzX = pWall->pLine->texHorzX + translateX;
  200.     texHorzY = pWall->pLine->texHorzY + translateY;
  201.  
  202.     pWall->originX = ((texOriginX * playerAngleCosine) - (texOriginY * playerAngleSine));
  203.     pWall->originZ = ((texOriginX * playerAngleSine) + (texOriginY * playerAngleCosine));
  204.     pWall->horzX = ((texHorzX * playerAngleCosine) - (texHorzY * playerAngleSine));
  205.     pWall->horzZ = ((texHorzX * playerAngleSine) + (texHorzY * playerAngleCosine));
  206.  
  207.  
  208.     // Set which side the player is looking at and, if there's no texture there, don't draw the wall.
  209.     if( pWall->viewSide == LeftSide )
  210.     {
  211.         if( pWall->pLine->idLeftTex == BAD_TEXTURE_ID )
  212.             return FALSE;
  213.         else
  214.             pWall->viewSide = LeftSide;
  215.     }
  216.     else
  217.     {
  218.         if( pWall->pLine->idRightTex == BAD_TEXTURE_ID )
  219.             return FALSE;
  220.         else
  221.             pWall->viewSide = RightSide;
  222.     }
  223.         
  224.     
  225.     return TRUE;
  226. }
  227.  
  228.  
  229. BOOL dr_ClipWall( ProcessWall *pWall )
  230. {
  231.     // Used for clipping against the view boundaries.
  232.     Fixed x1, y1, x2, y2;
  233.     Angle rotateAngle;
  234.     WORD pointClipped;
  235.  
  236.     
  237.     
  238.     // First check if it even needs to be clipped.
  239.     if( pWall->y1 > CLIP_Z && pWall->y2 > CLIP_Z )
  240.     {
  241.         pWall->t1 = 0;
  242.         pWall->t2 = FIXED_ONE;
  243.     }
  244.     else if( pWall->y1 <= CLIP_Z && pWall->y2 <= CLIP_Z )
  245.         return FALSE;
  246.     else
  247.     {
  248.         // Clip against z=CLIP_Z.
  249.         dr_ClipAgainstLine( CLIP_Z, &pWall->x1, &pWall->y1, &pWall->x2, &pWall->y2, &pWall->t1, &pWall->t2, TRUE );
  250.     }
  251.  
  252.  
  253.     // Now clip the Line against the viewing angles.
  254.     
  255.     // Clip against the right side.
  256.     rotateAngle = (ANGLE_RES-xViewAngle) & ANGLE_MASK;
  257.     RotatePointFixed( 0, 0, rotateAngle, pWall->x1, pWall->y1, &x1, &y1 );
  258.     RotatePointFixed( 0, 0, rotateAngle, pWall->x2, pWall->y2, &x2, &y2 );
  259.  
  260.     // Check if it needs to be clipped at all.
  261.     if( y1 < 0 && y2 < 0 )
  262.         return FALSE;
  263.     else if( y1 > 0 && y2 > 0 )
  264.         ;
  265.     else
  266.     {
  267.         // Clip it.
  268.         pointClipped = dr_ClipAgainstLine( 0, &x1, &y1, &x2, &y2, &pWall->t1, &pWall->t2, TRUE );
  269.         
  270.         // Rotate the point that got clipped back.
  271.         rotateAngle = xViewAngle;
  272.         if( pointClipped == 1 )
  273.             RotatePointFixed( 0, 0, rotateAngle, x1, y1, &pWall->x1, &pWall->y1 );
  274.         else
  275.             RotatePointFixed( 0, 0, rotateAngle, x2, y2, &pWall->x2, &pWall->y2 );
  276.     }
  277.  
  278.  
  279.  
  280.     // Clip against the left side (xViewAngle+HALF_PI).
  281.     rotateAngle = (ANGLE_RES - (PI-xViewAngle)) & ANGLE_MASK;
  282.     RotatePointFixed( 0, 0, rotateAngle, pWall->x1, pWall->y1, &x1, &y1 );
  283.     RotatePointFixed( 0, 0, rotateAngle, pWall->x2, pWall->y2, &x2, &y2 );
  284.  
  285.     // Check if it needs to be clipped at all.
  286.     if( y1 > 0 && y2 > 0 )
  287.         return FALSE;
  288.     else if( y1 < 0 && y2 < 0 )
  289.         ;
  290.     else
  291.     {
  292.         // Clip it.
  293.         pointClipped = dr_ClipAgainstLine( 0, &x1, &y1, &x2, &y2, &pWall->t1, &pWall->t2, FALSE );
  294.         
  295.         // Rotate the point that got clipped back.
  296.         rotateAngle = PI-xViewAngle;
  297.         
  298.         if( pointClipped == 1 )        
  299.             RotatePointFixed( 0, 0, rotateAngle, x1, y1, &pWall->x1, &pWall->y1 );
  300.         else
  301.             RotatePointFixed( 0, 0, rotateAngle, x2, y2, &pWall->x2, &pWall->y2 );
  302.     }
  303.  
  304.  
  305.     return TRUE;
  306. }
  307.  
  308.                                                                                                                   
  309. BOOL dr_ProjectWall( ProcessWall *pWall )
  310. {
  311.     WORD tempX;
  312.  
  313.     WORD y1Top, y2Top;
  314.     WORD y1Bottom, y2Bottom;
  315.     
  316.     Fixed x1Div, x2Div, y1Div, y2Div;
  317.     
  318.     BYTE drawColor;
  319.  
  320.     
  321.     // Keep in mind, pWall->y1 & 2 is really z1 & 2...
  322.     x1Div = pWall->y1 / xWorldScale;
  323.     x2Div = pWall->y2 / xWorldScale;
  324.  
  325.     y1Div = pWall->y1 / yWorldScale;
  326.     y2Div = pWall->y2 / yWorldScale;    
  327.  
  328.     pWall->screenX1 = W_UNFIX( FDiv( pWall->x1, x1Div ) ) + centerX;
  329.     pWall->screenX2 = W_UNFIX( FDiv( pWall->x2, x2Div ) ) + centerX;
  330.  
  331.     if( pWall->screenX1 == pWall->screenX2 )
  332.         return FALSE;
  333.  
  334.     y1Top = W_UNFIX( FDiv( topY, y1Div ) ) + centerY;
  335.     y1Bottom = W_UNFIX( FDiv( bottomY, y1Div ) ) + centerY;
  336.     
  337.     y2Top = W_UNFIX( FDiv( topY, y2Div ) ) + centerY;
  338.     y2Bottom = W_UNFIX( FDiv( bottomY, y2Div ) ) + centerY;
  339.  
  340.  
  341.     // Fill in the information for the top and bottom lines.
  342.     pWall->topSlope = FIX(y2Top - y1Top) / (pWall->screenX2 - pWall->screenX1);
  343.     pWall->bottomSlope = FIX(y2Bottom - y1Bottom) / (pWall->screenX2 - pWall->screenX1);
  344.  
  345.     pWall->yTopIntercept = y1Top - W_UNFIX(pWall->screenX1 * pWall->topSlope);
  346.     pWall->yBottomIntercept = y1Bottom - W_UNFIX(pWall->screenX1 * pWall->bottomSlope);
  347.     
  348.  
  349.     // Make sure screenX 1 and 2 go from left to right.
  350.     if( pWall->screenX1 > pWall->screenX2 )
  351.     {
  352.         tempX = pWall->screenX1;
  353.         pWall->screenX1 = pWall->screenX2;
  354.         pWall->screenX2 = tempX;
  355.     
  356.         pWall->bFlippedX = TRUE;
  357.     }
  358.     else
  359.         pWall->bFlippedX = FALSE;
  360.  
  361.  
  362.     // Show the projected points.
  363.     if( bDisplayProjectionPoints )
  364.     {
  365.         drawColor = 35;
  366.         
  367.         if( tempX == pWall->screenX2 )
  368.         {
  369.             s_SetPixel( pWall->screenX2, y1Top, drawColor );    
  370.             s_SetPixel( pWall->screenX2, y1Bottom, drawColor );    
  371.             s_SetPixel( pWall->screenX1, y2Top, drawColor );    
  372.             s_SetPixel( pWall->screenX1, y2Bottom, drawColor );    
  373.         }
  374.         else
  375.         {
  376.             s_SetPixel( pWall->screenX1, y1Top, drawColor );    
  377.             s_SetPixel( pWall->screenX1, y1Bottom, drawColor );    
  378.             s_SetPixel( pWall->screenX2, y2Top, drawColor );
  379.             s_SetPixel( pWall->screenX2, y2Bottom, drawColor );    
  380.         }
  381.     }
  382.  
  383.  
  384.     // Set the unclipped ones here.
  385.     pWall->unclippedScreenX1 = pWall->screenX1;
  386.     pWall->unclippedScreenX2 = pWall->screenX2;
  387.  
  388.     
  389.     return TRUE;
  390. }
  391.  
  392.  
  393.  
  394. DrawReturn dr_TableClipAndDrawWall( ProcessWall *pWall )
  395. {
  396.     X_Clip    *pCurNode, *pPrevNode, *pNewNode;
  397.     BOOL    bIn;
  398.     
  399.     
  400.     
  401. // Screen boundary clipping.
  402. //////////////////////
  403.     
  404.     // Test if it's all the way off the screen.
  405.     if( pWall->screenX2 < s_MinX )
  406.         return WallOffScreen;
  407.     
  408.     if( pWall->screenX1 >= s_MaxX )
  409.         return WallOffScreen;
  410.     
  411.     if( pWall->screenX1 < s_MinX )
  412.         pWall->screenX1 = s_MinX;
  413.     
  414.     if( pWall->screenX2 >= s_MaxX )
  415.         pWall->screenX2 = s_MaxX;
  416.  
  417.     if( pWall->screenX1 == pWall->screenX2 )
  418.         return DrewWall;
  419.     
  420.     
  421. // Find where the Line enters into the table.  Insert a new X_Clip in the table
  422. // if necessary.
  423.  
  424.     pCurNode = &headNode;
  425.     pPrevNode = &headNode;
  426.  
  427.     bIn = FALSE;
  428.     
  429.     while( pCurNode->pNext != pCurNode )
  430.     {
  431.         if( pWall->screenX1 >= pCurNode->x && pWall->screenX1 < pCurNode->pNext->x )
  432.         {
  433.             if( bIn )
  434.             {
  435.                 // Doesn't matter what these are because you're not going to be drawing anything
  436.                 // at screenX1.
  437.                 pPrevNode = pCurNode;
  438.                 break;
  439.             }
  440.             else if( (pWall->screenX1 - pCurNode->x) < 1 && pCurNode != &headNode )
  441.             {
  442.                 break;
  443.             }
  444.             else
  445.             {
  446.                 pNewNode = GetXClip();
  447.                 pNewNode->x = pWall->screenX1;
  448.                 
  449.                 pNewNode->pNext = pCurNode->pNext;
  450.                 pCurNode->pNext = pNewNode;
  451.  
  452.                 pCurNode = pNewNode;
  453.                 pPrevNode = pCurNode;
  454.                 break;    
  455.             }                                
  456.         }            
  457.     
  458.         // Advance in the list and update the in/out flag.
  459.         pPrevNode = pCurNode;
  460.         pCurNode = pCurNode->pNext;
  461.         bIn = !bIn;
  462.     }
  463.  
  464.  
  465.  
  466. // At this point, pPrevNode = pCurNode, and bIn is valid.  Draw and remove edges until
  467. // you hit pWall->screenX2.
  468.  
  469.     while( pCurNode->pNext != pCurNode )
  470.     {
  471.         // If you're at the end of the Line...
  472.         if( pWall->screenX2 <= pCurNode->pNext->x || pCurNode->pNext == &tailNode )
  473.         {
  474.             if( !bIn )
  475.             {
  476.                 if( pCurNode->pNext->x - pWall->screenX2 < 1 )
  477.                 {
  478.                     pPrevNode->pNext = pCurNode->pNext->pNext;
  479.                     dr_DrawHorizontalStrip( pWall, pCurNode->x, pWall->screenX2 );
  480.                 }
  481.                 else
  482.                 {                
  483.                     // If you're in open space, add a new edge for screenX2 and get rid of the 
  484.                     // current edge.
  485.                     pNewNode = GetXClip();
  486.                     pNewNode->x = pWall->screenX2;
  487.                 
  488.                     pNewNode->pNext = pCurNode->pNext;
  489.                     pPrevNode->pNext = pNewNode;
  490.                     dr_DrawHorizontalStrip( pWall, pCurNode->x, pWall->screenX2 );
  491.                 }
  492.             }
  493.             else
  494.             {
  495.                 pPrevNode->pNext = pCurNode->pNext;            
  496.             }
  497.             
  498.             break;
  499.         }
  500.         
  501.         if( !bIn )
  502.             dr_DrawHorizontalStrip( pWall, pCurNode->x, pCurNode->pNext->x );
  503.             
  504.         
  505.         pPrevNode->pNext = pCurNode->pNext;
  506.         pCurNode = pCurNode->pNext;            
  507.         bIn = !bIn;
  508.     }
  509.  
  510.  
  511.     // Check if the whole screen is drawn.
  512.     if( (headNode.pNext->x == s_MinX && headNode.pNext->pNext->x == s_MaxX) || headNode.pNext->x == s_MaxX )
  513.         return ScreenCompletelyDrawn;
  514.     else
  515.         return DrewWall;
  516. }
  517.  
  518.  
  519.  
  520. X_Clip *GetXClip()
  521. {
  522.     X_Clip *pRetVal;
  523.     
  524.     pRetVal = &clipSpace[nClipsUsed++];
  525.     assert(nClipsUsed < MAX_X_CLIPS);
  526.     return pRetVal;
  527. }
  528.  
  529.  
  530. void dr_DrawHorizontalStrip( ProcessWall *pWall, WORD xLeft, WORD xRight )
  531. {
  532.     Fixed tLeft, tRight;
  533.  
  534.     Fixed curTopY, curBottomY;
  535.     WORD x;
  536.     
  537.     BYTE *pPaletteMap;
  538.     DWORD paletteMap;
  539.  
  540.     Fixed worldXStart, worldZStart;
  541.     Fixed worldXEnd, worldZEnd;
  542.     Fixed worldXStep, worldZStep;
  543.     Fixed fixedWorldX, fixedWorldZ;
  544.     DWORD worldX, worldZ;
  545.     
  546.     WORD xTexturePos=0;
  547.     Texture *pTexture, *pSky;
  548.     
  549.     // Stuff for showing projection lines.
  550.     DWORD y1, y2;
  551.     BYTE color1=30, color2=130;
  552.     
  553.     // Texture mapping variables.
  554.     Fixed a, c, u;
  555.     
  556.     WORD unfixedTopY, unfixedBottomY;
  557.     Fixed textureStep, textureClipAdd, tempStep, texturePos;
  558.     BYTE *pParallax;
  559.         
  560.  
  561. #pragma aux dr_WallLine =    \
  562. "mov eax,texturePos"    \
  563. "sub eax,textureStep"    \
  564. "LOOP_AGAIN:"    \
  565. "add eax,textureStep"    \
  566. "mov texturePos,eax"    \
  567. "shr eax,20"    \
  568. "xor edx,edx"    \
  569. "mov dl,[esi+eax]"    \
  570. "mov al, [ebx+edx]"    \
  571. "mov [edi],al"    \
  572. "mov eax,texturePos"    \
  573. "add edi,s_PagedWidth"    \
  574. "loopnz LOOP_AGAIN"    \
  575. modify [edx]    \
  576. parm [edi] [esi] [ebx] [eax] [ecx];
  577.  
  578.  
  579. #pragma aux dr_ParallaxLine = \
  580. "push ebp"    \
  581. "mov ebp,s_PagedWidth"    \
  582. "LOOP_AGAIN:"    \
  583. "xor eax,eax"    \
  584. "lodsb"    \
  585. "mov dl,[ebx+eax]"    \
  586. "mov [edi],dl"    \
  587. "add edi,ebp"    \
  588. "loopnz LOOP_AGAIN"    \
  589. "pop ebp"    \
  590. modify [eax]    \
  591. parm [edi] [esi] [ebx] [ecx];
  592.  
  593.  
  594. #pragma aux dr_BlankVLine = \
  595. "LOOP_AGAIN:"    \
  596. "mov [edi],al"    \
  597. "add edi,esi"    \
  598. "loopnz LOOP_AGAIN"    \
  599. parm [edi] [ecx] [esi] [al];
  600.  
  601.     
  602.     // Increment the Y coordinates.
  603.     curTopY = (pWall->topSlope * (Fixed)xLeft) + FIX(pWall->yTopIntercept);                                               
  604.     curBottomY = (pWall->bottomSlope * (Fixed)xLeft) + FIX(pWall->yBottomIntercept);
  605.  
  606.     if( pWall->viewSide == RightSide )
  607.     {
  608.         pTexture = tx_GetTexture( pWall->pLine->idRightTex );
  609.  
  610.         tLeft = FIX(xLeft - pWall->unclippedScreenX1) / (pWall->unclippedScreenX2 - pWall->unclippedScreenX1);
  611.         tRight = FIX(xRight - pWall->unclippedScreenX1) / (pWall->unclippedScreenX2 - pWall->unclippedScreenX1);
  612.     }
  613.     else
  614.     {
  615.         pTexture = tx_GetTexture( pWall->pLine->idLeftTex );
  616.  
  617.         tLeft = FIX(xRight - pWall->unclippedScreenX1) / (pWall->unclippedScreenX2 - pWall->unclippedScreenX1);
  618.         tRight = FIX(xLeft - pWall->unclippedScreenX1) / (pWall->unclippedScreenX2 - pWall->unclippedScreenX1);
  619.     }        
  620.  
  621.     worldXStart = pWall->x1 + FMul(tLeft, pWall->x2 - pWall->x1);
  622.     worldZStart = pWall->y1 + FMul(tLeft, pWall->y2 - pWall->y1);
  623.     worldXEnd = pWall->x1 + FMul(tRight, pWall->x2 - pWall->x1);
  624.     worldZEnd = pWall->y1 + FMul(tRight, pWall->y2 - pWall->y1);
  625.     worldXStep = (worldXEnd - worldXStart) / (xRight-xLeft);
  626.     worldZStep = (worldZEnd - worldZStart) / (xRight-xLeft);
  627.  
  628.     fixedWorldX = worldXStart;
  629.     fixedWorldZ = worldZStart;
  630.     
  631.     
  632.     // Set up texture mapping stuff for this Wall (if it's not already.)
  633.     if( !pWall->bTextureInitted )
  634.     {
  635.         pWall->Px = pWall->originX;
  636.         pWall->Py = bottomY;
  637.         pWall->Pz = pWall->originZ / xWorldScale;
  638.     
  639.         pWall->Mx = (pWall->horzX - pWall->originX);
  640.         pWall->My = 0;
  641.         pWall->Mz = (pWall->horzZ - pWall->originZ) / xWorldScale;
  642.             
  643.         pWall->Nx = 0;
  644.         pWall->Ny = topY - bottomY;
  645.         pWall->Nz = 0;
  646.     
  647.         // Magic numbers..
  648.         pWall->Oa = -FMul(pWall->Ny,pWall->Px);
  649.         pWall->Ha = FMul(pWall->Ny,pWall->Pz);
  650.         
  651.         pWall->Oc = -FMul(pWall->Mx,pWall->Ny);
  652.         pWall->Hc = FMul(pWall->Mz,pWall->Ny);
  653.         
  654.         pWall->bTextureInitted = TRUE;
  655.     }
  656.         
  657.  
  658.     // Set up the texture mapping.
  659.     a = pWall->Oa + ((xLeft-centerX) * pWall->Ha);
  660.     c = pWall->Oc + ((xLeft-centerX) * pWall->Hc);
  661.     
  662.  
  663.     // Get a pointer to the sky texture.
  664.     pSky = tx_GetTexture( curLevel.idCurSky );
  665.     
  666.     // Draw from xLeft to xRight.
  667.     for( x=xLeft; x < xRight; x++ )
  668.     {
  669.         worldX = UNFIX(fixedWorldX);
  670.         worldZ = UNFIX(fixedWorldZ);
  671.         fixedWorldX += worldXStep;
  672.         fixedWorldZ += worldZStep;
  673.  
  674.  
  675.         // Get the texture position.
  676.         a += pWall->Ha;
  677.         c += pWall->Hc;
  678.         u = FDiv(a,c);
  679.         xTexturePos = (u >> pTexture->xTextureShift) & pTexture->xTextureMask;
  680.     
  681.  
  682.         // Get the right palette map.
  683.         if( bBlackAndWhite )
  684.         {
  685.             pPaletteMap = blackWhitePal;
  686.         }
  687.         else
  688.         {
  689.             paletteMap = (worldZ * worldZ) >> (FIXED_SHIFT-5);
  690.             
  691. #ifndef PALETTE_MAPS
  692.             paletteMap = (FIX(paletteMap) / zFadeOut) >> (FIXED_SHIFT-5);
  693. #else
  694.             paletteMap = (FIX(paletteMap) / zFadeOut) >> (FIXED_SHIFT-6);
  695. #endif
  696.             if( paletteMap >= nPaletteMaps )
  697.                 paletteMap = nPaletteMaps-1;
  698.             
  699.             pPaletteMap = pPaletteMaps[paletteMap];
  700.         }
  701.         
  702.         
  703.         // Do the actual drawing of the vertical lines.
  704.         unfixedTopY = UNFIX(curTopY);
  705.         unfixedBottomY = UNFIX(curBottomY);
  706.         textureStep = FDiv(FIX(pTexture->height-1)<<TEXTURE_FIX, (curBottomY - curTopY));
  707.         
  708.         if( unfixedTopY > s_MinY )
  709.         {   
  710.             // Draw the parallaxing sky.
  711.             pParallax = pSky->pVertLines[ (parallaxLookup.Get(x-s_MinX) + player.facingAngle) & pSky->xTextureMask ];
  712.             
  713.             tempStep = textureStep;
  714.             textureStep = (FIX(128)<<TEXTURE_FIX) / (centerY - s_MinY);
  715.  
  716. texturePos = 0;
  717.  
  718.             dr_WallLine( &pScreenMem[(s_MinY*s_PagedWidth) + s_PageLookup[x]], pParallax, pPaletteMaps[parallaxMap], s_MinX, unfixedTopY );
  719.             textureStep = tempStep;
  720.             
  721.  
  722.             // Do the texture map.
  723.             textureClipAdd = textureStep * unfixedTopY;
  724.             textureClipAdd -= FMul(textureStep, curTopY - FIXED_ONE);
  725.  
  726. texturePos = textureClipAdd;
  727.  
  728.             if( unfixedBottomY >= s_MaxY )
  729.                 dr_WallLine( &pScreenMem[(unfixedTopY*s_PagedWidth) + s_PageLookup[x]], pTexture->pVertLines[xTexturePos], pPaletteMap, textureClipAdd, s_MaxY-unfixedTopY );
  730.             else                                                                                       
  731.                 dr_WallLine( &pScreenMem[(unfixedTopY*s_PagedWidth) + s_PageLookup[x]], pTexture->pVertLines[xTexturePos], pPaletteMap, textureClipAdd, unfixedBottomY-unfixedTopY );
  732.         }
  733.         else
  734.         {
  735.             textureClipAdd = FMul(textureStep, FIX(s_MinY)-curTopY + FIXED_ONE);
  736.  
  737. texturePos = textureClipAdd;
  738.             
  739.             if( unfixedBottomY >= s_MaxY )
  740.                 dr_WallLine( &pScreenMem[(s_MinY*s_PagedWidth) + s_PageLookup[x]], pTexture->pVertLines[xTexturePos], pPaletteMap, textureClipAdd, s_DrawHeight );
  741.             else
  742.                 dr_WallLine( &pScreenMem[(s_MinY*s_PagedWidth) + s_PageLookup[x]], pTexture->pVertLines[xTexturePos], pPaletteMap, textureClipAdd, unfixedBottomY );
  743.         }
  744.         
  745.         if( unfixedBottomY < s_MaxY )
  746.             dr_BlankVLine( &pScreenMem[((DWORD)unfixedBottomY*s_PagedWidth)+s_PageLookup[x]], s_Height-unfixedBottomY, s_PagedWidth, 0 );
  747.         
  748.         // Increment top and bottom lines.
  749.         curTopY += pWall->topSlope;
  750.         curBottomY += pWall->bottomSlope;
  751.     }
  752.  
  753.     if( bDisplayProjectionPoints )
  754.     {
  755.         if( pWall->viewSide == LeftSide )
  756.         {
  757.             // Left side has lines going up and down.
  758.             
  759.             y1 = W_UNFIX(pWall->screenX1 * pWall->topSlope) + pWall->yTopIntercept;
  760.             y2 = W_UNFIX(pWall->screenX1 * pWall->bottomSlope) + pWall->yBottomIntercept;
  761.             dr_DrawLine( pWall->screenX1, y1, pWall->screenX1, y2, s_MaxX, s_MaxY, color1 );    
  762.         
  763.             y1 = W_UNFIX(pWall->screenX2 * pWall->topSlope) + pWall->yTopIntercept;
  764.             y2 = W_UNFIX(pWall->screenX2 * pWall->bottomSlope) + pWall->yBottomIntercept;
  765.             dr_DrawLine( pWall->screenX2, y1, pWall->screenX2, y2, s_MaxX, s_MaxY, color1 );
  766.         }
  767.         else
  768.         {
  769.             // Right side has lines going left to right.
  770.             
  771.             y1 = W_UNFIX(pWall->screenX1 * pWall->topSlope) + pWall->yTopIntercept;
  772.             y2 = W_UNFIX(pWall->screenX2 * pWall->topSlope) + pWall->yTopIntercept;
  773.             dr_DrawLine( pWall->screenX1, y1, pWall->screenX2, y2, s_MaxX, s_MaxY, color2 );
  774.  
  775.             y1 = W_UNFIX(pWall->screenX1 * pWall->bottomSlope) + pWall->yBottomIntercept;
  776.             y2 = W_UNFIX(pWall->screenX2 * pWall->bottomSlope) + pWall->yBottomIntercept;
  777.             dr_DrawLine( pWall->screenX1, y1, pWall->screenX2, y2, s_MaxX, s_MaxY, color2 );
  778.         }    
  779.     }
  780. }
  781.  
  782. /*
  783. void dr_WallLine( BYTE *pDrawTo, BYTE *pBuffer, BYTE *pPaletteMap, Fixed bufferStartPos, Fixed bufferAdd, WORD vLineInc, WORD numPixels )
  784. {
  785.     WORD i;
  786.     Fixed bufferPos;
  787.     BYTE color;
  788.     
  789.     bufferPos=bufferStartPos;
  790.     for( i=0; i < numPixels; i++ )
  791.     {
  792.         color = pBuffer[bufferPos >> (FIXED_SHIFT+TEXTURE_FIX)];
  793.         *pDrawTo = pPaletteMap[color];
  794.     
  795.         bufferPos += bufferAdd;
  796.         pDrawTo += vLineInc;
  797.     }
  798. }
  799. */
  800.  
  801. /*
  802. void dr_ParallaxLine( BYTE *pDrawTo, BYTE *pBuffer, BYTE *pPaletteMap, DWORD vLineInc, DWORD numPixels )
  803. {
  804.     WORD i;
  805.     
  806.     for( i=0; i < numPixels; i++ )
  807.     {
  808.         *pDrawTo = pPaletteMap[*pBuffer];
  809.     
  810.         ++pBuffer;
  811.         pDrawTo += vLineInc;
  812.     }
  813. }
  814. */
  815.  
  816. void Draw2DEnvironment( CLineArray *pLines, CPointArray *pPoints, WORD xOffset, WORD yOffset, Fixed scale, WORD maxX, WORD maxY )
  817. {
  818.     Fixed x1, y1, x2, y2;
  819.     Fixed x, y;
  820.     WORD drawX, drawY;
  821.     WORD i;
  822.     CLine *pCurLine;
  823.     CPoint *pCurPt;    
  824.  
  825.     // Draw all the Lines.
  826.     for( i=0; i < pLines->NumElements(); i++ )
  827.     {
  828.         pCurLine = pLines->GetLine(i);
  829.  
  830.         x1 = xOffset + pCurLine->pPoint1->localX;            
  831.         y1 = yOffset + pCurLine->pPoint1->localY;
  832.         x2 = xOffset + pCurLine->pPoint2->localX;
  833.         y2 = yOffset + pCurLine->pPoint2->localY;
  834.     
  835.         x1 = x1 * scale;
  836.         y1 = y1 * scale;
  837.         x2 = x2 * scale;
  838.         y2 = y2 * scale;
  839.  
  840.         dr_DrawLine( W_UNFIX(x1), -W_UNFIX(y1), W_UNFIX(x2), -W_UNFIX(y2), maxX, maxY, 30 );
  841.     }
  842.         
  843.  
  844.     // Draw all the Points.
  845.     for( i=0; i < pPoints->NumElements(); i++ )
  846.     {
  847.         pCurPt = pPoints->GetPoint(i);
  848.  
  849.         x = xOffset + pCurPt->localX;
  850.         y = yOffset + pCurPt->localY;
  851.  
  852.         x = x * scale;
  853.         y = y * scale;
  854.             
  855.         drawX = W_UNFIX(x);
  856.         drawY = -W_UNFIX(y);
  857.         
  858.         if( drawX >= 0 && drawX < maxX && drawY >= 0 && drawY < maxY )
  859.             pScreenMem[ (drawY*s_PagedWidth) + s_PageLookup[drawX] ] = 60;
  860.     }
  861.                           
  862.     s_SetPixel( W_UNFIX(player.xPos*scale), W_UNFIX(player.yPos*scale), 120 );
  863. }
  864.  
  865.  
  866. void dr_DrawLine( DWORD x1, DWORD y1, DWORD x2, DWORD y2, WORD maxX, WORD maxY, BYTE color )
  867. {
  868.     WORD numPixels;
  869.     WORD i;
  870.     Fixed curX, curY, xInc, yInc;
  871.     WORD x, y;
  872.  
  873.     // Test if it's off the screen so we might not have to draw it.
  874.     if( (x1 < 0 || x1 >= maxX) && (y1 < 0 || y1 >= maxY) &&
  875.         (x2 < 0 || x2 >= maxX) && (y2 < 0 || y2 >= maxY) )
  876.         return;
  877.     
  878.     if( ABS(x2-x1) > ABS(y2-y1) )
  879.         numPixels = (WORD)ABS(x2-x1);
  880.     else
  881.         numPixels = (WORD)ABS(y2-y1);
  882.  
  883.     if( numPixels < 2 )
  884.         return;
  885.     
  886.     curX = FIX(x1);
  887.     curY = FIX(y1);
  888.  
  889.     xInc = FIX(x2-x1) / numPixels;
  890.     yInc = FIX(y2-y1) / numPixels;
  891.  
  892.     for( i=0; i < numPixels; i++ )
  893.     {
  894.         x = W_UNFIX(curX);
  895.         y = W_UNFIX(curY);
  896.         
  897.         if( x >= 0 && x < maxX && y >= 0 && y < maxY )
  898.             pScreenMem[ s_PageLookup[x] + (y*s_PagedWidth) ] = color;
  899.  
  900.         curX += xInc;
  901.         curY += yInc;
  902.     }
  903. }
  904.  
  905.  
  906. WORD dr_ClipAgainstLine( Fixed clipLine, Fixed *pX1, Fixed *pY1, Fixed *pX2, Fixed *pY2, Fixed *pT1, Fixed *pT2, BOOL bPositiveHalf )
  907. {
  908.     assert( *pY1 != *pY2 );
  909.  
  910.     // Replace (x1,y1) or (x2,y2), depending on which one was off the screen.
  911.     if( bPositiveHalf )
  912.     {
  913.         if( *pY1 < clipLine )
  914.         {
  915.             *pT1 = FDiv( clipLine - *pY1, *pY2 - *pY1 );
  916.             *pT2 = FIXED_ONE;
  917.  
  918.             *pX1 = *pX1 + FMul(*pT1, *pX2 - *pX1);
  919.             *pY1 = *pY1 + FMul(*pT1, *pY2 - *pY1);
  920.  
  921.             return 1;
  922.         }
  923.         else
  924.         {
  925.             *pT1 = 0;
  926.             *pT2 = FDiv( clipLine - *pY1, *pY2 - *pY1 );
  927.         
  928.             *pX2 = *pX1 + FMul(*pT2, *pX2 - *pX1);
  929.             *pY2 = *pY1 + FMul(*pT2, *pY2 - *pY1);
  930.         
  931.             return 2;
  932.         }
  933.     }
  934.     else
  935.     {
  936.         if( *pY1 < clipLine )
  937.         {
  938.             *pT1 = 0;
  939.             *pT2 = FDiv( clipLine - *pY1, *pY2 - *pY1 );
  940.                 
  941.             *pX2 = *pX1 + FMul(*pT2, *pX2 - *pX1);
  942.             *pY2 = *pY1 + FMul(*pT2, *pY2 - *pY1);
  943.         
  944.             return 2;
  945.         }
  946.         else
  947.         {
  948.             *pT1 = FDiv( *pY1 - clipLine, *pY2 - *pY1 );
  949.             *pT2 = FIXED_ONE;
  950.         
  951.             *pX1 = *pX1 - FMul(*pT1, *pX2 - *pX1);
  952.             *pY1 = *pY1 - FMul(*pT1, *pY2 - *pY1);
  953.         
  954.             return 1;
  955.         }
  956.     }
  957.  
  958.     return 0;
  959. }                                               
  960.  
  961.  
  962.  
  963.