Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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