/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2015 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.render; import static org.jwildfire.base.mathlib.MathLib.EPSILON; import static org.jwildfire.base.mathlib.MathLib.M_PI; import static org.jwildfire.base.mathlib.MathLib.cos; import static org.jwildfire.base.mathlib.MathLib.exp; import static org.jwildfire.base.mathlib.MathLib.fabs; import static org.jwildfire.base.mathlib.MathLib.sin; import org.jwildfire.base.mathlib.GfxMathLib; import org.jwildfire.create.tina.base.Flame; import org.jwildfire.create.tina.base.Stereo3dEye; import org.jwildfire.create.tina.base.XYZPoint; import org.jwildfire.create.tina.base.XYZProjectedPoint; import org.jwildfire.create.tina.base.solidrender.ShadowType; import org.jwildfire.create.tina.random.AbstractRandomGenerator; import org.jwildfire.create.tina.render.dof.DOFBlurShape; import org.jwildfire.create.tina.variation.FlameTransformationContext; public class FlameRendererView { protected final Flame flame; protected double cameraMatrix[][] = new double[3][3]; protected double camDOF_10; protected boolean useDOF; protected boolean solidFlame; protected boolean solidHardShadows; protected boolean legacyDOF; protected double cosa; protected double sina; double camX0, camX1, camY0, camY1; double camW, camH; protected double rcX; protected double rcY; double bws; double bhs; protected XYZPoint camPoint = new XYZPoint(); // 3D stuff protected boolean doProject3D = false; private final AbstractRandomGenerator randGen; private final int borderWidth; private final int maxBorderWidth; private final int imageWidth; private final int imageHeight; private final int rasterWidth; private final int rasterHeight; private final FlameTransformationContext flameTransformationContext; private final DOFBlurShape dofBlurShape; protected final Stereo3dEye eye; private double area, fade, areaMinusFade; private LightViewCalculator lightViewCalculator; public FlameRendererView(Stereo3dEye pEye, Flame pFlame, AbstractRandomGenerator pRandGen, int pBorderWidth, int pMaxBorderWidth, int pImageWidth, int pImageHeight, int pRasterWidth, int pRasterHeight, FlameTransformationContext pFlameTransformationContext) { flame = pFlame; randGen = pRandGen; borderWidth = pBorderWidth; maxBorderWidth = pMaxBorderWidth; imageWidth = pImageWidth; imageHeight = pImageHeight; rasterWidth = pRasterWidth; rasterHeight = pRasterHeight; eye = pEye; flameTransformationContext = pFlameTransformationContext; init3D(); initView(); dofBlurShape = pFlame.getCamDOFShape().getDOFBlurShape(); dofBlurShape.assignParams(pFlame); dofBlurShape.prepare(flameTransformationContext, randGen, camDOF_10); } protected void init3D() { { double yaw = -flame.getCamYaw() * M_PI / 180.0; double pitch = flame.getCamPitch() * M_PI / 180.0; double roll = flame.getCamRoll() * M_PI / 180.0; createProjectionMatrix(cameraMatrix, yaw, pitch, roll); } useDOF = flame.isDOFActive(); solidFlame = flame.getSolidRenderSettings().isSolidRenderingEnabled(); if (solidFlame) { lightViewCalculator = new LightViewCalculator(flame); solidHardShadows = !ShadowType.OFF.equals(flame.getSolidRenderSettings().getShadowType()); } else { lightViewCalculator = null; solidHardShadows = false; } doProject3D = flame.is3dProjectionRequired(); legacyDOF = !flame.isNewCamDOF(); camDOF_10 = 0.1 * flame.getCamDOF(); area = flame.getCamDOFArea(); fade = flame.getCamDOFArea() / 2.25; areaMinusFade = area - fade; } private void createProjectionMatrix(double m[][], double yaw, double pitch, double roll) { m[0][0] = cos(yaw) * cos(roll) - sin(roll) * sin(yaw) * cos(pitch); m[1][0] = -sin(yaw) * cos(roll) - cos(yaw) * cos(pitch) * sin(roll); m[2][0] = sin(roll) * sin(pitch); m[0][1] = cos(yaw) * sin(roll) + cos(roll) * sin(yaw) * cos(pitch); m[1][1] = -sin(yaw) * sin(roll) + cos(yaw) * cos(pitch) * cos(roll); m[2][1] = -cos(roll) * sin(pitch); m[0][2] = sin(yaw) * sin(pitch); m[1][2] = cos(yaw) * sin(pitch); m[2][2] = cos(pitch); } public void initView() { double pixelsPerUnit = flame.getPixelsPerUnit() * flame.getCamZoom(); double corner_x = flame.getCentreX() - (double) imageWidth / pixelsPerUnit / 2.0; double corner_y = flame.getCentreY() - (double) imageHeight / pixelsPerUnit / 2.0; int oversample = flame.getSpatialOversampling(); double t0 = borderWidth / (oversample * pixelsPerUnit); double t1 = borderWidth / (oversample * pixelsPerUnit); double t2 = (2 * maxBorderWidth - borderWidth) / (oversample * pixelsPerUnit); double t3 = (2 * maxBorderWidth - borderWidth) / (oversample * pixelsPerUnit); camX0 = corner_x - t0; camY0 = corner_y - t1; camX1 = corner_x + (double) imageWidth / pixelsPerUnit + t2; camY1 = corner_y + (double) imageHeight / pixelsPerUnit + t3; camW = camX1 - camX0; double Xsize, Ysize; if (fabs(camW) > 0.01) Xsize = 1.0 / camW; else Xsize = 1.0; camH = camY1 - camY0; if (fabs(camH) > 0.01) Ysize = 1.0 / camH; else Ysize = 1; bws = (rasterWidth - 0.5) * Xsize; bhs = (rasterHeight - 0.5) * Ysize; if (!doProject3D) { cosa = cos(-M_PI * (flame.getCamRoll()) / 180.0); sina = sin(-M_PI * (flame.getCamRoll()) / 180.0); rcX = flame.getCentreX() * (1 - cosa) - flame.getCentreY() * sina - camX0; rcY = flame.getCentreY() * (1 - cosa) + flame.getCentreX() * sina - camY0; } else { cosa = 1.0; sina = 0.0; rcX = -camX0; rcY = -camY0; } } public boolean project(XYZPoint pPoint, XYZProjectedPoint pProjectedPoint) { if (doProject3D) { if (solidHardShadows) { lightViewCalculator.project(pPoint, pProjectedPoint); } applyCameraMatrix(pPoint); camPoint.x += flame.getCamPosX(); camPoint.y += flame.getCamPosY(); camPoint.z += flame.getCamPosZ(); double zr = 1.0 - flame.getCamPerspective() * camPoint.z + flame.getCamPosZ(); if (zr < EPSILON) { return false; } pProjectedPoint.z = camPoint.z; if (flame.getDimishZ() > EPSILON) { double zdist = (flame.getCamZ() - camPoint.z); if (zdist > 0.0) { pProjectedPoint.intensity = exp(-zdist * zdist * flame.getDimishZ()); } else { pProjectedPoint.intensity = 1.0; } } else { pProjectedPoint.intensity = 1.0; } if (useDOF) { if (legacyDOF) { double zdist = (flame.getCamZ() - camPoint.z); if (zdist > 0.0) { pProjectedPoint.dofDist = zdist; if (solidFlame) { dofBlurShape.applyOnlyCamera(camPoint, pPoint, zdist, zr); } else { dofBlurShape.applyDOFAndCamera(camPoint, pPoint, zdist, zr); } } else { pProjectedPoint.dofDist = 0.0; dofBlurShape.applyOnlyCamera(camPoint, pPoint, zdist, zr); } } else { double xdist = (camPoint.x - flame.getFocusX()); double ydist = (camPoint.y - flame.getFocusY()); double zdist = (camPoint.z - flame.getFocusZ()); double dist = Math.pow(xdist * xdist + ydist * ydist + zdist * zdist, 1.0 / flame.getCamDOFExponent()); if (dist > area) { pProjectedPoint.dofDist = dist; if (solidFlame) { dofBlurShape.applyOnlyCamera(camPoint, pPoint, dist, zr); } else { dofBlurShape.applyDOFAndCamera(camPoint, pPoint, dist, zr); } } else if (dist > areaMinusFade) { /* double scl = (dist - areaMinusFade) / fade; double sclDist = dist * scl * scl;*/ double scl = GfxMathLib.smootherstep(0.0, 1.0, (dist - areaMinusFade) / fade); double sclDist = scl * dist; pProjectedPoint.dofDist = sclDist; if (solidFlame) { dofBlurShape.applyOnlyCamera(camPoint, pPoint, sclDist, zr); } else { dofBlurShape.applyDOFAndCamera(camPoint, pPoint, sclDist, zr); } } else { pProjectedPoint.dofDist = 0.0; dofBlurShape.applyOnlyCamera(camPoint, pPoint, zdist, zr); } } } else { pPoint.x = camPoint.x / zr; pPoint.y = camPoint.y / zr; pProjectedPoint.dofDist = 0.0; } } else { pProjectedPoint.intensity = 1.0; } pProjectedPoint.x = pPoint.x * cosa + pPoint.y * sina + rcX; if ((pProjectedPoint.x < 0) || (pProjectedPoint.x > camW)) return false; pProjectedPoint.y = pPoint.y * cosa - pPoint.x * sina + rcY; if ((pProjectedPoint.y < 0) || (pProjectedPoint.y > camH)) return false; return true; } protected void applyCameraMatrix(XYZPoint pPoint) { camPoint.x = cameraMatrix[0][0] * pPoint.x + cameraMatrix[1][0] * pPoint.y + cameraMatrix[2][0] * pPoint.z; camPoint.y = cameraMatrix[0][1] * pPoint.x + cameraMatrix[1][1] * pPoint.y + cameraMatrix[2][1] * pPoint.z; camPoint.z = cameraMatrix[0][2] * pPoint.x + cameraMatrix[1][2] * pPoint.y + cameraMatrix[2][2] * pPoint.z; } public double getRcX() { return rcX; } public double getRcY() { return rcY; } public double getBws() { return bws; } public double getBhs() { return bhs; } public LightViewCalculator getLightViewCalculator() { return lightViewCalculator; } }