/*
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.filter;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jwildfire.base.Tools;
import org.jwildfire.create.eden.base.Face3i;
import org.jwildfire.create.eden.base.Point3f;
import org.jwildfire.create.eden.export.SunflowExporter;
import org.jwildfire.create.eden.scene.Scene;
import org.jwildfire.create.eden.scene.camera.Camera;
import org.jwildfire.create.eden.scene.light.SkyLight;
import org.jwildfire.create.eden.scene.primitive.Mesh;
import org.jwildfire.create.tina.base.Flame;
import org.jwildfire.create.tina.render.FilterHolder;
import org.jwildfire.image.SimpleImage;
import org.sunflow.SunflowAPI;
public class FilterKernelVisualisation3dRenderer extends FilterHolder implements FilterKernelVisualisationRenderer {
private static final Map<String, SimpleImage> cache = new HashMap<String, SimpleImage>();
public FilterKernelVisualisation3dRenderer(Flame pFlame) {
super(pFlame);
}
private static final Color emptyFilterColor = new Color(160, 160, 160);
public SimpleImage createKernelVisualisation(int pWidth, int pHeight) {
String key = makeKey(pWidth, pHeight);
SimpleImage img = cache.get(key);
if (img == null) {
img = new SimpleImage(pWidth, pHeight);
if (noiseFilterSize > 0) {
Scene scene = createScene(pWidth, pHeight);
double sunflowScale = 10.0;
double sunflowZScale = 0.6;
int rectCount = noiseFilterSize;
double dx = (double) pWidth / (double) rectCount;
double dy = (double) pHeight / (double) rectCount;
double w2 = (double) pWidth / 2.0;
double h2 = (double) pHeight / 2.0;
double xOff = 0.0, yOff = 0.0;
for (int i = 0; i < noiseFilterSize; i++) {
xOff = 0;
for (int j = 0; j < noiseFilterSize; j++) {
double fValue = filter[i][j];
Color rectColor;
if (fValue >= 0) {
int fValueClr = Tools.FTOI(255.0 * fValue);
if (fValueClr > 255) {
fValueClr = 255;
}
rectColor = new Color(fValueClr, fValueClr, fValueClr);
}
else {
int fValueClr = Tools.FTOI(-255.0 * (fValue - 0.5));
if (fValueClr > 255) {
fValueClr = 255;
}
rectColor = new Color(fValueClr, 0, 0);
}
addCube(scene, sunflowScale * (xOff - w2) / (double) pWidth, sunflowScale * (yOff - h2) / (double) pHeight, sunflowScale * dx / (double) pWidth, sunflowScale * dy / (double) pHeight, sunflowScale * fValue * sunflowZScale, rectColor);
xOff += dx;
}
yOff += dy;
}
try {
SunflowAPI api = createSunflowRenderer(scene);
SunFlowImagePanel imagePanel = new SunFlowImagePanel();
imagePanel.setBounds(0, 0, pWidth, pHeight);
api.render(SunflowAPI.DEFAULT_OPTIONS, imagePanel);
img.setBufferedImage(imagePanel.getImage(), imagePanel.getWidth(), imagePanel.getHeight());
}
catch (Exception e) {
e.printStackTrace();
img.fillBackground(emptyFilterColor.getRed(), emptyFilterColor.getGreen(), emptyFilterColor.getBlue());
}
}
else {
img.fillBackground(emptyFilterColor.getRed(), emptyFilterColor.getGreen(), emptyFilterColor.getBlue());
}
cache.put(key, img);
}
return img;
}
private String makeKey(int pWidth, int pHeight) {
return filterKernel.getClass().getName() + "#" + noiseFilterSize + "#" + pWidth + "#" + pHeight;
}
private SunflowAPI createSunflowRenderer(Scene scene) throws IOException, Exception {
String sceneTxt = new SunflowExporter().exportScene(scene);
String filename = createTmpFilename();
Tools.writeUTF8Textfile(filename, sceneTxt);
String template = "import org.sunflow.core.*;\nimport org.sunflow.core.accel.*;\nimport org.sunflow.core.camera.*;\nimport org.sunflow.core.primitive.*;\nimport org.sunflow.core.shader.*;\nimport org.sunflow.image.Color;\nimport org.sunflow.math.*;\n\npublic void build() {\n include(\"" + filename.replace("\\", "\\\\") + "\");\n}\n";
SunflowAPI api = SunflowAPI.compile(template);
api.build();
api.parameter("sampler", "ipr");
api.parameter("accel", "kdtree");
api.options(SunflowAPI.DEFAULT_OPTIONS);
return api;
}
private static File tmpFile = null;
private static String createTmpFilename() throws IOException {
if (tmpFile == null) {
tmpFile = File.createTempFile("jwf", ".sc");
tmpFile.deleteOnExit();
}
return tmpFile.getAbsolutePath();
}
private void addCube(Scene pScene, double pX, double pY, double pWidth, double pHeight, double pZ, Color pColor) {
Mesh mesh = pScene.addMesh();
List<Point3f> pPoints = mesh.getPoints();
List<Face3i> pFaces = mesh.getFaces();
double z0 = 0;
int idx0 = pPoints.size();
// top points
pPoints.add(new Point3f(pX, pY, pZ));
pPoints.add(new Point3f(pX, pY + pHeight, pZ));
pPoints.add(new Point3f(pX + pWidth, pY + pHeight, pZ));
pPoints.add(new Point3f(pX + pWidth, pY, pZ));
// top 0 1 3/3 1 2
pFaces.add(new Face3i(idx0, idx0 + 1, idx0 + 3));
pFaces.add(new Face3i(idx0 + 3, idx0 + 1, idx0 + 2));
// bottom points
pPoints.add(new Point3f(pX, pY, z0));
pPoints.add(new Point3f(pX, pY + pHeight, z0));
pPoints.add(new Point3f(pX + pWidth, pY + pHeight, z0));
pPoints.add(new Point3f(pX + pWidth, pY, z0));
// front 1 5 2/2 5 6
pFaces.add(new Face3i(idx0 + 1, idx0 + 5, idx0 + 2));
pFaces.add(new Face3i(idx0 + 2, idx0 + 5, idx0 + 6));
// right 2 6 3/3 6 7
pFaces.add(new Face3i(idx0 + 2, idx0 + 6, idx0 + 3));
pFaces.add(new Face3i(idx0 + 3, idx0 + 6, idx0 + 7));
// back 3 7 0/0 7 4
pFaces.add(new Face3i(idx0 + 3, idx0 + 7, idx0));
pFaces.add(new Face3i(idx0, idx0 + 7, idx0 + 4));
// left 0 4 1/1 4 5
pFaces.add(new Face3i(idx0, idx0 + 4, idx0 + 1));
pFaces.add(new Face3i(idx0 + 1, idx0 + 4, idx0 + 5));
}
private Scene createScene(int pWidth, int pHeight) {
Scene scene = new Scene();
SkyLight light = scene.addSkyLight();
light.setUp(0.0, 0.0, 1.0);
light.setEast(0.0, 1.0, 0.0);
light.setSundir(1.0, -1.0, 0.31);
light.setTurbidity(1.8);
light.setSamples(16);
Camera camera = scene.getCamera();
camera.setEye(12.0, 11.0, 15.0);
camera.setTarget(0.0, 0.0, 2.0);
camera.setUp(0.0, 0.0, 1.0);
camera.setFov(32.0);
camera.setAspect(1.0);
scene.setImageWidth(pWidth);
scene.setImageHeight(pHeight);
scene.getCamera().setAspect((double) pWidth / (double) pHeight);
return scene;
}
}