// CA_3D_1
// 2D Cellular automaton in a 3D space
// 3 lamps hover around randomly
// mouse changes the camera angle, click to reinitialize the CA
//
int ROWS=30;
int COLS=30;
int BOXSIZE=6;
int map[][]=new int[ROWS*COLS][2];
int id[]={0,1,0};
int rule=513;
float camY=0;
float aX,aY;
boolean running=true;
Light lamps[]=new Light[3];
void setup() {
size(400,400);
background(0,0,0);
fill(#FFFFFF);
lights();
g.lightR[0] = 0.1f;
g.lightG[0] = 0.1f;
g.lightB[0] = 0.1f;
g.lightKind[1] = DIFFUSE;
g.lightR[1] = 1f;
g.lightG[1] = 0f;
g.lightB[1] = 0f;
g.lightKind[2] = DIFFUSE;
g.lightR[2] = 1.0f;
g.lightG[2] = 1.0f;
g.lightB[2] = 0.0f;
g.lightKind[3] = DIFFUSE;
g.lightR[3] = 1.0f;
g.lightG[3] = 0.5f;
g.lightB[3] = 0.0f;
for(int i=0;i<3;i++) {
lamps[i]=new Light(i+1);
}
aX=aY=0;
noStroke();
initCA();
}
void loop() {
beginCamera();
perspective(60.0, (float) width / (float) height, 1.0, 1000.0);
translate(0.0, 0.0, -200);
rotateX(-aX*0.01);
rotateY(-aY*0.01);
endCamera();
for(int i=0;i<3;i++) {
lamps[i].run();
}
aY+=(mouseX-aY)*0.2;
aX+=(mouseY-aX)*0.2;
if (mousePressed) { initCA(); }
if(running) runCA();
fill(#FFFFFF);
for(int i=0; i<COLS;i++) {
for(int j=0; j<ROWS;j++) {
push();
translate(i*BOXSIZE-COLS*BOXSIZE/2, j*BOXSIZE-ROWS*BOXSIZE/2,0);
if (map[i+j*COLS][0]==1) box(BOXSIZE);
pop();
}
}
}
void initCA () {
for (int i=0; i<(COLS*ROWS); i++) {
if (random(10)>5) map[i][0]=1;
else map[i][0]=0;
}
running=true;
}
void runCA()
{
for(int t=0;t<2;t++) {
// For each cell in the grid
for(int i=0; i<COLS; i++) {
for(int j=0; j<ROWS; j++) {
// Wrap around offsets
int right=(i+1) % COLS;
int bottom=(j+1) % ROWS;
int left=i-1; if (left==-1) left=COLS-1;
int top=j-1; if (top==-1) top=ROWS-1;
// Calculate the sum of 9 neighbors
int sum=0;
sum+=map[left+j*COLS][0]; // left middle
sum+=map[left+top*COLS][0]; // left top
sum+=map[left+bottom*COLS][0]; // left bottom
sum+=map[right+j*COLS][0]; // right middle
sum+=map[right+top*COLS][0]; // right top
sum+=map[right+bottom*COLS][0]; // right bottom
sum+=map[i+j*COLS][0]; // middle middle
sum+=map[i+top*COLS][0]; // middle top
sum+=map[i+bottom*COLS][0]; // middle bottom
// Update the copy of the map
if ((rule & (1<<sum)) >0) map[i+j*COLS][1]=1;
else map[i+j*COLS][1]=0;
}
}
// Transfer copy to map
for (int i=0; i<(COLS*ROWS); i++) {
map[i][0]=map[i][1];
}
}
int xsum=0;
for (int i=0; i<(COLS*ROWS); i++) {
xsum+=map[i][0];
}
id[2]=id[1];
id[1]=id[0];
id[0]=xsum;
if ( (id[0]==0) || (id[1]>=COLS*ROWS)) initCA();
if ((id[0]==id[1]) && (id[1]==id[2])) { running=false; }
}
class Light {
float f1,f2,f3,f4,f5,f6; // sine waves frequencies
float p1,p2,p3,p4,p5,p6; // sine waves phases
float t; // clock
int lightID;
Light(int id) {
lightID=id;
f1=random(0.5)+0.1;
f2=random(0.5)+0.1;
f3=random(0.5)+0.1;
f4=random(0.5)+0.1;
f5=random(0.5)+0.1;
f6=random(0.5)+0.1;
p1=random(PI);
p2=random(PI);
p3=random(PI);
p4=random(PI);
p5=random(PI);
p6=random(PI);
}
void run() {
g.lightX[lightID]=sin(f1*t+p1)*sin(f2*t+p2)*100.0f;
g.lightY[lightID]=sin(f3*t+p3)*sin(f4*t+p4)*100.0f;
g.lightZ[lightID]=sin(f5*t+p5)*sin(f6*t+p6)*100.0f+150;
t+=0.1;
}
}