324 lines
5.9 KiB
C
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
|