/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2017 Andreas Maschke This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jwildfire.create.tina.base.raster; import org.jwildfire.base.mathlib.MathLib; import org.jwildfire.create.tina.base.Flame; import org.jwildfire.create.tina.base.solidrender.AOCalculator; import org.jwildfire.create.tina.base.solidrender.ShadowCalculator; import org.jwildfire.create.tina.random.AbstractRandomGenerator; import org.jwildfire.create.tina.random.MarsagliaRandomGenerator; import org.jwildfire.create.tina.render.LightViewCalculator; import org.jwildfire.create.tina.render.PlotSample; import org.jwildfire.create.tina.render.ZBufferSample; public class RasterFloatIntWithPreciseZBuffer extends RasterFloatInt { private static final long serialVersionUID = 1L; private float zBuf[][]; private float nxBuf[][]; private float nyBuf[][]; private float nzBuf[][]; private float aoBuf[][]; private float dofBuf[][]; private float materialBuf[][]; private AbstractRandomGenerator randGen; private NormalsCalculator normalsCalculator; private AOCalculator aoCalculator; private boolean withDOF; private double dofAmount; private float[][] originXBuf, originYBuf, originZBuf; private double imgSize; private LightViewCalculator lightViewCalculator; private ShadowCalculator shadowCalculator; @Override public void allocRaster(Flame flame, int pWidth, int pHeight, int pOversample, double pSampleDensity) { super.allocRaster(flame, pWidth, pHeight, pOversample, pSampleDensity); imgSize = MathLib.sqrt(MathLib.sqr(pWidth) + MathLib.sqr(pHeight)); zBuf = new float[rasterWidth][rasterHeight]; nxBuf = new float[rasterWidth][rasterHeight]; nyBuf = new float[rasterWidth][rasterHeight]; nzBuf = new float[rasterWidth][rasterHeight]; materialBuf = new float[rasterWidth][rasterHeight]; for (int i = 0; i < pWidth; i++) { for (int j = 0; j < pHeight; j++) { nxBuf[i][j] = zBuf[i][j] = NormalsCalculator.ZBUF_ZMIN; } } randGen = new MarsagliaRandomGenerator(); randGen.randomize(System.currentTimeMillis()); if (flame.getCamDOF() > MathLib.EPSILON) { withDOF = true; dofBuf = new float[rasterWidth][rasterHeight]; dofAmount = flame.getCamDOF() * imgSize / (1000.0 * (double) flame.getSpatialOversampling()); } else { withDOF = false; } originXBuf = new float[rasterWidth][rasterHeight]; originYBuf = new float[rasterWidth][rasterHeight]; originZBuf = new float[rasterWidth][rasterHeight]; for (int k = 0; k < originZBuf.length; k++) { for (int l = 0; l < originZBuf[0].length; l++) { originXBuf[k][l] = NormalsCalculator.ZBUF_ZMIN; originYBuf[k][l] = NormalsCalculator.ZBUF_ZMIN; originZBuf[k][l] = NormalsCalculator.ZBUF_ZMIN; } } if (flame.getSolidRenderSettings().isAoEnabled()) { aoCalculator = new AOCalculator(flame, rasterWidth, rasterHeight, zBuf, nxBuf, nyBuf, nzBuf); } normalsCalculator = new NormalsCalculator(rasterWidth, rasterHeight, nxBuf, nyBuf, nzBuf, originXBuf, originYBuf, originZBuf); if (flame.isWithShadows()) { shadowCalculator = new ShadowCalculator(rasterWidth, rasterHeight, originXBuf, originYBuf, originZBuf, imgSize, flame); } else { shadowCalculator = null; } } @Override public void notifyInit(LightViewCalculator lightViewCalculator) { this.lightViewCalculator = lightViewCalculator; if (shadowCalculator != null) { shadowCalculator.setLightViewCalculator(lightViewCalculator); } } @Override public/* synchronized */void addSamples(PlotSample[] pPlotBuffer, int pCount) { for (int i = 0; i < pCount; i++) { PlotSample sample = pPlotBuffer[i]; final int x = sample.screenX, y = sample.screenY; final float material = (float) sample.material; final float z = (float) sample.z; if (z > zBuf[x][y]) { count[x][y] = 1; zBuf[x][y] = z; originXBuf[x][y] = (float) sample.originalX; originYBuf[x][y] = (float) sample.originalY; originZBuf[x][y] = (float) sample.originalZ; if (sample.r >= 0 && sample.g >= 0 && sample.b >= 0) { red[x][y] = (float) sample.r; green[x][y] = (float) sample.g; blue[x][y] = (float) sample.b; } else { red[x][y] = green[x][y] = blue[x][y] = 0; } if (sample.receiveOnlyShadows) { materialBuf[x][y] = -1; } else { materialBuf[x][y] = material; } if (withDOF) { dofBuf[x][y] = (float) sample.dofDist; } if ((normalsCalculator.hasNormalAtLocation(x, y) && randGen.random() > 0.85) || randGen.random() > 0.5) { normalsCalculator.refreshNormalAtLocation(x, y); } } } } @Override public void finalizeRaster() { // No call to super here normalsCalculator.refreshAllNormals(); aoBuf = new float[rasterWidth][rasterHeight]; if (aoCalculator != null) { aoCalculator.refreshAO(aoBuf); } if (shadowCalculator != null) { shadowCalculator.accelerateShadows(); shadowCalculator.finalizeRaster(); } } private double calcDOF(double dofBufVal) { return MathLib.fabs(dofBufVal * dofAmount); } @Override public void readRasterPoint(int pX, int pY, RasterPoint pDestRasterPoint) { pDestRasterPoint.clear(); // flame density pDestRasterPoint.red = 0.0; pDestRasterPoint.green = 0.0; pDestRasterPoint.blue = 0.0; pDestRasterPoint.count = 0; // normal if (nxBuf[pX][pY] != NormalsCalculator.ZBUF_ZMIN) { // solid colors pDestRasterPoint.solidRed = red[pX][pY]; pDestRasterPoint.solidGreen = green[pX][pY]; pDestRasterPoint.solidBlue = blue[pX][pY]; pDestRasterPoint.hasSolidColors = true; pDestRasterPoint.hasNormals = true; pDestRasterPoint.nx = nxBuf[pX][pY]; pDestRasterPoint.ny = nyBuf[pX][pY]; pDestRasterPoint.nz = nzBuf[pX][pY]; pDestRasterPoint.zBuf = zBuf[pX][pY]; } // ssao if (aoBuf != null) { pDestRasterPoint.hasSSAO = true; pDestRasterPoint.ao = aoBuf[pX][pY]; } // mat pDestRasterPoint.hasMaterial = true; pDestRasterPoint.material = materialBuf[pX][pY]; if (withDOF) { pDestRasterPoint.dofDist = calcDOF(dofBuf[pX][pY]); } else { pDestRasterPoint.dofDist = 0.0; } if (shadowCalculator != null) { shadowCalculator.calcShadows(pX, pY, pDestRasterPoint); } else { pDestRasterPoint.hasShadows = false; } } @Override public void addShadowMapSamples(int pShadowMapIdx, PlotSample[] pPlotBuffer, int pCount) { shadowCalculator.addShadowMapSamples(pShadowMapIdx, pPlotBuffer, pCount); } @Override public void readZBuffer(int pX, int pY, ZBufferSample pDest) { pDest.clear(); if (zBuf[pX][pY] != NormalsCalculator.ZBUF_ZMIN) { pDest.hasZ = true; pDest.z = zBuf[pX][pY]; } } @Override public LightViewCalculator getLightViewCalculator() { return lightViewCalculator; } }