summaryrefslogtreecommitdiffstats
path: root/apps/plugins/sdl/progs/quake/d_sprite.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/progs/quake/d_sprite.c')
-rw-r--r--apps/plugins/sdl/progs/quake/d_sprite.c442
1 files changed, 442 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/d_sprite.c b/apps/plugins/sdl/progs/quake/d_sprite.c
new file mode 100644
index 0000000000..2f02ad2c64
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_sprite.c
@@ -0,0 +1,442 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+// d_sprite.c: software top-level rasterization driver module for drawing
+// sprites
+
+#include "quakedef.h"
+#include "d_local.h"
+
+static int sprite_height;
+static int minindex, maxindex;
+static sspan_t *sprite_spans;
+
+#if !id386
+
+/*
+=====================
+D_SpriteDrawSpans
+=====================
+*/
+void D_SpriteDrawSpans (sspan_t *pspan)
+{
+ int count, spancount, izistep;
+ int izi;
+ byte *pbase, *pdest;
+ fixed16_t s, t, snext, tnext, sstep, tstep;
+ float sdivz, tdivz, zi, z, du, dv, spancountminus1;
+ float sdivz8stepu, tdivz8stepu, zi8stepu;
+ byte btemp;
+ short *pz;
+
+ sstep = 0; // keep compiler happy
+ tstep = 0; // ditto
+
+ pbase = cacheblock;
+
+ sdivz8stepu = d_sdivzstepu * 8;
+ tdivz8stepu = d_tdivzstepu * 8;
+ zi8stepu = d_zistepu * 8;
+
+// we count on FP exceptions being turned off to avoid range problems
+ izistep = (int)(d_zistepu * 0x8000 * 0x10000);
+
+ do
+ {
+ pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
+ pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
+
+ count = pspan->count;
+
+ if (count <= 0)
+ goto NextSpan;
+
+ // calculate the initial s/z, t/z, 1/z, s, and t and clamp
+ du = (float)pspan->u;
+ dv = (float)pspan->v;
+
+ sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+ tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+ zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+ // we count on FP exceptions being turned off to avoid range problems
+ izi = (int)(zi * 0x8000 * 0x10000);
+
+ s = (int)(sdivz * z) + sadjust;
+ if (s > bbextents)
+ s = bbextents;
+ else if (s < 0)
+ s = 0;
+
+ t = (int)(tdivz * z) + tadjust;
+ if (t > bbextentt)
+ t = bbextentt;
+ else if (t < 0)
+ t = 0;
+
+ do
+ {
+ // calculate s and t at the far end of the span
+ if (count >= 8)
+ spancount = 8;
+ else
+ spancount = count;
+
+ count -= spancount;
+
+ if (count)
+ {
+ // calculate s/z, t/z, zi->fixed s and t at far end of span,
+ // calculate s and t steps across span by shifting
+ sdivz += sdivz8stepu;
+ tdivz += tdivz8stepu;
+ zi += zi8stepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+
+ snext = (int)(sdivz * z) + sadjust;
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < 8)
+ snext = 8; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ tnext = (int)(tdivz * z) + tadjust;
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < 8)
+ tnext = 8; // guard against round-off error on <0 steps
+
+ sstep = (snext - s) >> 3;
+ tstep = (tnext - t) >> 3;
+ }
+ else
+ {
+ // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+ // can't step off polygon), clamp, calculate s and t steps across
+ // span by division, biasing steps low so we don't run off the
+ // texture
+ spancountminus1 = (float)(spancount - 1);
+ sdivz += d_sdivzstepu * spancountminus1;
+ tdivz += d_tdivzstepu * spancountminus1;
+ zi += d_zistepu * spancountminus1;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+ snext = (int)(sdivz * z) + sadjust;
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < 8)
+ snext = 8; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ tnext = (int)(tdivz * z) + tadjust;
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < 8)
+ tnext = 8; // guard against round-off error on <0 steps
+
+ if (spancount > 1)
+ {
+ sstep = (snext - s) / (spancount - 1);
+ tstep = (tnext - t) / (spancount - 1);
+ }
+ }
+
+ do
+ {
+ btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
+ if (btemp != 255)
+ {
+ if (*pz <= (izi >> 16))
+ {
+ *pz = izi >> 16;
+ *pdest = btemp;
+ }
+ }
+
+ izi += izistep;
+ pdest++;
+ pz++;
+ s += sstep;
+ t += tstep;
+ } while (--spancount > 0);
+
+ s = snext;
+ t = tnext;
+
+ } while (count > 0);
+
+NextSpan:
+ pspan++;
+
+ } while (pspan->count != DS_SPAN_LIST_END);
+}
+
+#endif
+
+
+/*
+=====================
+D_SpriteScanLeftEdge
+=====================
+*/
+void D_SpriteScanLeftEdge (void)
+{
+ int i, v, itop, ibottom, lmaxindex;
+ emitpoint_t *pvert, *pnext;
+ sspan_t *pspan;
+ float du, dv, vtop, vbottom, slope;
+ fixed16_t u, u_step;
+
+ pspan = sprite_spans;
+ i = minindex;
+ if (i == 0)
+ i = r_spritedesc.nump;
+
+ lmaxindex = maxindex;
+ if (lmaxindex == 0)
+ lmaxindex = r_spritedesc.nump;
+
+ vtop = ceil (r_spritedesc.pverts[i].v);
+
+ do
+ {
+ pvert = &r_spritedesc.pverts[i];
+ pnext = pvert - 1;
+
+ vbottom = ceil (pnext->v);
+
+ if (vtop < vbottom)
+ {
+ du = pnext->u - pvert->u;
+ dv = pnext->v - pvert->v;
+ slope = du / dv;
+ u_step = (int)(slope * 0x10000);
+ // adjust u to ceil the integer portion
+ u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
+ (0x10000 - 1);
+ itop = (int)vtop;
+ ibottom = (int)vbottom;
+
+ for (v=itop ; v<ibottom ; v++)
+ {
+ pspan->u = u >> 16;
+ pspan->v = v;
+ u += u_step;
+ pspan++;
+ }
+ }
+
+ vtop = vbottom;
+
+ i--;
+ if (i == 0)
+ i = r_spritedesc.nump;
+
+ } while (i != lmaxindex);
+}
+
+
+/*
+=====================
+D_SpriteScanRightEdge
+=====================
+*/
+void D_SpriteScanRightEdge (void)
+{
+ int i, v, itop, ibottom;
+ emitpoint_t *pvert, *pnext;
+ sspan_t *pspan;
+ float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
+ fixed16_t u, u_step;
+
+ pspan = sprite_spans;
+ i = minindex;
+
+ vvert = r_spritedesc.pverts[i].v;
+ if (vvert < r_refdef.fvrecty_adj)
+ vvert = r_refdef.fvrecty_adj;
+ if (vvert > r_refdef.fvrectbottom_adj)
+ vvert = r_refdef.fvrectbottom_adj;
+
+ vtop = ceil (vvert);
+
+ do
+ {
+ pvert = &r_spritedesc.pverts[i];
+ pnext = pvert + 1;
+
+ vnext = pnext->v;
+ if (vnext < r_refdef.fvrecty_adj)
+ vnext = r_refdef.fvrecty_adj;
+ if (vnext > r_refdef.fvrectbottom_adj)
+ vnext = r_refdef.fvrectbottom_adj;
+
+ vbottom = ceil (vnext);
+
+ if (vtop < vbottom)
+ {
+ uvert = pvert->u;
+ if (uvert < r_refdef.fvrectx_adj)
+ uvert = r_refdef.fvrectx_adj;
+ if (uvert > r_refdef.fvrectright_adj)
+ uvert = r_refdef.fvrectright_adj;
+
+ unext = pnext->u;
+ if (unext < r_refdef.fvrectx_adj)
+ unext = r_refdef.fvrectx_adj;
+ if (unext > r_refdef.fvrectright_adj)
+ unext = r_refdef.fvrectright_adj;
+
+ du = unext - uvert;
+ dv = vnext - vvert;
+ slope = du / dv;
+ u_step = (int)(slope * 0x10000);
+ // adjust u to ceil the integer portion
+ u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
+ (0x10000 - 1);
+ itop = (int)vtop;
+ ibottom = (int)vbottom;
+
+ for (v=itop ; v<ibottom ; v++)
+ {
+ pspan->count = (u >> 16) - pspan->u;
+ u += u_step;
+ pspan++;
+ }
+ }
+
+ vtop = vbottom;
+ vvert = vnext;
+
+ i++;
+ if (i == r_spritedesc.nump)
+ i = 0;
+
+ } while (i != maxindex);
+
+ pspan->count = DS_SPAN_LIST_END; // mark the end of the span list
+}
+
+
+/*
+=====================
+D_SpriteCalculateGradients
+=====================
+*/
+void D_SpriteCalculateGradients (void)
+{
+ vec3_t p_normal, p_saxis, p_taxis, p_temp1;
+ float distinv;
+
+ TransformVector (r_spritedesc.vpn, p_normal);
+ TransformVector (r_spritedesc.vright, p_saxis);
+ TransformVector (r_spritedesc.vup, p_taxis);
+ VectorInverse (p_taxis);
+
+ distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn));
+
+ d_sdivzstepu = p_saxis[0] * xscaleinv;
+ d_tdivzstepu = p_taxis[0] * xscaleinv;
+
+ d_sdivzstepv = -p_saxis[1] * yscaleinv;
+ d_tdivzstepv = -p_taxis[1] * yscaleinv;
+
+ d_zistepu = p_normal[0] * xscaleinv * distinv;
+ d_zistepv = -p_normal[1] * yscaleinv * distinv;
+
+ d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu -
+ ycenter * d_sdivzstepv;
+ d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu -
+ ycenter * d_tdivzstepv;
+ d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu -
+ ycenter * d_zistepv;
+
+ TransformVector (modelorg, p_temp1);
+
+ sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
+ (-(cachewidth >> 1) << 16);
+ tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
+ (-(sprite_height >> 1) << 16);
+
+// -1 (-epsilon) so we never wander off the edge of the texture
+ bbextents = (cachewidth << 16) - 1;
+ bbextentt = (sprite_height << 16) - 1;
+}
+
+
+/*
+=====================
+D_DrawSprite
+=====================
+*/
+void D_DrawSprite (void)
+{
+ int i, nump;
+ float ymin, ymax;
+ emitpoint_t *pverts;
+ sspan_t spans[MAXHEIGHT+1];
+
+ sprite_spans = spans;
+
+// find the top and bottom vertices, and make sure there's at least one scan to
+// draw
+ ymin = 999999.9;
+ ymax = -999999.9;
+ pverts = r_spritedesc.pverts;
+
+ for (i=0 ; i<r_spritedesc.nump ; i++)
+ {
+ if (pverts->v < ymin)
+ {
+ ymin = pverts->v;
+ minindex = i;
+ }
+
+ if (pverts->v > ymax)
+ {
+ ymax = pverts->v;
+ maxindex = i;
+ }
+
+ pverts++;
+ }
+
+ ymin = ceil (ymin);
+ ymax = ceil (ymax);
+
+ if (ymin >= ymax)
+ return; // doesn't cross any scans at all
+
+ cachewidth = r_spritedesc.pspriteframe->width;
+ sprite_height = r_spritedesc.pspriteframe->height;
+ cacheblock = (byte *)&r_spritedesc.pspriteframe->pixels[0];
+
+// copy the first vertex to the last vertex, so we don't have to deal with
+// wrapping
+ nump = r_spritedesc.nump;
+ pverts = r_spritedesc.pverts;
+ pverts[nump] = pverts[0];
+
+ D_SpriteCalculateGradients ();
+ D_SpriteScanLeftEdge ();
+ D_SpriteScanRightEdge ();
+ D_SpriteDrawSpans (sprite_spans);
+}
+