home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the 3D Game Programming Gurus / gurus.iso / Articles / TextureMapMania / tmapper.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-02-05  |  19.4 KB  |  878 lines

  1. // TMAPPER.CPP - The texture mapping function
  2. // compile this and link it to the TMAPDEMO.CPP to
  3. // make a complete executable
  4. // Affine Texture Mapper, for 256 color linear
  5. // memory 64x64 pixel texture mapping of 3 vertex polys.
  6. // there's an example at the bottom!
  7.  
  8. #include <iostream.h> // include important C/C++ stuff
  9. #include <conio.h>
  10. #include <stdlib.h>
  11. #include <malloc.h>
  12. #include <memory.h>
  13. #include <string.h>
  14. #include <stdarg.h>
  15. #include <stdio.h> 
  16. #include <math.h>
  17.  
  18. #include "tmapper.h" // include all the header info and classes
  19.  
  20. // GLOBALS /////////////////////////////////////////////////////////////////
  21.  
  22. // the viewport to clip to, can be smaller than the screen
  23. extern int poly_clip_min_x,
  24.            poly_clip_max_x,
  25.            poly_clip_min_y,
  26.            poly_clip_max_y;
  27.  
  28. // FUNCTIONS ////////////////////////////////////////////////////////////////
  29.  
  30.  
  31. void Draw_Textured_Triangle(void *vface,          // ptr to face
  32.                             UCHAR *dest_buffer,   // pointer to video buffer
  33.                             int mem_pitch)        // bytes per line, 320, 640 etc.
  34. {
  35. // this function draws a textured triangle
  36.  
  37. FACE3D_PTR face; // working face
  38.  
  39. int v0=0,
  40.     v1=1,
  41.     v2=2,
  42.     temp=0,
  43.     tri_type = TRI_TYPE_NONE,
  44.     irestart = INTERP_LHS;
  45.  
  46. int dx,dy,dyl,dyr,      // general deltas
  47.     u,v,
  48.     du,dv,
  49.     xi,yi,              // the current interpolated x,y
  50.     ui,vi,              // the current interpolated u,v
  51.     index_x,index_y,    // looping vars
  52.     x,y,                // hold general x,y
  53.     xstart,
  54.     xend,
  55.     ystart,
  56.     yrestart,
  57.     yend,
  58.     xl,                 
  59.     dxdyl,              
  60.     xr,
  61.     dxdyr,             
  62.     dudyl,    
  63.     ul,
  64.     dvdyl,   
  65.     vl,
  66.     dudyr,
  67.     ur,
  68.     dvdyr,
  69.     vr;
  70.  
  71. int x0,y0,tu0,tv0,    // cached vertices
  72.     x1,y1,tu1,tv1,
  73.     x2,y2,tu2,tv2;
  74.  
  75. UCHAR *screen_ptr  = NULL,
  76.       *screen_line = NULL,
  77.       *textmap     = NULL;
  78.  
  79. // convert void ptr to face
  80. face = (FACE3D_PTR)vface;
  81.  
  82. // extract texture map
  83. textmap = face->texture;
  84.  
  85. // first trivial clipping rejection tests 
  86. if (((face->tlist[0].y < poly_clip_min_y)  && 
  87.      (face->tlist[1].y < poly_clip_min_y)  &&
  88.      (face->tlist[2].y < poly_clip_min_y)) ||
  89.  
  90.     ((face->tlist[0].y > poly_clip_max_y)  && 
  91.      (face->tlist[1].y > poly_clip_max_y)  &&
  92.      (face->tlist[2].y > poly_clip_max_y)) ||
  93.  
  94.     ((face->tlist[0].x < poly_clip_min_x)  && 
  95.      (face->tlist[1].x < poly_clip_min_x)  &&
  96.      (face->tlist[2].x < poly_clip_min_x)) ||
  97.  
  98.     ((face->tlist[0].x > poly_clip_max_x)  && 
  99.      (face->tlist[1].x > poly_clip_max_x)  &&
  100.      (face->tlist[2].x > poly_clip_max_x)))
  101.    return;
  102.  
  103. // degenerate triangle
  104. if ( ((face->tlist[0].x==face->tlist[1].x) && (face->tlist[1].x==face->tlist[2].x)) ||
  105.      ((face->tlist[0].y==face->tlist[1].y) && (face->tlist[1].y==face->tlist[2].y)))
  106.    return;
  107.  
  108. // sort vertices
  109. if (face->tlist[v1].y < face->tlist[v0].y) 
  110.     {SWAP(v0,v1,temp);} 
  111.  
  112. if (face->tlist[v2].y < face->tlist[v0].y) 
  113.     {SWAP(v0,v2,temp);}
  114.  
  115. if (face->tlist[v2].y < face->tlist[v1].y) 
  116.     {SWAP(v1,v2,temp);}
  117.  
  118. // now test for trivial flat sided cases
  119. if (face->tlist[v0].y==face->tlist[v1].y)
  120.     { 
  121.     // set triangle type
  122.     tri_type = TRI_TYPE_FLAT_TOP;
  123.  
  124.     // sort vertices left to right
  125.     if (face->tlist[v1].x < face->tlist[v0].x) 
  126.         {SWAP(v0,v1,temp);}
  127.  
  128.     } // end if
  129. else
  130. // now test for trivial flat sided cases
  131. if (face->tlist[v1].y==face->tlist[v2].y)
  132.     { 
  133.     // set triangle type
  134.     tri_type = TRI_TYPE_FLAT_BOTTOM;
  135.  
  136.     // sort vertices left to right
  137.     if (face->tlist[v2].x < face->tlist[v1].x) 
  138.         {SWAP(v1,v2,temp);}
  139.     
  140.     } // end if
  141. else
  142.     {
  143.     // must be a general triangle
  144.     tri_type = TRI_TYPE_GENERAL;
  145.  
  146.     } // end else
  147.  
  148. // extract vertices for processing, now that we have order
  149. x0  = face->tlist[v0].x;
  150. y0  = face->tlist[v0].y;
  151. tu0 = face->tlist[v0].u;
  152. tv0 = face->tlist[v0].v;
  153.  
  154. x1  = face->tlist[v1].x;
  155. y1  = face->tlist[v1].y;
  156. tu1 = face->tlist[v1].u;
  157. tv1 = face->tlist[v1].v;
  158.  
  159. x2  = face->tlist[v2].x;
  160. y2  = face->tlist[v2].y;
  161. tu2 = face->tlist[v2].u;
  162. tv2 = face->tlist[v2].v;
  163.  
  164. // set interpolation restart value
  165. yrestart = y1;
  166.  
  167. // what kind of triangle
  168. if (tri_type & TRI_TYPE_FLAT_MASK)
  169.     {
  170.  
  171.     if (tri_type == TRI_TYPE_FLAT_TOP)
  172.     {
  173.     // compute all deltas
  174.     dy = (y2 - y0);
  175.  
  176.     dxdyl = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  177.     dudyl = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  178.     dvdyl = ((tv2 - tv0) << FIXP16_SHIFT)/dy;    
  179.  
  180.     dxdyr = ((x2 - x1)   << FIXP16_SHIFT)/dy;
  181.     dudyr = ((tu2 - tu1) << FIXP16_SHIFT)/dy;  
  182.     dvdyr = ((tv2 - tv1) << FIXP16_SHIFT)/dy;   
  183.  
  184.     // test for y clipping
  185.     if (y0 < poly_clip_min_y)
  186.         {
  187.         // compute overclip
  188.         dy = (poly_clip_min_y - y0);
  189.  
  190.         // computer new LHS starting values
  191.         xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  192.         ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  193.         vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  194.  
  195.         // compute new RHS starting values
  196.         xr = dxdyr*dy + (x1  << FIXP16_SHIFT);
  197.         ur = dudyr*dy + (tu1 << FIXP16_SHIFT);
  198.         vr = dvdyr*dy + (tv1 << FIXP16_SHIFT);
  199.  
  200.         // compute new starting y
  201.         ystart = poly_clip_min_y;
  202.  
  203.         } // end if
  204.     else
  205.         {
  206.         // no clipping
  207.  
  208.         // set starting values
  209.         xl = (x0 << FIXP16_SHIFT);
  210.         xr = (x1 << FIXP16_SHIFT);
  211.  
  212.         ul = (tu0 << FIXP16_SHIFT);
  213.         vl = (tv0 << FIXP16_SHIFT);
  214.  
  215.         ur = (tu1 << FIXP16_SHIFT);
  216.         vr = (tv1 << FIXP16_SHIFT);
  217.  
  218.         // set starting y
  219.         ystart = y0;
  220.  
  221.         } // end else
  222.  
  223.     } // end if flat top
  224.     else
  225.     {
  226.     // must be flat bottom
  227.  
  228.     // compute all deltas
  229.     dy = (y1 - y0);
  230.  
  231.     dxdyl = ((x1 - x0)   << FIXP16_SHIFT)/dy;
  232.     dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dy;  
  233.     dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dy;    
  234.  
  235.     dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  236.     dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  237.     dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dy;   
  238.  
  239.     // test for y clipping
  240.     if (y0 < poly_clip_min_y)
  241.         {
  242.         // compute overclip
  243.         dy = (poly_clip_min_y - y0);
  244.  
  245.         // computer new LHS starting values
  246.         xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  247.         ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  248.         vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  249.  
  250.         // compute new RHS starting values
  251.         xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  252.         ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  253.         vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  254.  
  255.         // compute new starting y
  256.         ystart = poly_clip_min_y;
  257.  
  258.         } // end if
  259.     else
  260.         {
  261.         // no clipping
  262.  
  263.         // set starting values
  264.         xl = (x0 << FIXP16_SHIFT);
  265.         xr = (x0 << FIXP16_SHIFT);
  266.  
  267.         ul = (tu0 << FIXP16_SHIFT);
  268.         vl = (tv0 << FIXP16_SHIFT);
  269.  
  270.         ur = (tu0 << FIXP16_SHIFT);
  271.         vr = (tv0 << FIXP16_SHIFT);
  272.  
  273.         // set starting y
  274.         ystart = y0;
  275.  
  276.         } // end else    
  277.  
  278.     } // end else flat bottom
  279.  
  280.     // test for bottom clip, always
  281.     if ((yend = y2) > poly_clip_max_y)
  282.         yend = poly_clip_max_y;
  283.  
  284.     // test for horizontal clipping
  285.     if ((x0 < poly_clip_min_x) || (x0 > poly_clip_max_x) ||
  286.         (x1 < poly_clip_min_x) || (x1 > poly_clip_max_x) ||
  287.         (x2 < poly_clip_min_x) || (x2 > poly_clip_max_x))
  288.     {
  289.     // clip version
  290.  
  291.     // point screen ptr to starting line
  292.     screen_ptr = dest_buffer + (ystart * mem_pitch);
  293.  
  294.     for (yi = ystart; yi<=yend; yi++)
  295.         {
  296.         // compute span endpoints
  297.         xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  298.         xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  299.  
  300.         // compute starting points for u,v interpolants
  301.         ui = ul + FIXP16_ROUND_UP;
  302.         vi = vl + FIXP16_ROUND_UP;
  303.         
  304.         // compute u,v interpolants
  305.         if ((dx = (xend - xstart))>0)
  306.             {
  307.             du = (ur - ul)/dx;
  308.             dv = (vr - vl)/dx;
  309.             } // end if
  310.         else
  311.             {
  312.             du = (ur - ul);
  313.             dv = (vr - vl);
  314.             } // end else
  315.  
  316.         ///////////////////////////////////////////////////////////////////////
  317.  
  318.         // test for x clipping, LHS
  319.         if (xstart < poly_clip_min_x)
  320.             {
  321.             // compute x overlap
  322.             dx = poly_clip_min_x - xstart;
  323.  
  324.             // slide interpolants over
  325.             ui+=dx*du;
  326.             vi+=dx*dv;
  327.             
  328.             // reset vars
  329.             xstart = poly_clip_min_x;
  330.  
  331.             } // end if
  332.         
  333.         // test for x clipping RHS
  334.         if (xend > poly_clip_max_x)
  335.             xend = poly_clip_max_x;
  336.  
  337.         ///////////////////////////////////////////////////////////////////////
  338.  
  339.         // draw span
  340.         for (xi=xstart; xi<=xend; xi++)
  341.             {
  342.             // write textel
  343.                         screen_ptr[xi] = textmap[(ui >> FIXP16_SHIFT) +
  344.                         ((vi >> FIXP16_SHIFT) << 6)];
  345.             
  346.             // interpolate u,v
  347.             ui+=du;
  348.             vi+=dv;
  349.             } // end for xi
  350.  
  351.         // interpolate u,v,x along right and left edge
  352.         xl+=dxdyl;
  353.         ul+=dudyl;
  354.         vl+=dvdyl;
  355.     
  356.         xr+=dxdyr;
  357.         ur+=dudyr;
  358.         vr+=dvdyr;
  359.  
  360.         // advance screen ptr
  361.         screen_ptr+=mem_pitch;
  362.  
  363.         } // end for y
  364.  
  365.     } // end if clip
  366.     else
  367.     {
  368.     // non-clip version
  369.  
  370.     // point screen ptr to starting line
  371.     screen_ptr = dest_buffer + (ystart * mem_pitch);
  372.  
  373.     for (yi = ystart; yi<=yend; yi++)
  374.         {
  375.         // compute span endpoints
  376.         xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  377.         xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  378.         
  379.         // compute starting points for u,v interpolants
  380.         ui = ul + FIXP16_ROUND_UP;
  381.         vi = vl + FIXP16_ROUND_UP;
  382.     
  383.         // compute u,v interpolants
  384.         if ((dx = (xend - xstart))>0)
  385.             {
  386.             du = (ur - ul)/dx;
  387.             dv = (vr - vl)/dx;
  388.             } // end if
  389.         else
  390.             {
  391.             du = (ur - ul);
  392.             dv = (vr - vl);
  393.             } // end else
  394.  
  395.         // draw span
  396.         for (xi=xstart; xi<=xend; xi++)
  397.             {
  398.             // write textel
  399.                         screen_ptr[xi] = textmap[(ui >> FIXP16_SHIFT) +
  400.                         ((vi >> FIXP16_SHIFT) << 6)];
  401.             
  402.             // interpolate u,v
  403.             ui+=du;
  404.             vi+=dv;
  405.             } // end for xi
  406.  
  407.         // interpolate u,v,x along right and left edge
  408.         xl+=dxdyl;
  409.         ul+=dudyl;
  410.         vl+=dvdyl;
  411.     
  412.         xr+=dxdyr;
  413.         ur+=dudyr;
  414.         vr+=dvdyr;
  415.  
  416.         // advance screen ptr
  417.         screen_ptr+=mem_pitch;
  418.  
  419.         } // end for y
  420.  
  421.     } // end if non-clipped
  422.  
  423.     } // end if
  424. else
  425. if (tri_type==TRI_TYPE_GENERAL)
  426.     {
  427.  
  428.     // first test for bottom clip, always
  429.     if ((yend = y2) > poly_clip_max_y)
  430.         yend = poly_clip_max_y;
  431.  
  432.     // pre-test y clipping status
  433.     if (y1 < poly_clip_min_y)
  434.         {
  435.         // compute all deltas
  436.         // LHS
  437.         dyl = (y2 - y1);
  438.  
  439.         dxdyl = ((x2  - x1)  << FIXP16_SHIFT)/dyl;
  440.         dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  441.         dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;    
  442.  
  443.         // RHS
  444.         dyr = (y2 - y0);    
  445.  
  446.         dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  447.         dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  448.         dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  449.         
  450.         // compute overclip
  451.         dyr = (poly_clip_min_y - y0);
  452.         dyl = (poly_clip_min_y - y1);
  453.  
  454.         // computer new LHS starting values
  455.         xl = dxdyl*dyl + (x1  << FIXP16_SHIFT);
  456.         ul = dudyl*dyl + (tu1 << FIXP16_SHIFT);
  457.         vl = dvdyl*dyl + (tv1 << FIXP16_SHIFT);
  458.  
  459.         // compute new RHS starting values
  460.         xr = dxdyr*dyr + (x0  << FIXP16_SHIFT);
  461.         ur = dudyr*dyr + (tu0 << FIXP16_SHIFT);
  462.         vr = dvdyr*dyr + (tv0 << FIXP16_SHIFT);
  463.  
  464.         // compute new starting y
  465.         ystart = poly_clip_min_y;
  466.  
  467.         // test if we need swap to keep rendering left to right
  468.         if (dxdyr > dxdyl)
  469.             {
  470.             SWAP(dxdyl,dxdyr,temp);
  471.             SWAP(dudyl,dudyr,temp);
  472.             SWAP(dvdyl,dvdyr,temp);
  473.             SWAP(xl,xr,temp);
  474.             SWAP(ul,ur,temp);
  475.             SWAP(vl,vr,temp);
  476.             SWAP(x1,x2,temp);
  477.             SWAP(y1,y2,temp);
  478.             SWAP(tu1,tu2,temp);
  479.             SWAP(tv1,tv2,temp);
  480.         
  481.             // set interpolation restart
  482.             irestart = INTERP_RHS;
  483.  
  484.             } // end if
  485.  
  486.         } // end if
  487.     else
  488.     if (y0 < poly_clip_min_y)
  489.         {
  490.         // compute all deltas
  491.         // LHS
  492.         dyl = (y1 - y0);
  493.  
  494.         dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  495.         dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  496.         dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  497.  
  498.         // RHS
  499.         dyr = (y2 - y0);    
  500.  
  501.         dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  502.         dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  503.         dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  504.         
  505.         // compute overclip
  506.         dy = (poly_clip_min_y - y0);
  507.  
  508.         // computer new LHS starting values
  509.         xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  510.         ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  511.         vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  512.  
  513.         // compute new RHS starting values
  514.         xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  515.         ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  516.         vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  517.  
  518.         // compute new starting y
  519.         ystart = poly_clip_min_y;
  520.  
  521.         // test if we need swap to keep rendering left to right
  522.         if (dxdyr < dxdyl)
  523.             {
  524.             SWAP(dxdyl,dxdyr,temp);
  525.             SWAP(dudyl,dudyr,temp);
  526.             SWAP(dvdyl,dvdyr,temp);
  527.             SWAP(xl,xr,temp);
  528.             SWAP(ul,ur,temp);
  529.             SWAP(vl,vr,temp);
  530.             SWAP(x1,x2,temp);
  531.             SWAP(y1,y2,temp);
  532.             SWAP(tu1,tu2,temp);
  533.             SWAP(tv1,tv2,temp);
  534.         
  535.             // set interpolation restart
  536.             irestart = INTERP_RHS;
  537.  
  538.             } // end if
  539.  
  540.         } // end if
  541.     else
  542.         {
  543.         // no initial y clipping
  544.     
  545.         // compute all deltas
  546.         // LHS
  547.         dyl = (y1 - y0);
  548.  
  549.         dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  550.         dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  551.         dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  552.  
  553.         // RHS
  554.         dyr = (y2 - y0);    
  555.  
  556.         dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dyr;
  557.         dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  558.         dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;           
  559.  
  560.         // no clipping y
  561.  
  562.         // set starting values
  563.         xl = (x0 << FIXP16_SHIFT);
  564.         xr = (x0 << FIXP16_SHIFT);
  565.  
  566.         ul = (tu0 << FIXP16_SHIFT);
  567.         vl = (tv0 << FIXP16_SHIFT);
  568.  
  569.         ur = (tu0 << FIXP16_SHIFT);
  570.         vr = (tv0 << FIXP16_SHIFT);
  571.  
  572.         // set starting y
  573.         ystart = y0;
  574.  
  575.         // test if we need swap to keep rendering left to right
  576.         if (dxdyr < dxdyl)
  577.             {
  578.             SWAP(dxdyl,dxdyr,temp);
  579.             SWAP(dudyl,dudyr,temp);
  580.             SWAP(dvdyl,dvdyr,temp);
  581.             SWAP(xl,xr,temp);
  582.             SWAP(ul,ur,temp);
  583.             SWAP(vl,vr,temp);
  584.             SWAP(x1,x2,temp);
  585.             SWAP(y1,y2,temp);
  586.             SWAP(tu1,tu2,temp);
  587.             SWAP(tv1,tv2,temp);
  588.         
  589.             // set interpolation restart
  590.             irestart = INTERP_RHS;
  591.  
  592.             } // end if
  593.  
  594.         } // end else
  595.  
  596.  
  597.     // test for horizontal clipping
  598.     if ((x0 < poly_clip_min_x) || (x0 > poly_clip_max_x) ||
  599.         (x1 < poly_clip_min_x) || (x1 > poly_clip_max_x) ||
  600.         (x2 < poly_clip_min_x) || (x2 > poly_clip_max_x))
  601.     {
  602.     // clip version
  603.     // x clipping    
  604.  
  605.     // point screen ptr to starting line
  606.     screen_ptr = dest_buffer + (ystart * mem_pitch);
  607.  
  608.     for (yi = ystart; yi<=yend; yi++)
  609.         {
  610.         // compute span endpoints
  611.         xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  612.         xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  613.         
  614.         // compute starting points for u,v interpolants
  615.         ui = ul + FIXP16_ROUND_UP;
  616.         vi = vl + FIXP16_ROUND_UP;
  617.     
  618.         // compute u,v interpolants
  619.         if ((dx = (xend - xstart))>0)
  620.             {
  621.             du = (ur - ul)/dx;
  622.             dv = (vr - vl)/dx;
  623.             } // end if
  624.         else
  625.             {
  626.             du = (ur - ul);
  627.             dv = (vr - vl);
  628.             } // end else
  629.  
  630.         ///////////////////////////////////////////////////////////////////////
  631.  
  632.         // test for x clipping, LHS
  633.         if (xstart < poly_clip_min_x)
  634.             {
  635.             // compute x overlap
  636.             dx = poly_clip_min_x - xstart;
  637.  
  638.             // slide interpolants over
  639.             ui+=dx*du;
  640.             vi+=dx*dv;
  641.             
  642.             // set x to left clip edge
  643.             xstart = poly_clip_min_x;
  644.  
  645.             } // end if
  646.         
  647.         // test for x clipping RHS
  648.         if (xend > poly_clip_max_x)
  649.             xend = poly_clip_max_x;
  650.  
  651.         ///////////////////////////////////////////////////////////////////////
  652.  
  653.         // draw span
  654.         for (xi=xstart; xi<=xend; xi++)
  655.             {
  656.             // write textel
  657.             screen_ptr[xi] = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << 6)];
  658.             
  659.             // interpolate u,v
  660.             ui+=du;
  661.             vi+=dv;
  662.             } // end for xi
  663.  
  664.         // interpolate u,v,x along right and left edge
  665.         xl+=dxdyl;
  666.         ul+=dudyl;
  667.         vl+=dvdyl;
  668.     
  669.         xr+=dxdyr;
  670.         ur+=dudyr;
  671.         vr+=dvdyr;
  672.  
  673.         // advance screen ptr
  674.         screen_ptr+=mem_pitch;
  675.  
  676.         // test for yi hitting second region, if so change interpolant
  677.         if (yi==yrestart)
  678.             {
  679.  
  680.         // test interpolation side change flag
  681.  
  682.             if (irestart == INTERP_LHS)
  683.             {
  684.             // LHS
  685.             dyl = (y2 - y1);    
  686.  
  687.             dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  688.             dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  689.             dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;           
  690.  
  691.             // set starting values
  692.             xl = (x1  << FIXP16_SHIFT);
  693.             ul = (tu1 << FIXP16_SHIFT);
  694.             vl = (tv1 << FIXP16_SHIFT);
  695.  
  696.             // interpolate down on LHS to even up
  697.             xl+=dxdyl;
  698.             ul+=dudyl;
  699.             vl+=dvdyl;
  700.             } // end if
  701.             else
  702.             {
  703.             // RHS
  704.             dyr = (y1 - y2);    
  705.  
  706.             dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  707.             dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  708.             dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;           
  709.  
  710.             // set starting values
  711.             xr = (x2  << FIXP16_SHIFT);
  712.             ur = (tu2 << FIXP16_SHIFT);
  713.             vr = (tv2 << FIXP16_SHIFT);
  714.  
  715.             // interpolate down on RHS to even up
  716.             xr+=dxdyr;
  717.             ur+=dudyr;
  718.             vr+=dvdyr;
  719.         
  720.             } // end else
  721.  
  722.  
  723.             } // end if
  724.  
  725.         } // end for y
  726.  
  727.     } // end if
  728.     else
  729.     {
  730.     // no x clipping
  731.     // point screen ptr to starting line
  732.     screen_ptr = dest_buffer + (ystart * mem_pitch);
  733.  
  734.     for (yi = ystart; yi<=yend; yi++)
  735.         {
  736.         // compute span endpoints
  737.         xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  738.         xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  739.         
  740.         // compute starting points for u,v interpolants
  741.         ui = ul + FIXP16_ROUND_UP;
  742.         vi = vl + FIXP16_ROUND_UP;
  743.     
  744.         // compute u,v interpolants
  745.         if ((dx = (xend - xstart))>0)
  746.             {
  747.             du = (ur - ul)/dx;
  748.             dv = (vr - vl)/dx;
  749.             } // end if
  750.         else
  751.             {
  752.             du = (ur - ul);
  753.             dv = (vr - vl);
  754.             } // end else
  755.  
  756.         // draw span
  757.         for (xi=xstart; xi<=xend; xi++)
  758.             {
  759.             // write textel
  760.             screen_ptr[xi] = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << 6)];
  761.             
  762.             // interpolate u,v
  763.             ui+=du;
  764.             vi+=dv;
  765.             } // end for xi
  766.  
  767.         // interpolate u,v,x along right and left edge
  768.         xl+=dxdyl;
  769.         ul+=dudyl;
  770.         vl+=dvdyl;
  771.     
  772.         xr+=dxdyr;
  773.         ur+=dudyr;
  774.         vr+=dvdyr;
  775.  
  776.         // advance screen ptr
  777.         screen_ptr+=mem_pitch;
  778.  
  779.         // test for yi hitting second region, if so change interpolant
  780.         if (yi==yrestart)
  781.             {
  782.             // test interpolation side change flag
  783.  
  784.             if (irestart == INTERP_LHS)
  785.             {
  786.             // LHS
  787.             dyl = (y2 - y1);    
  788.  
  789.             dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  790.             dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  791.             dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;           
  792.  
  793.             // set starting values
  794.             xl = (x1  << FIXP16_SHIFT);
  795.             ul = (tu1 << FIXP16_SHIFT);
  796.             vl = (tv1 << FIXP16_SHIFT);
  797.  
  798.             // interpolate down on LHS to even up
  799.             xl+=dxdyl;
  800.             ul+=dudyl;
  801.             vl+=dvdyl;
  802.             } // end if
  803.             else
  804.             {
  805.             // RHS
  806.             dyr = (y1 - y2);    
  807.  
  808.             dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  809.             dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  810.             dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;           
  811.  
  812.             // set starting values
  813.             xr = (x2  << FIXP16_SHIFT);
  814.             ur = (tu2 << FIXP16_SHIFT);
  815.             vr = (tv2 << FIXP16_SHIFT);
  816.  
  817.             // interpolate down on RHS to even up
  818.             xr+=dxdyr;
  819.             ur+=dudyr;
  820.             vr+=dvdyr;
  821.         
  822.             } // end else
  823.  
  824.             } // end if
  825.  
  826.         } // end for y
  827.  
  828.     } // end else    
  829.  
  830.     } // end if
  831.  
  832. } // end Draw_Textured_Triangle
  833.  
  834. /******************************* EXAMPLE ***********************************
  835.  
  836. This is the setup:
  837.  
  838. To create a single triangle to be rendered consisting of the 3
  839. points (in CC order I think):
  840.  
  841. (x0,y0,u0,v0)
  842. (x1,y1,u1,v1)
  843. (x2,y2,u2,v2)
  844.  
  845. 64x64 texture at address texture_buffer in row major form
  846.  
  847. FACE3D face; // the triangle object
  848.  
  849. // set up the vertices
  850. face.tlist[0].x = x0;
  851. face.tlist[0].y = y0;
  852. face.tlist[0].u = u0;
  853. face.tlist[0].v = v0;
  854.  
  855. face.tlist[1].x = x1;
  856. face.tlist[1].y = y1;
  857. face.tlist[1].u = u1;
  858. face.tlist[1].v = v1;
  859.  
  860. face.tlist[2].x = x2;
  861. face.tlist[2].y = y2;
  862. face.tlist[2].u = u2;
  863. face.tlist[2].v = v2;
  864.  
  865. // assign the texture to your 64x64 texture map buffer
  866. face.texture = texture_buffer;
  867.  
  868. // set the clipping coords of the desired 2D viewport
  869. poly_clip_min_x = 0; 
  870. poly_clip_max_x = 0;
  871. poly_clip_min_y = SCREEN_WIDTH-1;
  872. poly_clip_max_y = SCREEN_HEIGHT-1
  873.  
  874. // then draw the triangle to the rendering buffer
  875. Draw_Textured_Triangle((void *)&face, double_buffer, memory_pitch);
  876.  
  877. ***************************************************************************/
  878.