Last active
February 28, 2024 05:14
-
-
Save jasoncoon/d4c935566ec82731fece to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// "Close Encounters" by Jason Coon | |
// https://gist.github.com/pup05/d4c935566ec82731fece | |
// | |
// The start of the main light bar on the ship in Close Encounters of the Third Kind: https://www.youtube.com/watch?v=S4PYI6TzqYk | |
// Multiple anti-aliased light bars running in alternating directions, now just needs the pulses of color. | |
// | |
// A slight modification of Mark Kriegsman's Anti-aliased light bar example: http://pastebin.com/g8Bxi6zW | |
// https://plus.google.com/u/0/112916219338292742137/posts/2VYNQgD38Pw | |
#include <FastLED.h> | |
#define LED_PIN 3 | |
#define CLOCK_PIN 2 | |
#define COLOR_ORDER GRB | |
#define CHIPSET APA102 | |
#define NUM_LEDS 63 | |
#define BRIGHTNESS 240 | |
CRGB leds[NUM_LEDS]; | |
int Width = 4; // width of each light bar, in whole pixels | |
const int barCount = 8; | |
int bars[barCount]; | |
int F16delta = 1; // how many 16ths of a pixel to move the Fractional Bar | |
uint16_t Fhue16 = 0; // color for Fractional Bar | |
int InterframeDelay = 40; //ms | |
void setup() | |
{ | |
FastLED.addLeds<CHIPSET, LED_PIN, CLOCK_PIN, BGR, DATA_RATE_MHZ(12)>(leds, NUM_LEDS); | |
FastLED.setBrightness(BRIGHTNESS); | |
for (int i = 0; i < barCount; i++) { | |
bars[i] = i * ((NUM_LEDS * 16) / barCount); | |
} | |
} | |
// Draw a "Fractional Bar" of light starting at position 'pos16', which is counted in | |
// sixteenths of a pixel from the start of the strip. Fractional positions are | |
// rendered using 'anti-aliasing' of pixel brightness. | |
// The bar width is specified in whole pixels. | |
// Arguably, this is the interesting code. | |
void drawFractionalBar(int pos16, int width, uint8_t hue, uint8_t sat) | |
{ | |
int i = pos16 / 16; // convert from pos to raw pixel number | |
uint8_t frac = pos16 & 0x0F; // extract the 'factional' part of the position | |
// brightness of the first pixel in the bar is 1.0 - (fractional part of position) | |
// e.g., if the light bar starts drawing at pixel "57.9", then | |
// pixel #57 should only be lit at 10% brightness, because only 1/10th of it | |
// is "in" the light bar: | |
// | |
// 57.9 . . . . . . . . . . . . . . . . . 61.9 | |
// v v | |
// ---+---56----+---57----+---58----+---59----+---60----+---61----+---62----> | |
// | | X|XXXXXXXXX|XXXXXXXXX|XXXXXXXXX|XXXXXXXX | | |
// ---+---------+---------+---------+---------+---------+---------+---------> | |
// 10% 100% 100% 100% 90% | |
// | |
// the fraction we get is in 16ths and needs to be converted to 256ths, | |
// so we multiply by 16. We subtract from 255 because we want a high | |
// fraction (e.g. 0.9) to turn into a low brightness (e.g. 0.1) | |
uint8_t firstpixelbrightness = 255 - (frac * 16); | |
// if the bar is of integer length, the last pixel's brightness is the | |
// reverse of the first pixel's; see illustration above. | |
uint8_t lastpixelbrightness = 255 - firstpixelbrightness; | |
// For a bar of width "N", the code has to consider "N+1" pixel positions, | |
// which is why the "<= width" below instead of "< width". | |
uint8_t bright; | |
for (int n = 0; n <= width; n++) { | |
if (n == 0) { | |
// first pixel in the bar | |
bright = firstpixelbrightness; | |
} | |
else if (n == width) { | |
// last pixel in the bar | |
bright = lastpixelbrightness; | |
} | |
else { | |
// middle pixels | |
bright = 255; | |
} | |
leds[i] += CHSV(hue, sat, bright); | |
i++; | |
if (i == NUM_LEDS) i = 0; // wrap around | |
} | |
} | |
void loop() | |
{ | |
// Draw everything: | |
// clear the pixel buffer | |
memset8(leds, 0, NUM_LEDS * sizeof(CRGB)); | |
for (int i = 0; i < barCount; i++) { | |
int bar = bars[i]; | |
// Update the "Fraction Bar" by 1/16th pixel every time | |
if (i % 2 == 0) | |
bar += F16delta; | |
else | |
bar -= F16delta; | |
// wrap around at end | |
// remember that F16pos contains position in "16ths of a pixel" | |
// so the 'end of the strip' is (NUM_LEDS * 16) | |
if (bar >= (NUM_LEDS * 16)) | |
bar -= NUM_LEDS * 16; | |
else if (bar < 0) | |
bar = (NUM_LEDS * 16) - 1; | |
// draw the Fractional Bar, length=4px | |
drawFractionalBar(bar, Width, 0, 0); | |
bars[i] = bar; | |
} | |
FastLED.show(); | |
FastLED.delay(InterframeDelay); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Cool. Thanks.