home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / r_draw.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  21.2 KB  |  913 lines

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