forked from Michel2/LoLshield
395 lines
13 KiB
Arduino
395 lines
13 KiB
Arduino
#include "Charliplexing.h"
|
|
#include "Myfont.h"
|
|
#include <Arduino.h>
|
|
#include <EEPROM.h>
|
|
|
|
int toggleState;
|
|
int EEPROMaddress = 0;
|
|
int charLength = 30;
|
|
unsigned char text[]="Would you like to play a game?";
|
|
|
|
byte brightness = 7;
|
|
|
|
//Game of Life stuff
|
|
#define DELAY 150 //Sets the time each generation is shown
|
|
#define RESEEDRATE 5000 //Sets the rate the world is re-seeded
|
|
#define SIZEX 14 //Sets the X axis size
|
|
#define SIZEY 9 //Sets the Y axis size
|
|
byte world[SIZEX][SIZEY][2]; //Creates a double buffer world
|
|
long density = 50; //Sets density % during seeding
|
|
int geck = 0; //Counter for re-seeding
|
|
|
|
void upToggleState();
|
|
void plasma();
|
|
void life();
|
|
void DNA();
|
|
int neighbours(int x, int y);
|
|
void seedWorld();
|
|
|
|
void setup(){
|
|
toggleState = EEPROM.read(EEPROMaddress);
|
|
upToggleState();
|
|
LedSign::Init(GRAYSCALE);
|
|
|
|
for (int i = toggleState+1; i > 0; i--){
|
|
LedSign::Set(i-1, 0, brightness);
|
|
}
|
|
delay(1000);
|
|
LedSign::Clear(0);
|
|
|
|
}
|
|
|
|
void loop(){
|
|
/*
|
|
0 Plasma
|
|
1 Game of Life
|
|
2 "Would you like to play a game?"
|
|
3 Double Helix
|
|
|
|
*/
|
|
|
|
switch(toggleState){
|
|
case 0:
|
|
plasma();
|
|
break;
|
|
case 1:
|
|
life();
|
|
break;
|
|
case 2:
|
|
Myfont::Banner(charLength,text);
|
|
break;
|
|
case 3:
|
|
DNA();
|
|
break;
|
|
default:
|
|
EEPROM.write(EEPROMaddress, 0);
|
|
}
|
|
}
|
|
|
|
//Ups or resets the state counter
|
|
void upToggleState(){
|
|
toggleState++;
|
|
if (toggleState > 3) toggleState = 0;
|
|
EEPROM.write(EEPROMaddress, toggleState);
|
|
}
|
|
|
|
void plasma(){
|
|
/*
|
|
Plasma
|
|
written by Zach Archer http://zacharcher.com/
|
|
|
|
NOTES:
|
|
- Requires the LoLshield library to run. Get the library here: http://code.google.com/p/lolshield/downloads/
|
|
- How to install the library: http://www.arduino.cc/en/Hacking/Libraries
|
|
|
|
This sketch moves two points along Lissajious curves. See: http://en.wikipedia.org/wiki/Lissajous_curve
|
|
The distances between each LED and each point are multiplied,
|
|
then this value is shaped using a sine function, and this sets the brightness of each LED.
|
|
*/
|
|
|
|
// Convenient 2D point structure
|
|
struct Point {
|
|
float x;
|
|
float y;
|
|
};
|
|
|
|
|
|
|
|
float phase = 0.0;
|
|
float phaseIncrement = 0.08; // Controls the speed of the moving points. Higher == faster. I like 0.08 .
|
|
float colorStretch = 0.11; // Higher numbers will produce tighter color bands. I like 0.11 .
|
|
|
|
|
|
// This function is called every frame.
|
|
while(true) {
|
|
phase += phaseIncrement;
|
|
|
|
// The two points move along Lissajious curves, see: http://en.wikipedia.org/wiki/Lissajous_curve
|
|
// We want values that fit the LED grid: x values between 0..13, y values between 0..8 .
|
|
// The sin() function returns values in the range of -1.0..1.0, so scale these to our desired ranges.
|
|
// The phase value is multiplied by various constants; I chose these semi-randomly, to produce a nice motion.
|
|
Point p1 = {
|
|
(sin(phase*1.000)+1.0) * 7.5, (sin(phase*1.310)+1.0) * 4.0 };
|
|
Point p2 = {
|
|
(sin(phase*1.770)+1.0) * 7.5, (sin(phase*2.865)+1.0) * 4.0 };
|
|
|
|
byte row, col;
|
|
|
|
// For each row...
|
|
for( row=0; row<9; row++ ) {
|
|
float row_f = float(row); // Optimization: Keep a floating point value of the row number, instead of recasting it repeatedly.
|
|
|
|
// For each column...
|
|
for( col=0; col<14; col++ ) {
|
|
float col_f = float(col); // Optimization.
|
|
|
|
// Calculate the distance between this LED, and p1.
|
|
Point dist1 = {
|
|
col_f - p1.x, row_f - p1.y }; // The vector from p1 to this LED.
|
|
float distance = sqrt( dist1.x*dist1.x + dist1.y*dist1.y );
|
|
|
|
// Calculate the distance between this LED, and p2.
|
|
Point dist2 = {
|
|
col_f - p2.x, row_f - p2.y }; // The vector from p2 to this LED.
|
|
// Multiply this with the other distance, this will create weird plasma values :)
|
|
distance *= sqrt( dist2.x*dist2.x + dist2.y*dist2.y );
|
|
//distance += sqrt( dist2.x*dist2.x + dist2.y*dist2.y ); // Variation: weird linear color bands. Might need to increase colorStretch
|
|
|
|
|
|
// Warp the distance with a sin() function. As the distance value increases, the LEDs will get light,dark,light,dark,etc...
|
|
// You can use a cos() for slightly different shading, or experiment with other functions. Go crazy!
|
|
float color_f = (sin( distance * colorStretch ) + 1.0) * 0.5; // range: 0.0...1.0
|
|
|
|
// Square the color_f value to weight it towards 0. The image will be darker and have higher contrast.
|
|
color_f *= color_f;
|
|
//color_f *= color_f*color_f*color_f; // Uncomment this line to make it even darker :)
|
|
|
|
// Scale the color up to 0..7 . Max brightness is 7.
|
|
LedSign::Set( col, row, byte( round(color_f * 7.0) ) );
|
|
}
|
|
}
|
|
// There's so much math happening, it's already a bit slow ;) No need for extra delays!
|
|
//delay( 20 );
|
|
}
|
|
}
|
|
|
|
void DNA(){
|
|
/*
|
|
DoubleHelix
|
|
written by Zach Archer http://zacharcher.com/
|
|
|
|
NOTES:
|
|
- Requires the LoLshield library to run. Get the library here: http://code.google.com/p/lolshield/downloads/
|
|
- How to install the library: http://www.arduino.cc/en/Hacking/Libraries
|
|
|
|
This sketch draws two sine waves with different brightness values.
|
|
The phase of the "darker" sine wave will drift a bit.
|
|
On every other column, LEDs between the sines will be subtly lit (hopefully resembling DNA nucleobases).
|
|
*/
|
|
|
|
// You can tweak these values to create a custom DNA molecule :)
|
|
float stretch = 0.44; // The width of each sine wave. Smaller values create wider sine waves. I like 0.44 .
|
|
|
|
float phaseIncrement = 0.1; // How fast the sines move. I like 0.1 .
|
|
|
|
// The phase of the "darker" sine wave will drift (relative to the "lighter" sine wave).
|
|
// This makes the DoubleHelix more organic/hypnotic .
|
|
float driftIncrement = 0.019; // The speed it drifts back and forth. Larger == faster. I like 0.019 .
|
|
float driftForce = 0.4; // The visual amount of drift. I like 0.4 .
|
|
|
|
// On every other column, light the LEDs between the sine waves, resembling the nucleotides of a DNA molecule.
|
|
// This looks good if we switch between lighting odd columns, then even columns -- the molecule appears to be moving.
|
|
float barPhaseIncrement = 0.09; // Bar movement speed. Plz use values between 0..1 . I like 0.09 .
|
|
|
|
// Brightness values. Range is 0..7
|
|
byte lightSineBrightness = 7;
|
|
byte darkSineBrightness = 3;
|
|
byte barBrightness = 1;
|
|
|
|
// (End tweak section)
|
|
|
|
// These values change every frame:
|
|
float phase = 0.0; // This is how "far" we've travelled along the DNA.
|
|
float driftPhase = 0.0;
|
|
float barPhase = 0.0;
|
|
|
|
// This function is called every frame.
|
|
while(true) {
|
|
phase += phaseIncrement; // Move the sine waves forward.
|
|
|
|
// The "darker" sine wave drifts (relative to the "lighter" sine wave).
|
|
driftPhase += driftIncrement;
|
|
|
|
// Increment the position of the bars.
|
|
barPhase += barPhaseIncrement;
|
|
if( barPhase > 1.0 ) barPhase -= 1.0; // Wrap this value between 0..1 .
|
|
|
|
// We'll hilite either the even columns, or odd columns, depending on the value of barPhase.
|
|
boolean drawEvenBars = (barPhase < 0.5);
|
|
|
|
byte row, col;
|
|
|
|
// For each column of LEDs...
|
|
for( col=0; col<14; col++ ) {
|
|
|
|
// This is the "raw" value for the lighter sine wave. Range: -1.0...1.0
|
|
float lightSineThisColumn = sin( phase + float(col)*stretch );
|
|
|
|
// Scale the "raw" value and round it off, so the range is 0..8 . This is the LED we're going to light in this column.
|
|
int lightSine = int( round( lightSineThisColumn*4.0 ) ) + 4;
|
|
|
|
// driftPhase controls the phase drift of the "darker" sine.
|
|
// The drift amount is derived from this sin() function, so it will drift back and forth.
|
|
// Orbit around 2.1, which is about 1/3 phase offset from the lighter sine wave (2*PI/3). Looks pretty good.
|
|
float drift = 2.1 + (driftForce * sin( driftPhase ));
|
|
|
|
// This is the LED we're going to light for the "dark" sine wave.
|
|
// This is similar to computing the lightSine value, but it's compacted into one line :P
|
|
int darkSine = int( round( sin(phase+drift+float(col)*stretch)*4.0 ) ) + 4;
|
|
|
|
// For each LED within the column...
|
|
for( row=0; row<9; row++ ) {
|
|
|
|
// Does this LED belong to our light sine wave?
|
|
if( row==lightSine ) {
|
|
LedSign::Set( col, row, lightSineBrightness ); // The third argument is the brightness. Max bright == 7.
|
|
|
|
// Does this LED belong to our dark sine wave?
|
|
}
|
|
else if( row==darkSine ) {
|
|
LedSign::Set( col, row, darkSineBrightness ); // The third argument is the brightness.
|
|
|
|
}
|
|
else {
|
|
// This LED doesn't belong to either sine wave. So we'll turn it off, unless it belongs to a vertical bar.
|
|
int color = 0; // 0 == unlit
|
|
|
|
// Alternate even/odd columns:
|
|
// If col is an odd number, (col & 0x1) evaluates to true. (Example: 13 == B1101, rightmost bit is 1, so it's odd!)
|
|
// The ^ operator is binary XOR. So this statement evaluates true if _one_ condition is met, but _not_ both.
|
|
if( (col & 0x1) ^ (drawEvenBars) ) {
|
|
|
|
// If lightSine is above this LED, and darkSine is below, then this LED belongs to a vertical bar.
|
|
if( lightSine < darkSine ) {
|
|
if( lightSine<row && row<darkSine ) {
|
|
color = barBrightness;
|
|
}
|
|
|
|
// If darkSine is above, and lightSine is below, this LED belongs to a vertical bar.
|
|
}
|
|
else if( darkSine < lightSine ) {
|
|
if( darkSine<row && row<lightSine ) {
|
|
color = barBrightness;
|
|
}
|
|
}
|
|
}
|
|
|
|
LedSign::Set( col, row, color );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wait between frames to slow down the animation.
|
|
delay( 20 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void life(){
|
|
/*
|
|
Conway's "Life"
|
|
|
|
Writen for the LoL Shield, designed by Jimmie Rodgers:
|
|
http://jimmieprodgers.com/kits/lolshield/
|
|
|
|
This needs the Charliplexing library, which you can get at the
|
|
LoL Shield project page: http://code.google.com/p/lolshield/
|
|
|
|
Created by Jimmie Rodgers on 12/30/2009.
|
|
Adapted from: http://www.arduino.cc/playground/Main/DirectDriveLEDMatrix
|
|
|
|
History:
|
|
December 30, 2009 - V1.0 first version written at 26C3/Berlin
|
|
|
|
This is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Version 3 General Public
|
|
License as published by the Free Software Foundation;
|
|
or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
//#include <Charliplexing.h> //Imports the library, which needs to be
|
|
//Initialized in setup.
|
|
|
|
|
|
randomSeed(analogRead(5));
|
|
//Builds the world with an initial seed.
|
|
for (int i = 0; i < SIZEX; i++) {
|
|
for (int j = 0; j < SIZEY; j++) {
|
|
if (random(100) < density) {
|
|
world[i][j][0] = 1;
|
|
}
|
|
else {
|
|
world[i][j][0] = 0;
|
|
}
|
|
world[i][j][1] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
while(true) {
|
|
// Birth and death cycle
|
|
for (int x = 0; x < SIZEX; x++) {
|
|
for (int y = 0; y < SIZEY; y++) {
|
|
// Default is for cell to stay the same
|
|
world[x][y][1] = world[x][y][0];
|
|
int count = neighbours(x, y);
|
|
geck++;
|
|
if (count == 3 && world[x][y][0] == 0) {
|
|
// A new cell is born
|
|
world[x][y][1] = 1;
|
|
LedSign::Set(x,y,brightness);
|
|
}
|
|
else if ((count < 2 || count > 3) && world[x][y][0] == 1) {
|
|
// Cell dies
|
|
world[x][y][1] = 0;
|
|
LedSign::Set(x,y,0);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//Counts and then checks for re-seeding
|
|
//Otherwise the display will die out at some point
|
|
geck++;
|
|
if (geck > RESEEDRATE){
|
|
seedWorld();
|
|
geck = 0;
|
|
}
|
|
|
|
// Copy next generation into place
|
|
for (int x = 0; x < SIZEX; x++) {
|
|
for (int y = 0; y < SIZEY; y++) {
|
|
world[x][y][0] = world[x][y][1];
|
|
}
|
|
}
|
|
delay(DELAY);
|
|
}
|
|
|
|
//Re-seeds based off of RESEEDRATE
|
|
|
|
|
|
//Runs the rule checks, including screen wrap
|
|
|
|
}
|
|
void seedWorld(){
|
|
randomSeed(analogRead(5));
|
|
for (int i = 0; i < SIZEX; i++) {
|
|
for (int j = 0; j < SIZEY; j++) {
|
|
if (random(100) < density) {
|
|
world[i][j][1] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
int neighbours(int x, int y) {
|
|
return world[(x + 1) % SIZEX][y][0] +
|
|
world[x][(y + 1) % SIZEY][0] +
|
|
world[(x + SIZEX - 1) % SIZEX][y][0] +
|
|
world[x][(y + SIZEY - 1) % SIZEY][0] +
|
|
world[(x + 1) % SIZEX][(y + 1) % SIZEY][0] +
|
|
world[(x + SIZEX - 1) % SIZEX][(y + 1) % SIZEY][0] +
|
|
world[(x + SIZEX - 1) % SIZEX][(y + SIZEY - 1) % SIZEY][0] +
|
|
world[(x + 1) % SIZEX][(y + SIZEY - 1) % SIZEY][0];
|
|
}
|