engine/engine/sw/sw_spans.h

324 lines
5.9 KiB
C

/*
this file is expected to be #included as the body of a real function
to define create a new pixel shader, define PLOT_PIXEL(outval) at the top of your function and you're good to go
//modifiers:
SPAN_ST - interpolates S+T across the span. access with 'sc' and 'tc'
affine... no perspective correction.
*/
{
swvert_t *vt;
int y;
int secondhalf;
int xl,xld, xr,xrd;
#ifdef SPAN_ST
float sl,sld, sd;
float tl,tld, td;
#endif
#ifdef SPAN_Z
unsigned int zl,zld, zd;
#endif
unsigned int *restrict outbuf;
unsigned int *restrict ti;
int i;
const swvert_t *vlt,*vlb,*vrt,*vrb;
int spanlen;
int numspans;
unsigned int *vplout;
int dx, dy;
int recalcside;
int interlace;
float fdx1,fdy1,fdx2,fdy2,fz,d1,d2;
if (!img)
return;
/*we basically render a diamond
that is, the single triangle is split into two triangles, outwards towards the midpoint and inwards to the final position.
*/
/*reorder the verticies for height*/
if (v1->vcoord[1] > v2->vcoord[1])
{
vt = v1;
v1 = v2;
v2 = vt;
}
if (v1->vcoord[1] > v3->vcoord[1])
{
vt = v1;
v1 = v3;
v3 = vt;
}
if (v2->vcoord[1] > v3->vcoord[1])
{
vt = v3;
v3 = v2;
v2 = vt;
}
{
const swvert_t *v[3];
v[0] = v1;
v[1] = v2;
v[2] = v3;
//reject triangles with any point offscreen, for now
for (i = 0; i < 3; i++)
{
if (v[i]->vcoord[0] < 0 || v[i]->vcoord[0] >= th->vpwidth)
return;
if (v[i]->vcoord[1] < 0 || v[i]->vcoord[1] >= th->vpheight)
return;
if (v[i]->vcoord[2] < 0)
return;
}
for (i = 0; i < 2; i++)
{
if (v[i]->vcoord[1] > v[i+1]->vcoord[1])
return;
}
}
fdx1 = v2->vcoord[0] - v1->vcoord[0];
fdy1 = v2->vcoord[1] - v1->vcoord[1];
fdx2 = v3->vcoord[0] - v1->vcoord[0];
fdy2 = v3->vcoord[1] - v1->vcoord[1];
fz = fdx1*fdy2 - fdx2*fdy1;
if (fz == 0)
{
//weird angle...
return;
}
fz = 1.0 / fz;
fdx1 *= fz;
fdy1 *= fz;
fdx2 *= fz;
fdy2 *= fz;
#ifdef SPAN_ST //affine
d1 = v2->tccoord[0] - v1->tccoord[0];
d2 = v3->tccoord[0] - v1->tccoord[0];
sld = fdx1*d2 - fdx2*d1;
sd = fdy2*d1 - fdy1*d2;
d1 = v2->tccoord[1] - v1->tccoord[1];
d2 = v3->tccoord[1] - v1->tccoord[1];
tld = fdx1*d2 - fdx2*d1;
td = fdy2*d1 - fdy1*d2;
#endif
#ifdef SPAN_Z
d1 = (v2->vcoord[2] - v1->vcoord[2])*UINT_MAX;
d2 = (v3->vcoord[2] - v1->vcoord[2])*UINT_MAX;
zld = fdx1*d2 - fdx2*d1;
zd = fdy2*d1 - fdy1*d2;
#endif
ti = img->data;
y = v1->vcoord[1];
for (secondhalf = 0; secondhalf <= 1; secondhalf++)
{
if (secondhalf)
{
if (numspans < 0)
{
interlace = -numspans;
y+=interlace;
numspans-=interlace;
xl += xld*interlace;
xr += xrd*interlace;
vplout += th->vpcstride*interlace;
#ifdef SPAN_ST
sl += sld*interlace;
tl += tld*interlace;
#endif
#ifdef SPAN_Z
zl += zld*interlace;
#endif
}
/*v2->v3*/
if (fz <= 0)
{
vlt = v2;
//vrt == v1;
vlb = v3;
//vrb == v3;
recalcside = 1;
#ifdef SPAN_ST
sld -= sd*xld/(float)(1<<16);
tld -= td*xld/(float)(1<<16);
#endif
#ifdef SPAN_Z
zld -= zd*xld/(float)(1<<16);
#endif
}
else
{
//vlt == v1;
vrt = v2;
///vlb == v3;
vrb = v3;
recalcside = 2;
}
//flip the triangle to keep it facing the screen (we swapped the verts almost randomly)
numspans = v3->vcoord[1] - y;
}
else
{
vlt = v1;
vrt = v1;
/*v1->v2*/
if (fz < 0)
{
vlb = v2;
vrb = v3;
}
else
{
vlb = v3;
vrb = v2;
}
recalcside = 3;
//flip the triangle to keep it facing the screen (we swapped the verts almost randomly)
numspans = v2->vcoord[1] - y;
}
if (recalcside & 1)
{
dx = (vlb->vcoord[0] - vlt->vcoord[0]);
dy = (vlb->vcoord[1] - vlt->vcoord[1]);
if (dy > 0)
xld = (dx<<16) / dy;
else
xld = 0;
xl = (int)vlt->vcoord[0]<<16;
#ifdef SPAN_ST
sl = vlt->tccoord[0];
sld = sld + sd*xld/(float)(1<<16);
tl = vlt->tccoord[1];
tld = tld + td*xld/(float)(1<<16);
#endif
#ifdef SPAN_Z
zl = vlt->vcoord[2]*UINT_MAX;
zld = zld + zd*xld/(float)(1<<16);
#endif
}
if (recalcside & 2)
{
dx = (vrb->vcoord[0] - vrt->vcoord[0]);
dy = (vrb->vcoord[1] - vrt->vcoord[1]);
if (dy)
xrd = (dx<<16) / dy;
else
xrd = 0;
xr = (int)vrt->vcoord[0]<<16;
}
if (y + numspans >= th->vpheight)
numspans = th->vpheight - y - 1;
if (numspans <= 0)
continue;
vplout = th->vpcbuf + y * th->vpcstride; //this is a pointer to the left of the viewport buffer.
interlace = ((y + th->interlaceline) % th->interlacemod);
if (interlace)
{
if (interlace > numspans)
{
interlace = numspans;
y+=interlace;
}
else
{
y+=interlace;
numspans-=interlace;
}
xl += xld*interlace;
xr += xrd*interlace;
vplout += th->vpcstride*interlace;
#ifdef SPAN_ST
sl += sld*interlace;
tl += tld*interlace;
#endif
#ifdef SPAN_Z
zl += zld*interlace;
#endif
}
for (; numspans > 0;
numspans -= th->interlacemod
,xl += xld*th->interlacemod
,xr += xrd*th->interlacemod
,vplout += th->vpcstride*th->interlacemod
,y += th->interlacemod
#ifdef SPAN_ST
,sl += sld*th->interlacemod
,tl += tld*th->interlacemod
#endif
#ifdef SPAN_Z
,zl += zld*th->interlacemod
#endif
)
{
#ifdef SPAN_ST
float s = sl;
float t = tl;
#endif
#ifdef SPAN_Z
unsigned int z = zl;
unsigned int *restrict zb = th->vpdbuf + y * th->vpwidth + (xl>>16);
#endif
spanlen = (xr - xl)>>16;
outbuf = vplout + (xl>>16);
while(spanlen-->=0)
{
PLOT_PIXEL(*outbuf);
outbuf++;
#ifdef SPAN_ST
s += sd;
t += td;
#endif
#ifdef SPAN_Z
z += zd;
zb++;
#endif
}
}
}
}
#undef SPAN_ST
#undef PLOT_PIXEL