Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Disorient Art Car Wash sign / Want It! matrix display emulator
==============================================================

See: [Art Car Wash sign documentation](http://wiki.disorient.info/index.php?title=ACW_Sign)

See: [Want It! matrix display](http://www.labradoc.com/i/myelin/p/25x12-networked-led-matrix-display)

Usage
-----

- Install all dependencies into your sketchbook/libraries folder
- Uncomment the Disorient or Want It! settings in acw_emulator.pde
- Run acw_emulator
- Run acw

Dependencies
------------

- hypermedia.net UDP library: http://www.ubaa.net/shared/processing/udp/
119 changes: 67 additions & 52 deletions Dacwes_Emulator.pde → acw_emulator.pde
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import hypermedia.net.*;
/**
* This sketch emulates the Disorient Art Car Wash Electronic Sign
* At Burning Man 2010. The sign is a 64' x 16' 32x8 pixel grid.
* Uncomment the Want It! matrix display settings section to emulate
* a 25 x 12 RGB sign instead.
*
* Listens on port 58082 for UDP packets. Packet is expected
* to start with 1, followed by 256 bytes. I believe the 1
* to start with 1, followed by 256 bytes. I believe the 1
* signifies a new frame, but this emulator just expects 257
* bytes.
*
Expand All @@ -15,6 +17,7 @@ import hypermedia.net.*;
* emulator.
*
* (c)2010 Justin Day
* Want It! matrix support (c)2012 Phillip Pearson
*
* You may use under a CC+Attribution License.
*
Expand All @@ -26,7 +29,7 @@ import hypermedia.net.*;
int Y_AXIS = 1;
int X_AXIS = 2;

// These are the addressing schemes, which vary with how the sign is constructed.
// These are the addressing schemes, which vary with how the sign is constructed.
// The comments are describing how the pixel addresses are laid out in order. Keep
// in mind that if the sign is in vertical mode that the pixels go from top to bottom
// not left to right. The comments assume the pixels per channel are 8.
Expand All @@ -36,12 +39,24 @@ int ADDRESSING_HALF = 3; // 0-7, 128-135, 8-15, 136-143...

// Configuration
int PIXELS_PER_CHANNEL = 8;
int ADDRESSING = ADDRESSING_FLIPFLOP;
int HEIGHT = 16;
int WIDTH = 16;
int BOARD_SPACING = 20;
int CHANNEL_SPACING = 20;

// Want It! matrix display settings
int ADDRESSING = ADDRESSING_NORMAL;
int WIDTH = 25;
int HEIGHT = 12;
boolean isRGB = true;
boolean VERTICAL = false; // set to false when panels are mounted horizontally

/*
// Disorient ACW settings
int ADDRESSING = ADDRESSING_FLIPFLOP;
int WIDTH = 16;
int HEIGHT = 16;
boolean isRGB = true;
boolean VERTICAL = true; // set to false when panels are mounted horizontally
*/

// privates
UDP udp;
Expand All @@ -61,15 +76,15 @@ void setup() {
left = 360 - (WIDTH * (BOARD_SPACING/2));
top = 360 - (HEIGHT * CHANNEL_SPACING);
}


udp = new UDP( this, 58082 );
udp.listen( true );

// Sign is 64' (10 pixels per foot plus buffer)
// By 16' (Lots more buffer)
// By 16' (Lots more buffer)
size(720,480);

paintBackground();
paintSign();
initState();
Expand All @@ -79,7 +94,7 @@ void setup() {

void paintBackground() {
color sky1, sky2, sky3;

if (nightMode) {
sky1 = color(0,0,0);
sky2 = color(0,0,50);
Expand All @@ -92,12 +107,12 @@ void paintBackground() {
}
color ply1 = color(30,10,10);
color ply2 = color(130,100,100);

setGradient(0,0,720,100,sky1,sky2,Y_AXIS);
fill(sky2); noStroke(); rect(0,100,720,80);
setGradient(0,180,720,140,sky2,sky3,Y_AXIS);
setGradient(0,320,720,160,ply1,ply2,Y_AXIS);

if (nightMode) {
for (int i=0; i<100; i++) {
int x = (int)random(720);
Expand All @@ -106,40 +121,26 @@ void paintBackground() {
rect(x,y,2,2);
}
}

}

void paintSign() {
noFill();
fill(0);
stroke(0);

if (VERTICAL)
{
rect(left,top,WIDTH*CHANNEL_SPACING,HEIGHT*BOARD_SPACING);
}
else
{
rect(left,top,WIDTH*BOARD_SPACING,HEIGHT*CHANNEL_SPACING);
}

fill(nightMode ? 50 : 150);
if (VERTICAL)
{
for (int i=0; i<WIDTH; i++) {
rect(left+i*CHANNEL_SPACING+(CHANNEL_SPACING/2),top,6,HEIGHT*BOARD_SPACING);
}
}
else
{
for (int i=0; i<HEIGHT; i++) {
rect(left,top+i*CHANNEL_SPACING+(CHANNEL_SPACING/2),WIDTH*BOARD_SPACING,6);
}
rect(left,top,WIDTH*BOARD_SPACING+BOARD_SPACING/3,HEIGHT*CHANNEL_SPACING+CHANNEL_SPACING/3);
}
}

void initState() {
state = new int[256];
for (int i=0; i<256; i++) {
state = new int[(isRGB ? 3 : 1) * WIDTH * HEIGHT];
for (int i=0; i<WIDTH*HEIGHT; i++) {
state[i] = 0;
}
}
Expand Down Expand Up @@ -180,8 +181,8 @@ int getAddress(int x, int y) {
return (y * HEIGHT + x);
}
}
}
}

return 0;
}

Expand All @@ -192,10 +193,14 @@ void paintBoards() {
int i;
for (int y=0; y<HEIGHT; y++) {
for (int x=0; x<WIDTH; x++) {
i = getAddress(x,y);

fill(state[i], state[i]/255.0*100, 0);

i = getAddress(x,y) * (isRGB ? 3 : 1);

if (isRGB) {
fill(state[i], state[i+1], state[i+2]);
} else {
fill(state[i], state[i]/255.0*100, 0);
}

// FIXME
if (VERTICAL) {
rect(x*CHANNEL_SPACING+left+(CHANNEL_SPACING/2),y*BOARD_SPACING+top+(BOARD_SPACING/2),7,6);
Expand All @@ -210,24 +215,34 @@ void paintBoards() {
void runDemo() {
if (crawl == -1 && state[0] < 255) {
for (int i=0; i<WIDTH*HEIGHT; i++) {
state[i]+=8;
if (isRGB) {
state[3 * i] += 8;
state[3 * i + 1] += 8;
state[3 * i + 2] += 8;
} else {
state[i]+=8;
}
}
}
else {
crawl++;
for (int i=0; i<WIDTH*HEIGHT; i++) {
state[i] = (crawl == i) ? 255 : 0;
if (isRGB) {
state[3 * i] = state[3 * i + 1] = state[3 * i + 2] = (crawl == i) ? 255 : 0;
} else {
state[i] = (crawl == i) ? 255 : 0;
}
}
if (crawl>=WIDTH*HEIGHT)
crawl = -1;
}
}
}

void draw () {
if (demoMode) {
runDemo();
}

paintBoards();
}

Expand All @@ -236,27 +251,27 @@ void receive(byte[] data, String ip, int port) {
println("Started receiving data from " + ip + ". Demo mode disabled.");
demoMode = false;
}

if (data[0] == 1) {
if (data.length < 257) {
println("Packet size mismatch. Expected 257, got " + data.length);
}

for (int i=1; i<data.length; i++) {
state[i-1] = convertByte(data[i]);
}
}
else {
println("Packet header mismatch. Expected 1, got " + data[0]);
}
}
}

int convertByte(byte b) {
return (b<0) ? 256+b : b;
}

void setGradient(int x, int y, float w, float h, color c1, color c2, int axis ){
// calculate differences between color components
// calculate differences between color components
float deltaR = red(c2)-red(c1);
float deltaG = green(c2)-green(c1);
float deltaB = blue(c2)-blue(c1);
Expand All @@ -272,25 +287,25 @@ void setGradient(int x, int y, float w, float h, color c1, color c2, int axis ){
color c = color(
(red(c1)+(j-y)*(deltaR/h)),
(green(c1)+(j-y)*(deltaG/h)),
(blue(c1)+(j-y)*(deltaB/h))
(blue(c1)+(j-y)*(deltaB/h))
);
set(i, j, c);
}
}
}
}
}
else if(axis == X_AXIS){
// column
// column
for (int i=y; i<=(y+h); i++){
// row
for (int j = x; j<=(x+w); j++){
color c = color(
(red(c1)+(j-x)*(deltaR/h)),
(green(c1)+(j-x)*(deltaG/h)),
(blue(c1)+(j-x)*(deltaB/h))
(blue(c1)+(j-x)*(deltaB/h))
);
set(j, i, c);
}
}
}
}
}