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

游戏

开发平台:

Visual C++

  1. // compute all deltas
  2. dy = (y1 - y0);
  3. dxdyl = ((x1 - x0)   << FIXP16_SHIFT)/dy;
  4. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dy;  
  5. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dy;    
  6. dzdyl = ((tz1 - tz0) << FIXP16_SHIFT)/dy; 
  7. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  8. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  9. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dy;   
  10. dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dy;   
  11. // test for y clipping
  12. if (y0 < min_clip_y)
  13. {
  14. // compute overclip
  15. dy = (min_clip_y - y0);
  16. // computer new LHS starting values
  17. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  18. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  19. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  20. zl = dzdyl*dy + (tz0 << FIXP16_SHIFT);
  21. // compute new RHS starting values
  22. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  23. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  24. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  25. zr = dzdyr*dy + (tz0 << FIXP16_SHIFT);
  26. // compute new starting y
  27. ystart = min_clip_y;
  28. } // end if
  29. else
  30. {
  31. // no clipping
  32. // set starting values
  33. xl = (x0 << FIXP16_SHIFT);
  34. xr = (x0 << FIXP16_SHIFT);
  35. ul = (tu0 << FIXP16_SHIFT);
  36. vl = (tv0 << FIXP16_SHIFT);
  37. zl = (tz0 << FIXP16_SHIFT);
  38. ur = (tu0 << FIXP16_SHIFT);
  39. vr = (tv0 << FIXP16_SHIFT);
  40. zr = (tz0 << FIXP16_SHIFT);
  41. // set starting y
  42. ystart = y0;
  43. } // end else
  44. } // end else flat bottom
  45. // test for bottom clip, always
  46. if ((yend = y2) > max_clip_y)
  47. yend = max_clip_y;
  48.     // test for horizontal clipping
  49. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  50. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  51. (x2 < min_clip_x) || (x2 > max_clip_x))
  52. {
  53.     // clip version
  54. // point screen ptr to starting line
  55. screen_ptr = dest_buffer + (ystart * mem_pitch);
  56.     // point zbuffer to starting line
  57.     z_ptr = zbuffer + (ystart * zpitch);
  58. for (yi = ystart; yi < yend; yi++)
  59. {
  60. // compute span endpoints
  61. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  62. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  63. // compute starting points for u,v interpolants
  64. ui = ul + FIXP16_ROUND_UP;
  65. vi = vl + FIXP16_ROUND_UP;
  66. zi = zl + FIXP16_ROUND_UP;
  67. // compute u,v interpolants
  68. if ((dx = (xend - xstart))>0)
  69. {
  70. du = (ur - ul)/dx;
  71. dv = (vr - vl)/dx;
  72. dz = (zr - zl)/dx;
  73. } // end if
  74. else
  75. {
  76. du = (ur - ul);
  77. dv = (vr - vl);
  78. dz = (zr - zl);
  79. } // end else
  80. ///////////////////////////////////////////////////////////////////////
  81. // test for x clipping, LHS
  82. if (xstart < min_clip_x)
  83. {
  84. // compute x overlap
  85. dx = min_clip_x - xstart;
  86. // slide interpolants over
  87. ui+=dx*du;
  88. vi+=dx*dv;
  89. zi+=dx*dz;
  90. // reset vars
  91. xstart = min_clip_x;
  92. } // end if
  93. // test for x clipping RHS
  94. if (xend > max_clip_x)
  95. xend = max_clip_x;
  96. ///////////////////////////////////////////////////////////////////////
  97. // draw span
  98. for (xi=xstart; xi < xend; xi++)
  99. {
  100.             // test if z of current pixel is nearer than current z buffer value
  101.             if (zi < z_ptr[xi])
  102.                {
  103.    // write textel
  104.        // get textel first
  105.      textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
  106.                // extract rgb components
  107.                r_textel  = ((textel >> 11)       ); 
  108.                g_textel  = ((textel >> 5)  & 0x3f); 
  109.                b_textel =   (textel        & 0x1f);
  110.                // modulate textel with lit background color
  111.                r_textel*=r_base; 
  112.                g_textel*=g_base;
  113.                b_textel*=b_base;
  114.                // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  115.                // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  116.                // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  117.                // and they all cancel out for the most part, but we will need logical anding, we will do
  118.                // it later when we optimize more...
  119.            screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  120.                              alpha_table_src2[((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11))];
  121.                // update z-buffer
  122.                z_ptr[xi] = zi;           
  123.                } // end if
  124. // interpolate u,v,z
  125. ui+=du;
  126. vi+=dv;
  127. zi+=dz;
  128. } // end for xi
  129. // interpolate u,v,x along right and left edge
  130. xl+=dxdyl;
  131. ul+=dudyl;
  132. vl+=dvdyl;
  133. zl+=dzdyl;
  134. xr+=dxdyr;
  135. ur+=dudyr;
  136. vr+=dvdyr;
  137. zr+=dzdyr;
  138.  
  139. // advance screen ptr
  140. screen_ptr+=mem_pitch;
  141.         // advance zbuffer ptr
  142.         z_ptr+=zpitch;
  143. } // end for y
  144. } // end if clip
  145. else
  146. {
  147. // non-clip version
  148. // point screen ptr to starting line
  149. screen_ptr = dest_buffer + (ystart * mem_pitch);
  150.     // point zbuffer to starting line
  151.     z_ptr = zbuffer + (ystart * zpitch);
  152. for (yi = ystart; yi < yend; yi++)
  153. {
  154. // compute span endpoints
  155. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  156. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  157. // compute starting points for u,v interpolants
  158. ui = ul + FIXP16_ROUND_UP;
  159. vi = vl + FIXP16_ROUND_UP;
  160. zi = zl + FIXP16_ROUND_UP;
  161. // compute u,v interpolants
  162. if ((dx = (xend - xstart))>0)
  163. {
  164. du = (ur - ul)/dx;
  165. dv = (vr - vl)/dx;
  166. dz = (zr - zl)/dx;
  167. } // end if
  168. else
  169. {
  170. du = (ur - ul);
  171. dv = (vr - vl);
  172.             dz = (zr - zl);
  173. } // end else
  174. // draw span
  175. for (xi=xstart; xi < xend; xi++)
  176. {
  177.             // test if z of current pixel is nearer than current z buffer value
  178.             if (zi < z_ptr[xi])
  179.                {
  180.    // write textel
  181.        // get textel first
  182.      textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
  183.                // extract rgb components
  184.                r_textel  = ((textel >> 11)       ); 
  185.                g_textel  = ((textel >> 5)  & 0x3f); 
  186.                b_textel =   (textel        & 0x1f);
  187.                // modulate textel with lit background color
  188.                r_textel*=r_base; 
  189.                g_textel*=g_base;
  190.                b_textel*=b_base;
  191.                // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  192.                // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  193.                // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  194.                // and they all cancel out for the most part, but we will need logical anding, we will do
  195.                // it later when we optimize more...
  196.            screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  197.                              alpha_table_src2[((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11))];
  198.                // update z-buffer
  199.                z_ptr[xi] = zi;           
  200.                } // end if
  201. // interpolate u,v,z
  202. ui+=du;
  203. vi+=dv;
  204.             zi+=dz;
  205. } // end for xi
  206. // interpolate u,v,x along right and left edge
  207. xl+=dxdyl;
  208. ul+=dudyl;
  209. vl+=dvdyl;
  210.     zl+=dzdyl;
  211. xr+=dxdyr;
  212. ur+=dudyr;
  213. vr+=dvdyr;
  214.         zr+=dzdyr;
  215. // advance screen ptr
  216. screen_ptr+=mem_pitch;
  217.         // advance zbuffer ptr
  218.         z_ptr+=zpitch;
  219. } // end for y
  220. } // end if non-clipped
  221. } // end if
  222. else
  223. if (tri_type==TRI_TYPE_GENERAL)
  224. {
  225. // first test for bottom clip, always
  226. if ((yend = y2) > max_clip_y)
  227. yend = max_clip_y;
  228. // pre-test y clipping status
  229. if (y1 < min_clip_y)
  230. {
  231. // compute all deltas
  232. // LHS
  233. dyl = (y2 - y1);
  234. dxdyl = ((x2  - x1)  << FIXP16_SHIFT)/dyl;
  235. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  236. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;    
  237.         dzdyl = ((tz2 - tz1) << FIXP16_SHIFT)/dyl;    
  238. // RHS
  239. dyr = (y2 - y0);
  240. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  241. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  242. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  243.         dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dyr;   
  244. // compute overclip
  245. dyr = (min_clip_y - y0);
  246. dyl = (min_clip_y - y1);
  247. // computer new LHS starting values
  248. xl = dxdyl*dyl + (x1  << FIXP16_SHIFT);
  249. ul = dudyl*dyl + (tu1 << FIXP16_SHIFT);
  250. vl = dvdyl*dyl + (tv1 << FIXP16_SHIFT);
  251.         zl = dzdyl*dyl + (tz1 << FIXP16_SHIFT);
  252. // compute new RHS starting values
  253. xr = dxdyr*dyr + (x0  << FIXP16_SHIFT);
  254. ur = dudyr*dyr + (tu0 << FIXP16_SHIFT);
  255. vr = dvdyr*dyr + (tv0 << FIXP16_SHIFT);
  256.         zr = dzdyr*dyr + (tz0 << FIXP16_SHIFT);
  257. // compute new starting y
  258. ystart = min_clip_y;
  259. // test if we need swap to keep rendering left to right
  260. if (dxdyr > dxdyl)
  261. {
  262. SWAP(dxdyl,dxdyr,temp);
  263. SWAP(dudyl,dudyr,temp);
  264. SWAP(dvdyl,dvdyr,temp);
  265. SWAP(dzdyl,dzdyr,temp);
  266. SWAP(xl,xr,temp);
  267. SWAP(ul,ur,temp);
  268. SWAP(vl,vr,temp);
  269. SWAP(zl,zr,temp);
  270. SWAP(x1,x2,temp);
  271. SWAP(y1,y2,temp);
  272. SWAP(tu1,tu2,temp);
  273. SWAP(tv1,tv2,temp);
  274. SWAP(tz1,tz2,temp);
  275. // set interpolation restart
  276. irestart = INTERP_RHS;
  277. } // end if
  278. } // end if
  279. else
  280. if (y0 < min_clip_y)
  281. {
  282. // compute all deltas
  283. // LHS
  284. dyl = (y1 - y0);
  285. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  286. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  287. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  288.         dzdyl = ((tz1 - tz0) << FIXP16_SHIFT)/dyl;    
  289. // RHS
  290. dyr = (y2 - y0);
  291. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  292. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  293. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  294.         dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dyr;   
  295. // compute overclip
  296. dy = (min_clip_y - y0);
  297. // computer new LHS starting values
  298. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  299. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  300. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  301.         zl = dzdyl*dy + (tz0 << FIXP16_SHIFT);
  302. // compute new RHS starting values
  303. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  304. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  305. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  306.         zr = dzdyr*dy + (tz0 << FIXP16_SHIFT);
  307. // compute new starting y
  308. ystart = min_clip_y;
  309. // test if we need swap to keep rendering left to right
  310. if (dxdyr < dxdyl)
  311. {
  312. SWAP(dxdyl,dxdyr,temp);
  313. SWAP(dudyl,dudyr,temp);
  314. SWAP(dvdyl,dvdyr,temp);
  315. SWAP(dzdyl,dzdyr,temp);
  316. SWAP(xl,xr,temp);
  317. SWAP(ul,ur,temp);
  318. SWAP(vl,vr,temp);
  319. SWAP(zl,zr,temp);
  320. SWAP(x1,x2,temp);
  321. SWAP(y1,y2,temp);
  322. SWAP(tu1,tu2,temp);
  323. SWAP(tv1,tv2,temp);
  324. SWAP(tz1,tz2,temp);
  325. // set interpolation restart
  326. irestart = INTERP_RHS;
  327. } // end if
  328. } // end if
  329. else
  330. {
  331. // no initial y clipping
  332. // compute all deltas
  333. // LHS
  334. dyl = (y1 - y0);
  335. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  336. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  337. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  338.         dzdyl = ((tz1 - tz0) << FIXP16_SHIFT)/dyl;    
  339. // RHS
  340. dyr = (y2 - y0);
  341. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dyr;
  342. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  343. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  344.         dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dyr;   
  345. // no clipping y
  346. // set starting values
  347. xl = (x0 << FIXP16_SHIFT);
  348. xr = (x0 << FIXP16_SHIFT);
  349. ul = (tu0 << FIXP16_SHIFT);
  350. vl = (tv0 << FIXP16_SHIFT);
  351.         zl = (tz0 << FIXP16_SHIFT);
  352. ur = (tu0 << FIXP16_SHIFT);
  353. vr = (tv0 << FIXP16_SHIFT);
  354.         zr = (tz0 << FIXP16_SHIFT);
  355. // set starting y
  356. ystart = y0;
  357. // test if we need swap to keep rendering left to right
  358. if (dxdyr < dxdyl)
  359. {
  360. SWAP(dxdyl,dxdyr,temp);
  361. SWAP(dudyl,dudyr,temp);
  362. SWAP(dvdyl,dvdyr,temp);
  363. SWAP(dzdyl,dzdyr,temp);
  364. SWAP(xl,xr,temp);
  365. SWAP(ul,ur,temp);
  366. SWAP(vl,vr,temp);
  367. SWAP(zl,zr,temp);
  368. SWAP(x1,x2,temp);
  369. SWAP(y1,y2,temp);
  370. SWAP(tu1,tu2,temp);
  371. SWAP(tv1,tv2,temp);
  372. SWAP(tz1,tz2,temp);
  373. // set interpolation restart
  374. irestart = INTERP_RHS;
  375. } // end if
  376. } // end else
  377.     // test for horizontal clipping
  378. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  379. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  380. (x2 < min_clip_x) || (x2 > max_clip_x))
  381. {
  382.     // clip version
  383. // x clipping
  384. // point screen ptr to starting line
  385. screen_ptr = dest_buffer + (ystart * mem_pitch);
  386.     // point zbuffer to starting line
  387.     z_ptr = zbuffer + (ystart * zpitch);
  388. for (yi = ystart; yi < yend; yi++)
  389. {
  390. // compute span endpoints
  391. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  392. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  393. // compute starting points for u,v interpolants
  394. ui = ul + FIXP16_ROUND_UP;
  395. vi = vl + FIXP16_ROUND_UP;
  396.         zi = zl + FIXP16_ROUND_UP;
  397. // compute u,v interpolants
  398. if ((dx = (xend - xstart))>0)
  399. {
  400. du = (ur - ul)/dx;
  401. dv = (vr - vl)/dx;
  402.             dz = (zr - zl)/dx;
  403. } // end if
  404. else
  405. {
  406. du = (ur - ul);
  407. dv = (vr - vl);
  408.             dz = (zr - zl);
  409. } // end else
  410. ///////////////////////////////////////////////////////////////////////
  411. // test for x clipping, LHS
  412. if (xstart < min_clip_x)
  413. {
  414. // compute x overlap
  415. dx = min_clip_x - xstart;
  416. // slide interpolants over
  417. ui+=dx*du;
  418. vi+=dx*dv;
  419. zi+=dx*dz;
  420. // set x to left clip edge
  421. xstart = min_clip_x;
  422. } // end if
  423. // test for x clipping RHS
  424. if (xend > max_clip_x)
  425. xend = max_clip_x;
  426. ///////////////////////////////////////////////////////////////////////
  427. // draw span
  428. for (xi=xstart; xi < xend; xi++)
  429. {
  430.             // test if z of current pixel is nearer than current z buffer value
  431.             if (zi < z_ptr[xi])
  432.                {
  433.    // write textel
  434.        // get textel first
  435.      textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
  436.                // extract rgb components
  437.                r_textel  = ((textel >> 11)       ); 
  438.                g_textel  = ((textel >> 5)  & 0x3f); 
  439.                b_textel =   (textel        & 0x1f);
  440.                // modulate textel with lit background color
  441.                r_textel*=r_base; 
  442.                g_textel*=g_base;
  443.                b_textel*=b_base;
  444.                // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  445.                // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  446.                // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  447.                // and they all cancel out for the most part, but we will need logical anding, we will do
  448.                // it later when we optimize more...
  449.            screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  450.                                 alpha_table_src2[((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11))];
  451.                // update z-buffer
  452.                z_ptr[xi] = zi;           
  453.                } // end if
  454. // interpolate u,v
  455. ui+=du;
  456. vi+=dv;
  457.             zi+=dz;
  458. } // end for xi
  459. // interpolate u,v,x along right and left edge
  460. xl+=dxdyl;
  461. ul+=dudyl;
  462. vl+=dvdyl;
  463. zl+=dzdyl;
  464. xr+=dxdyr;
  465. ur+=dudyr;
  466. vr+=dvdyr;
  467. zr+=dzdyr;
  468. // advance screen ptr
  469. screen_ptr+=mem_pitch;
  470.         // advance zbuffer ptr
  471.         z_ptr+=zpitch;
  472. // test for yi hitting second region, if so change interpolant
  473. if (yi==yrestart)
  474. {
  475.       // test interpolation side change flag
  476. if (irestart == INTERP_LHS)
  477. {
  478. // LHS
  479. dyl = (y2 - y1);
  480. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  481. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  482. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  483. dzdyl = ((tz2 - tz1) << FIXP16_SHIFT)/dyl;  
  484. // set starting values
  485. xl = (x1  << FIXP16_SHIFT);
  486. ul = (tu1 << FIXP16_SHIFT);
  487. vl = (tv1 << FIXP16_SHIFT);
  488. zl = (tz1 << FIXP16_SHIFT);
  489. // interpolate down on LHS to even up
  490. xl+=dxdyl;
  491. ul+=dudyl;
  492. vl+=dvdyl;
  493. zl+=dzdyl;
  494. } // end if
  495. else
  496. {
  497. // RHS
  498. dyr = (y1 - y2);
  499. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  500. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  501. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  502. dzdyr = ((tz1 - tz2) << FIXP16_SHIFT)/dyr;   
  503. // set starting values
  504. xr = (x2  << FIXP16_SHIFT);
  505. ur = (tu2 << FIXP16_SHIFT);
  506. vr = (tv2 << FIXP16_SHIFT);
  507. zr = (tz2 << FIXP16_SHIFT);
  508. // interpolate down on RHS to even up
  509. xr+=dxdyr;
  510. ur+=dudyr;
  511. vr+=dvdyr;
  512. zr+=dzdyr;
  513. } // end else
  514. } // end if
  515. } // end for y
  516. } // end if
  517. else
  518. {
  519. // no x clipping
  520. // point screen ptr to starting line
  521. screen_ptr = dest_buffer + (ystart * mem_pitch);
  522.     // point zbuffer to starting line
  523.     z_ptr = zbuffer + (ystart * zpitch);
  524. for (yi = ystart; yi < yend; yi++)
  525. {
  526. // compute span endpoints
  527. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  528. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  529. // compute starting points for u,v,z interpolants
  530. ui = ul + FIXP16_ROUND_UP;
  531. vi = vl + FIXP16_ROUND_UP;
  532. zi = zl + FIXP16_ROUND_UP;
  533. // compute u,v interpolants
  534. if ((dx = (xend - xstart))>0)
  535. {
  536. du = (ur - ul)/dx;
  537. dv = (vr - vl)/dx;
  538.             dz = (zr - zl)/dx;
  539. } // end if
  540. else
  541. {
  542. du = (ur - ul);
  543. dv = (vr - vl);
  544.             dz = (zr - zl);
  545. } // end else
  546. // draw span
  547. for (xi=xstart; xi < xend; xi++)
  548. {
  549.             // test if z of current pixel is nearer than current z buffer value
  550.             if (zi < z_ptr[xi])
  551.                {
  552.    // write textel
  553.        // get textel first
  554.      textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
  555.                // extract rgb components
  556.                r_textel  = ((textel >> 11)       ); 
  557.                g_textel  = ((textel >> 5)  & 0x3f); 
  558.                b_textel =   (textel        & 0x1f);
  559.                // modulate textel with lit background color
  560.                r_textel*=r_base; 
  561.                g_textel*=g_base;
  562.                b_textel*=b_base;
  563.                // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  564.                // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  565.                // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  566.                // and they all cancel out for the most part, but we will need logical anding, we will do
  567.                // it later when we optimize more...
  568.            screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  569.                                 alpha_table_src2[((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11))];
  570.                // update z-buffer
  571.                z_ptr[xi] = zi;           
  572.                } // end if
  573. // interpolate u,v,z
  574. ui+=du;
  575. vi+=dv;
  576.             zi+=dz;
  577. } // end for xi
  578. // interpolate u,v,x along right and left edge
  579. xl+=dxdyl;
  580. ul+=dudyl;
  581. vl+=dvdyl;
  582.         zl+=dzdyl;
  583. xr+=dxdyr;
  584. ur+=dudyr;
  585. vr+=dvdyr;
  586.         zr+=dzdyr;
  587. // advance screen ptr
  588. screen_ptr+=mem_pitch;
  589.         // advance zbuffer ptr
  590.         z_ptr+=zpitch;
  591. // test for yi hitting second region, if so change interpolant
  592. if (yi==yrestart)
  593. {
  594. // test interpolation side change flag
  595. if (irestart == INTERP_LHS)
  596. {
  597. // LHS
  598. dyl = (y2 - y1);
  599. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  600. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  601. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  602. dzdyl = ((tz2 - tz1) << FIXP16_SHIFT)/dyl; 
  603. // set starting values
  604. xl = (x1  << FIXP16_SHIFT);
  605. ul = (tu1 << FIXP16_SHIFT);
  606. vl = (tv1 << FIXP16_SHIFT);
  607. zl = (tz1 << FIXP16_SHIFT);
  608. // interpolate down on LHS to even up
  609. xl+=dxdyl;
  610. ul+=dudyl;
  611. vl+=dvdyl;
  612. zl+=dzdyl;
  613. } // end if
  614. else
  615. {
  616. // RHS
  617. dyr = (y1 - y2);
  618. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  619. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  620. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  621. dzdyr = ((tz1 - tz2) << FIXP16_SHIFT)/dyr;   
  622. // set starting values
  623. xr = (x2  << FIXP16_SHIFT);
  624. ur = (tu2 << FIXP16_SHIFT);
  625. vr = (tv2 << FIXP16_SHIFT);
  626. zr = (tz2 << FIXP16_SHIFT);
  627. // interpolate down on RHS to even up
  628. xr+=dxdyr;
  629. ur+=dudyr;
  630. vr+=dvdyr;
  631. zr+=dzdyr;
  632. } // end else
  633. } // end if
  634. } // end for y
  635.    } // end else
  636. } // end if
  637. } // end Draw_Textured_TriangleFSZB_Alpha16
  638. ///////////////////////////////////////////////////////////////////////////////
  639. void Draw_Textured_TriangleGSZB_Alpha16(POLYF4DV2_PTR face, // ptr to face
  640.                                  UCHAR *_dest_buffer,       // pointer to video buffer
  641.                                  int mem_pitch,             // bytes per line, 320, 640 etc.
  642.                                  UCHAR *_zbuffer,           // pointer to z-buffer
  643.                                  int zpitch,                // bytes per line of zbuffer
  644.                                  int alpha)
  645. {
  646. // this function draws a textured gouraud shaded polygon, and z bufferedbased on the affine texture mapper, 
  647. // we simply interpolate the (R,G,B) values across the polygons along with the texture coordinates
  648. // and then modulate to get the final color 
  649. int v0=0,
  650.     v1=1,
  651. v2=2,
  652. temp=0,
  653. tri_type = TRI_TYPE_NONE,
  654. irestart = INTERP_LHS;
  655. int dx,dy,dyl,dyr,      // general deltas
  656.     u,v,w,z, s,t,
  657.     du,dv,dw,dz, ds, dt, 
  658.     xi,yi,             // the current interpolated x,y
  659. ui,vi,wi,zi, si, ti,    // the current interpolated u,v
  660. index_x,index_y,    // looping vars
  661. x,y,                // hold general x,y
  662. xstart,
  663. xend,
  664. ystart,
  665. yrestart,
  666. yend,
  667. xl,                 
  668. dxdyl,              
  669. xr,
  670. dxdyr,             
  671. dudyl,    
  672. ul,
  673. dvdyl,   
  674. vl,
  675. dwdyl,   
  676. wl,
  677. dzdyl,   
  678. zl,
  679. dsdyl,    
  680. sl,
  681. dtdyl,   
  682. tl,
  683. dudyr,
  684. ur,
  685. dvdyr,
  686. vr,
  687. dwdyr,
  688. wr,
  689. dzdyr,
  690. zr,
  691. dsdyr,
  692. sr,
  693. dtdyr,
  694. tr;
  695. int x0,y0,tu0,tv0,tw0, tz0, ts0,tt0,    // cached vertices
  696. x1,y1,tu1,tv1,tw1, tz1, ts1,tt1,
  697. x2,y2,tu2,tv2,tw2, tz2, ts2,tt2;
  698. int r_base0, g_base0, b_base0,
  699.     r_base1, g_base1, b_base1,
  700.     r_base2, g_base2, b_base2;
  701. UINT r_textel, g_textel, b_textel;
  702. USHORT textel;
  703. USHORT *screen_ptr  = NULL,
  704.    *screen_line = NULL,
  705.    *textmap     = NULL,
  706.        *dest_buffer = (USHORT *)_dest_buffer;
  707. UINT  *z_ptr = NULL,
  708.       *zbuffer = (UINT *)_zbuffer;
  709. #ifdef DEBUG_ON
  710. // track rendering stats
  711.     debug_polys_rendered_per_frame++;
  712. #endif
  713. // extract texture map
  714. textmap = (USHORT *)face->texture->buffer;
  715. // extract base 2 of texture width
  716. int texture_shift2 = logbase2ofx[face->texture->width];
  717. // adjust memory pitch to words, divide by 2
  718. mem_pitch >>=1;
  719. // adjust zbuffer pitch for 32 bit alignment
  720. zpitch >>= 2;
  721. // apply fill convention to coordinates
  722. face->tvlist[0].x = (int)(face->tvlist[0].x+0.0);
  723. face->tvlist[0].y = (int)(face->tvlist[0].y+0.0);
  724. face->tvlist[1].x = (int)(face->tvlist[1].x+0.0);
  725. face->tvlist[1].y = (int)(face->tvlist[1].y+0.0);
  726. face->tvlist[2].x = (int)(face->tvlist[2].x+0.0);
  727. face->tvlist[2].y = (int)(face->tvlist[2].y+0.0);
  728. // first trivial clipping rejection tests 
  729. if (((face->tvlist[0].y < min_clip_y)  && 
  730.  (face->tvlist[1].y < min_clip_y)  &&
  731.  (face->tvlist[2].y < min_clip_y)) ||
  732. ((face->tvlist[0].y > max_clip_y)  && 
  733.  (face->tvlist[1].y > max_clip_y)  &&
  734.  (face->tvlist[2].y > max_clip_y)) ||
  735. ((face->tvlist[0].x < min_clip_x)  && 
  736.  (face->tvlist[1].x < min_clip_x)  &&
  737.  (face->tvlist[2].x < min_clip_x)) ||
  738. ((face->tvlist[0].x > max_clip_x)  && 
  739.  (face->tvlist[1].x > max_clip_x)  &&
  740.  (face->tvlist[2].x > max_clip_x)))
  741.    return;
  742. // sort vertices
  743. if (face->tvlist[v1].y < face->tvlist[v0].y) 
  744. {SWAP(v0,v1,temp);} 
  745. if (face->tvlist[v2].y < face->tvlist[v0].y) 
  746. {SWAP(v0,v2,temp);}
  747. if (face->tvlist[v2].y < face->tvlist[v1].y) 
  748. {SWAP(v1,v2,temp);}
  749. // now test for trivial flat sided cases
  750. if (FCMP(face->tvlist[v0].y, face->tvlist[v1].y) )
  751. // set triangle type
  752. tri_type = TRI_TYPE_FLAT_TOP;
  753. // sort vertices left to right
  754. if (face->tvlist[v1].x < face->tvlist[v0].x) 
  755. {SWAP(v0,v1,temp);}
  756. } // end if
  757. else
  758. // now test for trivial flat sided cases
  759. if (FCMP(face->tvlist[v1].y, face->tvlist[v2].y) )
  760. // set triangle type
  761. tri_type = TRI_TYPE_FLAT_BOTTOM;
  762. // sort vertices left to right
  763. if (face->tvlist[v2].x < face->tvlist[v1].x) 
  764. {SWAP(v1,v2,temp);}
  765. } // end if
  766. else
  767. {
  768. // must be a general triangle
  769. tri_type = TRI_TYPE_GENERAL;
  770. } // end else
  771. // assume 5.6.5 format -- sorry!
  772. // we can't afford a function call in the inner loops, so we must write 
  773. // two hard coded versions, if we want support for both 5.6.5, and 5.5.5
  774. _RGB565FROM16BIT(face->lit_color[v0], &r_base0, &g_base0, &b_base0);
  775. _RGB565FROM16BIT(face->lit_color[v1], &r_base1, &g_base1, &b_base1);
  776. _RGB565FROM16BIT(face->lit_color[v2], &r_base2, &g_base2, &b_base2);
  777. // scale to 8 bit 
  778. r_base0 <<= 3;
  779. g_base0 <<= 2;
  780. b_base0 <<= 3;
  781. // scale to 8 bit 
  782. r_base1 <<= 3;
  783. g_base1 <<= 2;
  784. b_base1 <<= 3;
  785. // scale to 8 bit 
  786. r_base2 <<= 3;
  787. g_base2 <<= 2;
  788. b_base2 <<= 3;
  789. // extract vertices for processing, now that we have order
  790. x0  = (int)(face->tvlist[v0].x+0.0);
  791. y0  = (int)(face->tvlist[v0].y+0.0);
  792. tz0 = (int)(face->tvlist[v0].z+0.5);
  793. ts0 = (int)(face->tvlist[v0].u0);
  794. tt0 = (int)(face->tvlist[v0].v0);
  795. tu0 = r_base0;
  796. tv0 = g_base0; 
  797. tw0 = b_base0; 
  798. x1  = (int)(face->tvlist[v1].x+0.0);
  799. y1  = (int)(face->tvlist[v1].y+0.0);
  800. tz1 = (int)(face->tvlist[v1].z+0.5);
  801. ts1 = (int)(face->tvlist[v1].u0);
  802. tt1 = (int)(face->tvlist[v1].v0);
  803. tu1 = r_base1;
  804. tv1 = g_base1; 
  805. tw1 = b_base1; 
  806. x2  = (int)(face->tvlist[v2].x+0.0);
  807. y2  = (int)(face->tvlist[v2].y+0.0);
  808. tz2 = (int)(face->tvlist[v2].z+0.5);
  809. ts2 = (int)(face->tvlist[v2].u0);
  810. tt2 = (int)(face->tvlist[v2].v0);
  811. tu2 = r_base2; 
  812. tv2 = g_base2; 
  813. tw2 = b_base2; 
  814. // degenerate triangle
  815. if ( ((x0 == x1) && (x1 == x2)) || ((y0 ==  y1) && (y1 == y2)))
  816.    return;
  817. // assign both source1 and source2 alpha tables based on polygon alpha level
  818. USHORT *alpha_table_src1 = (USHORT *)&rgb_alpha_table[(NUM_ALPHA_LEVELS-1) - alpha][0];
  819. USHORT *alpha_table_src2 = (USHORT *)&rgb_alpha_table[alpha][0];
  820. // set interpolation restart value
  821. yrestart = y1;
  822. // what kind of triangle
  823. if (tri_type & TRI_TYPE_FLAT_MASK)
  824. {
  825. if (tri_type == TRI_TYPE_FLAT_TOP)
  826. {
  827. // compute all deltas
  828. dy = (y2 - y0);
  829. dxdyl = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  830. dudyl = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  831. dvdyl = ((tv2 - tv0) << FIXP16_SHIFT)/dy;    
  832. dwdyl = ((tw2 - tw0) << FIXP16_SHIFT)/dy;  
  833. dzdyl = ((tz2 - tz0) << FIXP16_SHIFT)/dy; 
  834.     dsdyl = ((ts2 - ts0) << FIXP16_SHIFT)/dy;    
  835. dtdyl = ((tt2 - tt0) << FIXP16_SHIFT)/dy;  
  836. dxdyr = ((x2 - x1)   << FIXP16_SHIFT)/dy;
  837. dudyr = ((tu2 - tu1) << FIXP16_SHIFT)/dy;  
  838. dvdyr = ((tv2 - tv1) << FIXP16_SHIFT)/dy;   
  839. dwdyr = ((tw2 - tw1) << FIXP16_SHIFT)/dy;   
  840. dzdyr = ((tz2 - tz1) << FIXP16_SHIFT)/dy;   
  841. dsdyr = ((ts2 - ts1) << FIXP16_SHIFT)/dy;   
  842. dtdyr = ((tt2 - tt1) << FIXP16_SHIFT)/dy;   
  843. // test for y clipping
  844. if (y0 < min_clip_y)
  845. {
  846. // compute overclip
  847. dy = (min_clip_y - y0);
  848. // computer new LHS starting values
  849. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  850. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  851. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  852. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  853. zl = dzdyl*dy + (tz0 << FIXP16_SHIFT);
  854. sl = dsdyl*dy + (ts0 << FIXP16_SHIFT);
  855. tl = dtdyl*dy + (tt0 << FIXP16_SHIFT);
  856. // compute new RHS starting values
  857. xr = dxdyr*dy + (x1  << FIXP16_SHIFT);
  858. ur = dudyr*dy + (tu1 << FIXP16_SHIFT);
  859. vr = dvdyr*dy + (tv1 << FIXP16_SHIFT);
  860. wr = dwdyr*dy + (tw1 << FIXP16_SHIFT);
  861. zr = dzdyr*dy + (tz1 << FIXP16_SHIFT);
  862. sr = dsdyr*dy + (ts1 << FIXP16_SHIFT);
  863. tr = dtdyr*dy + (tt1 << FIXP16_SHIFT);
  864. // compute new starting y
  865. ystart = min_clip_y;
  866. } // end if
  867. else
  868. {
  869. // no clipping
  870. // set starting values
  871. xl = (x0 << FIXP16_SHIFT);
  872. xr = (x1 << FIXP16_SHIFT);
  873. ul = (tu0 << FIXP16_SHIFT);
  874. vl = (tv0 << FIXP16_SHIFT);
  875. wl = (tw0 << FIXP16_SHIFT);
  876. zl = (tz0 << FIXP16_SHIFT);
  877. sl = (ts0 << FIXP16_SHIFT);
  878. tl = (tt0 << FIXP16_SHIFT);
  879. ur = (tu1 << FIXP16_SHIFT);
  880. vr = (tv1 << FIXP16_SHIFT);
  881. wr = (tw1 << FIXP16_SHIFT);
  882. zr = (tz1 << FIXP16_SHIFT);
  883. sr = (ts1 << FIXP16_SHIFT);
  884. tr = (tt1 << FIXP16_SHIFT);
  885. // set starting y
  886. ystart = y0;
  887. } // end else
  888. } // end if flat top
  889. else
  890. {
  891. // must be flat bottom
  892. // compute all deltas
  893. dy = (y1 - y0);
  894. dxdyl = ((x1 - x0)   << FIXP16_SHIFT)/dy;
  895. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dy;  
  896. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dy;    
  897. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dy; 
  898. dzdyl = ((tz1 - tz0) << FIXP16_SHIFT)/dy; 
  899. dsdyl = ((ts1 - ts0) << FIXP16_SHIFT)/dy;    
  900. dtdyl = ((tt1 - tt0) << FIXP16_SHIFT)/dy; 
  901. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  902. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  903. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dy;   
  904. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dy;   
  905. dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dy;   
  906. dsdyr = ((ts2 - ts0) << FIXP16_SHIFT)/dy;   
  907. dtdyr = ((tt2 - tt0) << FIXP16_SHIFT)/dy;   
  908. // test for y clipping
  909. if (y0 < min_clip_y)
  910. {
  911. // compute overclip
  912. dy = (min_clip_y - y0);
  913. // computer new LHS starting values
  914. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  915. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  916. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  917. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  918. zl = dzdyl*dy + (tz0 << FIXP16_SHIFT);
  919. sl = dsdyl*dy + (ts0 << FIXP16_SHIFT);
  920. tl = dtdyl*dy + (tt0 << FIXP16_SHIFT);
  921. // compute new RHS starting values
  922. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  923. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  924. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  925. wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
  926. zr = dzdyr*dy + (tz0 << FIXP16_SHIFT);
  927. sr = dsdyr*dy + (ts0 << FIXP16_SHIFT);
  928. tr = dtdyr*dy + (tt0 << FIXP16_SHIFT);
  929. // compute new starting y
  930. ystart = min_clip_y;
  931. } // end if
  932. else
  933. {
  934. // no clipping
  935. // set starting values
  936. xl = (x0 << FIXP16_SHIFT);
  937. xr = (x0 << FIXP16_SHIFT);
  938. ul = (tu0 << FIXP16_SHIFT);
  939. vl = (tv0 << FIXP16_SHIFT);
  940. wl = (tw0 << FIXP16_SHIFT);
  941. zl = (tz0 << FIXP16_SHIFT);
  942. sl = (ts0 << FIXP16_SHIFT);
  943. tl = (tt0 << FIXP16_SHIFT);
  944. ur = (tu0 << FIXP16_SHIFT);
  945. vr = (tv0 << FIXP16_SHIFT);
  946. wr = (tw0 << FIXP16_SHIFT);
  947. zr = (tz0 << FIXP16_SHIFT);
  948. sr = (ts0 << FIXP16_SHIFT);
  949. tr = (tt0 << FIXP16_SHIFT);
  950. // set starting y
  951. ystart = y0;
  952. } // end else
  953. } // end else flat bottom
  954. // test for bottom clip, always
  955. if ((yend = y2) > max_clip_y)
  956. yend = max_clip_y;
  957.     // test for horizontal clipping
  958. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  959. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  960. (x2 < min_clip_x) || (x2 > max_clip_x))
  961. {
  962.     // clip version
  963. // point screen ptr to starting line
  964. screen_ptr = dest_buffer + (ystart * mem_pitch);
  965.     // point zbuffer to starting line
  966.     z_ptr = zbuffer + (ystart * zpitch);
  967. for (yi = ystart; yi < yend; yi++)
  968. {
  969. // compute span endpoints
  970. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  971. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  972. // compute starting points for u,v,w interpolants
  973. ui = ul + FIXP16_ROUND_UP;
  974. vi = vl + FIXP16_ROUND_UP;
  975. wi = wl + FIXP16_ROUND_UP;
  976. zi = zl + FIXP16_ROUND_UP;
  977.         si = sl + FIXP16_ROUND_UP;
  978. ti = tl + FIXP16_ROUND_UP;
  979. // compute u,v interpolants
  980. if ((dx = (xend - xstart))>0)
  981. {
  982. du = (ur - ul)/dx;
  983. dv = (vr - vl)/dx;
  984. dw = (wr - wl)/dx;
  985. dz = (zr - zl)/dx;
  986. ds = (sr - sl)/dx;
  987. dt = (tr - tl)/dx;
  988. } // end if
  989. else
  990. {
  991. du = (ur - ul);
  992. dv = (vr - vl);
  993. dw = (wr - wl);
  994. dz = (zr - zl);
  995. ds = (sr - sl);
  996. dt = (tr - tl);
  997. } // end else
  998. ///////////////////////////////////////////////////////////////////////
  999. // test for x clipping, LHS
  1000. if (xstart < min_clip_x)
  1001. {
  1002. // compute x overlap
  1003. dx = min_clip_x - xstart;
  1004. // slide interpolants over
  1005. ui+=dx*du;
  1006. vi+=dx*dv;
  1007. wi+=dx*dw;
  1008. zi+=dx*dz;
  1009. si+=dx*ds;
  1010. ti+=dx*dt;
  1011. // reset vars
  1012. xstart = min_clip_x;
  1013. } // end if
  1014. // test for x clipping RHS
  1015. if (xend > max_clip_x)
  1016. xend = max_clip_x;
  1017. ///////////////////////////////////////////////////////////////////////
  1018. // draw span
  1019. for (xi=xstart; xi < xend; xi++)
  1020. {
  1021. // write textel assume 5.6.5
  1022.             // test if z of current pixel is nearer than current z buffer value
  1023.             if (zi < z_ptr[xi])
  1024.             { 
  1025.     // get textel first
  1026.   textel = textmap[(si >> FIXP16_SHIFT) + ((ti >> FIXP16_SHIFT) << texture_shift2)];
  1027.             // extract rgb components
  1028.             r_textel  = ((textel >> 11)       ); 
  1029.             g_textel  = ((textel >> 5)  & 0x3f); 
  1030.             b_textel =   (textel        & 0x1f);
  1031.             // modulate textel with gouraud shading
  1032.             r_textel*=ui; 
  1033.             g_textel*=vi;
  1034.             b_textel*=wi;
  1035.             // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  1036.             // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  1037.             // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  1038.             // and they all cancel out for the most part, but we will need logical anding, we will do
  1039.             // it later when we optimize more...
  1040.             screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  1041.                              alpha_table_src2[((b_textel >> (FIXP16_SHIFT+8)) + 
  1042.                                               ((g_textel >> (FIXP16_SHIFT+8)) << 5) + 
  1043.                                               ((r_textel >> (FIXP16_SHIFT+8)) << 11))];
  1044.             // update z-buffer
  1045.             z_ptr[xi] = zi;   
  1046.             } // end if 
  1047. // interpolate u,v
  1048. ui+=du;
  1049. vi+=dv;
  1050. wi+=dw;
  1051. zi+=dz;
  1052. si+=ds;
  1053. ti+=dt;
  1054. } // end for xi
  1055. // interpolate u,v,w,x along right and left edge
  1056. xl+=dxdyl;
  1057. ul+=dudyl;
  1058. vl+=dvdyl;
  1059. wl+=dwdyl;
  1060. zl+=dzdyl;
  1061. sl+=dsdyl;
  1062. tl+=dtdyl;
  1063. xr+=dxdyr;
  1064. ur+=dudyr;
  1065. vr+=dvdyr;
  1066. wr+=dwdyr;
  1067. zr+=dzdyr;
  1068.  
  1069. sr+=dsdyr;
  1070. tr+=dtdyr;
  1071. // advance screen ptr
  1072. screen_ptr+=mem_pitch;
  1073.         // advance zbuffer ptr
  1074.         z_ptr+=zpitch;
  1075. } // end for y
  1076. } // end if clip
  1077. else
  1078. {
  1079. // non-clip version
  1080. // point screen ptr to starting line
  1081. screen_ptr = dest_buffer + (ystart * mem_pitch);
  1082.     // point zbuffer to starting line
  1083.     z_ptr = zbuffer + (ystart * zpitch);
  1084. for (yi = ystart; yi < yend; yi++)
  1085. {
  1086. // compute span endpoints
  1087. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1088. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1089. // compute starting points for u,v,w interpolants
  1090. ui = ul + FIXP16_ROUND_UP;
  1091. vi = vl + FIXP16_ROUND_UP;
  1092. wi = wl + FIXP16_ROUND_UP;
  1093. zi = zl + FIXP16_ROUND_UP;
  1094. si = sl + FIXP16_ROUND_UP;
  1095. ti = tl + FIXP16_ROUND_UP;
  1096. // compute u,v interpolants
  1097. if ((dx = (xend - xstart))>0)
  1098. {
  1099. du = (ur - ul)/dx;
  1100. dv = (vr - vl)/dx;
  1101. dw = (wr - wl)/dx;
  1102. dz = (zr - zl)/dx;
  1103. ds = (sr - sl)/dx;
  1104. dt = (tr - tl)/dx;
  1105. } // end if
  1106. else
  1107. {
  1108. du = (ur - ul);
  1109. dv = (vr - vl);
  1110. dw = (wr - wl);
  1111. dz = (zr - zl);
  1112. ds = (sr - sl);
  1113. dt = (tr - tl);
  1114. } // end else
  1115. // draw span
  1116. for (xi=xstart; xi < xend; xi++)
  1117. {
  1118. // write textel assume 5.6.5
  1119.             // test if z of current pixel is nearer than current z buffer value
  1120.             if (zi < z_ptr[xi])
  1121.             { 
  1122.     // get textel first
  1123.   textel = textmap[(si >> FIXP16_SHIFT) + ((ti >> FIXP16_SHIFT) << texture_shift2)];
  1124.             // extract rgb components
  1125.             r_textel  = ((textel >> 11)       ); 
  1126.             g_textel  = ((textel >> 5)  & 0x3f); 
  1127.             b_textel =   (textel        & 0x1f);
  1128.             // modulate textel with gouraud shading
  1129.             r_textel*=ui; 
  1130.             g_textel*=vi;
  1131.             b_textel*=wi;
  1132.             // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  1133.             // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  1134.             // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  1135.             // and they all cancel out for the most part, but we will need logical anding, we will do
  1136.             // it later when we optimize more...
  1137.             screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  1138.                              alpha_table_src2[((b_textel >> (FIXP16_SHIFT+8)) + 
  1139.                                               ((g_textel >> (FIXP16_SHIFT+8)) << 5) + 
  1140.                                               ((r_textel >> (FIXP16_SHIFT+8)) << 11))];
  1141.             // update z-buffer
  1142.             z_ptr[xi] = zi;   
  1143.             } // end if 
  1144. // interpolate u,v
  1145. ui+=du;
  1146. vi+=dv;
  1147. wi+=dw;
  1148. zi+=dz;
  1149. si+=ds;
  1150. ti+=dt;
  1151. } // end for xi
  1152. // interpolate u,v,w,x along right and left edge
  1153. xl+=dxdyl;
  1154. ul+=dudyl;
  1155. vl+=dvdyl;
  1156. wl+=dwdyl;
  1157. zl+=dzdyl;
  1158. sl+=dsdyl;
  1159. tl+=dtdyl;
  1160. xr+=dxdyr;
  1161. ur+=dudyr;
  1162. vr+=dvdyr;
  1163. wr+=dwdyr;
  1164. zr+=dzdyr;
  1165. sr+=dsdyr;
  1166. tr+=dtdyr;
  1167. // advance screen ptr
  1168. screen_ptr+=mem_pitch;
  1169.         // advance zbuffer ptr
  1170.         z_ptr+=zpitch;
  1171. } // end for y
  1172. } // end if non-clipped
  1173. } // end if
  1174. else
  1175. if (tri_type==TRI_TYPE_GENERAL)
  1176. {
  1177. // first test for bottom clip, always
  1178. if ((yend = y2) > max_clip_y)
  1179. yend = max_clip_y;
  1180. // pre-test y clipping status
  1181. if (y1 < min_clip_y)
  1182. {
  1183. // compute all deltas
  1184. // LHS
  1185. dyl = (y2 - y1);
  1186. dxdyl = ((x2  - x1)  << FIXP16_SHIFT)/dyl;
  1187. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  1188. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;    
  1189. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;  
  1190. dzdyl = ((tz2 - tz1) << FIXP16_SHIFT)/dyl;  
  1191. dsdyl = ((ts2 - ts1) << FIXP16_SHIFT)/dyl;    
  1192. dtdyl = ((tt2 - tt1) << FIXP16_SHIFT)/dyl;  
  1193. // RHS
  1194. dyr = (y2 - y0);
  1195. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  1196. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  1197. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  1198. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;   
  1199. dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dyr;   
  1200. dsdyr = ((ts2 - ts0) << FIXP16_SHIFT)/dyr;   
  1201. dtdyr = ((tt2 - tt0) << FIXP16_SHIFT)/dyr;  
  1202. // compute overclip
  1203. dyr = (min_clip_y - y0);
  1204. dyl = (min_clip_y - y1);
  1205. // computer new LHS starting values
  1206. xl = dxdyl*dyl + (x1  << FIXP16_SHIFT);
  1207. ul = dudyl*dyl + (tu1 << FIXP16_SHIFT);
  1208. vl = dvdyl*dyl + (tv1 << FIXP16_SHIFT);
  1209. wl = dwdyl*dyl + (tw1 << FIXP16_SHIFT);
  1210. zl = dzdyl*dyl + (tz1 << FIXP16_SHIFT);
  1211. sl = dsdyl*dyl + (ts1 << FIXP16_SHIFT);
  1212. tl = dtdyl*dyl + (tt1 << FIXP16_SHIFT);
  1213. // compute new RHS starting values
  1214. xr = dxdyr*dyr + (x0  << FIXP16_SHIFT);
  1215. ur = dudyr*dyr + (tu0 << FIXP16_SHIFT);
  1216. vr = dvdyr*dyr + (tv0 << FIXP16_SHIFT);
  1217. wr = dwdyr*dyr + (tw0 << FIXP16_SHIFT);
  1218. zr = dzdyr*dyr + (tz0 << FIXP16_SHIFT);
  1219. sr = dsdyr*dyr + (ts0 << FIXP16_SHIFT);
  1220. tr = dtdyr*dyr + (tt0 << FIXP16_SHIFT);
  1221. // compute new starting y
  1222. ystart = min_clip_y;
  1223. // test if we need swap to keep rendering left to right
  1224. if (dxdyr > dxdyl)
  1225. {
  1226. SWAP(dxdyl,dxdyr,temp);
  1227. SWAP(dudyl,dudyr,temp);
  1228. SWAP(dvdyl,dvdyr,temp);
  1229. SWAP(dwdyl,dwdyr,temp);
  1230. SWAP(dzdyl,dzdyr,temp);
  1231. SWAP(dsdyl,dsdyr,temp);
  1232. SWAP(dtdyl,dtdyr,temp);
  1233.           SWAP(xl,xr,temp);
  1234. SWAP(ul,ur,temp);
  1235. SWAP(vl,vr,temp);
  1236. SWAP(wl,wr,temp);
  1237. SWAP(zl,zr,temp);
  1238. SWAP(sl,sr,temp);
  1239. SWAP(tl,tr,temp);
  1240. SWAP(x1,x2,temp);
  1241. SWAP(y1,y2,temp);
  1242. SWAP(tu1,tu2,temp);
  1243. SWAP(tv1,tv2,temp);
  1244. SWAP(tw1,tw2,temp);
  1245. SWAP(tz1,tz2,temp);
  1246. SWAP(ts1,ts2,temp);
  1247. SWAP(tt1,tt2,temp);
  1248. // set interpolation restart
  1249. irestart = INTERP_RHS;
  1250. } // end if
  1251. } // end if
  1252. else
  1253. if (y0 < min_clip_y)
  1254. {
  1255. // compute all deltas
  1256. // LHS
  1257. dyl = (y1 - y0);
  1258. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  1259. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  1260. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  1261. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dyl; 
  1262. dzdyl = ((tz1 - tz0) << FIXP16_SHIFT)/dyl; 
  1263. dsdyl = ((ts1 - ts0) << FIXP16_SHIFT)/dyl;    
  1264. dtdyl = ((tt1 - tt0) << FIXP16_SHIFT)/dyl; 
  1265. // RHS
  1266. dyr = (y2 - y0);
  1267. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  1268. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  1269. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  1270. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;   
  1271. dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dyr;   
  1272. dsdyr = ((ts2 - ts0) << FIXP16_SHIFT)/dyr;   
  1273. dtdyr = ((tt2 - tt0) << FIXP16_SHIFT)/dyr;   
  1274. // compute overclip
  1275. dy = (min_clip_y - y0);
  1276. // computer new LHS starting values
  1277. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  1278. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  1279. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  1280. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  1281. zl = dzdyl*dy + (tz0 << FIXP16_SHIFT);
  1282. sl = dsdyl*dy + (ts0 << FIXP16_SHIFT);
  1283. tl = dtdyl*dy + (tt0 << FIXP16_SHIFT);
  1284. // compute new RHS starting values
  1285. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  1286. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  1287. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  1288. wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
  1289. zr = dzdyr*dy + (tz0 << FIXP16_SHIFT);
  1290. sr = dsdyr*dy + (ts0 << FIXP16_SHIFT);
  1291. tr = dtdyr*dy + (tt0 << FIXP16_SHIFT);
  1292. // compute new starting y
  1293. ystart = min_clip_y;
  1294. // test if we need swap to keep rendering left to right
  1295. if (dxdyr < dxdyl)
  1296. {
  1297. SWAP(dxdyl,dxdyr,temp);
  1298. SWAP(dudyl,dudyr,temp);
  1299. SWAP(dvdyl,dvdyr,temp);
  1300. SWAP(dwdyl,dwdyr,temp);
  1301. SWAP(dzdyl,dzdyr,temp);
  1302. SWAP(dsdyl,dsdyr,temp);
  1303. SWAP(dtdyl,dtdyr,temp);
  1304. SWAP(xl,xr,temp);
  1305. SWAP(ul,ur,temp);
  1306. SWAP(vl,vr,temp);
  1307. SWAP(wl,wr,temp);
  1308. SWAP(zl,zr,temp);
  1309. SWAP(sl,sr,temp);
  1310. SWAP(tl,tr,temp);
  1311. SWAP(x1,x2,temp);
  1312. SWAP(y1,y2,temp);
  1313. SWAP(tu1,tu2,temp);
  1314. SWAP(tv1,tv2,temp);
  1315. SWAP(tw1,tw2,temp);
  1316. SWAP(tz1,tz2,temp);
  1317. SWAP(ts1,ts2,temp);
  1318. SWAP(tt1,tt2,temp);
  1319. // set interpolation restart
  1320. irestart = INTERP_RHS;
  1321. } // end if
  1322. } // end if
  1323. else
  1324. {
  1325. // no initial y clipping
  1326. // compute all deltas
  1327. // LHS
  1328. dyl = (y1 - y0);
  1329. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  1330. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  1331. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  1332. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dyl;   
  1333. dzdyl = ((tz1 - tz0) << FIXP16_SHIFT)/dyl;  
  1334. dsdyl = ((ts1 - ts0) << FIXP16_SHIFT)/dyl;    
  1335. dtdyl = ((tt1 - tt0) << FIXP16_SHIFT)/dyl;   
  1336. // RHS
  1337. dyr = (y2 - y0);
  1338. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dyr;
  1339. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  1340. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  1341. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;
  1342. dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dyr;
  1343. dsdyr = ((ts2 - ts0) << FIXP16_SHIFT)/dyr;   
  1344. dtdyr = ((tt2 - tt0) << FIXP16_SHIFT)/dyr;
  1345. // no clipping y
  1346. // set starting values
  1347. xl = (x0 << FIXP16_SHIFT);
  1348. xr = (x0 << FIXP16_SHIFT);
  1349. ul = (tu0 << FIXP16_SHIFT);
  1350. vl = (tv0 << FIXP16_SHIFT);
  1351. wl = (tw0 << FIXP16_SHIFT);
  1352. zl = (tz0 << FIXP16_SHIFT);
  1353. sl = (ts0 << FIXP16_SHIFT);
  1354. tl = (tt0 << FIXP16_SHIFT);
  1355. ur = (tu0 << FIXP16_SHIFT);
  1356. vr = (tv0 << FIXP16_SHIFT);
  1357. wr = (tw0 << FIXP16_SHIFT);
  1358. zr = (tz0 << FIXP16_SHIFT);
  1359. sr = (ts0 << FIXP16_SHIFT);
  1360. tr = (tt0 << FIXP16_SHIFT);
  1361. // set starting y
  1362. ystart = y0;
  1363. // test if we need swap to keep rendering left to right
  1364. if (dxdyr < dxdyl)
  1365. {
  1366. SWAP(dxdyl,dxdyr,temp);
  1367. SWAP(dudyl,dudyr,temp);
  1368. SWAP(dvdyl,dvdyr,temp);
  1369. SWAP(dwdyl,dwdyr,temp);
  1370. SWAP(dzdyl,dzdyr,temp);
  1371. SWAP(dsdyl,dsdyr,temp);
  1372. SWAP(dtdyl,dtdyr,temp);
  1373. SWAP(xl,xr,temp);
  1374. SWAP(ul,ur,temp);
  1375. SWAP(vl,vr,temp);
  1376. SWAP(wl,wr,temp);
  1377. SWAP(zl,zr,temp);
  1378. SWAP(sl,sr,temp);
  1379. SWAP(tl,tr,temp);
  1380. SWAP(x1,x2,temp);
  1381. SWAP(y1,y2,temp);
  1382. SWAP(tu1,tu2,temp);
  1383. SWAP(tv1,tv2,temp);
  1384. SWAP(tw1,tw2,temp);
  1385. SWAP(tz1,tz2,temp);
  1386. SWAP(ts1,ts2,temp);
  1387. SWAP(tt1,tt2,temp);
  1388. // set interpolation restart
  1389. irestart = INTERP_RHS;
  1390. } // end if
  1391. } // end else
  1392.     // test for horizontal clipping
  1393. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  1394. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  1395. (x2 < min_clip_x) || (x2 > max_clip_x))
  1396. {
  1397.     // clip version
  1398. // x clipping
  1399. // point screen ptr to starting line
  1400. screen_ptr = dest_buffer + (ystart * mem_pitch);
  1401.     // point zbuffer to starting line
  1402.     z_ptr = zbuffer + (ystart * zpitch);
  1403. for (yi = ystart; yi < yend; yi++)
  1404. {
  1405. // compute span endpoints
  1406. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1407. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1408. // compute starting points for u,v,w interpolants
  1409. ui = ul + FIXP16_ROUND_UP;
  1410. vi = vl + FIXP16_ROUND_UP;
  1411. wi = wl + FIXP16_ROUND_UP;
  1412. zi = zl + FIXP16_ROUND_UP;
  1413. si = sl + FIXP16_ROUND_UP;
  1414. ti = tl + FIXP16_ROUND_UP;
  1415. // compute u,v interpolants
  1416. if ((dx = (xend - xstart))>0)
  1417. {
  1418. du = (ur - ul)/dx;
  1419. dv = (vr - vl)/dx;
  1420. dw = (wr - wl)/dx;
  1421. dz = (zr - zl)/dx;
  1422. ds = (sr - sl)/dx;
  1423. dt = (tr - tl)/dx;
  1424. } // end if
  1425. else
  1426. {
  1427. du = (ur - ul);
  1428. dv = (vr - vl);
  1429. dw = (wr - wl);
  1430. dz = (zr - zl);
  1431. ds = (sr - sl);
  1432. dt = (tr - tl);
  1433. } // end else
  1434. ///////////////////////////////////////////////////////////////////////
  1435. // test for x clipping, LHS
  1436. if (xstart < min_clip_x)
  1437. {
  1438. // compute x overlap
  1439. dx = min_clip_x - xstart;
  1440. // slide interpolants over
  1441. ui+=dx*du;
  1442. vi+=dx*dv;
  1443. wi+=dx*dw;
  1444. zi+=dx*dz;
  1445. si+=dx*ds;
  1446. ti+=dx*dt;
  1447. // set x to left clip edge
  1448. xstart = min_clip_x;
  1449. } // end if
  1450. // test for x clipping RHS
  1451. if (xend > max_clip_x)
  1452. xend = max_clip_x;
  1453. ///////////////////////////////////////////////////////////////////////
  1454. // draw span
  1455. for (xi=xstart; xi < xend; xi++)
  1456. {
  1457. // write textel assume 5.6.5
  1458.             // test if z of current pixel is nearer than current z buffer value
  1459.             if (zi < z_ptr[xi])
  1460.             { 
  1461.     // get textel first
  1462.   textel = textmap[(si >> FIXP16_SHIFT) + ((ti >> FIXP16_SHIFT) << texture_shift2)];
  1463.             // extract rgb components
  1464.             r_textel  = ((textel >> 11)       ); 
  1465.             g_textel  = ((textel >> 5)  & 0x3f); 
  1466.             b_textel =   (textel        & 0x1f);
  1467.             // modulate textel with gouraud shading
  1468.             r_textel*=ui; 
  1469.             g_textel*=vi;
  1470.             b_textel*=wi;
  1471.             // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  1472.             // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  1473.             // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  1474.             // and they all cancel out for the most part, but we will need logical anding, we will do
  1475.             // it later when we optimize more...
  1476.             screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  1477.                              alpha_table_src2[((b_textel >> (FIXP16_SHIFT+8)) + 
  1478.                                               ((g_textel >> (FIXP16_SHIFT+8)) << 5) + 
  1479.                                               ((r_textel >> (FIXP16_SHIFT+8)) << 11))];
  1480.             // update z-buffer
  1481.             z_ptr[xi] = zi;   
  1482.             } // end if 
  1483. // interpolate u,v
  1484. ui+=du;
  1485. vi+=dv;
  1486. wi+=dw;
  1487. zi+=dz;
  1488. si+=ds;
  1489. ti+=dt;
  1490. } // end for xi
  1491. // interpolate u,v,w,x along right and left edge
  1492. xl+=dxdyl;
  1493.         ul+=dudyl;
  1494. vl+=dvdyl;
  1495. wl+=dwdyl;
  1496. zl+=dzdyl;
  1497. sl+=dsdyl;
  1498. tl+=dtdyl;
  1499. xr+=dxdyr;
  1500.       ur+=dudyr;
  1501. vr+=dvdyr;
  1502. wr+=dwdyr;
  1503. zr+=dzdyr;
  1504. sr+=dsdyr;
  1505. tr+=dtdyr;
  1506. // advance screen ptr
  1507. screen_ptr+=mem_pitch;
  1508.         // advance zbuffer ptr
  1509.         z_ptr+=zpitch;
  1510. // test for yi hitting second region, if so change interpolant
  1511. if (yi==yrestart)
  1512. {
  1513.     // test interpolation side change flag
  1514. if (irestart == INTERP_LHS)
  1515. {
  1516. // LHS
  1517. dyl = (y2 - y1);
  1518. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  1519. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  1520. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  1521. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;  
  1522. dzdyl = ((tz2 - tz1) << FIXP16_SHIFT)/dyl;  
  1523. dsdyl = ((ts2 - ts1) << FIXP16_SHIFT)/dyl;   
  1524. dtdyl = ((tt2 - tt1) << FIXP16_SHIFT)/dyl;  
  1525. // set starting values
  1526. xl = (x1  << FIXP16_SHIFT);
  1527. ul = (tu1 << FIXP16_SHIFT);
  1528. vl = (tv1 << FIXP16_SHIFT);
  1529. wl = (tw1 << FIXP16_SHIFT);
  1530. zl = (tz1 << FIXP16_SHIFT);
  1531. sl = (ts1 << FIXP16_SHIFT);
  1532. tl = (tt1 << FIXP16_SHIFT);
  1533. // interpolate down on LHS to even up
  1534. xl+=dxdyl;
  1535. ul+=dudyl;
  1536. vl+=dvdyl;
  1537. wl+=dwdyl;
  1538. zl+=dzdyl;
  1539. sl+=dsdyl;
  1540. tl+=dtdyl;
  1541. } // end if
  1542. else
  1543. {
  1544. // RHS
  1545. dyr = (y1 - y2);
  1546. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  1547. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  1548. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  1549. dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;   
  1550. dzdyr = ((tz1 - tz2) << FIXP16_SHIFT)/dyr;   
  1551. dsdyr = ((ts1 - ts2) << FIXP16_SHIFT)/dyr;   
  1552. dtdyr = ((tt1 - tt2) << FIXP16_SHIFT)/dyr;  
  1553. // set starting values
  1554. xr = (x2  << FIXP16_SHIFT);
  1555. ur = (tu2 << FIXP16_SHIFT);
  1556. vr = (tv2 << FIXP16_SHIFT);
  1557. wr = (tw2 << FIXP16_SHIFT);
  1558. zr = (tz2 << FIXP16_SHIFT);
  1559. sr = (ts2 << FIXP16_SHIFT);
  1560. tr = (tt2 << FIXP16_SHIFT);
  1561. // interpolate down on RHS to even up
  1562. xr+=dxdyr;
  1563. ur+=dudyr;
  1564. vr+=dvdyr;
  1565. wr+=dwdyr;
  1566. zr+=dzdyr;
  1567. sr+=dsdyr;
  1568. tr+=dtdyr;
  1569. } // end else
  1570. } // end if
  1571. } // end for y
  1572. } // end if
  1573. else
  1574. {
  1575. // no x clipping
  1576. // point screen ptr to starting line
  1577. screen_ptr = dest_buffer + (ystart * mem_pitch);
  1578.     // point zbuffer to starting line
  1579.     z_ptr = zbuffer + (ystart * zpitch);
  1580. for (yi = ystart; yi < yend; yi++)
  1581. {
  1582. // compute span endpoints
  1583. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1584. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  1585. // compute starting points for u,v,w interpolants
  1586. ui = ul + FIXP16_ROUND_UP;
  1587. vi = vl + FIXP16_ROUND_UP;
  1588. wi = wl + FIXP16_ROUND_UP;
  1589. zi = zl + FIXP16_ROUND_UP;
  1590. si = sl + FIXP16_ROUND_UP;
  1591. ti = tl + FIXP16_ROUND_UP;
  1592. // compute u,v interpolants
  1593. if ((dx = (xend - xstart))>0)
  1594. {
  1595. du = (ur - ul)/dx;
  1596. dv = (vr - vl)/dx;
  1597. dw = (wr - wl)/dx;
  1598. dz = (zr - zl)/dx;
  1599. ds = (sr - sl)/dx;
  1600. dt = (tr - tl)/dx;
  1601. } // end if
  1602. else
  1603. {
  1604. du = (ur - ul);
  1605. dv = (vr - vl);
  1606. dw = (wr - wl);
  1607. dz = (zr - zl);
  1608. ds = (sr - sl);
  1609. dt = (tr - tl);
  1610. } // end else
  1611. // draw span
  1612. for (xi=xstart; xi < xend; xi++)
  1613. {
  1614. // write textel assume 5.6.5
  1615.             // test if z of current pixel is nearer than current z buffer value
  1616.             if (zi < z_ptr[xi])
  1617.             { 
  1618.     // get textel first
  1619.   textel = textmap[(si >> FIXP16_SHIFT) + ((ti >> FIXP16_SHIFT) << texture_shift2)];
  1620.             // extract rgb components
  1621.             r_textel  = ((textel >> 11)       ); 
  1622.             g_textel  = ((textel >> 5)  & 0x3f); 
  1623.             b_textel =   (textel        & 0x1f);
  1624.             // modulate textel with gouraud shading
  1625.             r_textel*=ui; 
  1626.             g_textel*=vi;
  1627.             b_textel*=wi;
  1628.             // finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
  1629.             // hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
  1630.             // the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
  1631.             // and they all cancel out for the most part, but we will need logical anding, we will do
  1632.             // it later when we optimize more...
  1633.             screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  1634.                              alpha_table_src2[((b_textel >> (FIXP16_SHIFT+8)) + 
  1635.                                               ((g_textel >> (FIXP16_SHIFT+8)) << 5) + 
  1636.                                               ((r_textel >> (FIXP16_SHIFT+8)) << 11))];
  1637.             // update z-buffer
  1638.             z_ptr[xi] = zi;   
  1639.             } // end if 
  1640. // interpolate u,v
  1641. ui+=du;
  1642. vi+=dv;
  1643. wi+=dw;
  1644. zi+=dz;
  1645. si+=ds;
  1646. ti+=dt;
  1647. } // end for xi
  1648. // interpolate u,v,w,x along right and left edge
  1649. xl+=dxdyl;
  1650. ul+=dudyl;
  1651. vl+=dvdyl;
  1652. wl+=dwdyl;
  1653. zl+=dzdyl;
  1654. sl+=dsdyl;
  1655. tl+=dtdyl;
  1656. xr+=dxdyr;
  1657. ur+=dudyr;
  1658. vr+=dvdyr;
  1659. wr+=dwdyr;
  1660. zr+=dzdyr;
  1661. sr+=dsdyr;
  1662. tr+=dtdyr;
  1663. // advance screen ptr
  1664. screen_ptr+=mem_pitch;
  1665.         // advance zbuffer ptr
  1666.         z_ptr+=zpitch;
  1667. // test for yi hitting second region, if so change interpolant
  1668. if (yi==yrestart)
  1669. {
  1670. // test interpolation side change flag
  1671. if (irestart == INTERP_LHS)
  1672. {
  1673. // LHS
  1674. dyl = (y2 - y1);
  1675. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  1676. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  1677. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  1678. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;   
  1679. dzdyl = ((tz2 - tz1) << FIXP16_SHIFT)/dyl;  
  1680. dsdyl = ((ts2 - ts1) << FIXP16_SHIFT)/dyl;   
  1681. dtdyl = ((tt2 - tt1) << FIXP16_SHIFT)/dyl;   
  1682. // set starting values
  1683. xl = (x1  << FIXP16_SHIFT);
  1684. ul = (tu1 << FIXP16_SHIFT);
  1685. vl = (tv1 << FIXP16_SHIFT);
  1686. wl = (tw1 << FIXP16_SHIFT);
  1687. zl = (tz1 << FIXP16_SHIFT);
  1688. sl = (ts1 << FIXP16_SHIFT);
  1689. tl = (tt1 << FIXP16_SHIFT);
  1690. // interpolate down on LHS to even up
  1691. xl+=dxdyl;
  1692. ul+=dudyl;
  1693. vl+=dvdyl;
  1694. wl+=dwdyl;
  1695. zl+=dzdyl;
  1696. sl+=dsdyl;
  1697. tl+=dtdyl;
  1698. } // end if
  1699. else
  1700. {
  1701. // RHS
  1702. dyr = (y1 - y2);
  1703. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  1704. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  1705. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  1706. dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;   
  1707. dzdyr = ((tz1 - tz2) << FIXP16_SHIFT)/dyr;   
  1708. dsdyr = ((ts1 - ts2) << FIXP16_SHIFT)/dyr;   
  1709. dtdyr = ((tt1 - tt2) << FIXP16_SHIFT)/dyr;   
  1710. // set starting values
  1711. xr = (x2  << FIXP16_SHIFT);
  1712. ur = (tu2 << FIXP16_SHIFT);
  1713. vr = (tv2 << FIXP16_SHIFT);
  1714. wr = (tw2 << FIXP16_SHIFT);
  1715. zr = (tz2 << FIXP16_SHIFT);
  1716. sr = (ts2 << FIXP16_SHIFT);
  1717. tr = (tt2 << FIXP16_SHIFT);
  1718. // interpolate down on RHS to even up
  1719. xr+=dxdyr;
  1720. ur+=dudyr;
  1721. vr+=dvdyr;
  1722. wr+=dwdyr;
  1723. zr+=dzdyr;
  1724. sr+=dsdyr;
  1725. tr+=dtdyr;
  1726. } // end else
  1727. } // end if
  1728. } // end for y
  1729.    } // end else
  1730. } // end if
  1731. } // end Draw_Textured_TriangleGSZB_Alpha16
  1732. ///////////////////////////////////////////////////////////////////////////////
  1733. void Draw_Gouraud_TriangleZB_Alpha16(POLYF4DV2_PTR face,   // ptr to face
  1734.                                      UCHAR *_dest_buffer,   // pointer to video buffer
  1735.                                      int mem_pitch,         // bytes per line, 320, 640 etc.
  1736.                                      UCHAR *_zbuffer,       // pointer to z-buffer
  1737.                                      int zpitch,            // bytes per line of zbuffer
  1738.                                      int alpha)
  1739. {
  1740. // this function draws a gouraud shaded polygon, based on the affine texture mapper, instead
  1741. // of interpolating the texture coordinates, we simply interpolate the (R,G,B) values across
  1742. // the polygons, I simply needed at another interpolant, I have mapped u->red, v->green, w->blue
  1743. // also a new interpolant for z buffering has been added
  1744. int v0=0,
  1745.     v1=1,
  1746. v2=2,
  1747. temp=0,
  1748. tri_type = TRI_TYPE_NONE,
  1749. irestart = INTERP_LHS;
  1750. int dx,dy,dyl,dyr,      // general deltas
  1751.     u,v,w,z,
  1752.     du,dv,dw,dz,
  1753.     xi,yi,              // the current interpolated x,y
  1754. ui,vi,wi,zi,        // the current interpolated u,v,w,z
  1755. index_x,index_y,    // looping vars
  1756. x,y,                // hold general x,y
  1757. xstart,
  1758. xend,
  1759. ystart,
  1760. yrestart,
  1761. yend,
  1762. xl,                 
  1763. dxdyl,              
  1764. xr,
  1765. dxdyr,             
  1766.     dudyl,    
  1767. ul,
  1768. dvdyl,   
  1769. vl,
  1770. dwdyl,   
  1771. wl,
  1772. dzdyl,   
  1773. zl,
  1774. dudyr,
  1775. ur,
  1776. dvdyr,
  1777. vr,
  1778. dwdyr,
  1779. wr,
  1780. dzdyr,
  1781. zr;
  1782. int x0,y0,tu0,tv0,tw0,tz0,    // cached vertices
  1783. x1,y1,tu1,tv1,tw1,tz1,
  1784. x2,y2,tu2,tv2,tw2,tz2;
  1785. int r_base0, g_base0, b_base0,
  1786.     r_base1, g_base1, b_base1,
  1787.     r_base2, g_base2, b_base2;
  1788. USHORT *screen_ptr  = NULL,
  1789.    *screen_line = NULL,
  1790.    *textmap     = NULL,
  1791.        *dest_buffer = (USHORT *)_dest_buffer;
  1792. UINT  *z_ptr = NULL,
  1793.       *zbuffer = (UINT *)_zbuffer;
  1794. #ifdef DEBUG_ON
  1795. // track rendering stats
  1796.     debug_polys_rendered_per_frame++;
  1797. #endif
  1798. // adjust memory pitch to words, divide by 2
  1799. mem_pitch >>=1;
  1800. // adjust zbuffer pitch for 32 bit alignment
  1801. zpitch >>= 2;
  1802. // apply fill convention to coordinates
  1803. face->tvlist[0].x = (int)(face->tvlist[0].x+0.5);
  1804. face->tvlist[0].y = (int)(face->tvlist[0].y+0.5);
  1805. face->tvlist[1].x = (int)(face->tvlist[1].x+0.5);
  1806. face->tvlist[1].y = (int)(face->tvlist[1].y+0.5);
  1807. face->tvlist[2].x = (int)(face->tvlist[2].x+0.5);
  1808. face->tvlist[2].y = (int)(face->tvlist[2].y+0.5);
  1809. // first trivial clipping rejection tests 
  1810. if (((face->tvlist[0].y < min_clip_y)  && 
  1811.  (face->tvlist[1].y < min_clip_y)  &&
  1812.  (face->tvlist[2].y < min_clip_y)) ||
  1813. ((face->tvlist[0].y > max_clip_y)  && 
  1814.  (face->tvlist[1].y > max_clip_y)  &&
  1815.  (face->tvlist[2].y > max_clip_y)) ||
  1816. ((face->tvlist[0].x < min_clip_x)  && 
  1817.  (face->tvlist[1].x < min_clip_x)  &&
  1818.  (face->tvlist[2].x < min_clip_x)) ||
  1819. ((face->tvlist[0].x > max_clip_x)  && 
  1820.  (face->tvlist[1].x > max_clip_x)  &&
  1821.  (face->tvlist[2].x > max_clip_x)))
  1822.    return;
  1823. // sort vertices
  1824. if (face->tvlist[v1].y < face->tvlist[v0].y) 
  1825. {SWAP(v0,v1,temp);} 
  1826. if (face->tvlist[v2].y < face->tvlist[v0].y) 
  1827. {SWAP(v0,v2,temp);}
  1828. if (face->tvlist[v2].y < face->tvlist[v1].y) 
  1829. {SWAP(v1,v2,temp);}
  1830. // now test for trivial flat sided cases
  1831. if (FCMP(face->tvlist[v0].y, face->tvlist[v1].y))
  1832. // set triangle type
  1833. tri_type = TRI_TYPE_FLAT_TOP;
  1834. // sort vertices left to right
  1835. if (face->tvlist[v1].x < face->tvlist[v0].x) 
  1836. {SWAP(v0,v1,temp);}
  1837. } // end if
  1838. else
  1839. // now test for trivial flat sided cases
  1840. if (FCMP(face->tvlist[v1].y, face->tvlist[v2].y) )
  1841. // set triangle type
  1842. tri_type = TRI_TYPE_FLAT_BOTTOM;
  1843. // sort vertices left to right
  1844. if (face->tvlist[v2].x < face->tvlist[v1].x) 
  1845. {SWAP(v1,v2,temp);}
  1846. } // end if
  1847. else
  1848. {
  1849. // must be a general triangle
  1850. tri_type = TRI_TYPE_GENERAL;
  1851. } // end else
  1852. // assume 5.6.5 format -- sorry!
  1853. // we can't afford a function call in the inner loops, so we must write 
  1854. // two hard coded versions, if we want support for both 5.6.5, and 5.5.5
  1855. _RGB565FROM16BIT(face->lit_color[v0], &r_base0, &g_base0, &b_base0);
  1856. _RGB565FROM16BIT(face->lit_color[v1], &r_base1, &g_base1, &b_base1);
  1857. _RGB565FROM16BIT(face->lit_color[v2], &r_base2, &g_base2, &b_base2);
  1858. // scale to 8 bit 
  1859. r_base0 <<= 3;
  1860. g_base0 <<= 2;
  1861. b_base0 <<= 3;
  1862. // scale to 8 bit 
  1863. r_base1 <<= 3;
  1864. g_base1 <<= 2;
  1865. b_base1 <<= 3;
  1866. // scale to 8 bit 
  1867. r_base2 <<= 3;
  1868. g_base2 <<= 2;
  1869. b_base2 <<= 3;
  1870. // extract vertices for processing, now that we have order
  1871. x0  = (int)(face->tvlist[v0].x+0.0);
  1872. y0  = (int)(face->tvlist[v0].y+0.0);
  1873. tz0 = (int)(face->tvlist[v0].z+0.5);
  1874. tu0 = r_base0;
  1875. tv0 = g_base0; 
  1876. tw0 = b_base0; 
  1877. x1  = (int)(face->tvlist[v1].x+0.0);
  1878. y1  = (int)(face->tvlist[v1].y+0.0);
  1879. tz1 = (int)(face->tvlist[v1].z+0.5);
  1880. tu1 = r_base1;
  1881. tv1 = g_base1; 
  1882. tw1 = b_base1; 
  1883. x2  = (int)(face->tvlist[v2].x+0.0);
  1884. y2  = (int)(face->tvlist[v2].y+0.0);
  1885. tz2 = (int)(face->tvlist[v2].z+0.5);
  1886. tu2 = r_base2; 
  1887. tv2 = g_base2; 
  1888. tw2 = b_base2; 
  1889. // degenerate triangle
  1890. if ( ((x0 == x1) && (x1 == x2)) || ((y0 ==  y1) && (y1 == y2)))
  1891.    return;
  1892. // assign both source1 and source2 alpha tables based on polygon alpha level
  1893. USHORT *alpha_table_src1 = (USHORT *)&rgb_alpha_table[(NUM_ALPHA_LEVELS-1) - alpha][0];
  1894. USHORT *alpha_table_src2 = (USHORT *)&rgb_alpha_table[alpha][0];
  1895. // set interpolation restart value
  1896. yrestart = y1;
  1897. // what kind of triangle
  1898. if (tri_type & TRI_TYPE_FLAT_MASK)
  1899. {
  1900. if (tri_type == TRI_TYPE_FLAT_TOP)
  1901. {
  1902. // compute all deltas
  1903. dy = (y2 - y0);
  1904. dxdyl = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  1905. dudyl = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  1906. dvdyl = ((tv2 - tv0) << FIXP16_SHIFT)/dy;    
  1907. dwdyl = ((tw2 - tw0) << FIXP16_SHIFT)/dy;  
  1908. dzdyl = ((tz2 - tz0) << FIXP16_SHIFT)/dy; 
  1909. dxdyr = ((x2 - x1)   << FIXP16_SHIFT)/dy;
  1910. dudyr = ((tu2 - tu1) << FIXP16_SHIFT)/dy;  
  1911. dvdyr = ((tv2 - tv1) << FIXP16_SHIFT)/dy;   
  1912. dwdyr = ((tw2 - tw1) << FIXP16_SHIFT)/dy;   
  1913. dzdyr = ((tz2 - tz1) << FIXP16_SHIFT)/dy;   
  1914. // test for y clipping
  1915. if (y0 < min_clip_y)
  1916. {
  1917. // compute overclip
  1918. dy = (min_clip_y - y0);
  1919. // computer new LHS starting values
  1920. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  1921. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  1922. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  1923. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  1924. zl = dzdyl*dy + (tz0 << FIXP16_SHIFT);
  1925. // compute new RHS starting values
  1926. xr = dxdyr*dy + (x1  << FIXP16_SHIFT);
  1927. ur = dudyr*dy + (tu1 << FIXP16_SHIFT);
  1928. vr = dvdyr*dy + (tv1 << FIXP16_SHIFT);
  1929. wr = dwdyr*dy + (tw1 << FIXP16_SHIFT);
  1930. zr = dzdyr*dy + (tz1 << FIXP16_SHIFT);
  1931. // compute new starting y
  1932. ystart = min_clip_y;
  1933. } // end if
  1934. else
  1935. {
  1936. // no clipping
  1937. // set starting values
  1938. xl = (x0 << FIXP16_SHIFT);
  1939. xr = (x1 << FIXP16_SHIFT);
  1940. ul = (tu0 << FIXP16_SHIFT);
  1941. vl = (tv0 << FIXP16_SHIFT);
  1942. wl = (tw0 << FIXP16_SHIFT);
  1943. zl = (tz0 << FIXP16_SHIFT);
  1944. ur = (tu1 << FIXP16_SHIFT);
  1945. vr = (tv1 << FIXP16_SHIFT);
  1946. wr = (tw1 << FIXP16_SHIFT);
  1947. zr = (tz1 << FIXP16_SHIFT);
  1948. // set starting y
  1949. ystart = y0;
  1950. } // end else
  1951. } // end if flat top
  1952. else
  1953. {
  1954. // must be flat bottom
  1955. // compute all deltas
  1956. dy = (y1 - y0);
  1957. dxdyl = ((x1 - x0)   << FIXP16_SHIFT)/dy;
  1958. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dy;  
  1959. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dy;    
  1960. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dy; 
  1961. dzdyl = ((tz1 - tz0) << FIXP16_SHIFT)/dy; 
  1962. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dy;
  1963. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dy;  
  1964. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dy;   
  1965. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dy;   
  1966. dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dy;   
  1967. // test for y clipping
  1968. if (y0 < min_clip_y)
  1969. {
  1970. // compute overclip
  1971. dy = (min_clip_y - y0);
  1972. // computer new LHS starting values
  1973. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  1974. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  1975. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  1976. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  1977. zl = dzdyl*dy + (tz0 << FIXP16_SHIFT);
  1978. // compute new RHS starting values
  1979. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  1980. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  1981. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  1982. wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
  1983. zr = dzdyr*dy + (tz0 << FIXP16_SHIFT);
  1984. // compute new starting y
  1985. ystart = min_clip_y;
  1986. } // end if
  1987. else
  1988. {
  1989. // no clipping
  1990. // set starting values
  1991. xl = (x0 << FIXP16_SHIFT);
  1992. xr = (x0 << FIXP16_SHIFT);
  1993. ul = (tu0 << FIXP16_SHIFT);
  1994. vl = (tv0 << FIXP16_SHIFT);
  1995. wl = (tw0 << FIXP16_SHIFT);
  1996. zl = (tz0 << FIXP16_SHIFT);
  1997. ur = (tu0 << FIXP16_SHIFT);
  1998. vr = (tv0 << FIXP16_SHIFT);
  1999. wr = (tw0 << FIXP16_SHIFT);
  2000. zr = (tz0 << FIXP16_SHIFT);
  2001. // set starting y
  2002. ystart = y0;
  2003. } // end else
  2004. } // end else flat bottom
  2005. // test for bottom clip, always
  2006. if ((yend = y2) > max_clip_y)
  2007. yend = max_clip_y;
  2008.     // test for horizontal clipping
  2009. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  2010. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  2011. (x2 < min_clip_x) || (x2 > max_clip_x))
  2012. {
  2013.     // clip version
  2014. // point screen ptr to starting line
  2015. screen_ptr = dest_buffer + (ystart * mem_pitch);
  2016.     // point zbuffer to starting line
  2017.     z_ptr = zbuffer + (ystart * zpitch);
  2018. for (yi = ystart; yi < yend; yi++)
  2019. {
  2020. // compute span endpoints
  2021. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2022. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2023. // compute starting points for u,v,w interpolants
  2024. ui = ul + FIXP16_ROUND_UP;
  2025. vi = vl + FIXP16_ROUND_UP;
  2026. wi = wl + FIXP16_ROUND_UP;
  2027. zi = zl + FIXP16_ROUND_UP;
  2028. // compute u,v interpolants
  2029. if ((dx = (xend - xstart))>0)
  2030. {
  2031. du = (ur - ul)/dx;
  2032. dv = (vr - vl)/dx;
  2033. dw = (wr - wl)/dx;
  2034. dz = (zr - zl)/dx;
  2035. } // end if
  2036. else
  2037. {
  2038. du = (ur - ul);
  2039. dv = (vr - vl);
  2040. dw = (wr - wl);
  2041. dz = (zr - zl);
  2042. } // end else
  2043. ///////////////////////////////////////////////////////////////////////
  2044. // test for x clipping, LHS
  2045. if (xstart < min_clip_x)
  2046. {
  2047. // compute x overlap
  2048. dx = min_clip_x - xstart;
  2049. // slide interpolants over
  2050. ui+=dx*du;
  2051. vi+=dx*dv;
  2052. wi+=dx*dw;
  2053. zi+=dx*dz;
  2054. // reset vars
  2055. xstart = min_clip_x;
  2056. } // end if
  2057. // test for x clipping RHS
  2058. if (xend > max_clip_x)
  2059. xend = max_clip_x;
  2060. ///////////////////////////////////////////////////////////////////////
  2061. // draw span
  2062. for (xi=xstart; xi < xend; xi++)
  2063. {
  2064.             // test if z of current pixel is nearer than current z buffer value
  2065.             if (zi < z_ptr[xi])
  2066.                {
  2067.    // write textel assume 5.6.5
  2068.                screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  2069.                              alpha_table_src2[((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3))];
  2070.                // update z-buffer
  2071.                z_ptr[xi] = zi;           
  2072.                } // end if
  2073. // interpolate u,v,w,z
  2074. ui+=du;
  2075. vi+=dv;
  2076. wi+=dw;
  2077. zi+=dz;
  2078. } // end for xi
  2079. // interpolate u,v,w,z,x along right and left edge
  2080. xl+=dxdyl;
  2081. ul+=dudyl;
  2082. vl+=dvdyl;
  2083. wl+=dwdyl;
  2084. zl+=dzdyl;
  2085. xr+=dxdyr;
  2086. ur+=dudyr;
  2087. vr+=dvdyr;
  2088. wr+=dwdyr;
  2089. zr+=dzdyr;
  2090.  
  2091. // advance screen ptr
  2092. screen_ptr+=mem_pitch;
  2093.         // advance z-buffer ptr
  2094.         z_ptr+=zpitch;
  2095. } // end for y
  2096. } // end if clip
  2097. else
  2098. {
  2099. // non-clip version
  2100. // point screen ptr to starting line
  2101. screen_ptr = dest_buffer + (ystart * mem_pitch);
  2102.     // point zbuffer to starting line
  2103.     z_ptr = zbuffer + (ystart * zpitch);
  2104. for (yi = ystart; yi < yend; yi++)
  2105. {
  2106. // compute span endpoints
  2107. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2108. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2109. // compute starting points for u,v,w interpolants
  2110. ui = ul + FIXP16_ROUND_UP;
  2111. vi = vl + FIXP16_ROUND_UP;
  2112. wi = wl + FIXP16_ROUND_UP;
  2113. zi = zl + FIXP16_ROUND_UP;
  2114. // compute u,v interpolants
  2115. if ((dx = (xend - xstart))>0)
  2116. {
  2117. du = (ur - ul)/dx;
  2118. dv = (vr - vl)/dx;
  2119. dw = (wr - wl)/dx;
  2120. dz = (zr - zl)/dx;
  2121. } // end if
  2122. else
  2123. {
  2124. du = (ur - ul);
  2125. dv = (vr - vl);
  2126. dw = (wr - wl);
  2127. dz = (zr - zl);
  2128. } // end else
  2129. // draw span
  2130. for (xi=xstart; xi < xend; xi++)
  2131. {
  2132.             // test if z of current pixel is nearer than current z buffer value
  2133.             if (zi < z_ptr[xi])
  2134.                {
  2135.    // write textel 5.6.5
  2136.            screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  2137.                              alpha_table_src2[((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3))];
  2138.                // update z-buffer
  2139.                z_ptr[xi] = zi;           
  2140.                } // end if
  2141. // interpolate u,v,w,z
  2142. ui+=du;
  2143. vi+=dv;
  2144. wi+=dw;
  2145. zi+=dz;
  2146. } // end for xi
  2147. // interpolate u,v,w,x along right and left edge
  2148. xl+=dxdyl;
  2149. ul+=dudyl;
  2150. vl+=dvdyl;
  2151. wl+=dwdyl;
  2152. zl+=dzdyl;
  2153. xr+=dxdyr;
  2154. ur+=dudyr;
  2155. vr+=dvdyr;
  2156. wr+=dwdyr;
  2157. zr+=dzdyr;
  2158. // advance screen ptr
  2159. screen_ptr+=mem_pitch;
  2160.         // advance z-buffer ptr
  2161.         z_ptr+=zpitch;
  2162. } // end for y
  2163. } // end if non-clipped
  2164. } // end if
  2165. else
  2166. if (tri_type==TRI_TYPE_GENERAL)
  2167. {
  2168. // first test for bottom clip, always
  2169. if ((yend = y2) > max_clip_y)
  2170. yend = max_clip_y;
  2171. // pre-test y clipping status
  2172. if (y1 < min_clip_y)
  2173. {
  2174. // compute all deltas
  2175. // LHS
  2176. dyl = (y2 - y1);
  2177. dxdyl = ((x2  - x1)  << FIXP16_SHIFT)/dyl;
  2178. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  2179. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;    
  2180. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;  
  2181. dzdyl = ((tz2 - tz1) << FIXP16_SHIFT)/dyl; 
  2182. // RHS
  2183. dyr = (y2 - y0);
  2184. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  2185. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  2186. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  2187. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;   
  2188. dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dyr;  
  2189. // compute overclip
  2190. dyr = (min_clip_y - y0);
  2191. dyl = (min_clip_y - y1);
  2192. // computer new LHS starting values
  2193. xl = dxdyl*dyl + (x1  << FIXP16_SHIFT);
  2194. ul = dudyl*dyl + (tu1 << FIXP16_SHIFT);
  2195. vl = dvdyl*dyl + (tv1 << FIXP16_SHIFT);
  2196. wl = dwdyl*dyl + (tw1 << FIXP16_SHIFT);
  2197. zl = dzdyl*dyl + (tz1 << FIXP16_SHIFT);
  2198. // compute new RHS starting values
  2199. xr = dxdyr*dyr + (x0  << FIXP16_SHIFT);
  2200. ur = dudyr*dyr + (tu0 << FIXP16_SHIFT);
  2201. vr = dvdyr*dyr + (tv0 << FIXP16_SHIFT);
  2202. wr = dwdyr*dyr + (tw0 << FIXP16_SHIFT);
  2203. zr = dzdyr*dyr + (tz0 << FIXP16_SHIFT);
  2204. // compute new starting y
  2205. ystart = min_clip_y;
  2206. // test if we need swap to keep rendering left to right
  2207. if (dxdyr > dxdyl)
  2208. {
  2209. SWAP(dxdyl,dxdyr,temp);
  2210. SWAP(dudyl,dudyr,temp);
  2211. SWAP(dvdyl,dvdyr,temp);
  2212. SWAP(dwdyl,dwdyr,temp);
  2213. SWAP(dzdyl,dzdyr,temp);
  2214. SWAP(xl,xr,temp);
  2215. SWAP(ul,ur,temp);
  2216. SWAP(vl,vr,temp);
  2217. SWAP(wl,wr,temp);
  2218. SWAP(zl,zr,temp);
  2219. SWAP(x1,x2,temp);
  2220. SWAP(y1,y2,temp);
  2221. SWAP(tu1,tu2,temp);
  2222. SWAP(tv1,tv2,temp);
  2223. SWAP(tw1,tw2,temp);
  2224. SWAP(tz1,tz2,temp);
  2225. // set interpolation restart
  2226. irestart = INTERP_RHS;
  2227. } // end if
  2228. } // end if
  2229. else
  2230. if (y0 < min_clip_y)
  2231. {
  2232. // compute all deltas
  2233. // LHS
  2234. dyl = (y1 - y0);
  2235. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  2236. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  2237. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  2238. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dyl; 
  2239. dzdyl = ((tz1 - tz0) << FIXP16_SHIFT)/dyl; 
  2240. // RHS
  2241. dyr = (y2 - y0);
  2242. dxdyr = ((x2  - x0)  << FIXP16_SHIFT)/dyr;
  2243. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  2244. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  2245. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;   
  2246. dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dyr;  
  2247. // compute overclip
  2248. dy = (min_clip_y - y0);
  2249. // computer new LHS starting values
  2250. xl = dxdyl*dy + (x0  << FIXP16_SHIFT);
  2251. ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
  2252. vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
  2253. wl = dwdyl*dy + (tw0 << FIXP16_SHIFT);
  2254. zl = dzdyl*dy + (tz0 << FIXP16_SHIFT);
  2255. // compute new RHS starting values
  2256. xr = dxdyr*dy + (x0  << FIXP16_SHIFT);
  2257. ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
  2258. vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
  2259. wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
  2260. zr = dzdyr*dy + (tz0 << FIXP16_SHIFT);
  2261. // compute new starting y
  2262. ystart = min_clip_y;
  2263. // test if we need swap to keep rendering left to right
  2264. if (dxdyr < dxdyl)
  2265. {
  2266. SWAP(dxdyl,dxdyr,temp);
  2267. SWAP(dudyl,dudyr,temp);
  2268. SWAP(dvdyl,dvdyr,temp);
  2269. SWAP(dwdyl,dwdyr,temp);
  2270. SWAP(dzdyl,dzdyr,temp);
  2271. SWAP(xl,xr,temp);
  2272. SWAP(ul,ur,temp);
  2273. SWAP(vl,vr,temp);
  2274. SWAP(wl,wr,temp);
  2275. SWAP(zl,zr,temp);
  2276. SWAP(x1,x2,temp);
  2277. SWAP(y1,y2,temp);
  2278. SWAP(tu1,tu2,temp);
  2279. SWAP(tv1,tv2,temp);
  2280. SWAP(tw1,tw2,temp);
  2281. SWAP(tz1,tz2,temp);
  2282. // set interpolation restart
  2283. irestart = INTERP_RHS;
  2284. } // end if
  2285. } // end if
  2286. else
  2287. {
  2288. // no initial y clipping
  2289. // compute all deltas
  2290. // LHS
  2291. dyl = (y1 - y0);
  2292. dxdyl = ((x1  - x0)  << FIXP16_SHIFT)/dyl;
  2293. dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;  
  2294. dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;    
  2295. dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dyl;   
  2296. dzdyl = ((tz1 - tz0) << FIXP16_SHIFT)/dyl; 
  2297. // RHS
  2298. dyr = (y2 - y0);
  2299. dxdyr = ((x2 - x0)   << FIXP16_SHIFT)/dyr;
  2300. dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;  
  2301. dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;   
  2302. dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;
  2303. dzdyr = ((tz2 - tz0) << FIXP16_SHIFT)/dyr;
  2304. // no clipping y
  2305. // set starting values
  2306. xl = (x0 << FIXP16_SHIFT);
  2307. xr = (x0 << FIXP16_SHIFT);
  2308. ul = (tu0 << FIXP16_SHIFT);
  2309. vl = (tv0 << FIXP16_SHIFT);
  2310. wl = (tw0 << FIXP16_SHIFT);
  2311. zl = (tz0 << FIXP16_SHIFT);
  2312. ur = (tu0 << FIXP16_SHIFT);
  2313. vr = (tv0 << FIXP16_SHIFT);
  2314. wr = (tw0 << FIXP16_SHIFT);
  2315. zr = (tz0 << FIXP16_SHIFT);
  2316. // set starting y
  2317. ystart = y0;
  2318. // test if we need swap to keep rendering left to right
  2319. if (dxdyr < dxdyl)
  2320. {
  2321. SWAP(dxdyl,dxdyr,temp);
  2322. SWAP(dudyl,dudyr,temp);
  2323. SWAP(dvdyl,dvdyr,temp);
  2324. SWAP(dwdyl,dwdyr,temp);
  2325. SWAP(dzdyl,dzdyr,temp);
  2326. SWAP(xl,xr,temp);
  2327. SWAP(ul,ur,temp);
  2328. SWAP(vl,vr,temp);
  2329. SWAP(wl,wr,temp);
  2330. SWAP(zl,zr,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. SWAP(tz1,tz2,temp);
  2337. // set interpolation restart
  2338. irestart = INTERP_RHS;
  2339. } // end if
  2340. } // end else
  2341.     // test for horizontal clipping
  2342. if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
  2343. (x1 < min_clip_x) || (x1 > max_clip_x) ||
  2344. (x2 < min_clip_x) || (x2 > max_clip_x))
  2345. {
  2346.     // clip version
  2347. // x clipping
  2348. // point screen ptr to starting line
  2349. screen_ptr = dest_buffer + (ystart * mem_pitch);
  2350.     // point zbuffer to starting line
  2351.     z_ptr = zbuffer + (ystart * zpitch);
  2352. for (yi = ystart; yi < yend; yi++)
  2353. {
  2354. // compute span endpoints
  2355. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2356. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2357. // compute starting points for u,v,w interpolants
  2358. ui = ul + FIXP16_ROUND_UP;
  2359. vi = vl + FIXP16_ROUND_UP;
  2360. wi = wl + FIXP16_ROUND_UP;
  2361. zi = zl + FIXP16_ROUND_UP;
  2362. // compute u,v interpolants
  2363. if ((dx = (xend - xstart))>0)
  2364. {
  2365. du = (ur - ul)/dx;
  2366. dv = (vr - vl)/dx;
  2367. dw = (wr - wl)/dx;
  2368. dz = (zr - zl)/dx;
  2369. } // end if
  2370. else
  2371. {
  2372. du = (ur - ul);
  2373. dv = (vr - vl);
  2374. dw = (wr - wl);
  2375. dz = (zr - zl);
  2376. } // end else
  2377. ///////////////////////////////////////////////////////////////////////
  2378. // test for x clipping, LHS
  2379. if (xstart < min_clip_x)
  2380. {
  2381. // compute x overlap
  2382. dx = min_clip_x - xstart;
  2383. // slide interpolants over
  2384. ui+=dx*du;
  2385. vi+=dx*dv;
  2386. wi+=dx*dw;
  2387. zi+=dx*dz;
  2388. // set x to left clip edge
  2389. xstart = min_clip_x;
  2390. } // end if
  2391. // test for x clipping RHS
  2392. if (xend > max_clip_x)
  2393. xend = max_clip_x;
  2394. ///////////////////////////////////////////////////////////////////////
  2395. // draw span
  2396. for (xi=xstart; xi < xend; xi++)
  2397. {
  2398.             // test if z of current pixel is nearer than current z buffer value
  2399.             if (zi < z_ptr[xi])
  2400.                {
  2401.    // write textel assume 5.6.5
  2402.            screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  2403.                              alpha_table_src2[((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3))];
  2404.                // update z-buffer
  2405.                z_ptr[xi] = zi;           
  2406.                } // end if
  2407. // interpolate u,v,w,z
  2408. ui+=du;
  2409. vi+=dv;
  2410. wi+=dw;
  2411. zi+=dz;
  2412. } // end for xi
  2413. // interpolate u,v,w,z,x along right and left edge
  2414. xl+=dxdyl;
  2415.         ul+=dudyl;
  2416. vl+=dvdyl;
  2417. wl+=dwdyl;
  2418. zl+=dzdyl;
  2419. xr+=dxdyr;
  2420.       ur+=dudyr;
  2421. vr+=dvdyr;
  2422. wr+=dwdyr;
  2423. zr+=dzdyr;
  2424. // advance screen ptr
  2425. screen_ptr+=mem_pitch;
  2426.         // advance z-buffer ptr
  2427.         z_ptr+=zpitch;
  2428. // test for yi hitting second region, if so change interpolant
  2429. if (yi==yrestart)
  2430. {
  2431.     // test interpolation side change flag
  2432. if (irestart == INTERP_LHS)
  2433. {
  2434. // LHS
  2435. dyl = (y2 - y1);
  2436. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  2437. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  2438. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  2439. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;  
  2440. dzdyl = ((tz2 - tz1) << FIXP16_SHIFT)/dyl;  
  2441. // set starting values
  2442. xl = (x1  << FIXP16_SHIFT);
  2443. ul = (tu1 << FIXP16_SHIFT);
  2444. vl = (tv1 << FIXP16_SHIFT);
  2445. wl = (tw1 << FIXP16_SHIFT);
  2446. zl = (tz1 << FIXP16_SHIFT);
  2447. // interpolate down on LHS to even up
  2448. xl+=dxdyl;
  2449. ul+=dudyl;
  2450. vl+=dvdyl;
  2451. wl+=dwdyl;
  2452. zl+=dzdyl;
  2453. } // end if
  2454. else
  2455. {
  2456. // RHS
  2457. dyr = (y1 - y2);
  2458. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  2459. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  2460. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  2461. dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;   
  2462. dzdyr = ((tz1 - tz2) << FIXP16_SHIFT)/dyr;   
  2463. // set starting values
  2464. xr = (x2  << FIXP16_SHIFT);
  2465. ur = (tu2 << FIXP16_SHIFT);
  2466. vr = (tv2 << FIXP16_SHIFT);
  2467. wr = (tw2 << FIXP16_SHIFT);
  2468. zr = (tz2 << FIXP16_SHIFT);
  2469. // interpolate down on RHS to even up
  2470. xr+=dxdyr;
  2471. ur+=dudyr;
  2472. vr+=dvdyr;
  2473. wr+=dwdyr;
  2474. zr+=dzdyr;
  2475. } // end else
  2476. } // end if
  2477. } // end for y
  2478. } // end if
  2479. else
  2480. {
  2481. // no x clipping
  2482. // point screen ptr to starting line
  2483. screen_ptr = dest_buffer + (ystart * mem_pitch);
  2484.     // point zbuffer to starting line
  2485.     z_ptr = zbuffer + (ystart * zpitch);
  2486. for (yi = ystart; yi < yend; yi++)
  2487. {
  2488. // compute span endpoints
  2489. xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2490. xend   = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
  2491. // compute starting points for u,v,w,z interpolants
  2492. ui = ul + FIXP16_ROUND_UP;
  2493. vi = vl + FIXP16_ROUND_UP;
  2494. wi = wl + FIXP16_ROUND_UP;
  2495. zi = zl + FIXP16_ROUND_UP;
  2496. // compute u,v interpolants
  2497. if ((dx = (xend - xstart))>0)
  2498. {
  2499. du = (ur - ul)/dx;
  2500. dv = (vr - vl)/dx;
  2501. dw = (wr - wl)/dx;
  2502. dz = (zr - zl)/dx;
  2503. } // end if
  2504. else
  2505. {
  2506. du = (ur - ul);
  2507. dv = (vr - vl);
  2508. dw = (wr - wl);
  2509. dz = (zr - zl);
  2510. } // end else
  2511. // draw span
  2512. for (xi=xstart; xi < xend; xi++)
  2513. {
  2514.             // test if z of current pixel is nearer than current z buffer value
  2515.             if (zi < z_ptr[xi])
  2516.                {
  2517.    // write textel assume 5.6.5
  2518.                screen_ptr[xi] = alpha_table_src1[screen_ptr[xi]] + 
  2519.                              alpha_table_src2[((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3))];
  2520.                // update z-buffer
  2521.                z_ptr[xi] = zi;           
  2522.                } // end if
  2523. // interpolate u,v,w,z
  2524. ui+=du;
  2525. vi+=dv;
  2526. wi+=dw;
  2527. zi+=dz;
  2528. } // end for xi
  2529. // interpolate u,v,w,x,z along right and left edge
  2530. xl+=dxdyl;
  2531. ul+=dudyl;
  2532. vl+=dvdyl;
  2533. wl+=dwdyl;
  2534. zl+=dzdyl;
  2535. xr+=dxdyr;
  2536. ur+=dudyr;
  2537. vr+=dvdyr;
  2538. wr+=dwdyr;
  2539. zr+=dzdyr;
  2540. // advance screen ptr
  2541. screen_ptr+=mem_pitch;
  2542.         // advance z-buffer ptr
  2543.         z_ptr+=zpitch;
  2544. // test for yi hitting second region, if so change interpolant
  2545. if (yi==yrestart)
  2546. {
  2547. // test interpolation side change flag
  2548. if (irestart == INTERP_LHS)
  2549. {
  2550. // LHS
  2551. dyl = (y2 - y1);
  2552. dxdyl = ((x2 - x1)   << FIXP16_SHIFT)/dyl;
  2553. dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;  
  2554. dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;   
  2555. dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;   
  2556. dzdyl = ((tz2 - tz1) << FIXP16_SHIFT)/dyl;   
  2557. // set starting values
  2558. xl = (x1  << FIXP16_SHIFT);
  2559. ul = (tu1 << FIXP16_SHIFT);
  2560. vl = (tv1 << FIXP16_SHIFT);
  2561. wl = (tw1 << FIXP16_SHIFT);
  2562. zl = (tz1 << FIXP16_SHIFT);
  2563. // interpolate down on LHS to even up
  2564. xl+=dxdyl;
  2565. ul+=dudyl;
  2566. vl+=dvdyl;
  2567. wl+=dwdyl;
  2568. zl+=dzdyl;
  2569. } // end if
  2570. else
  2571. {
  2572. // RHS
  2573. dyr = (y1 - y2);
  2574. dxdyr = ((x1 - x2)   << FIXP16_SHIFT)/dyr;
  2575. dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;  
  2576. dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;   
  2577. dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;   
  2578. dzdyr = ((tz1 - tz2) << FIXP16_SHIFT)/dyr;   
  2579. // set starting values
  2580. xr = (x2  << FIXP16_SHIFT);
  2581. ur = (tu2 << FIXP16_SHIFT);
  2582. vr = (tv2 << FIXP16_SHIFT);
  2583. wr = (tw2 << FIXP16_SHIFT);
  2584. zr = (tz2 << FIXP16_SHIFT);
  2585. // interpolate down on RHS to even up
  2586. xr+=dxdyr;
  2587. ur+=dudyr;
  2588. vr+=dvdyr;
  2589. wr+=dwdyr;
  2590. zr+=dzdyr;
  2591. } // end else
  2592. } // end if
  2593. } // end for y
  2594.    } // end else
  2595. } // end if
  2596. } // end Draw_Gouraud_TriangleZB_Alpha16
  2597. ///////////////////////////////////////////////////////////////////////////////
  2598. void Draw_RENDERLIST4DV2_SolidZB_Alpha16(RENDERLIST4DV2_PTR rend_list, 
  2599.                                          UCHAR *video_buffer, 
  2600.                   int lpitch,
  2601.                                          UCHAR *zbuffer,
  2602.                                          int zpitch,
  2603.                                          int alpha_override)
  2604. {
  2605. // 16-bit version
  2606. // this function "executes" the render list or in other words
  2607. // draws all the faces in the list, the function will call the 
  2608. // proper rasterizer based on the lighting model of the polygons
  2609. // only call the alpha rasterizer for polys with the POLY4DV2_ATTR_TRANSPARENT
  2610. // flag set
  2611. POLYF4DV2 face; // temp face used to render polygon
  2612. int alpha;      // alpha of the face
  2613. // at this point, all we have is a list of polygons and it's time
  2614. // to draw them
  2615. for (int poly=0; poly < rend_list->num_polys; poly++)
  2616.     {
  2617.     // render this polygon if and only if it's not clipped, not culled,
  2618.     // active, and visible, note however the concecpt of "backface" is 
  2619.     // irrelevant in a wire frame engine though
  2620.     if (!(rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_ACTIVE) ||
  2621.          (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_CLIPPED ) ||
  2622.          (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_BACKFACE) )
  2623.        continue; // move onto next poly
  2624.     // test for alpha override
  2625.     if (alpha_override >= 0)
  2626.        {
  2627.        // set alpha to override value
  2628.        alpha = alpha_override;
  2629.        }  // end if 
  2630.     else
  2631.         {
  2632.         // extract alpha (even if there isn't any)
  2633.         alpha = ((rend_list->poly_ptrs[poly]->color & 0xff000000) >> 24);
  2634.         } // end else
  2635.     // need to test for textured first, since a textured poly can either
  2636.     // be emissive, or flat shaded, hence we need to call different
  2637.     // rasterizers    
  2638.     if (rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_TEXTURE)
  2639.        {
  2640.        // set the vertices
  2641.        face.tvlist[0].x = (float)rend_list->poly_ptrs[poly]->tvlist[0].x;
  2642.        face.tvlist[0].y = (float)rend_list->poly_ptrs[poly]->tvlist[0].y;
  2643.        face.tvlist[0].z  = (float)rend_list->poly_ptrs[poly]->tvlist[0].z;
  2644.        face.tvlist[0].u0 = (float)rend_list->poly_ptrs[poly]->tvlist[0].u0;
  2645.        face.tvlist[0].v0 = (float)rend_list->poly_ptrs[poly]->tvlist[0].v0;
  2646.        face.tvlist[1].x = (float)rend_list->poly_ptrs[poly]->tvlist[1].x;
  2647.        face.tvlist[1].y = (float)rend_list->poly_ptrs[poly]->tvlist[1].y;
  2648.        face.tvlist[1].z  = (float)rend_list->poly_ptrs[poly]->tvlist[1].z;
  2649.        face.tvlist[1].u0 = (float)rend_list->poly_ptrs[poly]->tvlist[1].u0;
  2650.        face.tvlist[1].v0 = (float)rend_list->poly_ptrs[poly]->tvlist[1].v0;
  2651.        face.tvlist[2].x = (float)rend_list->poly_ptrs[poly]->tvlist[2].x;
  2652.        face.tvlist[2].y = (float)rend_list->poly_ptrs[poly]->tvlist[2].y;
  2653.        face.tvlist[2].z  = (float)rend_list->poly_ptrs[poly]->tvlist[2].z;
  2654.        face.tvlist[2].u0 = (float)rend_list->poly_ptrs[poly]->tvlist[2].u0;
  2655.        face.tvlist[2].v0 = (float)rend_list->poly_ptrs[poly]->tvlist[2].v0;
  2656.     
  2657.        // assign the texture
  2658.        face.texture = rend_list->poly_ptrs[poly]->texture;
  2659.        
  2660.        // is this a plain emissive texture?
  2661.        if (rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_CONSTANT)
  2662.           {
  2663.           // draw the textured triangle as emissive
  2664.           if ((rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || alpha_override >=0)
  2665.              Draw_Textured_TriangleZB_Alpha16(&face, video_buffer, lpitch,zbuffer,zpitch, alpha);
  2666.           else
  2667.              Draw_Textured_TriangleZB2_16(&face, video_buffer, lpitch,zbuffer,zpitch);
  2668.           } // end if
  2669.        else
  2670.       if (rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT)
  2671.           {
  2672.           // draw as flat shaded
  2673.           face.lit_color[0] = rend_list->poly_ptrs[poly]->lit_color[0];
  2674.           // test for transparency
  2675.           if ((rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || alpha_override >=0)
  2676.              Draw_Textured_TriangleFSZB_Alpha16(&face, video_buffer, lpitch,zbuffer,zpitch, alpha);
  2677.           else
  2678.              Draw_Textured_TriangleFSZB2_16(&face, video_buffer, lpitch,zbuffer,zpitch);
  2679.           } // end else if
  2680.       else
  2681.          { // POLY4DV2_ATTR_SHADE_MODE_GOURAUD
  2682.           // must be gouraud POLY4DV2_ATTR_SHADE_MODE_GOURAUD
  2683.           face.lit_color[0] = rend_list->poly_ptrs[poly]->lit_color[0];
  2684.           face.lit_color[1] = rend_list->poly_ptrs[poly]->lit_color[1];
  2685.           face.lit_color[2] = rend_list->poly_ptrs[poly]->lit_color[2];
  2686.           // test for transparency
  2687.           if ((rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || alpha_override >=0)
  2688.              Draw_Textured_TriangleGSZB_Alpha16(&face, video_buffer, lpitch,zbuffer,zpitch,alpha);
  2689.           else
  2690.              Draw_Textured_TriangleGSZB_16(&face, video_buffer, lpitch,zbuffer,zpitch);
  2691.          } // end else
  2692.        } // end if      
  2693.     else
  2694.     if ((rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT) || 
  2695.         (rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_CONSTANT) )
  2696.        {
  2697.        // draw as constant shaded
  2698.        face.lit_color[0] = rend_list->poly_ptrs[poly]->lit_color[0];
  2699.        
  2700.        // set the vertices
  2701.        face.tvlist[0].x = (float)rend_list->poly_ptrs[poly]->tvlist[0].x;
  2702.        face.tvlist[0].y = (float)rend_list->poly_ptrs[poly]->tvlist[0].y;
  2703.        face.tvlist[0].z  = (float)rend_list->poly_ptrs[poly]->tvlist[0].z;
  2704.        face.tvlist[1].x = (float)rend_list->poly_ptrs[poly]->tvlist[1].x;
  2705.        face.tvlist[1].y = (float)rend_list->poly_ptrs[poly]->tvlist[1].y;
  2706.        face.tvlist[1].z  = (float)rend_list->poly_ptrs[poly]->tvlist[1].z;
  2707.        face.tvlist[2].x = (float)rend_list->poly_ptrs[poly]->tvlist[2].x;
  2708.        face.tvlist[2].y = (float)rend_list->poly_ptrs[poly]->tvlist[2].y;
  2709.        face.tvlist[2].z  = (float)rend_list->poly_ptrs[poly]->tvlist[2].z;
  2710.        // draw the triangle with basic flat rasterizer
  2711.        // test for transparency
  2712.        if ((rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || alpha_override >=0)
  2713.           Draw_Triangle_2DZB_Alpha16(&face, video_buffer, lpitch,zbuffer,zpitch,alpha);
  2714.        else
  2715.           Draw_Triangle_2DZB_16(&face, video_buffer, lpitch,zbuffer,zpitch);
  2716.        } // end if
  2717.     else
  2718.     if (rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD)
  2719.        {
  2720.         // {andre take advantage of the data structures later..}
  2721.         // set the vertices
  2722.         face.tvlist[0].x  = (float)rend_list->poly_ptrs[poly]->tvlist[0].x;
  2723.         face.tvlist[0].y  = (float)rend_list->poly_ptrs[poly]->tvlist[0].y;
  2724.         face.tvlist[0].z  = (float)rend_list->poly_ptrs[poly]->tvlist[0].z;
  2725.         face.lit_color[0] = rend_list->poly_ptrs[poly]->lit_color[0];
  2726.         face.tvlist[1].x  = (float)rend_list->poly_ptrs[poly]->tvlist[1].x;
  2727.         face.tvlist[1].y  = (float)rend_list->poly_ptrs[poly]->tvlist[1].y;
  2728.         face.tvlist[1].z  = (float)rend_list->poly_ptrs[poly]->tvlist[1].z;
  2729.         face.lit_color[1] = rend_list->poly_ptrs[poly]->lit_color[1];
  2730.         face.tvlist[2].x  = (float)rend_list->poly_ptrs[poly]->tvlist[2].x;
  2731.         face.tvlist[2].y  = (float)rend_list->poly_ptrs[poly]->tvlist[2].y;
  2732.         face.tvlist[2].z  = (float)rend_list->poly_ptrs[poly]->tvlist[2].z;
  2733.         face.lit_color[2] = rend_list->poly_ptrs[poly]->lit_color[2];
  2734.     // draw the gouraud shaded triangle
  2735.         // test for transparency
  2736.         if ((rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || alpha_override >=0)
  2737.             Draw_Gouraud_TriangleZB_Alpha16(&face, video_buffer, lpitch,zbuffer,zpitch,alpha);
  2738.         else
  2739.             Draw_Gouraud_TriangleZB2_16(&face, video_buffer, lpitch,zbuffer,zpitch);
  2740.        } // end if gouraud
  2741.     } // end for poly
  2742. } // end Draw_RENDERLIST4DV2_SolidZB_Alpha16
  2743. /////////////////////////////////////////////////////////////////////////////////////////////
  2744. int RGB_Alpha_Table_Builder(int num_alpha_levels,            // number of levels to create
  2745.                             USHORT rgb_alpha_table[NUM_ALPHA_LEVELS][65536]) // lookup table
  2746. {
  2747. // this function creates an alpha lookup table, the purpose of the table is as 
  2748. // follows; when alpha blending two RGB values, one can't simply use the formula:
  2749. // final = (alpha)*(source1RGB) + (1-alpha)*(source2RGB)
  2750. // the reason of course is that the multiplication has to be carried out on R, G, B
  2751. // separately, this we first have to extract out r,g,b from both sources, then multiply
  2752. // both, then add the results, then build the result up and store it ! Ouch! 
  2753. // therefore, we can use a table to speed this up in some cases, so if we think of
  2754. // the input RGB as a number and then let the table extract everything out and do the
  2755. // multiplication by the alpha blending factor, then we save all that work and in the 
  2756. // end an alpha blend turns into two accesses, and an addition, so we avoid 6 multiplications
  2757. // and all the shift. Of course, if the colors are already in r,g,b form already then
  2758. // another approach may be better. In any case, the function works by creating a 
  2759. // table that consists of num_alpha_levels rows, each row consist of 65536 entries which
  2760. // represents the scale value of that row times each of the 65536 colors in RGB format
  2761. // also, the num_alpha_levels must be a power of two, so num_alpha_levels of 8 for example
  2762. // will result in a table that has 8 rows, where the multiplier each row would be
  2763. // 8/8, 7/8, 6/8..........1/8, 0/8 is the amount of source pixel to mix
  2764. // first check the pointer
  2765. if (!rgb_alpha_table)
  2766.    return(-1);
  2767. int r,g,b; // used to scan colors out of rgbindex
  2768. float alpha       = 0;
  2769. float delta_alpha = EPSILON_E6 + 1/((float)(num_alpha_levels-1)); 
  2770. // we need num_alpha_level_rows
  2771. for (int alpha_level = 0; alpha_level < num_alpha_levels; alpha_level++)
  2772.     {
  2773.     // there are 65536 RGB values we need to compute, assuming that we are in RGB: 4.4.4  format
  2774.     for (int rgbindex = 0; rgbindex < 65536; rgbindex++)
  2775.         {
  2776.         // extract r,g,b from rgbindex, assuming an encoding of 5.6.5
  2777.         _RGB565FROM16BIT(rgbindex, &r, &g, &b);
  2778.         // scale
  2779.         r = (int)( (float)r * (float)alpha );
  2780.         g = (int)( (float)g * (float)alpha );
  2781.         b = (int)( (float)b * (float)alpha );
  2782.         // build pixel back up and store
  2783.         rgb_alpha_table[alpha_level][rgbindex] = _RGB16BIT565(r,g,b);
  2784.         } // end for rgbindex
  2785.         
  2786.     // decrease alpha level
  2787.     alpha+=delta_alpha;
  2788.     } // end for row 
  2789. // return success
  2790. return(1);
  2791. } // end RGB_Alpha_Table_Builder
  2792. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2793. int Load_OBJECT4DV2_COB2(OBJECT4DV2_PTR obj,   // pointer to object
  2794.                          char *filename,       // filename of Caligari COB file
  2795.                          VECTOR4D_PTR scale,   // initial scaling factors
  2796.                          VECTOR4D_PTR pos,     // initial position
  2797.                          VECTOR4D_PTR rot,     // initial rotations
  2798.                          int vertex_flags,     // flags to re-order vertices 
  2799.                                                // and perform transforms
  2800.                          int mipmap  )         // mipmap enable flag
  2801.                                                // 0 means no mipmap, 1 means
  2802.                                                // generate mip map
  2803.   
  2804. {
  2805. // this function loads a Caligari TrueSpace .COB file object in off disk, additionally
  2806. // it allows the caller to scale, position, and rotate the object
  2807. // to save extra calls later for non-dynamic objects, note that this function 
  2808. // works with a OBJECT4DV2 which has support for textures, but not materials, etc, 
  2809. // however we will still parse out the material stuff and get them ready for the 
  2810. // next incarnation objects, so we can re-use this code to support those features
  2811. // also, since this version IS going to read in the texture map and texture coordinates
  2812. // we have a couple issues to think about, first COB format like absolute texture paths
  2813. // we can't have that, so we will simple extract out ONLY the texture map bitmap name
  2814. // and use the global texture path variable to build a real file path, also texture
  2815. // coordinates are in 0..1 0..1 form, I still haven't decided if I want to use absolute
  2816. // coordinates or 0..1 0..1, but right now the affine texture mapper uses 
  2817. // new version 2.0 supports alpha channel and mip mapping, if mipmap = 1 then the
  2818. // loader will automatically mipmap the texture and then fix the object pointer and 
  2819. // all subsequent polygon texture pointers to point to the mipmap chain d=0 texture
  2820. // pointer rather than directly to the texture, thus mipmapped objects
  2821. // must be flagged and processed differently
  2822. // create a parser object
  2823. CPARSERV1 parser; 
  2824. char seps[16];          // seperators for token scanning
  2825. char token_buffer[256]; // used as working buffer for token
  2826. char *token;            // pointer to next token
  2827. int r,g,b;              // working colors
  2828. // cache for texture vertices
  2829. VERTEX2DF texture_vertices[OBJECT4DV2_MAX_VERTICES];
  2830. int num_texture_vertices = 0;
  2831. MATRIX4X4 mat_local,  // storage for local transform if user requests it in cob format
  2832.           mat_world;  // "   " for local to world " "
  2833. // initialize matrices
  2834. MAT_IDENTITY_4X4(&mat_local);
  2835. MAT_IDENTITY_4X4(&mat_world);
  2836. // Step 1: clear out the object and initialize it a bit
  2837. memset(obj, 0, sizeof(OBJECT4DV2));
  2838. // set state of object to active and visible
  2839. obj->state = OBJECT4DV2_STATE_ACTIVE | OBJECT4DV2_STATE_VISIBLE;
  2840. // set number of frames
  2841. obj->num_frames = 1;
  2842. obj->curr_frame = 0;
  2843. obj->attr = OBJECT4DV2_ATTR_SINGLE_FRAME;
  2844. // set position of object is caller requested position
  2845. if (pos)
  2846.    {
  2847.    // set position of object
  2848.    obj->world_pos.x = pos->x;
  2849.    obj->world_pos.y = pos->y;
  2850.    obj->world_pos.z = pos->z;
  2851.    obj->world_pos.w = pos->w;
  2852.    } // end 
  2853. else
  2854.    {
  2855.    // set it to (0,0,0,1)
  2856.    obj->world_pos.x = 0;
  2857.    obj->world_pos.y = 0;
  2858.    obj->world_pos.z = 0;
  2859.    obj->world_pos.w = 1;
  2860.    } // end else
  2861. // Step 2: open the file for reading using the parser
  2862. if (!parser.Open(filename))
  2863.    {
  2864.    Write_Error("Couldn't open .COB file %s.", filename);
  2865.    return(0);
  2866.    } // end if
  2867. // Step 3: 
  2868. // lets find the name of the object first 
  2869. while(1)
  2870.      {
  2871.      // get the next line, we are looking for "Name"
  2872.      if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  2873.         {
  2874.         Write_Error("Image 'name' not found in .COB file %s.", filename);
  2875.         return(0);
  2876.         } // end if
  2877.     
  2878.      // check for pattern?  
  2879.      if ( parser.Pattern_Match(parser.buffer, "['Name'] [s>0]") )
  2880.         {
  2881.         // name should be in second string variable, index 1
  2882.         strcpy(obj->name, parser.pstrings[1]);          
  2883.         Write_Error("nCOB Reader Object Name: %s", obj->name);
  2884.         break;    
  2885.         } // end if
  2886.      } // end while
  2887. // step 4: get local and world transforms and store them
  2888. // center 0 0 0
  2889. // x axis 1 0 0
  2890. // y axis 0 1 0
  2891. // z axis 0 0 1
  2892. while(1)
  2893.      {
  2894.      // get the next line, we are looking for "center"
  2895.      if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  2896.         {
  2897.         Write_Error("Center not found in .COB file %s.", filename);
  2898.         return(0);
  2899.         } // end if
  2900.     
  2901.      // check for pattern?  
  2902.      if ( parser.Pattern_Match(parser.buffer, "['center'] [f] [f] [f]") )
  2903.         {
  2904.         // the "center" holds the translation factors, so place in
  2905.         // last row of homogeneous matrix, note that these are row vectors
  2906.         // that we need to drop in each column of matrix
  2907.         mat_local.M[3][0] = -parser.pfloats[0]; // center x
  2908.         mat_local.M[3][1] = -parser.pfloats[1]; // center y
  2909.         mat_local.M[3][2] = -parser.pfloats[2]; // center z
  2910.         // ok now, the next 3 lines should be the x,y,z transform vectors
  2911.         // so build up   
  2912.         // "x axis" 
  2913.         parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS);
  2914.         parser.Pattern_Match(parser.buffer, "['x'] ['axis'] [f] [f] [f]");
  2915.       
  2916.         // place row in x column of transform matrix
  2917.         mat_local.M[0][0] = parser.pfloats[0]; // rxx
  2918.         mat_local.M[1][0] = parser.pfloats[1]; // rxy
  2919.         mat_local.M[2][0] = parser.pfloats[2]; // rxz
  2920.         // "y axis" 
  2921.         parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS);
  2922.         parser.Pattern_Match(parser.buffer, "['y'] ['axis'] [f] [f] [f]");
  2923.       
  2924.         // place row in y column of transform matrix
  2925.         mat_local.M[0][1] = parser.pfloats[0]; // ryx
  2926.         mat_local.M[1][1] = parser.pfloats[1]; // ryy
  2927.         mat_local.M[2][1] = parser.pfloats[2]; // ryz
  2928.         // "z axis" 
  2929.         parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS);
  2930.         parser.Pattern_Match(parser.buffer, "['z'] ['axis'] [f] [f] [f]");
  2931.       
  2932.         // place row in z column of transform matrix
  2933.         mat_local.M[0][2] = parser.pfloats[0]; // rzx
  2934.         mat_local.M[1][2] = parser.pfloats[1]; // rzy
  2935.         mat_local.M[2][2] = parser.pfloats[2]; // rzz
  2936.         Print_Mat_4X4(&mat_local, "Local COB Matrix:");
  2937.         break;    
  2938.         } // end if
  2939.      } // end while
  2940. // now "Transform"
  2941. while(1)
  2942.      {
  2943.      // get the next line, we are looking for "Transform"
  2944.      if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  2945.         {
  2946.         Write_Error("Transform not found in .COB file %s.", filename);
  2947.         return(0);
  2948.         } // end if
  2949.     
  2950.      // check for pattern?  
  2951.      if ( parser.Pattern_Match(parser.buffer, "['Transform']") )
  2952.         {
  2953.         // "x axis" 
  2954.         parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS);
  2955.         parser.Pattern_Match(parser.buffer, "[f] [f] [f]");
  2956.       
  2957.         // place row in x column of transform matrix
  2958.         mat_world.M[0][0] = parser.pfloats[0]; // rxx
  2959.         mat_world.M[1][0] = parser.pfloats[1]; // rxy
  2960.         mat_world.M[2][0] = parser.pfloats[2]; // rxz
  2961.         // "y axis" 
  2962.         parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS);
  2963.         parser.Pattern_Match(parser.buffer, "[f] [f] [f]");
  2964.       
  2965.         // place row in y column of transform matrix
  2966.         mat_world.M[0][1] = parser.pfloats[0]; // ryx
  2967.         mat_world.M[1][1] = parser.pfloats[1]; // ryy
  2968.         mat_world.M[2][1] = parser.pfloats[2]; // ryz
  2969.         // "z axis" 
  2970.         parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS);
  2971.         parser.Pattern_Match(parser.buffer, "[f] [f] [f]");
  2972.       
  2973.         // place row in z column of transform matrix
  2974.         mat_world.M[0][2] = parser.pfloats[0]; // rzx
  2975.         mat_world.M[1][2] = parser.pfloats[1]; // rzy
  2976.         mat_world.M[2][2] = parser.pfloats[2]; // rzz
  2977.         Print_Mat_4X4(&mat_world, "World COB Matrix:");
  2978.         // no need to read in last row, since it's always 0,0,0,1 and we don't use it anyway
  2979.         break;    
  2980.         } // end if
  2981.      } // end while
  2982. // step 6: get number of vertices and polys in object
  2983. while(1)
  2984.      {
  2985.      // get the next line, we are looking for "World Vertices" 
  2986.      if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  2987.         {
  2988.         Write_Error("'World Vertices' line not found in .COB file %s.", filename);
  2989.         return(0);
  2990.         } // end if
  2991.     
  2992.      // check for pattern?  
  2993.      if (parser.Pattern_Match(parser.buffer, "['World'] ['Vertices'] [i]") )
  2994.         {
  2995.         // simply extract the number of vertices from the pattern matching 
  2996.         // output arrays
  2997.         obj->num_vertices = parser.pints[0];
  2998.         Write_Error("nCOB Reader Num Vertices: %d", obj->num_vertices);
  2999.         break;    
  3000.  
  3001.         } // end if
  3002.      } // end while
  3003. // allocate the memory for the vertices and number of polys (unknown, so use 3*num_vertices)
  3004. // the call parameters are redundant in this case, but who cares
  3005. if (!Init_OBJECT4DV2(obj,   // object to allocate
  3006.                 obj->num_vertices, 
  3007.                 obj->num_vertices*3,  
  3008.                 obj->num_frames))
  3009.     {
  3010.     Write_Error("nASC file error with file %s (can't allocate memory).",filename);
  3011.     } // end if
  3012. // Step 7: load the vertex list
  3013. // now read in vertex list, format:
  3014. // "d.d d.d d.d"
  3015.  for (int vertex = 0; vertex < obj->num_vertices; vertex++)
  3016.      {
  3017.      // hunt for vertex
  3018.      while(1)
  3019.      {
  3020.      // get the next vertex
  3021.      if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3022.         {
  3023.         Write_Error("nVertex list ended abruptly! in .COB file %s.", filename);
  3024.         return(0);
  3025.         } // end if
  3026.     
  3027.      // check for pattern?  
  3028.      if (parser.Pattern_Match(parser.buffer, "[f] [f] [f]"))
  3029.         {
  3030.         // at this point we have the x,y,z in the the pfloats array locations 0,1,2
  3031.         obj->vlist_local[vertex].x = parser.pfloats[0];
  3032.         obj->vlist_local[vertex].y = parser.pfloats[1];
  3033.         obj->vlist_local[vertex].z = parser.pfloats[2];
  3034.         obj->vlist_local[vertex].w = 1;
  3035.         // do vertex swapping right here, allow muliple swaps, why not!
  3036.         // defines for vertex re-ordering flags
  3037.         //#define VERTEX_FLAGS_INVERT_X   1    // inverts the Z-coordinates
  3038.         //#define VERTEX_FLAGS_INVERT_Y   2    // inverts the Z-coordinates
  3039.         //#define VERTEX_FLAGS_INVERT_Z   4    // inverts the Z-coordinates
  3040.         //#define VERTEX_FLAGS_SWAP_YZ    8    // transforms a RHS model to a LHS model
  3041.         //#define VERTEX_FLAGS_SWAP_XZ    16   // ???
  3042.         //#define VERTEX_FLAGS_SWAP_XY    32
  3043.         //#define VERTEX_FLAGS_INVERT_WINDING_ORDER 64  // invert winding order from cw to ccw or ccw to cc
  3044.         //#define VERTEX_FLAGS_TRANSFORM_LOCAL         512   // if file format has local transform then do it!
  3045.         //#define VERTEX_FLAGS_TRANSFORM_LOCAL_WORLD  1024  // if file format has local to world then do it!
  3046.         VECTOR4D temp_vector; // temp for calculations
  3047.         // now apply local and world transformations encoded in COB format
  3048.         if (vertex_flags & VERTEX_FLAGS_TRANSFORM_LOCAL )
  3049.            {
  3050.            Mat_Mul_VECTOR4D_4X4(&obj->vlist_local[vertex].v, &mat_local, &temp_vector);
  3051.            VECTOR4D_COPY(&obj->vlist_local[vertex].v, &temp_vector); 
  3052.            } // end if 
  3053.         if (vertex_flags & VERTEX_FLAGS_TRANSFORM_LOCAL_WORLD )
  3054.            {
  3055.            Mat_Mul_VECTOR4D_4X4(&obj->vlist_local[vertex].v, &mat_world, &temp_vector);
  3056.            VECTOR4D_COPY(&obj->vlist_local[vertex].v, &temp_vector); 
  3057.            } // end if 
  3058.         float temp_f; // used for swapping
  3059.         // invert signs?
  3060.         if (vertex_flags & VERTEX_FLAGS_INVERT_X)
  3061.            obj->vlist_local[vertex].x=-obj->vlist_local[vertex].x;
  3062.         if (vertex_flags & VERTEX_FLAGS_INVERT_Y)
  3063.            obj->vlist_local[vertex].y=-obj->vlist_local[vertex].y;
  3064.         if (vertex_flags & VERTEX_FLAGS_INVERT_Z)
  3065.            obj->vlist_local[vertex].z=-obj->vlist_local[vertex].z;
  3066.         // swap any axes?
  3067.         if (vertex_flags & VERTEX_FLAGS_SWAP_YZ)
  3068.            SWAP(obj->vlist_local[vertex].y, obj->vlist_local[vertex].z, temp_f);
  3069.         
  3070.         if (vertex_flags & VERTEX_FLAGS_SWAP_XZ)
  3071.            SWAP(obj->vlist_local[vertex].x, obj->vlist_local[vertex].z, temp_f);
  3072.         if (vertex_flags & VERTEX_FLAGS_SWAP_XY)
  3073.            SWAP(obj->vlist_local[vertex].x, obj->vlist_local[vertex].y, temp_f);
  3074.         // scale vertices
  3075.         if (scale)
  3076.            {
  3077.            obj->vlist_local[vertex].x*=scale->x;
  3078.            obj->vlist_local[vertex].y*=scale->y;
  3079.            obj->vlist_local[vertex].z*=scale->z;
  3080.            } // end if
  3081.           Write_Error("nVertex %d = %f, %f, %f, %f", vertex,
  3082.                                            obj->vlist_local[vertex].x, 
  3083.                                            obj->vlist_local[vertex].y, 
  3084.                                            obj->vlist_local[vertex].z,
  3085.                                            obj->vlist_local[vertex].w);
  3086.          // set point field in this vertex, we need that at least 
  3087.          SET_BIT(obj->vlist_local[vertex].attr, VERTEX4DTV1_ATTR_POINT);
  3088.         // found vertex, break out of while for next pass
  3089.         break;
  3090.         } // end if
  3091.     } // end while
  3092.     } // end for vertex
  3093. // compute average and max radius
  3094. Compute_OBJECT4DV2_Radius(obj);
  3095. Write_Error("nObject average radius = %f, max radius = %f", 
  3096.             obj->avg_radius, obj->max_radius);
  3097. // step 8: get number of texture vertices
  3098. while(1)
  3099.      {
  3100.      // get the next line, we are looking for "Texture Vertices ddd" 
  3101.      if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3102.         {
  3103.         Write_Error("'Texture Vertices' line not found in .COB file %s.", filename);
  3104.         return(0);
  3105.         } // end if
  3106.     
  3107.      // check for pattern?  
  3108.      if (parser.Pattern_Match(parser.buffer, "['Texture'] ['Vertices'] [i]") )
  3109.         {
  3110.         // simply extract the number of texture vertices from the pattern matching 
  3111.         // output arrays
  3112.         num_texture_vertices = parser.pints[0];
  3113.         Write_Error("nCOB Reader Texture Vertices: %d", num_texture_vertices);
  3114.         break;    
  3115.  
  3116.         } // end if
  3117.      } // end while
  3118. // Step 9: load the texture vertex list in format "U V"
  3119. // "d.d d.d"
  3120.  for (int tvertex = 0; tvertex < num_texture_vertices; tvertex++)
  3121.      {
  3122.      // hunt for texture
  3123.      while(1)
  3124.      {
  3125.      // get the next vertex
  3126.      if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3127.         {
  3128.         Write_Error("nTexture Vertex list ended abruptly! in .COB file %s.", filename);
  3129.         return(0);
  3130.         } // end if
  3131.     
  3132.      // check for pattern?  
  3133.      if (parser.Pattern_Match(parser.buffer, "[f] [f]"))
  3134.         {
  3135.         // at this point we have the U V in the the pfloats array locations 0,1 for this 
  3136.         // texture vertex, store in texture coordinate list
  3137.         // note texture coords are in 0..1 format, and must be scaled to texture size
  3138.         // after we load the texture
  3139.         obj->tlist[tvertex].x = parser.pfloats[0]; 
  3140.         obj->tlist[tvertex].y = parser.pfloats[1];
  3141.         Write_Error("nTexture Vertex %d: U=%f, V=%f", tvertex,
  3142.                                           obj->tlist[tvertex].x, 
  3143.                                           obj->tlist[tvertex].y );
  3144.         // found vertex, break out of while for next pass
  3145.         break;
  3146.         } // end if
  3147.        } // end while
  3148.    } // end for
  3149. // when we load in the polygons then we will copy the texture vertices into the polygon
  3150. // vertices assuming that each vertex has a SINGLE texture coordinate, this means that
  3151. // you must NOT use multiple textures on an object! in other words think "skin" this is
  3152. // inline with Quake II md2 format, in 99% of the cases a single object can be textured
  3153. // with a single skin and the texture coordinates can be unique for each vertex and 1:1
  3154. int poly_material[OBJECT4DV2_MAX_POLYS]; // this holds the material index for each polygon
  3155.                                          // we need these indices since when reading the file
  3156.                                          // we read the polygons BEFORE the materials, so we need
  3157.                                          // this data, so we can go back later and extract the material
  3158.                                          // that each poly WAS assigned and get the colors out, since
  3159.                                          // objects and polygons do not currently support materials
  3160. int material_index_referenced[MAX_MATERIALS];   // used to track if an index has been used yet as a material 
  3161.                                                 // reference. since we don't know how many materials, we need
  3162.                                                 // a way to count them up, but if we have seen a material reference
  3163.                                                 // more than once then we don't increment the total number of materials
  3164.                                                 // this array is for this
  3165. // clear out reference array
  3166. memset(material_index_referenced,0, sizeof(material_index_referenced));
  3167. // step 10: load in the polygons
  3168. // poly list starts off with:
  3169. // "Faces ddd:"
  3170. while(1)
  3171.      {
  3172.      // get next line
  3173.      if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3174.         {
  3175.         Write_Error("n'Faces' line not found in .COB file %s.", filename);
  3176.         return(0);
  3177.         } // end if
  3178.     
  3179.      // check for pattern?  
  3180.      if (parser.Pattern_Match(parser.buffer, "['Faces'] [i]"))
  3181.         {
  3182.         Write_Error("nCOB Reader found face list in .COB file %s.", filename);
  3183.         // finally set number of polys
  3184.         obj->num_polys = parser.pints[0];
  3185.         break;
  3186.         } // end if
  3187.      } // end while
  3188. // now read each face in format:
  3189. // Face verts nn flags ff mat mm
  3190. // the nn is the number of vertices, always 3
  3191. // the ff is the flags, unused for now, has to do with holes
  3192. // the mm is the material index number 
  3193. int poly_surface_desc    = 0; // ASC surface descriptor/material in this case
  3194. int poly_num_verts       = 0; // number of vertices for current poly (always 3)
  3195. int num_materials_object = 0; // number of materials for this object
  3196. for (int poly=0; poly < obj->num_polys; poly++)
  3197.     {
  3198.     Write_Error("nPolygon %d:", poly);
  3199.     // hunt until next face is found
  3200.     while(1)
  3201.          {
  3202.          // get the next polygon face
  3203.          if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3204.             {
  3205.             Write_Error("nface list ended abruptly! in .COB file %s.", filename);
  3206.             return(0);
  3207.             } // end if
  3208.      
  3209.          // check for pattern?  
  3210.          if (parser.Pattern_Match(parser.buffer, "['Face'] ['verts'] [i] ['flags'] [i] ['mat'] [i]"))
  3211.             {
  3212.             // at this point we have the number of vertices for the polygon, the flags, and it's material index
  3213.             // in the integer output array locations 0,1,2
  3214.             // store the material index for this polygon for retrieval later, but make sure adjust the 
  3215.             // the index to take into consideration that the data in parser.pints[2] is 0 based, and we need
  3216.             // an index relative to the entire library, so we simply need to add num_materials to offset the 
  3217.             // index properly, but we will leave this reference zero based for now... and fix up later
  3218.             poly_material[poly] = parser.pints[2];
  3219.             // update the reference array
  3220.             if (material_index_referenced[ poly_material[poly] ] == 0)
  3221.                {
  3222.                // mark as referenced
  3223.                material_index_referenced[ poly_material[poly] ] = 1;
  3224.                // increment total number of materials for this object
  3225.                num_materials_object++;
  3226.                } // end if        
  3227.             // test if number of vertices is 3
  3228.             if (parser.pints[0]!=3)
  3229.                {
  3230.                Write_Error("nface not a triangle! in .COB file %s.", filename);
  3231.                return(0);
  3232.                } // end if
  3233.            // now read out the vertex indices and texture indices format:
  3234.            // <vindex0, tindex0>  <vindex1, tindex1> <vindex1, tindex1> 
  3235.            if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3236.               {
  3237.               Write_Error("nface list ended abruptly! in .COB file %s.", filename);
  3238.               return(0);
  3239.               } // end if
  3240.            // lets replace ",<>" with ' ' to make extraction easy
  3241.            ReplaceChars(parser.buffer, parser.buffer, ",<>",' ');      
  3242.            parser.Pattern_Match(parser.buffer, "[i] [i] [i] [i] [i] [i]");
  3243.  
  3244.            // 0,2,4 holds vertex indices
  3245.            // 1,3,5 holds texture indices
  3246.            
  3247.           // insert polygon, check for winding order invert
  3248.           if (vertex_flags & VERTEX_FLAGS_INVERT_WINDING_ORDER)
  3249.              {     
  3250.              poly_num_verts           = 3;
  3251.              obj->plist[poly].vert[0] = parser.pints[4];
  3252.              obj->plist[poly].vert[1] = parser.pints[2];
  3253.              obj->plist[poly].vert[2] = parser.pints[0];
  3254.              // now copy the texture coordinates into the vertices, this
  3255.              // may not be needed if the polygon doesn't have texture mapping
  3256.              // enabled, etc., 
  3257.              // so here's the deal the texture coordinates that 
  3258.              // map to vertex 0,1,2 have indices stored in the odd
  3259.              // numbered pints[] locations, so we simply need to copy
  3260.              // the right texture coordinate into the right vertex
  3261.              obj->plist[poly].text[0] = parser.pints[5];
  3262.              obj->plist[poly].text[1] = parser.pints[3];
  3263.              obj->plist[poly].text[2] = parser.pints[1];
  3264.              
  3265.              Write_Error("nAssigning texture vertex index %d [%f, %f] to mesh vertex %d",
  3266.                                                                    parser.pints[5],
  3267.                                                                    obj->tlist[ parser.pints[5] ].x, 
  3268.                                                                    obj->tlist[ parser.pints[5] ].y,
  3269.                                                                    obj->plist[poly].vert[0] );
  3270.              Write_Error("nAssigning texture vertex index %d [%f, %f] to mesh vertex %d",
  3271.                                                                    parser.pints[3],
  3272.                                                                    obj->tlist[ parser.pints[3] ].x, 
  3273.                                                                    obj->tlist[ parser.pints[3] ].y,
  3274.                                                                    obj->plist[poly].vert[1] );
  3275.              Write_Error("nAssigning texture vertex index %d [%f, %f] to mesh vertex %d",
  3276.                                                                    parser.pints[1],
  3277.                                                                    obj->tlist[ parser.pints[1] ].x, 
  3278.                                                                    obj->tlist[ parser.pints[1] ].y,
  3279.                                                                    obj->plist[poly].vert[2] );
  3280.    
  3281.              } // end if
  3282.           else
  3283.              { // leave winding order alone
  3284.              poly_num_verts           = 3;
  3285.              obj->plist[poly].vert[0] = parser.pints[0];
  3286.              obj->plist[poly].vert[1] = parser.pints[2];
  3287.              obj->plist[poly].vert[2] = parser.pints[4];
  3288.              // now copy the texture coordinates into the vertices, this
  3289.              // may not be needed if the polygon doesn't have texture mapping
  3290.              // enabled, etc., 
  3291.              // so here's the deal the texture coordinates that 
  3292.              // map to vertex 0,1,2 have indices stored in the odd
  3293.              // numbered pints[] locations, so we simply need to copy
  3294.              // the right texture coordinate into the right vertex
  3295.              obj->plist[poly].text[0] = parser.pints[1];
  3296.              obj->plist[poly].text[1] = parser.pints[3];
  3297.              obj->plist[poly].text[2] = parser.pints[5];
  3298.              
  3299.              Write_Error("nAssigning texture vertex index %d [%f, %f] to mesh vertex %d",
  3300.                                                                    parser.pints[1],
  3301.                                                                    obj->tlist[ parser.pints[1] ].x, 
  3302.                                                                    obj->tlist[ parser.pints[1] ].y,
  3303.                                                                    obj->plist[poly].vert[0] );
  3304.              Write_Error("nAssigning texture vertex index %d [%f, %f] to mesh vertex %d",
  3305.                                                                    parser.pints[3],
  3306.                                                                    obj->tlist[ parser.pints[3] ].x, 
  3307.                                                                    obj->tlist[ parser.pints[3] ].y,
  3308.                                                                    obj->plist[poly].vert[1] );
  3309.              Write_Error("nAssigning texture vertex index %d [%f, %f] to mesh vertex %d",
  3310.                                                                    parser.pints[5],
  3311.                                                                    obj->tlist[ parser.pints[5] ].x, 
  3312.                                                                    obj->tlist[ parser.pints[5] ].y,
  3313.                                                                    obj->plist[poly].vert[2] );
  3314.              } // end else
  3315.           // point polygon vertex list to object's vertex list
  3316.           // note that this is redundant since the polylist is contained
  3317.           // within the object in this case and its up to the user to select
  3318.           // whether the local or transformed vertex list is used when building up
  3319.           // polygon geometry, might be a better idea to set to NULL in the context
  3320.           // of polygons that are part of an object
  3321.           obj->plist[poly].vlist = obj->vlist_local; 
  3322.           // set texture coordinate list, this is needed
  3323.           obj->plist[poly].tlist = obj->tlist;
  3324.           // set polygon to active
  3325.           obj->plist[poly].state = POLY4DV2_STATE_ACTIVE;    
  3326.           // found the face, break out of while for another pass
  3327.           break;
  3328.           } // end if
  3329.  
  3330.        } // end while      
  3331.        Write_Error("nLocal material Index=%d, total materials for object = %d, vert_indices [%d, %d, %d]", 
  3332.                                                                                 poly_material[poly],
  3333.                                                                                 num_materials_object,
  3334.                                                                                 obj->plist[poly].vert[0],
  3335.                                                                                 obj->plist[poly].vert[1],
  3336.                                                                                 obj->plist[poly].vert[2]);       
  3337.     } // end for poly
  3338. // now find materials!!! and we are out of here!
  3339. for (int curr_material = 0; curr_material < num_materials_object; curr_material++)
  3340.     {
  3341.     // hunt for the material header "mat# ddd"
  3342.     while(1)
  3343.     {
  3344.     // get the next polygon material 
  3345.     if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3346.        {
  3347.        Write_Error("nmaterial list ended abruptly! in .COB file %s.", filename);
  3348.        return(0);
  3349.        } // end if
  3350.      
  3351.     // check for pattern?  
  3352.     if (parser.Pattern_Match(parser.buffer, "['mat#'] [i]") )
  3353.        {
  3354.        // extract the material that is being defined 
  3355.        int material_index = parser.pints[0];
  3356.        // get color of polygon, although it might be irrelevant for a textured surface
  3357.        while(1)
  3358.             {
  3359.             // get the next line
  3360.             if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3361.                {
  3362.                Write_Error("nRGB color ended abruptly! in .COB file %s.", filename);
  3363.                return(0);
  3364.                } // end if
  3365.                // replace the , comma's if there are any with spaces
  3366.                ReplaceChars(parser.buffer, parser.buffer, ",", ' ', 1);
  3367.                // look for "rgb float,float,float"
  3368.                if (parser.Pattern_Match(parser.buffer, "['rgb'] [f] [f] [f]") )
  3369.                   {
  3370.                   // extract data and store color in material libary
  3371.                   // pfloats[] 0,1,2,3, has data
  3372.                   materials[material_index + num_materials].color.r = (int)(parser.pfloats[0]*255 + 0.5);
  3373.                   materials[material_index + num_materials].color.g = (int)(parser.pfloats[1]*255 + 0.5);
  3374.                   materials[material_index + num_materials].color.b = (int)(parser.pfloats[2]*255 + 0.5);
  3375.                   break; // while looking for rgb
  3376.                   } // end if
  3377.              } // end while    
  3378.        // extract out lighting constants for the heck of it, they are on a line like this:
  3379.        // "alpha float ka float ks float exp float ior float"
  3380.        // alpha is transparency           0 - 1
  3381.        // ka is ambient coefficient       0 - 1
  3382.        // ks is specular coefficient      0 - 1
  3383.        // exp is highlight power exponent 0 - 1
  3384.        // ior is index of refraction (unused)
  3385.        // although our engine will have minimal support for these, we might as well get them
  3386.        while(1)
  3387.             {
  3388.             // get the next line
  3389.             if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3390.                {
  3391.                Write_Error("nmaterial properties ended abruptly! in .COB file %s.", filename);
  3392.                return(0);
  3393.                } // end if
  3394.             // look for "alpha float ka float ks float exp float ior float"
  3395.             if (parser.Pattern_Match(parser.buffer, "['alpha'] [f] ['ka'] [f] ['ks'] [f] ['exp'] [f]") )
  3396.                {
  3397.                // extract data and store in material libary
  3398.                // pfloats[] 0,1,2,3, has data
  3399.                materials[material_index + num_materials].color.a  = (UCHAR)(parser.pfloats[0]*255 + 0.5);
  3400.                materials[material_index + num_materials].ka       = parser.pfloats[1];
  3401.                materials[material_index + num_materials].kd       = 1; // hard code for now
  3402.                materials[material_index + num_materials].ks       = parser.pfloats[2];
  3403.                materials[material_index + num_materials].power    = parser.pfloats[3];
  3404.  
  3405.                // compute material reflectivities in pre-multiplied format to help engine
  3406.                for (int rgb_index=0; rgb_index < 3; rgb_index++)
  3407.                     {
  3408.                     // ambient reflectivity
  3409.                     materials[material_index + num_materials].ra.rgba_M[rgb_index] = 
  3410.                               ( (UCHAR)(materials[material_index + num_materials].ka * 
  3411.                                 (float)materials[material_index + num_materials].color.rgba_M[rgb_index] + 0.5) );
  3412.   
  3413.                     // diffuse reflectivity
  3414.                     materials[material_index + num_materials].rd.rgba_M[rgb_index] = 
  3415.                               ( (UCHAR)(materials[material_index + num_materials].kd * 
  3416.                                 (float)materials[material_index + num_materials].color.rgba_M[rgb_index] + 0.5) );
  3417.   
  3418.                     // specular reflectivity
  3419.                     materials[material_index + num_materials].rs.rgba_M[rgb_index] = 
  3420.                               ( (UCHAR)(materials[material_index + num_materials].ks * 
  3421.                                 (float)materials[material_index + num_materials].color.rgba_M[rgb_index] + 0.5) );
  3422.                      } // end for rgb_index
  3423.                break;
  3424.                } // end if
  3425.              } // end while    
  3426.        // now we need to know the shading model, it's a bit tricky, we need to look for the lines
  3427.        // "Shader class: color" first, then after this line is:
  3428.        // "Shader name: "xxxxxx" (xxxxxx) "
  3429.        // where the xxxxx part will be "plain color" and "plain" for colored polys 
  3430.        // or "texture map" and "caligari texture"  for textures
  3431.        // THEN based on that we hunt for "Shader class: reflectance" which is where the type
  3432.        // of shading is encoded, we look for the "Shader name: "xxxxxx" (xxxxxx) " again, 
  3433.        // and based on it's value we map it to our shading system as follows:
  3434.        // "constant" -> MATV1_ATTR_SHADE_MODE_CONSTANT 
  3435.        // "matte"    -> MATV1_ATTR_SHADE_MODE_FLAT
  3436.        // "plastic"  -> MATV1_ATTR_SHADE_MODE_GOURAUD
  3437.        // "phong"    -> MATV1_ATTR_SHADE_MODE_FASTPHONG 
  3438.        // and in the case that in the "color" class, we found a "texture map" then the "shading mode" is
  3439.        // "texture map" -> MATV1_ATTR_SHADE_MODE_TEXTURE 
  3440.        // which must be logically or'ed with the other previous modes
  3441.  
  3442.        //  look for the "shader class: color"
  3443.        while(1)
  3444.             {
  3445.             // get the next line
  3446.             if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3447.                {
  3448.                Write_Error("nshader class ended abruptly! in .COB file %s.", filename);
  3449.                return(0);
  3450.                } // end if
  3451.        
  3452.             if (parser.Pattern_Match(parser.buffer, "['Shader'] ['class:'] ['color']") )
  3453.                {
  3454.                break;
  3455.                } // end if
  3456.              } // end while
  3457.           
  3458.        // now look for the shader name for this class
  3459.        // Shader name: "plain color" or Shader name: "texture map"
  3460.        while(1)
  3461.             {
  3462.             // get the next line
  3463.             if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3464.                {
  3465.                Write_Error("nshader name ended abruptly! in .COB file %s.", filename);
  3466.                return(0);
  3467.                } // end if
  3468.             // replace the " with spaces
  3469.             ReplaceChars(parser.buffer, parser.buffer, """, ' ', 1);
  3470.             // is this a "plain color" poly?
  3471.             if (parser.Pattern_Match(parser.buffer, "['Shader'] ['name:'] ['plain'] ['color']") )
  3472.                {
  3473.                // not much to do this is default, we need to wait for the reflectance type
  3474.                // to tell us the shading mode
  3475.                break;
  3476.                } // end if
  3477.             // is this a "texture map" poly?
  3478.             if (parser.Pattern_Match(parser.buffer, "['Shader'] ['name:'] ['texture'] ['map']") )
  3479.                {
  3480.                // set the texture mapping flag in material
  3481.                SET_BIT(materials[material_index + num_materials].attr, MATV1_ATTR_SHADE_MODE_TEXTURE);
  3482.       
  3483.                // almost done, we need the file name of the darn texture map, its in this format:
  3484.                // file name: string "D:Source..modelstextureswall01.bmp"
  3485.           
  3486.                // of course the filename in the quotes will change
  3487.                // so lets hunt until we find it...
  3488.                while(1)
  3489.                     {
  3490.                     // get the next line
  3491.                     if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3492.                        {
  3493.                        Write_Error("ncouldnt find texture name! in .COB file %s.", filename);
  3494.                        return(0);
  3495.                        } // end if
  3496.                     // replace the " with spaces
  3497.                     ReplaceChars(parser.buffer, parser.buffer, """, ' ', 1);
  3498.                     // is this the file name?
  3499.                     if (parser.Pattern_Match(parser.buffer, "['file'] ['name:'] ['string']") )
  3500.                        {
  3501.                        // and save the FULL filename (useless though since its the path from the 
  3502.                        // machine that created it, but later we might want some of the info).
  3503.                        // filename and path starts at char position 19, 0 indexed
  3504.                        memcpy(materials[material_index + num_materials].texture_file, &parser.buffer[18], strlen(parser.buffer) - 18 + 2 );
  3505.                        // the OBJECT4DV2 is only allowed a single texture, although we are loading in all
  3506.                        // the materials, if this is the first texture map, load it, and set a flag disallowing
  3507.                        // any more texture loads for the object
  3508.                        if (!obj->texture)
  3509.                           {
  3510.                           // step 1: allocate memory for bitmap
  3511.                           obj->texture = (BITMAP_IMAGE_PTR)malloc(sizeof(BITMAP_IMAGE));
  3512.                           // load the texture, just use the final file name and the absolute global 
  3513.                           // texture path
  3514.                           char filename[80];
  3515.                           char path_filename[80];
  3516.                           // get the filename                     
  3517.                           Extract_Filename_From_Path(materials[material_index + num_materials].texture_file, filename);
  3518.                           // build the filename with root path
  3519.                           strcpy(path_filename, texture_path);
  3520.                           strcat(path_filename, filename);
  3521.                           // buffer now holds final texture path and file name
  3522.                           // load the bitmap(8/16 bit)
  3523.                           Load_Bitmap_File(&bitmap16bit, path_filename);
  3524.                           // create a proper size and bitdepth bitmap
  3525.                           Create_Bitmap(obj->texture,0,0,
  3526.                                         bitmap16bit.bitmapinfoheader.biWidth,
  3527.                                         bitmap16bit.bitmapinfoheader.biHeight,
  3528.                                         bitmap16bit.bitmapinfoheader.biBitCount);
  3529.                           
  3530.                           // load the bitmap image (later make this 8/16 bit)
  3531.                           if (obj->texture->bpp == 16)
  3532.                              Load_Image_Bitmap16(obj->texture, &bitmap16bit,0,0,BITMAP_EXTRACT_MODE_ABS);
  3533.                           else
  3534.                              {
  3535.                              Load_Image_Bitmap(obj->texture, &bitmap16bit,0,0,BITMAP_EXTRACT_MODE_ABS);
  3536.                              } // end else 8 bit
  3537.                           // done, so unload the bitmap
  3538.                           Unload_Bitmap_File(&bitmap16bit);
  3539.                           // flag object as having textures
  3540.                           SET_BIT(obj->attr, OBJECT4DV2_ATTR_TEXTURES);
  3541.                           } // end if
  3542.                        break;
  3543.                        } // end if
  3544.                     } // end while
  3545.                 break;
  3546.                 } // end if
  3547.             } // end while 
  3548.        ////////////////////////////////////////////////////////////////////////////////////////////
  3549.        // ADDED CODE FOR TRANSPARENCY AND ALPHA BLENDING //////////////////////////////////////////
  3550.        ////////////////////////////////////////////////////////////////////////////////////////////
  3551.        // Now we need to know if there is any transparency for the material
  3552.        // we have decided to encoded this in the shader class: transparency :)
  3553.        // also, you must use the "filter" shader, and then set the RGB color to
  3554.        // the level of transparency you want, 0,0,0 means totally transparent
  3555.        // 255,255,255 means totally opaque, so we are looking for something like
  3556.        // this:
  3557.        // Shader class: transparency
  3558.        // Shader name: "filter" (plain)
  3559.        // Number of parameters: 1
  3560.        // colour: color (146, 146, 146)
  3561.        // 
  3562.        // and if there isn't transparency then we will see this:
  3563.        //
  3564.        // Shader class: transparency
  3565.        // Shader name: "none" (none)
  3566.        // Number of parameters: 0
  3567.        // 
  3568.        // now, since we aren't doing anykind of RGB transparency, we are only concerned
  3569.        // with the overall value, so the way, I am going to do this is to look at the 
  3570.        // 3 values of R, G, B, and use the highest one as the final alpha/transparency 
  3571.        // value, so a value of 255, 255, 255 with be 100% alpha or totally opaque
  3572.       
  3573.        //  look for the "Shader class: transparency"
  3574.        while(1)
  3575.             {
  3576.             // get the next line
  3577.             if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3578.                {
  3579.                Write_Error("nshader transparency class not found in .COB file %s.", filename);
  3580.                return(0);
  3581.                } // end if
  3582.             // look for "Shader class: transparency"
  3583.             if (parser.Pattern_Match(parser.buffer, "['Shader'] ['class:'] ['transparency']") )
  3584.                {
  3585.                // now we know the next "shader name" is what we are looking for so, break
  3586.                break;
  3587.                } // end if
  3588.              } // end while    
  3589.         while(1)
  3590.              {
  3591.              // get the next line
  3592.              if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3593.                 {
  3594.                 Write_Error("nshader name ended abruptly! in .COB file %s.", filename);
  3595.                 return(0);
  3596.                 } // end if
  3597.          
  3598.              // get rid of those quotes
  3599.              ReplaceChars(parser.buffer, parser.buffer, """,' ',1);
  3600.              // did we find the name?
  3601.             if (parser.Pattern_Match(parser.buffer, "['Shader'] ['name:'] [s>0]" ) )
  3602.                {
  3603.                // figure out if transparency is enabled
  3604.                if (strcmp(parser.pstrings[2], "none") == 0)
  3605.                   {
  3606.                   // disable the alpha bit and write 0 alpha
  3607.                   RESET_BIT(materials[material_index + num_materials].attr, MATV1_ATTR_TRANSPARENT);
  3608.     
  3609.                   // set alpha to 0, unused
  3610.                   materials[material_index + num_materials].color.a = 0;
  3611.                   } // end if
  3612.                else
  3613.                if (strcmp(parser.pstrings[2], "filter") == 0)
  3614.                   {
  3615.                   // enable the alpha bit and write the alpha level
  3616.                   SET_BIT(materials[material_index + num_materials].attr, MATV1_ATTR_TRANSPARENT);
  3617.                   // now search for color line to extract alpha level
  3618.                   //  look for the "Shader class: transparency"
  3619.                   while(1)
  3620.                        {
  3621.                        // get the next line
  3622.                        if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3623.                           {
  3624.                           Write_Error("ntransparency color not found in .COB file %s.", filename);
  3625.                           return(0);
  3626.                           } // end if
  3627.                           // get rid of extraneous characters
  3628.                           ReplaceChars(parser.buffer, parser.buffer, ":(,)",' ',1);
  3629.                         // look for colour: color (146, 146, 146)
  3630.                         if (parser.Pattern_Match(parser.buffer, "['colour'] ['color'] [i] [i] [i]") )
  3631.                            {
  3632.                            // set the alpha level to the highest value
  3633.                            int max_alpha = MAX(parser.pints[0], parser.pints[1]);
  3634.                            max_alpha = MAX(max_alpha, parser.pints[2]);
  3635.                            // set alpha value
  3636.                            materials[material_index + num_materials].color.a = 
  3637.                                                  (int)( (float)max_alpha/255 * (float)(NUM_ALPHA_LEVELS-1) + (float)0.5);
  3638.                            
  3639.                            // clamp
  3640.                            if (materials[material_index + num_materials].color.a >= NUM_ALPHA_LEVELS)
  3641.                                materials[material_index + num_materials].color.a = NUM_ALPHA_LEVELS-1;
  3642.                            break;
  3643.                            } // end if
  3644.             
  3645.                         } // end while    
  3646.                   } // end if
  3647.             break;
  3648.             } // end if
  3649.          } // end while
  3650.        //////////////////////////////////////////////////////////////////////////////////////////////
  3651.        // alright, finally! Now we need to know what the actual shader type, now in the COB format
  3652.        // I have decided that in the "reflectance" class that's where we will look at what kind
  3653.        // of shader is supposed to be used on the polygon
  3654.        //  look for the "Shader class: reflectance"
  3655.        while(1)
  3656.             {
  3657.             // get the next line
  3658.             if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3659.                {
  3660.                Write_Error("nshader reflectance class not found in .COB file %s.", filename);
  3661.                return(0);
  3662.                } // end if
  3663.             // look for "Shader class: reflectance"
  3664.             if (parser.Pattern_Match(parser.buffer, "['Shader'] ['class:'] ['reflectance']") )
  3665.                {
  3666.                // now we know the next "shader name" is what we are looking for so, break
  3667.                break;
  3668.                } // end if
  3669.              } // end while    
  3670.         // looking for "Shader name: "xxxxxx" (xxxxxx) " again, 
  3671.         // and based on it's value we map it to our shading system as follows:
  3672.         // "constant" -> MATV1_ATTR_SHADE_MODE_CONSTANT 
  3673.         // "matte"    -> MATV1_ATTR_SHADE_MODE_FLAT
  3674.         // "plastic"  -> MATV1_ATTR_SHADE_MODE_GOURAUD
  3675.         // "phong"    -> MATV1_ATTR_SHADE_MODE_FASTPHONG 
  3676.         // and in the case that in the "color" class, we found a "texture map" then the "shading mode" is
  3677.         // "texture map" -> MATV1_ATTR_SHADE_MODE_TEXTURE 
  3678.         // which must be logically or'ed with the other previous modes
  3679.         while(1)
  3680.              {
  3681.              // get the next line
  3682.              if (!parser.Getline(PARSER_STRIP_EMPTY_LINES | PARSER_STRIP_WS_ENDS))
  3683.                 {
  3684.                 Write_Error("nshader name ended abruptly! in .COB file %s.", filename);
  3685.                 return(0);
  3686.                 } // end if
  3687.          
  3688.              // get rid of those quotes
  3689.              ReplaceChars(parser.buffer, parser.buffer, """,' ',1);
  3690.              // did we find the name?
  3691.             if (parser.Pattern_Match(parser.buffer, "['Shader'] ['name:'] [s>0]" ) )
  3692.                {
  3693.                // figure out which shader to use
  3694.                if (strcmp(parser.pstrings[2], "constant") == 0)
  3695.                   {
  3696.                   // set the shading mode flag in material
  3697.                   SET_BIT(materials[material_index + num_materials].attr, MATV1_ATTR_SHADE_MODE_CONSTANT);
  3698.                   } // end if
  3699.                else
  3700.                if (strcmp(parser.pstrings[2], "matte") == 0)
  3701.                   {
  3702.                   // set the shading mode flag in material
  3703.                   SET_BIT(materials[material_index + num_materials].attr, MATV1_ATTR_SHADE_MODE_FLAT);
  3704.                   } // end if
  3705.                else
  3706.                if (strcmp(parser.pstrings[2], "plastic") == 0)
  3707.                   {