import processing.video.*;
//import fullscreen.*;
import processing.opengl.*;
import processing.serial.*;

OffOn offon = new OffOn(25,30,25,00);
Serial myPort;

//SoftFullScreen fs;

PFont fontB;
Capture video1D;
int delayNum = 100;
delaytimecode DTC;
timecode TC;
float[][][] delayArray;
float adjustedBright;
int[][] video2D;
int[][] bright2D;
int numPixels;
float rotation = 0;
float multiplier = 0;
float mode = 0;
float colorVar = 0;
float zZoom = 0;
float tracers = 125;
float interval = 1;
float strokeWeightVar = 1;
boolean pip = true;
float pipScale,pipX,pipY;
int type; //1 means pixels are dots, 2 means pixels are lines etc
int state = 1;
int numStates = 19;
int framesPerState = 1000;
float clock;
float clockSpeed = 1;
float LFO;
float LFOspeed = 1;
float LFOclock;

int readFrame;
int writeFrame = 1;

color currColor;
int currBright;
float brightOut;
float setMidPoint = 117;
float midPoint = 117;

void setup(){
size (640,960, P3D);

noCursor();
String portName = Serial.list()[0];
myPort = new Serial(this,portName,9600);

//fs = new SoftFullScreen(this);
//fs.enter();

TC = new timecode(580,450,270,.75,255,"LCDMonoNormal-48.vlw");
DTC = new delaytimecode(620, 450, 270,1,255,"LCDMonoNormal-48.vlw");
String[] devices = Capture.list();
fontB = loadFont("MyriadPro-SemiboldIt-48.vlw");
println(devices);
println("+,_ contrast//1,2 pixel interval//3,4 pixel size// [,] z-axis multiplier// <,> rotation");
frameRate(30);

video1D = new Capture(this, width, height/2);
video2D = new int [width][height/2];
bright2D = new int [width][height/2];

delayArray = new float [delayNum][width][height/2];
loadPixels();
numPixels = video1D.width * video1D.height;
print(numPixels);

}


