import processing.core.*;
import SGCamera.*;
import SGQuickVar.*;
import Raytracing.*;
 
 
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.zip.*;
 
public class DepthOfField extends PApplet {
 
SGCamera cam;
int time = 0;
float dof = 1;
int iterations = 200;
Vector splats;
boolean running = false;
hdrColor[] buffer;
float jitX = -1 / (iterations / 2);
float jitY = -1 / (iterations / 2);
int dim = 50;
SGVariable focalLength;
SGVariable samples;
SGVariable amt;
PFont font;
Raytracer house;
int keyTime = 0;
int keyEndTime = 150;
float keyLerp = 0;
boolean rendering = false;
float li = 0;
float lf = 8;
float lc;
 
public void setup() {
size(550, 550, P3D);
frameRate(240);
cam = new SGCamera(this, 10, 10, 0, 0, 0, 0, SGCamera.ORBIT, SGCamera.DOLLY);
 
 
cam.lookAt(0, -10, 0);
cam.setPosition(0, -20, -60);
 
cam.setRhoLimits(15,100);
cam.setVerticalLimits(0, PI/2);
buffer = new hdrColor[width * height];
 
for (int i = 0; i < width * height; i++) {
buffer[i] = new hdrColor(0, 0, 0);
}
 
time = 0;
font = loadFont("writing.vlw");
textFont(font);
 
focalLength = new SGVariable(this, font, "Focal Length", 'a', 'z', 30f, 2f, 10f, 150);
focalLength.setTextColor(0);
samples = new SGVariable(this, font, "Samples", 's', 'x', 8, 1, 4, 50);
samples.setTextColor(0);
amt = new SGVariable(this, font, "Radius", 'd', 'c', 2, .2f, 0, 8);
amt.setTextColor(0);
splats = buildStratified(1, (int) (samples.val * samples.val));
 
house = new Raytracer(this);
house.openFile("shoeBot.mra");
 
 
g.hint(PApplet.DISABLE_ACCURATE_TEXTURES);
 
}
 
public Vector buildStratified(float jitter, int samples) {
splats = new Vector();
int side = (int) sqrt(samples);
 
float pixWidth = 1.f / side;
float wt;
for (float i = -.5f; i < .5f; i += 1.f / side) {
for (float j = -.5f; j < .5f; j += 1.f / side) {
wt = sqrt(i * i + j * j);
if (wt < .5f) {
splats.add(new PVector(i + random(-pixWidth, pixWidth), j + random(-pixWidth, pixWidth), 1.01f - 2.f * wt));
}
}
}
return splats;
}
 
public void draw() {
 
keyLerp = (float) keyTime / keyEndTime;
lc = li + keyLerp * (lf - li);
 
 
 
background(220);
PVector sample = (PVector) splats.elementAt(time);
 
cam.focus = focalLength.val;
cam.fx = amt.val * sample.x;
cam.fy = amt.val * sample.y;
 
 
 
cam.feed();
 
pushMatrix();
rotateX(PI / 2);
int scale = 10;
for (int i = -10; i < 10; i++) {
for (int j = -10; j < 10; j++) {
if ((i + j) % 2 == 0) {
fill(0);
}
else {
fill(128);
}
rect(scale * i, scale * j, scale, scale);
}
}
popMatrix();
 
 
noStroke();
fill(100, 25, 25);
 
for (int m = -2; m <= 2; m++) {
for (int i = -2; i <= 2; i++) {
pushMatrix();
 
translate(m * 15, 0, 15 * i);
rotateY(i * .5f);
scale(.25f);
house.draw();
popMatrix();
}
}
 
if (running && time < splats.size() - 1) {
time++;
loadPixels();
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
buffer[j * width + i].add(pixels[j * width + i], sample.z);
}
}
 
}
else if (running) {
 
for (int i = 0; i < width * height; i++) {
pixels[i] = buffer[i].toLDR(iterations);
}
updatePixels();
 
if (rendering) {
String name = "";
if (keyTime < 10) {
name = "0";
}
if (keyTime < 100) {
name += "0";
}
 
saveFrame(name + keyTime + ".png");
keyTime++;
resetBuffers();
if (keyTime < keyEndTime) {
running = true;
}
 
amt.val = lc;
}
 
}
 
}
 
private void vignette(hdrColor[] buffer) {
 
float sc;
float off = 300;
float on = 50;
float fade = .4f;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
sc = sqrt((i - width / 2) * (i - width / 2) + (j - height / 2) * (j - height / 2));
if (sc > on) {
sc -= on;
sc /= (off - on);
sc *= sc;
sc = (1 - fade*sc);
buffer[j * width + i].weight /= sc;
}
}
}
}
 
private void resetBuffers() {
time = 0;
running = false;
 
for (int i = 0; i < width * height; i++) {
buffer[i] = new hdrColor(0, 0, 0);
}
}
 
public void mousePressed() {
resetBuffers();
 
}
 
public void keyPressed() {
if (key == ' ') {
resetBuffers();
splats = buildStratified(1, (int) (samples.val * samples.val));
running = true;
 
}
else if (key == 'r') {
resetBuffers();
splats = buildStratified(1, (int) (samples.val * samples.val));
running = true;
rendering = true;
}
else if (key == 'v') {
vignette(buffer);
}
 
}
 
public class hdrColor {
 
float r, g, b, a;
float weight;
 
public hdrColor(float r, float g, float b) {
this.r = r;
this.g = g;
this.b = b;
}
 
public void add(int c1, float weight) {
r += weight * (c1 >> 16 & 0xff);
g += weight * (c1 >> 8 & 0xff);
b += weight * (c1 & 0xff);
this.weight += weight;
}
 
public int toLDR(float exposure) {
return color(r / weight, g / weight, b / weight);
 
}
}
 
static public void main(String args[]) {
PApplet.main(new String[]{"DepthOfField"});
}
}