I’m having an issue I suspect has to do with the accuracy of a fixed-int, and that I’m not recalculating, I’m just stepping.
64x64 bitmap at 800x600 (more severe when rendered at a different ratio)
http://puu.sh/q535m/0fd7bfd7cb.png
100x75 (1/8th size of screen) bitmap at 800x600 (only affects second triangle, possibly has to do with rotation?)
http://puu.sh/q53M6/999bd1b04f.png
This is how I’m rendering it:
s.drawBitmap(rainbow, 0, 0, getWidth(),getHeight());
public void drawBitmap(Bitmap src, int x, int y, int w, int h) {
drawBitmap(src, x, y, x + w, y + h, 0, 0, src.width, src.height);
}
public void drawBitmap(Bitmap src, int dx0, int dy0, int dx1, int dy1, int sx0, int sy0, int sx1, int sy1) {
drawBitmapTriangle(src,
dx0, dy0, sx0, sy0, // x0, y0, u0, v0
dx1, dy0, sx1, sy0, // x1, y1, u1, v1
dx0, dy1, sx0, sy1 // x2, y2, u2, v2
);
drawBitmapTriangle(src,
dx1, dy1, sx1, sy1,
dx1, dy0, sx1, sy0,
dx0, dy1, sx0, sy1
);
}
public void drawBitmapTriangle(Bitmap src, int x0, int y0, int u0, int v0, int x1, int y1, int u1, int v1, int x2, int y2, int u2, int v2) {
// C above A
if (y2 < y0) {
int tmp = x0;
x0 = x2;
x2 = tmp;
tmp = y0;
y0 = y2;
y2 = tmp;
tmp = u0;
u0 = u2;
u2 = tmp;
tmp = v0;
v0 = v2;
v2 = tmp;
}
// B above A
if (y1 < y0) {
int tmp = x0;
x0 = x1;
x1 = tmp;
tmp = y0;
y0 = y1;
y1 = tmp;
tmp = u0;
u0 = u1;
u1 = tmp;
tmp = v0;
v0 = v1;
v1 = tmp;
}
// C above B
if (y2 < y1) {
int tmp = x1;
x1 = x2;
x2 = tmp;
tmp = y1;
y1 = y2;
y2 = tmp;
tmp = u1;
u1 = u2;
u2 = tmp;
tmp = v1;
v1 = v2;
v2 = tmp;
}
// A is below our boundaries, so we know the entire triangle is not visible.
if (y0 >= maxY) {
return;
}
// Our slope values
int mx0 = 0, mx1 = 0, mx2 = 0;
int mu0 = 0, mu1 = 0, mu2 = 0;
int mv0 = 0, mv1 = 0, mv2 = 0;
// A to B
if (y0 != y1) {
int d = y1 - y0;
mx0 = ((x1 - x0) << 16) / d;
mu0 = ((u1 - u0) << 16) / d;
mv0 = ((v1 - v0) << 16) / d;
}
// B to C
if (y1 != y2) {
int d = y2 - y1;
mx1 = ((x2 - x1) << 16) / d;
mu1 = ((u2 - u1) << 16) / d;
mv1 = ((v2 - v1) << 16) / d;
}
// A to C
if (y0 != y2) {
int d = y2 - y0;
mx2 = ((x2 - x0) << 16) / d;
mu2 = ((u2 - u0) << 16) / d;
mv2 = ((v2 - v0) << 16) / d;
}
// To 16.16 fixed
x0 <<= 16;
u0 <<= 16;
v0 <<= 16;
// Start C at B
x2 = x1 << 16;
u2 = u1 << 16;
v2 = v1 << 16;
// A (16.16)
x1 = x0;
u1 = u0;
v1 = v0;
// A is above the minimum boundary
if (y0 < minY) {
// how far we need to step vertically to get back into bounds
int step = minY - y0;
// Step A toward C
x0 += mx2 * step;
u0 += mu2 * step;
v0 += mv2 * step;
// Step A toward B
x1 += mx0 * step;
u1 += mu0 * step;
v1 += mv0 * step;
y0 = 0;
}
// B is above minimum boundary
if (y1 < minY) {
int step = minY - y1;
// Step B toward C
x2 += mx1 * step;
u2 += mu1 * step;
v2 += mv1 * step;
y1 = 0;
}
// The vertical distance between B and A
int remaining = y1 - y0;
int offset = y0 * bitmap.width;
// The first segment
while (remaining-- > 0) {
// stop if we leave the boundaries
if (++y0 > maxY) {
return;
}
drawBitmapScanline(src, offset,
x0 >> 16, u0, v0,
x1 >> 16, u1, v1
);
// step toward C
x0 += mx2;
u0 += mu2;
v0 += mv2;
// step toward B
x1 += mx0;
u1 += mu0;
v1 += mv0;
// step one row down
offset += bitmap.width;
}
// The vertical distance between B and C
remaining = y2 - y1;
// The second segment
while (remaining-- > 0) {
// stop if we leave the boundaries
if (++y0 > maxY) {
return;
}
drawBitmapScanline(src, offset,
x0 >> 16, u0, v0,
x2 >> 16, u2, v2
);
// step toward C
x0 += mx2;
u0 += mu2;
v0 += mv2;
// step toward C
x2 += mx1;
u2 += mu1;
v2 += mv1;
// step one row down
offset += bitmap.width;
}
}
private void drawBitmapScanline(Bitmap src, int offset, int x0, int u0, int v0, int x1, int u1, int v1) {
// nothing to draw
if (x0 == x1) {
return;
}
// flip
if (x0 > x1) {
int tmp = x0;
x0 = x1;
x1 = tmp;
tmp = u0;
u0 = u1;
u1 = tmp;
tmp = v0;
v0 = v1;
v1 = tmp;
}
int length = x1 - x0;
// slopes
int mu = (u1 - u0) / length;
int mv = (v1 - v0) / length;
// keep within bounds
if (x0 < minX) {
int step = minX - x0;
u0 += step * mu;
v0 += step * mv;
x0 = minX;
}
if (x1 > maxX) {
x1 = maxX;
}
length = x1 - x0;
offset += x0;
if (alpha == 256) {
while (length-- > 0) {
int x = (u0 >> 16);
int y = (v0 >> 16);
// clamp
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x >= src.width) x = src.width - 1;
if (y >= src.height) y = src.height - 1;
bitmap.data[offset++] = src.data[x + src.offsetY[y]];
u0 += mu;
v0 += mv;
}
} else {
int beta = 256 - alpha;
while (length-- > 0) {
int x = u0 >> 16;
int y = v0 >> 16;
// clamp
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x >= src.width) x = src.width - 1;
if (y >= src.height) y = src.height - 1;
bitmap.data[offset] = mix(bitmap.data[offset++], src.data[x + src.offsetY[y]], alpha, beta);
u0 += mu;
v0 += mv;
}
}
}