void draw(){
pushMatrix();

// strokeWeightVar = interval;
if (video1D.available()) {
video1D.read();
video1D.loadPixels();
background(0);

for (int i = 0; i < 480; i ++){
for (int j = 0; j < width; j ++){

video2D[j][i] = video1D.pixels[i * video1D.width + j];

currBright = int(brightness(video2D[j][i]));

if (currBright >= midPoint){
adjustedBright = map(currBright,midPoint,255,setMidPoint,255);
}
else if(currBright < midPoint){
adjustedBright = map(currBright,0,midPoint,0,setMidPoint);
}
delayArray[writeFrame][j][i] = adjustedBright;

}
}

pushMatrix();
translate (width/2, height/4, zZoom);
rotateY (radians(rotation));
for(int i = 0; i < height/2; i += interval){
for(int j = 0; j < width; j += interval){
brightOut = delayArray[writeFrame][j][i];
stroke(brightOut);
strokeWeight(strokeWeightVar);

switch(type){
case 1:

point (j-width/2, i-height/4, brightOut * multiplier);
break;

case 2:

line(j-width/2, i - height/4, brightOut * multiplier, j-width/2,i-height/4, -brightOut * multiplier);
break;

case 3:
point (j-width/2, i-height/4, brightOut * multiplier - 100);
strokeWeight(strokeWeightVar/2);
point (j-width/2, i-height/4, brightOut * multiplier + 100);
point (j-width/2, i-height/4, brightOut * multiplier );
break;

case 4:
point(j - width/2, i - height/4 - brightOut * multiplier, 0);
break;

case 5:
int J;
if(j - interval > -1){
J = round(j - interval);
}
else{
J = 0;
}
line(j - width/2, i - height/4, currBright * multiplier, j - interval - width/2, i - interval - height/4, delayArray[readFrame][J][i] * multiplier);
break;

case 6:
int Jminus, Jplus;
if(j - interval > -1){
Jminus = round(j - interval);

}
else{
Jminus = 0;
}
if(j + interval < width){
Jplus = int(j + interval);
}
else{
Jplus = width - 1;
}

line(j - width/2, i - height/4, currBright * multiplier, j - interval - width/2, i - interval - height/4, delayArray[readFrame][Jminus][i] * multiplier);
line(j - width/2, i - height/4, currBright * multiplier, j + interval - width/2, i - interval - height/4, delayArray[readFrame][Jplus][i] * multiplier);
break;

case 7:
point (j-width/2 + multiplier, i-height/4, brightOut * multiplier - 100);
strokeWeight(strokeWeightVar/2);
point (j-width/2 + multiplier, i-height/4, brightOut * multiplier + 100);
point (j-width/2 + multiplier, i-height/4, brightOut * multiplier );
break;

case 8:
point(j - width/2 + ((brightOut - 117) * multiplier * sin(radians(3 * clock))),
i - height/4 + ((brightOut - 117) * multiplier * cos(radians(3 * clock))),0);
break;

case 9: // this is a mirror image of case 5
int JJ;
if(j + interval < width - 1){
JJ = round(j + interval);
}
else{
JJ = width -1;
}
line(j - width/2, i - height/4, currBright * multiplier, j + interval - width/2, i - interval - height/4, delayArray[writeFrame][JJ][i] * multiplier);
break;

case 10:
int I;
if(i + interval < height/2){
I = int(i + interval);
}
else{
I = height/2 - 1;
}
line(j - width/2, i - height/4, currBright * multiplier, j - width/2, i - height/4 + interval, delayArray[writeFrame][j][I] * multiplier);
break;

case 11:
if(j + interval < width){
J = int(j + interval);
}
else{
J = width - 1;
}
line(j - width/2, i - height/4, currBright * multiplier, j - width/2 + interval, i - height/4, delayArray[readFrame][J][i] * multiplier);
break;

case 12:

point (j - width/2, i - height/4, 0);
fill(brightOut, 75);
point (j - width/2, i - height/4, 30);
fill(brightOut, 50);
point (j - width/2, i - height/4, 60);
fill(brightOut, 25);
point (j - width/2, i - height/4, 90);
break;

case 13:
stroke(255 - brightOut);
point (j - width/2, i - height/4, brightOut * multiplier);
break;
}///////
}

}
popMatrix();
}

/* pushMatrix();
if(pip == true){
translate(pipX,pipY);
scale(.3,.15);
image(video1D, 1500,0);
}
popMatrix(); */

writeFrame = (writeFrame + 1)%delayNum;
readFrame = (writeFrame + (delayNum + 1)) % delayNum;
println("writeFrame = " + writeFrame + " readFrame = " + readFrame);

TC.update();
DTC.update();

clock += 1;
state = floor(clock/framesPerState) % numStates;
LFOclock += LFOspeed;
LFO = sin(radians(LFOclock));
//println(LFO);

switch (state){
case 0:
pip = false;
multiplier = .5 * LFO;
strokeWeightVar = 1;
rotation = LFO * 45;
type = 2;
interval = 6;
break;

case 1:
type = 4;
interval = 3;
strokeWeightVar = 2;
multiplier = LFO * 1.5;
break;

case 2:
type = 6;
multiplier = LFO;
interval = 5;
strokeWeightVar = 2;
LFOspeed = .5;
println(LFO);
break;

case 3:
multiplier = LFO * .5;
rotation = LFO * 30;
type = 3;
strokeWeightVar = (LFO *2) + 5;
pip = false;
break;

case 4:
rotation = LFO * 30;
LFOspeed = 1;
clockSpeed = .5;
type = 7;
strokeWeightVar = (LFO*2) + 5;
multiplier = LFO * 1;
break;

case 5:

type = 4;
strokeWeightVar = LFO * 3 + 4;
interval = 8;
break;

case 6:
interval = 12;
rotation = 0;
strokeWeightVar = 5;
type = 5;
break;

case 7: //a mirror image sort of of case 6
type = 9;
break;

case 8:
type = 10;
multiplier = LFO;
strokeWeightVar = 3;
interval = 8;
rotation = LFO * 25;
break;

case 9:// this one is a pair with case 8;
type = 11;
multiplier = LFO;
break;

case 10:
type = 8;
LFOspeed = 3;
rotation = LFO * 10;
multiplier = LFO;
break;

case 11:
type = 1;
LFOspeed = 1;
multiplier = 0;
interval = strokeWeightVar = 3;
break;

case 12:
type = 1;
interval = LFO * 3 + 4;
strokeWeightVar = 4 - LFO * 3;
pip = false;
break;

case 13:
type = 1;

interval = 20;
strokeWeightVar = 14;
break;

case 14:
type = 1;
interval = 30;
strokeWeightVar = 26;
break;

case 15:
pip = false;
type = 1;
multiplier = 0;
interval = strokeWeightVar = 2;
break;

case 16:
type = 6;
interval = 25;
strokeWeightVar = 10;
rotation = LFO * 26;
multiplier = LFO;
break;

case 17:
type = 12;
interval = 6;
strokeWeightVar = 2;
rotation = 0;
break;

case 18:
// pip = true;
strokeWeightVar = 4;
type = 13;
multiplier = LFO;
break;

}

println("state = " + state + " type = " + type);

//image(video1D,0,height/2);

popMatrix();
/*
pushMatrix();
translate(0,height/2);
scale(1,.5);

image(video1D,0,0);
popMatrix();
*/
for(int k = 0; k < height/2; k += 1){
for(int l = 0; l < width; l += 1){
pushMatrix();
stroke(delayArray[readFrame][l][k]);
translate(0,height/2);
//scale(1,.75);
point(l,k);
popMatrix();
//println(delayArray[readFrame][l][k]);
}
}


pushMatrix(); //second set of timecodes
translate(0,480);
TC.update();
DTC.update();
popMatrix();
offon.update();

}

//for use with read_from_computer_serial

