//---- tri_persp
// Array of flattened 256x256 32-bit RGB texture bitmaps
// In the case of Lewpen.com panorama viewer, the dimensions are tex[6][65536]
int[][] tex;
// Arguments for tri_persp - co-ordinates and texture co-ords of each corner
float tri_x1, tri_y1, tri_z1, tri_u1, tri_v1;
float tri_x2, tri_y2, tri_z2, tri_u2, tri_v2;
float tri_x3, tri_y3, tri_z3, tri_u3, tri_v3;
public void tri_persp(int texnum)
{
if(tri_z1 < 0) return;
if(tri_z2 < 0) return;
if(tri_z3 < 0) return;
int[] tex = this.tex[texnum];
tri_u1 = 256-tri_u1;
tri_u2 = 256-tri_u2;
tri_u3 = 256-tri_u3;
int i, j;
// Don't draw if backfacing
if((tri_x2-tri_x1)*(tri_y3-tri_y1) < (tri_x3-tri_x1)*(tri_y2-tri_y1)) return;
//- Sort points
float t;
if(tri_y2 < tri_y1)
{
t = tri_x1; tri_x1 = tri_x2; tri_x2 = t;
t = tri_y1; tri_y1 = tri_y2; tri_y2 = t;
t = tri_z1; tri_z1 = tri_z2; tri_z2 = t;
t = tri_u1; tri_u1 = tri_u2; tri_u2 = t;
t = tri_v1; tri_v1 = tri_v2; tri_v2 = t;
}
if(tri_y3 < tri_y2)
{
t = tri_x2; tri_x2 = tri_x3; tri_x3 = t;
t = tri_y2; tri_y2 = tri_y3; tri_y3 = t;
t = tri_z2; tri_z2 = tri_z3; tri_z3 = t;
t = tri_u2; tri_u2 = tri_u3; tri_u3 = t;
t = tri_v2; tri_v2 = tri_v3; tri_v3 = t;
}
if(tri_y2 < tri_y1)
{
t = tri_x1; tri_x1 = tri_x2; tri_x2 = t;
t = tri_y1; tri_y1 = tri_y2; tri_y2 = t;
t = tri_z1; tri_z1 = tri_z2; tri_z2 = t;
t = tri_u1; tri_u1 = tri_u2; tri_u2 = t;
t = tri_v1; tri_v1 = tri_v2; tri_v2 = t;
}
//- Divide by z to do perspective correction
tri_u1 /= tri_z1; tri_u2 /= tri_z2; tri_u3 /= tri_z3;
tri_v1 /= tri_z1; tri_v2 /= tri_z2; tri_v3 /= tri_z3;
tri_z1 = 1.0f/tri_z1; tri_z2 = 1.0f/tri_z2; tri_z3 = 1.0f/tri_z3;
//- Work out deltas along edges
float dx12 = (tri_x2-tri_x1)/(tri_y2-tri_y1), dx23 = (tri_x3-tri_x2)/(tri_y3-tri_y2), dx13 = (tri_x3-tri_x1)/(tri_y3-tri_y1);
float dz12 = (tri_z2-tri_z1)/(tri_y2-tri_y1), dz23 = (tri_z3-tri_z2)/(tri_y3-tri_y2), dz13 = (tri_z3-tri_z1)/(tri_y3-tri_y1);
float du12 = (tri_u2-tri_u1)/(tri_y2-tri_y1), du23 = (tri_u3-tri_u2)/(tri_y3-tri_y2), du13 = (tri_u3-tri_u1)/(tri_y3-tri_y1);
float dv12 = (tri_v2-tri_v1)/(tri_y2-tri_y1), dv23 = (tri_v3-tri_v2)/(tri_y3-tri_y2), dv13 = (tri_v3-tri_v1)/(tri_y3-tri_y1);
//- Round to pixel and clip to top & bottom of screen
int y1 = (int)tri_y1; if(y1 < tri_y1) y1++;
int y2 = (int)tri_y2; if(y2 < tri_y2) y2++;
int y3 = (int)tri_y3; if(y3 < tri_y3) y3++;
if(y1 < clip_y1) y1 = clip_y1;
if(y2 < clip_y1) y2 = clip_y1;
if(y3 < clip_y1) y3 = clip_y1;
if(y1 > clip_y2) y1 = clip_y2;
if(y2 > clip_y2) y2 = clip_y2;
if(y3 > clip_y2) y3 = clip_y2;
if(y3 <= y1) return;
//- Calculate horizontal and vertical deltas for parameters
float d = (tri_x3-tri_x1)*(tri_y2-tri_y1) - (tri_y3-tri_y1)*(tri_x2-tri_x1);
float dzx = ( (tri_y2-tri_y1)*(tri_z3-tri_z1) + (tri_y1-tri_y3)*(tri_z2-tri_z1) ) / d;
float dzy = ( (tri_x1-tri_x2)*(tri_z3-tri_z1) + (tri_x3-tri_x1)*(tri_z2-tri_z1) ) / d;
float dux = ( (tri_y2-tri_y1)*(tri_u3-tri_u1) + (tri_y1-tri_y3)*(tri_u2-tri_u1) ) / d;
float duy = ( (tri_x1-tri_x2)*(tri_u3-tri_u1) + (tri_x3-tri_x1)*(tri_u2-tri_u1) ) / d;
float dvx = ( (tri_y2-tri_y1)*(tri_v3-tri_v1) + (tri_y1-tri_y3)*(tri_v2-tri_v1) ) / d;
float dvy = ( (tri_x1-tri_x2)*(tri_v3-tri_v1) + (tri_x3-tri_x1)*(tri_v2-tri_v1) ) / d;
//- See if we need to flip triangle horizontally
boolean side13onleft = dx13 < dx12;
//- Draw top of triangle
float xa, xb, dxa, dxb;
if(side13onleft)
{
xa = tri_x1 + dx13 * (y1-tri_y1);
xb = tri_x1 + dx12 * (y1-tri_y1);
dxa = dx13;
dxb = dx12;
}
else
{
xa = tri_x1 + dx12 * (y1-tri_y1);
xb = tri_x1 + dx13 * (y1-tri_y1);
dxa = dx12;
dxb = dx13;
}
float zl = tri_z1 - tri_x1*dzx + (y1-tri_y1)*dzy;
float ul = tri_u1 - tri_x1*dux + (y1-tri_y1)*duy;
float vl = tri_v1 - tri_x1*dvx + (y1-tri_y1)*dvy;
for(j=y1; j<y2; j++)
{
int xai = (int)xa; if(xai < xa) xai++;
int xbi = (int)xb; if(xbi < xb) xbi++;
if(xai < clip_x1) xai = clip_x1;
if(xbi < clip_x1) xbi = clip_x1;
if(xai > clip_x2) xai = clip_x2;
if(xbi > clip_x2) xbi = clip_x2;
float z = zl + xai*dzx;
float u = ul + xai*dux;
float v = vl + xai*dvx;
int o = j*w+xai;
for(i=xai; i<xbi; i++)
{
// Perspective per-pixel divide by Z happens here
buf[o++] = tex[ ( (((int)(v/z))<<8) + ((int)(u/z)) ) & 0xFFFF ];
// use (((int)u)<<16)+(((int)v)<<8) for linear.
z += dzx;
u += dux;
v += dvx;
}
xa += dxa; xb += dxb;
zl += dzy;
ul += duy;
vl += dvy;
}
//- Draw bottom of triangle
if(side13onleft)
{
xb = tri_x2 + dx23 * (y2-tri_y2);
dxb = dx23;
}
else
{
xa = tri_x2 + dx23 * (y2-tri_y2);
dxa = dx23;
}
for(j=y2; j<y3; j++)
{
int xai = (int)xa; if(xai < xa) xai++;
int xbi = (int)xb; if(xbi < xb) xbi++;
if(xai < clip_x1) xai = clip_x1;
if(xbi < clip_x1) xbi = clip_x1;
if(xai > clip_x2) xai = clip_x2;
if(xbi > clip_x2) xbi = clip_x2;
float z = zl + xai*dzx;
float u = ul + xai*dux;
float v = vl + xai*dvx;
int o = j*w+xai;
for(i=xai; i<xbi; i++)
{
// Perspective per-pixel divide by Z happens here
buf[o++] = tex[ ( (((int)(v/z))<<8) + ((int)(u/z)) ) & 0xFFFF ];
// use (((int)u)<<16)+(((int)v)<<8) for linear.
z += dzx;
u += dux;
v += dvx;
}
xa += dxa; xb += dxb;
zl += dzy;
ul += duy;
vl += dvy;
}
} |