import processing.serial.*;
import java.awt.Rectangle;
float gamma = 1.7;
int numPorts=0; // the number of serial ports in use
int maxPorts=24; // maximum number of serial ports
PImage img; // Declare variable "a" of type PImage
PImage shot;
float x; // horizontal location of headline
XML xml;
String[] headlines;
int index = 0;
Serial[] ledSerial = new Serial[maxPorts]; // each port's actual Serial port
Rectangle[] ledArea = new Rectangle[maxPorts]; // the area of the movie each port gets, in % (0-100)
boolean[] ledLayout = new boolean[maxPorts]; // layout of rows, true = even is left->right
PImage[] ledImage = new PImage[maxPorts]; // image sent to each port
int[] gammatable = new int[256];
int errorCount=0;
String[] strLines;
void setup() {
String[] list = Serial.list();
delay(20);
println("Serial Ports List:");
println(list);
serialConfigure("COM4"); // change these to your port names
if (errorCount > 0) exit();
for (int i=0; i < 256; i++) {
gammatable[i] = (int)(pow((float)i / 255.0, gamma) * 255.0 + 0.5);
}
size(480, 400); // create the window
strLines = loadStrings("C:/Documents and Settings/alissa/Desktop/positions2.txt");
x = width;
// The image file must be in the data folder of the current sketch
// to load successfully
img = loadImage("test.JPG"); // Load the image into the program
// The URL for the XML document
String url = "http://news.google.com/news?cf=all&hl=en&pz=1&ned=us&output=rss";
// Load the XML document
xml = loadXML(url);
// Grab the element we want
XML[] headers = xml.getChildren("channel/item/title");
headlines = new String[headers.length];
for (int i = 0; i < headers.length; i++) {
headlines[i] = headers[i].getContent();
}
}
// image2data converts an image to OctoWS2811's raw data format.
// The number of vertical pixels in the image must be a multiple
// of 8. The data array must be the proper size for the image.
void image2data(PImage image, byte[] data) {
int offset = 3;
int i, j, counter, mask;
int pixel[] = new int[8];
for (i = 0; i < strLines.length/8; i++) {
for (j = 0; j < 8; j++) {
pixel[j] = image.pixels[int(strLines[i * 8 + j])];
pixel[j] = colorWiring(pixel[j]);
}
// convert 8 pixels to 24 bytes this is it
for (mask = 0x800000; mask != 0; mask >>= 1) {
byte b = 0;
for (j=0; j < 8; j++) {
if ((pixel[j] & mask) != 0) b |= (1 << j);
}
data[offset++] = b;
}
}
}
// translate the 24 bit color from RGB to the actual
// order used by the LED wiring. GRB is the most common.
int colorWiring(int c) {
int green = (c & 0xFF0000) >> 16;
int red = (c & 0x00FF00) >> 8;
int blue = (c & 0x0000FF);
red = gammatable[red/16];
green = gammatable[green/16];
blue = gammatable[blue/16];
return (green << 16) | (red << 8) | (blue); // GRB - most common wiring
}
// ask a Teensy board for its LED configuration, and set up the info for it.
void serialConfigure(String portName) {
if (numPorts >= maxPorts) {
println("too many serial ports, please increase maxPorts");
errorCount++;
return;
}
try {
ledSerial[numPorts] = new Serial(this, portName);
if (ledSerial[numPorts] == null) throw new NullPointerException();
ledSerial[numPorts].write('?');
} catch (Throwable e) {
println("Serial port " + portName + " does not exist or is non-functional");
errorCount++;
return;
}
delay(50);
String line = ledSerial[numPorts].readStringUntil(10);
if (line == null) {
println("Serial port " + portName + " is not responding.");
println("Is it really a Teensy 3.0 running VideoDisplay?");
errorCount++;
return;
}
String param[] = line.split(",");
if (param.length != 12) {
println("Error: port " + portName + " did not respond to LED config query");
errorCount++;
return;
}
// only store the info and increase numPorts if Teensy responds properly
ledImage[numPorts] = new PImage(Integer.parseInt(param[0]), Integer.parseInt(param[1]), RGB);
ledArea[numPorts] = new Rectangle(Integer.parseInt(param[5]), Integer.parseInt(param[6]),
Integer.parseInt(param[7]), Integer.parseInt(param[8]));
ledLayout[numPorts] = (Integer.parseInt(param[5]) == 0);
numPorts++;
}
void draw() {
// Displays the image in same size as window at point (0,0)
image(img, 0, 0, 480, 400);
textSize(100);
fill(255,255,255);
text(headlines[index], x, 170);
x = x - 10;
float w = textWidth(headlines[index]);
if (x < -w) {
x = width;
index = (index + 1) % headlines.length;
}
if (keyPressed) {
if (key == 'x') {
clear();
} else {
//draw a bunch of squares below the pic
loadPixels();
for (int i=0; i < strLines.length; i++) {
pixels[int(strLines[i])] = color(0, 0, 0);
}
updatePixels();
}
}
for (int i=0; i < numPorts; i++) {
// copy a portion of the movie's image to the LED image
int xoffset = percentage(width, ledArea[i].x);
int yoffset = percentage(height, ledArea[i].y);
int xwidth = percentage(width, ledArea[i].width);
int yheight = percentage(height, ledArea[i].height);
//rect(10, 75, 10, 10);
//shot = get(10, 75, 10, 10);
shot = get(0, 0, width, height);
//ledImage[i].copy(shot, xoffset, yoffset, xwidth, yheight,
// 0, 0, xwidth, yheight);
ledImage[i] = shot;
// convert the LED image to raw data
byte[] ledData = new byte[(ledImage[i].width * ledImage[i].height * 3) + 3];
image2data(ledImage[i], ledData);
if (i == 0) {
ledData[0] = '*'; // first Teensy is the frame sync master
int usec = (int)((1000000.0 / 30) * 0.75);
ledData[1] = (byte)(usec); // request the frame sync pulse
ledData[2] = (byte)(usec >> 8); // at 75% of the frame time
} else {
ledData[0] = '%'; // others sync to the master board
ledData[1] = 0;
ledData[2] = 0;
}
// send the raw data to the LEDs :-)
ledSerial[i].write(ledData);
}
if (keyPressed) {
if (key == 'x') {
exit();
}
}
}
// scale a number by a percentage, from 0 to 100
int percentage(int num, int percent) {
double mult = percentageFloat(percent);
double output = num * mult;
return (int)output;
}
// scale a number by the inverse of a percentage, from 0 to 100
int percentageInverse(int num, int percent) {
double div = percentageFloat(percent);
double output = num / div;
return (int)output;
}
// convert an integer from 0 to 100 to a float percentage
// from 0.0 to 1.0. Special cases for 1/3, 1/6, 1/7, etc
// are handled automatically to fix integer rounding.
double percentageFloat(int percent) {
if (percent == 33) return 1.0 / 3.0;
if (percent == 17) return 1.0 / 6.0;
if (percent == 14) return 1.0 / 7.0;
if (percent == 13) return 1.0 / 8.0;
if (percent == 11) return 1.0 / 9.0;
if (percent == 9) return 1.0 / 11.0;
if (percent == 8) return 1.0 / 12.0;
return (double)percent / 100.0;
}