public class RenderBuffer
{
//---- DATA
//---- Buffer data
int w, h, size;
int[] buf;
int[] zbuf;
int clip_x1, clip_y1;
int clip_x2, clip_y2;
int cx, cy;
//---- Triangle data
float tri_x1, tri_y1, tri_z1;
float tri_x2, tri_y2, tri_z2;
float tri_x3, tri_y3, tri_z3;
//---- CODE
//---- RenderBuffer
public RenderBuffer(int width, int height)
{
w = width;
h = height;
cx = w >> 1;
cy = h >> 1;
clip_x1 = 0; clip_y1 = 0;
clip_x2 = w; clip_y2 = h;
size = w*h;
buf = new int[size];
zbuf = new int[size];
clear(0);
clearZBuf();
}
//---- clear
public void clear(int col)
{
for(int i=0; i<size; i++) buf[i] = col;
}
//---- clearZBuf
public void clearZBuf()
{
for(int i=0; i<size; i++) zbuf[i] = 0;
}
//---- copy
public void copy(RenderBuffer src)
{
int[] srcbuf = src.buf;
for(int i=0; i<size; i++) buf[i] = srcbuf[i];
}
//---- layer
public void layer(RenderBuffer src)
{
int[] srcbuf = src.buf;
for(int i=0; i<size; i++) if((srcbuf[i] & 0xFF000000) != 0) buf[i] = srcbuf[i];
}
//---- box
public void box(double x1, double y1, double x2, double y2, int col)
{
int xx1 = (int)x1, yy1 = (int)y1, xx2 = (int)x2, yy2 = (int)y2;
if(xx1 < clip_x1) xx1 = clip_x1;
if(xx2 > clip_x2) xx2 = clip_x2;
if(yy1 < clip_y1) yy1 = clip_y1;
if(yy2 > clip_y2) yy2 = clip_y2;
int i, i1, i2;
for(int j=yy1; j<yy2; j++)
{
i1 = j*w + xx1;
i2 = j*w + xx2;
for(i=i1; i<i2; i++) buf[i] = col;
}
}
//---- circle
public void circle(double cx, double cy, double r, int col)
{
int y1 = (int)(cy-r-1);
int y2 = (int)(cy+r+1);
int i, i1, i2;
double r2 = r*r;
double a;
if(y1 < clip_y1) y1 = clip_y1;
if(y2 > clip_y2) y2 = clip_y2;
for(int y = y1; y < y2; y ++)
{
a = r2 - (cy-y)*(cy-y);
if(a > 0)
{
a = Math.sqrt(a);
i1 = (int)(cx-a);
i2 = (int)(cx+a);
if(i1 < clip_x1) i1 = clip_x1;
if(i2 > clip_x2) i2 = clip_x2;
i1 += y*w;
i2 += y*w;
for(i=i1; i<i2; i++) buf[i] = col;
}
}
}
//---- xSkewCircle
public void xSkewCircle(double cx, double cy, double r, double xscale, double xskew, int col)
{
int y1 = (int)(cy-r-1);
int y2 = (int)(cy+r+1);
int i, i1, i2;
double r2 = r*r;
double a;
if(y1 < clip_y1) y1 = clip_y1;
if(y2 > clip_y2) y2 = clip_y2;
for(int y = y1; y < y2; y ++)
{
a = r2 - (cy-y)*(cy-y);
if(a > 0)
{
a = xscale * Math.sqrt(a);
i1 = (int)(cx - a + (cy-y)*xskew);
i2 = (int)(cx + a + (cy-y)*xskew);
if(i1 < clip_x1) i1 = clip_x1;
if(i2 > clip_x2) i2 = clip_x2;
i1 += y*w;
i2 += y*w;
for(i=i1; i<i2; i++) buf[i] = col;
}
}
}
//---- alphaPixel
void alphaPixel(int i, int r, int g, int b, int a)
{
int c = buf[i];
int rr = (c>>16) & 0xFF;
int gg = (c>> 8) & 0xFF;
int bb = (c ) & 0xFF;
rr = ( rr*(255-a) + r*(a) ) >> 8;
gg = ( gg*(255-a) + g*(a) ) >> 8;
bb = ( bb*(255-a) + b*(a) ) >> 8;
buf[i] = 0xFF000000 + (rr << 16) + (gg << 8) + (bb);
}
//---- hilightEdges
void hilightEdges(int col)
{
int x, y, a;
for(int i = w*3 + 3; i < size-w*3-3; i++)
{
/*
if(zbuf[i] == 0)
{
for(y = -w*3; y <= w*3; y+= w) for(x = -3; x <= 3; x++)
{
if(zbuf[i+x+y] > 0)
{
buf[i] = 0xFFFFFFFF;
break;
}
}
}
*/
int dx = zbuf[i-1] - 2*zbuf[i] + zbuf[i+1];
int dy = zbuf[i-w] - 2*zbuf[i] + zbuf[i+w];
if(dx < 0) dx =- dx;
if(dy < 0) dy =- dy;
// if(dx > 40) buf[i] = col;
// if(dy > 40) buf[i] = col;
if(dx > 40 || dy > 40)
{
a = dx;
if(a < dy) a = dy;
if(a > 255+40) a = 255+40;
alphaPixel(i, 0, 0, 0, a-40);
}
}
}
//---- zbufTri
void zbufTri(int col)
{
int i, j;
//- 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;
}
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;
}
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;
}
//- 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);
//- 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;
//- See if we need to flip triangle horizontally
boolean side13onleft = dx13 < dx12;
//- Draw top of triangle
float xa, xb, dxa, dxb;
float za, zb, dza, dzb;
// Swap over if necessary
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;
}
int fxa = (int)(xa * 0x10000), fxb = (int)(xb * 0x10000);
int fdxa = (int)(dxa * 0x10000), fdxb = (int)(dxb * 0x10000);
float zl = tri_z1 - tri_x1*dzx + (y1-tri_y1)*dzy;
for(j=y1; j<y2; j++)
{
int xai = (fxa+0xFFFF) >> 16; // int xai = (int)xa; if(xai < xa) xai++;
int xbi = (fxb+0xFFFF) >> 16; // 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;
int o = j*w + xai;
int oz = j*w + xai;
for(i=xai; i<xbi; i++)
{
int tempz = (int)(z*0x10000);
if(tempz > zbuf[oz])
{
buf[o] = col;
zbuf[oz] = tempz;
}
o ++;
oz ++;
z += dzx;
}
fxa += fdxa; fxb += fdxb;
zl += dzy;
}
//- Draw bottom of triangle
if(side13onleft)
{
xb = tri_x2 + dx23 * (y2-tri_y2);
dxb = dx23;
fxb = (int)(xb *0x10000);
fdxb = (int)(dxb*0x10000);
}
else
{
xa = tri_x2 + dx23 * (y2-tri_y2);
dxa = dx23;
fxa = (int)(xa *0x10000);
fdxa = (int)(dxa*0x10000);
}
for(j=y2; j<y3; j++)
{
int xai = (fxa+0xFFFF) >> 16; // int xai = (int)xa; if(xai < xa) xai++;
int xbi = (fxb+0xFFFF) >> 16; // 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;
int o = j*w + xai;
int oz = j*w + xai;
for(i=xai; i<xbi; i++)
{
int tempz = (int)(z*0x10000);
if(tempz > zbuf[oz])
{
buf[o] = col;
zbuf[oz] = tempz;
}
o ++;
oz ++;
z += dzx;
}
fxa += fdxa; fxb += fdxb;
zl += dzy;
}
}
}