home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quakeworld_src / client / r_draw.c.orig < prev    next >
Encoding:
Text File  |  2000-06-17  |  21.1 KB  |  909 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. static qboolean makeleftedge, makerightedge;
  51. qboolean    r_nearzionly;
  52.  
  53. int   sintable[1280];
  54. int   intsintable[1280];
  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.