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

游戏

开发平台:

Visual C++

  1. // T3DLIB11.CPP -
  2. // I N C L U D E S ///////////////////////////////////////////////////////////
  3. #define DEBUG_ON
  4. #define WIN32_LEAN_AND_MEAN  
  5. #include <windows.h>   // include important windows stuff
  6. #include <windowsx.h> 
  7. #include <mmsystem.h>
  8. #include <objbase.h>
  9. #include <iostream.h> // include important C/C++ stuff
  10. #include <conio.h>
  11. #include <stdlib.h>
  12. #include <malloc.h>
  13. #include <memory.h>
  14. #include <string.h>
  15. #include <stdarg.h>
  16. #include <stdio.h>
  17. #include <math.h>
  18. #include <io.h>
  19. #include <fcntl.h>
  20. #include <direct.h>
  21. #include <wchar.h>
  22. #include <limits.h>
  23. #include <float.h>
  24. #include <search.h>
  25. #include <ddraw.h>      // needed for defs in T3DLIB1.H 
  26. #include "T3DLIB1.H"
  27. #include "T3DLIB4.H"
  28. #include "T3DLIB5.H"
  29. #include "T3DLIB6.H"
  30. #include "T3DLIB7.H"
  31. #include "T3DLIB8.H"
  32. #include "T3DLIB9.H"
  33. #include "T3DLIB10.H"
  34. #include "T3DLIB11.H"
  35. // DEFINES //////////////////////////////////////////////////////////////////
  36. // GLOBALS //////////////////////////////////////////////////////////////////
  37. // dot product look up table
  38. float dp_inverse_cos[360+2]; // 0 to 180 in .5 degree steps
  39.                              // the +2 for padding
  40. int bhv_nodes_visited;       // used to track how many nodes where visited
  41. // MACROS ////////////////////////////////////////////////
  42. // FUNCTIONS ////////////////////////////////////////////////////////////////
  43. void Intersect_Lines(float x0,float y0,float x1,float y1,
  44.                      float x2,float y2,float x3,float y3,
  45.                      float *xi,float *yi)
  46. {
  47. // this function computes the intersection of the sent lines
  48. // and returns the intersection point, note that the function assumes
  49. // the lines intersect. the function can handle vertical as well
  50. // as horizontal lines. note the function isn't very clever, it simply applies
  51. // the math, but we don't need speed since this is a pre-processing step
  52. // we could have used parametric lines if we wanted, but this is more straight
  53. // forward for this use, I want the intersection of 2 infinite lines
  54. // rather than line segments as the parametric system defines
  55. float a1,b1,c1, // constants of linear equations
  56.       a2,b2,c2,
  57.       det_inv,  // the inverse of the determinant of the coefficient matrix
  58.       m1,m2;    // the slopes of each line
  59. // compute slopes, note the cludge for infinity, however, this will
  60. // be close enough
  61. if ((x1-x0)!=0)
  62.    m1 = (y1-y0) / (x1-x0);
  63. else
  64.    m1 = (float)1.0E+20;   // close enough to infinity
  65. if ((x3-x2)!=0)
  66.    m2 = (y3-y2) / (x3-x2);
  67. else
  68.    m2 = (float)1.0E+20;   // close enough to infinity
  69. // compute constants 
  70. a1 = m1;
  71. a2 = m2;
  72. b1 = -1;
  73. b2 = -1;
  74. c1 = (y0-m1*x0);
  75. c2 = (y2-m2*x2);
  76. // compute the inverse of the determinate
  77. det_inv = 1 / (a1*b2 - a2*b1);
  78. // use cramers rule to compute xi and yi
  79. *xi=((b1*c2 - b2*c1)*det_inv);
  80. *yi=((a2*c1 - a1*c2)*det_inv);
  81. } // end Intersect_Lines
  82. /////////////////////////////////////////////////////////////////////////////
  83. void Bsp_Build_Tree(BSPNODEV1_PTR root)
  84. {
  85. // this function recursively builds the bsp tree from the root of the wall list
  86. // the function works by taking the wall list which begins as a linked list
  87. // of walls in no particular order, then it uses the wall at the TOP of the list
  88. // as the separating plane and then divides space with that wall computing
  89. // the walls on the front and back of the separating plane. The walls that are
  90. // determined to be on the front and back, are once again linked lists, that 
  91. // are each processed recursively in the same manner. When the process is 
  92. // complete the entire BSP tree is built with exactly one node/leaf per wall
  93. static BSPNODEV1_PTR next_wall,  // pointer to next wall to be processed
  94.                   front_wall,    // the front wall
  95.                   back_wall,     // the back wall
  96.                   temp_wall;     // a temporary wall
  97. static float dot_wall_1,              // dot products for test wall
  98.              dot_wall_2,
  99.              wall_x0,wall_y0,wall_z0, // working vars for test wall
  100.              wall_x1,wall_y1,wall_z1,
  101.              pp_x0,pp_y0,pp_z0,       // working vars for partitioning plane
  102.              pp_x1,pp_y1,pp_z1,
  103.              xi,zi;                   // points of intersection when the partioning
  104.                                       // plane cuts a wall in two
  105. static VECTOR4D test_vector_1,  // test vectors from the partioning plane
  106.                 test_vector_2;  // to the test wall to test the side
  107.                                 // of the partioning plane the test wall
  108.                                 // lies on
  109. static int front_flag = 0,      // flags if a wall is on the front or back
  110.            back_flag  = 0,      // of the partioning plane
  111.            index;               // looping index
  112. // SECTION 1 ////////////////////////////////////////////////////////////////
  113. // test if this tree is complete
  114. if (root==NULL)
  115.    return;
  116. // the root is the partitioning plane, partition the polygons using it
  117. next_wall  = root->link;
  118. root->link = NULL;
  119. // extract top two vertices of partioning plane wall for ease of calculations
  120. pp_x0 = root->wall.vlist[0].x;
  121. pp_y0 = root->wall.vlist[0].y;
  122. pp_z0 = root->wall.vlist[0].z;
  123. pp_x1 = root->wall.vlist[1].x;
  124. pp_y1 = root->wall.vlist[1].y;
  125. pp_z1 = root->wall.vlist[1].z;
  126. // SECTION 2  ////////////////////////////////////////////////////////////////
  127. // test if all walls have been partitioned
  128. while(next_wall)
  129.      {
  130.      // test which side test wall is relative to partioning plane
  131.      // defined by root
  132.      // first compute vectors from point on partioning plane to points on
  133.      // test wall
  134.      VECTOR4D_Build(&root->wall.vlist[0].v, 
  135.                     &next_wall->wall.vlist[0].v, 
  136.                     &test_vector_1);
  137.      VECTOR4D_Build(&root->wall.vlist[0].v,
  138.                     &next_wall->wall.vlist[1].v,
  139.                     &test_vector_2);
  140.      // now dot each test vector with the surface normal and analyze signs
  141.      // to determine half space
  142.      dot_wall_1 = VECTOR4D_Dot(&test_vector_1, &root->wall.normal);
  143.      dot_wall_2 = VECTOR4D_Dot(&test_vector_2, &root->wall.normal);
  144. // SECTION 3  ////////////////////////////////////////////////////////////////
  145.      // perform the tests
  146.      // case 0, the partioning plane and the test wall have a point in common
  147.      // this is a special case and must be accounted for, shorten the code
  148.      // we will set a pair of flags and then the next case will handle
  149.      // the actual insertion of the wall into BSP
  150.      // reset flags
  151.      front_flag = back_flag = 0;
  152.      // determine if wall is tangent to endpoints of partitioning wall
  153.      if (VECTOR4D_Equal(&root->wall.vlist[0].v ,&next_wall->wall.vlist[0].v) )
  154.         {
  155.         // p0 of partioning plane is the same at p0 of test wall
  156.         // we only need to see what side p1 of test wall in on
  157.         if (dot_wall_2 > 0)
  158.            front_flag = 1;
  159.         else
  160.            back_flag = 1;
  161.         } // end if
  162.      else
  163.      if (VECTOR4D_Equal(&root->wall.vlist[0].v, &next_wall->wall.vlist[1].v) )
  164.         {
  165.         // p0 of partioning plane is the same at p1 of test wall
  166.         // we only need to see what side p0 of test wall in on
  167.         if (dot_wall_1 > 0)
  168.            front_flag = 1;
  169.         else
  170.            back_flag = 1;
  171.         } // end if
  172.      else
  173.      if (VECTOR4D_Equal(&root->wall.vlist[1].v, &next_wall->wall.vlist[0].v) )
  174.         {
  175.         // p1 of partioning plane is the same at p0 of test wall
  176.         // we only need to see what side p1 of test wall in on
  177.         if (dot_wall_2 > 0)
  178.            front_flag = 1;
  179.         else
  180.            back_flag = 1;
  181.         } // end if
  182.      else
  183.      if (VECTOR4D_Equal(&root->wall.vlist[1].v, &next_wall->wall.vlist[1].v) )
  184.         {
  185.         // p1 of partioning plane is the same at p1 of test wall
  186.         // we only need to see what side p0 of test wall in on
  187.         if (dot_wall_1 > 0)
  188.            front_flag = 1;
  189.         else
  190.            back_flag = 1;
  191.         } // end if
  192. // SECTION 4  ////////////////////////////////////////////////////////////////
  193.      // case 1 both signs are the same or the front or back flag has been set
  194.      if ( (dot_wall_1 >= 0 && dot_wall_2 >= 0) || front_flag )
  195.         {
  196.         // place this wall on the front list
  197.         if (root->front==NULL)
  198.            {
  199.            // this is the first node
  200.            root->front      = next_wall;
  201.            next_wall        = next_wall->link;
  202.            front_wall       = root->front;
  203.            front_wall->link = NULL;
  204.            } // end if
  205.         else
  206.            {
  207.            // this is the nth node
  208.            front_wall->link = next_wall;
  209.            next_wall        = next_wall->link;
  210.            front_wall       = front_wall->link;
  211.            front_wall->link = NULL;
  212.            } // end else
  213.         } // end if both positive
  214. // SECTION  5 ////////////////////////////////////////////////////////////////
  215.      else // back side sub-case
  216.      if ( (dot_wall_1 < 0 && dot_wall_2 < 0) || back_flag)
  217.         {
  218.         // place this wall on the back list
  219.         if (root->back==NULL)
  220.            {
  221.            // this is the first node
  222.            root->back      = next_wall;
  223.            next_wall       = next_wall->link;
  224.            back_wall       = root->back;
  225.            back_wall->link = NULL;
  226.            } // end if
  227.         else
  228.            {
  229.            // this is the nth node
  230.            back_wall->link = next_wall;
  231.            next_wall       = next_wall->link;
  232.            back_wall       = back_wall->link;
  233.            back_wall->link = NULL;
  234.            } // end else
  235.         } // end if both negative
  236.      // case 2 both signs are different, we must partition the wall
  237. // SECTION 6  ////////////////////////////////////////////////////////////////
  238.      else
  239.      if ( (dot_wall_1 < 0 && dot_wall_2 >= 0) ||
  240.           (dot_wall_1 >= 0 && dot_wall_2 < 0))
  241.         {
  242.         // the partioning plane cuts the wall in half, the wall
  243.         // must be split into two walls
  244.         // extract top two vertices of test wall for ease of calculations
  245.         wall_x0 = next_wall->wall.vlist[0].x;
  246.         wall_y0 = next_wall->wall.vlist[0].y;
  247.         wall_z0 = next_wall->wall.vlist[0].z;
  248.         wall_x1 = next_wall->wall.vlist[1].x;
  249.         wall_y1 = next_wall->wall.vlist[1].y;
  250.         wall_z1 = next_wall->wall.vlist[1].z;
  251.         // compute the point of intersection between the walls
  252.         // note that the intersection takes place in the x-z plane 
  253.         Intersect_Lines(wall_x0, wall_z0, wall_x1, wall_z1,
  254.                         pp_x0,   pp_z0,   pp_x1,   pp_z1,
  255.                         &xi, &zi);
  256.         // here comes the tricky part, we need to split the wall in half and
  257.         // create two new walls. We'll do this by creating two new walls,
  258.         // placing them on the appropriate front and back lists and
  259.         // then deleting the original wall (hold your breath)...
  260.         // process first wall...
  261.         // allocate the memory for the wall
  262.         temp_wall = (BSPNODEV1_PTR)malloc(sizeof(BSPNODEV1));
  263.         // set links
  264.         temp_wall->front = NULL;
  265.         temp_wall->back  = NULL;
  266.         temp_wall->link  = NULL;
  267.         // poly normal is the same
  268.         temp_wall->wall.normal  = next_wall->wall.normal;
  269.         temp_wall->wall.nlength = next_wall->wall.nlength;
  270.         // poly color is the same
  271.         temp_wall->wall.color = next_wall->wall.color;
  272.         // poly material is the same
  273.         temp_wall->wall.mati = next_wall->wall.mati;
  274.         // poly texture is the same
  275.         temp_wall->wall.texture = next_wall->wall.texture;
  276.         // poly attributes are the same
  277.         temp_wall->wall.attr = next_wall->wall.attr;
  278.         // poly states are the same
  279.         temp_wall->wall.state = next_wall->wall.state;
  280.         temp_wall->id          = next_wall->id + WALL_SPLIT_ID; // add factor denote a split
  281.         // compute wall vertices
  282.         for (index = 0; index < 4; index++)
  283.             {
  284.             temp_wall->wall.vlist[index].x = next_wall->wall.vlist[index].x;
  285.             temp_wall->wall.vlist[index].y = next_wall->wall.vlist[index].y;
  286.             temp_wall->wall.vlist[index].z = next_wall->wall.vlist[index].z;
  287.             temp_wall->wall.vlist[index].w = 1;
  288.             // copy vertex attributes, texture coordinates, normal
  289.             temp_wall->wall.vlist[index].attr = next_wall->wall.vlist[index].attr;
  290.             temp_wall->wall.vlist[index].n    = next_wall->wall.vlist[index].n;
  291.             temp_wall->wall.vlist[index].t    = next_wall->wall.vlist[index].t;
  292.             } // end for index
  293.         // now modify vertices 1 and 2 to reflect intersection point
  294.         // but leave y alone since it's invariant for the wall spliting
  295.         temp_wall->wall.vlist[1].x = xi;
  296.         temp_wall->wall.vlist[1].z = zi;
  297.         temp_wall->wall.vlist[2].x = xi;
  298.         temp_wall->wall.vlist[2].z = zi;
  299. // SECTION 7  ////////////////////////////////////////////////////////////////
  300.         // insert new wall into front or back of root
  301.         if (dot_wall_1 >= 0)
  302.            {
  303.            // place this wall on the front list
  304.            if (root->front==NULL)
  305.               {
  306.               // this is the first node
  307.               root->front      = temp_wall;
  308.               front_wall       = root->front;
  309.               front_wall->link = NULL;
  310.               } // end if
  311.            else
  312.               {
  313.               // this is the nth node
  314.               front_wall->link = temp_wall;
  315.               front_wall       = front_wall->link;
  316.               front_wall->link = NULL;
  317.               } // end else
  318.            } // end if positive
  319.         else
  320.         if (dot_wall_1 < 0)
  321.            {
  322.            // place this wall on the back list
  323.            if (root->back==NULL)
  324.               {
  325.               // this is the first node
  326.               root->back      = temp_wall;
  327.               back_wall       = root->back;
  328.               back_wall->link = NULL;
  329.               } // end if
  330.            else
  331.               {
  332.               // this is the nth node
  333.               back_wall->link = temp_wall;
  334.               back_wall       = back_wall->link;
  335.               back_wall->link = NULL;
  336.               } // end else
  337.            } // end if negative
  338. // SECTION  8 ////////////////////////////////////////////////////////////////
  339.         // process second wall...
  340.         // allocate the memory for the wall
  341.         temp_wall = (BSPNODEV1_PTR)malloc(sizeof(BSPNODEV1));
  342.         // set links
  343.         temp_wall->front = NULL;
  344.         temp_wall->back  = NULL;
  345.         temp_wall->link  = NULL;
  346.         // poly normal is the same
  347.         temp_wall->wall.normal  = next_wall->wall.normal;
  348.         temp_wall->wall.nlength = next_wall->wall.nlength;
  349.         // poly color is the same
  350.         temp_wall->wall.color = next_wall->wall.color;
  351.         // poly material is the same
  352.         temp_wall->wall.mati = next_wall->wall.mati;
  353.         // poly texture is the same
  354.         temp_wall->wall.texture = next_wall->wall.texture;
  355.         // poly attributes are the same
  356.         temp_wall->wall.attr = next_wall->wall.attr;
  357.         // poly states are the same
  358.         temp_wall->wall.state = next_wall->wall.state;
  359.         temp_wall->id          = next_wall->id + WALL_SPLIT_ID; // add factor denote a split
  360.         // compute wall vertices
  361.         for (index=0; index < 4; index++)
  362.             {
  363.             temp_wall->wall.vlist[index].x = next_wall->wall.vlist[index].x;
  364.             temp_wall->wall.vlist[index].y = next_wall->wall.vlist[index].y;
  365.             temp_wall->wall.vlist[index].z = next_wall->wall.vlist[index].z;
  366.             temp_wall->wall.vlist[index].w = 1;
  367.             // copy vertex attributes, texture coordinates, normal
  368.             temp_wall->wall.vlist[index].attr = next_wall->wall.vlist[index].attr;
  369.             temp_wall->wall.vlist[index].n    = next_wall->wall.vlist[index].n;
  370.             temp_wall->wall.vlist[index].t    = next_wall->wall.vlist[index].t;
  371.             } // end for index
  372.         // now modify vertices 0 and 3 to reflect intersection point
  373.         // but leave y alone since it's invariant for the wall spliting
  374.         temp_wall->wall.vlist[0].x = xi;
  375.         temp_wall->wall.vlist[0].z = zi;
  376.         temp_wall->wall.vlist[3].x = xi;
  377.         temp_wall->wall.vlist[3].z = zi;
  378.         // insert new wall into front or back of root
  379.         if (dot_wall_2 >= 0)
  380.            {
  381.            // place this wall on the front list
  382.            if (root->front==NULL)
  383.               {
  384.               // this is the first node
  385.               root->front      = temp_wall;
  386.               front_wall       = root->front;
  387.               front_wall->link = NULL;
  388.               } // end if
  389.            else
  390.               {
  391.               // this is the nth node
  392.               front_wall->link = temp_wall;
  393.               front_wall       = front_wall->link;
  394.               front_wall->link = NULL;
  395.               } // end else
  396.            } // end if positive
  397.         else
  398.         if (dot_wall_2 < 0)
  399.            {
  400.            // place this wall on the back list
  401.            if (root->back==NULL)
  402.               {
  403.               // this is the first node
  404.               root->back      = temp_wall;
  405.               back_wall       = root->back;
  406.               back_wall->link = NULL;
  407.               } // end if
  408.            else
  409.               {
  410.               // this is the nth node
  411.               back_wall->link = temp_wall;
  412.               back_wall       = back_wall->link;
  413.               back_wall->link = NULL;
  414.               } // end else
  415.            } // end if negative
  416. // SECTION  9  ////////////////////////////////////////////////////////////////
  417.         // we are now done splitting the wall, so we can delete it
  418.         temp_wall = next_wall;
  419.         next_wall = next_wall->link;
  420.         // release the memory
  421.         free(temp_wall);
  422.         } // end else
  423.      } // end while
  424. // SECTION  10 ////////////////////////////////////////////////////////////////
  425. // recursively process front and back walls/sub-trees
  426. Bsp_Build_Tree(root->front);
  427. Bsp_Build_Tree(root->back);
  428. } // end Bsp_Build_Tree
  429. //////////////////////////////////////////////////////////////////////////////
  430. void Bsp_Print(BSPNODEV1_PTR root)
  431. {
  432. // this function performs a recursive in-order traversal of the BSP tree and
  433. // prints the results out to the file opened with fp_out as the handle
  434. // test if this child is null
  435. if (root==NULL)
  436.    {
  437.    Write_Error("nReached NULL node returning...");
  438.    return;
  439.    } // end if
  440. // search left tree (back walls)
  441. Write_Error("nTraversing back sub-tree...");
  442. // call recursively
  443. Bsp_Print(root->back);
  444. // visit node
  445. Write_Error("nnnWall ID #%d",root->id);
  446. Write_Error("nstate   = %d", root->wall.state);      // state information
  447. Write_Error("nattr    = %d", root->wall.attr);       // physical attributes of polygon
  448. Write_Error("ncolor   = %d", root->wall.color);      // color of polygon
  449. Write_Error("ntexture = %x", root->wall.texture);    // pointer to the texture information for simple texture mapping
  450. Write_Error("nmati    = %d", root->wall.mati);       // material index (-1) for no material  (new)
  451. Write_Error("nVertex 0: (%f,%f,%f,%f)",root->wall.vlist[0].x,
  452.                                         root->wall.vlist[0].y,
  453.                                         root->wall.vlist[0].z,
  454.                                         root->wall.vlist[0].w);
  455. Write_Error("nVertex 1: (%f,%f,%f, %f)",root->wall.vlist[1].x,
  456.                                          root->wall.vlist[1].y,
  457.                                          root->wall.vlist[1].z,
  458.                                          root->wall.vlist[1].w);
  459. Write_Error("nVertex 2: (%f,%f,%f, %f)",root->wall.vlist[2].x,
  460.                                          root->wall.vlist[2].y,
  461.                                          root->wall.vlist[2].z,
  462.                                          root->wall.vlist[2].w);
  463. Write_Error("nVertex 3: (%f,%f,%f, %f)",root->wall.vlist[3].x,
  464.                                          root->wall.vlist[3].y,
  465.                                          root->wall.vlist[3].z,
  466.                                          root->wall.vlist[3].w);
  467. Write_Error("nNormal (%f,%f,%f, %f), length=%f",root->wall.normal.x,
  468.                                                  root->wall.normal.y,
  469.                                                  root->wall.normal.z,
  470.                                                  root->wall.nlength);
  471. Write_Error("nTextCoords (%f,%f)",root->wall.vlist[1].u0,
  472.                                    root->wall.vlist[1].v0);
  473. Write_Error("nEnd wall datan");
  474. // search right tree (front walls)
  475. Write_Error("nTraversing front sub-tree..");
  476. Bsp_Print(root->front);
  477. } // end Bsp_Print
  478. //////////////////////////////////////////////////////////////////////////////
  479. void Bsp_Delete(BSPNODEV1_PTR root)
  480. {
  481. // this function recursively deletes all the nodes in the bsp tree and free's
  482. // the memory back to the OS.
  483. BSPNODEV1_PTR temp_wall; // a temporary wall
  484. // test if we have hit a dead end
  485. if (root==NULL)
  486.    return;
  487. // delete back sub tree
  488. Bsp_Delete(root->back);
  489. // delete this node, but first save the front sub-tree
  490. temp_wall = root->front;
  491. // delete the memory
  492. free(root);
  493. // assign the root to the saved front most sub-tree
  494. root = temp_wall;
  495. // delete front sub tree
  496. Bsp_Delete(root);
  497. } // end Bsp_Delete
  498. ///////////////////////////////////////////////////////////////////////////////
  499. void Bsp_Insertion_Traversal_RENDERLIST4DV2(RENDERLIST4DV2_PTR rend_list, 
  500.                                             BSPNODEV1_PTR root,
  501.                                             CAM4DV1_PTR cam,
  502.                                             int insert_local=0)
  503.                                       
  504. {
  505. // converts the entire bsp tree into a face list and then inserts
  506. // the visible, active, non-clipped, non-culled polygons into
  507. // the render list, also note the flag insert_local control 
  508. // whether or not the vlist_local or vlist_trans vertex list
  509. // is used, thus you can insert a bsp tree "raw" totally untranformed
  510. // if you set insert_local to 1, default is 0, that is you would
  511. // only insert an object after at least the local to world transform
  512. // the functions walks the tree recursively in back to front order
  513. // relative to the viewpoint sent in cam, the bsp must be in world coordinates
  514. // for this to work correctly
  515. // this function works be testing the viewpoint against the current wall
  516. // in the bsp, then depending on the side the viewpoint is the algorithm
  517. // proceeds. the search takes place as the rest in an "inorder" method
  518. // with hooks to process and add each node into the polygon list at the
  519. // right time
  520. static VECTOR4D test_vector;
  521. static float dot_wall;
  522. // SECTION 1  ////////////////////////////////////////////////////////////////
  523. //Write_Error("nEntering Bsp_Insertion_Traversal_RENDERLIST4DV2()...");
  524. //Write_Error("nTesting root...");
  525. // is this a dead end?
  526. if (root==NULL)
  527.    {
  528.    //Write_Error("nRoot was null...");
  529.    return;
  530.    } // end if
  531. //Write_Error("nRoot was valid...");
  532. // test which side viewpoint is on relative to the current wall
  533. VECTOR4D_Build(&root->wall.vlist[0].v, &cam->pos, &test_vector);
  534. // now dot test vector with the surface normal and analyze signs
  535. dot_wall = VECTOR4D_Dot(&test_vector, &root->wall.normal);
  536. //Write_Error("nTesting dot product...");
  537. // SECTION 2  ////////////////////////////////////////////////////////////////
  538. // if the sign of the dot product is positive then the viewer on on the
  539. // front side of current wall, so recursively process the walls behind then
  540. // in front of this wall, else do the opposite
  541. if (dot_wall > 0)
  542.    {
  543.    // viewer is in front of this wall
  544.    //Write_Error("nDot > 0, front side...");
  545.    // process the back wall sub tree
  546.    Bsp_Insertion_Traversal_RENDERLIST4DV2(rend_list, root->back, cam, insert_local);
  547.    // split quad into (2) triangles for insertion
  548.    POLYF4DV2 poly1, poly2;
  549.    // the only difference from the POLYF4DV2 and the POLYF4DV2Q is that
  550.    // the later has (4) vertices rather than (3), thus we are going to
  551.    // create (2) triangles from the single quad :)
  552.    // copy fields that are important
  553.    poly1.state   = root->wall.state;      // state information
  554.    poly1.attr    = root->wall.attr;       // physical attributes of polygon
  555.    poly1.color   = root->wall.color;      // color of polygon
  556.    poly1.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  557.    poly1.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  558.    poly1.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  559.    poly1.normal  = root->wall.normal;     // the general polygon normal (new)
  560.    poly2.state   = root->wall.state;      // state information
  561.    poly2.attr    = root->wall.attr;       // physical attributes of polygon
  562.    poly2.color   = root->wall.color;      // color of polygon
  563.    poly2.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  564.    poly2.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  565.    poly2.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  566.    poly2.normal  = root->wall.normal;     // the general polygon normal (new)
  567.    // now the vertices, they currently look like this
  568.    // v0      v1
  569.    //
  570.    //
  571.    // v3      v2
  572.    // we want to create (2) triangles that look like this
  573.    //    poly 1           poly2
  574.    // v0      v1                v1  
  575.    // 
  576.    //        
  577.    //
  578.    // v3                v3      v2        
  579.    // 
  580.    // where the winding order of poly 1 is v0,v1,v3 and the winding order
  581.    // of poly 2 is v1, v2, v3 to keep with our clockwise conventions
  582.    if (insert_local==1)
  583.       {
  584.       // polygon 1
  585.       poly1.vlist[0]  = root->wall.vlist[0];  // the vertices of this triangle 
  586.       poly1.tvlist[0] = root->wall.vlist[0];  // the vertices of this triangle    
  587.       poly1.vlist[1]  = root->wall.vlist[1];  // the vertices of this triangle 
  588.       poly1.tvlist[1] = root->wall.vlist[1];  // the vertices of this triangle  
  589.       poly1.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  590.       poly1.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  591.       // polygon 2
  592.       poly2.vlist[0]  = root->wall.vlist[1];  // the vertices of this triangle 
  593.       poly2.tvlist[0] = root->wall.vlist[1];  // the vertices of this triangle    
  594.       poly2.vlist[1]  = root->wall.vlist[2];  // the vertices of this triangle 
  595.       poly2.tvlist[1] = root->wall.vlist[2];  // the vertices of this triangle  
  596.       poly2.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  597.       poly2.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  598.       } // end if
  599.    else
  600.       {
  601.       // polygon 1
  602.       poly1.vlist[0]  = root->wall.vlist[0];   // the vertices of this triangle 
  603.       poly1.tvlist[0] = root->wall.tvlist[0];  // the vertices of this triangle    
  604.       poly1.vlist[1]  = root->wall.vlist[1];   // the vertices of this triangle 
  605.       poly1.tvlist[1] = root->wall.tvlist[1];  // the vertices of this triangle  
  606.       poly1.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  607.       poly1.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  608.       // polygon 2
  609.       poly2.vlist[0]  = root->wall.vlist[1];   // the vertices of this triangle 
  610.       poly2.tvlist[0] = root->wall.tvlist[1];  // the vertices of this triangle    
  611.       poly2.vlist[1]  = root->wall.vlist[2];   // the vertices of this triangle 
  612.       poly2.tvlist[1] = root->wall.tvlist[2];  // the vertices of this triangle  
  613.       poly2.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  614.       poly2.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  615.       } // end if
  616.     //Write_Error("nInserting polygons...");
  617.    // insert polygons into rendering list
  618.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly1);
  619.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly2);
  620.    // now process the front walls sub tree
  621.    Bsp_Insertion_Traversal_RENDERLIST4DV2(rend_list, root->front, cam, insert_local);
  622.    } // end if
  623. // SECTION 3 ////////////////////////////////////////////////////////////////
  624. else
  625.    {
  626.    // viewer is behind this wall
  627.    //Write_Error("nDot < 0, back side...");
  628.    // process the back wall sub tree
  629.    Bsp_Insertion_Traversal_RENDERLIST4DV2(rend_list, root->front, cam, insert_local);
  630.    // split quad into (2) triangles for insertion
  631.    POLYF4DV2 poly1, poly2;
  632.    // the only difference from the POLYF4DV2 and the POLYF4DV2Q is that
  633.    // the later has (4) vertices rather than (3), thus we are going to
  634.    // create (2) triangles from the single quad :)
  635.    // copy fields that are important
  636.    poly1.state   = root->wall.state;      // state information
  637.    poly1.attr    = root->wall.attr;       // physical attributes of polygon
  638.    poly1.color   = root->wall.color;      // color of polygon
  639.    poly1.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  640.    poly1.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  641.    poly1.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  642.    poly1.normal  = root->wall.normal;     // the general polygon normal (new)
  643.    poly2.state   = root->wall.state;      // state information
  644.    poly2.attr    = root->wall.attr;       // physical attributes of polygon
  645.    poly2.color   = root->wall.color;      // color of polygon
  646.    poly2.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  647.    poly2.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  648.    poly2.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  649.    poly2.normal  = root->wall.normal;     // the general polygon normal (new)
  650.    // now the vertices, they currently look like this
  651.    // v0      v1
  652.    //
  653.    //
  654.    // v3      v2
  655.    // we want to create (2) triangles that look like this
  656.    //    poly 1           poly2
  657.    // v0      v1                v1  
  658.    // 
  659.    //        
  660.    //
  661.    // v3                v3      v2        
  662.    // 
  663.    // where the winding order of poly 1 is v0,v1,v3 and the winding order
  664.    // of poly 2 is v1, v2, v3 to keep with our clockwise conventions
  665.    if (insert_local==1)
  666.       {
  667.       // polygon 1
  668.       poly1.vlist[0]  = root->wall.vlist[0];  // the vertices of this triangle 
  669.       poly1.tvlist[0] = root->wall.vlist[0];  // the vertices of this triangle    
  670.       poly1.vlist[1]  = root->wall.vlist[1];  // the vertices of this triangle 
  671.       poly1.tvlist[1] = root->wall.vlist[1];  // the vertices of this triangle  
  672.       poly1.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  673.       poly1.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  674.       // polygon 2
  675.       poly2.vlist[0]  = root->wall.vlist[1];  // the vertices of this triangle 
  676.       poly2.tvlist[0] = root->wall.vlist[1];  // the vertices of this triangle    
  677.       poly2.vlist[1]  = root->wall.vlist[2];  // the vertices of this triangle 
  678.       poly2.tvlist[1] = root->wall.vlist[2];  // the vertices of this triangle  
  679.       poly2.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  680.       poly2.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  681.       } // end if
  682.    else
  683.       {
  684.       // polygon 1
  685.       poly1.vlist[0]  = root->wall.vlist[0];   // the vertices of this triangle 
  686.       poly1.tvlist[0] = root->wall.tvlist[0];  // the vertices of this triangle    
  687.       poly1.vlist[1]  = root->wall.vlist[1];   // the vertices of this triangle 
  688.       poly1.tvlist[1] = root->wall.tvlist[1];  // the vertices of this triangle  
  689.       poly1.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  690.       poly1.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  691.       // polygon 2
  692.       poly2.vlist[0]  = root->wall.vlist[1];   // the vertices of this triangle 
  693.       poly2.tvlist[0] = root->wall.tvlist[1];  // the vertices of this triangle    
  694.       poly2.vlist[1]  = root->wall.vlist[2];   // the vertices of this triangle 
  695.       poly2.tvlist[1] = root->wall.tvlist[2];  // the vertices of this triangle  
  696.       poly2.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  697.       poly2.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  698.       } // end if
  699.    //Write_Error("nInserting polygons...");
  700.    // insert polygons into rendering list
  701.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly1);
  702.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly2);
  703.    // now process the front walls sub tree
  704.    Bsp_Insertion_Traversal_RENDERLIST4DV2(rend_list, root->back, cam, insert_local);
  705.    } // end else
  706. //Write_Error("nExiting Bsp_Insertion_Traversal_RENDERLIST4DV2()...");
  707. } // end Bsp_Insertion_Traversal_RENDERLIST4DV2
  708. ///////////////////////////////////////////////////////////////////////////////
  709. void Bsp_Insertion_Traversal_RemoveBF_RENDERLIST4DV2(RENDERLIST4DV2_PTR rend_list, 
  710.                                                              BSPNODEV1_PTR root,
  711.                                                              CAM4DV1_PTR cam,
  712.                                                              int insert_local=0)
  713.                                       
  714. {
  715. // converts the entire bsp tree into a face list and then inserts
  716. // the visible, active, non-clipped, non-culled polygons into
  717. // the render list, also note the flag insert_local control 
  718. // whether or not the vlist_local or vlist_trans vertex list
  719. // is used, thus you can insert a bsp tree "raw" totally untranformed
  720. // if you set insert_local to 1, default is 0, that is you would
  721. // only insert an object after at least the local to world transform
  722. // the functions walks the tree recursively in back to front order
  723. // relative to the viewpoint sent in cam, the bsp must be in world coordinates
  724. // for this to work correctly
  725. // this function works be testing the viewpoint against the current wall
  726. // in the bsp, then depending on the side the viewpoint is the algorithm
  727. // proceeds. the search takes place as the rest in an "inorder" method
  728. // with hooks to process and add each node into the polygon list at the
  729. // right time
  730. // additionally the function tests for backfaces on the fly and only inserts
  731. // polygons that are not backfacing the viewpoint
  732. // also, it's up to the caller to make sure that cam->n has the valid look at 
  733. // view vector for euler or UVN model
  734. static VECTOR4D test_vector;
  735. static float dot_wall;
  736. // SECTION 1  ////////////////////////////////////////////////////////////////
  737. //Write_Error("nEntering Bsp_Insertion_Traversal_RENDERLIST4DV2()...");
  738. //Write_Error("nTesting root...");
  739. // is this a dead end?
  740. if (root==NULL)
  741.    {
  742.    //Write_Error("nRoot was null...");
  743.    return;
  744.    } // end if
  745. //Write_Error("nRoot was valid...");
  746. // test which side viewpoint is on relative to the current wall
  747. VECTOR4D_Build(&root->wall.vlist[0].v, &cam->pos, &test_vector);
  748. // now dot test vector with the surface normal and analyze signs
  749. dot_wall = VECTOR4D_Dot(&test_vector, &root->wall.normal);
  750. //Write_Error("nTesting dot product...");
  751. // SECTION 2  ////////////////////////////////////////////////////////////////
  752. // if the sign of the dot product is positive then the viewer on on the
  753. // front side of current wall, so recursively process the walls behind then
  754. // in front of this wall, else do the opposite
  755. if (dot_wall > 0)
  756.    {
  757.    // viewer is in front of this wall
  758.    //Write_Error("nDot > 0, front side...");
  759.    // process the back wall sub tree
  760.    Bsp_Insertion_Traversal_RemoveBF_RENDERLIST4DV2(rend_list, root->back, cam, insert_local);
  761.    // we want to cull polygons that can't be seen from the current viewpoint
  762.    // based not only on the view position, but the viewing angle, hence
  763.    // we first determine if we are on the front or back side of the partitioning
  764.    // plane, then we compute the angle theta from the partitioning plane
  765.    // normal to the viewing direction the player is currently pointing
  766.    // then we ask the question given the field of view and the current
  767.    // viewing direction, can the player see this plane? the answer boils down
  768.    // to the following tests
  769.    // front side test:
  770.    // if theta > (90 + fov/2)
  771.    // and for back side:
  772.    // if theta < (90 - fov/2)
  773.    // to compute theta we need this
  774.    // u . v = |u| * |v| * cos theta
  775.    // since |u| = |v| = 1, we can write
  776.    // u . v = cos theta, hence using the inverse cosine we can get the angle
  777.    // theta = arccosine(u . v)
  778.    // we use the lookup table created with the value of u . v : [-1,1] scaled to
  779.    // 0  to 180 (or 360 for .5 degree accuracy) to compute the angle which is 
  780.    // ALWAYS from 0 - 180, the 360 table just has more accurate entries.
  781.    float dp = VECTOR4D_Dot(&cam->n, &root->wall.normal);  
  782.    // polygon is visible if this is true
  783.    if (FAST_INV_COS(dp) > (90 - cam->fov/2) )
  784.    {
  785.    //////////////////////////////////////////////////////////////////////////// 
  786.    // split quad into (2) triangles for insertion
  787.    POLYF4DV2 poly1, poly2;
  788.    // the only difference from the POLYF4DV2 and the POLYF4DV2Q is that
  789.    // the later has (4) vertices rather than (3), thus we are going to
  790.    // create (2) triangles from the single quad :)
  791.    // copy fields that are important
  792.    poly1.state   = root->wall.state;      // state information
  793.    poly1.attr    = root->wall.attr;       // physical attributes of polygon
  794.    poly1.color   = root->wall.color;      // color of polygon
  795.    poly1.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  796.    poly1.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  797.    poly1.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  798.    poly1.normal  = root->wall.normal;     // the general polygon normal (new)
  799.    poly2.state   = root->wall.state;      // state information
  800.    poly2.attr    = root->wall.attr;       // physical attributes of polygon
  801.    poly2.color   = root->wall.color;      // color of polygon
  802.    poly2.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  803.    poly2.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  804.    poly2.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  805.    poly2.normal  = root->wall.normal;     // the general polygon normal (new)
  806.    // now the vertices, they currently look like this
  807.    // v0      v1
  808.    //
  809.    //
  810.    // v3      v2
  811.    // we want to create (2) triangles that look like this
  812.    //    poly 1           poly2
  813.    // v0      v1                v1  
  814.    // 
  815.    //        
  816.    //
  817.    // v3                v3      v2        
  818.    // 
  819.    // where the winding order of poly 1 is v0,v1,v3 and the winding order
  820.    // of poly 2 is v1, v2, v3 to keep with our clockwise conventions
  821.    if (insert_local==1)
  822.       {
  823.       // polygon 1
  824.       poly1.vlist[0]  = root->wall.vlist[0];  // the vertices of this triangle 
  825.       poly1.tvlist[0] = root->wall.vlist[0];  // the vertices of this triangle    
  826.       poly1.vlist[1]  = root->wall.vlist[1];  // the vertices of this triangle 
  827.       poly1.tvlist[1] = root->wall.vlist[1];  // the vertices of this triangle  
  828.       poly1.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  829.       poly1.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  830.       // polygon 2
  831.       poly2.vlist[0]  = root->wall.vlist[1];  // the vertices of this triangle 
  832.       poly2.tvlist[0] = root->wall.vlist[1];  // the vertices of this triangle    
  833.       poly2.vlist[1]  = root->wall.vlist[2];  // the vertices of this triangle 
  834.       poly2.tvlist[1] = root->wall.vlist[2];  // the vertices of this triangle  
  835.       poly2.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  836.       poly2.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  837.       } // end if
  838.    else
  839.       {
  840.       // polygon 1
  841.       poly1.vlist[0]  = root->wall.vlist[0];   // the vertices of this triangle 
  842.       poly1.tvlist[0] = root->wall.tvlist[0];  // the vertices of this triangle    
  843.       poly1.vlist[1]  = root->wall.vlist[1];   // the vertices of this triangle 
  844.       poly1.tvlist[1] = root->wall.tvlist[1];  // the vertices of this triangle  
  845.       poly1.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  846.       poly1.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  847.       // polygon 2
  848.       poly2.vlist[0]  = root->wall.vlist[1];   // the vertices of this triangle 
  849.       poly2.tvlist[0] = root->wall.tvlist[1];  // the vertices of this triangle    
  850.       poly2.vlist[1]  = root->wall.vlist[2];   // the vertices of this triangle 
  851.       poly2.tvlist[1] = root->wall.tvlist[2];  // the vertices of this triangle  
  852.       poly2.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  853.       poly2.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  854.       } // end if
  855.     //Write_Error("nInserting polygons...");
  856.    // insert polygons into rendering list
  857.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly1);
  858.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly2);
  859.    ////////////////////////////////////////////////////////////////////////////
  860.    } // end if visible
  861.    
  862.    // now process the front walls sub tree
  863.    Bsp_Insertion_Traversal_RemoveBF_RENDERLIST4DV2(rend_list, root->front, cam, insert_local);
  864.    } // end if
  865. // SECTION 3 ////////////////////////////////////////////////////////////////
  866. else
  867.    {
  868.    // viewer is behind this wall
  869.    //Write_Error("nDot < 0, back side...");
  870.    // process the back wall sub tree
  871.    Bsp_Insertion_Traversal_RemoveBF_RENDERLIST4DV2(rend_list, root->front, cam, insert_local);
  872.    // review explanation above...
  873.    float dp = VECTOR4D_Dot(&cam->n, &root->wall.normal);  
  874.    // polygon is visible if this is true
  875.    if (FAST_INV_COS(dp) < (90 + cam->fov/2) )
  876.    {
  877.    //////////////////////////////////////////////////////////////////////////// 
  878.    // split quad into (2) triangles for insertion
  879.    POLYF4DV2 poly1, poly2;
  880.    // the only difference from the POLYF4DV2 and the POLYF4DV2Q is that
  881.    // the later has (4) vertices rather than (3), thus we are going to
  882.    // create (2) triangles from the single quad :)
  883.    // copy fields that are important
  884.    poly1.state   = root->wall.state;      // state information
  885.    poly1.attr    = root->wall.attr;       // physical attributes of polygon
  886.    poly1.color   = root->wall.color;      // color of polygon
  887.    poly1.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  888.    poly1.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  889.    poly1.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  890.    poly1.normal  = root->wall.normal;     // the general polygon normal (new)
  891.    poly2.state   = root->wall.state;      // state information
  892.    poly2.attr    = root->wall.attr;       // physical attributes of polygon
  893.    poly2.color   = root->wall.color;      // color of polygon
  894.    poly2.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  895.    poly2.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  896.    poly2.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  897.    poly2.normal  = root->wall.normal;     // the general polygon normal (new)
  898.    // now the vertices, they currently look like this
  899.    // v0      v1
  900.    //
  901.    //
  902.    // v3      v2
  903.    // we want to create (2) triangles that look like this
  904.    //    poly 1           poly2
  905.    // v0      v1                v1  
  906.    // 
  907.    //        
  908.    //
  909.    // v3                v3      v2        
  910.    // 
  911.    // where the winding order of poly 1 is v0,v1,v3 and the winding order
  912.    // of poly 2 is v1, v2, v3 to keep with our clockwise conventions
  913.    if (insert_local==1)
  914.       {
  915.       // polygon 1
  916.       poly1.vlist[0]  = root->wall.vlist[0];  // the vertices of this triangle 
  917.       poly1.tvlist[0] = root->wall.vlist[0];  // the vertices of this triangle    
  918.       poly1.vlist[1]  = root->wall.vlist[1];  // the vertices of this triangle 
  919.       poly1.tvlist[1] = root->wall.vlist[1];  // the vertices of this triangle  
  920.       poly1.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  921.       poly1.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  922.       // polygon 2
  923.       poly2.vlist[0]  = root->wall.vlist[1];  // the vertices of this triangle 
  924.       poly2.tvlist[0] = root->wall.vlist[1];  // the vertices of this triangle    
  925.       poly2.vlist[1]  = root->wall.vlist[2];  // the vertices of this triangle 
  926.       poly2.tvlist[1] = root->wall.vlist[2];  // the vertices of this triangle  
  927.       poly2.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  928.       poly2.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  929.       } // end if
  930.    else
  931.       {
  932.       // polygon 1
  933.       poly1.vlist[0]  = root->wall.vlist[0];   // the vertices of this triangle 
  934.       poly1.tvlist[0] = root->wall.tvlist[0];  // the vertices of this triangle    
  935.       poly1.vlist[1]  = root->wall.vlist[1];   // the vertices of this triangle 
  936.       poly1.tvlist[1] = root->wall.tvlist[1];  // the vertices of this triangle  
  937.       poly1.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  938.       poly1.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  939.       // polygon 2
  940.       poly2.vlist[0]  = root->wall.vlist[1];   // the vertices of this triangle 
  941.       poly2.tvlist[0] = root->wall.tvlist[1];  // the vertices of this triangle    
  942.       poly2.vlist[1]  = root->wall.vlist[2];   // the vertices of this triangle 
  943.       poly2.tvlist[1] = root->wall.tvlist[2];  // the vertices of this triangle  
  944.       poly2.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  945.       poly2.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  946.       } // end if
  947.    //Write_Error("nInserting polygons...");
  948.    // insert polygons into rendering list
  949.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly1);
  950.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly2);
  951.    ////////////////////////////////////////////////////////////////////////////
  952.    } // end if visible
  953.  
  954.    // now process the front walls sub tree
  955.    Bsp_Insertion_Traversal_RemoveBF_RENDERLIST4DV2(rend_list, root->back, cam, insert_local);
  956.    } // end else
  957. //Write_Error("nExiting Bsp_Insertion_Traversal_RENDERLIST4DV2()...");
  958. } // end Bsp_Insertion_Traversal_RemoveBF_RENDERLIST4DV2
  959. /////////////////////////////////////////////////////////////////////
  960. void Bsp_Insertion_Traversal_FrustrumCull_RENDERLIST4DV2(RENDERLIST4DV2_PTR rend_list, 
  961.                                                          BSPNODEV1_PTR root,
  962.                                                          CAM4DV1_PTR cam,
  963.                                                          int insert_local=0)
  964.                                       
  965. {
  966. // converts the entire bsp tree into a face list and then inserts
  967. // the visible, active, non-clipped, non-culled polygons into
  968. // the render list, also note the flag insert_local control 
  969. // whether or not the vlist_local or vlist_trans vertex list
  970. // is used, thus you can insert a bsp tree "raw" totally untranformed
  971. // if you set insert_local to 1, default is 0, that is you would
  972. // only insert an object after at least the local to world transform
  973. // the functions walks the tree recursively in back to front order
  974. // relative to the viewpoint sent in cam, the bsp must be in world coordinates
  975. // for this to work correctly
  976. // this function works be testing the viewpoint against the current wall
  977. // in the bsp, then depending on the side the viewpoint is the algorithm
  978. // proceeds. the search takes place as the rest in an "inorder" method
  979. // with hooks to process and add each node into the polygon list at the
  980. // right time
  981. // additionally the function cull the BSP on the fly and only inserts
  982. // polygons that are not backfacing the viewpoint
  983. // also, it's up to the caller to make sure that cam->n has the valid look at 
  984. // view vector for euler or UVN model
  985. static VECTOR4D test_vector;
  986. static float dot_wall;
  987. // SECTION 1  ////////////////////////////////////////////////////////////////
  988. //Write_Error("nEntering Bsp_Insertion_Traversal_RENDERLIST4DV2()...");
  989. //Write_Error("nTesting root...");
  990. // is this a dead end?
  991. if (root==NULL)
  992.    {
  993.    //Write_Error("nRoot was null...");
  994.    return;
  995.    } // end if
  996. //Write_Error("nRoot was valid...");
  997. // test which side viewpoint is on relative to the current wall
  998. VECTOR4D_Build(&root->wall.vlist[0].v, &cam->pos, &test_vector);
  999. // now dot test vector with the surface normal and analyze signs
  1000. dot_wall = VECTOR4D_Dot(&test_vector, &root->wall.normal);
  1001. //Write_Error("nTesting dot product...");
  1002. // SECTION 2  ////////////////////////////////////////////////////////////////
  1003. // if the sign of the dot product is positive then the viewer on on the
  1004. // front side of current wall, so recursively process the walls behind then
  1005. // in front of this wall, else do the opposite
  1006. if (dot_wall > 0)
  1007.    {
  1008.    // viewer is in front of this wall
  1009.    //Write_Error("nDot > 0, front side...");
  1010.    // we want to cull sub spaces that can't be seen from the current viewpoint
  1011.    // based not only on the view position, but the viewing angle, hence
  1012.    // we first determine if we are on the front or back side of the partitioning
  1013.    // plane, then we compute the angle theta from the partitioning plane
  1014.    // normal to the viewing direction the player is currently pointing
  1015.    // then we ask the question given the field of view and the current
  1016.    // viewing direction, can the player see this plane? the answer boils down
  1017.    // to the following tests
  1018.    // front side test:
  1019.    // if theta > (90 + fov/2)
  1020.    // and for back side:
  1021.    // if theta < (90 - fov/2)
  1022.    // to compute theta we need this
  1023.    // u . v = |u| * |v| * cos theta
  1024.    // since |u| = |v| = 1, we can write
  1025.    // u . v = cos theta, hence using the inverse cosine we can get the angle
  1026.    // theta = arccosine(u . v)
  1027.    // we use the lookup table created with the value of u . v : [-1,1] scaled to
  1028.    // 0  to 180 (or 360 for .5 degree accuracy) to compute the angle which is 
  1029.    // ALWAYS from 0 - 180, the 360 table just has more accurate entries.
  1030.    float dp = VECTOR4D_Dot(&cam->n, &root->wall.normal);  
  1031.    // polygon is visible if this is true
  1032.    if (FAST_INV_COS(dp) > (90 - cam->fov/2) )
  1033.    {
  1034.    // process the back wall sub tree
  1035.    Bsp_Insertion_Traversal_FrustrumCull_RENDERLIST4DV2(rend_list, root->back, cam, insert_local);
  1036.    //////////////////////////////////////////////////////////////////////////// 
  1037.    // split quad into (2) triangles for insertion
  1038.    POLYF4DV2 poly1, poly2;
  1039.    // the only difference from the POLYF4DV2 and the POLYF4DV2Q is that
  1040.    // the later has (4) vertices rather than (3), thus we are going to
  1041.    // create (2) triangles from the single quad :)
  1042.    // copy fields that are important
  1043.    poly1.state   = root->wall.state;      // state information
  1044.    poly1.attr    = root->wall.attr;       // physical attributes of polygon
  1045.    poly1.color   = root->wall.color;      // color of polygon
  1046.    poly1.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  1047.    poly1.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  1048.    poly1.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  1049.    poly1.normal  = root->wall.normal;     // the general polygon normal (new)
  1050.    poly2.state   = root->wall.state;      // state information
  1051.    poly2.attr    = root->wall.attr;       // physical attributes of polygon
  1052.    poly2.color   = root->wall.color;      // color of polygon
  1053.    poly2.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  1054.    poly2.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  1055.    poly2.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  1056.    poly2.normal  = root->wall.normal;     // the general polygon normal (new)
  1057.    // now the vertices, they currently look like this
  1058.    // v0      v1
  1059.    //
  1060.    //
  1061.    // v3      v2
  1062.    // we want to create (2) triangles that look like this
  1063.    //    poly 1           poly2
  1064.    // v0      v1                v1  
  1065.    // 
  1066.    //        
  1067.    //
  1068.    // v3                v3      v2        
  1069.    // 
  1070.    // where the winding order of poly 1 is v0,v1,v3 and the winding order
  1071.    // of poly 2 is v1, v2, v3 to keep with our clockwise conventions
  1072.    if (insert_local==1)
  1073.       {
  1074.       // polygon 1
  1075.       poly1.vlist[0]  = root->wall.vlist[0];  // the vertices of this triangle 
  1076.       poly1.tvlist[0] = root->wall.vlist[0];  // the vertices of this triangle    
  1077.       poly1.vlist[1]  = root->wall.vlist[1];  // the vertices of this triangle 
  1078.       poly1.tvlist[1] = root->wall.vlist[1];  // the vertices of this triangle  
  1079.       poly1.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  1080.       poly1.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  1081.       // polygon 2
  1082.       poly2.vlist[0]  = root->wall.vlist[1];  // the vertices of this triangle 
  1083.       poly2.tvlist[0] = root->wall.vlist[1];  // the vertices of this triangle    
  1084.       poly2.vlist[1]  = root->wall.vlist[2];  // the vertices of this triangle 
  1085.       poly2.tvlist[1] = root->wall.vlist[2];  // the vertices of this triangle  
  1086.       poly2.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  1087.       poly2.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  1088.       } // end if
  1089.    else
  1090.       {
  1091.       // polygon 1
  1092.       poly1.vlist[0]  = root->wall.vlist[0];   // the vertices of this triangle 
  1093.       poly1.tvlist[0] = root->wall.tvlist[0];  // the vertices of this triangle    
  1094.       poly1.vlist[1]  = root->wall.vlist[1];   // the vertices of this triangle 
  1095.       poly1.tvlist[1] = root->wall.tvlist[1];  // the vertices of this triangle  
  1096.       poly1.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  1097.       poly1.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  1098.       // polygon 2
  1099.       poly2.vlist[0]  = root->wall.vlist[1];   // the vertices of this triangle 
  1100.       poly2.tvlist[0] = root->wall.tvlist[1];  // the vertices of this triangle    
  1101.       poly2.vlist[1]  = root->wall.vlist[2];   // the vertices of this triangle 
  1102.       poly2.tvlist[1] = root->wall.tvlist[2];  // the vertices of this triangle  
  1103.       poly2.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  1104.       poly2.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  1105.       } // end if
  1106.     //Write_Error("nInserting polygons...");
  1107.    // insert polygons into rendering list
  1108.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly1);
  1109.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly2);
  1110.    ////////////////////////////////////////////////////////////////////////////
  1111.    } // end if visible
  1112.    
  1113.    // now process the front walls sub tree
  1114.    Bsp_Insertion_Traversal_FrustrumCull_RENDERLIST4DV2(rend_list, root->front, cam, insert_local);
  1115.    } // end if
  1116. // SECTION 3 ////////////////////////////////////////////////////////////////
  1117. else
  1118.    {
  1119.    // viewer is behind this wall
  1120.    //Write_Error("nDot < 0, back side...");
  1121.    // review explanation above...
  1122.    float dp = VECTOR4D_Dot(&cam->n, &root->wall.normal);  
  1123.    // polygon is visible if this is true
  1124.    if (FAST_INV_COS(dp) < (90 + cam->fov/2) )
  1125.    {
  1126.    // process the back wall sub tree
  1127.    Bsp_Insertion_Traversal_FrustrumCull_RENDERLIST4DV2(rend_list, root->front, cam, insert_local);
  1128.    //////////////////////////////////////////////////////////////////////////// 
  1129.    // split quad into (2) triangles for insertion
  1130.    POLYF4DV2 poly1, poly2;
  1131.    // the only difference from the POLYF4DV2 and the POLYF4DV2Q is that
  1132.    // the later has (4) vertices rather than (3), thus we are going to
  1133.    // create (2) triangles from the single quad :)
  1134.    // copy fields that are important
  1135.    poly1.state   = root->wall.state;      // state information
  1136.    poly1.attr    = root->wall.attr;       // physical attributes of polygon
  1137.    poly1.color   = root->wall.color;      // color of polygon
  1138.    poly1.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  1139.    poly1.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  1140.    poly1.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  1141.    poly1.normal  = root->wall.normal;     // the general polygon normal (new)
  1142.    poly2.state   = root->wall.state;      // state information
  1143.    poly2.attr    = root->wall.attr;       // physical attributes of polygon
  1144.    poly2.color   = root->wall.color;      // color of polygon
  1145.    poly2.texture = root->wall.texture;    // pointer to the texture information for simple texture mapping
  1146.    poly2.mati    = root->wall.mati;       // material index (-1) for no material  (new)
  1147.    poly2.nlength = root->wall.nlength;    // length of the polygon normal if not normalized (new)
  1148.    poly2.normal  = root->wall.normal;     // the general polygon normal (new)
  1149.    // now the vertices, they currently look like this
  1150.    // v0      v1
  1151.    //
  1152.    //
  1153.    // v3      v2
  1154.    // we want to create (2) triangles that look like this
  1155.    //    poly 1           poly2
  1156.    // v0      v1                v1  
  1157.    // 
  1158.    //        
  1159.    //
  1160.    // v3                v3      v2        
  1161.    // 
  1162.    // where the winding order of poly 1 is v0,v1,v3 and the winding order
  1163.    // of poly 2 is v1, v2, v3 to keep with our clockwise conventions
  1164.    if (insert_local==1)
  1165.       {
  1166.       // polygon 1
  1167.       poly1.vlist[0]  = root->wall.vlist[0];  // the vertices of this triangle 
  1168.       poly1.tvlist[0] = root->wall.vlist[0];  // the vertices of this triangle    
  1169.       poly1.vlist[1]  = root->wall.vlist[1];  // the vertices of this triangle 
  1170.       poly1.tvlist[1] = root->wall.vlist[1];  // the vertices of this triangle  
  1171.       poly1.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  1172.       poly1.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  1173.       // polygon 2
  1174.       poly2.vlist[0]  = root->wall.vlist[1];  // the vertices of this triangle 
  1175.       poly2.tvlist[0] = root->wall.vlist[1];  // the vertices of this triangle    
  1176.       poly2.vlist[1]  = root->wall.vlist[2];  // the vertices of this triangle 
  1177.       poly2.tvlist[1] = root->wall.vlist[2];  // the vertices of this triangle  
  1178.       poly2.vlist[2]  = root->wall.vlist[3];  // the vertices of this triangle 
  1179.       poly2.tvlist[2] = root->wall.vlist[3];  // the vertices of this triangle  
  1180.       } // end if
  1181.    else
  1182.       {
  1183.       // polygon 1
  1184.       poly1.vlist[0]  = root->wall.vlist[0];   // the vertices of this triangle 
  1185.       poly1.tvlist[0] = root->wall.tvlist[0];  // the vertices of this triangle    
  1186.       poly1.vlist[1]  = root->wall.vlist[1];   // the vertices of this triangle 
  1187.       poly1.tvlist[1] = root->wall.tvlist[1];  // the vertices of this triangle  
  1188.       poly1.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  1189.       poly1.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  1190.       // polygon 2
  1191.       poly2.vlist[0]  = root->wall.vlist[1];   // the vertices of this triangle 
  1192.       poly2.tvlist[0] = root->wall.tvlist[1];  // the vertices of this triangle    
  1193.       poly2.vlist[1]  = root->wall.vlist[2];   // the vertices of this triangle 
  1194.       poly2.tvlist[1] = root->wall.tvlist[2];  // the vertices of this triangle  
  1195.       poly2.vlist[2]  = root->wall.vlist[3];   // the vertices of this triangle 
  1196.       poly2.tvlist[2] = root->wall.tvlist[3];  // the vertices of this triangle  
  1197.       } // end if
  1198.    //Write_Error("nInserting polygons...");
  1199.    // insert polygons into rendering list
  1200.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly1);
  1201.    Insert_POLYF4DV2_RENDERLIST4DV2(rend_list, &poly2);
  1202.    ////////////////////////////////////////////////////////////////////////////
  1203.    } // end if visible
  1204.  
  1205.    // now process the front walls sub tree
  1206.    Bsp_Insertion_Traversal_FrustrumCull_RENDERLIST4DV2(rend_list, root->back, cam, insert_local);
  1207.    } // end else
  1208. //Write_Error("nExiting Bsp_Insertion_Traversal_RENDERLIST4DV2()...");
  1209. } // end Bsp_Insertion_Traversal_FrustrumCull_RENDERLIST4DV2
  1210. /////////////////////////////////////////////////////////////////////
  1211. void Bsp_Transform(BSPNODEV1_PTR root,  // root of bsp tree
  1212.                    MATRIX4X4_PTR mt,    // transformation matrix
  1213.                    int coord_select)    // selects coords to transform)
  1214. {
  1215. // this function traverses the bsp tree and applies the transformation
  1216. // matrix to each node, the function is of course recursive and uses 
  1217. // and inorder traversal, other traversals such as preorder and postorder 
  1218. // will would just as well...
  1219. // test if we have hit a dead end
  1220. if (root==NULL)
  1221.    return;
  1222. // transform back most sub-tree
  1223. Bsp_Transform(root->back, mt, coord_select);
  1224. // iterate thru all vertices of current wall and transform them into
  1225. // camera coordinates
  1226. // what coordinates should be transformed?
  1227. switch(coord_select)
  1228.       {
  1229.       case TRANSFORM_LOCAL_ONLY:
  1230.            {
  1231.            // transform each local/model vertex of the object mesh in place
  1232.            for (int vertex = 0; vertex < 4; vertex++)
  1233.               {
  1234.               POINT4D presult; // hold result of each transformation
  1235.               // transform point
  1236.               Mat_Mul_VECTOR4D_4X4(&root->wall.vlist[vertex].v, mt, &presult);
  1237.               // store result back
  1238.               VECTOR4D_COPY(&root->wall.vlist[vertex].v, &presult); 
  1239.  
  1240.               // transform vertex normal if needed
  1241.               if (root->wall.vlist[vertex].attr & VERTEX4DTV1_ATTR_NORMAL)
  1242.                  {
  1243.                  // transform normal
  1244.                  Mat_Mul_VECTOR4D_4X4(&root->wall.vlist[vertex].n, mt, &presult);
  1245.                  // store result back
  1246.                  VECTOR4D_COPY(&root->wall.vlist[vertex].n, &presult); 
  1247.                  } // end if
  1248.                } // end for index
  1249.             } break;
  1250.  
  1251.       case TRANSFORM_TRANS_ONLY:
  1252.            {
  1253.            // transform each "transformed" vertex of the object mesh in place
  1254.            // remember, the idea of the vlist_trans[] array is to accumulate
  1255.            // transformations
  1256.            for (int vertex = 0; vertex < 4; vertex++)
  1257.               {
  1258.               POINT4D presult; // hold result of each transformation
  1259.               // transform point
  1260.               Mat_Mul_VECTOR4D_4X4(&root->wall.tvlist[vertex].v, mt, &presult);
  1261.               // store result back
  1262.               VECTOR4D_COPY(&root->wall.tvlist[vertex].v, &presult); 
  1263.  
  1264.               // transform vertex normal if needed
  1265.               if (root->wall.tvlist[vertex].attr & VERTEX4DTV1_ATTR_NORMAL)
  1266.                  {
  1267.                  // transform normal
  1268.                  Mat_Mul_VECTOR4D_4X4(&root->wall.tvlist[vertex].n, mt, &presult);
  1269.                  // store result back
  1270.                  VECTOR4D_COPY(&root->wall.tvlist[vertex].n, &presult); 
  1271.                  } // end if
  1272.                } // end for index
  1273.            } break;
  1274.        case TRANSFORM_LOCAL_TO_TRANS:
  1275.             {
  1276.             // transform each local/model vertex of the object mesh and store result
  1277.             // in "transformed" vertex list
  1278.             for (int vertex=0; vertex < 4; vertex++)
  1279.                 {
  1280.                 POINT4D presult; // hold result of each transformation
  1281.                 // transform point
  1282.                 Mat_Mul_VECTOR4D_4X4(&root->wall.vlist[vertex].v, mt, &root->wall.tvlist[vertex].v);
  1283.                 // transform vertex normal if needed
  1284.                 if (root->wall.tvlist[vertex].attr & VERTEX4DTV1_ATTR_NORMAL)
  1285.                    {
  1286.                    // transform point
  1287.                    Mat_Mul_VECTOR4D_4X4(&root->wall.vlist[vertex].n, mt, &root->wall.tvlist[vertex].n);
  1288.                    } // end if
  1289.                  } // end for index
  1290.            } break;
  1291.       default: break;
  1292.       } // end switch
  1293. // transform front most sub-tree
  1294. Bsp_Transform(root->front, mt, coord_select);
  1295. } // end Bsp_Insertion_Traversal_RENDERLIST4DV2
  1296. ////////////////////////////////////////////////////////////////////////
  1297. void Bsp_Translate(BSPNODEV1_PTR root, VECTOR4D_PTR trans)
  1298. {
  1299. // this function translates all the walls that make up the bsp world
  1300. // note function is recursive, we don't really need this function, but
  1301. // it's a good example of how we might perform transformations on the BSP
  1302. // tree and similar tree like structures using recursion
  1303. // note the translation is perform from local to world coords
  1304. static int index; // looping variable
  1305. // test if we have hit a dead end
  1306. if (root==NULL)
  1307.    return;
  1308. // translate back most sub-tree
  1309. Bsp_Translate(root->back, trans);
  1310. // iterate thru all vertices of current wall and translate them
  1311. for (index=0; index < 4; index++)
  1312.     {
  1313.     // perform translation
  1314.     root->wall.tvlist[index].x = root->wall.vlist[index].x + trans->x;
  1315.     root->wall.tvlist[index].y = root->wall.vlist[index].y + trans->y;
  1316.     root->wall.tvlist[index].z = root->wall.vlist[index].x + trans->z;
  1317.     } // end for index
  1318. // translate front most sub-tree
  1319. Bsp_Translate(root->front, trans);
  1320. } // end Bsp_Translate
  1321. ///////////////////////////////////////////////////////////////////////////////
  1322. ///////////////////////////////////////////////////////////////////////////////
  1323. void Build_Inverse_Cos_Table(float *invcos,     // storage for table
  1324.                              int   range_scale) // range for table to span
  1325.                              
  1326. {
  1327. // this function builds an inverse cosine table used to help with
  1328. // dot product calculations where the angle is needed rather than 
  1329. // the value -1 to 1, the function maps the values [-1, 1] to
  1330. // [0, range] and then breaks that interval up into n intervals
  1331. // where the interval size is 180/range then the function computes
  1332. // the arccos for each value -1 to 1 scaled and mapped as 
  1333. // referred to above and places the values in the table
  1334. // for example if the range is 360 then the interval will be
  1335. // [0, 360] therefore, since the inverse cosine must
  1336. // always be from 0 - 180, we are going to map 0 - 180 to 0 - 360
  1337. // or in other words, the array elements will each represent .5
  1338. // degree increments
  1339. // the table must be large enough to hold the results which will
  1340. // be = (range_scale+1) * sizeof(float)
  1341. // to use the table, the user must scale the value of [-1, 1] to the 
  1342. // exact table size, for example say you made a table with 0..180 
  1343. // the to access it with values from x = [-1, 1] would be:
  1344. // invcos[ (x+1)*180 ], the result would be the angle in degrees
  1345. // to a 1.0 degree accuracy.
  1346. float val = -1; // starting value
  1347. // create table
  1348. for (int index = 0; index <= range_scale; index++)
  1349.     {
  1350.     // insert next element in table in degrees
  1351.     val = (val > 1) ? 1 : val;
  1352.     invcos[index] = RAD_TO_DEG(acos(val));
  1353.     //Write_Error("ninvcos[%d] = %f, val = %f", index, invcos[index], val);
  1354.     // increment val by interval
  1355.     val += ((float)1/(float)(range_scale/2));
  1356.     } // end for index
  1357. // insert one more element for padding, so that durring access if there is
  1358. // an overflow of 1, we won't go out of bounds and we can save the clamp in the
  1359. // floating point logic
  1360. invcos[index] = invcos[index-1];
  1361. } // end Build_Inverse_Cos_Table
  1362. ///////////////////////////////////////////////////////////////////////////////
  1363. void Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16_2(RENDERCONTEXTV1_PTR rc)
  1364. {
  1365. // this function renders the rendering list, it's based on the new
  1366. // rendering context data structure which is container for everything
  1367. // we need to consider when rendering, z, 1/z buffering, alpha, mipmapping,
  1368. // perspective, bilerp, etc. the function is basically a merge of all the functions
  1369. // we have written thus far, so its rather long, but better than having 
  1370. // 20-30 rendering functions for all possible permutations!
  1371. // this new version _2 supports the new RENDER_ATTR_WRITETHRUZBUFFER 
  1372. // functionality in a very limited manner, it supports mip mapping in general
  1373. // no alpha blending, and only supports the following types:
  1374. // constant shaded, flat shaded, gouraud shaded 
  1375. // affine only: constant textured, flat textured, and gouraud textured
  1376. // when not using the RENDER_ATTR_WRITETHRUZBUFFER support, the 
  1377. // function is identical to the previous version
  1378. POLYF4DV2 face; // temp face used to render polygon
  1379. int alpha;      // alpha of the face
  1380. // we need to try and separate as much conditional logic as possible
  1381. // at the beginning of the function, so we can minimize it inline during
  1382. // the traversal of the polygon list, let's start by subclassing which
  1383. // kind of rendering we are doing none, z buffered, or 1/z buffered
  1384.                                       
  1385. if (rc->attr & RENDER_ATTR_NOBUFFER) ////////////////////////////////////
  1386. {
  1387. // no buffering at all
  1388. // at this point, all we have is a list of polygons and it's time
  1389. // to draw them
  1390. for (int poly=0; poly < rc->rend_list->num_polys; poly++)
  1391.     {
  1392.     // render this polygon if and only if it's not clipped, not culled,
  1393.     // active, and visible, note however the concecpt of "backface" is 
  1394.     // irrelevant in a wire frame engine though
  1395.     if (!(rc->rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_ACTIVE) ||
  1396.          (rc->rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_CLIPPED ) ||
  1397.          (rc->rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_BACKFACE) )
  1398.        continue; // move onto next poly
  1399.     // test for alpha override
  1400.     if (rc->alpha_override>= 0)
  1401.        {
  1402.        // set alpha to override value
  1403.        alpha = rc->alpha_override;
  1404.        }  // end if 
  1405.     else
  1406.         {
  1407.         // extract alpha (even if there isn't any)
  1408.         alpha = ((rc->rend_list->poly_ptrs[poly]->color & 0xff000000) >> 24);
  1409.         } // end else
  1410.     // need to test for textured first, since a textured poly can either
  1411.     // be emissive, or flat shaded, hence we need to call different
  1412.     // rasterizers    
  1413.     if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_TEXTURE)
  1414.        {
  1415.        // set the vertices
  1416.        face.tvlist[0].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].x;
  1417.        face.tvlist[0].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].y;
  1418.        face.tvlist[0].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].z;
  1419.        face.tvlist[0].u0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].u0;
  1420.        face.tvlist[0].v0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].v0;
  1421.        face.tvlist[1].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].x;
  1422.        face.tvlist[1].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].y;
  1423.        face.tvlist[1].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].z;
  1424.        face.tvlist[1].u0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].u0;
  1425.        face.tvlist[1].v0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].v0;
  1426.        face.tvlist[2].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].x;
  1427.        face.tvlist[2].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].y;
  1428.        face.tvlist[2].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].z;
  1429.        face.tvlist[2].u0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].u0;
  1430.        face.tvlist[2].v0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].v0;
  1431.        // test if this is a mipmapped polygon?
  1432.        if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_MIPMAP)
  1433.           {
  1434.           // determine if mipmapping is desired at all globally
  1435.           if (rc->attr & RENDER_ATTR_MIPMAP)
  1436.              {
  1437.              // determine mip level for this polygon
  1438.              // first determine how many miplevels there are in mipchain for this polygon
  1439.              int tmiplevels = logbase2ofx[((BITMAP_IMAGE_PTR *)(rc->rend_list->poly_ptrs[poly]->texture))[0]->width];
  1440.              // now based on the requested linear miplevel fall off distance, cut
  1441.              // the viewdistance into segments, determine what segment polygon is
  1442.              // in and select mip level -- simple! later you might want something more
  1443.              // robust, also note I only use a single vertex, you might want to find the average
  1444.              // since for long walls perpendicular to view direction this might causing mip
  1445.              // popping mid surface
  1446.              int miplevel = (tmiplevels * rc->rend_list->poly_ptrs[poly]->tvlist[0].z / rc->mip_dist);
  1447.           
  1448.              // clamp miplevel
  1449.              if (miplevel > tmiplevels) miplevel = tmiplevels;
  1450.              // based on miplevel select proper texture
  1451.              face.texture = ((BITMAP_IMAGE_PTR *)(rc->rend_list->poly_ptrs[poly]->texture))[miplevel];
  1452.              // now we must divide each texture coordinate by 2 per miplevel
  1453.              for (int ts = 0; ts < miplevel; ts++)
  1454.                  {
  1455.                  face.tvlist[0].u0*=.5;
  1456.                  face.tvlist[0].v0*=.5;
  1457.                  face.tvlist[1].u0*=.5;
  1458.                  face.tvlist[1].v0*=.5;
  1459.                  face.tvlist[2].u0*=.5;
  1460.                  face.tvlist[2].v0*=.5;
  1461.                 } // end for
  1462.              } // end if mipmmaping enabled globally
  1463.           else // mipmapping not selected globally
  1464.              {
  1465.              // in this case the polygon IS mipmapped, but the caller has requested NO
  1466.              // mipmapping, so we will support this by selecting mip level 0 since the
  1467.              // texture pointer is pointing to a mip chain regardless
  1468.              face.texture = ((BITMAP_IMAGE_PTR *)(rc->rend_list->poly_ptrs[poly]->texture))[0];
  1469.  
  1470.              // note: texture coordinate manipulation is unneeded
  1471.              } // end else
  1472.           } // end if
  1473.        else
  1474.           {
  1475.           // assign the texture without change
  1476.           face.texture = rc->rend_list->poly_ptrs[poly]->texture;
  1477.           } // end if
  1478.        
  1479.        // is this a plain emissive texture?
  1480.        if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_CONSTANT)
  1481.           {
  1482.           // draw the textured triangle as emissive
  1483.           if ((rc->attr & RENDER_ATTR_ALPHA) &&
  1484.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  1485.              {
  1486.              // alpha version
  1487.              
  1488.              // which texture mapper?
  1489.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  1490.                 {
  1491.                 Draw_Textured_Triangle_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1492.                 } // end if
  1493.              else
  1494.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  1495.                 {
  1496.                 // not supported yet!
  1497.                 Draw_Textured_Triangle_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1498.                 } // end if
  1499.              else
  1500.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  1501.                 {
  1502.                 // not supported yet
  1503.                 Draw_Textured_Triangle_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1504.                 } // end if
  1505.              else
  1506.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  1507.                 {
  1508.                 // test z distance again perspective transition gate
  1509.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  1510.                     {
  1511.                     // default back to affine
  1512.                     Draw_Textured_Triangle_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1513.                     } // end if
  1514.                 else
  1515.                     {
  1516.                     // use perspective linear
  1517.                     // not supported yet
  1518.                     Draw_Textured_Triangle_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1519.                     } // end if
  1520.                  } // end if
  1521.              } // end if
  1522.           else
  1523.              {
  1524.              // non alpha
  1525.              // which texture mapper?
  1526.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  1527.                 {
  1528.                 // use bilerp?
  1529.                 if (rc->attr & RENDER_ATTR_BILERP)
  1530.                    Draw_Textured_Bilerp_Triangle_16(&face, rc->video_buffer, rc->lpitch);               
  1531.                 else
  1532.                    Draw_Textured_Triangle2_16(&face, rc->video_buffer, rc->lpitch);
  1533.                 } // end if
  1534.              else
  1535.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  1536.                 {
  1537.                 // not supported yet
  1538.                 Draw_Textured_Triangle2_16(&face, rc->video_buffer, rc->lpitch);
  1539.                 } // end if
  1540.              else
  1541.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  1542.                 {
  1543.                 // not supported yet
  1544.                 Draw_Textured_Triangle2_16(&face, rc->video_buffer, rc->lpitch);
  1545.                 } // end if
  1546.              else
  1547.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  1548.                 {
  1549.                 // test z distance again perspective transition gate
  1550.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  1551.                     {
  1552.                     // default back to affine
  1553.                     Draw_Textured_Triangle2_16(&face, rc->video_buffer, rc->lpitch);
  1554.                     } // end if
  1555.                 else
  1556.                     {
  1557.                     // use perspective linear
  1558.                     // not supported yet
  1559.                     Draw_Textured_Triangle2_16(&face, rc->video_buffer, rc->lpitch);
  1560.                     } // end if
  1561.                 } // end if
  1562.              } // end if
  1563.           } // end if
  1564.        else
  1565.        if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT)
  1566.           {
  1567.           // draw as flat shaded
  1568.           face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  1569.           if ((rc->attr & RENDER_ATTR_ALPHA) &&
  1570.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  1571.              {
  1572.              // alpha version
  1573.              
  1574.              // which texture mapper?
  1575.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  1576.                 {
  1577.                 Draw_Textured_TriangleFS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1578.                 } // end if
  1579.              else
  1580.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  1581.                 {
  1582.                 // not supported yet!
  1583.                 Draw_Textured_TriangleFS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1584.                 } // end if
  1585.              else
  1586.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  1587.                 {
  1588.                 // not supported yet
  1589.                 Draw_Textured_TriangleFS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1590.                 } // end if
  1591.              else
  1592.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  1593.                 {
  1594.                 // test z distance again perspective transition gate
  1595.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  1596.                     {
  1597.                     // default back to affine
  1598.                     Draw_Textured_TriangleFS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1599.                     } // end if
  1600.                 else
  1601.                     {
  1602.                     // use perspective linear
  1603.                     // not supported yet
  1604.                     Draw_Textured_TriangleFS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1605.                     } // end if
  1606.                  } // end if
  1607.              } // end if
  1608.           else
  1609.              {
  1610.              // non alpha
  1611.              // which texture mapper?
  1612.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  1613.                 {
  1614.                 Draw_Textured_TriangleFS2_16(&face, rc->video_buffer, rc->lpitch);
  1615.                 } // end if
  1616.              else
  1617.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  1618.                 {
  1619.                 // not supported yet
  1620.                 Draw_Textured_TriangleFS2_16(&face, rc->video_buffer, rc->lpitch);
  1621.                 } // end if
  1622.              else
  1623.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  1624.                 {
  1625.                 // not supported yet
  1626.                 Draw_Textured_TriangleFS2_16(&face, rc->video_buffer, rc->lpitch);
  1627.                 } // end if
  1628.              else
  1629.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  1630.                 {
  1631.                 // test z distance again perspective transition gate
  1632.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  1633.                     {
  1634.                     // default back to affine
  1635.                     Draw_Textured_TriangleFS2_16(&face, rc->video_buffer, rc->lpitch);
  1636.                     } // end if
  1637.                 else
  1638.                     {
  1639.                     // use perspective linear
  1640.                     // not supported yet
  1641.                     Draw_Textured_TriangleFS2_16(&face, rc->video_buffer, rc->lpitch);
  1642.                     } // end if
  1643.                 } // end if
  1644.              } // end if
  1645.           } // end else
  1646.        else
  1647.           {
  1648.           // must be gouraud POLY4DV2_ATTR_SHADE_MODE_GOURAUD
  1649.           face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  1650.           face.lit_color[1] = rc->rend_list->poly_ptrs[poly]->lit_color[1];
  1651.           face.lit_color[2] = rc->rend_list->poly_ptrs[poly]->lit_color[2];
  1652.           if ((rc->attr & RENDER_ATTR_ALPHA) &&
  1653.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  1654.              {
  1655.              // alpha version
  1656.              
  1657.              // which texture mapper?
  1658.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  1659.                 {
  1660.                 Draw_Textured_TriangleGS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1661.                 } // end if
  1662.              else
  1663.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  1664.                 {
  1665.                 // not supported yet!
  1666.                 Draw_Textured_TriangleGS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1667.                 } // end if
  1668.              else
  1669.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  1670.                 {
  1671.                 // not supported yet
  1672.                 Draw_Textured_TriangleGS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1673.                 } // end if
  1674.              else
  1675.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  1676.                 {
  1677.                 // test z distance again perspective transition gate
  1678.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  1679.                     {
  1680.                     // default back to affine
  1681.                     Draw_Textured_TriangleGS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1682.                     } // end if
  1683.                 else
  1684.                     {
  1685.                     // use perspective linear
  1686.                     // not supported yet
  1687.                     Draw_Textured_TriangleGS_Alpha16(&face, rc->video_buffer, rc->lpitch, alpha);
  1688.                     } // end if
  1689.                  } // end if
  1690.              } // end if
  1691.           else
  1692.              {
  1693.              // non alpha
  1694.              // which texture mapper?
  1695.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  1696.                 {
  1697.                 Draw_Textured_TriangleGS_16(&face, rc->video_buffer, rc->lpitch);
  1698.                 } // end if
  1699.              else
  1700.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  1701.                 {
  1702.                 // not supported yet
  1703.                 Draw_Textured_TriangleGS_16(&face, rc->video_buffer, rc->lpitch);
  1704.                 } // end if
  1705.              else
  1706.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  1707.                 {
  1708.                 // not supported yet
  1709.                 Draw_Textured_TriangleGS_16(&face, rc->video_buffer, rc->lpitch);
  1710.                 } // end if
  1711.              else
  1712.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  1713.                 {
  1714.                 // test z distance again perspective transition gate
  1715.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  1716.                     {
  1717.                     // default back to affine
  1718.                     Draw_Textured_TriangleGS_16(&face, rc->video_buffer, rc->lpitch);
  1719.                     } // end if
  1720.                 else
  1721.                     {
  1722.                     // use perspective linear
  1723.                     // not supported yet
  1724.                     Draw_Textured_TriangleGS_16(&face, rc->video_buffer, rc->lpitch);
  1725.                     } // end if
  1726.                 } // end if
  1727.              } // end if
  1728.           } // end else
  1729.        } // end if      
  1730.     else
  1731.     if ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT) || 
  1732.         (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_CONSTANT) )
  1733.        {
  1734.        // draw as constant shaded
  1735.        face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  1736.        
  1737.        // set the vertices
  1738.        face.tvlist[0].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].x;
  1739.        face.tvlist[0].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].y;
  1740.        face.tvlist[0].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].z;
  1741.        face.tvlist[1].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].x;
  1742.        face.tvlist[1].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].y;
  1743.        face.tvlist[1].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].z;
  1744.        face.tvlist[2].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].x;
  1745.        face.tvlist[2].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].y;
  1746.        face.tvlist[2].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].z;
  1747.        // draw the triangle with basic flat rasterizer
  1748.        // test for transparent
  1749.        if ((rc->attr & RENDER_ATTR_ALPHA) &&
  1750.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  1751.           {
  1752.           Draw_Triangle_2D_Alpha16(&face, rc->video_buffer, rc->lpitch,alpha);
  1753.           } // end if
  1754.        else
  1755.           {
  1756.           Draw_Triangle_2D3_16(&face, rc->video_buffer, rc->lpitch);
  1757.           } // end if
  1758.                           
  1759.        } // end if                    
  1760.     else
  1761.     if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD)
  1762.        {
  1763.         // {andre take advantage of the data structures later..}
  1764.         // set the vertices
  1765.         face.tvlist[0].x  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].x;
  1766.         face.tvlist[0].y  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].y;
  1767.         face.tvlist[0].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].z;
  1768.         face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  1769.         face.tvlist[1].x  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].x;
  1770.         face.tvlist[1].y  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].y;
  1771.         face.tvlist[1].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].z;
  1772.         face.lit_color[1] = rc->rend_list->poly_ptrs[poly]->lit_color[1];
  1773.         face.tvlist[2].x  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].x;
  1774.         face.tvlist[2].y  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].y;
  1775.         face.tvlist[2].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].z;
  1776.         face.lit_color[2] = rc->rend_list->poly_ptrs[poly]->lit_color[2];
  1777.     // draw the gouraud shaded triangle
  1778.         // test for transparent
  1779.           if ((rc->attr & RENDER_ATTR_ALPHA) &&
  1780.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  1781.            {
  1782.            Draw_Gouraud_Triangle_Alpha16(&face, rc->video_buffer, rc->lpitch,alpha);
  1783.            } // end if
  1784.         else
  1785.            {
  1786.            Draw_Gouraud_Triangle2_16(&face, rc->video_buffer, rc->lpitch);
  1787.            } // end if
  1788.        } // end if gouraud
  1789.     } // end for poly
  1790. } // end if RENDER_ATTR_NOBUFFER
  1791. else
  1792. if (rc->attr & RENDER_ATTR_ZBUFFER) ////////////////////////////////////
  1793. {
  1794. // use the z buffer
  1795. // we have is a list of polygons and it's time draw them
  1796. for (int poly=0; poly < rc->rend_list->num_polys; poly++)
  1797.     {
  1798.     // render this polygon if and only if it's not clipped, not culled,
  1799.     // active, and visible, note however the concecpt of "backface" is 
  1800.     // irrelevant in a wire frame engine though
  1801.     if (!(rc->rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_ACTIVE) ||
  1802.          (rc->rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_CLIPPED ) ||
  1803.          (rc->rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_BACKFACE) )
  1804.        continue; // move onto next poly
  1805.     // test for alpha override
  1806.     if (rc->alpha_override>= 0)
  1807.        {
  1808.        // set alpha to override value
  1809.        alpha = rc->alpha_override;
  1810.        }  // end if 
  1811.     else
  1812.         {
  1813.         // extract alpha (even if there isn't any)
  1814.         alpha = ((rc->rend_list->poly_ptrs[poly]->color & 0xff000000) >> 24);
  1815.         } // end else
  1816.     // need to test for textured first, since a textured poly can either
  1817.     // be emissive, or flat shaded, hence we need to call different
  1818.     // rasterizers    
  1819.     if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_TEXTURE)
  1820.        {
  1821.        // set the vertices
  1822.        face.tvlist[0].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].x;
  1823.        face.tvlist[0].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].y;
  1824.        face.tvlist[0].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].z;
  1825.        face.tvlist[0].u0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].u0;
  1826.        face.tvlist[0].v0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].v0;
  1827.        face.tvlist[1].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].x;
  1828.        face.tvlist[1].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].y;
  1829.        face.tvlist[1].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].z;
  1830.        face.tvlist[1].u0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].u0;
  1831.        face.tvlist[1].v0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].v0;
  1832.        face.tvlist[2].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].x;
  1833.        face.tvlist[2].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].y;
  1834.        face.tvlist[2].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].z;
  1835.        face.tvlist[2].u0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].u0;
  1836.        face.tvlist[2].v0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].v0;
  1837.     
  1838.        // test if this is a mipmapped polygon?
  1839.        if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_MIPMAP)
  1840.           {
  1841.           // determine if mipmapping is desired at all globally
  1842.           if (rc->attr & RENDER_ATTR_MIPMAP)
  1843.              {
  1844.              // determine mip level for this polygon
  1845.              // first determine how many miplevels there are in mipchain for this polygon
  1846.              int tmiplevels = logbase2ofx[((BITMAP_IMAGE_PTR *)(rc->rend_list->poly_ptrs[poly]->texture))[0]->width];
  1847.              // now based on the requested linear miplevel fall off distance, cut
  1848.              // the viewdistance into segments, determine what segment polygon is
  1849.              // in and select mip level -- simple! later you might want something more
  1850.              // robust, also note I only use a single vertex, you might want to find the average
  1851.              // since for long walls perpendicular to view direction this might causing mip
  1852.              // popping mid surface
  1853.              int miplevel = (tmiplevels * rc->rend_list->poly_ptrs[poly]->tvlist[0].z / rc->mip_dist);
  1854.           
  1855.              // clamp miplevel
  1856.              if (miplevel > tmiplevels) miplevel = tmiplevels;
  1857.              // based on miplevel select proper texture
  1858.              face.texture = ((BITMAP_IMAGE_PTR *)(rc->rend_list->poly_ptrs[poly]->texture))[miplevel];
  1859.              // now we must divide each texture coordinate by 2 per miplevel
  1860.              for (int ts = 0; ts < miplevel; ts++)
  1861.                  {
  1862.                  face.tvlist[0].u0*=.5;
  1863.                  face.tvlist[0].v0*=.5;
  1864.                  face.tvlist[1].u0*=.5;
  1865.                  face.tvlist[1].v0*=.5;
  1866.                  face.tvlist[2].u0*=.5;
  1867.                  face.tvlist[2].v0*=.5;
  1868.                 } // end for
  1869.              } // end if mipmmaping enabled globally
  1870.           else // mipmapping not selected globally
  1871.              {
  1872.              // in this case the polygon IS mipmapped, but the caller has requested NO
  1873.              // mipmapping, so we will support this by selecting mip level 0 since the
  1874.              // texture pointer is pointing to a mip chain regardless
  1875.              face.texture = ((BITMAP_IMAGE_PTR *)(rc->rend_list->poly_ptrs[poly]->texture))[0];
  1876.  
  1877.              // note: texture coordinate manipulation is unneeded
  1878.              } // end else
  1879.           } // end if
  1880.        else
  1881.           {
  1882.           // assign the texture without change
  1883.           face.texture = rc->rend_list->poly_ptrs[poly]->texture;
  1884.           } // end if
  1885.        
  1886.        // is this a plain emissive texture?
  1887.        if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_CONSTANT)
  1888.           {
  1889.           // draw the textured triangle as emissive
  1890.           if ((rc->attr & RENDER_ATTR_ALPHA) &&
  1891.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  1892.              {
  1893.              // alpha version
  1894.              
  1895.              // which texture mapper?
  1896.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  1897.                 {
  1898.                 Draw_Textured_TriangleZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  1899.                 } // end if
  1900.              else
  1901.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  1902.                 {
  1903.                 // not supported yet!
  1904.                 Draw_Textured_TriangleZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  1905.                 } // end if
  1906.              else
  1907.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  1908.                 {
  1909.                 // not supported yet
  1910.                 Draw_Textured_TriangleZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  1911.                 } // end if
  1912.              else
  1913.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  1914.                 {
  1915.                 // test z distance again perspective transition gate
  1916.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  1917.                     {
  1918.                     // default back to affine
  1919.                     Draw_Textured_TriangleZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  1920.                     } // end if
  1921.                 else
  1922.                     {
  1923.                     // use perspective linear
  1924.                     // not supported yet
  1925.                     Draw_Textured_TriangleZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  1926.                     } // end if
  1927.                  } // end if
  1928.              } // end if
  1929.           else
  1930.              {
  1931.              // non alpha
  1932.              // which texture mapper?
  1933.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  1934.                 {
  1935.                 // use bilerp?
  1936.                 if (rc->attr & RENDER_ATTR_BILERP)
  1937.                    Draw_Textured_Bilerp_TriangleZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);               
  1938.                 else
  1939.                    Draw_Textured_TriangleZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  1940.                 } // end if
  1941.              else
  1942.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  1943.                 {
  1944.                 // not supported yet
  1945.                 Draw_Textured_TriangleZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  1946.                 } // end if
  1947.              else
  1948.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  1949.                 {
  1950.                 // not supported yet
  1951.                 Draw_Textured_TriangleZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  1952.                 } // end if
  1953.              else
  1954.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  1955.                 {
  1956.                 // test z distance again perspective transition gate
  1957.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  1958.                     {
  1959.                     // default back to affine
  1960.                     Draw_Textured_TriangleZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  1961.                     } // end if
  1962.                 else
  1963.                     {
  1964.                     // use perspective linear
  1965.                     // not supported yet
  1966.                     Draw_Textured_TriangleZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  1967.                     } // end if
  1968.                 } // end if
  1969.              } // end if
  1970.           } // end if
  1971.        else
  1972.        if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT)
  1973.           {
  1974.           // draw as flat shaded
  1975.           face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  1976.           // test for transparency
  1977.           if ((rc->attr & RENDER_ATTR_ALPHA) &&
  1978.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  1979.              {
  1980.              // alpha version
  1981.              // which texture mapper?
  1982.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  1983.                 {
  1984.                 Draw_Textured_TriangleFSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  1985.                 } // end if
  1986.              else
  1987.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  1988.                 {
  1989.                 // not supported yet
  1990.                 Draw_Textured_TriangleFSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  1991.                 } // end if
  1992.              else
  1993.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  1994.                 {
  1995.                 // not supported yet
  1996.                 Draw_Textured_TriangleFSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  1997.                 } // end if
  1998.              else
  1999.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2000.                 {
  2001.                 // test z distance again perspective transition gate
  2002.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2003.                     {
  2004.                     // default back to affine
  2005.                     Draw_Textured_TriangleFSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2006.                     } // end if
  2007.                 else
  2008.                     {
  2009.                     // use perspective linear
  2010.                     // not supported yet
  2011.                     Draw_Textured_TriangleFSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2012.                     } // end if
  2013.                  } // end if
  2014.              } // end if
  2015.           else
  2016.              {
  2017.              // non alpha
  2018.              // which texture mapper?
  2019.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  2020.                 {
  2021.                 Draw_Textured_TriangleFSZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2022.                 } // end if
  2023.              else
  2024.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  2025.                 {
  2026.                 // not supported yet
  2027.                 Draw_Textured_TriangleFSZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2028.                 } // end if
  2029.              else
  2030.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  2031.                 {
  2032.                 // not supported yet
  2033.                 Draw_Textured_TriangleFSZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2034.                 } // end if
  2035.              else
  2036.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2037.                 {
  2038.                 // test z distance again perspective transition gate
  2039.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2040.                     {
  2041.                     // default back to affine
  2042.                     Draw_Textured_TriangleFSZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2043.                     } // end if
  2044.                 else
  2045.                     {
  2046.                     // use perspective linear
  2047.                     // not supported yet
  2048.                     Draw_Textured_TriangleFSZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2049.                     } // end if
  2050.                  } // end if
  2051.              } // end if
  2052.           } // end else if
  2053.       else
  2054.          { // POLY4DV2_ATTR_SHADE_MODE_GOURAUD
  2055.           // must be gouraud POLY4DV2_ATTR_SHADE_MODE_GOURAUD
  2056.           face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  2057.           face.lit_color[1] = rc->rend_list->poly_ptrs[poly]->lit_color[1];
  2058.           face.lit_color[2] = rc->rend_list->poly_ptrs[poly]->lit_color[2];
  2059.          // test for transparency
  2060.          if ((rc->attr & RENDER_ATTR_ALPHA) &&
  2061.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  2062.              {
  2063.              // alpha version
  2064.              // which texture mapper?
  2065.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  2066.                 {
  2067.                 Draw_Textured_TriangleGSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2068.                 } // end if
  2069.              else
  2070.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  2071.                 {
  2072.                 // not supported yet :)
  2073.                 Draw_Textured_TriangleGSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2074.                 } // end if
  2075.              else
  2076.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  2077.                 {
  2078.                 // not supported yet :)
  2079.                 Draw_Textured_TriangleGSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2080.                 } // end if
  2081.              else
  2082.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2083.                 {
  2084.                 // test z distance again perspective transition gate
  2085.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2086.                     {
  2087.                     // default back to affine
  2088.                     Draw_Textured_TriangleGSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2089.                     } // end if
  2090.                 else
  2091.                     {
  2092.                     // use perspective linear
  2093.                     // not supported yet :)
  2094.                     Draw_Textured_TriangleGSZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2095.                     } // end if
  2096.                  } // end if
  2097.              } // end if
  2098.           else
  2099.              {
  2100.              // non alpha
  2101.              // which texture mapper?
  2102.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  2103.                 {
  2104.                 Draw_Textured_TriangleGSZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2105.                 } // end if
  2106.              else
  2107.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  2108.                 {
  2109.                 // not supported yet :)
  2110.                 Draw_Textured_TriangleGSZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2111.                 } // end if
  2112.              else
  2113.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  2114.                 {
  2115.                 // not supported yet :)
  2116.                 Draw_Textured_TriangleGSZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2117.                 } // end if
  2118.              else
  2119.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2120.                 {
  2121.                 // test z distance again perspective transition gate
  2122.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2123.                     {
  2124.                     // default back to affine
  2125.                     Draw_Textured_TriangleGSZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2126.                     } // end if
  2127.                 else
  2128.                     {
  2129.                     // use perspective linear
  2130.                     // not supported yet :)
  2131.                     Draw_Textured_TriangleGSZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2132.                     } // end if
  2133.                  } // end if
  2134.              } // end if
  2135.          } // end else
  2136.        } // end if      
  2137.     else
  2138.     if ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT) || 
  2139.         (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_CONSTANT) )
  2140.        {
  2141.        // draw as constant shaded
  2142.        face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  2143.        
  2144.        // set the vertices
  2145.        face.tvlist[0].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].x;
  2146.        face.tvlist[0].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].y;
  2147.        face.tvlist[0].z = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].z;
  2148.        face.tvlist[1].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].x;
  2149.        face.tvlist[1].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].y;
  2150.        face.tvlist[1].z = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].z;
  2151.        face.tvlist[2].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].x;
  2152.        face.tvlist[2].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].y;
  2153.        face.tvlist[2].z = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].z;
  2154.        // draw the triangle with basic flat rasterizer
  2155.        // test for transparency
  2156.        if ((rc->attr & RENDER_ATTR_ALPHA) &&
  2157.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  2158.           {
  2159.           // alpha version
  2160.           Draw_Triangle_2DZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch,alpha);
  2161.           } // end if
  2162.        else
  2163.           {
  2164.           // non alpha version
  2165.           Draw_Triangle_2DZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2166.           }  // end if
  2167.        } // end if
  2168.     else
  2169.     if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD)
  2170.        {
  2171.         // {andre take advantage of the data structures later..}
  2172.         // set the vertices
  2173.         face.tvlist[0].x  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].x;
  2174.         face.tvlist[0].y  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].y;
  2175.         face.tvlist[0].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].z;
  2176.         face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  2177.         face.tvlist[1].x  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].x;
  2178.         face.tvlist[1].y  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].y;
  2179.         face.tvlist[1].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].z;
  2180.         face.lit_color[1] = rc->rend_list->poly_ptrs[poly]->lit_color[1];
  2181.         face.tvlist[2].x  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].x;
  2182.         face.tvlist[2].y  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].y;
  2183.         face.tvlist[2].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].z;
  2184.         face.lit_color[2] = rc->rend_list->poly_ptrs[poly]->lit_color[2];
  2185.     // draw the gouraud shaded triangle
  2186.         // test for transparency
  2187.         if ((rc->attr & RENDER_ATTR_ALPHA) &&
  2188.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  2189.            {
  2190.            // alpha version
  2191.            Draw_Gouraud_TriangleZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch,alpha);
  2192.            } // end if
  2193.         else
  2194.            { 
  2195.            // non alpha
  2196.            Draw_Gouraud_TriangleZB2_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2197.            } // end if
  2198.        } // end if gouraud
  2199.     } // end for poly
  2200. } // end if RENDER_ATTR_ZBUFFER
  2201. else
  2202. if (rc->attr & RENDER_ATTR_INVZBUFFER) ////////////////////////////////////
  2203. {
  2204. // use the inverse z buffer
  2205. // we have is a list of polygons and it's time draw them
  2206. for (int poly=0; poly < rc->rend_list->num_polys; poly++)
  2207.     {
  2208.     // render this polygon if and only if it's not clipped, not culled,
  2209.     // active, and visible, note however the concecpt of "backface" is 
  2210.     // irrelevant in a wire frame engine though
  2211.     if (!(rc->rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_ACTIVE) ||
  2212.          (rc->rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_CLIPPED ) ||
  2213.          (rc->rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_BACKFACE) )
  2214.        continue; // move onto next poly
  2215.     // test for alpha override
  2216.     if (rc->alpha_override>= 0)
  2217.        {
  2218.        // set alpha to override value
  2219.        alpha = rc->alpha_override;
  2220.        }  // end if 
  2221.     else
  2222.        {
  2223.        // extract alpha (even if there isn't any)
  2224.        alpha = ((rc->rend_list->poly_ptrs[poly]->color & 0xff000000) >> 24);
  2225.        } // end else
  2226.     // need to test for textured first, since a textured poly can either
  2227.     // be emissive, or flat shaded, hence we need to call different
  2228.     // rasterizers    
  2229.     if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_TEXTURE)
  2230.        {
  2231.        // set the vertices
  2232.        face.tvlist[0].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].x;
  2233.        face.tvlist[0].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].y;
  2234.        face.tvlist[0].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].z;
  2235.        face.tvlist[0].u0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].u0;
  2236.        face.tvlist[0].v0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].v0;
  2237.        face.tvlist[1].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].x;
  2238.        face.tvlist[1].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].y;
  2239.        face.tvlist[1].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].z;
  2240.        face.tvlist[1].u0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].u0;
  2241.        face.tvlist[1].v0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].v0;
  2242.        face.tvlist[2].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].x;
  2243.        face.tvlist[2].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].y;
  2244.        face.tvlist[2].z  = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].z;
  2245.        face.tvlist[2].u0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].u0;
  2246.        face.tvlist[2].v0 = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].v0;
  2247.     
  2248.     
  2249.        // test if this is a mipmapped polygon?
  2250.        if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_MIPMAP)
  2251.           {
  2252.           // determine if mipmapping is desired at all globally
  2253.           if (rc->attr & RENDER_ATTR_MIPMAP)
  2254.              {
  2255.              // determine mip level for this polygon
  2256.              // first determine how many miplevels there are in mipchain for this polygon
  2257.              int tmiplevels = logbase2ofx[((BITMAP_IMAGE_PTR *)(rc->rend_list->poly_ptrs[poly]->texture))[0]->width];
  2258.              // now based on the requested linear miplevel fall off distance, cut
  2259.              // the viewdistance into segments, determine what segment polygon is
  2260.              // in and select mip level -- simple! later you might want something more
  2261.              // robust, also note I only use a single vertex, you might want to find the average
  2262.              // since for long walls perpendicular to view direction this might causing mip
  2263.              // popping mid surface
  2264.              int miplevel = (tmiplevels * rc->rend_list->poly_ptrs[poly]->tvlist[0].z / rc->mip_dist);
  2265.           
  2266.              // clamp miplevel
  2267.              if (miplevel > tmiplevels) miplevel = tmiplevels;
  2268.              // based on miplevel select proper texture
  2269.              face.texture = ((BITMAP_IMAGE_PTR *)(rc->rend_list->poly_ptrs[poly]->texture))[miplevel];
  2270.              // now we must divide each texture coordinate by 2 per miplevel
  2271.              for (int ts = 0; ts < miplevel; ts++)
  2272.                  {
  2273.                  face.tvlist[0].u0*=.5;
  2274.                  face.tvlist[0].v0*=.5;
  2275.                  face.tvlist[1].u0*=.5;
  2276.                  face.tvlist[1].v0*=.5;
  2277.                  face.tvlist[2].u0*=.5;
  2278.                  face.tvlist[2].v0*=.5;
  2279.                 } // end for
  2280.              } // end if mipmmaping enabled globally
  2281.           else // mipmapping not selected globally
  2282.              {
  2283.              // in this case the polygon IS mipmapped, but the caller has requested NO
  2284.              // mipmapping, so we will support this by selecting mip level 0 since the
  2285.              // texture pointer is pointing to a mip chain regardless
  2286.              face.texture = ((BITMAP_IMAGE_PTR *)(rc->rend_list->poly_ptrs[poly]->texture))[0];
  2287.  
  2288.              // note: texture coordinate manipulation is unneeded
  2289.              } // end else
  2290.           } // end if
  2291.        else
  2292.           {
  2293.           // assign the texture without change
  2294.           face.texture = rc->rend_list->poly_ptrs[poly]->texture;
  2295.           } // end if
  2296.               
  2297.        // is this a plain emissive texture?
  2298.        if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_CONSTANT)
  2299.           {
  2300.           // draw the textured triangle as emissive
  2301.           if ((rc->attr & RENDER_ATTR_ALPHA) &&
  2302.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  2303.              {
  2304.              // alpha version
  2305.              
  2306.              // which texture mapper?
  2307.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  2308.                 {
  2309.                 Draw_Textured_TriangleINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2310.                 } // end if
  2311.              else
  2312.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  2313.                 {
  2314.                 Draw_Textured_Perspective_Triangle_INVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2315.                 } // end if
  2316.              else
  2317.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  2318.                 {
  2319.                 Draw_Textured_PerspectiveLP_Triangle_INVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2320.                 } // end if
  2321.              else
  2322.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2323.                 {
  2324.                 // test z distance again perspective transition gate
  2325.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2326.                     {
  2327.                     // default back to affine
  2328.                     Draw_Textured_TriangleINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2329.                     } // end if
  2330.                 else
  2331.                     {
  2332.                     // use perspective linear
  2333.                     Draw_Textured_PerspectiveLP_Triangle_INVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2334.                     } // end if
  2335.                  } // end if
  2336.              } // end if
  2337.           else
  2338.              {
  2339.              // non alpha
  2340.              // which texture mapper?
  2341.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  2342.                 {
  2343.                 // use bilerp?
  2344.                 if (rc->attr & RENDER_ATTR_BILERP)
  2345.                     Draw_Textured_Bilerp_TriangleINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);             
  2346.                 else
  2347.                     Draw_Textured_TriangleINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2348.                 } // end if
  2349.              else
  2350.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  2351.                 {
  2352.                 Draw_Textured_Perspective_Triangle_INVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2353.                 } // end if
  2354.              else
  2355.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  2356.                 {
  2357.                 Draw_Textured_PerspectiveLP_Triangle_INVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2358.                 } // end if
  2359.              else
  2360.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2361.                 {
  2362.                 // test z distance again perspective transition gate
  2363.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2364.                     {
  2365.                     // default back to affine
  2366.                     Draw_Textured_TriangleINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2367.                     } // end if
  2368.                 else
  2369.                     {
  2370.                     // use perspective linear
  2371.                     Draw_Textured_PerspectiveLP_Triangle_INVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2372.                     } // end if
  2373.                 } // end if
  2374.              } // end if
  2375.           } // end if
  2376.        else
  2377.        if (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT)
  2378.           {
  2379.           // draw as flat shaded
  2380.           face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  2381.           // test for transparency
  2382.           if ((rc->attr & RENDER_ATTR_ALPHA) &&
  2383.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  2384.              {
  2385.              // alpha version
  2386.              // which texture mapper?
  2387.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  2388.                 {
  2389.                 Draw_Textured_TriangleFSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2390.                 } // end if
  2391.              else
  2392.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  2393.                 {
  2394.                 Draw_Textured_Perspective_Triangle_FSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2395.                 } // end if
  2396.              else
  2397.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  2398.                 {
  2399.                 Draw_Textured_PerspectiveLP_Triangle_FSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2400.                 } // end if
  2401.              else
  2402.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2403.                 {
  2404.                 // test z distance again perspective transition gate
  2405.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2406.                     {
  2407.                     // default back to affine
  2408.                     Draw_Textured_TriangleFSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2409.                     } // end if
  2410.                 else
  2411.                     {
  2412.                     // use perspective linear
  2413.                     Draw_Textured_PerspectiveLP_Triangle_FSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2414.                     } // end if
  2415.                  } // end if
  2416.              } // end if
  2417.           else
  2418.              {
  2419.              // non alpha
  2420.              // which texture mapper?
  2421.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  2422.                 {
  2423.                 Draw_Textured_TriangleFSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2424.                 } // end if
  2425.              else
  2426.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  2427.                 {
  2428.                 Draw_Textured_Perspective_Triangle_FSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2429.                 } // end if
  2430.              else
  2431.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  2432.                 {
  2433.                 Draw_Textured_PerspectiveLP_Triangle_FSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2434.                 } // end if
  2435.              else
  2436.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2437.                 {
  2438.                 // test z distance again perspective transition gate
  2439.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2440.                     {
  2441.                     // default back to affine
  2442.                     Draw_Textured_TriangleFSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2443.                     } // end if
  2444.                 else
  2445.                     {
  2446.                     // use perspective linear
  2447.                     Draw_Textured_PerspectiveLP_Triangle_FSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2448.                     } // end if
  2449.                  } // end if
  2450.              } // end if
  2451.           } // end else if
  2452.       else
  2453.          { // POLY4DV2_ATTR_SHADE_MODE_GOURAUD
  2454.           // must be gouraud POLY4DV2_ATTR_SHADE_MODE_GOURAUD
  2455.           face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  2456.           face.lit_color[1] = rc->rend_list->poly_ptrs[poly]->lit_color[1];
  2457.           face.lit_color[2] = rc->rend_list->poly_ptrs[poly]->lit_color[2];
  2458.          // test for transparency
  2459.          if ((rc->attr & RENDER_ATTR_ALPHA) &&
  2460.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  2461.              {
  2462.              // alpha version
  2463.              // which texture mapper?
  2464.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  2465.                 {
  2466.                 Draw_Textured_TriangleGSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2467.                 } // end if
  2468.              else
  2469.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  2470.                 {
  2471.                 // not supported yet :)
  2472.                 Draw_Textured_TriangleGSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2473.                 } // end if
  2474.              else
  2475.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  2476.                 {
  2477.                 // not supported yet :)
  2478.                 Draw_Textured_TriangleGSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2479.                 } // end if
  2480.              else
  2481.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2482.                 {
  2483.                 // test z distance again perspective transition gate
  2484.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2485.                     {
  2486.                     // default back to affine
  2487.                     Draw_Textured_TriangleGSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2488.                     } // end if
  2489.                 else
  2490.                     {
  2491.                     // use perspective linear
  2492.                     // not supported yet :)
  2493.                     Draw_Textured_TriangleGSINVZB_Alpha16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch, alpha);
  2494.                     } // end if
  2495.                  } // end if
  2496.              } // end if
  2497.           else
  2498.              {
  2499.              // non alpha
  2500.              // which texture mapper?
  2501.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE)
  2502.                 {
  2503.                 Draw_Textured_TriangleGSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2504.                 } // end if
  2505.              else
  2506.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_CORRECT)
  2507.                 {
  2508.                 // not supported yet :)
  2509.                 Draw_Textured_TriangleGSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2510.                 } // end if
  2511.              else
  2512.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_LINEAR)
  2513.                 {
  2514.                 // not supported yet :)
  2515.                 Draw_Textured_TriangleGSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2516.                 } // end if
  2517.              else
  2518.              if (rc->attr & RENDER_ATTR_TEXTURE_PERSPECTIVE_HYBRID1)
  2519.                 {
  2520.                 // test z distance again perspective transition gate
  2521.                 if (rc->rend_list->poly_ptrs[poly]->tvlist[0].z > rc-> texture_dist)
  2522.                     {
  2523.                     // default back to affine
  2524.                     Draw_Textured_TriangleFSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2525.                     } // end if
  2526.                 else
  2527.                     {
  2528.                     // use perspective linear
  2529.                     // not supported yet :)
  2530.                     Draw_Textured_TriangleGSINVZB_16(&face, rc->video_buffer, rc->lpitch,rc->zbuffer,rc->zpitch);
  2531.                     } // end if
  2532.                  } // end if
  2533.              } // end if
  2534.          } // end else
  2535.        } // end if      
  2536.     else
  2537.     if ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT) || 
  2538.         (rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_CONSTANT) )
  2539.        {
  2540.        // draw as constant shaded
  2541.        face.lit_color[0] = rc->rend_list->poly_ptrs[poly]->lit_color[0];
  2542.        
  2543.        // set the vertices
  2544.        face.tvlist[0].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].x;
  2545.        face.tvlist[0].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].y;
  2546.        face.tvlist[0].z = (float)rc->rend_list->poly_ptrs[poly]->tvlist[0].z;
  2547.        face.tvlist[1].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].x;
  2548.        face.tvlist[1].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].y;
  2549.        face.tvlist[1].z = (float)rc->rend_list->poly_ptrs[poly]->tvlist[1].z;
  2550.        face.tvlist[2].x = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].x;
  2551.        face.tvlist[2].y = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].y;
  2552.        face.tvlist[2].z = (float)rc->rend_list->poly_ptrs[poly]->tvlist[2].z;
  2553.        // draw the triangle with basic flat rasterizer
  2554.        // test for transparency
  2555.        if ((rc->attr & RENDER_ATTR_ALPHA) &&
  2556.               ((rc->rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_TRANSPARENT) || rc->alpha_override>=0) )
  2557.           {
  2558.           // alpha version