//created=7 Nov 07
//description=In scene texture baking in the presence of dynamic lighting.
//title=Shadow Baking
//titlebar=Just in Time Texture Baking
//publish=true
 
import SGGUI.*;
import SGCamera.*;
import Raytracing.*;
import Tuple.*;
 
SGCamera cam;
Raytracer tracer;
 
SGGUI controller;
VerticalLayout settings;
PFont fnt;
 
SGSlider lx,ly,lz,res, soft, lightSamples;
SGButton update;
 
Lamp light;
 
float mu=.2,mv=.2;
 
Ray isect = new Ray(60,0,60, random(-1,0), random(-1,0), random(-1,0));
 
 
Triangle bob;
SolidShader redShader = new SolidShader(0,255,0,0);
 
 
int renderObject = 100;
void setup(){
 
size(550,550,P3D);
fnt = loadFont("writing.vlw");
textFont(fnt);
textMode(SCREEN);
controller = new SGGUI(this,fnt);
//controller.GUI_HIGHLIGHT = color(200,220,200);
settings = new VerticalLayout(controller,10,10,150);
settings.title = "Controls";
lx = new SGSlider( "Lamp X",20,1,-50,50);
ly = new SGSlider( "Lamp Y",-80,1,-200,0);
lz = new SGSlider( "Lamp Z",0,1,-50,50);
res = new SGSlider( "Resolution",100,5,50,300);
soft = new SGSlider( "Soft",0,1,0,10);
lightSamples= new SGSlider( "lightSamples",1,1,1,16);
update = new SGButton("Bake Textures");
update.addGUIListener(this);
 
settings.add(lx);
settings.add(ly);
settings.add(lz);
settings.add(res);
settings.add(soft);
settings.add(lightSamples);
settings.add(update);
 
controller.add(settings);
 
tracer = new Raytracer(this);
 
cam = new SGCamera(this,100,-50,100,0,0,0);
cam.setMouseMode(LEFT,SGCamera.ORBIT);
cam.setMouseMode(RIGHT,SGCamera.DOLLY);
 
tracer.openFile("bake.mra",cam);
cam.lookAt(0,0,0);
 
light = new Lamp(new Tuple3f(-300,-900,200),0);
 
 
 
}
 
 
public void texturizeTri(Triangle tri){
float cu=0,cv=0;
 
tri.texture=new PImage((int)res.getVal(),(int)res.getVal());
 
int wide = tri.texture.width;
float step = .99f/wide;
Ray lightRay = new Ray();
int count = 0;
while(cv < 1.1){
count++;
float b = 1.0f-cu-cv;
int tu = (int)(tri.texture.height*(tri.u0*b + tri.u1*cu + tri.u2*cv));
int tv = (int)(wide*(tri.v0*b + tri.v1*cu + tri.v2*cv));
lightRay.origin = tri.getPoint(cu,cv);
Tuple3f lightOrigin;
///Tuple3f accum = new Tuple3f(0,0,0);
int accum = 0;
//do this multiple times for each light
for (int i=0; i < lightSamples.getVal(); i++){
lightOrigin = light.origin.getCopy();
light.origin.x += 10*soft.getVal()*random(-1,1);
light.origin.y += 10*soft.getVal()*random(-1,1);
light.origin.z += 10*soft.getVal()*random(-1,1);
light.getSample(lightRay,null);
light.origin = lightOrigin;
lightRay.minDist = .001f;
if (tracer.accelerator.findNearest(lightRay)){
try{
//tri.texture.pixels[tv*wide + tu] = color(0);
}catch(Exception e){};
}
else{
//get cos of angle between light
float k = abs(lightRay.direction.dot(tri.gNormal));
try{
//tri.texture.pixels[tv*wide + tu] = color(k*255);
accum += k*255;
}catch(Exception e){}
}
}
//accum.divideEquals(lightSamples.getVal());
accum /= lightSamples.getVal();
//println(accum + tv + ":" + tu + ":" + wide);
try{
tri.texture.pixels[tv*wide + tu] = color(accum);
}catch(Exception e){}
cu +=step;
if (cu + cv > 1.1f){
cu = -.1;
cv += step;
}
}
 
}
 
 
public void draw(){
 
light.origin.x =10*lx.getVal();
light.origin.y =10*ly.getVal();
light.origin.z =10*lz.getVal();
 
 
lights();
background(32,32,40);
cam.feed();
tracer.draw();
fill(200);
noStroke();
translate(light.origin.x,light.origin.y,light.origin.z);
sphere(5 + 5*soft.getVal());
 
}
 
void GUIEventPerformed(GUIEvent e){
TextureThread thread1 = new TextureThread();
thread1.start();
 
}
 
public class TextureThread extends Thread {
 
 
// We must implement run, this gets triggered by start()
public void run ()
{
Triangle tri;
Accelerator bob = (Accelerator) tracer.accelerator;
for (int i =0; i < bob.objects.size(); i++){
 
tri = (Triangle)bob.objects.elementAt(i);
texturizeTri(tri);
//println("Baking " + i + " of " + bob.objects.size() + " with area:" + tri.area);
update.title = "progress: " + 100*(float)i/bob.objects.size() + "%";
 
}
update.title = "Bake Textures";
}
 
}