Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20.  
  21. // r_draw.c
  22.  
  23. #include "quakedef.h"
  24. #include "r_local.h"
  25. #include "d_local.h"    // FIXME: shouldn't need to include this
  26.  
  27. #define MAXLEFTCLIPEDGES                100
  28.  
  29. // !!! if these are changed, they must be changed in asm_draw.h too !!!
  30. #define FULLY_CLIPPED_CACHED    0x80000000
  31. #define FRAMECOUNT_MASK                 0x7FFFFFFF
  32.  
  33. unsigned int    cacheoffset;
  34.  
  35. int                     c_faceclip;                                     // number of faces clipped
  36.  
  37. zpointdesc_t    r_zpointdesc;
  38.  
  39. polydesc_t              r_polydesc;
  40.  
  41.  
  42.  
  43. clipplane_t     *entity_clipplanes;
  44. clipplane_t     view_clipplanes[4];
  45. clipplane_t     world_clipplanes[16];
  46.  
  47. medge_t                 *r_pedge;
  48.  
  49. qboolean                r_leftclipped, r_rightclipped;
  50. static qboolean makeleftedge, makerightedge;
  51. qboolean                r_nearzionly;
  52.  
  53. int             sintable[SIN_BUFFER_SIZE];
  54. int             intsintable[SIN_BUFFER_SIZE];
  55.  
  56. mvertex_t       r_leftenter, r_leftexit;
  57. mvertex_t       r_rightenter, r_rightexit;
  58.  
  59. typedef struct
  60. {
  61.         float   u,v;
  62.         int             ceilv;
  63. } evert_t;
  64.  
  65. int                             r_emitted;
  66. float                   r_nearzi;
  67. float                   r_u1, r_v1, r_lzi1;
  68. int                             r_ceilv1;
  69.  
  70. qboolean        r_lastvertvalid;
  71.  
  72.  
  73. #if     !id386
  74.  
  75. /*
  76. ================
  77. R_EmitEdge
  78. ================
  79. */
  80. void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
  81. {
  82.         edge_t  *edge, *pcheck;
  83.         int             u_check;
  84.         float   u, u_step;
  85.         vec3_t  local, transformed;
  86.         float   *world;
  87.         int             v, v2, ceilv0;
  88.         float   scale, lzi0, u0, v0;
  89.         int             side;
  90.  
  91.         if (r_lastvertvalid)
  92.         {
  93.                 u0 = r_u1;
  94.                 v0 = r_v1;
  95.                 lzi0 = r_lzi1;
  96.                 ceilv0 = r_ceilv1;
  97.         }
  98.         else
  99.         {
  100.                 world = &pv0->position[0];
  101.        
  102.         // transform and project
  103.                 VectorSubtract (world, modelorg, local);
  104.                 TransformVector (local, transformed);
  105.        
  106.                 if (transformed[2] < NEAR_CLIP)
  107.                         transformed[2] = NEAR_CLIP;
  108.        
  109.                 lzi0 = 1.0 / transformed[2];
  110.        
  111.         // FIXME: build x/yscale into transform?
  112.                 scale = xscale * lzi0;
  113.                 u0 = (xcenter + scale*transformed[0]);
  114.                 if (u0 < r_refdef.fvrectx_adj)
  115.                         u0 = r_refdef.fvrectx_adj;
  116.                 if (u0 > r_refdef.fvrectright_adj)
  117.                         u0 = r_refdef.fvrectright_adj;
  118.        
  119.                 scale = yscale * lzi0;
  120.                 v0 = (ycenter - scale*transformed[1]);
  121.                 if (v0 < r_refdef.fvrecty_adj)
  122.                         v0 = r_refdef.fvrecty_adj;
  123.                 if (v0 > r_refdef.fvrectbottom_adj)
  124.                         v0 = r_refdef.fvrectbottom_adj;
  125.        
  126.                 ceilv0 = (int) ceil(v0);
  127.         }
  128.  
  129.         world = &pv1->position[0];
  130.  
  131. // transform and project
  132.         VectorSubtract (world, modelorg, local);
  133.         TransformVector (local, transformed);
  134.  
  135.         if (transformed[2] < NEAR_CLIP)
  136.                 transformed[2] = NEAR_CLIP;
  137.  
  138.         r_lzi1 = 1.0 / transformed[2];
  139.  
  140.         scale = xscale * r_lzi1;
  141.         r_u1 = (xcenter + scale*transformed[0]);
  142.         if (r_u1 < r_refdef.fvrectx_adj)
  143.                 r_u1 = r_refdef.fvrectx_adj;
  144.         if (r_u1 > r_refdef.fvrectright_adj)
  145.                 r_u1 = r_refdef.fvrectright_adj;
  146.  
  147.         scale = yscale * r_lzi1;
  148.         r_v1 = (ycenter - scale*transformed[1]);
  149.         if (r_v1 < r_refdef.fvrecty_adj)
  150.                 r_v1 = r_refdef.fvrecty_adj;
  151.         if (r_v1 > r_refdef.fvrectbottom_adj)
  152.                 r_v1 = r_refdef.fvrectbottom_adj;
  153.  
  154.         if (r_lzi1 > lzi0)
  155.                 lzi0 = r_lzi1;
  156.  
  157.         if (lzi0 > r_nearzi)    // for mipmap finding
  158.                 r_nearzi = lzi0;
  159.  
  160. // for right edges, all we want is the effect on 1/z
  161.         if (r_nearzionly)
  162.                 return;
  163.  
  164.         r_emitted = 1;
  165.  
  166.         r_ceilv1 = (int) ceil(r_v1);
  167.  
  168.  
  169. // create the edge
  170.         if (ceilv0 == r_ceilv1)
  171.         {
  172.         // we cache unclipped horizontal edges as fully clipped
  173.                 if (cacheoffset != 0x7FFFFFFF)
  174.                 {
  175.                         cacheoffset = FULLY_CLIPPED_CACHED |
  176.                                         (r_framecount & FRAMECOUNT_MASK);
  177.                 }
  178.  
  179.                 return;         // horizontal edge
  180.         }
  181.  
  182.         side = ceilv0 > r_ceilv1;
  183.  
  184.         edge = edge_p++;
  185.  
  186.         edge->owner = r_pedge;
  187.  
  188.         edge->nearzi = lzi0;
  189.  
  190.         if (side == 0)
  191.         {
  192.         // trailing edge (go from p1 to p2)
  193.                 v = ceilv0;
  194.                 v2 = r_ceilv1 - 1;
  195.  
  196.                 edge->surfs[0] = surface_p - surfaces;
  197.                 edge->surfs[1] = 0;
  198.  
  199.                 u_step = ((r_u1 - u0) / (r_v1 - v0));
  200.                 u = u0 + ((float)v - v0) * u_step;
  201.         }
  202.         else
  203.         {
  204.         // leading edge (go from p2 to p1)
  205.                 v2 = ceilv0 - 1;
  206.                 v = r_ceilv1;
  207.  
  208.                 edge->surfs[0] = 0;
  209.                 edge->surfs[1] = surface_p - surfaces;
  210.  
  211.                 u_step = ((u0 - r_u1) / (v0 - r_v1));
  212.                 u = r_u1 + ((float)v - r_v1) * u_step;
  213.         }
  214.  
  215.         edge->u_step = u_step*0x100000;
  216.         edge->u = u*0x100000 + 0xFFFFF;
  217.  
  218. // we need to do this to avoid stepping off the edges if a very nearly
  219. // horizontal edge is less than epsilon above a scan, and numeric error causes
  220. // it to incorrectly extend to the scan, and the extension of the line goes off
  221. // the edge of the screen
  222. // FIXME: is this actually needed?
  223.         if (edge->u < r_refdef.vrect_x_adj_shift20)
  224.                 edge->u = r_refdef.vrect_x_adj_shift20;
  225.         if (edge->u > r_refdef.vrectright_adj_shift20)
  226.                 edge->u = r_refdef.vrectright_adj_shift20;
  227.  
  228. //
  229. // sort the edge in normally
  230. //
  231.         u_check = edge->u;
  232.         if (edge->surfs[0])
  233.                 u_check++;      // sort trailers after leaders
  234.  
  235.         if (!newedges[v] || newedges[v]->u >= u_check)
  236.         {
  237.                 edge->next = newedges[v];
  238.                 newedges[v] = edge;
  239.         }
  240.         else
  241.         {
  242.                 pcheck = newedges[v];
  243.                 while (pcheck->next && pcheck->next->u < u_check)
  244.                         pcheck = pcheck->next;
  245.                 edge->next = pcheck->next;
  246.                 pcheck->next = edge;
  247.         }
  248.  
  249.         edge->nextremove = removeedges[v2];
  250.         removeedges[v2] = edge;
  251. }
  252.  
  253.  
  254. /*
  255. ================
  256. R_ClipEdge
  257. ================
  258. */
  259. void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
  260. {
  261.         float           d0, d1, f;
  262.         mvertex_t       clipvert;
  263.  
  264.         if (clip)
  265.         {
  266.                 do
  267.                 {
  268.                         d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
  269.                         d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
  270.  
  271.                         if (d0 >= 0)
  272.                         {
  273.                         // point 0 is unclipped
  274.                                 if (d1 >= 0)
  275.                                 {
  276.                                 // both points are unclipped
  277.                                         continue;
  278.                                 }
  279.  
  280.                         // only point 1 is clipped
  281.  
  282.                         // we don't cache clipped edges
  283.                                 cacheoffset = 0x7FFFFFFF;
  284.  
  285.                                 f = d0 / (d0 - d1);
  286.                                 clipvert.position[0] = pv0->position[0] +
  287.                                                 f * (pv1->position[0] - pv0->position[0]);
  288.                                 clipvert.position[1] = pv0->position[1] +
  289.                                                 f * (pv1->position[1] - pv0->position[1]);
  290.                                 clipvert.position[2] = pv0->position[2] +
  291.                                                 f * (pv1->position[2] - pv0->position[2]);
  292.  
  293.                                 if (clip->leftedge)
  294.                                 {
  295.                                         r_leftclipped = true;
  296.                                         r_leftexit = clipvert;
  297.                                 }
  298.                                 else if (clip->rightedge)
  299.                                 {
  300.                                         r_rightclipped = true;
  301.                                         r_rightexit = clipvert;
  302.                                 }
  303.  
  304.                                 R_ClipEdge (pv0, &clipvert, clip->next);
  305.                                 return;
  306.                         }
  307.                         else
  308.                         {
  309.                         // point 0 is clipped
  310.                                 if (d1 < 0)
  311.                                 {
  312.                                 // both points are clipped
  313.                                 // we do cache fully clipped edges
  314.                                         if (!r_leftclipped)
  315.                                                 cacheoffset = FULLY_CLIPPED_CACHED |
  316.                                                                 (r_framecount & FRAMECOUNT_MASK);
  317.                                         return;
  318.                                 }
  319.  
  320.                         // only point 0 is clipped
  321.                                 r_lastvertvalid = false;
  322.  
  323.                         // we don't cache partially clipped edges
  324.                                 cacheoffset = 0x7FFFFFFF;
  325.  
  326.                                 f = d0 / (d0 - d1);
  327.                                 clipvert.position[0] = pv0->position[0] +
  328.                                                 f * (pv1->position[0] - pv0->position[0]);
  329.                                 clipvert.position[1] = pv0->position[1] +
  330.                                                 f * (pv1->position[1] - pv0->position[1]);
  331.                                 clipvert.position[2] = pv0->position[2] +
  332.                                                 f * (pv1->position[2] - pv0->position[2]);
  333.  
  334.                                 if (clip->leftedge)
  335.                                 {
  336.                                         r_leftclipped = true;
  337.                                         r_leftenter = clipvert;
  338.                                 }
  339.                                 else if (clip->rightedge)
  340.                                 {
  341.                                         r_rightclipped = true;
  342.                                         r_rightenter = clipvert;
  343.                                 }
  344.  
  345.                                 R_ClipEdge (&clipvert, pv1, clip->next);
  346.                                 return;
  347.                         }
  348.                 } while ((clip = clip->next) != NULL);
  349.         }
  350.  
  351. // add the edge
  352.         R_EmitEdge (pv0, pv1);
  353. }
  354.  
  355. #endif  // !id386
  356.  
  357.  
  358. /*
  359. ================
  360. R_EmitCachedEdge
  361. ================
  362. */
  363. void R_EmitCachedEdge (void)
  364. {
  365.         edge_t          *pedge_t;
  366.  
  367.         pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset);
  368.  
  369.         if (!pedge_t->surfs[0])
  370.                 pedge_t->surfs[0] = surface_p - surfaces;
  371.         else
  372.                 pedge_t->surfs[1] = surface_p - surfaces;
  373.  
  374.         if (pedge_t->nearzi > r_nearzi) // for mipmap finding
  375.                 r_nearzi = pedge_t->nearzi;
  376.  
  377.         r_emitted = 1;
  378. }
  379.  
  380.  
  381. /*
  382. ================
  383. R_RenderFace
  384. ================
  385. */
  386. void R_RenderFace (msurface_t *fa, int clipflags)
  387. {
  388.         int                     i, lindex;
  389.         unsigned        mask;
  390.         mplane_t        *pplane;
  391.         float           distinv;
  392.         vec3_t          p_normal;
  393.         medge_t         *pedges, tedge;
  394.         clipplane_t     *pclip;
  395.  
  396. // skip out if no more surfs
  397.         if ((surface_p) >= surf_max)
  398.         {
  399.                 r_outofsurfaces++;
  400.                 return;
  401.         }
  402.  
  403. // ditto if not enough edges left, or switch to auxedges if possible
  404.         if ((edge_p + fa->numedges + 4) >= edge_max)
  405.         {
  406.                 r_outofedges += fa->numedges;
  407.                 return;
  408.         }
  409.  
  410.         c_faceclip++;
  411.  
  412. // set up clip planes
  413.         pclip = NULL;
  414.  
  415.         for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
  416.         {
  417.                 if (clipflags & mask)
  418.                 {
  419.                         view_clipplanes[i].next = pclip;
  420.                         pclip = &view_clipplanes[i];
  421.                 }
  422.         }
  423.  
  424. // push the edges through
  425.         r_emitted = 0;
  426.         r_nearzi = 0;
  427.         r_nearzionly = false;
  428.         makeleftedge = makerightedge = false;
  429.         pedges = currententity->model->edges;
  430.         r_lastvertvalid = false;
  431.  
  432.         for (i=0 ; i<fa->numedges ; i++)
  433.         {
  434.                 lindex = currententity->model->surfedges[fa->firstedge + i];
  435.  
  436.                 if (lindex > 0)
  437.                 {
  438.                         r_pedge = &pedges[lindex];
  439.  
  440.                 // if the edge is cached, we can just reuse the edge
  441.                         if (!insubmodel)
  442.                         {
  443.                                 if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
  444.                                 {
  445.                                         if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
  446.                                                 r_framecount)
  447.                                         {
  448.                                                 r_lastvertvalid = false;
  449.                                                 continue;
  450.                                         }
  451.                                 }
  452.                                 else
  453.                                 {
  454.                                         if ((((unsigned long)edge_p - (unsigned long)r_edges) >
  455.                                                  r_pedge->cachededgeoffset) &&
  456.                                                 (((edge_t *)((unsigned long)r_edges +
  457.                                                  r_pedge->cachededgeoffset))->owner == r_pedge))
  458.                                         {
  459.                                                 R_EmitCachedEdge ();
  460.                                                 r_lastvertvalid = false;
  461.                                                 continue;
  462.                                         }
  463.                                 }
  464.                         }
  465.  
  466.                 // assume it's cacheable
  467.                         cacheoffset = (byte *)edge_p - (byte *)r_edges;
  468.                         r_leftclipped = r_rightclipped = false;
  469.                         R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
  470.                                                 &r_pcurrentvertbase[r_pedge->v[1]],
  471.                                                 pclip);
  472.                         r_pedge->cachededgeoffset = cacheoffset;
  473.  
  474.                         if (r_leftclipped)
  475.                                 makeleftedge = true;
  476.                         if (r_rightclipped)
  477.                                 makerightedge = true;
  478.                         r_lastvertvalid = true;
  479.                 }
  480.                 else
  481.                 {
  482.                         lindex = -lindex;
  483.                         r_pedge = &pedges[lindex];
  484.                 // if the edge is cached, we can just reuse the edge
  485.                         if (!insubmodel)
  486.                         {
  487.                                 if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
  488.                                 {
  489.                                         if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
  490.                                                 r_framecount)
  491.                                         {
  492.                                                 r_lastvertvalid = false;
  493.                                                 continue;
  494.                                         }
  495.                                 }
  496.                                 else
  497.                                 {
  498.                                 // it's cached if the cached edge is valid and is owned
  499.                                 // by this medge_t
  500.                                         if ((((unsigned long)edge_p - (unsigned long)r_edges) >
  501.                                                  r_pedge->cachededgeoffset) &&
  502.                                                 (((edge_t *)((unsigned long)r_edges +
  503.                                                  r_pedge->cachededgeoffset))->owner == r_pedge))
  504.                                         {
  505.                                                 R_EmitCachedEdge ();
  506.                                                 r_lastvertvalid = false;
  507.                                                 continue;
  508.                                         }
  509.                                 }
  510.                         }
  511.  
  512.                 // assume it's cacheable
  513.                         cacheoffset = (byte *)edge_p - (byte *)r_edges;
  514.                         r_leftclipped = r_rightclipped = false;
  515.                         R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
  516.                                                 &r_pcurrentvertbase[r_pedge->v[0]],
  517.                                                 pclip);
  518.                         r_pedge->cachededgeoffset = cacheoffset;
  519.  
  520.                         if (r_leftclipped)
  521.                                 makeleftedge = true;
  522.                         if (r_rightclipped)
  523.                                 makerightedge = true;
  524.                         r_lastvertvalid = true;
  525.                 }
  526.         }
  527.  
  528. // if there was a clip off the left edge, add that edge too
  529. // FIXME: faster to do in screen space?
  530. // FIXME: share clipped edges?
  531.         if (makeleftedge)
  532.         {
  533.                 r_pedge = &tedge;
  534.                 r_lastvertvalid = false;
  535.                 R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
  536.         }
  537.  
  538. // if there was a clip off the right edge, get the right r_nearzi
  539.         if (makerightedge)
  540.         {
  541.                 r_pedge = &tedge;
  542.                 r_lastvertvalid = false;
  543.                 r_nearzionly = true;
  544.                 R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
  545.         }
  546.  
  547. // if no edges made it out, return without posting the surface
  548.         if (!r_emitted)
  549.                 return;
  550.  
  551.         r_polycount++;
  552.  
  553.         surface_p->data = (void *)fa;
  554.         surface_p->nearzi = r_nearzi;
  555.         surface_p->flags = fa->flags;
  556.         surface_p->insubmodel = insubmodel;
  557.         surface_p->spanstate = 0;
  558.         surface_p->entity = currententity;
  559.         surface_p->key = r_currentkey++;
  560.         surface_p->spans = NULL;
  561.  
  562.         pplane = fa->plane;
  563. // FIXME: cache this?
  564.         TransformVector (pplane->normal, p_normal);
  565. // FIXME: cache this?
  566.         distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
  567.  
  568.         surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
  569.         surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
  570.         surface_p->d_ziorigin = p_normal[2] * distinv -
  571.                         xcenter * surface_p->d_zistepu -
  572.                         ycenter * surface_p->d_zistepv;
  573.  
  574. //JDC   VectorCopy (r_worldmodelorg, surface_p->modelorg);
  575.         surface_p++;
  576. }
  577.  
  578.  
  579. /*
  580. ================
  581. R_RenderBmodelFace
  582. ================
  583. */
  584. void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
  585. {
  586.         int                     i;
  587.         unsigned        mask;
  588.         mplane_t        *pplane;
  589.         float           distinv;
  590.         vec3_t          p_normal;
  591.         medge_t         tedge;
  592.         clipplane_t     *pclip;
  593.  
  594. // skip out if no more surfs
  595.         if (surface_p >= surf_max)
  596.         {
  597.                 r_outofsurfaces++;
  598.                 return;
  599.         }
  600.  
  601. // ditto if not enough edges left, or switch to auxedges if possible
  602.         if ((edge_p + psurf->numedges + 4) >= edge_max)
  603.         {
  604.                 r_outofedges += psurf->numedges;
  605.                 return;
  606.         }
  607.  
  608.         c_faceclip++;
  609.  
  610. // this is a dummy to give the caching mechanism someplace to write to
  611.         r_pedge = &tedge;
  612.  
  613. // set up clip planes
  614.         pclip = NULL;
  615.  
  616.         for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
  617.         {
  618.                 if (r_clipflags & mask)
  619.                 {
  620.                         view_clipplanes[i].next = pclip;
  621.                         pclip = &view_clipplanes[i];
  622.                 }
  623.         }
  624.  
  625. // push the edges through
  626.         r_emitted = 0;
  627.         r_nearzi = 0;
  628.         r_nearzionly = false;
  629.         makeleftedge = makerightedge = false;
  630. // FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
  631. // can be used?
  632.         r_lastvertvalid = false;
  633.  
  634.         for ( ; pedges ; pedges = pedges->pnext)
  635.         {
  636.                 r_leftclipped = r_rightclipped = false;
  637.                 R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
  638.  
  639.                 if (r_leftclipped)
  640.                         makeleftedge = true;
  641.                 if (r_rightclipped)
  642.                         makerightedge = true;
  643.         }
  644.  
  645. // if there was a clip off the left edge, add that edge too
  646. // FIXME: faster to do in screen space?
  647. // FIXME: share clipped edges?
  648.         if (makeleftedge)
  649.         {
  650.                 r_pedge = &tedge;
  651.                 R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
  652.         }
  653.  
  654. // if there was a clip off the right edge, get the right r_nearzi
  655.         if (makerightedge)
  656.         {
  657.                 r_pedge = &tedge;
  658.                 r_nearzionly = true;
  659.                 R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
  660.         }
  661.  
  662. // if no edges made it out, return without posting the surface
  663.         if (!r_emitted)
  664.                 return;
  665.  
  666.         r_polycount++;
  667.  
  668.         surface_p->data = (void *)psurf;
  669.         surface_p->nearzi = r_nearzi;
  670.         surface_p->flags = psurf->flags;
  671.         surface_p->insubmodel = true;
  672.         surface_p->spanstate = 0;
  673.         surface_p->entity = currententity;
  674.         surface_p->key = r_currentbkey;
  675.         surface_p->spans = NULL;
  676.  
  677.         pplane = psurf->plane;
  678. // FIXME: cache this?
  679.         TransformVector (pplane->normal, p_normal);
  680. // FIXME: cache this?
  681.         distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
  682.  
  683.         surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
  684.         surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
  685.         surface_p->d_ziorigin = p_normal[2] * distinv -
  686.                         xcenter * surface_p->d_zistepu -
  687.                         ycenter * surface_p->d_zistepv;
  688.  
  689. //JDC   VectorCopy (r_worldmodelorg, surface_p->modelorg);
  690.         surface_p++;
  691. }
  692.  
  693.  
  694. /*
  695. ================
  696. R_RenderPoly
  697. ================
  698. */
  699. void R_RenderPoly (msurface_t *fa, int clipflags)
  700. {
  701.         int                     i, lindex, lnumverts, s_axis, t_axis;
  702.         float           dist, lastdist, lzi, scale, u, v, frac;
  703.         unsigned        mask;
  704.         vec3_t          local, transformed;
  705.         clipplane_t     *pclip;
  706.         medge_t         *pedges;
  707.         mplane_t        *pplane;
  708.         mvertex_t       verts[2][100];  //FIXME: do real number
  709.         polyvert_t      pverts[100];    //FIXME: do real number, safely
  710.         int                     vertpage, newverts, newpage, lastvert;
  711.         qboolean        visible;
  712.  
  713. // FIXME: clean this up and make it faster
  714. // FIXME: guard against running out of vertices
  715.  
  716.         s_axis = t_axis = 0;    // keep compiler happy
  717.  
  718. // set up clip planes
  719.         pclip = NULL;
  720.  
  721.         for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
  722.         {
  723.                 if (clipflags & mask)
  724.                 {
  725.                         view_clipplanes[i].next = pclip;
  726.                         pclip = &view_clipplanes[i];
  727.                 }
  728.         }
  729.  
  730. // reconstruct the polygon
  731. // FIXME: these should be precalculated and loaded off disk
  732.         pedges = currententity->model->edges;
  733.         lnumverts = fa->numedges;
  734.         vertpage = 0;
  735.  
  736.         for (i=0 ; i<lnumverts ; i++)
  737.         {
  738.                 lindex = currententity->model->surfedges[fa->firstedge + i];
  739.  
  740.                 if (lindex > 0)
  741.                 {
  742.                         r_pedge = &pedges[lindex];
  743.                         verts[0][i] = r_pcurrentvertbase[r_pedge->v[0]];
  744.                 }
  745.                 else
  746.                 {
  747.                         r_pedge = &pedges[-lindex];
  748.                         verts[0][i] = r_pcurrentvertbase[r_pedge->v[1]];
  749.                 }
  750.         }
  751.  
  752. // clip the polygon, done if not visible
  753.         while (pclip)
  754.         {
  755.                 lastvert = lnumverts - 1;
  756.                 lastdist = DotProduct (verts[vertpage][lastvert].position,
  757.                                                            pclip->normal) - pclip->dist;
  758.  
  759.                 visible = false;
  760.                 newverts = 0;
  761.                 newpage = vertpage ^ 1;
  762.  
  763.                 for (i=0 ; i<lnumverts ; i++)
  764.                 {
  765.                         dist = DotProduct (verts[vertpage][i].position, pclip->normal) -
  766.                                         pclip->dist;
  767.  
  768.                         if ((lastdist > 0) != (dist > 0))
  769.                         {
  770.                                 frac = dist / (dist - lastdist);
  771.                                 verts[newpage][newverts].position[0] =
  772.                                                 verts[vertpage][i].position[0] +
  773.                                                 ((verts[vertpage][lastvert].position[0] -
  774.                                                   verts[vertpage][i].position[0]) * frac);
  775.                                 verts[newpage][newverts].position[1] =
  776.                                                 verts[vertpage][i].position[1] +
  777.                                                 ((verts[vertpage][lastvert].position[1] -
  778.                                                   verts[vertpage][i].position[1]) * frac);
  779.                                 verts[newpage][newverts].position[2] =
  780.                                                 verts[vertpage][i].position[2] +
  781.                                                 ((verts[vertpage][lastvert].position[2] -
  782.                                                   verts[vertpage][i].position[2]) * frac);
  783.                                 newverts++;
  784.                         }
  785.  
  786.                         if (dist >= 0)
  787.                         {
  788.                                 verts[newpage][newverts] = verts[vertpage][i];
  789.                                 newverts++;
  790.                                 visible = true;
  791.                         }
  792.  
  793.                         lastvert = i;
  794.                         lastdist = dist;
  795.                 }
  796.  
  797.                 if (!visible || (newverts < 3))
  798.                         return;
  799.  
  800.                 lnumverts = newverts;
  801.                 vertpage ^= 1;
  802.                 pclip = pclip->next;
  803.         }
  804.  
  805. // transform and project, remembering the z values at the vertices and
  806. // r_nearzi, and extract the s and t coordinates at the vertices
  807.         pplane = fa->plane;
  808.         switch (pplane->type)
  809.         {
  810.         case PLANE_X:
  811.         case PLANE_ANYX:
  812.                 s_axis = 1;
  813.                 t_axis = 2;
  814.                 break;
  815.         case PLANE_Y:
  816.         case PLANE_ANYY:
  817.                 s_axis = 0;
  818.                 t_axis = 2;
  819.                 break;
  820.         case PLANE_Z:
  821.         case PLANE_ANYZ:
  822.                 s_axis = 0;
  823.                 t_axis = 1;
  824.                 break;
  825.         }
  826.  
  827.         r_nearzi = 0;
  828.  
  829.         for (i=0 ; i<lnumverts ; i++)
  830.         {
  831.         // transform and project
  832.                 VectorSubtract (verts[vertpage][i].position, modelorg, local);
  833.                 TransformVector (local, transformed);
  834.  
  835.                 if (transformed[2] < NEAR_CLIP)
  836.                         transformed[2] = NEAR_CLIP;
  837.  
  838.                 lzi = 1.0 / transformed[2];
  839.  
  840.                 if (lzi > r_nearzi)     // for mipmap finding
  841.                         r_nearzi = lzi;
  842.  
  843.         // FIXME: build x/yscale into transform?
  844.                 scale = xscale * lzi;
  845.                 u = (xcenter + scale*transformed[0]);
  846.                 if (u < r_refdef.fvrectx_adj)
  847.                         u = r_refdef.fvrectx_adj;
  848.                 if (u > r_refdef.fvrectright_adj)
  849.                         u = r_refdef.fvrectright_adj;
  850.  
  851.                 scale = yscale * lzi;
  852.                 v = (ycenter - scale*transformed[1]);
  853.                 if (v < r_refdef.fvrecty_adj)
  854.                         v = r_refdef.fvrecty_adj;
  855.                 if (v > r_refdef.fvrectbottom_adj)
  856.                         v = r_refdef.fvrectbottom_adj;
  857.  
  858.                 pverts[i].u = u;
  859.                 pverts[i].v = v;
  860.                 pverts[i].zi = lzi;
  861.                 pverts[i].s = verts[vertpage][i].position[s_axis];
  862.                 pverts[i].t = verts[vertpage][i].position[t_axis];
  863.         }
  864.  
  865. // build the polygon descriptor, including fa, r_nearzi, and u, v, s, t, and z
  866. // for each vertex
  867.         r_polydesc.numverts = lnumverts;
  868.         r_polydesc.nearzi = r_nearzi;
  869.         r_polydesc.pcurrentface = fa;
  870.         r_polydesc.pverts = pverts;
  871.  
  872. // draw the polygon
  873.         D_DrawPoly ();
  874. }
  875.  
  876.  
  877. /*
  878. ================
  879. R_ZDrawSubmodelPolys
  880. ================
  881. */
  882. void R_ZDrawSubmodelPolys (model_t *pmodel)
  883. {
  884.         int                     i, numsurfaces;
  885.         msurface_t      *psurf;
  886.         float           dot;
  887.         mplane_t        *pplane;
  888.  
  889.         psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
  890.         numsurfaces = pmodel->nummodelsurfaces;
  891.  
  892.         for (i=0 ; i<numsurfaces ; i++, psurf++)
  893.         {
  894.         // find which side of the node we are on
  895.                 pplane = psurf->plane;
  896.  
  897.                 dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
  898.  
  899.         // draw the polygon
  900.                 if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
  901.                         (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
  902.                 {
  903.                 // FIXME: use bounding-box-based frustum clipping info?
  904.                         R_RenderPoly (psurf, 15);
  905.                 }
  906.         }
  907. }
  908.  
  909.