Skip to content

Instantly share code, notes, and snippets.

@rkbenton
Created February 10, 2014 23:03
Show Gist options
  • Save rkbenton/8926010 to your computer and use it in GitHub Desktop.
Save rkbenton/8926010 to your computer and use it in GitHub Desktop.
/*
(This is an implementation of the Modified BSD License. This version allows unlimited
redistribution for any purpose as long as its copyright notices and the license's
disclaimers of warranty are maintained. The license also contains a clause restricting
use of the names of contributors for endorsement of a derived work without specific
permission.)
Copyright (c) 2013-2014, Rebecca K. Benton
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Notes:
o This is a quick-and-dirty program writte to play with Digistump's
Digispark USB Development Board (http://digistump.com/products/1)
o It can be compiled using Visual Studio (or any other advanced IDE)
be including a #define WIN32. If not def'd, it can be compiled in
the special Arduino IDE provided by Digistump
o This is /not/ an indication of my mode of programming; this was a
quick, fun side-project that was for experimentation, not for any
sort of long-lived development
*/
#include <DigisparkRGB.h>
byte RED = 0;
byte BLUE = 2;
byte GREEN = 1;
// == aColor ========================================================
// def
struct aColor {
byte r;
byte g;
byte b;
aColor();
aColor(byte inR, byte inG, byte inB);
void SetValues(byte inR, byte inG, byte inB);
};
// impl
aColor::aColor() : r(0), g(0), b(0){}
aColor::aColor(byte inR, byte inG, byte inB) : r(inR), g(inG), b(inB){}
void aColor::SetValues(byte inR, byte inG, byte inB) {
r = inR;
g = inG;
b = inB;
}
// == ColorScheme ========================================================
#define MAX_SCHEME_COLORS 5
class ColorScheme {
public:
aColor* colors[MAX_SCHEME_COLORS];
int count;
int idx;
ColorScheme();
void Add(aColor*);
aColor* GetColor(int);
aColor GetRandomColor();
int GetCount();
};
ColorScheme::ColorScheme() {
count = 0;
idx = 0;
}
aColor ColorScheme::GetRandomColor() {
idx = random(this->GetCount());
aColor* c = colors[idx];
return *c;
}
void ColorScheme::Add(aColor* c) {
if (count < (MAX_SCHEME_COLORS - 1)) {
colors[count++] = c;
}
}
aColor* ColorScheme::GetColor(int idx) {
if (idx < 0) {
return colors[0]; // negative idx? be safe and quietly return first color
}
if (idx > (count - 1) || idx >= MAX_SCHEME_COLORS) {
return colors[count - 1]; // if off end of built colors or array itself, return last color
}
return colors[idx]; // return color requested
}
int ColorScheme::GetCount() {
return count;
}
enum {Black, White, Grey, LightGray, SlateGray, CornflowerBlue, DeepSkyBlue, DodgerBlue,
LightBlue, Cyan, LightCyan, LightSkyBlue, MediumBlue, MediumTurquoise, Aquamarine,
MediumAquamarine, RosyBrown, SaddleBrown, SandyBrown, DarkGreen, DarkOliveGreen, chartreuse,
DarkOrange, DarkSalmon, LightPink, Pink, AntiqueWhite, Linen, Wheat, BlanchedAlmond,
LightGoldenrod, Gold};
aColor colorArray[] = {
aColor(0, 0, 0),
aColor(255, 255, 255),
aColor(84, 84, 84),
aColor(211, 211, 211),
aColor(112, 128, 144),
aColor(100, 149, 237),
aColor(0, 191, 255),
aColor(30, 144, 255),
aColor(170, 187, 204),
aColor(0, 255, 255),
aColor(224, 255, 255),
aColor(135, 206, 250),
aColor(0, 0, 205),
aColor(72, 209, 204),
aColor(127, 255, 212),
aColor(102, 205, 170),
aColor(188, 143, 143),
aColor(139, 69, 19),
aColor(244, 164, 96),
aColor(47, 79, 47),
aColor(85, 107, 47),
aColor(127, 255, 0),
aColor(255, 140, 0),
aColor(233, 150, 122),
aColor(255, 182, 193),
aColor(255, 192, 203),
aColor(250, 235, 215),
aColor(250, 240, 230),
aColor(245, 222, 179),
aColor(255, 235, 205),
aColor(238, 221, 130),
aColor(255, 215, 0)
};
#define MAX_SCHEMES 5
static ColorScheme schemes[MAX_SCHEMES];
void CreatesColorSchemes() {
ColorScheme* theScheme = &schemes[0];
theScheme->Add(&colorArray[Grey]);
theScheme->Add(&colorArray[LightGray]);
theScheme->Add(&colorArray[CornflowerBlue]);
theScheme->Add(&colorArray[DarkGreen]);
theScheme->Add(&colorArray[DarkOliveGreen]);
#ifdef WIN32
printf("scheme1 Added %d colors\n", theScheme->GetCount());
for (int i = 0; i < theScheme->GetCount(); ++i) {
aColor* c = theScheme->GetItem(i);
printf("\t%d: %u, %u, %u\n", i, c->r, c->g, c->b);
}
#endif // WIN32
theScheme = &schemes[1];
theScheme->Add(&colorArray[SaddleBrown]);
theScheme->Add(&colorArray[SandyBrown]);
theScheme->Add(&colorArray[DarkGreen]);
theScheme->Add(&colorArray[BlanchedAlmond]);
theScheme->Add(&colorArray[Gold]);
theScheme->Add(&colorArray[Aquamarine]);
#ifdef WIN32
printf("Added %d colors\n", theScheme->GetCount());
for (int i = 0; i < theScheme->GetCount(); ++i) {
aColor* c = theScheme->GetItem(i);
printf("\t%d: %u, %u, %u\n", i, c->r, c->g, c->b);
}
#endif // WIN32
theScheme = &schemes[2];
theScheme->Add(&colorArray[CornflowerBlue]);
theScheme->Add(&colorArray[MediumBlue]);
theScheme->Add(&colorArray[DarkGreen]);
theScheme->Add(&colorArray[DarkSalmon]);
#ifdef WIN32
printf("Added %d colors\n", theScheme->GetCount());
for (int i = 0; i < theScheme->GetCount(); ++i) {
aColor* c = theScheme->GetItem(i);
printf("\t%d: %u, %u, %u\n", i, c->r, c->g, c->b);
}
#endif // WIN32
theScheme = &schemes[3];
theScheme->Add(&colorArray[White]);
theScheme->Add(&colorArray[LightCyan]);
theScheme->Add(&colorArray[DarkSalmon]);
theScheme->Add(&colorArray[MediumBlue]);
theScheme->Add(&colorArray[RosyBrown]);
theScheme->Add(&colorArray[Wheat]);
#ifdef WIN32
printf("Added %d colors\n", theScheme->GetCount());
for (int i = 0; i < theScheme->GetCount(); ++i) {
aColor* c = theScheme->GetItem(i);
printf("\t%d: %u, %u, %u\n", i, c->r, c->g, c->b);
}
#endif // WIN32
theScheme = &schemes[4];
theScheme->Add(&colorArray[White]);
theScheme->Add(&colorArray[LightCyan]);
theScheme->Add(&colorArray[MediumBlue]);
theScheme->Add(&colorArray[DarkOliveGreen]);
theScheme->Add(&colorArray[SaddleBrown]);
theScheme->Add(&colorArray[DarkOrange]);
#ifdef WIN32
printf("scheme5 Added %d colors\n", theScheme->GetCount());
for (int i = 0; i < theScheme->GetCount(); ++i) {
aColor* c = theScheme->GetItem(i);
printf("\t%d: %u, %u, %u\n", i, c->r, c->g, c->b);
}
#endif // WIN32
}
enum showState{ACT, SCENE_START, SCENE_DONE, FADE_OUT_BEGIN, FADE_OUT, FADE_OUT_DONE, COMMERCIAL};
struct StateVars {
showState currShowState;
unsigned long currStateStarted;
unsigned long currStateEndsAt;
int currStateEndsAfterNIterations;
int jitterIterations;
ColorScheme currColorScheme;
aColor currSchemeColor;
aColor currRenderColor;
int numScenesLeftInAct;
int jitterR;
int jitterG;
int jitterB;
int FADE_OUT_MS;
StateVars() {
currShowState = ACT;
numScenesLeftInAct = random(5);
FADE_OUT_MS = 2000;
currStateEndsAfterNIterations = 0;
jitterIterations = 0;
jitterR = 0;
jitterG = 0;
jitterB = 0;
}
byte AddJitter(byte colorVal, int jitter) {
int newVal = constrain(colorVal + jitter, 0, 255); // jitter may be negative
return (byte)newVal;
}
};
void setup() {
// Serial.begin(9600); // open the serial port at 9600 bps:
DigisparkRGBBegin();
randomSeed(analogRead(0));
// schemes
CreatesColorSchemes();
}
#define DELAY_MS 25
#define ITERATIONS_PER_SECOND (1000 / 25)
void loop ()
{
static StateVars stateVars;
/*
if (0 >= stateVars.currStateEndsAfterNIterations--) {
switch(stateVars.currShowState) {
case ACT:
stateVars.currSchemeColor.r = 0; stateVars.currSchemeColor.g = 0; stateVars.currSchemeColor.b = 255;
stateVars.currShowState = SCENE_START;
stateVars.currStateEndsAfterNIterations = 1000 / DELAY_MS;
break;
case SCENE_START:
stateVars.currSchemeColor.r = 0; stateVars.currSchemeColor.g = 255; stateVars.currSchemeColor.b = 0;
stateVars.currShowState = ACT;
stateVars.currStateEndsAfterNIterations = 500 / DELAY_MS;
break;
default:
stateVars.currSchemeColor.r = 255; stateVars.currSchemeColor.g = 0; stateVars.currSchemeColor.b = 0;
}
}
stateVars.currRenderColor = stateVars.currSchemeColor;
DigisparkRGB(RED, stateVars.currRenderColor.r);
DigisparkRGB(GREEN, stateVars.currRenderColor.g);
DigisparkRGB(BLUE, stateVars.currRenderColor.b);
DigisparkRGBDelay(DELAY_MS);
return;
*/
bool switchAgain = false;
do {
switchAgain = false;
if (0 >= stateVars.currStateEndsAfterNIterations--) {
switch(stateVars.currShowState) {
case ACT:
stateVars.numScenesLeftInAct = random(7, 10);
stateVars.currColorScheme = schemes[random(MAX_SCHEMES)];
stateVars.currShowState = SCENE_START;
switchAgain = true;
break;
case SCENE_START:
stateVars.currStateEndsAfterNIterations = random(3, 10) * ITERATIONS_PER_SECOND;
stateVars.currSchemeColor = stateVars.currColorScheme.GetRandomColor();
stateVars.currShowState = SCENE_DONE;
break;
case SCENE_DONE:
stateVars.numScenesLeftInAct--;
if (0 >= stateVars.numScenesLeftInAct) {
stateVars.currShowState = FADE_OUT_BEGIN;
} else {
stateVars.currShowState = SCENE_START;
switchAgain = true;
}
break;
case FADE_OUT_BEGIN:
stateVars.currStateEndsAfterNIterations = stateVars.FADE_OUT_MS / DELAY_MS;
stateVars.currShowState = FADE_OUT;
break;
case FADE_OUT:
stateVars.currShowState = FADE_OUT_DONE;
break;
case FADE_OUT_DONE:
stateVars.currShowState = COMMERCIAL;
switchAgain = true;
break;
case COMMERCIAL:
stateVars.currShowState = ACT;
#ifdef WIN32
std::cout << "case COMMERCIAL \n" << "press any key to quit";
std::cin.get();
#endif
switchAgain = true;
break;
default:
stateVars.currRenderColor.r = 11; stateVars.currRenderColor.g = 11; stateVars.currRenderColor.b = 11;
stateVars.currShowState = ACT;
switchAgain = true;
break;
}
}
} while (switchAgain);
stateVars.currRenderColor = stateVars.currSchemeColor;
if (stateVars.currShowState == FADE_OUT) {
long factor = 20;
long denom = stateVars.FADE_OUT_MS / DELAY_MS;
long numer = denom - (stateVars.currStateEndsAfterNIterations > 0 ? stateVars.currStateEndsAfterNIterations: 0);
stateVars.currRenderColor.r =
(byte) (stateVars.currRenderColor.r - ((stateVars.currRenderColor.r * numer * factor) / denom)/factor);
stateVars.currRenderColor.g =
(byte) (stateVars.currRenderColor.g - ((stateVars.currRenderColor.g * numer * factor) / denom)/factor);
stateVars.currRenderColor.b =
(byte) (stateVars.currRenderColor.b - ((stateVars.currRenderColor.b * numer * factor) / denom)/factor);
// double fadeRatio = 1.0 - ((now - stateVars.currStateStarted) / (double)stateVars.FADE_OUT_MS);
// if (fadeRatio < 0) fadeRatio = 0;
// stateVars.currRenderColor.r *= fadeRatio;
// stateVars.currRenderColor.g *= fadeRatio;
// stateVars.currRenderColor.b *= fadeRatio;
// printf("\tFaded color to %d, %d, %d\n", stateVars.currRenderColor.r, stateVars.currRenderColor.g, stateVars.currRenderColor.b);
}
// perhaps add some light jitter
if (0 >= stateVars.jitterIterations && random(0,100) < 10) {
stateVars.jitterIterations = abs(random(6, 50));
int r = random(0,100);
if (r < 40) {
int j = random(10,30); // brighten all
stateVars.jitterR = j;
stateVars.jitterG = j;
stateVars.jitterB = j;
}else if (r < 60) {
stateVars.jitterR = random(15, 25); // postive/negative color swing
stateVars.jitterG = random(15, 25);
stateVars.jitterB = random(15, 25);
stateVars.jitterR *= random(100) % 2 == 0? 1 : -1;
stateVars.jitterG *= random(100) % 2 == 0? 1 : -1;
stateVars.jitterB *= random(100) % 2 == 0? 1 : -1;
} else {
stateVars.jitterR = random(10,30); // random positive
stateVars.jitterG = random(10,30);
stateVars.jitterB = random(10,30);
}
}
if (0 < stateVars.jitterIterations) {
stateVars.jitterIterations--;
stateVars.currRenderColor.r = stateVars.AddJitter(stateVars.currRenderColor.r, stateVars.jitterR);
stateVars.currRenderColor.g = stateVars.AddJitter(stateVars.currRenderColor.g, stateVars.jitterG);
stateVars.currRenderColor.b = stateVars.AddJitter(stateVars.currRenderColor.b, stateVars.jitterB);
}
DigisparkRGB(RED, stateVars.currRenderColor.r);
DigisparkRGB(GREEN, stateVars.currRenderColor.g);
DigisparkRGB(BLUE, stateVars.currRenderColor.b);
DigisparkRGBDelay(DELAY_MS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment