t3dlib7.cpp
上传用户:husern
上传日期:2018-01-20
资源大小:42486k
文件大小:512k
源码类别:

游戏

开发平台:

Visual C++

  1. // set starting y
  2. ystart = y0;
  3. // test if we need swap to keep rendering left to right
  4. if (dxdyr < dxdyl)
  5. {
  6. SWAP(dxdyl,dxdyr,temp);
  7. SWAP(dudyl,dudyr,temp);
  8. SWAP(dvdyl,dvdyr,temp);
  9. SWAP(xl,xr,temp);
  10. SWAP(ul,ur,temp);
  11. SWAP(vl,vr,temp);
  12. SWAP(x1,x2,temp);
  13. SWAP(y1,y2,temp);
  14. SWAP(tu1,tu2,temp);
  15. SWAP(tv1,tv2,temp);
  16. // set interpolation restart
  17. irestart = INTERP_RHS;
  18. } // end if
  19. } // end else
  20.     // test for horizontal clipping
  21. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  22. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  23. (x2 < min_clip_x) || (x2 > max_clip_x))
  24. {
  25.     // clip version
  26. // x clipping
  27. // point screen ptr to starting line
  28. screen_ptr = dest_buffer + (ystart * mem_pitch);
  29. for (yi = ystart; yi<=yend; yi++)
  30. {
  31. // compute span endpoints
  32. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  33. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  34. // compute starting points for u,v interpolants
  35. ui = ul + FIXP16_ROUND_UP;
  36. vi = vl + FIXP16_ROUND_UP;
  37. // compute u,v interpolants
  38. if ((dx = (xend - xstart))>0)
  39. {
  40. du = (ur - ul)/dx;
  41. dv = (vr - vl)/dx;
  42. } // end if
  43. else
  44. {
  45. du = (ur - ul);
  46. dv = (vr - vl);
  47. } // end else
  48. ///////////////////////////////////////////////////////////////////////
  49. // test for x clipping, LHS
  50. if (xstart < min_clip_x)
  51. {
  52. // compute x overlap
  53. dx = min_clip_x - xstart;
  54. // slide interpolants over
  55. ui+=dx*du;
  56. vi+=dx*dv;
  57. // set x to left clip edge
  58. xstart = min_clip_x;
  59. } // end if
  60. // test for x clipping RHS
  61. if (xend > max_clip_x)
  62. xend = max_clip_x;
  63. ///////////////////////////////////////////////////////////////////////
  64. // draw span
  65. for (xi=xstart; xi<=xend; xi++)
  66. {
  67. // write textel
  68.             //screen_ptr[xi] = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
  69.     // get textel first
  70.   textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
  71.             // extract rgb components
  72.             r_textel  = ((textel >> 11)       ); 
  73.             g_textel  = ((textel >> 5)  & 0x3f); 
  74.             b_textel =   (textel        & 0x1f);
  75.             // modulate textel with lit background color
  76.             r_textel*=r_base; 
  77.             g_textel*=g_base;
  78.             b_textel*=b_base;
  79.             // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  80.             // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  81.             // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  82.             // and they all cancel out for the most part, but we will need logical anding, we will do
  83.             // it later when we optimize more...
  84.             screen_ptr[xi] = ((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11));
  85. // interpolate u,v
  86. ui+=du;
  87. vi+=dv;
  88. } // end for xi
  89. // interpolate u,v,x along right and left edge
  90. xl+=dxdyl;
  91. ul+=dudyl;
  92. vl+=dvdyl;
  93. xr+=dxdyr;
  94. ur+=dudyr;
  95. vr+=dvdyr;
  96. // advance screen ptr
  97. screen_ptr+=mem_pitch;
  98. // test for yi hitting second region, if so change interpolant
  99. if (yi==yrestart)
  100. {
  101.       // test interpolation side change flag
  102. if (irestart == INTERP_LHS)
  103. {
  104. // LHS
  105. dyl = (y2 - y1);
  106. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  107. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  108. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  109. // set starting values
  110. xl = (x1  << FIXP16_SHIFT);
  111. ul = (tu1 << FIXP16_SHIFT);
  112. vl = (tv1 << FIXP16_SHIFT);
  113. // interpolate down on LHS to even up
  114. xl+=dxdyl;
  115. ul+=dudyl;
  116. vl+=dvdyl;
  117. } // end if
  118. else
  119. {
  120. // RHS
  121. dyr = (y1 - y2);
  122. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  123. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  124. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  125. // set starting values
  126. xr = (x2  << FIXP16_SHIFT);
  127. ur = (tu2 << FIXP16_SHIFT);
  128. vr = (tv2 << FIXP16_SHIFT);
  129. // interpolate down on RHS to even up
  130. xr+=dxdyr;
  131. ur+=dudyr;
  132. vr+=dvdyr;
  133. } // end else
  134. } // end if
  135. } // end for y
  136. } // end if
  137. else
  138. {
  139. // no x clipping
  140. // point screen ptr to starting line
  141. screen_ptr = dest_buffer + (ystart * mem_pitch);
  142. for (yi = ystart; yi<=yend; yi++)
  143. {
  144. // compute span endpoints
  145. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  146. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  147. // compute starting points for u,v interpolants
  148. ui = ul + FIXP16_ROUND_UP;
  149. vi = vl + FIXP16_ROUND_UP;
  150. // compute u,v interpolants
  151. if ((dx = (xend - xstart))>0)
  152. {
  153. du = (ur - ul)/dx;
  154. dv = (vr - vl)/dx;
  155. } // end if
  156. else
  157. {
  158. du = (ur - ul);
  159. dv = (vr - vl);
  160. } // end else
  161. // draw span
  162. for (xi=xstart; xi<=xend; xi++)
  163. {
  164. // write textel
  165.     // get textel first
  166.   textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
  167.             // extract rgb components
  168.             r_textel  = ((textel >> 11)       ); 
  169.             g_textel  = ((textel >> 5)  & 0x3f); 
  170.             b_textel =   (textel        & 0x1f);
  171.             // modulate textel with lit background color
  172.             r_textel*=r_base; 
  173.             g_textel*=g_base;
  174.             b_textel*=b_base;
  175.             // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  176.             // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  177.             // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  178.             // and they all cancel out for the most part, but we will need logical anding, we will do
  179.             // it later when we optimize more...
  180.             screen_ptr[xi] = ((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11));
  181. // interpolate u,v
  182. ui+=du;
  183. vi+=dv;
  184. } // end for xi
  185. // interpolate u,v,x along right and left edge
  186. xl+=dxdyl;
  187. ul+=dudyl;
  188. vl+=dvdyl;
  189. xr+=dxdyr;
  190. ur+=dudyr;
  191. vr+=dvdyr;
  192. // advance screen ptr
  193. screen_ptr+=mem_pitch;
  194. // test for yi hitting second region, if so change interpolant
  195. if (yi==yrestart)
  196. {
  197. // test interpolation side change flag
  198. if (irestart == INTERP_LHS)
  199. {
  200. // LHS
  201. dyl = (y2 - y1);
  202. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  203. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  204. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  205. // set starting values
  206. xl = (x1  << FIXP16_SHIFT);
  207. ul = (tu1 << FIXP16_SHIFT);
  208. vl = (tv1 << FIXP16_SHIFT);
  209. // interpolate down on LHS to even up
  210. xl+=dxdyl;
  211. ul+=dudyl;
  212. vl+=dvdyl;
  213. } // end if
  214. else
  215. {
  216. // RHS
  217. dyr = (y1 - y2);
  218. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  219. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  220. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  221. // set starting values
  222. xr = (x2  << FIXP16_SHIFT);
  223. ur = (tu2 << FIXP16_SHIFT);
  224. vr = (tv2 << FIXP16_SHIFT);
  225. // interpolate down on RHS to even up
  226. xr+=dxdyr;
  227. ur+=dudyr;
  228. vr+=dvdyr;
  229. } // end else
  230. } // end if
  231. } // end for y
  232.    } // end else
  233. } // end if
  234. } // end Draw_Textured_TriangleFS16
  235. /////////////////////////////////////////////////////////////////////////////
  236. void Draw_Top_Tri2_16(float x1, float y1, 
  237.                       float x2, float y2, 
  238.                       float x3, float y3,
  239.                       int color, 
  240.                       UCHAR *_dest_buffer, int mempitch)
  241. {
  242. // this function draws a triangle that has a flat top
  243. float dx_right,    // the dx/dy ratio of the right edge of line
  244.       dx_left,     // the dx/dy ratio of the left edge of line
  245.       xs,xe,       // the starting and ending points of the edges
  246.       height,      // the height of the triangle
  247.       temp_x,        // used during sorting as temps
  248.       temp_y,
  249.       right,         // used by clipping
  250.       left;
  251. int iy1,iy3,loop_y; // integers for y looping
  252. // cast dest buffer to ushort
  253. USHORT *dest_buffer = (USHORT *)_dest_buffer;
  254. // destination address of next scanline
  255. USHORT *dest_addr = NULL;
  256. // recompute mempitch in 16-bit words
  257. mempitch = (mempitch >> 1);
  258. // test order of x1 and x2
  259. if (x2 < x1)
  260.    {
  261.    SWAP(x1,x2,temp_x);
  262.    } // end if swap
  263. // compute delta's
  264. height = y3 - y1;
  265. dx_left  = (x3-x1) / height;
  266. dx_right = (x3-x2) / height;
  267. // set starting points
  268. xs = x1;
  269. xe = x2; 
  270. #if (RASTERIZER_MODE==RASTERIZER_ACCURATE)
  271. // perform y clipping
  272. if (y1 < min_clip_y)
  273.    {
  274.    // compute new xs and ys
  275.    xs = xs+dx_left*(-y1+min_clip_y);
  276.    xe = xe+dx_right*(-y1+min_clip_y);
  277.    // reset y1
  278.    y1 = min_clip_y;
  279.    // make sure top left fill convention is observed
  280.    iy1 = y1;
  281.    } // end if top is off screen
  282. else
  283.    {
  284.    // make sure top left fill convention is observed
  285.    iy1 = ceil(y1);
  286.    // bump xs and xe appropriately
  287.    xs = xs+dx_left*(iy1-y1);
  288.    xe = xe+dx_right*(iy1-y1);
  289.    } // end else
  290. if (y3 > max_clip_y)
  291.    {
  292.    // clip y
  293.    y3 = max_clip_y;
  294.    // make sure top left fill convention is observed
  295.    iy3 = y3-1;
  296.    } // end if
  297. else
  298.    {
  299.    // make sure top left fill convention is observed
  300.    iy3 = ceil(y3)-1;
  301.    } // end else
  302. #endif
  303. #if ( (RASTERIZER_MODE==RASTERIZER_FAST) || (RASTERIZER_MODE==RASTERIZER_FASTEST) )
  304. // perform y clipping
  305. if (y1 < min_clip_y)
  306.    {
  307.    // compute new xs and ys
  308.    xs = xs+dx_left*(-y1+min_clip_y);
  309.    xe = xe+dx_right*(-y1+min_clip_y);
  310.    // reset y1
  311.    y1 = min_clip_y;
  312.    } // end if top is off screen
  313. if (y3 > max_clip_y)
  314.    y3 = max_clip_y;
  315. // make sure top left fill convention is observed
  316. iy1 = ceil(y1);
  317. iy3 = ceil(y3)-1;
  318. #endif 
  319. //Write_Error("nTri-Top: xs=%f, xe=%f, y1=%f, y3=%f, iy1=%d, iy3=%d", xs,xe,y1,y3,iy1,iy3);
  320. // compute starting address in video memory
  321. dest_addr = dest_buffer + iy1*mempitch;
  322. // test if x clipping is needed
  323. if (x1 >= min_clip_x && x1 <= max_clip_x &&
  324.     x2 >= min_clip_x && x2 <= max_clip_x &&
  325.     x3 >= min_clip_x && x3 <= max_clip_x)
  326.     {
  327.     // draw the triangle
  328.     for (loop_y=iy1; loop_y <= iy3; loop_y++, dest_addr+=mempitch)
  329.         {
  330.         //Write_Error("nxs=%f, xe=%f", xs,xe);
  331.         // draw the line
  332.         Mem_Set_WORD(dest_addr+(unsigned int)(xs),color,(unsigned int)((int)xe-(int)xs+1));
  333.         // adjust starting point and ending point
  334.         xs+=dx_left;
  335.         xe+=dx_right;
  336.         } // end for
  337.     } // end if no x clipping needed
  338. else
  339.    {
  340.    // clip x axis with slower version
  341.    // draw the triangle
  342.    for (loop_y=iy1; loop_y <= iy3; loop_y++, dest_addr+=mempitch)
  343.        {
  344.        // do x clip
  345.        left  = xs;
  346.        right = xe;
  347.        // adjust starting point and ending point
  348.        xs+=dx_left;
  349.        xe+=dx_right;
  350.        // clip line
  351.        if (left < min_clip_x)
  352.           {
  353.           left = min_clip_x;
  354.           if (right < min_clip_x)
  355.              continue;
  356.           }
  357.        if (right > max_clip_x)
  358.           {
  359.           right = max_clip_x;
  360.           if (left > max_clip_x)
  361.              continue;
  362.           }
  363.         //Write_Error("nleft=%f, right=%f", left,right);
  364.         // draw the line
  365.         Mem_Set_WORD(dest_addr+(unsigned int)(left),color,(unsigned int)((int)right-(int)left+1));
  366.        } // end for
  367.    } // end else x clipping needed
  368. } // end Draw_Top_Tri2_16
  369. /////////////////////////////////////////////////////////////////////////////
  370. void Draw_Bottom_Tri2_16(float x1, float y1, 
  371.                          float x2, float y2, 
  372.                          float x3, float y3,
  373.                          int color,
  374.                          UCHAR *_dest_buffer, int mempitch)
  375. {
  376. // this function draws a triangle that has a flat bottom
  377. float dx_right,    // the dx/dy ratio of the right edge of line
  378.       dx_left,     // the dx/dy ratio of the left edge of line
  379.       xs,xe,       // the starting and ending points of the edges
  380.       height,      // the height of the triangle
  381.       temp_x,      // used during sorting as temps
  382.       temp_y,
  383.       right,       // used by clipping
  384.       left;
  385. int iy1,iy3,loop_y;
  386. // cast dest buffer to ushort
  387. USHORT *dest_buffer = (USHORT *)_dest_buffer;
  388. // destination address of next scanline
  389. USHORT  *dest_addr = NULL;
  390. // recompute mempitch in 16-bit words
  391. mempitch = (mempitch >> 1);
  392. // test order of x1 and x2
  393. if (x3 < x2)
  394.    {
  395.    SWAP(x2,x3,temp_x);
  396.    } // end if swap
  397. // compute delta's
  398. height = y3 - y1;
  399. dx_left  = (x2-x1)/height;
  400. dx_right = (x3-x1)/height;
  401. // set starting points
  402. xs = x1;
  403. xe = x1; 
  404. #if (RASTERIZER_MODE==RASTERIZER_ACCURATE)
  405. // perform y clipping
  406. if (y1 < min_clip_y)
  407.    {
  408.    // compute new xs and ys
  409.    xs = xs+dx_left*(-y1+min_clip_y);
  410.    xe = xe+dx_right*(-y1+min_clip_y);
  411.    // reset y1
  412.    y1 = min_clip_y;
  413.    // make sure top left fill convention is observed
  414.    iy1 = y1;
  415.    } // end if top is off screen
  416. else
  417.    {
  418.    // make sure top left fill convention is observed
  419.    iy1 = ceil(y1);
  420.    // bump xs and xe appropriately
  421.    xs = xs+dx_left*(iy1-y1);
  422.    xe = xe+dx_right*(iy1-y1);
  423.    } // end else
  424. if (y3 > max_clip_y)
  425.    {
  426.    // clip y
  427.    y3 = max_clip_y;
  428.    // make sure top left fill convention is observed
  429.    iy3 = y3-1;
  430.    } // end if
  431. else
  432.    {
  433.    // make sure top left fill convention is observed
  434.    iy3 = ceil(y3)-1;
  435.    } // end else
  436. #endif
  437. #if ( (RASTERIZER_MODE==RASTERIZER_FAST) || (RASTERIZER_MODE==RASTERIZER_FASTEST) )
  438. // perform y clipping
  439. if (y1 < min_clip_y)
  440.    {
  441.    // compute new xs and ys
  442.    xs = xs+dx_left*(-y1+min_clip_y);
  443.    xe = xe+dx_right*(-y1+min_clip_y);
  444.    // reset y1
  445.    y1 = min_clip_y;
  446.    } // end if top is off screen
  447. if (y3 > max_clip_y)
  448.    y3 = max_clip_y;
  449. // make sure top left fill convention is observed
  450. iy1 = ceil(y1);
  451. iy3 = ceil(y3)-1;
  452. #endif 
  453. //Write_Error("nTri-Bottom: xs=%f, xe=%f, y1=%f, y3=%f, iy1=%d, iy3=%d", xs,xe,y1,y3,iy1,iy3);
  454. // compute starting address in video memory
  455. dest_addr = dest_buffer + iy1*mempitch;
  456. // test if x clipping is needed
  457. if (x1 >= min_clip_x && x1 <= max_clip_x &&
  458.     x2 >= min_clip_x && x2 <= max_clip_x &&
  459.     x3 >= min_clip_x && x3 <= max_clip_x)
  460.     {
  461.     // draw the triangle
  462.     for (loop_y = iy1; loop_y <= iy3; loop_y++, dest_addr+=mempitch)
  463.         {
  464.         //Write_Error("nxs=%f, xe=%f", xs,xe);
  465.         // draw the line
  466.         Mem_Set_WORD(dest_addr+(unsigned int)(xs),color,(unsigned int)((int)xe-(int)xs+1));
  467.         // adjust starting point and ending point
  468.         xs+=dx_left;
  469.         xe+=dx_right;
  470.         } // end for
  471.     } // end if no x clipping needed
  472. else
  473.    {
  474.    // clip x axis with slower version
  475.    // draw the triangle
  476.    for (loop_y = iy1; loop_y <= iy3; loop_y++,dest_addr+=mempitch)
  477.        {
  478.        // do x clip
  479.        left  = xs;
  480.        right = xe;
  481.        // adjust starting point and ending point
  482.        xs+=dx_left;
  483.        xe+=dx_right;
  484.        // clip line
  485.        if (left < min_clip_x)
  486.           {
  487.           left = min_clip_x;
  488.           if (right < min_clip_x)
  489.              continue;
  490.           }
  491.        if (right > max_clip_x)
  492.           {
  493.           right = max_clip_x;
  494.           if (left > max_clip_x)
  495.              continue;
  496.           }
  497.        //Write_Error("nleft=%f, right=%f", left,right);
  498.        // draw the line
  499.        Mem_Set_WORD(dest_addr+(unsigned int)(left),color,(unsigned int)((int)right-(int)left+1));
  500.        } // end for
  501.    } // end else x clipping needed
  502. } // end Draw_Bottom_Tri2_16
  503. ///////////////////////////////////////////////////////////////////////////////
  504. void Draw_Triangle_2D2_16(float x1,float y1,
  505.                           float x2,float y2,
  506.                           float x3,float y3,
  507.                           int color,
  508.                           UCHAR *dest_buffer, int mempitch)
  509. {
  510. // this function draws a triangle on the destination buffer
  511. // it decomposes all triangles into a pair of flat top, flat bottom
  512. float temp_x, // used for sorting
  513.       temp_y,
  514.       new_x;
  515. #ifdef DEBUG_ON
  516. // track rendering stats
  517.     debug_polys_rendered_per_frame++;
  518. #endif
  519. // test for h lines and v lines
  520. if ((FCMP(x1,x2) && FCMP(x2,x3))  ||  (FCMP(y1,y2) && FCMP(y2,y3)))
  521.    return;
  522. // sort p1,p2,p3 in ascending y order
  523. if (y2 < y1)
  524.    {
  525.    SWAP(x1,x2,temp_x);
  526.    SWAP(y1,y2,temp_y);
  527.    } // end if
  528. // now we know that p1 and p2 are in order
  529. if (y3 < y1)
  530.    {
  531.    SWAP(x1,x3,temp_x);
  532.    SWAP(y1,y3,temp_y);
  533.    } // end if
  534. // finally test y3 against y2
  535. if (y3 < y2)
  536.    {
  537.    SWAP(x2,x3,temp_x);
  538.    SWAP(y2,y3,temp_y);
  539.    } // end if
  540. // do trivial rejection tests for clipping
  541. if ( y3 < min_clip_y || y1 > max_clip_y ||
  542.     (x1 < min_clip_x && x2 < min_clip_x && x3 < min_clip_x) ||
  543.     (x1 > max_clip_x && x2 > max_clip_x && x3 > max_clip_x) )
  544.    return;
  545. // test if top of triangle is flat
  546. if (FCMP(y1,y2))
  547.    {
  548.    Draw_Top_Tri2_16(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  549.    } // end if
  550. else
  551. if (FCMP(y2,y3))
  552.    {
  553.    Draw_Bottom_Tri2_16(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  554.    } // end if bottom is flat
  555. else
  556.    {
  557.    // general triangle that's needs to be broken up along long edge
  558.    new_x = x1 + (y2-y1)*(x3-x1)/(y3-y1);
  559.    // draw each sub-triangle
  560.    Draw_Bottom_Tri2_16(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
  561.    Draw_Top_Tri2_16(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
  562.    } // end else
  563. } // end Draw_Triangle_2D2_16
  564. ///////////////////////////////////////////////////////////////////////////////
  565. void Draw_Top_Tri2(float x1,float y1, 
  566.                    float x2,float y2, 
  567.                    float x3,float y3,
  568.                    int color, 
  569.                    UCHAR *dest_buffer, int mempitch)
  570. {
  571. // this function draws a triangle that has a flat top
  572. float dx_right,    // the dx/dy ratio of the right edge of line
  573.       dx_left,     // the dx/dy ratio of the left edge of line
  574.       xs,xe,       // the starting and ending points of the edges
  575.       height,      // the height of the triangle
  576.       temp_x,      // used during sorting as temps
  577.       temp_y,
  578.       right,       // used by clipping
  579.       left;
  580. int iy1,iy3,loop_y; // integers for y loops
  581. // destination address of next scanline
  582. UCHAR  *dest_addr = NULL;
  583. // test order of x1 and x2
  584. if (x2 < x1)
  585.    {
  586.    SWAP(x1,x2,temp_x);
  587.    } // end if swap
  588. // compute delta's
  589. height = y3-y1;
  590. dx_left  = (x3-x1)/height;
  591. dx_right = (x3-x2)/height;
  592. // set starting points
  593. xs = x1;
  594. xe = x2;
  595. #if (RASTERIZER_MODE==RASTERIZER_ACCURATE)
  596. // perform y clipping
  597. if (y1 < min_clip_y)
  598.    {
  599.    // compute new xs and ys
  600.    xs = xs+dx_left*(-y1+min_clip_y);
  601.    xe = xe+dx_right*(-y1+min_clip_y);
  602.    // reset y1
  603.    y1 = min_clip_y;
  604.    // make sure top left fill convention is observed
  605.    iy1 = y1;
  606.    } // end if top is off screen
  607. else
  608.    {
  609.    // make sure top left fill convention is observed
  610.    iy1 = ceil(y1);
  611.    // bump xs and xe appropriately
  612.    xs = xs+dx_left*(iy1-y1);
  613.    xe = xe+dx_right*(iy1-y1);
  614.    } // end else
  615. if (y3 > max_clip_y)
  616.    {
  617.    // clip y
  618.    y3 = max_clip_y;
  619.    // make sure top left fill convention is observed
  620.    iy3 = y3-1;
  621.    } // end if
  622. else
  623.    {
  624.    // make sure top left fill convention is observed
  625.    iy3 = ceil(y3)-1;
  626.    } // end else
  627. #endif
  628. #if ( (RASTERIZER_MODE==RASTERIZER_FAST) || (RASTERIZER_MODE==RASTERIZER_FASTEST) )
  629. // perform y clipping
  630. if (y1 < min_clip_y)
  631.    {
  632.    // compute new xs and ys
  633.    xs = xs+dx_left*(-y1+min_clip_y);
  634.    xe = xe+dx_right*(-y1+min_clip_y);
  635.    // reset y1
  636.    y1 = min_clip_y;
  637.    } // end if top is off screen
  638. if (y3 > max_clip_y)
  639.    y3 = max_clip_y;
  640. // make sure top left fill convention is observed
  641. iy1 = ceil(y1);
  642. iy3 = ceil(y3)-1;
  643. #endif 
  644. // compute starting address in video memory
  645. dest_addr = dest_buffer+iy1*mempitch;
  646. // test if x clipping is needed
  647. if (x1>=min_clip_x && x1<=max_clip_x &&
  648.     x2>=min_clip_x && x2<=max_clip_x &&
  649.     x3>=min_clip_x && x3<=max_clip_x)
  650.     {
  651.     // draw the triangle
  652.     for (loop_y=iy1; loop_y<=iy3; loop_y++,dest_addr+=mempitch)
  653.         {
  654.         // draw the line
  655.         memset((UCHAR *)dest_addr+(unsigned int)xs, color,(unsigned int)((int)xe-(int)xs+1));
  656.         // adjust starting point and ending point
  657.         xs+=dx_left;
  658.         xe+=dx_right;
  659.         } // end for
  660.     } // end if no x clipping needed
  661. else
  662.    {
  663.    // clip x axis with slower version
  664.    // draw the triangle
  665.    for (temp_y=iy1; temp_y<=iy3; temp_y++,dest_addr+=mempitch)
  666.        {
  667.        // do x clip
  668.        left  = xs;
  669.        right = xe;
  670.        // adjust starting point and ending point
  671.        xs+=dx_left;
  672.        xe+=dx_right;
  673.        // clip line
  674.        if (left < min_clip_x)
  675.           {
  676.           left = min_clip_x;
  677.           if (right < min_clip_x)
  678.              continue;
  679.           }
  680.        if (right > max_clip_x)
  681.           {
  682.           right = max_clip_x;
  683.           if (left > max_clip_x)
  684.              continue;
  685.           }
  686.        // draw the line
  687.        memset((UCHAR  *)dest_addr+(unsigned int)left, color,(unsigned int)((int)right-(int)left+1));
  688.        } // end for
  689.    } // end else x clipping needed
  690. } // end Draw_Top_Tri2
  691. /////////////////////////////////////////////////////////////////////////////
  692. void Draw_Bottom_Tri2(float x1,float y1, 
  693.                       float x2,float y2, 
  694.                       float x3,float y3,
  695.                       int color,
  696.                       UCHAR *dest_buffer, int mempitch)
  697. {
  698. // this function draws a triangle that has a flat bottom
  699. float dx_right,    // the dx/dy ratio of the right edge of line
  700.       dx_left,     // the dx/dy ratio of the left edge of line
  701.       xs,xe,       // the starting and ending points of the edges
  702.       height,      // the height of the triangle
  703.       temp_x,      // used during sorting as temps
  704.       temp_y,
  705.       right,       // used by clipping
  706.       left;
  707. int iy1,iy3,loop_y; // integers for y loops
  708. // destination address of next scanline
  709. UCHAR  *dest_addr;
  710. // test order of x1 and x2
  711. if (x3 < x2)
  712.    {
  713.    SWAP(x2,x3,temp_x);
  714.    } // end if swap
  715. // compute delta's
  716. height = y3-y1;
  717. dx_left  = (x2-x1)/height;
  718. dx_right = (x3-x1)/height;
  719. // set starting points
  720. xs = x1;
  721. xe = x1; 
  722. #if (RASTERIZER_MODE==RASTERIZER_ACCURATE)
  723. // perform y clipping
  724. if (y1 < min_clip_y)
  725.    {
  726.    // compute new xs and ys
  727.    xs = xs+dx_left*(-y1+min_clip_y);
  728.    xe = xe+dx_right*(-y1+min_clip_y);
  729.    // reset y1
  730.    y1 = min_clip_y;
  731.    // make sure top left fill convention is observed
  732.    iy1 = y1;
  733.    } // end if top is off screen
  734. else
  735.    {
  736.    // make sure top left fill convention is observed
  737.    iy1 = ceil(y1);
  738.    // bump xs and xe appropriately
  739.    xs = xs+dx_left*(iy1-y1);
  740.    xe = xe+dx_right*(iy1-y1);
  741.    } // end else
  742. if (y3 > max_clip_y)
  743.    {
  744.    // clip y
  745.    y3 = max_clip_y;
  746.    // make sure top left fill convention is observed
  747.    iy3 = y3-1;
  748.    } // end if
  749. else
  750.    {
  751.    // make sure top left fill convention is observed
  752.    iy3 = ceil(y3)-1;
  753.    } // end else
  754. #endif
  755. #if ( (RASTERIZER_MODE==RASTERIZER_FAST) || (RASTERIZER_MODE==RASTERIZER_FASTEST) )
  756. // perform y clipping
  757. if (y1 < min_clip_y)
  758.    {
  759.    // compute new xs and ys
  760.    xs = xs+dx_left*(-y1+min_clip_y);
  761.    xe = xe+dx_right*(-y1+min_clip_y);
  762.    // reset y1
  763.    y1 = min_clip_y;
  764.    } // end if top is off screen
  765. if (y3 > max_clip_y)
  766.    y3 = max_clip_y;
  767. // make sure top left fill convention is observed
  768. iy1 = ceil(y1);
  769. iy3 = ceil(y3)-1;
  770. #endif 
  771. // compute starting address in video memory
  772. dest_addr = dest_buffer+iy1*mempitch;
  773. // test if x clipping is needed
  774. if (x1 >= min_clip_x && x1 <= max_clip_x &&
  775.     x2 >= min_clip_x && x2 <= max_clip_x &&
  776.     x3 >= min_clip_x && x3 <= max_clip_x)
  777.     {
  778.     // draw the triangle
  779.     for (loop_y = iy1; loop_y <= iy3; loop_y++,dest_addr+=mempitch)
  780.         {
  781.         // fill the line
  782.         memset((UCHAR *)dest_addr+(unsigned int)xs, color,(unsigned int)((int)xe-(int)xs+1));
  783.         // adjust starting point and ending point
  784.         xs+=dx_left;
  785.         xe+=dx_right;
  786.         } // end for
  787.     } // end if no x clipping needed
  788. else
  789.    {
  790.    // clip x axis with slower version
  791.    // draw the triangle
  792.    for (loop_y = iy1; loop_y <= iy3; loop_y++,dest_addr+=mempitch)
  793.        {
  794.        // do x clip
  795.        left  = xs;
  796.        right = xe;
  797.        // adjust starting point and ending point
  798.        xs+=dx_left;
  799.        xe+=dx_right;
  800.        // clip line
  801.        if (left < min_clip_x)
  802.           {
  803.           left = min_clip_x;
  804.           if (right < min_clip_x)
  805.              continue;
  806.           }
  807.        if (right > max_clip_x)
  808.           {
  809.           right = max_clip_x;
  810.           if (left > max_clip_x)
  811.              continue;
  812.           }
  813.        // fill the line
  814.        memset((UCHAR *)dest_addr+(unsigned int)left, color,(unsigned int)((int)right-(int)left+1));
  815.        } // end for
  816.    } // end else x clipping needed
  817. } // end Draw_Bottom_Tri2
  818. ///////////////////////////////////////////////////////////////////////////////
  819. void Draw_Triangle_2D2(float x1,float y1,
  820.                        float x2,float y2,
  821.                        float x3,float y3,
  822.                        int color,
  823.    UCHAR *dest_buffer, int mempitch)
  824. {
  825. // this function draws a triangle on the destination buffer
  826. // it decomposes all triangles into a pair of flat top, flat bottom
  827. float temp_x, // used for sorting
  828.       temp_y,
  829.       new_x;
  830. #ifdef DEBUG_ON
  831. // track rendering stats
  832.     debug_polys_rendered_per_frame++;
  833. #endif
  834. // test for h lines and v lines
  835. if ((FCMP(x1,x2) && FCMP(x2,x3))  ||  (FCMP(y1,y2) && FCMP(y2,y3)))
  836.    return;
  837. // sort p1,p2,p3 in ascending y order
  838. if (y2 < y1)
  839.    {
  840.    SWAP(x1,x2,temp_x);
  841.    SWAP(y1,y2,temp_y);
  842.    } // end if
  843. // now we know that p1 and p2 are in order
  844. if (y3 < y1)
  845.    {
  846.    SWAP(x1,x3,temp_x);
  847.    SWAP(y1,y3,temp_y);
  848.    } // end if
  849. // finally test y3 against y2
  850. if (y3 < y2)
  851.    {
  852.    SWAP(x2,x3,temp_x);
  853.    SWAP(y2,y3,temp_y);
  854.    } // end if
  855. // do trivial rejection tests for clipping
  856. if ( y3 < min_clip_y || y1 > max_clip_y ||
  857.     (x1 < min_clip_x && x2 < min_clip_x && x3<min_clip_x) ||
  858.     (x1 > max_clip_x && x2 > max_clip_x && x3>max_clip_x) )
  859.    return;
  860. // test if top of triangle is flat
  861. if (FCMP(y1,y2))
  862.    {
  863.    Draw_Top_Tri2(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  864.    } // end if
  865. else
  866. if (FCMP(y2,y3))
  867.    {
  868.    Draw_Bottom_Tri2(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  869.    } // end if bottom is flat
  870. else
  871.    {
  872.    // general triangle that's needs to be broken up along long edge
  873.    new_x = x1 + (y2-y1)*(x3-x1)/(y3-y1);
  874.    // draw each sub-triangle
  875.    Draw_Bottom_Tri2(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
  876.    Draw_Top_Tri2(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
  877.    } // end else
  878. } // end Draw_Triangle_2D2
  879. ////////////////////////////////////////////////////////////////////////////
  880. int Load_Bitmap_File2(BITMAP_FILE_PTR bitmap, char *filename)
  881. {
  882. // simply checks the file extension and calls the appropriate loader
  883. // .bmp or .pcx of course there must be a file extension!
  884. char _filename[256]; // temp string
  885. // copy string and upcase it
  886. strcpy(_filename, filename);
  887. _strupr(_filename);
  888. // check for bmp
  889. if (strstr(_filename, ".BMP"))
  890.    return(Load_Bitmap_File(bitmap, _filename));
  891. else // pcx?
  892. if (strstr(_filename, ".PCX"))
  893.    return(Load_Bitmap_PCX_File(bitmap, _filename));
  894. else // serious trouble
  895.    return(0);
  896. } // end Load_Bitmap_File2
  897. ////////////////////////////////////////////////////////////////////////////
  898. int Load_Bitmap_PCX_File(BITMAP_FILE_PTR bitmap, char *filename)
  899. {
  900. // this function loads a PCX file into the bitmap file structure. The function
  901. // has three main parts: 1. load the PCX header, 2. load the image data and
  902. // decompress it and 3. load the palette data 
  903. FILE *fp;               // the file pointer used to open the PCX file
  904. PCX_HEADER pcx_header;  // pcx file header
  905. int num_bytes,          // number of bytes in current RLE run
  906.     index,              // loop variable
  907.     count,              // the total number of bytes decompressed
  908.     width,              // width of image in pixels
  909.     height,             // height of image in pixels
  910.     bits_per_pixel,     // bits per pixel
  911.     bytes_per_pixel;
  912. UCHAR data;             // the current pixel data
  913. // open the file, test if it exists
  914. if ((fp = fopen(filename,"rb"))==NULL)
  915.    {
  916.    return(0);
  917.    } // end if couldn't find file
  918. // load the header
  919. for (index=0; index < sizeof(PCX_HEADER); index++)
  920.     {
  921.     ((UCHAR *)&pcx_header)[index] = (UCHAR)getc(fp);
  922.     } // end for index
  923. // compute statistics
  924. width  = (pcx_header.xmax - pcx_header.xmin) + 1;
  925. height = (pcx_header.ymax - pcx_header.ymin) + 1;
  926. // allocate memory
  927. bitmap->buffer = (UCHAR *)malloc( width*height );
  928. // compute bit stuff, not needed since it's ALWAYS 8-bit
  929. bits_per_pixel = pcx_header.bits_per_pixel;
  930. bytes_per_pixel = bits_per_pixel / 8;
  931. // loop while width*height bytes haven't been decompressed
  932. for (count = 0; count < width * height; )
  933.      {
  934.      // get the first piece of data
  935.      data = (UCHAR)getc(fp);
  936.      // is this a RLE run?
  937.      if (data >= 192 && data <= 255)
  938.         {
  939.         // compute number of bytes in run
  940.         num_bytes = data-192;
  941.         // get the actual data for the run
  942.         data  = (UCHAR)getc(fp);
  943.         // replicate data in buffer num_bytes times
  944.         while(num_bytes-- > 0)
  945.              {
  946.              bitmap->buffer[count++] = data;
  947.              } // end while
  948.         } // end if rle
  949.      else
  950.         {
  951.         // actual data, just copy it into buffer at next location
  952.         bitmap->buffer[count++] = data;
  953.         } // end else not rle
  954.      } // end for
  955. // move to end of file then back up 768 bytes i.e. to begining of palette
  956. fseek(fp,-768L,SEEK_END);
  957. // load the PCX pallete into the VGA color registers
  958. for (index=0; index < 256; index++)
  959.     {
  960.     // get the red component
  961.     bitmap->palette[index].peRed   = (unsigned char)getc(fp);
  962.     // get the green component
  963.     bitmap->palette[index].peGreen = (unsigned char)getc(fp);
  964.     // get the blue component
  965.     bitmap->palette[index].peBlue  = (unsigned char)getc(fp);
  966.     // always set the flags word to this
  967.     bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
  968.     } // end for index
  969. // time to close the file
  970. fclose(fp);
  971. // now fill in bitmap BMP header fields with translated information from 
  972. // pcx file, sneaky, but has to be done...
  973. bitmap->bitmapinfoheader.biBitCount     = bits_per_pixel;
  974. bitmap->bitmapinfoheader.biSizeImage    = width*height*bytes_per_pixel;
  975. bitmap->bitmapinfoheader.biWidth        = width;
  976. bitmap->bitmapinfoheader.biHeight       = height;
  977. bitmap->bitmapinfoheader.biClrUsed      = 256;
  978. bitmap->bitmapinfoheader.biClrImportant = 256;
  979. #if 1
  980. // write the file info out 
  981. printf("nfilename:%s nsize=%d nwidth=%d nheight=%d nbitsperpixel=%d ncolors=%d nimpcolors=%d",
  982.         filename,
  983.         bitmap->bitmapinfoheader.biSizeImage,
  984.         bitmap->bitmapinfoheader.biWidth,
  985.         bitmap->bitmapinfoheader.biHeight,
  986. bitmap->bitmapinfoheader.biBitCount,
  987.         bitmap->bitmapinfoheader.biClrUsed,
  988.         bitmap->bitmapinfoheader.biClrImportant);
  989. #endif
  990. // success
  991. return(1);
  992. } // end Load_Bitmap_PCX_File
  993. //////////////////////////////////////////////////////////
  994. int Compute_OBJECT4DV2_Poly_Normals(OBJECT4DV2_PTR obj)
  995. {
  996. // the normal of a polygon is commonly needed in a number 
  997. // of functions, however, to store a normal turns out to
  998. // be counterproductive in most cases since the transformation
  999. // to rotate the normal ends up taking as long as computing the
  1000. // normal -- HOWEVER, if the normal must have unit length, then
  1001. // pre-computing the length of the normal, and then in real-time
  1002. // dividing by this save a length computation, so we get the 
  1003. // best of both worlds... thus, this function computes the length
  1004. // of a polygon's normal, but care must be taken, so that we compute
  1005. // the length based on the EXACT same two vectors that all other 
  1006. // functions will use when computing the normal
  1007. // in most cases the functions of interest are the lighting functions
  1008. // if we can pre-compute the normal length
  1009. // for all these functions then that will save at least:
  1010. // num_polys_per_frame * (time to compute length of vector)
  1011. // the way we have written the engine, in all cases the normals 
  1012. // during lighting are computed as u = v0->v1, and v = v1->v2
  1013. // so as long as we follow that convention we are fine.
  1014. // also, since the new OBJECT4DV2 format supports multiple frames
  1015. // we must perform these calculations for EACH frame of the animation
  1016. // since although the poly indices don't change, the vertice positions
  1017. // do and thus, so do the normals!!!
  1018. // is this object valid
  1019. if (!obj)
  1020.    return(0); 
  1021. // iterate thru the poly list of the object and compute normals
  1022. // each polygon
  1023. for (int poly=0; poly < obj->num_polys; poly++)
  1024.     {
  1025.  
  1026.     // extract vertex indices into master list, rember the polygons are 
  1027.     // NOT self contained, but based on the vertex list stored in the object
  1028.     // itself
  1029.     int vindex_0 = obj->plist[poly].vert[0];
  1030.     int vindex_1 = obj->plist[poly].vert[1];
  1031.     int vindex_2 = obj->plist[poly].vert[2];
  1032.     
  1033.     // we need to compute the normal of this polygon face, and recall
  1034.     // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1035.     VECTOR4D u, v, n;
  1036.  
  1037.     // build u, v
  1038.     VECTOR4D_Build(&obj->vlist_local[ vindex_0 ].v, &obj->vlist_local[ vindex_1 ].v, &u);
  1039.     VECTOR4D_Build(&obj->vlist_local[ vindex_0 ].v, &obj->vlist_local[ vindex_2 ].v, &v);
  1040.     // compute cross product
  1041.     VECTOR4D_Cross(&u, &v, &n);
  1042.     // compute length of normal accurately and store in poly nlength
  1043.     // +- epsilon later to fix over/underflows
  1044.     obj->plist[poly].nlength = VECTOR4D_Length(&n); 
  1045.     } // end for poly
  1046. // return success
  1047. return(1);
  1048. } // end Compute_OBJECT4DV2_Poly_Normals
  1049. ///////////////////////////////////////////////////////////////////////////////
  1050. int Compute_OBJECT4DV2_Vertex_Normals(OBJECT4DV2_PTR obj)
  1051. {
  1052. // the vertex normals of each polygon are commonly needed in a number 
  1053. // functions, most importantly lighting calculations for gouraud shading
  1054. // however, we only need to compute the vertex normals for polygons that are
  1055. // gouraud shader, so for every vertex we must determine the polygons that
  1056. // share the vertex then compute the average normal, to determine if a polygon
  1057. // contributes we look at the shading flags for the polygon
  1058. // is this object valid
  1059. if (!obj)
  1060.    return(0); 
  1061. // algorithm: we are going to scan the polygon list and for every polygon
  1062. // that needs normals we are going to "accumulate" the surface normal into all
  1063. // vertices that the polygon touches, and increment a counter to track how many
  1064. // polys contribute to vertex, then when the scan is done the counts will be used
  1065. // to average the accumulated values, so instead of an O(n^2) algorithm, we get a O(c*n)
  1066. // this tracks the polygon indices that touch a particular vertex
  1067. // the array is used to count the number of contributors to the vertex
  1068. // so at the end of the process we can divide each "accumulated" normal
  1069. // and average
  1070. int polys_touch_vertex[OBJECT4DV2_MAX_VERTICES];
  1071. memset((void *)polys_touch_vertex, 0, sizeof(int)*OBJECT4DV2_MAX_VERTICES);
  1072. // iterate thru the poly list of the object, compute its normal, then add
  1073. // each vertice that composes it to the "touching" vertex array
  1074. // while accumulating the normal in the vertex normal array
  1075. for (int poly=0; poly < obj->num_polys; poly++)
  1076.     {
  1077.     Write_Error("nprocessing poly %d", poly);
  1078.     // test if this polygon needs vertex normals
  1079.     if (obj->plist[poly].attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD)
  1080.        {
  1081.        // extract vertex indices into master list, rember the polygons are 
  1082.        // NOT self contained, but based on the vertex list stored in the object
  1083.        // itself
  1084.        int vindex_0 = obj->plist[poly].vert[0];
  1085.        int vindex_1 = obj->plist[poly].vert[1];
  1086.        int vindex_2 = obj->plist[poly].vert[2];
  1087.     
  1088.        Write_Error("nTouches vertices: %d, %d, %d", vindex_0, vindex_1, vindex_2);
  1089.        // we need to compute the normal of this polygon face, and recall
  1090.        // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
  1091.        VECTOR4D u, v, n;
  1092.  
  1093.        // build u, v
  1094.        VECTOR4D_Build(&obj->vlist_local[ vindex_0 ].v, &obj->vlist_local[ vindex_1 ].v, &u);
  1095.        VECTOR4D_Build(&obj->vlist_local[ vindex_0 ].v, &obj->vlist_local[ vindex_2 ].v, &v);
  1096.        // compute cross product
  1097.        VECTOR4D_Cross(&u, &v, &n);
  1098.        // update vertex array to flag this polygon as a contributor
  1099.        polys_touch_vertex[vindex_0]++;
  1100.        polys_touch_vertex[vindex_1]++;
  1101.        polys_touch_vertex[vindex_2]++;
  1102.        Write_Error("nPoly touch array v[%d] = %d,  v[%d] = %d,  v[%d] = %d", vindex_0, polys_touch_vertex[vindex_0],
  1103.                                                                            vindex_1, polys_touch_vertex[vindex_1],
  1104.                                                                            vindex_2, polys_touch_vertex[vindex_2]);
  1105.        // now accumulate the normal into the vertex normal itself
  1106.        // note, we do NOT normalize at this point since we want the length of the normal
  1107.        // to weight on the average, and since the length is in fact the area of the parallelogram
  1108.        // constructed by uxv, so we are taking the "influence" of the area into consideration
  1109.        VECTOR4D_Add(&obj->vlist_local[vindex_0].n, &n, &obj->vlist_local[vindex_0].n);
  1110.        VECTOR4D_Add(&obj->vlist_local[vindex_1].n, &n, &obj->vlist_local[vindex_1].n);
  1111.        VECTOR4D_Add(&obj->vlist_local[vindex_2].n, &n, &obj->vlist_local[vindex_2].n);
  1112.        } // end for poly
  1113.       
  1114.      } // end if needs vertex normals
  1115. // now we are almost done, we have accumulated all the vertex normals, but need to average them
  1116. for (int vertex = 0; vertex < obj->num_vertices; vertex++)
  1117.     {
  1118.     // if this vertex has any contributors then it must need averaging, OR we could check
  1119.     // the shading hints flags, they should be one to one
  1120.     Write_Error("nProcessing vertex: %d, attr: %d, contributors: %d", vertex, 
  1121.                                                                        obj->vlist_local[vertex].attr, 
  1122.                                                                        polys_touch_vertex[vertex]);
  1123.     // test if this vertex has a normal and needs averaging
  1124.     if (polys_touch_vertex[vertex] >= 1)
  1125.        {
  1126.        obj->vlist_local[vertex].nx/=polys_touch_vertex[vertex];
  1127.        obj->vlist_local[vertex].ny/=polys_touch_vertex[vertex];
  1128.        obj->vlist_local[vertex].nz/=polys_touch_vertex[vertex];
  1129.        // now normalize the normal
  1130.        VECTOR4D_Normalize(&obj->vlist_local[vertex].n);
  1131.        Write_Error("nAvg Vertex normal: [%f, %f, %f]", obj->vlist_local[vertex].nx,
  1132.                                                         obj->vlist_local[vertex].ny,
  1133.                                                         obj->vlist_local[vertex].nz);
  1134.        } // end if
  1135.     } // end for
  1136. // return success
  1137. return(1);
  1138. } // end Compute_OBJECT4DV2_Vertex_Normals
  1139. ///////////////////////////////////////////////////////////////////////////////////////////////
  1140. void Draw_Gouraud_Triangle16(POLYF4DV2_PTR face,   // ptr to face
  1141.                               UCHAR *_dest_buffer, // pointer to video buffer
  1142.                               int mem_pitch)       // bytes per line, 320, 640 etc.
  1143. {
  1144. // this function draws a gouraud shaded polygon, based on the affine texture mapper, instead
  1145. // of interpolating the texture coordinates, we simply interpolate the (R,G,B) values across
  1146. // the polygons, I simply needed at another interpolant, I have mapped u->red, v->green, w->blue
  1147. int v0=0,
  1148.     v1=1,
  1149. v2=2,
  1150. temp=0,
  1151. tri_type = TRI_TYPE_NONE,
  1152. irestart = INTERP_LHS;
  1153. int dx,dy,dyl,dyr,      // general deltas
  1154.     u,v,w,
  1155.     du,dv,dw,
  1156.     xi,yi,              // the current interpolated x,y
  1157. ui,vi,wi,           // the current interpolated u,v
  1158. index_x,index_y,    // looping vars
  1159. x,y,                // hold general x,y
  1160. xstart,
  1161. xend,
  1162. ystart,
  1163. yrestart,
  1164. yend,
  1165. xl,                 
  1166. dxdyl,              
  1167. xr,
  1168. dxdyr,             
  1169. dudyl,    
  1170. ul,
  1171. dvdyl,   
  1172. vl,
  1173. dwdyl,   
  1174. wl,
  1175. dudyr,
  1176. ur,
  1177. dvdyr,
  1178. vr,
  1179. dwdyr,
  1180. wr;
  1181. int x0,y0,tu0,tv0,tw0,    // cached vertices
  1182. x1,y1,tu1,tv1,tw1,
  1183. x2,y2,tu2,tv2,tw2;
  1184. int r_base0, g_base0, b_base0,
  1185.     r_base1, g_base1, b_base1,
  1186.     r_base2, g_base2, b_base2;
  1187. USHORT *screen_ptr  = NULL,
  1188.    *screen_line = NULL,
  1189.    *textmap     = NULL,
  1190.        *dest_buffer = (USHORT *)_dest_buffer;
  1191. #ifdef DEBUG_ON
  1192. // track rendering stats
  1193.     debug_polys_rendered_per_frame++;
  1194. #endif
  1195. // adjust memory pitch to words, divide by 2
  1196. mem_pitch >>=1;
  1197. // first trivial clipping rejection tests 
  1198. if (((face->tvlist[0].y < min_clip_y)  && 
  1199.  (face->tvlist[1].y < min_clip_y)  &&
  1200.  (face->tvlist[2].y < min_clip_y)) ||
  1201. ((face->tvlist[0].y > max_clip_y)  && 
  1202.  (face->tvlist[1].y > max_clip_y)  &&
  1203.  (face->tvlist[2].y > max_clip_y)) ||
  1204. ((face->tvlist[0].x < min_clip_x)  && 
  1205.  (face->tvlist[1].x < min_clip_x)  &&
  1206.  (face->tvlist[2].x < min_clip_x)) ||
  1207. ((face->tvlist[0].x > max_clip_x)  && 
  1208.  (face->tvlist[1].x > max_clip_x)  &&
  1209.  (face->tvlist[2].x > max_clip_x)))
  1210.    return;
  1211. // degenerate triangle
  1212. if ( ((face->tvlist[0].x==face->tvlist[1].x) && (face->tvlist[1].x==face->tvlist[2].x)) ||
  1213.  ((face->tvlist[0].y==face->tvlist[1].y) && (face->tvlist[1].y==face->tvlist[2].y)))
  1214.    return;
  1215. // sort vertices
  1216. if (face->tvlist[v1].y < face->tvlist[v0].y) 
  1217. {SWAP(v0,v1,temp);} 
  1218. if (face->tvlist[v2].y < face->tvlist[v0].y) 
  1219. {SWAP(v0,v2,temp);}
  1220. if (face->tvlist[v2].y < face->tvlist[v1].y) 
  1221. {SWAP(v1,v2,temp);}
  1222. // now test for trivial flat sided cases
  1223. if (face->tvlist[v0].y==face->tvlist[v1].y)
  1224. // set triangle type
  1225. tri_type = TRI_TYPE_FLAT_TOP;
  1226. // sort vertices left to right
  1227. if (face->tvlist[v1].x < face->tvlist[v0].x) 
  1228. {SWAP(v0,v1,temp);}
  1229. } // end if
  1230. else
  1231. // now test for trivial flat sided cases
  1232. if (face->tvlist[v1].y==face->tvlist[v2].y)
  1233. // set triangle type
  1234. tri_type = TRI_TYPE_FLAT_BOTTOM;
  1235. // sort vertices left to right
  1236. if (face->tvlist[v2].x < face->tvlist[v1].x) 
  1237. {SWAP(v1,v2,temp);}
  1238. } // end if
  1239. else
  1240. {
  1241. // must be a general triangle
  1242. tri_type = TRI_TYPE_GENERAL;
  1243. } // end else
  1244. // assume 5.6.5 format -- sorry!
  1245. // we can't afford a function call in the inner loops, so we must write 
  1246. // two hard coded versions, if we want support for both 5.6.5, and 5.5.5
  1247. _RGB565FROM16BIT(face->lit_color[v0], &r_base0, &g_base0, &b_base0);
  1248. _RGB565FROM16BIT(face->lit_color[v1], &r_base1, &g_base1, &b_base1);
  1249. _RGB565FROM16BIT(face->lit_color[v2], &r_base2, &g_base2, &b_base2);
  1250. // scale to 8 bit 
  1251. r_base0 <<= 3;
  1252. g_base0 <<= 2;
  1253. b_base0 <<= 3;
  1254. // scale to 8 bit 
  1255. r_base1 <<= 3;
  1256. g_base1 <<= 2;
  1257. b_base1 <<= 3;
  1258. // scale to 8 bit 
  1259. r_base2 <<= 3;
  1260. g_base2 <<= 2;
  1261. b_base2 <<= 3;
  1262. // extract vertices for processing, now that we have order
  1263. x0  = (int)(face->tvlist[v0].x+0.5);
  1264. y0  = (int)(face->tvlist[v0].y+0.5);
  1265. tu0 = r_base0;
  1266. tv0 = g_base0; 
  1267. tw0 = b_base0; 
  1268. x1  = (int)(face->tvlist[v1].x+0.5);
  1269. y1  = (int)(face->tvlist[v1].y+0.5);
  1270. tu1 = r_base1;
  1271. tv1 = g_base1; 
  1272. tw1 = b_base1; 
  1273. x2  = (int)(face->tvlist[v2].x+0.5);
  1274. y2  = (int)(face->tvlist[v2].y+0.5);
  1275. tu2 = r_base2; 
  1276. tv2 = g_base2; 
  1277. tw2 = b_base2; 
  1278. // set interpolation restart value
  1279. yrestart = y1;
  1280. // what kind of triangle
  1281. if (tri_type & TRI_TYPE_FLAT_MASK)
  1282. {
  1283. if (tri_type == TRI_TYPE_FLAT_TOP)
  1284. {
  1285. // compute all deltas
  1286. dy = (y2 - y0);
  1287. dxdyl = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  1288. dudyl = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  1289. dvdyl = ((tv2 - tv0) << FIXP16_SHIFT)/dy;    
  1290. dwdyl = ((tw2 - tw0) << FIXP16_SHIFT)/dy;  
  1291. dxdyr = ((x2 - x1)   << FIXP16_SHIFT)/dy;
  1292. dudyr = ((tu2 - tu1) << FIXP16_SHIFT)/dy;  
  1293. dvdyr = ((tv2 - tv1) << FIXP16_SHIFT)/dy;   
  1294. dwdyr = ((tw2 - tw1) << FIXP16_SHIFT)/dy;   
  1295. // test for y clipping
  1296. if (y0 < min_clip_y)
  1297. {
  1298. // compute overclip
  1299. dy = (min_clip_y - y0);
  1300. // computer new LHS starting values
  1301. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  1302. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  1303. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  1304. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  1305. // compute new RHS starting values
  1306. xr = dxdyr*dy + (x1  << FIXP16_SHIFT);
  1307. ur = dudyr*dy + (tu1 << FIXP16_SHIFT);
  1308. vr = dvdyr*dy + (tv1 << FIXP16_SHIFT);
  1309. wr = dwdyr*dy + (tw1 << FIXP16_SHIFT);
  1310. // compute new starting y
  1311. ystart = min_clip_y;
  1312. } // end if
  1313. else
  1314. {
  1315. // no clipping
  1316. // set starting values
  1317. xl = (x0 << FIXP16_SHIFT);
  1318. xr = (x1 << FIXP16_SHIFT);
  1319. ul = (tu0 << FIXP16_SHIFT);
  1320. vl = (tv0 << FIXP16_SHIFT);
  1321. wl = (tw0 << FIXP16_SHIFT);
  1322. ur = (tu1 << FIXP16_SHIFT);
  1323. vr = (tv1 << FIXP16_SHIFT);
  1324. wr = (tw1 << FIXP16_SHIFT);
  1325. // set starting y
  1326. ystart = y0;
  1327. } // end else
  1328. } // end if flat top
  1329. else
  1330. {
  1331. // must be flat bottom
  1332. // compute all deltas
  1333. dy = (y1 - y0);
  1334. dxdyl = ((x1 - x0)   << FIXP16_SHIFT)/dy;
  1335. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dy;  
  1336. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dy;    
  1337. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dy; 
  1338. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  1339. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  1340. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dy;   
  1341. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dy;   
  1342. // test for y clipping
  1343. if (y0 < min_clip_y)
  1344. {
  1345. // compute overclip
  1346. dy = (min_clip_y - y0);
  1347. // computer new LHS starting values
  1348. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  1349. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  1350. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  1351. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  1352. // compute new RHS starting values
  1353. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  1354. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  1355. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  1356. wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
  1357. // compute new starting y
  1358. ystart = min_clip_y;
  1359. } // end if
  1360. else
  1361. {
  1362. // no clipping
  1363. // set starting values
  1364. xl = (x0 << FIXP16_SHIFT);
  1365. xr = (x0 << FIXP16_SHIFT);
  1366. ul = (tu0 << FIXP16_SHIFT);
  1367. vl = (tv0 << FIXP16_SHIFT);
  1368. wl = (tw0 << FIXP16_SHIFT);
  1369. ur = (tu0 << FIXP16_SHIFT);
  1370. vr = (tv0 << FIXP16_SHIFT);
  1371. wr = (tw0 << FIXP16_SHIFT);
  1372. // set starting y
  1373. ystart = y0;
  1374. } // end else
  1375. } // end else flat bottom
  1376. // test for bottom clip, always
  1377. if ((yend = y2) > max_clip_y)
  1378. yend = max_clip_y;
  1379.     // test for horizontal clipping
  1380. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  1381. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  1382. (x2 < min_clip_x) || (x2 > max_clip_x))
  1383. {
  1384.     // clip version
  1385. // point screen ptr to starting line
  1386. screen_ptr = dest_buffer + (ystart * mem_pitch);
  1387. for (yi = ystart; yi<=yend; yi++)
  1388. {
  1389. // compute span endpoints
  1390. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1391. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1392. // compute starting points for u,v,w interpolants
  1393. ui = ul + FIXP16_ROUND_UP;
  1394. vi = vl + FIXP16_ROUND_UP;
  1395. wi = wl + FIXP16_ROUND_UP;
  1396. // compute u,v interpolants
  1397. if ((dx = (xend - xstart))>0)
  1398. {
  1399. du = (ur - ul)/dx;
  1400. dv = (vr - vl)/dx;
  1401. dw = (wr - wl)/dx;
  1402. } // end if
  1403. else
  1404. {
  1405. du = (ur - ul);
  1406. dv = (vr - vl);
  1407. dw = (wr - wl);
  1408. } // end else
  1409. ///////////////////////////////////////////////////////////////////////
  1410. // test for x clipping, LHS
  1411. if (xstart < min_clip_x)
  1412. {
  1413. // compute x overlap
  1414. dx = min_clip_x - xstart;
  1415. // slide interpolants over
  1416. ui+=dx*du;
  1417. vi+=dx*dv;
  1418. wi+=dx*dw;
  1419. // reset vars
  1420. xstart = min_clip_x;
  1421. } // end if
  1422. // test for x clipping RHS
  1423. if (xend > max_clip_x)
  1424. xend = max_clip_x;
  1425. ///////////////////////////////////////////////////////////////////////
  1426. // draw span
  1427. for (xi=xstart; xi<=xend; xi++)
  1428. {
  1429. // write textel assume 5.6.5
  1430.         screen_ptr[xi] = ((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3));   
  1431. // interpolate u,v
  1432. ui+=du;
  1433. vi+=dv;
  1434. wi+=dw;
  1435. } // end for xi
  1436. // interpolate u,v,w,x along right and left edge
  1437. xl+=dxdyl;
  1438. ul+=dudyl;
  1439. vl+=dvdyl;
  1440. wl+=dwdyl;
  1441. xr+=dxdyr;
  1442. ur+=dudyr;
  1443. vr+=dvdyr;
  1444. wr+=dwdyr;
  1445.  
  1446. // advance screen ptr
  1447. screen_ptr+=mem_pitch;
  1448. } // end for y
  1449. } // end if clip
  1450. else
  1451. {
  1452. // non-clip version
  1453. // point screen ptr to starting line
  1454. screen_ptr = dest_buffer + (ystart * mem_pitch);
  1455. for (yi = ystart; yi<=yend; yi++)
  1456. {
  1457. // compute span endpoints
  1458. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1459. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1460. // compute starting points for u,v,w interpolants
  1461. ui = ul + FIXP16_ROUND_UP;
  1462. vi = vl + FIXP16_ROUND_UP;
  1463. wi = wl + FIXP16_ROUND_UP;
  1464. // compute u,v interpolants
  1465. if ((dx = (xend - xstart))>0)
  1466. {
  1467. du = (ur - ul)/dx;
  1468. dv = (vr - vl)/dx;
  1469. dw = (wr - wl)/dx;
  1470. } // end if
  1471. else
  1472. {
  1473. du = (ur - ul);
  1474. dv = (vr - vl);
  1475. dw = (wr - wl);
  1476. } // end else
  1477. // draw span
  1478. for (xi=xstart; xi<=xend; xi++)
  1479. {
  1480. // write textel 5.6.5
  1481.             screen_ptr[xi] = ((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3));   
  1482. // interpolate u,v
  1483. ui+=du;
  1484. vi+=dv;
  1485. wi+=dw;
  1486. } // end for xi
  1487. // interpolate u,v,w,x along right and left edge
  1488. xl+=dxdyl;
  1489. ul+=dudyl;
  1490. vl+=dvdyl;
  1491. wl+=dwdyl;
  1492. xr+=dxdyr;
  1493. ur+=dudyr;
  1494. vr+=dvdyr;
  1495. wr+=dwdyr;
  1496. // advance screen ptr
  1497. screen_ptr+=mem_pitch;
  1498. } // end for y
  1499. } // end if non-clipped
  1500. } // end if
  1501. else
  1502. if (tri_type==TRI_TYPE_GENERAL)
  1503. {
  1504. // first test for bottom clip, always
  1505. if ((yend = y2) > max_clip_y)
  1506. yend = max_clip_y;
  1507. // pre-test y clipping status
  1508. if (y1 < min_clip_y)
  1509. {
  1510. // compute all deltas
  1511. // LHS
  1512. dyl = (y2 - y1);
  1513. dxdyl = ((x2  - x1)  << FIXP16_SHIFT)/dyl;
  1514. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  1515. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;    
  1516. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;  
  1517. // RHS
  1518. dyr = (y2 - y0);
  1519. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  1520. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  1521. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  1522. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;   
  1523. // compute overclip
  1524. dyr = (min_clip_y - y0);
  1525. dyl = (min_clip_y - y1);
  1526. // computer new LHS starting values
  1527. xl = dxdyl*dyl + (x1  << FIXP16_SHIFT);
  1528. ul = dudyl*dyl + (tu1 << FIXP16_SHIFT);
  1529. vl = dvdyl*dyl + (tv1 << FIXP16_SHIFT);
  1530. wl = dwdyl*dyl + (tw1 << FIXP16_SHIFT);
  1531. // compute new RHS starting values
  1532. xr = dxdyr*dyr + (x0  << FIXP16_SHIFT);
  1533. ur = dudyr*dyr + (tu0 << FIXP16_SHIFT);
  1534. vr = dvdyr*dyr + (tv0 << FIXP16_SHIFT);
  1535. wr = dwdyr*dyr + (tw0 << FIXP16_SHIFT);
  1536. // compute new starting y
  1537. ystart = min_clip_y;
  1538. // test if we need swap to keep rendering left to right
  1539. if (dxdyr > dxdyl)
  1540. {
  1541. SWAP(dxdyl,dxdyr,temp);
  1542. SWAP(dudyl,dudyr,temp);
  1543. SWAP(dvdyl,dvdyr,temp);
  1544. SWAP(dwdyl,dwdyr,temp);
  1545. SWAP(xl,xr,temp);
  1546. SWAP(ul,ur,temp);
  1547. SWAP(vl,vr,temp);
  1548. SWAP(wl,wr,temp);
  1549. SWAP(x1,x2,temp);
  1550. SWAP(y1,y2,temp);
  1551. SWAP(tu1,tu2,temp);
  1552. SWAP(tv1,tv2,temp);
  1553. SWAP(tw1,tw2,temp);
  1554. // set interpolation restart
  1555. irestart = INTERP_RHS;
  1556. } // end if
  1557. } // end if
  1558. else
  1559. if (y0 < min_clip_y)
  1560. {
  1561. // compute all deltas
  1562. // LHS
  1563. dyl = (y1 - y0);
  1564. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  1565. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  1566. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  1567. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dyl; 
  1568. // RHS
  1569. dyr = (y2 - y0);
  1570. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  1571. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  1572. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  1573. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;   
  1574. // compute overclip
  1575. dy = (min_clip_y - y0);
  1576. // computer new LHS starting values
  1577. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  1578. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  1579. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  1580. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  1581. // compute new RHS starting values
  1582. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  1583. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  1584. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  1585. wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
  1586. // compute new starting y
  1587. ystart = min_clip_y;
  1588. // test if we need swap to keep rendering left to right
  1589. if (dxdyr < dxdyl)
  1590. {
  1591. SWAP(dxdyl,dxdyr,temp);
  1592. SWAP(dudyl,dudyr,temp);
  1593. SWAP(dvdyl,dvdyr,temp);
  1594. SWAP(dwdyl,dwdyr,temp);
  1595. SWAP(xl,xr,temp);
  1596. SWAP(ul,ur,temp);
  1597. SWAP(vl,vr,temp);
  1598. SWAP(wl,wr,temp);
  1599. SWAP(x1,x2,temp);
  1600. SWAP(y1,y2,temp);
  1601. SWAP(tu1,tu2,temp);
  1602. SWAP(tv1,tv2,temp);
  1603. SWAP(tw1,tw2,temp);
  1604. // set interpolation restart
  1605. irestart = INTERP_RHS;
  1606. } // end if
  1607. } // end if
  1608. else
  1609. {
  1610. // no initial y clipping
  1611. // compute all deltas
  1612. // LHS
  1613. dyl = (y1 - y0);
  1614. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  1615. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  1616. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  1617. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dyl;   
  1618. // RHS
  1619. dyr = (y2 - y0);
  1620. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dyr;
  1621. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  1622. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  1623. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;
  1624. // no clipping y
  1625. // set starting values
  1626. xl = (x0 << FIXP16_SHIFT);
  1627. xr = (x0 << FIXP16_SHIFT);
  1628. ul = (tu0 << FIXP16_SHIFT);
  1629. vl = (tv0 << FIXP16_SHIFT);
  1630. wl = (tw0 << FIXP16_SHIFT);
  1631. ur = (tu0 << FIXP16_SHIFT);
  1632. vr = (tv0 << FIXP16_SHIFT);
  1633. wr = (tw0 << FIXP16_SHIFT);
  1634. // set starting y
  1635. ystart = y0;
  1636. // test if we need swap to keep rendering left to right
  1637. if (dxdyr < dxdyl)
  1638. {
  1639. SWAP(dxdyl,dxdyr,temp);
  1640. SWAP(dudyl,dudyr,temp);
  1641. SWAP(dvdyl,dvdyr,temp);
  1642. SWAP(dwdyl,dwdyr,temp);
  1643. SWAP(xl,xr,temp);
  1644. SWAP(ul,ur,temp);
  1645. SWAP(vl,vr,temp);
  1646. SWAP(wl,wr,temp);
  1647. SWAP(x1,x2,temp);
  1648. SWAP(y1,y2,temp);
  1649. SWAP(tu1,tu2,temp);
  1650. SWAP(tv1,tv2,temp);
  1651. SWAP(tw1,tw2,temp);
  1652. // set interpolation restart
  1653. irestart = INTERP_RHS;
  1654. } // end if
  1655. } // end else
  1656.     // test for horizontal clipping
  1657. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  1658. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  1659. (x2 < min_clip_x) || (x2 > max_clip_x))
  1660. {
  1661.     // clip version
  1662. // x clipping
  1663. // point screen ptr to starting line
  1664. screen_ptr = dest_buffer + (ystart * mem_pitch);
  1665. for (yi = ystart; yi<=yend; yi++)
  1666. {
  1667. // compute span endpoints
  1668. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1669. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1670. // compute starting points for u,v,w interpolants
  1671. ui = ul + FIXP16_ROUND_UP;
  1672. vi = vl + FIXP16_ROUND_UP;
  1673. wi = wl + FIXP16_ROUND_UP;
  1674. // compute u,v interpolants
  1675. if ((dx = (xend - xstart))>0)
  1676. {
  1677. du = (ur - ul)/dx;
  1678. dv = (vr - vl)/dx;
  1679. dw = (wr - wl)/dx;
  1680. } // end if
  1681. else
  1682. {
  1683. du = (ur - ul);
  1684. dv = (vr - vl);
  1685. dw = (wr - wl);
  1686. } // end else
  1687. ///////////////////////////////////////////////////////////////////////
  1688. // test for x clipping, LHS
  1689. if (xstart < min_clip_x)
  1690. {
  1691. // compute x overlap
  1692. dx = min_clip_x - xstart;
  1693. // slide interpolants over
  1694. ui+=dx*du;
  1695. vi+=dx*dv;
  1696. wi+=dx*dw;
  1697. // set x to left clip edge
  1698. xstart = min_clip_x;
  1699. } // end if
  1700. // test for x clipping RHS
  1701. if (xend > max_clip_x)
  1702. xend = max_clip_x;
  1703. ///////////////////////////////////////////////////////////////////////
  1704. // draw span
  1705. for (xi=xstart; xi<=xend; xi++)
  1706. {
  1707. // write textel assume 5.6.5
  1708.             screen_ptr[xi] = ((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3));   
  1709. // interpolate u,v
  1710. ui+=du;
  1711. vi+=dv;
  1712. wi+=dw;
  1713. } // end for xi
  1714. // interpolate u,v,w,x along right and left edge
  1715. xl+=dxdyl;
  1716.         ul+=dudyl;
  1717. vl+=dvdyl;
  1718. wl+=dwdyl;
  1719. xr+=dxdyr;
  1720.       ur+=dudyr;
  1721. vr+=dvdyr;
  1722. wr+=dwdyr;
  1723. // advance screen ptr
  1724. screen_ptr+=mem_pitch;
  1725. // test for yi hitting second region, if so change interpolant
  1726. if (yi==yrestart)
  1727. {
  1728.     // test interpolation side change flag
  1729. if (irestart == INTERP_LHS)
  1730. {
  1731. // LHS
  1732. dyl = (y2 - y1);
  1733. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  1734. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  1735. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  1736. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;  
  1737. // set starting values
  1738. xl = (x1  << FIXP16_SHIFT);
  1739. ul = (tu1 << FIXP16_SHIFT);
  1740. vl = (tv1 << FIXP16_SHIFT);
  1741. wl = (tw1 << FIXP16_SHIFT);
  1742. // interpolate down on LHS to even up
  1743. xl+=dxdyl;
  1744. ul+=dudyl;
  1745. vl+=dvdyl;
  1746. wl+=dwdyl;
  1747. } // end if
  1748. else
  1749. {
  1750. // RHS
  1751. dyr = (y1 - y2);
  1752. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  1753. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  1754. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  1755. dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;   
  1756. // set starting values
  1757. xr = (x2  << FIXP16_SHIFT);
  1758. ur = (tu2 << FIXP16_SHIFT);
  1759. vr = (tv2 << FIXP16_SHIFT);
  1760. wr = (tw2 << FIXP16_SHIFT);
  1761. // interpolate down on RHS to even up
  1762. xr+=dxdyr;
  1763. ur+=dudyr;
  1764. vr+=dvdyr;
  1765. wr+=dwdyr;
  1766. } // end else
  1767. } // end if
  1768. } // end for y
  1769. } // end if
  1770. else
  1771. {
  1772. // no x clipping
  1773. // point screen ptr to starting line
  1774. screen_ptr = dest_buffer + (ystart * mem_pitch);
  1775. for (yi = ystart; yi<=yend; yi++)
  1776. {
  1777. // compute span endpoints
  1778. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1779. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1780. // compute starting points for u,v,w interpolants
  1781. ui = ul + FIXP16_ROUND_UP;
  1782. vi = vl + FIXP16_ROUND_UP;
  1783. wi = wl + FIXP16_ROUND_UP;
  1784. // compute u,v interpolants
  1785. if ((dx = (xend - xstart))>0)
  1786. {
  1787. du = (ur - ul)/dx;
  1788. dv = (vr - vl)/dx;
  1789. dw = (wr - wl)/dx;
  1790. } // end if
  1791. else
  1792. {
  1793. du = (ur - ul);
  1794. dv = (vr - vl);
  1795. dw = (wr - wl);
  1796. } // end else
  1797. // draw span
  1798. for (xi=xstart; xi<=xend; xi++)
  1799. {
  1800. // write textel assume 5.6.5
  1801.             screen_ptr[xi] = ((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3));   
  1802. // interpolate u,v
  1803. ui+=du;
  1804. vi+=dv;
  1805. wi+=dw;
  1806. } // end for xi
  1807. // interpolate u,v,w,x along right and left edge
  1808. xl+=dxdyl;
  1809. ul+=dudyl;
  1810. vl+=dvdyl;
  1811. wl+=dwdyl;
  1812. xr+=dxdyr;
  1813. ur+=dudyr;
  1814. vr+=dvdyr;
  1815. wr+=dwdyr;
  1816. // advance screen ptr
  1817. screen_ptr+=mem_pitch;
  1818. // test for yi hitting second region, if so change interpolant
  1819. if (yi==yrestart)
  1820. {
  1821. // test interpolation side change flag
  1822. if (irestart == INTERP_LHS)
  1823. {
  1824. // LHS
  1825. dyl = (y2 - y1);
  1826. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  1827. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  1828. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  1829. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;   
  1830. // set starting values
  1831. xl = (x1  << FIXP16_SHIFT);
  1832. ul = (tu1 << FIXP16_SHIFT);
  1833. vl = (tv1 << FIXP16_SHIFT);
  1834. wl = (tw1 << FIXP16_SHIFT);
  1835. // interpolate down on LHS to even up
  1836. xl+=dxdyl;
  1837. ul+=dudyl;
  1838. vl+=dvdyl;
  1839. wl+=dwdyl;
  1840. } // end if
  1841. else
  1842. {
  1843. // RHS
  1844. dyr = (y1 - y2);
  1845. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  1846. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  1847. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  1848. dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;   
  1849. // set starting values
  1850. xr = (x2  << FIXP16_SHIFT);
  1851. ur = (tu2 << FIXP16_SHIFT);
  1852. vr = (tv2 << FIXP16_SHIFT);
  1853. wr = (tw2 << FIXP16_SHIFT);
  1854. // interpolate down on RHS to even up
  1855. xr+=dxdyr;
  1856. ur+=dudyr;
  1857. vr+=dvdyr;
  1858. wr+=dwdyr;
  1859. } // end else
  1860. } // end if
  1861. } // end for y
  1862.    } // end else
  1863. } // end if
  1864. } // end Draw_Gouraud_Triangle16
  1865. ///////////////////////////////////////////////////////////////////////////////
  1866. void Draw_Gouraud_Triangle(POLYF4DV2_PTR face,   // ptr to face
  1867.                           UCHAR *dest_buffer, // pointer to video buffer
  1868.                           int mem_pitch)       // bytes per line, 320, 640 etc.
  1869. {
  1870. // this function draws a gouraud shaded polygon, based on the affine texture mapper, instead
  1871. // of interpolating the texture coordinates, we simply interpolate the (R,G,B) values across
  1872. // the polygons, I simply needed at another interpolant, I have mapped u->red, v->green, w->blue
  1873. // note that this is the 8-bit version, and I have decided to throw caution at the wind and see
  1874. // what happens if we do a full RGB interpolation and then at the last minute use the color lookup
  1875. // to find the appropriate color
  1876. int v0=0,
  1877.     v1=1,
  1878. v2=2,
  1879. temp=0,
  1880. tri_type = TRI_TYPE_NONE,
  1881. irestart = INTERP_LHS;
  1882. int dx,dy,dyl,dyr,      // general deltas
  1883.     u,v,w,
  1884.     du,dv,dw,
  1885.     xi,yi,              // the current interpolated x,y
  1886. ui,vi,wi,           // the current interpolated u,v
  1887. index_x,index_y,    // looping vars
  1888. x,y,                // hold general x,y
  1889. xstart,
  1890. xend,
  1891. ystart,
  1892. yrestart,
  1893. yend,
  1894. xl,                 
  1895. dxdyl,              
  1896. xr,
  1897. dxdyr,             
  1898. dudyl,    
  1899. ul,
  1900. dvdyl,   
  1901. vl,
  1902. dwdyl,   
  1903. wl,
  1904. dudyr,
  1905. ur,
  1906. dvdyr,
  1907. vr,
  1908. dwdyr,
  1909. wr;
  1910. int x0,y0,tu0,tv0,tw0,    // cached vertices
  1911. x1,y1,tu1,tv1,tw1,
  1912. x2,y2,tu2,tv2,tw2;
  1913. int r_base0, g_base0, b_base0,
  1914.     r_base1, g_base1, b_base1,
  1915.     r_base2, g_base2, b_base2;
  1916. UCHAR  *screen_ptr  = NULL,
  1917.    *screen_line = NULL,
  1918.    *textmap     = NULL;
  1919. #ifdef DEBUG_ON
  1920. // track rendering stats
  1921.     debug_polys_rendered_per_frame++;
  1922. #endif
  1923. // first trivial clipping rejection tests 
  1924. if (((face->tvlist[0].y < min_clip_y)  && 
  1925.  (face->tvlist[1].y < min_clip_y)  &&
  1926.  (face->tvlist[2].y < min_clip_y)) ||
  1927. ((face->tvlist[0].y > max_clip_y)  && 
  1928.  (face->tvlist[1].y > max_clip_y)  &&
  1929.  (face->tvlist[2].y > max_clip_y)) ||
  1930. ((face->tvlist[0].x < min_clip_x)  && 
  1931.  (face->tvlist[1].x < min_clip_x)  &&
  1932.  (face->tvlist[2].x < min_clip_x)) ||
  1933. ((face->tvlist[0].x > max_clip_x)  && 
  1934.  (face->tvlist[1].x > max_clip_x)  &&
  1935.  (face->tvlist[2].x > max_clip_x)))
  1936.    return;
  1937. // degenerate triangle
  1938. if ( ((face->tvlist[0].x==face->tvlist[1].x) && (face->tvlist[1].x==face->tvlist[2].x)) ||
  1939.  ((face->tvlist[0].y==face->tvlist[1].y) && (face->tvlist[1].y==face->tvlist[2].y)))
  1940.    return;
  1941. // sort vertices
  1942. if (face->tvlist[v1].y < face->tvlist[v0].y) 
  1943. {SWAP(v0,v1,temp);} 
  1944. if (face->tvlist[v2].y < face->tvlist[v0].y) 
  1945. {SWAP(v0,v2,temp);}
  1946. if (face->tvlist[v2].y < face->tvlist[v1].y) 
  1947. {SWAP(v1,v2,temp);}
  1948. // now test for trivial flat sided cases
  1949. if (face->tvlist[v0].y==face->tvlist[v1].y)
  1950. // set triangle type
  1951. tri_type = TRI_TYPE_FLAT_TOP;
  1952. // sort vertices left to right
  1953. if (face->tvlist[v1].x < face->tvlist[v0].x) 
  1954. {SWAP(v0,v1,temp);}
  1955. } // end if
  1956. else
  1957. // now test for trivial flat sided cases
  1958. if (face->tvlist[v1].y==face->tvlist[v2].y)
  1959. // set triangle type
  1960. tri_type = TRI_TYPE_FLAT_BOTTOM;
  1961. // sort vertices left to right
  1962. if (face->tvlist[v2].x < face->tvlist[v1].x) 
  1963. {SWAP(v1,v2,temp);}
  1964. } // end if
  1965. else
  1966. {
  1967. // must be a general triangle
  1968. tri_type = TRI_TYPE_GENERAL;
  1969. } // end else
  1970. // assume 5.6.5 format -- sorry!
  1971. // we can't afford a function call in the inner loops, so we must write 
  1972. // two hard coded versions, if we want support for both 5.6.5, and 5.5.5
  1973. // notice that eventhough we will rasterize in 8-bit, the incoming data
  1974. // is still in RGB format
  1975. _RGB565FROM16BIT(face->lit_color[v0], &r_base0, &g_base0, &b_base0);
  1976. _RGB565FROM16BIT(face->lit_color[v1], &r_base1, &g_base1, &b_base1);
  1977. _RGB565FROM16BIT(face->lit_color[v2], &r_base2, &g_base2, &b_base2);
  1978. // scale to 8 bit 
  1979. r_base0 <<= 3;
  1980. g_base0 <<= 2;
  1981. b_base0 <<= 3;
  1982. // scale to 8 bit 
  1983. r_base1 <<= 3;
  1984. g_base1 <<= 2;
  1985. b_base1 <<= 3;
  1986. // scale to 8 bit 
  1987. r_base2 <<= 3;
  1988. g_base2 <<= 2;
  1989. b_base2 <<= 3;
  1990. // extract vertices for processing, now that we have order
  1991. x0  = (int)(face->tvlist[v0].x+0.5);
  1992. y0  = (int)(face->tvlist[v0].y+0.5);
  1993. tu0 = r_base0;
  1994. tv0 = g_base0; 
  1995. tw0 = b_base0; 
  1996. x1  = (int)(face->tvlist[v1].x+0.5);
  1997. y1  = (int)(face->tvlist[v1].y+0.5);
  1998. tu1 = r_base1;
  1999. tv1 = g_base1; 
  2000. tw1 = b_base1; 
  2001. x2  = (int)(face->tvlist[v2].x+0.5);
  2002. y2  = (int)(face->tvlist[v2].y+0.5);
  2003. tu2 = r_base2; 
  2004. tv2 = g_base2; 
  2005. tw2 = b_base2; 
  2006. // set interpolation restart value
  2007. yrestart = y1;
  2008. // what kind of triangle
  2009. if (tri_type & TRI_TYPE_FLAT_MASK)
  2010. {
  2011. if (tri_type == TRI_TYPE_FLAT_TOP)
  2012. {
  2013. // compute all deltas
  2014. dy = (y2 - y0);
  2015. dxdyl = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  2016. dudyl = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  2017. dvdyl = ((tv2 - tv0) << FIXP16_SHIFT)/dy;    
  2018. dwdyl = ((tw2 - tw0) << FIXP16_SHIFT)/dy;  
  2019. dxdyr = ((x2 - x1)   << FIXP16_SHIFT)/dy;
  2020. dudyr = ((tu2 - tu1) << FIXP16_SHIFT)/dy;  
  2021. dvdyr = ((tv2 - tv1) << FIXP16_SHIFT)/dy;   
  2022. dwdyr = ((tw2 - tw1) << FIXP16_SHIFT)/dy;   
  2023. // test for y clipping
  2024. if (y0 < min_clip_y)
  2025. {
  2026. // compute overclip
  2027. dy = (min_clip_y - y0);
  2028. // computer new LHS starting values
  2029. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  2030. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  2031. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  2032. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  2033. // compute new RHS starting values
  2034. xr = dxdyr*dy + (x1  << FIXP16_SHIFT);
  2035. ur = dudyr*dy + (tu1 << FIXP16_SHIFT);
  2036. vr = dvdyr*dy + (tv1 << FIXP16_SHIFT);
  2037. wr = dwdyr*dy + (tw1 << FIXP16_SHIFT);
  2038. // compute new starting y
  2039. ystart = min_clip_y;
  2040. } // end if
  2041. else
  2042. {
  2043. // no clipping
  2044. // set starting values
  2045. xl = (x0 << FIXP16_SHIFT);
  2046. xr = (x1 << FIXP16_SHIFT);
  2047. ul = (tu0 << FIXP16_SHIFT);
  2048. vl = (tv0 << FIXP16_SHIFT);
  2049. wl = (tw0 << FIXP16_SHIFT);
  2050. ur = (tu1 << FIXP16_SHIFT);
  2051. vr = (tv1 << FIXP16_SHIFT);
  2052. wr = (tw1 << FIXP16_SHIFT);
  2053. // set starting y
  2054. ystart = y0;
  2055. } // end else
  2056. } // end if flat top
  2057. else
  2058. {
  2059. // must be flat bottom
  2060. // compute all deltas
  2061. dy = (y1 - y0);
  2062. dxdyl = ((x1 - x0)   << FIXP16_SHIFT)/dy;
  2063. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dy;  
  2064. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dy;    
  2065. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dy; 
  2066. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  2067. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  2068. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dy;   
  2069. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dy;   
  2070. // test for y clipping
  2071. if (y0 < min_clip_y)
  2072. {
  2073. // compute overclip
  2074. dy = (min_clip_y - y0);
  2075. // computer new LHS starting values
  2076. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  2077. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  2078. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  2079. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  2080. // compute new RHS starting values
  2081. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  2082. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  2083. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  2084. wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
  2085. // compute new starting y
  2086. ystart = min_clip_y;
  2087. } // end if
  2088. else
  2089. {
  2090. // no clipping
  2091. // set starting values
  2092. xl = (x0 << FIXP16_SHIFT);
  2093. xr = (x0 << FIXP16_SHIFT);
  2094. ul = (tu0 << FIXP16_SHIFT);
  2095. vl = (tv0 << FIXP16_SHIFT);
  2096. wl = (tw0 << FIXP16_SHIFT);
  2097. ur = (tu0 << FIXP16_SHIFT);
  2098. vr = (tv0 << FIXP16_SHIFT);
  2099. wr = (tw0 << FIXP16_SHIFT);
  2100. // set starting y
  2101. ystart = y0;
  2102. } // end else
  2103. } // end else flat bottom
  2104. // test for bottom clip, always
  2105. if ((yend = y2) > max_clip_y)
  2106. yend = max_clip_y;
  2107.     // test for horizontal clipping
  2108. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  2109. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  2110. (x2 < min_clip_x) || (x2 > max_clip_x))
  2111. {
  2112.     // clip version
  2113. // point screen ptr to starting line
  2114. screen_ptr = dest_buffer + (ystart * mem_pitch);
  2115. for (yi = ystart; yi<=yend; yi++)
  2116. {
  2117. // compute span endpoints
  2118. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2119. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2120. // compute starting points for u,v,w interpolants
  2121. ui = ul + FIXP16_ROUND_UP;
  2122. vi = vl + FIXP16_ROUND_UP;
  2123. wi = wl + FIXP16_ROUND_UP;
  2124. // compute u,v interpolants
  2125. if ((dx = (xend - xstart))>0)
  2126. {
  2127. du = (ur - ul)/dx;
  2128. dv = (vr - vl)/dx;
  2129. dw = (wr - wl)/dx;
  2130. } // end if
  2131. else
  2132. {
  2133. du = (ur - ul);
  2134. dv = (vr - vl);
  2135. dw = (wr - wl);
  2136. } // end else
  2137. ///////////////////////////////////////////////////////////////////////
  2138. // test for x clipping, LHS
  2139. if (xstart < min_clip_x)
  2140. {
  2141. // compute x overlap
  2142. dx = min_clip_x - xstart;
  2143. // slide interpolants over
  2144. ui+=dx*du;
  2145. vi+=dx*dv;
  2146. wi+=dx*dw;
  2147. // reset vars
  2148. xstart = min_clip_x;
  2149. } // end if
  2150. // test for x clipping RHS
  2151. if (xend > max_clip_x)
  2152. xend = max_clip_x;
  2153. ///////////////////////////////////////////////////////////////////////
  2154. // draw span
  2155. for (xi=xstart; xi<=xend; xi++)
  2156. {
  2157. // write textel assume 5.6.5
  2158.         screen_ptr[xi] = rgblookup[( ((ui >> (FIXP16_SHIFT+3)) << 11) + 
  2159.                                          ((vi >> (FIXP16_SHIFT+2)) << 5) + 
  2160.                                           (wi >> (FIXP16_SHIFT+3)) ) ];   
  2161. // interpolate u,v
  2162. ui+=du;
  2163. vi+=dv;
  2164. wi+=dw;
  2165. } // end for xi
  2166. // interpolate u,v,w,x along right and left edge
  2167. xl+=dxdyl;
  2168. ul+=dudyl;
  2169. vl+=dvdyl;
  2170. wl+=dwdyl;
  2171. xr+=dxdyr;
  2172. ur+=dudyr;
  2173. vr+=dvdyr;
  2174. wr+=dwdyr;
  2175.  
  2176. // advance screen ptr
  2177. screen_ptr+=mem_pitch;
  2178. } // end for y
  2179. } // end if clip
  2180. else
  2181. {
  2182. // non-clip version
  2183. // point screen ptr to starting line
  2184. screen_ptr = dest_buffer + (ystart * mem_pitch);
  2185. for (yi = ystart; yi<=yend; yi++)
  2186. {
  2187. // compute span endpoints
  2188. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2189. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2190. // compute starting points for u,v,w interpolants
  2191. ui = ul + FIXP16_ROUND_UP;
  2192. vi = vl + FIXP16_ROUND_UP;
  2193. wi = wl + FIXP16_ROUND_UP;
  2194. // compute u,v interpolants
  2195. if ((dx = (xend - xstart))>0)
  2196. {
  2197. du = (ur - ul)/dx;
  2198. dv = (vr - vl)/dx;
  2199. dw = (wr - wl)/dx;
  2200. } // end if
  2201. else
  2202. {
  2203. du = (ur - ul);
  2204. dv = (vr - vl);
  2205. dw = (wr - wl);
  2206. } // end else
  2207. // draw span
  2208. for (xi=xstart; xi<=xend; xi++)
  2209. {
  2210. // write textel 5.6.5
  2211.             screen_ptr[xi] = rgblookup[( ((ui >> (FIXP16_SHIFT+3)) << 11) + 
  2212.                                          ((vi >> (FIXP16_SHIFT+2)) << 5) + 
  2213.                                           (wi >> (FIXP16_SHIFT+3)) ) ];   
  2214. // interpolate u,v
  2215. ui+=du;
  2216. vi+=dv;
  2217. wi+=dw;
  2218. } // end for xi
  2219. // interpolate u,v,w,x along right and left edge
  2220. xl+=dxdyl;
  2221. ul+=dudyl;
  2222. vl+=dvdyl;
  2223. wl+=dwdyl;
  2224. xr+=dxdyr;
  2225. ur+=dudyr;
  2226. vr+=dvdyr;
  2227. wr+=dwdyr;
  2228. // advance screen ptr
  2229. screen_ptr+=mem_pitch;
  2230. } // end for y
  2231. } // end if non-clipped
  2232. } // end if
  2233. else
  2234. if (tri_type==TRI_TYPE_GENERAL)
  2235. {
  2236. // first test for bottom clip, always
  2237. if ((yend = y2) > max_clip_y)
  2238. yend = max_clip_y;
  2239. // pre-test y clipping status
  2240. if (y1 < min_clip_y)
  2241. {
  2242. // compute all deltas
  2243. // LHS
  2244. dyl = (y2 - y1);
  2245. dxdyl = ((x2  - x1)  << FIXP16_SHIFT)/dyl;
  2246. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  2247. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;    
  2248. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;  
  2249. // RHS
  2250. dyr = (y2 - y0);
  2251. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  2252. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  2253. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  2254. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;   
  2255. // compute overclip
  2256. dyr = (min_clip_y - y0);
  2257. dyl = (min_clip_y - y1);
  2258. // computer new LHS starting values
  2259. xl = dxdyl*dyl + (x1  << FIXP16_SHIFT);
  2260. ul = dudyl*dyl + (tu1 << FIXP16_SHIFT);
  2261. vl = dvdyl*dyl + (tv1 << FIXP16_SHIFT);
  2262. wl = dwdyl*dyl + (tw1 << FIXP16_SHIFT);
  2263. // compute new RHS starting values
  2264. xr = dxdyr*dyr + (x0  << FIXP16_SHIFT);
  2265. ur = dudyr*dyr + (tu0 << FIXP16_SHIFT);
  2266. vr = dvdyr*dyr + (tv0 << FIXP16_SHIFT);
  2267. wr = dwdyr*dyr + (tw0 << FIXP16_SHIFT);
  2268. // compute new starting y
  2269. ystart = min_clip_y;
  2270. // test if we need swap to keep rendering left to right
  2271. if (dxdyr > dxdyl)
  2272. {
  2273. SWAP(dxdyl,dxdyr,temp);
  2274. SWAP(dudyl,dudyr,temp);
  2275. SWAP(dvdyl,dvdyr,temp);
  2276. SWAP(dwdyl,dwdyr,temp);
  2277. SWAP(xl,xr,temp);
  2278. SWAP(ul,ur,temp);
  2279. SWAP(vl,vr,temp);
  2280. SWAP(wl,wr,temp);
  2281. SWAP(x1,x2,temp);
  2282. SWAP(y1,y2,temp);
  2283. SWAP(tu1,tu2,temp);
  2284. SWAP(tv1,tv2,temp);
  2285. SWAP(tw1,tw2,temp);
  2286. // set interpolation restart
  2287. irestart = INTERP_RHS;
  2288. } // end if
  2289. } // end if
  2290. else
  2291. if (y0 < min_clip_y)
  2292. {
  2293. // compute all deltas
  2294. // LHS
  2295. dyl = (y1 - y0);
  2296. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  2297. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  2298. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  2299. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dyl; 
  2300. // RHS
  2301. dyr = (y2 - y0);
  2302. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  2303. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  2304. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  2305. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;   
  2306. // compute overclip
  2307. dy = (min_clip_y - y0);
  2308. // computer new LHS starting values
  2309. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  2310. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  2311. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  2312. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  2313. // compute new RHS starting values
  2314. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  2315. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  2316. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  2317. wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
  2318. // compute new starting y
  2319. ystart = min_clip_y;
  2320. // test if we need swap to keep rendering left to right
  2321. if (dxdyr < dxdyl)
  2322. {
  2323. SWAP(dxdyl,dxdyr,temp);
  2324. SWAP(dudyl,dudyr,temp);
  2325. SWAP(dvdyl,dvdyr,temp);
  2326. SWAP(dwdyl,dwdyr,temp);
  2327. SWAP(xl,xr,temp);
  2328. SWAP(ul,ur,temp);
  2329. SWAP(vl,vr,temp);
  2330. SWAP(wl,wr,temp);
  2331. SWAP(x1,x2,temp);
  2332. SWAP(y1,y2,temp);
  2333. SWAP(tu1,tu2,temp);
  2334. SWAP(tv1,tv2,temp);
  2335. SWAP(tw1,tw2,temp);
  2336. // set interpolation restart
  2337. irestart = INTERP_RHS;
  2338. } // end if
  2339. } // end if
  2340. else
  2341. {
  2342. // no initial y clipping
  2343. // compute all deltas
  2344. // LHS
  2345. dyl = (y1 - y0);
  2346. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  2347. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  2348. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  2349. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dyl;   
  2350. // RHS
  2351. dyr = (y2 - y0);
  2352. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dyr;
  2353. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  2354. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  2355. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;
  2356. // no clipping y
  2357. // set starting values
  2358. xl = (x0 << FIXP16_SHIFT);
  2359. xr = (x0 << FIXP16_SHIFT);
  2360. ul = (tu0 << FIXP16_SHIFT);
  2361. vl = (tv0 << FIXP16_SHIFT);
  2362. wl = (tw0 << FIXP16_SHIFT);
  2363. ur = (tu0 << FIXP16_SHIFT);
  2364. vr = (tv0 << FIXP16_SHIFT);
  2365. wr = (tw0 << FIXP16_SHIFT);
  2366. // set starting y
  2367. ystart = y0;
  2368. // test if we need swap to keep rendering left to right
  2369. if (dxdyr < dxdyl)
  2370. {
  2371. SWAP(dxdyl,dxdyr,temp);
  2372. SWAP(dudyl,dudyr,temp);
  2373. SWAP(dvdyl,dvdyr,temp);
  2374. SWAP(dwdyl,dwdyr,temp);
  2375. SWAP(xl,xr,temp);
  2376. SWAP(ul,ur,temp);
  2377. SWAP(vl,vr,temp);
  2378. SWAP(wl,wr,temp);
  2379. SWAP(x1,x2,temp);
  2380. SWAP(y1,y2,temp);
  2381. SWAP(tu1,tu2,temp);
  2382. SWAP(tv1,tv2,temp);
  2383. SWAP(tw1,tw2,temp);
  2384. // set interpolation restart
  2385. irestart = INTERP_RHS;
  2386. } // end if
  2387. } // end else
  2388.     // test for horizontal clipping
  2389. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  2390. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  2391. (x2 < min_clip_x) || (x2 > max_clip_x))
  2392. {
  2393.     // clip version
  2394. // x clipping
  2395. // point screen ptr to starting line
  2396. screen_ptr = dest_buffer + (ystart * mem_pitch);
  2397. for (yi = ystart; yi<=yend; yi++)
  2398. {
  2399. // compute span endpoints
  2400. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2401. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2402. // compute starting points for u,v,w interpolants
  2403. ui = ul + FIXP16_ROUND_UP;
  2404. vi = vl + FIXP16_ROUND_UP;
  2405. wi = wl + FIXP16_ROUND_UP;
  2406. // compute u,v interpolants
  2407. if ((dx = (xend - xstart))>0)
  2408. {
  2409. du = (ur - ul)/dx;
  2410. dv = (vr - vl)/dx;
  2411. dw = (wr - wl)/dx;
  2412. } // end if
  2413. else
  2414. {
  2415. du = (ur - ul);
  2416. dv = (vr - vl);
  2417. dw = (wr - wl);
  2418. } // end else
  2419. ///////////////////////////////////////////////////////////////////////
  2420. // test for x clipping, LHS
  2421. if (xstart < min_clip_x)
  2422. {
  2423. // compute x overlap
  2424. dx = min_clip_x - xstart;
  2425. // slide interpolants over
  2426. ui+=dx*du;
  2427. vi+=dx*dv;
  2428. wi+=dx*dw;
  2429. // set x to left clip edge
  2430. xstart = min_clip_x;
  2431. } // end if
  2432. // test for x clipping RHS
  2433. if (xend > max_clip_x)
  2434. xend = max_clip_x;
  2435. ///////////////////////////////////////////////////////////////////////
  2436. // draw span
  2437. for (xi=xstart; xi<=xend; xi++)
  2438. {
  2439. // write textel assume 5.6.5
  2440.         screen_ptr[xi] = rgblookup[( ((ui >> (FIXP16_SHIFT+3)) << 11) + 
  2441.                                          ((vi >> (FIXP16_SHIFT+2)) << 5) + 
  2442.                                           (wi >> (FIXP16_SHIFT+3)) ) ];   
  2443. // interpolate u,v
  2444. ui+=du;
  2445. vi+=dv;
  2446. wi+=dw;
  2447. } // end for xi
  2448. // interpolate u,v,w,x along right and left edge
  2449. xl+=dxdyl;
  2450.         ul+=dudyl;
  2451. vl+=dvdyl;
  2452. wl+=dwdyl;
  2453. xr+=dxdyr;
  2454.       ur+=dudyr;
  2455. vr+=dvdyr;
  2456. wr+=dwdyr;
  2457. // advance screen ptr
  2458. screen_ptr+=mem_pitch;
  2459. // test for yi hitting second region, if so change interpolant
  2460. if (yi==yrestart)
  2461. {
  2462.     // test interpolation side change flag
  2463. if (irestart == INTERP_LHS)
  2464. {
  2465. // LHS
  2466. dyl = (y2 - y1);
  2467. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  2468. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  2469. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  2470. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;  
  2471. // set starting values
  2472. xl = (x1  << FIXP16_SHIFT);
  2473. ul = (tu1 << FIXP16_SHIFT);
  2474. vl = (tv1 << FIXP16_SHIFT);
  2475. wl = (tw1 << FIXP16_SHIFT);
  2476. // interpolate down on LHS to even up
  2477. xl+=dxdyl;
  2478. ul+=dudyl;
  2479. vl+=dvdyl;
  2480. wl+=dwdyl;
  2481. } // end if
  2482. else
  2483. {
  2484. // RHS
  2485. dyr = (y1 - y2);
  2486. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  2487. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  2488. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  2489. dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;   
  2490. // set starting values
  2491. xr = (x2  << FIXP16_SHIFT);
  2492. ur = (tu2 << FIXP16_SHIFT);
  2493. vr = (tv2 << FIXP16_SHIFT);
  2494. wr = (tw2 << FIXP16_SHIFT);
  2495. // interpolate down on RHS to even up
  2496. xr+=dxdyr;
  2497. ur+=dudyr;
  2498. vr+=dvdyr;
  2499. wr+=dwdyr;
  2500. } // end else
  2501. } // end if
  2502. } // end for y
  2503. } // end if
  2504. else
  2505. {
  2506. // no x clipping
  2507. // point screen ptr to starting line
  2508. screen_ptr = dest_buffer + (ystart * mem_pitch);
  2509. for (yi = ystart; yi<=yend; yi++)
  2510. {
  2511. // compute span endpoints
  2512. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2513. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2514. // compute starting points for u,v,w interpolants
  2515. ui = ul + FIXP16_ROUND_UP;
  2516. vi = vl + FIXP16_ROUND_UP;
  2517. wi = wl + FIXP16_ROUND_UP;
  2518. // compute u,v interpolants
  2519. if ((dx = (xend - xstart))>0)
  2520. {
  2521. du = (ur - ul)/dx;
  2522. dv = (vr - vl)/dx;
  2523. dw = (wr - wl)/dx;
  2524. } // end if
  2525. else
  2526. {
  2527. du = (ur - ul);
  2528. dv = (vr - vl);
  2529. dw = (wr - wl);
  2530. } // end else
  2531. // draw span
  2532. for (xi=xstart; xi<=xend; xi++)
  2533. {
  2534. // write textel assume 5.6.5
  2535.         screen_ptr[xi] = rgblookup[( ((ui >> (FIXP16_SHIFT+3)) << 11) + 
  2536.                                          ((vi >> (FIXP16_SHIFT+2)) << 5) + 
  2537.                                           (wi >> (FIXP16_SHIFT+3)) ) ];   
  2538. // interpolate u,v
  2539. ui+=du;
  2540. vi+=dv;
  2541. wi+=dw;
  2542. } // end for xi
  2543. // interpolate u,v,w,x along right and left edge
  2544. xl+=dxdyl;
  2545. ul+=dudyl;
  2546. vl+=dvdyl;
  2547. wl+=dwdyl;
  2548. xr+=dxdyr;
  2549. ur+=dudyr;
  2550. vr+=dvdyr;
  2551. wr+=dwdyr;
  2552. // advance screen ptr
  2553. screen_ptr+=mem_pitch;
  2554. // test for yi hitting second region, if so change interpolant
  2555. if (yi==yrestart)
  2556. {
  2557. // test interpolation side change flag
  2558. if (irestart == INTERP_LHS)
  2559. {
  2560. // LHS
  2561. dyl = (y2 - y1);
  2562. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  2563. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  2564. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  2565. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;   
  2566. // set starting values
  2567. xl = (x1  << FIXP16_SHIFT);
  2568. ul = (tu1 << FIXP16_SHIFT);
  2569. vl = (tv1 << FIXP16_SHIFT);
  2570. wl = (tw1 << FIXP16_SHIFT);
  2571. // interpolate down on LHS to even up
  2572. xl+=dxdyl;
  2573. ul+=dudyl;
  2574. vl+=dvdyl;
  2575. wl+=dwdyl;
  2576. } // end if
  2577. else
  2578. {
  2579. // RHS
  2580. dyr = (y1 - y2);
  2581. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  2582. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  2583. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  2584. dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;   
  2585. // set starting values
  2586. xr = (x2  << FIXP16_SHIFT);
  2587. ur = (tu2 << FIXP16_SHIFT);
  2588. vr = (tv2 << FIXP16_SHIFT);
  2589. wr = (tw2 << FIXP16_SHIFT);
  2590. // interpolate down on RHS to even up
  2591. xr+=dxdyr;
  2592. ur+=dudyr;
  2593. vr+=dvdyr;
  2594. wr+=dwdyr;
  2595. } // end else
  2596. } // end if
  2597. } // end for y
  2598.    } // end else
  2599. } // end if
  2600. } // end Draw_Gouraud_Triangle
  2601. ///////////////////////////////////////////////////////////////////////////////
  2602. int RGB_12_8_Lighting_Table_Builder(LPPALETTEENTRY src_palette,       // source palette
  2603.                                     UCHAR rgblookup[4096][256])  // lookup table
  2604. {
  2605. // this function creates a lighting table used for 8-bit lighting inside the
  2606. // texture mapping function, what we need is a table that for every possible
  2607. // light color and textel color outputs the textel index that is the closest
  2608. // match for the given color modulation, however, that would be 256*65536 = 16.7 megs!
  2609. // a little excessive, thus, we will scale the incoming light value down to 4.4.4
  2610. // format, or only 16 different intensities per channel, or a total of 12 bits,
  2611. // now we will only need 256*2^12 = 1meg which is reasonable for the speed gain
  2612. // additionally, the table is going to be 2d, where the row is the intensity
  2613. // and the column is the color, this format is more effective since tables are
  2614. // stored in row-major form, and since we are shading flat shaded polys with
  2615. // texture, we know the texture color will change during the calculations,
  2616. // but not the light color, thus, the cache coherence will be excellent if we access
  2617. // elements in the form rgblookup[RGBcolor.12bit][textel index.8bit]
  2618. // finally, it's up to the caller to send in the rgblookup pre-allocated
  2619. // here it goes...
  2620. // first check the pointers
  2621. if (!src_palette || !rgblookup)
  2622.    return(-1);
  2623. // there are 4096 RGB values we need to compute, assuming that we are in RGB: 4.4.4  format
  2624. for (int rgbindex = 0; rgbindex < 4096; rgbindex++)
  2625.     {
  2626.     // for each RGB color 0..4095 we need to multiple by each palette entry 0..255
  2627.     // and then scan for the closest match, lots of loops!!!!
  2628.     for (int color_index = 0; color_index < 256; color_index++)
  2629.         {
  2630.         int  curr_index  = -1;        // current color index of best match
  2631.         long curr_error  = INT_MAX;    // distance in color space to nearest match or "error"
  2632.         // extract r,g,b from rgbindex, assuming an encoding of 4.4.4
  2633.         int r = (rgbindex >> 8);
  2634.         int g = ((rgbindex >> 4) & 0x0f);
  2635.         int b = (rgbindex & 0x0f);
  2636.         // now the final target is this r,g,b value which is simulating the light source
  2637.         // multiplied by the textel color, that IS our target...
  2638.         // modulate values together, make sure results stay in 0..255, so divide results
  2639.         // by 15 since the r,g,b values were normalized to 15 rather than 1.0
  2640.         r = (int)(( (float)r * (float)src_palette[color_index].peRed)   / 15);
  2641.         g = (int)(( (float)g * (float)src_palette[color_index].peGreen) / 15);
  2642.         b = (int)(( (float)b * (float)src_palette[color_index].peBlue)  / 15);
  2643.         
  2644.         // now scan palette to find this color
  2645.         for (int color_scan = 0; color_scan < 256; color_scan++)
  2646.             {
  2647.             // compute distance to color from target
  2648.             long delta_red   = abs(src_palette[color_scan].peRed   - r);
  2649.             long delta_green = abs(src_palette[color_scan].peGreen - g);
  2650.             long delta_blue  = abs(src_palette[color_scan].peBlue  - b);
  2651.             long error = (delta_red*delta_red) + (delta_green*delta_green) + (delta_blue*delta_blue);
  2652.    
  2653.             // is this color a better match?
  2654.             if (error < curr_error)
  2655.                { 
  2656.                curr_index = color_scan;
  2657.                curr_error = error;   
  2658.                } // end if
  2659.             } // end for color_scan
  2660.            // best match has been found, enter it into table
  2661.            rgblookup[rgbindex][color_index] = curr_index;   
  2662.          } // end for color_index
  2663.    } // end for rgbindex
  2664. // return success
  2665. return(1);
  2666. } // end RGB_12_8_Lighting_Table_Builder
  2667. ///////////////////////////////////////////////////////////////////////////////
  2668. // OBSOLETE and TEST FUNCTIONS ////////////////////////////////////////////////
  2669. ///////////////////////////////////////////////////////////////////////////////
  2670. void Draw_RENDERLIST4DV1_Solid2_16(RENDERLIST4DV1_PTR rend_list, 
  2671.                                 UCHAR *video_buffer, int lpitch)
  2672. {
  2673. // this function "executes" the render list or in other words
  2674. // draws all the faces in the list in wire frame 16bit mode
  2675. // note there is no need to sort wire frame polygons, but 
  2676. // later we will need to, so hidden surfaces stay hidden
  2677. // also, we leave it to the function to determine the bitdepth
  2678. // and call the correct rasterizer
  2679. // at this point, all we have is a list of polygons and it's time
  2680. // to draw them
  2681. for (int poly=0; poly < rend_list->num_polys; poly++)
  2682.     {
  2683.     // render this polygon if and only if it's not clipped, not culled,
  2684.     // active, and visible, note however the concecpt of "backface" is 
  2685.     // irrelevant in a wire frame engine though
  2686.     if (!(rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_ACTIVE) ||
  2687.          (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_CLIPPED ) ||
  2688.          (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_BACKFACE) )
  2689.        continue; // move onto next poly
  2690.     // draw the triangle
  2691.     Draw_Triangle_2D2_16(rend_list->poly_ptrs[poly]->tvlist[0].x, rend_list->poly_ptrs[poly]->tvlist[0].y,
  2692.                  rend_list->poly_ptrs[poly]->tvlist[1].x, rend_list->poly_ptrs[poly]->tvlist[1].y,
  2693.              rend_list->poly_ptrs[poly]->tvlist[2].x, rend_list->poly_ptrs[poly]->tvlist[2].y,
  2694.                  rend_list->poly_ptrs[poly]->color, video_buffer, lpitch);
  2695.     } // end for poly
  2696. } // end Draw_RENDERLIST4DV1_Solid2_16
  2697. //////////////////////////////////////////////////////////////////////////////////////
  2698. void Draw_OBJECT4DV1_Solid2(OBJECT4DV1_PTR obj, 
  2699.                           UCHAR *video_buffer, int lpitch)
  2700.                      
  2701. {
  2702. // this function renders an object to the screen in solid, 
  2703. // 8 bit mode, it has no regard at all about hidden surface removal, 
  2704. // etc. the function only exists as an easy way to render an object 
  2705. // without converting it into polygons, the function assumes all 
  2706. // coordinates are screen coordinates, but will perform 2D clipping
  2707. // iterate thru the poly list of the object and simply draw
  2708. // each polygon
  2709. for (int poly=0; poly < obj->num_polys; poly++)
  2710.     {
  2711.     // render this polygon if and only if it's not clipped, not culled,
  2712.     // active, and visible, note however the concecpt of "backface" is 
  2713.     // irrelevant in a wire frame engine though
  2714.     if (!(obj->plist[poly].state & POLY4DV1_STATE_ACTIVE) ||
  2715.          (obj->plist[poly].state & POLY4DV1_STATE_CLIPPED ) ||
  2716.          (obj->plist[poly].state & POLY4DV1_STATE_BACKFACE) )
  2717.        continue; // move onto next poly
  2718.     
  2719.     // extract vertex indices into master list, rember the polygons are 
  2720.     // NOT self contained, but based on the vertex list stored in the object
  2721.     // itself
  2722.     int vindex_0 = obj->plist[poly].vert[0];
  2723.     int vindex_1 = obj->plist[poly].vert[1];
  2724.     int vindex_2 = obj->plist[poly].vert[2];
  2725.     // draw the triangle
  2726.     Draw_Triangle_2D2(obj->vlist_trans[ vindex_0 ].x, obj->vlist_trans[ vindex_0 ].y,
  2727.              obj->vlist_trans[ vindex_1 ].x, obj->vlist_trans[ vindex_1 ].y,
  2728.              obj->vlist_trans[ vindex_2 ].x, obj->vlist_trans[ vindex_2 ].y,
  2729.              obj->plist[poly].color, video_buffer, lpitch);
  2730.     } // end for poly
  2731. } // end Draw_OBJECT4DV1_Solid2
  2732. ///////////////////////////////////////////////////////////////
  2733. void Draw_RENDERLIST4DV1_Solid2(RENDERLIST4DV1_PTR rend_list, 
  2734.                               UCHAR *video_buffer, int lpitch)
  2735. {
  2736. // this function "executes" the render list or in other words
  2737. // draws all the faces in the list in wire frame 8bit mode
  2738. // note there is no need to sort wire frame polygons, but 
  2739. // later we will need to, so hidden surfaces stay hidden
  2740. // also, we leave it to the function to determine the bitdepth
  2741. // and call the correct rasterizer
  2742. // at this point, all we have is a list of polygons and it's time
  2743. // to draw them
  2744. for (int poly=0; poly < rend_list->num_polys; poly++)
  2745.     {
  2746.     // render this polygon if and only if it's not clipped, not culled,
  2747.     // active, and visible, note however the concecpt of "backface" is 
  2748.     // irrelevant in a wire frame engine though
  2749.     if (!(rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_ACTIVE) ||
  2750.          (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_CLIPPED ) ||
  2751.          (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_BACKFACE) )
  2752.        continue; // move onto next poly
  2753.     // draw the triangle
  2754.     Draw_Triangle_2D2(rend_list->poly_ptrs[poly]->tvlist[0].x, rend_list->poly_ptrs[poly]->tvlist[0].y,
  2755.              rend_list->poly_ptrs[poly]->tvlist[1].x, rend_list->poly_ptrs[poly]->tvlist[1].y,
  2756.          rend_list->poly_ptrs[poly]->tvlist[2].x, rend_list->poly_ptrs[poly]->tvlist[2].y,
  2757.              rend_list->poly_ptrs[poly]->color, video_buffer, lpitch);
  2758.     } // end for poly
  2759. } // end Draw_RENDERLIST4DV1_Solid2
  2760. /////////////////////////////////////////////////////////////
  2761. void Draw_OBJECT4DV1_Solid2_16(OBJECT4DV1_PTR obj, 
  2762.                             UCHAR *video_buffer, int lpitch)
  2763.                      
  2764. {
  2765. // this function renders an object to the screen in wireframe, 
  2766. // 16 bit mode, it has no regard at all about hidden surface removal, 
  2767. // etc. the function only exists as an easy way to render an object 
  2768. // without converting it into polygons, the function assumes all 
  2769. // coordinates are screen coordinates, but will perform 2D clipping
  2770. // iterate thru the poly list of the object and simply draw
  2771. // each polygon
  2772. for (int poly=0; poly < obj->num_polys; poly++)
  2773.     {
  2774.     // render this polygon if and only if it's not clipped, not culled,
  2775.     // active, and visible, note however the concecpt of "backface" is 
  2776.     // irrelevant in a wire frame engine though
  2777.     if (!(obj->plist[poly].state & POLY4DV1_STATE_ACTIVE) ||
  2778.          (obj->plist[poly].state & POLY4DV1_STATE_CLIPPED ) ||
  2779.          (obj->plist[poly].state & POLY4DV1_STATE_BACKFACE) )
  2780.        continue; // move onto next poly
  2781.     
  2782.     // extract vertex indices into master list, rember the polygons are 
  2783.     // NOT self contained, but based on the vertex list stored in the object
  2784.     // itself
  2785.     int vindex_0 = obj->plist[poly].vert[0];
  2786.     int vindex_1 = obj->plist[poly].vert[1];
  2787.     int vindex_2 = obj->plist[poly].vert[2];
  2788.     
  2789.     // draw the triangle
  2790.     Draw_Triangle_2D2_16(obj->vlist_trans[ vindex_0 ].x, obj->vlist_trans[ vindex_0 ].y,
  2791.                obj->vlist_trans[ vindex_1 ].x, obj->vlist_trans[ vindex_1 ].y,
  2792.                obj->vlist_trans[ vindex_2 ].x, obj->vlist_trans[ vindex_2 ].y,
  2793.                obj->plist[poly].color, video_buffer, lpitch);
  2794.     } // end for poly
  2795. } // end Draw_OBJECT4DV1_Solid2_16
  2796. ///////////////////////////////////////////////////////////////////////////
  2797. void Draw_RENDERLIST4DV2_Textured(RENDERLIST4DV2_PTR rend_list, 
  2798.                               UCHAR *video_buffer, 
  2799.   int lpitch, 
  2800.   BITMAP_IMAGE_PTR texture)
  2801. {
  2802. // TEST FUNCTION ONLY!!!
  2803. POLYF4DV2 face; // temp face used to render polygon
  2804. // at this point, all we have is a list of polygons and it's time
  2805. // to draw them
  2806. for (int poly=0; poly < rend_list->num_polys; poly++)
  2807.     {
  2808.     // render this polygon if and only if it's not clipped, not culled,
  2809.     // active, and visible, note however the concecpt of "backface" is 
  2810.     // irrelevant in a wire frame engine though
  2811.     if (!(rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_ACTIVE) ||
  2812.          (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_CLIPPED ) ||
  2813.          (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_BACKFACE) )
  2814.        continue; // move onto next poly
  2815.     // set the vertices
  2816.     face.tvlist[0].x = (int)rend_list->poly_ptrs[poly]->tvlist[0].x;
  2817.     face.tvlist[0].y = (int)rend_list->poly_ptrs[poly]->tvlist[0].y;
  2818.     face.tvlist[0].u0 = 0;
  2819.     face.tvlist[0].v0 = 0;
  2820.     face.tvlist[1].x = (int)rend_list->poly_ptrs[poly]->tvlist[1].x;
  2821.     face.tvlist[1].y = (int)rend_list->poly_ptrs[poly]->tvlist[1].y;
  2822.     face.tvlist[1].u0 = 0;
  2823.     face.tvlist[1].v0 = 63;
  2824.     face.tvlist[2].x = (int)rend_list->poly_ptrs[poly]->tvlist[2].x;
  2825.     face.tvlist[2].y = (int)rend_list->poly_ptrs[poly]->tvlist[2].y;
  2826.     face.tvlist[2].u0 = 63;
  2827.     face.tvlist[2].v0 = 63;
  2828.     // assign the texture
  2829.     face.texture = texture;
  2830. // draw the textured triangle
  2831.     Draw_Textured_Triangle(&face, video_buffer, lpitch);
  2832.     } // end for poly
  2833. } // end Draw_RENDERLIST4DV2_Textured
  2834. ///////////////////////////////////////////////////////////////////////////
  2835. void Draw_RENDERLIST4DV2_Textured16(RENDERLIST4DV2_PTR rend_list, 
  2836.                               UCHAR *video_buffer, 
  2837.   int lpitch, 
  2838.   BITMAP_IMAGE_PTR texture)
  2839. {
  2840. // TEST FUNCTION ONLY!!!!
  2841. POLYF4DV2 face; // temp face used to render polygon
  2842. // at this point, all we have is a list of polygons and it's time
  2843. // to draw them
  2844. for (int poly=0; poly < rend_list->num_polys; poly++)
  2845.     {
  2846.     // render this polygon if and only if it's not clipped, not culled,
  2847.     // active, and visible, note however the concecpt of "backface" is 
  2848.     // irrelevant in a wire frame engine though
  2849.     if (!(rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_ACTIVE) ||
  2850.          (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_CLIPPED ) ||
  2851.          (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_BACKFACE) )
  2852.        continue; // move onto next poly
  2853.     // set the vertices
  2854.     face.tvlist[0].x = (int)rend_list->poly_ptrs[poly]->tvlist[0].x;
  2855.     face.tvlist[0].y = (int)rend_list->poly_ptrs[poly]->tvlist[0].y;
  2856.     face.tvlist[0].u0 = 0;
  2857.     face.tvlist[0].v0 = 0;
  2858.     face.tvlist[1].x = (int)rend_list->poly_ptrs[poly]->tvlist[1].x;
  2859.     face.tvlist[1].y = (int)rend_list->poly_ptrs[poly]->tvlist[1].y;
  2860.     face.tvlist[1].u0 = 0;
  2861.     face.tvlist[1].v0 = 63;
  2862.     face.tvlist[2].x = (int)rend_list->poly_ptrs[poly]->tvlist[2].x;
  2863.     face.tvlist[2].y = (int)rend_list->poly_ptrs[poly]->tvlist[2].y;
  2864.     face.tvlist[2].u0 = 63;
  2865.     face.tvlist[2].v0 = 63;
  2866.     // assign the texture
  2867.     face.texture = texture;
  2868. // draw the textured triangle
  2869.     Draw_Textured_Triangle16(&face, video_buffer, lpitch);
  2870.     } // end for poly
  2871. } // end Draw_RENDERLIST4DV2_Textured16
  2872. /////////////////////////////////////////////////////////////////////////
  2873. void Draw_OBJECT4DV1_Textured(OBJECT4DV1_PTR obj, 
  2874.                               UCHAR *video_buffer, int lpitch)
  2875.                      
  2876. {
  2877. // TEST FUNCTION ONLY!!!
  2878. // iterate thru the poly list of the object and simply draw
  2879. // each polygon
  2880. for (int poly=0; poly < obj->num_polys; poly++)
  2881.     {
  2882.     // render this polygon if and only if it's not clipped, not culled,
  2883.     // active, and visible, note however the concecpt of "backface" is 
  2884.     // irrelevant in a wire frame engine though
  2885.     if (!(obj->plist[poly].state & POLY4DV1_STATE_ACTIVE) ||
  2886.          (obj->plist[poly].state & POLY4DV1_STATE_CLIPPED ) ||
  2887.          (obj->plist[poly].state & POLY4DV1_STATE_BACKFACE) )
  2888.        continue; // move onto next poly
  2889.     
  2890.     // extract vertex indices into master list, rember the polygons are 
  2891.     // NOT self contained, but based on the vertex list stored in the object
  2892.     // itself
  2893.     int vindex_0 = obj->plist[poly].vert[0];
  2894.     int vindex_1 = obj->plist[poly].vert[1];
  2895.     int vindex_2 = obj->plist[poly].vert[2];
  2896.     // draw the triangle
  2897.     Draw_Triangle_2D(obj->vlist_trans[ vindex_0 ].x, obj->vlist_trans[ vindex_0 ].y,
  2898.              obj->vlist_trans[ vindex_1 ].x, obj->vlist_trans[ vindex_1 ].y,
  2899.              obj->vlist_trans[ vindex_2 ].x, obj->vlist_trans[ vindex_2 ].y,
  2900.              obj->plist[poly].color, video_buffer, lpitch);
  2901.     } // end for poly
  2902. } // end Draw_OBJECT4DV1_Textured
  2903. ///////////////////////////////////////////////////////////////
  2904. void Draw_RENDERLIST4DV1_Textured(RENDERLIST4DV1_PTR rend_list, 
  2905.                               UCHAR *video_buffer, 
  2906.   int lpitch, 
  2907.   BITMAP_IMAGE_PTR texture)
  2908. {
  2909. // TEST FUNCTION
  2910. POLYF4DV2 face; // temp face used to render polygon
  2911. // at this point, all we have is a list of polygons and it's time
  2912. // to draw them
  2913. for (int poly=0; poly < rend_list->num_polys; poly++)
  2914.     {
  2915.     // render this polygon if and only if it's not clipped, not culled,
  2916.     // active, and visible, note however the concecpt of "backface" is 
  2917.     // irrelevant in a wire frame engine though
  2918.     if (!(rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_ACTIVE) ||
  2919.          (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_CLIPPED ) ||
  2920.          (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_BACKFACE) )
  2921.        continue; // move onto next poly
  2922.     // set the vertices
  2923.     face.tvlist[0].x = (int)rend_list->poly_ptrs[poly]->tvlist[0].x;
  2924.     face.tvlist[0].y = (int)rend_list->poly_ptrs[poly]->tvlist[0].y;
  2925.     face.tvlist[0].u0 = 0;
  2926.     face.tvlist[0].v0 = 0;
  2927.     face.tvlist[1].x = (int)rend_list->poly_ptrs[poly]->tvlist[1].x;
  2928.     face.tvlist[1].y = (int)rend_list->poly_ptrs[poly]->tvlist[1].y;
  2929.     face.tvlist[1].u0 = 0;
  2930.     face.tvlist[1].v0 = 63;
  2931.     face.tvlist[2].x = (int)rend_list->poly_ptrs[poly]->tvlist[2].x;
  2932.     face.tvlist[2].y = (int)rend_list->poly_ptrs[poly]->tvlist[2].y;
  2933.     face.tvlist[2].u0 = 63;
  2934.     face.tvlist[2].v0 = 63;
  2935.     // assign the texture
  2936.     face.texture = texture;
  2937. // draw the textured triangle
  2938.     Draw_Textured_Triangle(&face, video_buffer, lpitch);
  2939.     } // end for poly
  2940. } // end Draw_RENDERLIST4DV1_Textured
  2941. ///////////////////////////////////////////////////////////////
  2942. void Draw_RENDERLIST4DV1_Textured16(RENDERLIST4DV1_PTR rend_list, 
  2943.                               UCHAR *video_buffer, 
  2944.   int lpitch, 
  2945.   BITMAP_IMAGE_PTR texture)
  2946. {
  2947. // TEST FUNCTION
  2948. POLYF4DV2 face; // temp face used to render polygon
  2949. // at this point, all we have is a list of polygons and it's time
  2950. // to draw them
  2951. for (int poly=0; poly < rend_list->num_polys; poly++)
  2952.     {
  2953.     // render this polygon if and only if it's not clipped, not culled,
  2954.     // active, and visible, note however the concecpt of "backface" is 
  2955.     // irrelevant in a wire frame engine though
  2956.     if (!(rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_ACTIVE) ||
  2957.          (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_CLIPPED ) ||
  2958.          (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_BACKFACE) )
  2959.        continue; // move onto next poly
  2960.     // set the vertices
  2961.     face.tvlist[0].x = (int)rend_list->poly_ptrs[poly]->tvlist[0].x;
  2962.     face.tvlist[0].y = (int)rend_list->poly_ptrs[poly]->tvlist[0].y;
  2963.     face.tvlist[0].u0 = 0;
  2964.     face.tvlist[0].v0 = 0;
  2965.     face.tvlist[1].x = (int)rend_list->poly_ptrs[poly]->tvlist[1].x;
  2966.     face.tvlist[1].y = (int)rend_list->poly_ptrs[poly]->tvlist[1].y;
  2967.     face.tvlist[1].u0 = 0;
  2968.     face.tvlist[1].v0 = 63;
  2969.     face.tvlist[2].x = (int)rend_list->poly_ptrs[poly]->tvlist[2].x;
  2970.     face.tvlist[2].y = (int)rend_list->poly_ptrs[poly]->tvlist[2].y;
  2971.     face.tvlist[2].u0 = 63;
  2972.     face.tvlist[2].v0 = 63;
  2973.     // assign the texture
  2974.     face.texture = texture;
  2975. // draw the textured triangle
  2976.     Draw_Textured_Triangle16(&face, video_buffer, lpitch);
  2977.     } // end for poly
  2978. } // end Draw_RENDERLIST4DV1_Textured16