import SGCamera.*;
import Raytracing.*;
import Tuple.*;
 
SGCamera cam;
Raytracer tracer;
 
float dx = 0,dy = 0, dz = 0;
 
PImage [] pix = new PImage[11];
PImage [] maps = new PImage[5];
int level = 0;
boolean jetpack = false;
int nextImg = 0;
int nextPort = 0;
int numImgs = 10;
void setup(){
 
size(550,450,P3D);
cam = new SGCamera(this,-50,-80,-100,0,0,0, SGCamera.MOUSELOOK, SGCamera.MOVE);
tracer = new Raytracer(this);
frameRate(30);
tracer.openFile("galleryIII.mra",cam);
 
pix[0] = loadImage("alpha.jpg");
pix[1] = loadImage("bravo.jpg");
pix[2] = loadImage("charlie.jpg");
pix[3] = loadImage("delta.jpg");
pix[4] = loadImage("echo.jpg");
pix[5] = loadImage("foxtrot.jpg");
pix[6] = loadImage("golf.jpg");
pix[7] = loadImage("hotel.jpg");
pix[8] = loadImage("india.jpg");
pix[9] = loadImage("juliet.jpg");
pix[10] = loadImage("lima.jpg");
 
PImage tmp;
for (int i =0; i < 5; i++){
tmp = (PImage)tracer.baked.elementAt(i);
maps[i] = new PImage(tmp.width, tmp.height);
System.arraycopy(tmp.pixels,0,maps[i].pixels,0,tmp.width*tmp.height);
}
cam.fov = 1.5;
 
nextBottom();
nextTop();
 
}
 
public void draw(){
background(220,220,255);
 
cam.feed();
tracer.draw();
 
Ray down = new Ray(cam.pos,new Tuple3f(0,1,0));
tracer.accelerator.findNearest(down);
if (down.occluder != null){
float eyeheight = 100;
if (jetpack){
dz -= 1.2f;
cam.translate(random(-1.5,1.5),dz + random(0,2),random(-1.5,1.5));
}
if (down.distance > eyeheight){
dz += .98;
cam.translate(0,dz,0);
}
else if (down.distance < eyeheight){
cam.translate(0,-(eyeheight-down.distance)/2.f,0);
dz = 0;
}
 
}
Tuple3f direction = null;
if (dx > 0) direction = cam.forward.getCopy();
else if (dx < 0) direction = cam.forward.times(-1.f);
if (dy !=0 && direction == null) direction = new Tuple3f();
if (dy > 0) direction.plusEquals(cam.right);
else if (dy < 0) direction.plusEquals(cam.right.times(-1.f));
if (direction != null){
direction.timesEquals(20);
Tuple3f bodypoint = cam.pos.getCopy();
bodypoint.y += 30.f;
direction.y = 0;
down = new Ray(bodypoint,direction);
down.maxDist = 100.f;
tracer.accelerator.findNearest(down);
if (down.occluder == null){
cam.translate(direction.x, direction.y,direction.z);
}
}
 
if (cam.pos.x > 0 && level == 0){
level = 1;
nextBottom();
}
else if (cam.pos.x < 0 && level == 1){
level = 0;
nextTop();
}
 
}
public void keyPressed(){
if (key == 'w' ){
dx = 20;
}
else if (key == 's' ){
dx = -20;
}
if (key == 'd' ){
dy = 20;
}
else if (key == 'a' ){
dy = -20;
}
else if (key == 'q'){
if (dz == 0){
dz -= 10.f;
cam.translate(0,dz,0);
}
}
else if (key == ' '){
 
if (level == 0) nextBottom();
else nextTop();
}
else if (key == 'e'){
cam.fov -= .2;
}
else if (key == 'c'){
cam.fov += .2;
}
cam.fov = constrain(cam.fov,.6,2.8);
}
 
public void keyReleased(){
if (key == 'w' || key == 's') dx = 0;
if (key == 'a' || key == 'd') dy = 0;
 
}
 
 
PImage rotateCCW(PImage img){
PImage tmp = new PImage(img.height,img.width);
for (int i = 0; i < img.width; i++){
for (int j = 0; j < img.height; j++){
tmp.pixels[i*img.height + j] = img.pixels[j*img.width + i];
}
}
return tmp;
}
 
PImage flip(PImage img){
PImage tmp = new PImage(img.width,img.height);
for (int i = 0; i < img.width; i++){
for (int j = 0; j < img.height; j++){
tmp.pixels[(img.height - j - 1)*img.width + i] = img.pixels[j*img.width + i];
}
}
return tmp;
}
 
void mousePressed(){
if (mouseButton == RIGHT) jetpack = true;
}
void mouseReleased(){
if (mouseButton == RIGHT) jetpack = false;
}
void nextBottom(){
bakeImage(2,nextPortrait(),1);
 
bakeImage(3,nextLand(),0);
 
bakeImage(4,nextLand(),0);
 
}
 
void nextTop(){
 
bakeImage(0,nextLand(),2);
bakeImage(1,nextLand(),2);
}
 
void bakeImage(int which, PImage pix, int rotation){
PImage nPix = new PImage(pix.width, pix.height);
System.arraycopy(pix.pixels,0,nPix.pixels,0,pix.width*pix.height);
PImage lightmap = maps[which];
PImage dest = (PImage)tracer.baked.elementAt(which);
if (rotation == 1) nPix = rotateCCW(nPix);
if (rotation == 2) nPix = flip(nPix);
nPix.blend(lightmap,0,0,lightmap.width,lightmap.height,0,0,nPix.width,nPix.height,MULTIPLY);
dest.pixels = nPix.pixels;
dest.width = nPix.width;
dest.height = nPix.height;
 
}
 
PImage nextPortrait(){
while(true){
nextPort++;
if (nextPort > numImgs) nextPort = 0;
if (pix[nextPort].height > pix[nextPort].width) return pix[nextPort];
}
 
}
PImage nextLand(){
while(true){
nextImg++;
if (nextImg > numImgs) nextImg = 0;
if (pix[nextImg].height < pix[nextImg].width) return pix[nextImg];
}
 
}