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