class OffOn{
int onMin, onHour, offMin, offHour, prevMin;
OffOn(int a, int b, int c, int d){
onHour = a;
onMin = b;
offHour = c;
offMin = d;
}
void update(){
if(prevMin != minute()){

if(onMin == minute()){
if (onHour == hour()){
println("ON");
myPort.write('H');
delay(100);
myPort.write('L');
}
}


if(offHour == hour()){
if(offMin == minute()){

myPort.write('H');
delay(100);
myPort.write('L');
delay(500);
myPort.write('H');
delay(100);
myPort.write('L');
println("OFF");
}
}
}
prevMin = minute();

}
}

void keyPressed(){
textFont(fontB);
if (key == '1'){
interval += 1;
print("interval = " + interval + " ");
text("interval",100, 100);
text(round(interval),100,200);
}
if (key == '2'){
if (interval > 1){
interval -= 1;
print(" interval = " + interval + " ");
text("interval",100, 100);
text(round(interval),100,200);

}
else{
interval = 1;
text("interval",100, 100);
text(round(interval),100,200);
}
}

if (key == '3'){
if (strokeWeightVar > 1){
strokeWeightVar -= 1;
text("strokeWeight",100, 100);
text(round(strokeWeightVar),100,200);
}
else{
strokeWeightVar = 1;
text("strokeWeight",100, 100);
text(round(strokeWeightVar),100,200);

}
}
if (key == '4'){
strokeWeightVar += 1;
text("strokeWeight",100, 100);
text(round(strokeWeightVar),100,200);
}

if(key == '='){
setMidPoint += 1;
text("setMidPoint",100, 100);
text(setMidPoint,100,200);
}
if(key == '-'){
setMidPoint -= 1;
text("setMidPoint",100, 100);
text(setMidPoint,100,200);
};
if(key == ']'){
multiplier += .05;
text("multiplier",100, 100);
text(multiplier,100,200);
}
if(key == '['){
multiplier -= .05;
text("multiplier",100, 100);
text(multiplier,100,200);
}
if(key == ','){
rotation += .5;
text("rotation",100, 100);
text(rotation,100,200);
}
if(key == '.'){
rotation -= .5;
text("rotation",100, 100);
text(rotation,100,200);
}
if(key == '/'){
clock += framesPerState;
}
}

class timecode{
String[] time = new String[6];
float rotateVar, Xpos, Ypos, scaleVar;
String timeString;
String fontName;
String HH, MM, DD;
int fillVar;


PFont fontA = loadFont("LCDMonoNormal-48.vlw");
timecode(float X, float Y,float r,float s, int fv, String fn){
rotateVar = radians(r);
Xpos = X;
Ypos = Y;
scaleVar = s;
fillVar = fv;
fontName = fn;
}

void update(){
pushMatrix();
translate(Xpos,Ypos);
rotate(rotateVar);
scale(scaleVar);
fill (fillVar);
textFont(fontA,48);
if(hour() < 10){
time[0] = "0";
}else{
time[0] = "";
}
time[1] = str(hour());
if(minute() < 10){
time[2] = ":0";
}else{
time[2] = ":";
}
time[3] = str(minute());
if(second() < 10){
time[4] = ":0";
}else{
time[4] = ":";
}
time[5] = str(second());
timeString = join(time,"");
text(timeString, 0, 0);
popMatrix();
}

}

 

class delaytimecode{
String[] time = new String[6];
float rotateVar, Xpos, Ypos, scaleVar;
String timeString;
String fontName;
String HH, MM, DD;
int fillVar;
int[] displayArray = new int[3];
int[][] delayTimeArray = new int[delayNum][3];

PFont fontA = loadFont("LCDMonoNormal-48.vlw");


delaytimecode(float X, float Y,float r,float s, int fv, String fn){
rotateVar = radians(r);
Xpos = X;
Ypos = Y;
scaleVar = s;
fillVar = fv;
fontName = fn;
}






void update(){
//println(delayTimeArray);
//readFrame = ((writeFrame + delayNum + 5) % delayNum);

delayTimeArray[writeFrame][0] = hour();
delayTimeArray[writeFrame][1] = minute();
delayTimeArray[writeFrame][2] = second();




pushMatrix();
translate(Xpos,Ypos);
rotate(rotateVar);
scale(scaleVar);
fill (fillVar);
textFont(fontA,48);
if(delayTimeArray[readFrame][0] < 10){
time[0] = "0";
}else{
time[0] = "";
}
time[1] = str(delayTimeArray[readFrame][0]);
if(delayTimeArray[readFrame][1] < 10){
time[2] = ":0";
}else{
time[2] = ":";
}
time[3] = str(delayTimeArray[readFrame][1]);
if(delayTimeArray[readFrame][2] < 10){
time[4] = ":0";
}else{
time[4] = ":";
}
time[5] = str(delayTimeArray[readFrame][2]);
timeString = join(time,"");
text(timeString, 0, 0);
popMatrix();

}

}