home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 15 / MA_Cover_15.iso / source / winquake / d_sprite.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-03  |  9.9 KB  |  445 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. // d_sprite.c: software top-level rasterization driver module for drawing
  21. // sprites
  22.  
  23. #include "quakedef.h"
  24. #include "d_local.h"
  25.  
  26. static int        sprite_height;
  27. static int        minindex, maxindex;
  28. static sspan_t    *sprite_spans;
  29.  
  30. #if    !id386
  31. #if !id68k
  32.  
  33. /*
  34. =====================
  35. D_SpriteDrawSpans
  36. =====================
  37. */
  38. void D_SpriteDrawSpans (sspan_t *pspan)
  39. {
  40.     int            count, spancount, izistep;
  41.     int            izi;
  42.     byte        *pbase, *pdest;
  43.     fixed16_t    s, t, snext, tnext, sstep, tstep;
  44.     float        sdivz, tdivz, zi, z, du, dv, spancountminus1;
  45.     float        sdivz8stepu, tdivz8stepu, zi8stepu;
  46.     byte        btemp;
  47.     short        *pz;
  48.  
  49.     sstep = 0;    // keep compiler happy
  50.     tstep = 0;    // ditto
  51.  
  52.     pbase = cacheblock;
  53.  
  54.     sdivz8stepu = d_sdivzstepu * 8;
  55.     tdivz8stepu = d_tdivzstepu * 8;
  56.     zi8stepu = d_zistepu * 8;
  57.  
  58. // we count on FP exceptions being turned off to avoid range problems
  59.     izistep = (int)(d_zistepu * 0x8000 * 0x10000);
  60.  
  61.     do
  62.     {
  63.         pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
  64.         pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
  65.  
  66.         count = pspan->count;
  67.  
  68.         if (count <= 0)
  69.             goto NextSpan;
  70.  
  71.     // calculate the initial s/z, t/z, 1/z, s, and t and clamp
  72.         du = (float)pspan->u;
  73.         dv = (float)pspan->v;
  74.  
  75.         sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
  76.         tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
  77.         zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
  78.         z = (float)0x10000 / zi;    // prescale to 16.16 fixed-point
  79.     // we count on FP exceptions being turned off to avoid range problems
  80.         izi = (int)(zi * 0x8000 * 0x10000);
  81.  
  82.         s = (int)(sdivz * z) + sadjust;
  83.         if (s > bbextents)
  84.             s = bbextents;
  85.         else if (s < 0)
  86.             s = 0;
  87.  
  88.         t = (int)(tdivz * z) + tadjust;
  89.         if (t > bbextentt)
  90.             t = bbextentt;
  91.         else if (t < 0)
  92.             t = 0;
  93.  
  94.         do
  95.         {
  96.         // calculate s and t at the far end of the span
  97.             if (count >= 8)
  98.                 spancount = 8;
  99.             else
  100.                 spancount = count;
  101.  
  102.             count -= spancount;
  103.  
  104.             if (count)
  105.             {
  106.             // calculate s/z, t/z, zi->fixed s and t at far end of span,
  107.             // calculate s and t steps across span by shifting
  108.                 sdivz += sdivz8stepu;
  109.                 tdivz += tdivz8stepu;
  110.                 zi += zi8stepu;
  111.                 z = (float)0x10000 / zi;    // prescale to 16.16 fixed-point
  112.  
  113.                 snext = (int)(sdivz * z) + sadjust;
  114.                 if (snext > bbextents)
  115.                     snext = bbextents;
  116.                 else if (snext < 8)
  117.                     snext = 8;    // prevent round-off error on <0 steps from
  118.                                 //  from causing overstepping & running off the
  119.                                 //  edge of the texture
  120.  
  121.                 tnext = (int)(tdivz * z) + tadjust;
  122.                 if (tnext > bbextentt)
  123.                     tnext = bbextentt;
  124.                 else if (tnext < 8)
  125.                     tnext = 8;    // guard against round-off error on <0 steps
  126.  
  127.                 sstep = (snext - s) >> 3;
  128.                 tstep = (tnext - t) >> 3;
  129.             }
  130.             else
  131.             {
  132.             // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
  133.             // can't step off polygon), clamp, calculate s and t steps across
  134.             // span by division, biasing steps low so we don't run off the
  135.             // texture
  136.                 spancountminus1 = (float)(spancount - 1);
  137.                 sdivz += d_sdivzstepu * spancountminus1;
  138.                 tdivz += d_tdivzstepu * spancountminus1;
  139.                 zi += d_zistepu * spancountminus1;
  140.                 z = (float)0x10000 / zi;    // prescale to 16.16 fixed-point
  141.                 snext = (int)(sdivz * z) + sadjust;
  142.                 if (snext > bbextents)
  143.                     snext = bbextents;
  144.                 else if (snext < 8)
  145.                     snext = 8;    // prevent round-off error on <0 steps from
  146.                                 //  from causing overstepping & running off the
  147.                                 //  edge of the texture
  148.  
  149.                 tnext = (int)(tdivz * z) + tadjust;
  150.                 if (tnext > bbextentt)
  151.                     tnext = bbextentt;
  152.                 else if (tnext < 8)
  153.                     tnext = 8;    // guard against round-off error on <0 steps
  154.  
  155.                 if (spancount > 1)
  156.                 {
  157.                     sstep = (snext - s) / (spancount - 1);
  158.                     tstep = (tnext - t) / (spancount - 1);
  159.                 }
  160.             }
  161.  
  162.             do
  163.             {
  164.                 btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
  165.                 if (btemp != 255)
  166.                 {
  167.                     if (*pz <= (izi >> 16))
  168.                     {
  169.                         *pz = izi >> 16;
  170.                         *pdest = btemp;
  171.                     }
  172.                 }
  173.  
  174.                 izi += izistep;
  175.                 pdest++;
  176.                 pz++;
  177.                 s += sstep;
  178.                 t += tstep;
  179.             } while (--spancount > 0);
  180.  
  181.             s = snext;
  182.             t = tnext;
  183.  
  184.         } while (count > 0);
  185.  
  186. NextSpan:
  187.         pspan++;
  188.  
  189.     } while (pspan->count != DS_SPAN_LIST_END);
  190. }
  191.  
  192. #endif
  193. #endif
  194.  
  195.  
  196. /*
  197. =====================
  198. D_SpriteScanLeftEdge
  199. =====================
  200. */
  201. void D_SpriteScanLeftEdge (void)
  202. {
  203.     int            i, v, itop, ibottom, lmaxindex;
  204.     emitpoint_t    *pvert, *pnext;
  205.     sspan_t        *pspan;
  206.     float        du, dv, vtop, vbottom, slope;
  207.     fixed16_t    u, u_step;
  208.  
  209.     pspan = sprite_spans;
  210.     i = minindex;
  211.     if (i == 0)
  212.         i = r_spritedesc.nump;
  213.  
  214.     lmaxindex = maxindex;
  215.     if (lmaxindex == 0)
  216.         lmaxindex = r_spritedesc.nump;
  217.  
  218.     vtop = ceil (r_spritedesc.pverts[i].v);
  219.  
  220.     do
  221.     {
  222.         pvert = &r_spritedesc.pverts[i];
  223.         pnext = pvert - 1;
  224.  
  225.         vbottom = ceil (pnext->v);
  226.  
  227.         if (vtop < vbottom)
  228.         {
  229.             du = pnext->u - pvert->u;
  230.             dv = pnext->v - pvert->v;
  231.             slope = du / dv;
  232.             u_step = (int)(slope * 0x10000);
  233.         // adjust u to ceil the integer portion
  234.             u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
  235.                     (0x10000 - 1);
  236.             itop = (int)vtop;
  237.             ibottom = (int)vbottom;
  238.  
  239.             for (v=itop ; v<ibottom ; v++)
  240.             {
  241.                 pspan->u = u >> 16;
  242.                 pspan->v = v;
  243.                 u += u_step;
  244.                 pspan++;
  245.             }
  246.         }
  247.  
  248.         vtop = vbottom;
  249.  
  250.         i--;
  251.         if (i == 0)
  252.             i = r_spritedesc.nump;
  253.  
  254.     } while (i != lmaxindex);
  255. }
  256.  
  257.  
  258. /*
  259. =====================
  260. D_SpriteScanRightEdge
  261. =====================
  262. */
  263. void D_SpriteScanRightEdge (void)
  264. {
  265.     int            i, v, itop, ibottom;
  266.     emitpoint_t    *pvert, *pnext;
  267.     sspan_t        *pspan;
  268.     float        du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
  269.     fixed16_t    u, u_step;
  270.  
  271.     pspan = sprite_spans;
  272.     i = minindex;
  273.  
  274.     vvert = r_spritedesc.pverts[i].v;
  275.     if (vvert < r_refdef.fvrecty_adj)
  276.         vvert = r_refdef.fvrecty_adj;
  277.     if (vvert > r_refdef.fvrectbottom_adj)
  278.         vvert = r_refdef.fvrectbottom_adj;
  279.  
  280.     vtop = ceil (vvert);
  281.  
  282.     do
  283.     {
  284.         pvert = &r_spritedesc.pverts[i];
  285.         pnext = pvert + 1;
  286.  
  287.         vnext = pnext->v;
  288.         if (vnext < r_refdef.fvrecty_adj)
  289.             vnext = r_refdef.fvrecty_adj;
  290.         if (vnext > r_refdef.fvrectbottom_adj)
  291.             vnext = r_refdef.fvrectbottom_adj;
  292.  
  293.         vbottom = ceil (vnext);
  294.  
  295.         if (vtop < vbottom)
  296.         {
  297.             uvert = pvert->u;
  298.             if (uvert < r_refdef.fvrectx_adj)
  299.                 uvert = r_refdef.fvrectx_adj;
  300.             if (uvert > r_refdef.fvrectright_adj)
  301.                 uvert = r_refdef.fvrectright_adj;
  302.  
  303.             unext = pnext->u;
  304.             if (unext < r_refdef.fvrectx_adj)
  305.                 unext = r_refdef.fvrectx_adj;
  306.             if (unext > r_refdef.fvrectright_adj)
  307.                 unext = r_refdef.fvrectright_adj;
  308.  
  309.             du = unext - uvert;
  310.             dv = vnext - vvert;
  311.             slope = du / dv;
  312.             u_step = (int)(slope * 0x10000);
  313.         // adjust u to ceil the integer portion
  314.             u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
  315.                     (0x10000 - 1);
  316.             itop = (int)vtop;
  317.             ibottom = (int)vbottom;
  318.  
  319.             for (v=itop ; v<ibottom ; v++)
  320.             {
  321.                 pspan->count = (u >> 16) - pspan->u;
  322.                 u += u_step;
  323.                 pspan++;
  324.             }
  325.         }
  326.  
  327.         vtop = vbottom;
  328.         vvert = vnext;
  329.  
  330.         i++;
  331.         if (i == r_spritedesc.nump)
  332.             i = 0;
  333.  
  334.     } while (i != maxindex);
  335.  
  336.     pspan->count = DS_SPAN_LIST_END;    // mark the end of the span list 
  337. }
  338.  
  339.  
  340. /*
  341. =====================
  342. D_SpriteCalculateGradients
  343. =====================
  344. */
  345. void D_SpriteCalculateGradients (void)
  346. {
  347.     vec3_t        p_normal, p_saxis, p_taxis, p_temp1;
  348.     float        distinv;
  349.  
  350.     TransformVector (r_spritedesc.vpn, p_normal);
  351.     TransformVector (r_spritedesc.vright, p_saxis);
  352.     TransformVector (r_spritedesc.vup, p_taxis);
  353.     VectorInverse (p_taxis);
  354.  
  355.     distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn));
  356.  
  357.     d_sdivzstepu = p_saxis[0] * xscaleinv;
  358.     d_tdivzstepu = p_taxis[0] * xscaleinv;
  359.  
  360.     d_sdivzstepv = -p_saxis[1] * yscaleinv;
  361.     d_tdivzstepv = -p_taxis[1] * yscaleinv;
  362.  
  363.     d_zistepu = p_normal[0] * xscaleinv * distinv;
  364.     d_zistepv = -p_normal[1] * yscaleinv * distinv;
  365.  
  366.     d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu -
  367.             ycenter * d_sdivzstepv;
  368.     d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu -
  369.             ycenter * d_tdivzstepv;
  370.     d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu -
  371.             ycenter * d_zistepv;
  372.  
  373.     TransformVector (modelorg, p_temp1);
  374.  
  375.     sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
  376.             (-(cachewidth >> 1) << 16);
  377.     tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
  378.             (-(sprite_height >> 1) << 16);
  379.  
  380. // -1 (-epsilon) so we never wander off the edge of the texture
  381.     bbextents = (cachewidth << 16) - 1;
  382.     bbextentt = (sprite_height << 16) - 1;
  383. }
  384.  
  385.  
  386. /*
  387. =====================
  388. D_DrawSprite
  389. =====================
  390. */
  391. void D_DrawSprite (void)
  392. {
  393.     int            i, nump;
  394.     float        ymin, ymax;
  395.     emitpoint_t    *pverts;
  396.     sspan_t        spans[MAXHEIGHT+1];
  397.  
  398.     sprite_spans = spans;
  399.  
  400. // find the top and bottom vertices, and make sure there's at least one scan to
  401. // draw
  402.     ymin = 999999.9;
  403.     ymax = -999999.9;
  404.     pverts = r_spritedesc.pverts;
  405.  
  406.     for (i=0 ; i<r_spritedesc.nump ; i++)
  407.     {
  408.         if (pverts->v < ymin)
  409.         {
  410.             ymin = pverts->v;
  411.             minindex = i;
  412.         }
  413.  
  414.         if (pverts->v > ymax)
  415.         {
  416.             ymax = pverts->v;
  417.             maxindex = i;
  418.         }
  419.  
  420.         pverts++;
  421.     }
  422.  
  423.     ymin = ceil (ymin);
  424.     ymax = ceil (ymax);
  425.  
  426.     if (ymin >= ymax)
  427.         return;        // doesn't cross any scans at all
  428.  
  429.     cachewidth = r_spritedesc.pspriteframe->width;
  430.     sprite_height = r_spritedesc.pspriteframe->height;
  431.     cacheblock = (byte *)&r_spritedesc.pspriteframe->pixels[0];
  432.  
  433. // copy the first vertex to the last vertex, so we don't have to deal with
  434. // wrapping
  435.     nump = r_spritedesc.nump;
  436.     pverts = r_spritedesc.pverts;
  437.     pverts[nump] = pverts[0];
  438.  
  439.     D_SpriteCalculateGradients ();
  440.     D_SpriteScanLeftEdge ();
  441.     D_SpriteScanRightEdge ();
  442.     D_SpriteDrawSpans (sprite_spans);
  443. }
  444.  
  445.