use of org.sunflow.image.formats.GenericBitmap in project joons-renderer by joonhyublee.
the class BucketRenderer method renderBucket.
private void renderBucket(Display display, int bx, int by, int threadID, IntersectionState istate) {
// pixel sized extents
int x0 = bx * bucketSize;
int y0 = by * bucketSize;
int bw = Math.min(bucketSize, imageWidth - x0);
int bh = Math.min(bucketSize, imageHeight - y0);
// prepare bucket
display.imagePrepare(x0, y0, bw, bh, threadID);
Color[] bucketRGB = new Color[bw * bh];
float[] bucketAlpha = new float[bw * bh];
// subpixel extents
int sx0 = x0 * subPixelSize - fs;
int sy0 = y0 * subPixelSize - fs;
int sbw = bw * subPixelSize + fs * 2;
int sbh = bh * subPixelSize + fs * 2;
// round up to align with maximum step size
sbw = (sbw + (maxStepSize - 1)) & (~(maxStepSize - 1));
sbh = (sbh + (maxStepSize - 1)) & (~(maxStepSize - 1));
// extra padding as needed
if (maxStepSize > 1) {
sbw++;
sbh++;
}
// allocate bucket memory
ImageSample[] samples = new ImageSample[sbw * sbh];
// allocate samples and compute jitter offsets
float invSubPixelSize = 1.0f / subPixelSize;
for (int y = 0, index = 0; y < sbh; y++) {
for (int x = 0; x < sbw; x++, index++) {
int sx = sx0 + x;
int sy = sy0 + y;
int j = sx & (sigmaLength - 1);
int k = sy & (sigmaLength - 1);
int i = (j << sigmaOrder) + QMC.sigma(k, sigmaOrder);
float dx = useJitter ? (float) QMC.halton(0, k) : 0.5f;
float dy = useJitter ? (float) QMC.halton(0, j) : 0.5f;
float rx = (sx + dx) * invSubPixelSize;
float ry = (sy + dy) * invSubPixelSize;
ry = imageHeight - ry;
samples[index] = new ImageSample(rx, ry, i);
}
}
for (int x = 0; x < sbw - 1; x += maxStepSize) {
for (int y = 0; y < sbh - 1; y += maxStepSize) {
refineSamples(samples, sbw, x, y, maxStepSize, thresh, istate);
}
}
if (dumpBuckets) {
UI.printInfo(Module.BCKT, "Dumping bucket [%d, %d] to file ...", bx, by);
GenericBitmap bitmap = new GenericBitmap(sbw, sbh);
for (int y = sbh - 1, index = 0; y >= 0; y--) {
for (int x = 0; x < sbw; x++, index++) {
bitmap.writePixel(x, y, samples[index].c, samples[index].alpha);
}
}
bitmap.save(String.format("bucket_%04d_%04d.png", bx, by));
}
if (displayAA) {
// color coded image of what is visible
float invArea = invSubPixelSize * invSubPixelSize;
for (int y = 0, index = 0; y < bh; y++) {
for (int x = 0; x < bw; x++, index++) {
int sampled = 0;
for (int i = 0; i < subPixelSize; i++) {
for (int j = 0; j < subPixelSize; j++) {
int sx = x * subPixelSize + fs + i;
int sy = y * subPixelSize + fs + j;
int s = sx + sy * sbw;
sampled += samples[s].sampled() ? 1 : 0;
}
}
bucketRGB[index] = new Color(sampled * invArea);
bucketAlpha[index] = 1.0f;
}
}
} else {
// filter samples into pixels
float cy = imageHeight - (y0 + 0.5f);
for (int y = 0, index = 0; y < bh; y++, cy--) {
float cx = x0 + 0.5f;
for (int x = 0; x < bw; x++, index++, cx++) {
Color c = Color.black();
float a = 0;
float weight = 0.0f;
for (int j = -fs, sy = y * subPixelSize; j <= fs; j++, sy++) {
for (int i = -fs, sx = x * subPixelSize, s = sx + sy * sbw; i <= fs; i++, sx++, s++) {
float dx = samples[s].rx - cx;
if (Math.abs(dx) > fhs) {
continue;
}
float dy = samples[s].ry - cy;
if (Math.abs(dy) > fhs) {
continue;
}
float f = filter.get(dx, dy);
c.madd(f, samples[s].c);
a += f * samples[s].alpha;
weight += f;
}
}
float invWeight = 1.0f / weight;
c.mul(invWeight);
a *= invWeight;
bucketRGB[index] = c;
bucketAlpha[index] = a;
}
}
}
// update pixels
display.imageUpdate(x0, y0, bw, bh, bucketRGB, bucketAlpha);
}
Aggregations