Version 2.1
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_0026.jpg
Normal file
|
After Width: | Height: | Size: 3.0 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_0027.jpg
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_0028.jpg
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_0693.jpg
Normal file
|
After Width: | Height: | Size: 4.1 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_0694.jpg
Normal file
|
After Width: | Height: | Size: 3.0 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_0695.jpg
Normal file
|
After Width: | Height: | Size: 3.1 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230303_121431.jpg
Normal file
|
After Width: | Height: | Size: 3.5 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230303_121447.jpg
Normal file
|
After Width: | Height: | Size: 3.3 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230306_110024.jpg
Normal file
|
After Width: | Height: | Size: 3.4 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230306_110029.jpg
Normal file
|
After Width: | Height: | Size: 3.1 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230306_110038.jpg
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230310_152719.jpg
Normal file
|
After Width: | Height: | Size: 3.3 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230310_152726.jpg
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230310_153016.jpg
Normal file
|
After Width: | Height: | Size: 3.2 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230317_155123.jpg
Normal file
|
After Width: | Height: | Size: 5.3 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230317_155130.jpg
Normal file
|
After Width: | Height: | Size: 5.0 MiB |
BIN
ESP32_MasterPx_DesignUhr/Bilder/IMG_20230317_155139.jpg
Normal file
|
After Width: | Height: | Size: 3.5 MiB |
2
ESP32_MasterPx_DesignUhr/Blech.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
https://bleche-nach-mass.de/blechzuschnitte/1090-magnetwaende?gclid=EAIaIQobChMI1Mfgl8m__QIVyud3Ch3O-wPpEAAYASAAEgIasvD_BwE#002-1091-6
|
||||
235x120
|
||||
@@ -0,0 +1,874 @@
|
||||
/*
|
||||
N-Tools 2023
|
||||
231112 -> Webseite Optimiert; kleinigkeiten für Uli;
|
||||
231210 -> Fehler in der Schrift NT7x10 behoben
|
||||
*/
|
||||
|
||||
#define VERSION (char *) "V2.1"
|
||||
|
||||
char ChipID[10] = "ERROR";
|
||||
uint64_t macAddress = ESP.getEfuseMac();
|
||||
uint64_t macAddressTrunc = (macAddress << 40);
|
||||
|
||||
#define R1_PIN 13
|
||||
#define G1_PIN 27
|
||||
#define B1_PIN 25
|
||||
#define R2_PIN 12
|
||||
#define G2_PIN 26
|
||||
#define B2_PIN 4
|
||||
#define A_PIN 19
|
||||
#define B_PIN 23 // Changed from library default
|
||||
#define C_PIN 18
|
||||
#define D_PIN 5
|
||||
#define E_PIN 15
|
||||
#define LAT_PIN 17
|
||||
#define OE_PIN 16
|
||||
#define CLK_PIN 14
|
||||
|
||||
#define PANEL_RES_X 96 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 48 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
|
||||
#define NUM_ROWS 1 // Number of rows of chained INDIVIDUAL PANELS
|
||||
#define NUM_COLS 1 // Number of INDIVIDUAL PANELS per ROW
|
||||
#define PANEL_CHAIN NUM_ROWS*NUM_COLS // total number of panels chained one to another
|
||||
|
||||
//#define PIXEL_COLOR_DEPTH_BITS 2
|
||||
|
||||
// library includes
|
||||
//#include <ESP32-VirtualMatrixPanel-I2S-DMA.h>
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
|
||||
MatrixPanel_I2S_DMA *display = nullptr;
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiAP.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ElegantOTA.h>
|
||||
#include <DNSServer.h>
|
||||
AsyncWebServer webServer(80);
|
||||
DNSServer dnsServer;
|
||||
IPAddress ip_local(192, 168, 13, 1);
|
||||
IPAddress ip_gateway(192, 168, 13, 1);
|
||||
IPAddress ip_subnet(255, 255, 255, 0);
|
||||
bool APEnabled = false;
|
||||
char ssid[30] = "";
|
||||
char pass[30] = "";
|
||||
char appass[30] = "";
|
||||
char localip[16];
|
||||
|
||||
#include "index_html.h"
|
||||
const char* PARAM_SET = "set";
|
||||
const char* PARAM_SAVE = "save";
|
||||
const char* PARAM_TO = "to";
|
||||
const char* PARAM_SHOWWHAT = "showWhat";
|
||||
const char* PARAM_BRIGHTNESS = "brightness";
|
||||
const char* PARAM_OPTIONS = "options";
|
||||
const char* PARAM_SSID = "ssid";
|
||||
const char* PARAM_PWD = "pwd";
|
||||
const char* PARAM_RESET = "reset";
|
||||
|
||||
// Replaces placeholder with button section in your web page
|
||||
char * html_processor(const String& var){
|
||||
if(var == "VERSION"){
|
||||
return VERSION;
|
||||
}else if(var == "ID"){
|
||||
return ChipID;
|
||||
}else if(var == "LOCALIP"){
|
||||
return localip;
|
||||
}
|
||||
return (char *) "not defined";
|
||||
}
|
||||
|
||||
String toStringIp(IPAddress ip) {
|
||||
String res = "";
|
||||
for (int i = 0; i < 3; i++) {
|
||||
res += String((ip >> (8 * i)) & 0xFF) + ".";
|
||||
}
|
||||
res += String(((ip >> 8 * 3)) & 0xFF);
|
||||
return res;
|
||||
}
|
||||
|
||||
void html_handle_notsuccess(AsyncWebServerRequest *request);
|
||||
void html_handle_notsuccess(AsyncWebServerRequest *request){
|
||||
request->send(200, "text/html", String("<a href='http://") + toStringIp(ip_local) + String("'>zur Konfigurationsseite</a><script> location.href = 'http://") + toStringIp(ip_local) + String("'; </script>"));
|
||||
}
|
||||
void html_root(AsyncWebServerRequest *request);
|
||||
void html_root(AsyncWebServerRequest *request) {
|
||||
request->send_P(200, "text/html", html_page_index, html_processor);
|
||||
}
|
||||
|
||||
void html_poll(AsyncWebServerRequest *request);
|
||||
void html_do(AsyncWebServerRequest *request);
|
||||
|
||||
|
||||
//permanenter Speicher
|
||||
#include <EEPROM.h>
|
||||
|
||||
//i2c
|
||||
#include <Wire.h>
|
||||
#include <RV-3028-C7.h>
|
||||
|
||||
RV3028 rtc;
|
||||
const int PINRTC_CLOCK = 34;
|
||||
bool rtcEnabled = false;
|
||||
bool doRTCSecond = false;
|
||||
|
||||
#include <TimeLib.h>
|
||||
#include <WeekNumber.h>
|
||||
|
||||
long ti_second = 0;
|
||||
float brightness = 1.0;
|
||||
|
||||
uint8_t timeColor[3] = {0xff,0xff,0xff};
|
||||
uint8_t tacticalTimeColor[3] = {0x88,0xff,0x00};
|
||||
uint8_t dateColor[3] {0x10,0xff,0x00};
|
||||
uint8_t kwColor[3] {0x10,0xff,0x00};
|
||||
|
||||
int8_t lastminutes = -1;
|
||||
|
||||
bool iDL = false;
|
||||
bool savediDL = false;
|
||||
|
||||
long lastTimeSyncTime = 0;
|
||||
uint8_t lastTimeSyncTyp = 0;
|
||||
|
||||
bool EEPROMDataNotSaved = false;
|
||||
uint8_t options = 0;
|
||||
|
||||
uint8_t timeIndex = 0;
|
||||
bool withSeconds = true;
|
||||
bool alwaysAccessPoint = true;
|
||||
|
||||
void setPixelColor(uint8_t x,uint8_t y, uint8_t red, uint8_t green ,uint8_t blue){
|
||||
display->drawPixelRGB888(x, y, red, green, blue);
|
||||
|
||||
}
|
||||
|
||||
//Zeichene eine Linie waagrecht x/y und z als länge
|
||||
void LineH(uint8_t x, uint8_t y, uint8_t z, uint8_t red, uint8_t green ,uint8_t blue){
|
||||
display->drawFastHLine(x,y,z,display->color565(red, green, blue));
|
||||
}
|
||||
|
||||
//Zeichene eine Linie senkrecht x/y und z als länge
|
||||
void LineV(uint8_t x, uint8_t y, int16_t z, uint8_t red, uint8_t green, uint8_t blue){
|
||||
display->drawFastVLine(x,y,z,display->color565(red, green, blue));
|
||||
}
|
||||
|
||||
void doClearTimeLEDs(uint8_t x=0,uint8_t y=0){
|
||||
for(uint8_t i=0;i<24;i++){
|
||||
display->drawFastHLine(x,y+i, 80, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void doClearTacticalLEDs(uint8_t x=0,uint8_t y=0){
|
||||
for(uint8_t i=0;i<16;i++){
|
||||
display->drawFastHLine(x,y+i, 96, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//eigene Schriften
|
||||
#include <char5x7.h>
|
||||
#include <char10x16.h>
|
||||
#include <char16x24.h>
|
||||
|
||||
#include <tthcent8p.h>
|
||||
#include <NT7x10.h>
|
||||
#include <BundesSans6P.h>
|
||||
#include <teko6P.h>
|
||||
|
||||
|
||||
void showNTOOLS(void){
|
||||
uint8_t zeile=12;
|
||||
uint8_t spalte=25;
|
||||
spalte += Out5x7Char('N',spalte,zeile,0,0,255)+1;
|
||||
spalte += Out5x7Char('-',spalte,zeile,0,0,255)+1;
|
||||
spalte += Out5x7Char('T',spalte,zeile,0,0,255)+1;
|
||||
spalte += Out5x7Char('o',spalte,zeile,0,0,255)+1;
|
||||
spalte += Out5x7Char('o',spalte,zeile-1,0,0,255)+1;
|
||||
spalte += Out5x7Char('l',spalte,zeile,0,0,255)+1;
|
||||
spalte += Out5x7Char('s',spalte,zeile,0,0,255)+1;
|
||||
spalte += Out5x7Char('.',spalte,zeile,0,0,255)+1;
|
||||
spalte += Out5x7Char('d',spalte,zeile,0,0,255)+1;
|
||||
spalte += Out5x7Char('e',spalte,zeile,0,0,255)+1;
|
||||
}
|
||||
|
||||
void drawSeconds(time_t t, uint8_t x=0, uint8_t y=0){
|
||||
uint16_t tmp = 0;
|
||||
|
||||
uint8_t r = timeColor[0];
|
||||
uint8_t g = timeColor[1];
|
||||
uint8_t b = timeColor[2];
|
||||
|
||||
for(uint8_t i=0;i<16;i++){
|
||||
display->drawFastHLine(x,y+i, 21, 0);
|
||||
}
|
||||
|
||||
tmp = second(t);
|
||||
Out10x16Char((tmp/10)+0x30,x,y,r,g,b);
|
||||
tmp -= (tmp/10)*10;
|
||||
x += 11;
|
||||
Out10x16Char((tmp)+0x30,x,y,r,g,b);
|
||||
}
|
||||
|
||||
void drawTime(time_t t,uint8_t x=0,uint8_t y=0){
|
||||
uint8_t tmp = 0;
|
||||
|
||||
uint8_t r = timeColor[0];
|
||||
uint8_t g = timeColor[1];
|
||||
uint8_t b = timeColor[2];
|
||||
|
||||
tmp = hour(t);
|
||||
|
||||
if((tmp/10 > 0)){
|
||||
if((tmp/10 == 1))
|
||||
Out16x24Char((tmp/10)+0x30,x+6,y,r,g,b);
|
||||
else
|
||||
Out16x24Char((tmp/10)+0x30,x,y,r,g,b);
|
||||
tmp -= (tmp/10)*10;
|
||||
}
|
||||
x += 19;
|
||||
if((tmp == 1))
|
||||
Out16x24Char((tmp)+0x30,x+3,y,r,g,b);
|
||||
else
|
||||
Out16x24Char((tmp)+0x30,x,y,r,g,b);
|
||||
Out16x24Char(':',x+19,y,r,g,b);
|
||||
x += 26;
|
||||
tmp = minute(t);
|
||||
if((tmp/10 == 1))
|
||||
Out16x24Char((tmp/10)+0x30,x+6,y,r,g,b);
|
||||
else
|
||||
Out16x24Char((tmp/10)+0x30,x,y,r,g,b);
|
||||
tmp -= (tmp/10)*10;
|
||||
x += 19;
|
||||
if((tmp == 1))
|
||||
Out16x24Char((tmp)+0x30,x+3,y,r,g,b);
|
||||
else
|
||||
Out16x24Char((tmp)+0x30,x,y,r,g,b);
|
||||
}
|
||||
|
||||
void showTime(time_t t,uint8_t x=12,uint8_t y=22){
|
||||
uint16_t tmp = minute(t);
|
||||
|
||||
if(withSeconds){
|
||||
drawSeconds(t,x+62,y+8);
|
||||
x -= 11;
|
||||
}
|
||||
|
||||
if(lastminutes != tmp){
|
||||
lastminutes = tmp;
|
||||
doClearTimeLEDs(x,y);
|
||||
//Uhrzeit
|
||||
drawTime(t,x,y);
|
||||
}
|
||||
}
|
||||
|
||||
char tacticalString[12] = "ddHHiiMMMyy";
|
||||
|
||||
void drawTactical(time_t t,uint8_t x = 0, uint8_t y = 0, uint8_t doCenterOf = 0){
|
||||
uint8_t r = tacticalTimeColor[0];
|
||||
uint8_t g = tacticalTimeColor[1];
|
||||
uint8_t b = tacticalTimeColor[2];
|
||||
|
||||
display->setFont(&NT7x10);
|
||||
display->setCursor(x, y+10);
|
||||
display->setTextColor(display->color565(r,g,b));
|
||||
|
||||
uint16_t tmp = day(t);
|
||||
tacticalString[0] = (tmp/10)+0x30;
|
||||
tmp -= (tmp/10)*10;
|
||||
tacticalString[1] = (tmp)+0x30;
|
||||
|
||||
tmp = hour(t);
|
||||
tacticalString[2] = (tmp/10)+0x30;
|
||||
tmp -= (tmp/10)*10;
|
||||
tacticalString[3] = (tmp)+0x30;
|
||||
|
||||
tmp = minute(t);
|
||||
tacticalString[4] = (tmp/10)+0x30;
|
||||
tmp -= (tmp/10)*10;
|
||||
tacticalString[5] = (tmp)+0x30;
|
||||
|
||||
tmp = month(t);
|
||||
switch(tmp){
|
||||
case 1:
|
||||
tacticalString[6] = 'j';
|
||||
tacticalString[7] = 'a';
|
||||
tacticalString[8] = 'n';
|
||||
break;
|
||||
case 2:
|
||||
tacticalString[6] = 'f';
|
||||
tacticalString[7] = 'e';
|
||||
tacticalString[8] = 'b';
|
||||
break;
|
||||
case 3:
|
||||
tacticalString[6] = 'm';
|
||||
tacticalString[7] = 'a';
|
||||
tacticalString[8] = 'r';
|
||||
|
||||
break;
|
||||
case 4:
|
||||
tacticalString[6] = 'a';
|
||||
tacticalString[7] = 'p';
|
||||
tacticalString[8] = 'r';
|
||||
break;
|
||||
case 5:
|
||||
tacticalString[6] = 'm';
|
||||
tacticalString[7] = 'a';
|
||||
tacticalString[8] = 'y';
|
||||
break;
|
||||
case 6:
|
||||
tacticalString[6] = 'j';
|
||||
tacticalString[7] = 'u';
|
||||
tacticalString[8] = 'n';
|
||||
break;
|
||||
case 7:
|
||||
tacticalString[6] = 'j';
|
||||
tacticalString[7] = 'u';
|
||||
tacticalString[8] = 'l';
|
||||
break;
|
||||
case 8:
|
||||
tacticalString[6] = 'a';
|
||||
tacticalString[7] = 'u';
|
||||
tacticalString[8] = 'g';
|
||||
break;
|
||||
case 9:
|
||||
tacticalString[6] = 's';
|
||||
tacticalString[7] = 'e';
|
||||
tacticalString[8] = 'p';
|
||||
break;
|
||||
case 10:
|
||||
tacticalString[6] = 'o';
|
||||
tacticalString[7] = 'c';
|
||||
tacticalString[8] = 't';
|
||||
break;
|
||||
case 11:
|
||||
tacticalString[6] = 'n';
|
||||
tacticalString[7] = 'o';
|
||||
tacticalString[8] = 'v';
|
||||
break;
|
||||
case 12:
|
||||
tacticalString[6] = 'd';
|
||||
tacticalString[7] = 'e';
|
||||
tacticalString[8] = 'c';
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = year(t)-2000;
|
||||
tacticalString[9] = (tmp/10)+0x30;
|
||||
tmp -= (tmp/10)*10;
|
||||
tacticalString[10] = (tmp)+0x30;
|
||||
|
||||
if(doCenterOf > 0){
|
||||
int16_t Tx,Ty;
|
||||
uint16_t w,h;
|
||||
display->getTextBounds(tacticalString,0,0,&Tx,&Ty,&w,&h);
|
||||
x = ceil((doCenterOf - w)/2);
|
||||
display->setCursor(x, y+10);
|
||||
}
|
||||
display->print(tacticalString);
|
||||
}
|
||||
|
||||
void showTimeTactical(time_t t){
|
||||
uint16_t tmp = minute(t);
|
||||
uint8_t x = 8;
|
||||
uint8_t y = 22;
|
||||
if(withSeconds){
|
||||
drawSeconds(t,x+62,y+8);
|
||||
x -= 11;
|
||||
}
|
||||
|
||||
if(lastminutes != tmp){
|
||||
lastminutes = tmp;
|
||||
doClearTacticalLEDs(0,7);
|
||||
drawTactical(t,0,7,96);
|
||||
//Uhrzeit
|
||||
doClearTimeLEDs(x,y);
|
||||
drawTime(t,x,y);
|
||||
}
|
||||
}
|
||||
|
||||
void doSetTime(unsigned long t){
|
||||
rtc.reset();
|
||||
rtc.setUNIX(t);
|
||||
}
|
||||
|
||||
uint8_t isDayLight(uint8_t hour, uint8_t day, uint8_t wday, uint8_t month){
|
||||
if( month < 3 || month > 10 ) // month 1, 2, 11, 12
|
||||
return 0; // -> Winter
|
||||
if( day - wday >= 25 && (wday || hour >= 2) ){ // after last Sunday 2:00
|
||||
if( month == 10 ) // October -> Winter
|
||||
return 0;
|
||||
}else{ // before last Sunday 2:00
|
||||
if( month == 3 ) // March -> Winter
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t isDayLightEx(void){
|
||||
long currentUNIXTime = now();
|
||||
byte Month, Day, Hour, WDay;
|
||||
Month = month(currentUNIXTime);
|
||||
Day = day(currentUNIXTime);
|
||||
Hour = hour(currentUNIXTime);
|
||||
WDay = weekday();
|
||||
return isDayLight(Hour,Day,WDay,Month);
|
||||
}
|
||||
|
||||
void checkiDL(void){
|
||||
iDL = isDayLightEx();
|
||||
if(iDL != savediDL){
|
||||
long currentUNIXTime = now();
|
||||
if(iDL){
|
||||
currentUNIXTime += (SECS_PER_HOUR);
|
||||
}else{
|
||||
currentUNIXTime -= (SECS_PER_HOUR);
|
||||
}
|
||||
setTime(currentUNIXTime);
|
||||
doSetTime(currentUNIXTime);
|
||||
savediDL = iDL;
|
||||
EEPROM.put(10, savediDL);
|
||||
EEPROM.commit();
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR rtc_clock(){ //Interrupt vom RTC
|
||||
if(digitalRead(PINRTC_CLOCK)){
|
||||
doRTCSecond = true;
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
//Serial.begin(115200);
|
||||
//Dispolay INIT
|
||||
HUB75_I2S_CFG::i2s_pins _pins = {
|
||||
R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN,
|
||||
A_PIN, B_PIN, C_PIN, D_PIN, E_PIN,
|
||||
LAT_PIN, OE_PIN, CLK_PIN
|
||||
};
|
||||
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN, // chain length
|
||||
_pins
|
||||
);
|
||||
|
||||
mxconfig.double_buff = false;
|
||||
mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_10M;
|
||||
mxconfig.latch_blanking = 4;
|
||||
mxconfig.min_refresh_rate = 50;
|
||||
|
||||
display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
display->begin();
|
||||
display->setPanelBrightness(100);
|
||||
display->clearScreen();
|
||||
display->setFont(&TTHCENT8pt7b);
|
||||
|
||||
EEPROM.begin(256);
|
||||
EEPROM.get(0, timeIndex);
|
||||
EEPROM.get(1, options);
|
||||
withSeconds = bitRead(options,0);
|
||||
alwaysAccessPoint = bitRead(options,1);
|
||||
|
||||
EEPROM.get(5, brightness);
|
||||
if(brightness < 0.10)
|
||||
brightness = 0.10;
|
||||
if(brightness > 1.0)
|
||||
brightness = 1.0;
|
||||
|
||||
EEPROM.get(10, savediDL);
|
||||
|
||||
timeColor[0] = EEPROM.read(11);
|
||||
timeColor[1] = EEPROM.read(12);
|
||||
timeColor[2] = EEPROM.read(13);
|
||||
|
||||
tacticalTimeColor[0] = EEPROM.read(21);
|
||||
tacticalTimeColor[1] = EEPROM.read(22);
|
||||
tacticalTimeColor[2] = EEPROM.read(23);
|
||||
|
||||
dateColor[0] = EEPROM.read(31);
|
||||
dateColor[1] = EEPROM.read(32);
|
||||
dateColor[2] = EEPROM.read(33);
|
||||
|
||||
kwColor[0] = EEPROM.read(41);
|
||||
kwColor[1] = EEPROM.read(42);
|
||||
kwColor[2] = EEPROM.read(43);
|
||||
|
||||
EEPROM.get(101,ssid);
|
||||
EEPROM.get(201,pass);
|
||||
EEPROM.get(151,appass);
|
||||
|
||||
|
||||
showNTOOLS();
|
||||
display->setCursor(1, 34);
|
||||
display->print("bitte warten");
|
||||
|
||||
Wire.begin(21,22);
|
||||
Wire.setClock(100000);
|
||||
if (rtc.begin() == true) {
|
||||
display->drawPixelRGB888(1,0,0,255,0);
|
||||
rtcEnabled = true;
|
||||
rtc.setBackupSwitchoverMode(3);
|
||||
rtc.enableClockOut(FD_CLKOUT_1);
|
||||
pinMode(PINRTC_CLOCK, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(PINRTC_CLOCK), rtc_clock, CHANGE);
|
||||
setTime(rtc.getUNIX());
|
||||
|
||||
//prüfen ob Winterzeit
|
||||
checkiDL();
|
||||
}else{
|
||||
display->drawPixelRGB888(1,0,255,0,0);
|
||||
}
|
||||
|
||||
macAddressTrunc = (macAddressTrunc >> 40);
|
||||
ultoa(macAddressTrunc,ChipID,10);
|
||||
|
||||
char NetName[30];
|
||||
strcpy(NetName, "NTDU");
|
||||
strcat(NetName, ChipID);
|
||||
char APName[30];
|
||||
strcpy(APName, "NT DesignUhr ");
|
||||
strcat(APName, ChipID);
|
||||
|
||||
WiFi.persistent(false);
|
||||
WiFi.begin(ssid,pass);
|
||||
WiFi.hostname(NetName);
|
||||
int xc = 0;
|
||||
while ((WiFi.status() != WL_CONNECTED) && (xc < 10)) {
|
||||
delay(1500);
|
||||
xc++;
|
||||
display->drawPixelRGB888(xc+6,0,255,255,0);
|
||||
}
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
char str[5];
|
||||
IPAddress lip;
|
||||
lip = WiFi.localIP();
|
||||
itoa(lip[0],str,10);
|
||||
strcpy(localip, str);
|
||||
strcat(localip, ".");
|
||||
itoa(lip[1],str,10);
|
||||
strcat(localip, str);
|
||||
strcat(localip, ".");
|
||||
itoa(lip[2],str,10);
|
||||
strcat(localip, str);
|
||||
strcat(localip, ".");
|
||||
itoa(lip[3],str,10);
|
||||
strcat(localip, str);
|
||||
show5x7( 5, 2, localip, 255, 255, 255);
|
||||
display->drawPixelRGB888(2, 0, 0, 255, 0);
|
||||
configTime(0,0, "ptbtime1.ptb.de", "ptbtime2.ptb.de", "ptbtime3.ptb.de");
|
||||
time_t timenow = time(nullptr);
|
||||
xc = 0;
|
||||
while((timenow < SECS_YR_2000) && (xc < 10)) {
|
||||
delay(1000);
|
||||
timenow = time(nullptr);
|
||||
xc++;
|
||||
display->drawPixelRGB888(xc+17,0,255,255,0);
|
||||
}
|
||||
if(timenow > SECS_YR_2000){
|
||||
byte Month, Day, Hour;
|
||||
setTime(timenow);
|
||||
Month = month(timenow);
|
||||
Day = day(timenow);
|
||||
Hour = hour(timenow);
|
||||
iDL = isDayLight(Hour,Day,weekday(),Month);
|
||||
if(iDL)
|
||||
timenow += (SECS_PER_HOUR * 2);
|
||||
else
|
||||
timenow += (SECS_PER_HOUR);
|
||||
setTime(timenow);
|
||||
if(rtcEnabled){
|
||||
doSetTime(timenow);
|
||||
}
|
||||
savediDL = iDL;
|
||||
EEPROM.put(10, savediDL);
|
||||
EEPROM.commit();
|
||||
display->drawPixelRGB888(3,0,0,255,0);
|
||||
}else{
|
||||
display->drawPixelRGB888(3,0,255,0,255);
|
||||
}
|
||||
delay(5000);
|
||||
}else{
|
||||
display->drawPixelRGB888(2,0,255,0,0);
|
||||
APEnabled = true;
|
||||
}
|
||||
|
||||
if(APEnabled || alwaysAccessPoint){
|
||||
if(WiFi.status() == WL_CONNECTED)
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
else
|
||||
WiFi.mode(WIFI_AP);
|
||||
delay(100);
|
||||
WiFi.softAPConfig(ip_local, ip_gateway, ip_subnet);
|
||||
APEnabled = WiFi.softAP(APName, appass,2,0,1);
|
||||
if(!APEnabled)
|
||||
display->drawPixelRGB888(4,0,255,0,0);
|
||||
else{
|
||||
display->drawPixelRGB888(4,0,0,255,0);
|
||||
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
|
||||
dnsServer.start(53, "*", ip_local);
|
||||
}
|
||||
}else{
|
||||
display->drawPixelRGB888(4,0,0,0,0);
|
||||
}
|
||||
|
||||
ElegantOTA.begin(&webServer); // Start AsyncElegantOTA
|
||||
webServer.onNotFound([](AsyncWebServerRequest *request){html_handle_notsuccess(request);});
|
||||
webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request){html_root(request);});
|
||||
webServer.on("/do", HTTP_GET, [] (AsyncWebServerRequest *request) {html_do(request);});
|
||||
webServer.on("/poll", HTTP_GET, [] (AsyncWebServerRequest *request) {html_poll(request);});
|
||||
webServer.begin();
|
||||
|
||||
delay(1000);
|
||||
|
||||
display->setPanelBrightness(ceil(255 * brightness));
|
||||
display->clearScreen();
|
||||
|
||||
/*display->setTextColor(display->color565(128,255,0));
|
||||
display->setFont(&NT7x10);
|
||||
display->setCursor(13, 11);
|
||||
display->print("alles gute im");
|
||||
display->setCursor(17, 22);
|
||||
display->setTextColor(display->color565(255,0,0));
|
||||
display->print("neuen heim");
|
||||
*/
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (millis() - ti_second > 1000) {
|
||||
ti_second = millis();
|
||||
if(!rtcEnabled){
|
||||
doRTCSecond = true;
|
||||
}
|
||||
}
|
||||
if(doRTCSecond){
|
||||
doRTCSecond = false;
|
||||
time_t currentUNIXTime = now();
|
||||
if(rtcEnabled){
|
||||
currentUNIXTime = rtc.getUNIX();
|
||||
setTime(currentUNIXTime);
|
||||
}
|
||||
uint8_t Hour, Minute, Second, WDay;
|
||||
Hour = hour(currentUNIXTime);
|
||||
Minute = minute(currentUNIXTime);
|
||||
Second = second(currentUNIXTime);
|
||||
WDay = weekday();
|
||||
checkiDL();
|
||||
//Sonntag Reset ..
|
||||
if((WDay == 1) && (Hour == 3) && (Minute == 1) && (Second == 0)){
|
||||
ESP.restart();
|
||||
}
|
||||
switch(timeIndex){
|
||||
case 0:
|
||||
showTimeTactical(currentUNIXTime);
|
||||
break;
|
||||
case 1:
|
||||
showTime(currentUNIXTime,4,10);
|
||||
break;
|
||||
case 2:
|
||||
//showDateTime(currentUNIXTime);
|
||||
break;
|
||||
case 3:
|
||||
|
||||
showTime(currentUNIXTime,8,24);
|
||||
break;
|
||||
case 4:
|
||||
//clock_center_x = 16;
|
||||
//showAnalogTime(currentUNIXTime);
|
||||
//showAnalogDate(currentUNIXTime);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(APEnabled)
|
||||
dnsServer.processNextRequest();
|
||||
ElegantOTA.loop();
|
||||
}
|
||||
|
||||
void html_poll(AsyncWebServerRequest *request) {
|
||||
long color = 0;
|
||||
char ret[250];
|
||||
char tempBuff[30];
|
||||
strcpy(ret,(char *)"[");
|
||||
if(rtcEnabled)
|
||||
ltoa(rtc.getUNIX(),tempBuff,DEC);
|
||||
else
|
||||
ltoa(now(),tempBuff,DEC);
|
||||
strcat(ret,tempBuff);
|
||||
color = timeColor[0] << 16;
|
||||
color += timeColor[1] << 8;
|
||||
color += timeColor[2];
|
||||
itoa(color,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
color = tacticalTimeColor[0] << 16;
|
||||
color += tacticalTimeColor[1] << 8;
|
||||
color += tacticalTimeColor[2];
|
||||
itoa(color,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
color = dateColor[0] << 16;
|
||||
color += dateColor[1] << 8;
|
||||
color += dateColor[2];
|
||||
itoa(color,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
itoa(timeIndex,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
itoa(lastTimeSyncTyp,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
itoa(lastTimeSyncTime,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
dtostrf(brightness, 10, 2, tempBuff);
|
||||
strcat(ret,(char *)",\"");
|
||||
strcat(ret,tempBuff);
|
||||
strcat(ret,(char *)"\"");
|
||||
itoa(rtcEnabled,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
itoa(EEPROMDataNotSaved,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
strcat(ret,(char *)",\"");
|
||||
strcat(ret,ssid);
|
||||
strcat(ret,(char *)"\"");
|
||||
itoa(options,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
color = kwColor[0] << 16;
|
||||
color += kwColor[1] << 8;
|
||||
color += kwColor[2];
|
||||
itoa(color,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
uint8_t kw = GetWeekNumber(year(now()),month(now()),day(now()));
|
||||
itoa(kw,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
itoa(iDL,tempBuff,DEC);
|
||||
strcat(ret,(char *)",");
|
||||
strcat(ret,tempBuff);
|
||||
strcat(ret,(char *)"]");
|
||||
request->send(200, "text/plain", ret);
|
||||
}
|
||||
|
||||
void html_do(AsyncWebServerRequest *request) {
|
||||
String s_set,s_value,s_idx,s_value2;
|
||||
uint32_t l_value;
|
||||
if (request->hasParam(PARAM_SET)) {
|
||||
s_set = request->getParam(PARAM_SET)->value();
|
||||
if((s_set == "time") & (request->hasParam(PARAM_TO))) {
|
||||
s_value = request->getParam(PARAM_TO)->value();
|
||||
l_value = strtol(s_value.c_str(), NULL, 10);
|
||||
doSetTime(l_value);
|
||||
lastTimeSyncTyp = 3;
|
||||
lastTimeSyncTime = now();
|
||||
}else if(request->hasParam(PARAM_SHOWWHAT)) {
|
||||
s_value = request->getParam(PARAM_SHOWWHAT)->value();
|
||||
timeIndex = s_value.toInt();
|
||||
display->clearScreen();
|
||||
EEPROM.put(0, timeIndex);
|
||||
EEPROMDataNotSaved = true;
|
||||
}else if(((s_set == "color") | (s_set == "tcolor") | (s_set == "dcolor") | (s_set == "kwcolor")) & (request->hasParam(PARAM_TO))) {
|
||||
s_value = request->getParam(PARAM_TO)->value();
|
||||
uint8_t c[3];
|
||||
l_value = strtol(s_value.c_str(), NULL, 16);
|
||||
c[0] = l_value >> 16;
|
||||
c[1] = l_value >> 8;
|
||||
c[2] = l_value;
|
||||
if(s_set == "color"){
|
||||
timeColor[0] = c[0];
|
||||
timeColor[1] = c[1];
|
||||
timeColor[2] = c[2];
|
||||
EEPROM.write(11,timeColor[0]);
|
||||
EEPROM.write(12,timeColor[1]);
|
||||
EEPROM.write(13,timeColor[2]);
|
||||
EEPROMDataNotSaved = true;
|
||||
}else if(s_set == "tcolor"){
|
||||
tacticalTimeColor[0] = c[0];
|
||||
tacticalTimeColor[1] = c[1];
|
||||
tacticalTimeColor[2] = c[2];
|
||||
EEPROM.write(21,tacticalTimeColor[0]);
|
||||
EEPROM.write(22,tacticalTimeColor[1]);
|
||||
EEPROM.write(23,tacticalTimeColor[2]);
|
||||
EEPROMDataNotSaved = true;
|
||||
}else if(s_set == "dcolor"){
|
||||
dateColor[0] = c[0];
|
||||
dateColor[1] = c[1];
|
||||
dateColor[2] = c[2];
|
||||
EEPROM.write(31,dateColor[0]);
|
||||
EEPROM.write(32,dateColor[1]);
|
||||
EEPROM.write(33,dateColor[2]);
|
||||
EEPROMDataNotSaved = true;
|
||||
}else if(s_set == "kwcolor"){
|
||||
kwColor[0] = c[0];
|
||||
kwColor[1] = c[1];
|
||||
kwColor[2] = c[2];
|
||||
EEPROM.write(41,kwColor[0]);
|
||||
EEPROM.write(42,kwColor[1]);
|
||||
EEPROM.write(43,kwColor[2]);
|
||||
EEPROMDataNotSaved = true;
|
||||
}
|
||||
}else if((s_set == "option")) {
|
||||
if(request->hasParam(PARAM_BRIGHTNESS)) {
|
||||
s_value = request->getParam(PARAM_BRIGHTNESS)->value();
|
||||
brightness = s_value.toFloat();
|
||||
EEPROM.put(5,brightness);
|
||||
EEPROMDataNotSaved = true;
|
||||
display->setPanelBrightness(ceil(255 * brightness));
|
||||
}
|
||||
if(request->hasParam(PARAM_OPTIONS)) {
|
||||
s_value = request->getParam(PARAM_OPTIONS)->value();
|
||||
options = s_value.toInt();
|
||||
EEPROM.put(1,options);
|
||||
EEPROMDataNotSaved = true;
|
||||
withSeconds = bitRead(options,0);
|
||||
alwaysAccessPoint = bitRead(options,1);
|
||||
display->clearScreen();
|
||||
}
|
||||
}else if((s_set == "wifi")) {
|
||||
if((request->hasParam(PARAM_SSID)) && (request->hasParam(PARAM_PWD))){
|
||||
s_value = request->getParam(PARAM_SSID)->value();
|
||||
s_value2 = request->getParam(PARAM_PWD )->value();
|
||||
if((s_value != ssid) || (s_value2 != pass)){
|
||||
s_value.toCharArray(ssid, 30);
|
||||
s_value2.toCharArray(pass, 30);
|
||||
EEPROM.put(101,ssid);
|
||||
EEPROM.put(201,pass);
|
||||
EEPROMDataNotSaved = true;
|
||||
}
|
||||
|
||||
}
|
||||
}else if((s_set == "appass")) {
|
||||
if(request->hasParam(PARAM_PWD)){
|
||||
s_value2 = request->getParam(PARAM_PWD )->value();
|
||||
if((s_value2 != appass)){
|
||||
s_value2.toCharArray(appass, 30);
|
||||
EEPROM.put(151,appass);
|
||||
EEPROMDataNotSaved = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
request->send(200, "text/plain", "OK");
|
||||
lastminutes = -1;
|
||||
}else if (request->hasParam(PARAM_SAVE)){
|
||||
EEPROM.commit();
|
||||
EEPROMDataNotSaved = false;
|
||||
request->send(200, "text/plain", "OK");
|
||||
}else if (request->hasParam(PARAM_RESET)){
|
||||
request->send(200, "text/plain", "OK");
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
request->send(200, "text/plain", "NOK");
|
||||
}
|
||||
|
||||
46087
ESP32_MasterPx_DesignUhr/ESP32_MasterPx_DesignUhr/esp32.svd
Normal file
560
ESP32_MasterPx_DesignUhr/ESP32_MasterPx_DesignUhr/index_html.h
Normal file
@@ -0,0 +1,560 @@
|
||||
const char html_page_index[] PROGMEM = R"rawliteral(
|
||||
<!DOCTYPE HTML><html>
|
||||
<head>
|
||||
<title>N-Tools.de Uhr</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="data:,">
|
||||
<style>
|
||||
html {font-family: Roboto, Arial; display: inline-block; text-align: center;}
|
||||
body {font-size: 1.5rem; margin:0px auto; padding-bottom: 25px; min-height:100%;}
|
||||
body * {font-size: 1.3rem;}
|
||||
input[type=checkbox]{
|
||||
transform: scale(1.5);
|
||||
padding: 10px;
|
||||
position: relative;
|
||||
}
|
||||
label {min-width: 150px;display: inline-block;text-align: left; padding-left: 5px;}
|
||||
input,select,option { display: inline-block;text-align:center;}
|
||||
h1,h2,h3{padding:0px;margin:0px;)}
|
||||
h1{font-size: 1.7rem;}
|
||||
.head{
|
||||
background: linear-gradient(to bottom, #1b62d8 0%, #003399 100%);
|
||||
text-align: right;
|
||||
margin: 0px;
|
||||
padding: 5px;
|
||||
box-shadow: 0 8px 32px 0 rgb(0 0 0 / 40%), 0 3px 20px 0 rgb(0 0 0 / 38%);
|
||||
color:#fff;
|
||||
}
|
||||
.site{
|
||||
|
||||
}
|
||||
.option {
|
||||
margin: 20px;
|
||||
padding: 10px;
|
||||
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
||||
min-width: 160px;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
display: inline-grid;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.value {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
}
|
||||
.act{
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
padding: 2px 5px 2px 5px;
|
||||
}
|
||||
.m50{
|
||||
min-width: 50%;
|
||||
}
|
||||
.fs25{
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
.fs12{
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.fs17{
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
.fs075, .fs075 *{
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.left{
|
||||
text-align: left;
|
||||
}
|
||||
.margin25left{
|
||||
margin-left: 25%;
|
||||
}
|
||||
.margin12left{
|
||||
margin-left: 12%;
|
||||
}
|
||||
#te{
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
margin: auto;
|
||||
padding: 3%;
|
||||
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
||||
min-height: 70%;
|
||||
width: 74%;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
opacity: 1.0;
|
||||
}
|
||||
#te > .value{
|
||||
text-align: left;
|
||||
}
|
||||
#oe{
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
margin: auto;
|
||||
padding: 3%;
|
||||
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
||||
min-height: 70%;
|
||||
width: 74%;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
opacity: 1.0;
|
||||
}
|
||||
#oe > .value{
|
||||
text-align: left;
|
||||
}
|
||||
#close{
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
display: block;
|
||||
}
|
||||
#message{
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 10%;
|
||||
left: 35%;
|
||||
margin: auto;
|
||||
padding: 5px;
|
||||
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
||||
width: 30%;
|
||||
border-radius: 4px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
input[type=button], input[type=submit], input[type=reset] {
|
||||
background-color: #1b62d8;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
|
||||
color: #fff;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
padding: 0.25rem 0.5rem;
|
||||
@media(min-width: 600px) {
|
||||
margin: 0 1em 2em;
|
||||
}
|
||||
|
||||
&:hover { text-decoration: none; }
|
||||
|
||||
box-shadow: inset 0 0 20px rgba(255, 255, 255, 0);
|
||||
outline: 1px solid;
|
||||
outline-color: rgba(255, 255, 255, .5);
|
||||
outline-offset: 0px;
|
||||
text-shadow: none;
|
||||
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
input[type=button]:hover {
|
||||
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
||||
outline-color: rgba(255, 255, 255, 0);
|
||||
outline-offset: 15px;
|
||||
text-shadow: 1px 1px 2px #427388;
|
||||
}
|
||||
.wsnw{
|
||||
white-space: nowrap;
|
||||
}
|
||||
.center{
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="head" class="head">
|
||||
<h1>N-Tools Design Uhr</h1>
|
||||
<h3>`VERSION`</h3>
|
||||
<h3>`ID`</h3>
|
||||
<span style='font-size: 0.7rem;'>lokale IP: `LOCALIP`</span>
|
||||
</div>
|
||||
<div id="site" class="site">
|
||||
<div id="message"></div>
|
||||
<div class='option' onclick="editTime(-1);">
|
||||
<div class='value'>
|
||||
<label class="center">aktuell:</label><br>
|
||||
<span class='act' id="actTime"></span><br>
|
||||
<span class='act' id="actTacTime"></span><br>
|
||||
<span class='act' id="actDate"></span><br>
|
||||
<span class='act' id="actKW"></span>
|
||||
</div><br>
|
||||
<div class='fs075'>
|
||||
<label>letzter abgleich:</label>
|
||||
<span id="sync"></span>
|
||||
</div>
|
||||
</div><br>
|
||||
<br>
|
||||
<div class='option m50'>
|
||||
<label for="showWhat">Zeige</label>
|
||||
<select id="showWhat" onchange="setShowWhat();">
|
||||
<option value=0>taktische Uhrzeit</option>
|
||||
<option value=1>Uhrzeit</option>
|
||||
<option value=2>Datum / Uhrzeit</option>
|
||||
<option value=3>Wormser</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class='option m50' onclick="return false">
|
||||
<span class="wsnw">
|
||||
<label for="brigtness">Helligkeit LEDs</label>
|
||||
<span><span id="brigtness"></span> %</span><br>
|
||||
</span>
|
||||
<div class="left">
|
||||
<span class="wsnw">
|
||||
<label for="SSID">SSID:</label>
|
||||
<span id="SSID"></span>
|
||||
</span>
|
||||
<br>
|
||||
<input type="button" onclick="editOption();" value="Optionen ändern"><br>
|
||||
<br>
|
||||
<span class="wsnw">
|
||||
<input id="rtcactive" type='checkbox' onclick="return false" readonly>
|
||||
<label for="rtcactive">RTC okay</label>
|
||||
</span>
|
||||
<span class="wsnw">
|
||||
<input id="withSeconds" type='checkbox' onclick="return false" readonly>
|
||||
<label for="withSeconds">Sekunden zeigen</label>
|
||||
</span>
|
||||
<span class="wsnw">
|
||||
<input id="isSummerTime" type='checkbox' onclick="return false" readonly>
|
||||
<label for="isSummerTime">Sommerzeit</label>
|
||||
</span>
|
||||
<span class="wsnw">
|
||||
<input id="alwaysAccessPoint" type='checkbox' onclick="return false" readonly>
|
||||
<label for="alwaysAccessPoint">AccessPoint erstellen auch bei erfolgreicher WiFi Verbindung</label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<input id="d" type='text' style='width:80%;font-size:0.75rem;display:none;' value=''>
|
||||
<div class='option m50'>
|
||||
<input class="fs17" id="save" class="btn" type='button' value='dauerhaft speichern' onclick='save();'>
|
||||
</div>
|
||||
<div class='option m50'>
|
||||
<input class="fs17" id="reset" class="btn" type='button' value='neu starten' onclick='reset();'>
|
||||
</div>
|
||||
<div id="te">
|
||||
<div id="close" onclick="closeEdit();">X</div>
|
||||
<div class='value'>
|
||||
<h1><span id="el"></span></h1>
|
||||
<label for="eActTimeC">Uhrzeit: </label><input type="color" id="eActTimeC" value=""><br>
|
||||
<label for="eActTacTimeC">taktische Zeit: </label><input type="color" id="eActTacTimeC" value=""><br>
|
||||
<label for="eActDateC">Datum: </label><input type="color" id="eActDateC" value=""><br>
|
||||
<label for="eActKWC">KW: </label><input type="color" id="eActKWC" value=""><br>
|
||||
<input type="button" class="btn fs12" onclick="setColor();closeEdit();" value="setzen"><br><br>
|
||||
<input type="button" id="doSetTime" class="btn fs12" onclick="doSetTime();" value="Uhrzeit nach diesem Gerät setzen"><br>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="oe">
|
||||
<div id="close" onclick="closeOptionEdit();">X</div>
|
||||
<div class='value'>
|
||||
<h1><span id="el">Optionen</span></h1>
|
||||
<input id="ebs" type='number' min="5" max="100" step="5"> %
|
||||
<label for="ebs">Helligkeitsfaktor (in Prozent)</label><br>
|
||||
<span>
|
||||
<input id="eWithSeconds" type='checkbox'>
|
||||
<label for="eWithSeconds">zeige Sekunden</label>
|
||||
</span>
|
||||
<span>
|
||||
<input id="eAlwaysAccessPoint" type='checkbox'>
|
||||
<label for="eAlwaysAccessPoint">AccessPoint erstellen auch bei erfolgreicher WiFi Verbindung</label>
|
||||
</span>
|
||||
<br>
|
||||
<input type="button" class="btn" onclick="setOption();" value="setzen">
|
||||
<br><br>
|
||||
<span>
|
||||
<label for="eSSID">SSID:</label>
|
||||
<input id="eSSID" type='text' onclick="return false">
|
||||
</span>
|
||||
<br>
|
||||
<span>
|
||||
<label for="ePASS">Passwort:</label>
|
||||
<input id="ePASS" type='text' onclick="return false">
|
||||
</span>
|
||||
<br>
|
||||
<input type="button" class="btn" onclick="setWifi();" value="setzen">
|
||||
<br><br>
|
||||
<span>
|
||||
<label for="apPASS">AccessPoint Passwort:</label>
|
||||
<input id="apPASS" type='text' maxlength="64" minlength="8" onclick="return false">
|
||||
</span>
|
||||
<br>
|
||||
<input type="button" class="btn" onclick="setAPPass();" value="setzen"><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
var ti = new Date;
|
||||
var EEPROMDataChanged = false;
|
||||
|
||||
function RGBToHex(rgb) {
|
||||
// Choose correct separator
|
||||
let sep = rgb.indexOf(",") > -1 ? "," : " ";
|
||||
// Turn "rgb(r,g,b)" into [r,g,b]
|
||||
rgb = rgb.substr(4).split(")")[0].split(sep);
|
||||
|
||||
let r = (+rgb[0]).toString(16),
|
||||
g = (+rgb[1]).toString(16),
|
||||
b = (+rgb[2]).toString(16);
|
||||
|
||||
if (r.length == 1)
|
||||
r = "0" + r;
|
||||
if (g.length == 1)
|
||||
g = "0" + g;
|
||||
if (b.length == 1)
|
||||
b = "0" + b;
|
||||
console.log("#" + r + g + b);
|
||||
return "#" + r + g + b;
|
||||
}
|
||||
|
||||
|
||||
function closeEdit(){
|
||||
document.getElementById("te").style.display = "none";
|
||||
}
|
||||
|
||||
function editTime(_what){
|
||||
if(_what == -1){
|
||||
document.getElementById("el").innerHTML = 'Farben';
|
||||
document.getElementById("eActTimeC").value = RGBToHex(document.getElementById('actTime').style.color);
|
||||
document.getElementById("eActTacTimeC").value = RGBToHex(document.getElementById('actTacTime').style.color);
|
||||
document.getElementById("eActDateC").value = RGBToHex(document.getElementById('actDate').style.color);
|
||||
document.getElementById("eActKWC").value = RGBToHex(document.getElementById('actKW').style.color);
|
||||
}
|
||||
document.getElementById("te").style.display = "initial";
|
||||
}
|
||||
|
||||
function closeOptionEdit(){
|
||||
document.getElementById("oe").style.display = "none";
|
||||
}
|
||||
|
||||
function editOption(){
|
||||
document.getElementById('ebs').value = document.getElementById('brigtness').innerHTML;
|
||||
document.getElementById('eSSID').value = document.getElementById('SSID').innerHTML;
|
||||
document.getElementById("eWithSeconds").checked = document.getElementById("withSeconds").checked;
|
||||
document.getElementById("eAlwaysAccessPoint").checked = document.getElementById("alwaysAccessPoint").checked;
|
||||
document.getElementById("oe").style.display = "initial";
|
||||
}
|
||||
|
||||
Number.prototype.AddZero= function(b,c){
|
||||
var l= (String(b || 10).length - String(this).length)+1;
|
||||
return l>0? new Array(l).join(c || '0')+this : this;
|
||||
}
|
||||
|
||||
function showOK(){
|
||||
document.getElementById("message").innerHTML='ok';
|
||||
document.getElementById("message").style.backgroundColor = "#0f0";
|
||||
document.getElementById("message").style.display = "initial";
|
||||
setTimeout(function(){
|
||||
document.getElementById("message").style.display = "none";
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function fetchHandle(res){
|
||||
if(!res.ok){
|
||||
console.log(res);
|
||||
document.getElementById("site").style.backgroundColor = "#f00";
|
||||
}else{
|
||||
if(EEPROMDataChanged)
|
||||
document.getElementById("site").style.backgroundColor = "#ffa";
|
||||
else
|
||||
document.getElementById("site").style.backgroundColor = "#fff";
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
function fetch_handle_response(res){
|
||||
var elem=document.getElementById('d');
|
||||
elem.value=res;
|
||||
if(res == 'OK'){
|
||||
showOK();
|
||||
}else if(res[0] == '['){
|
||||
try{
|
||||
var data = JSON.parse(res);
|
||||
ti = data[0];
|
||||
showAktTimeFromUnix(ti);
|
||||
colorString = "#" + data[1].toString(16).padStart(6, '0');
|
||||
document.getElementById('actTime').style.color = colorString;
|
||||
colorString = "#" + data[2].toString(16).padStart(6, '0');
|
||||
document.getElementById('actTacTime').style.color = colorString;
|
||||
colorString = "#" + data[3].toString(16).padStart(6, '0');
|
||||
document.getElementById('actDate').style.color = colorString;
|
||||
|
||||
document.getElementById('showWhat').value = parseInt(data[4]);
|
||||
switch(data[5]){
|
||||
case 0:
|
||||
document.getElementById('sync').innerHTML = " keiner";
|
||||
break;
|
||||
case 1:
|
||||
document.getElementById('sync').innerHTML += " (GPS)";
|
||||
break;
|
||||
case 2:
|
||||
document.getElementById('sync').innerHTML += " (NTP)";
|
||||
break;
|
||||
case 3:
|
||||
document.getElementById('sync').innerHTML += " (manuel)";
|
||||
break;
|
||||
}
|
||||
showTimeFromUnix(data[6],'sync');
|
||||
document.getElementById('brigtness').innerHTML = (data[7]*100);
|
||||
document.getElementById("rtcactive").checked = (data[8] == 1);
|
||||
|
||||
EEPROMDataChanged = (data[9] == 1);
|
||||
if(EEPROMDataChanged){
|
||||
document.getElementById("site").style.backgroundColor = "#ffa";
|
||||
}
|
||||
document.getElementById('SSID').innerHTML = data[10];
|
||||
var options = parseInt(data[11]);
|
||||
document.getElementById("withSeconds").checked = (options >> 0) & 0x1;
|
||||
document.getElementById("alwaysAccessPoint").checked = (options >> 1) & 0x1;
|
||||
|
||||
colorString = "#" + data[12].toString(16).padStart(6, '0');
|
||||
document.getElementById('actKW').style.color = colorString;
|
||||
document.getElementById('actKW').innerHTML = "KW " + data[13];
|
||||
document.getElementById("isSummerTime").checked = (data[14] == 1);
|
||||
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doSend(_value1,_value2=[],_value3=[]){
|
||||
var send_str = "/do?"+_value1[0]+"="+_value1[1];
|
||||
if(_value2.length > 0){
|
||||
send_str += "&"+_value2[0]+"="+_value2[1];
|
||||
}
|
||||
if(_value3.length > 0){
|
||||
send_str += "&"+_value3[0]+"="+_value3[1];
|
||||
}
|
||||
fetch(send_str).then(fetchHandle).then((res) => res.text()).then((text) => fetch_handle_response(text)).catch((err) => { console.log(err);document.getElementById("site").style.backgroundColor = "#f00";});
|
||||
}
|
||||
|
||||
function doPoll(){
|
||||
var send_str = "/poll";
|
||||
fetch(send_str).then(fetchHandle).then((res) => res.text()).then((text) => fetch_handle_response(text)).catch((err) => { console.log(err);document.getElementById("site").style.backgroundColor = "#f00";});
|
||||
}
|
||||
|
||||
function doSetTime(_idx = -1){
|
||||
var d=new Date();
|
||||
d.setTime(d.getTime() - (d.getTimezoneOffset()*60*1000) + 1000);
|
||||
doSend(['set','time'],['to',Math.floor(d /1000)],['idx',_idx]);
|
||||
}
|
||||
|
||||
function setColor(){
|
||||
var elem=document.getElementById('eActTimeC');
|
||||
doSend(['set','color'],['to',elem.value.substring(1)]);
|
||||
elem=document.getElementById('eActTacTimeC');
|
||||
doSend(['set','tcolor'],['to',elem.value.substring(1)]);
|
||||
elem=document.getElementById('eActDateC');
|
||||
doSend(['set','dcolor'],['to',elem.value.substring(1)]);
|
||||
elem=document.getElementById('eActKWC');
|
||||
doSend(['set','kwcolor'],['to',elem.value.substring(1)]);
|
||||
}
|
||||
|
||||
function setTimeFromUnix(_ti,_id){
|
||||
var elem=document.getElementById(_id);
|
||||
//var st = String(new Date(_ti*1000).toISOString().substr(0,19));
|
||||
var st = new Date(parseInt(_ti) * 1000);
|
||||
var sst = st.toISOString().slice(0,19);
|
||||
elem.value = sst;
|
||||
}
|
||||
|
||||
function showAktTimeFromUnix(_ti){
|
||||
var elem=document.getElementById('actTime');
|
||||
var elem2=document.getElementById('actTacTime');
|
||||
var elem3=document.getElementById('actDate');
|
||||
var st = new Date(parseInt(_ti) * 1000);
|
||||
st.setTime(st.getTime() + (st.getTimezoneOffset()*60*1000));
|
||||
//var sst = st.toUTCString();
|
||||
var sstTime = ("0" + st.getHours()).slice(-2) + ":" + ("0" + st.getMinutes()).slice(-2) + ":" + ("0" + st.getSeconds()).slice(-2);
|
||||
elem.innerHTML = sstTime;
|
||||
const formatter = new Intl.DateTimeFormat('en', { month: 'short' });
|
||||
const month = formatter.format(st);
|
||||
var sstTacTime = ("0" + st.getDate()).slice(-2) + "" + ("0" + st.getHours()).slice(-2) + "" + ("0" + st.getMinutes()).slice(-2) + month.toLowerCase() + ("" + st.getFullYear()).slice(-2);
|
||||
elem2.innerHTML = sstTacTime;
|
||||
var sstDate = ("0" + st.getDate()).slice(-2) + "." + ("0"+(st.getMonth()+1)).slice(-2) + "." +st.getFullYear();
|
||||
elem3.innerHTML = sstDate;
|
||||
}
|
||||
|
||||
function showTimeFromUnix(_ti,_id){
|
||||
var elem=document.getElementById(_id);
|
||||
var st = new Date(parseInt(_ti) * 1000);
|
||||
st.setTime(st.getTime() + (st.getTimezoneOffset()*60*1000));
|
||||
//var sst = st.toUTCString();
|
||||
var sst = ("0" + st.getDate()).slice(-2) + "." + ("0"+(st.getMonth()+1)).slice(-2) + "." +st.getFullYear() + " " + ("0" + st.getHours()).slice(-2) + ":" + ("0" + st.getMinutes()).slice(-2) + ":" + ("0" + st.getSeconds()).slice(-2);
|
||||
elem.innerHTML = sst;
|
||||
}
|
||||
|
||||
function setShowWhat(_what = -2){
|
||||
if(_what == -2){
|
||||
var elem=document.getElementById("showWhat");
|
||||
doSend(['set','option'],['showWhat',elem.value]);
|
||||
}else{
|
||||
doSend(['set','option'],['showWhat',_what]);
|
||||
}
|
||||
}
|
||||
|
||||
function setBrightness(){
|
||||
var elem=document.getElementById("ebs");
|
||||
doSend(['set','option'],['brightness',(elem.value / 100)]);
|
||||
}
|
||||
|
||||
function setWifi(){
|
||||
var elem=document.getElementById("eSSID");
|
||||
var elem2=document.getElementById("ePASS");
|
||||
doSend(['set','wifi'],['ssid',encodeURIComponent(elem.value)],['pwd',encodeURIComponent(elem2.value)]);
|
||||
}
|
||||
|
||||
function setAPPass(){
|
||||
var elem=document.getElementById("apPASS");
|
||||
var pwd = String(elem.value);
|
||||
if(((pwd.length > 7) && (pwd.length < 65)) || (pwd.length==0)){
|
||||
doSend(['set','appass'],['pwd',encodeURIComponent(pwd)]);
|
||||
elem.value = '';
|
||||
}else{
|
||||
alert('Das AccessPoint Passwort muss leer oder zwischen 8 und 64 Zeichen lang sein!');
|
||||
}
|
||||
}
|
||||
|
||||
function setOption(){
|
||||
setBrightness();
|
||||
var option = 0;
|
||||
if(document.getElementById("eWithSeconds").checked)
|
||||
option += 1;
|
||||
if(document.getElementById("eAlwaysAccessPoint").checked)
|
||||
option += 2;
|
||||
|
||||
doSend(['set','option'],['options',option]);
|
||||
}
|
||||
|
||||
function save() {
|
||||
doSend(['save','']);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
doSend(['reset','']);
|
||||
}
|
||||
|
||||
function poll() {
|
||||
doPoll();
|
||||
setTimeout(function(){
|
||||
poll();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
poll();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)rawliteral";
|
||||
@@ -0,0 +1,62 @@
|
||||
# HUB75 RGB LED matrix library utilizing ESP32 DMA Engine
|
||||
# https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA
|
||||
# MIT License
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
if(ARDUINO_ARCH_ESP32 OR CONFIG_ESP32_HUB75_USE_GFX)
|
||||
list(APPEND build_dependencies arduino Adafruit-GFX-Library)
|
||||
else()
|
||||
list(APPEND build_dependencies esp_lcd driver)
|
||||
endif()
|
||||
|
||||
if(${target} STREQUAL "esp32s3")
|
||||
list(APPEND extra_srcs src/platforms/${target}/gdma_lcd_parallel16.cpp)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "src/platforms/esp32/esp32_i2s_parallel_dma.cpp" "src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp" "src/ESP32-HUB75-MatrixPanel-leddrivers.cpp" ${extra_srcs}
|
||||
INCLUDE_DIRS "./src"
|
||||
)
|
||||
|
||||
# Dependencies cannot be added to the REQUIRES argument of `idf_component_register` because (according to the build process
|
||||
# listed at https://docs.espressif.com/projects/esp-idf/en/v4.2/esp32/api-guides/build-system.html#build-process)
|
||||
# `idf_component_register` is processed during the "Enumeration" stage which happens before the sdkconfig file is loaded
|
||||
# in the "Processing" stage. So if dependencies are going to be loaded based on certain CONFIG_* variables we must
|
||||
# use `target_link_libraries` instead. This is the method used by Arduino's CMakeLists.txt file.
|
||||
idf_build_get_property(components BUILD_COMPONENTS)
|
||||
foreach(component_name IN LISTS build_dependencies)
|
||||
if (NOT ${component_name} IN_LIST components)
|
||||
message(FATAL_ERROR "Missing component: ${component_name}")
|
||||
endif()
|
||||
idf_component_get_property(lib_name ${component_name} COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC ${lib_name})
|
||||
endforeach()
|
||||
|
||||
# In case you are running into issues with "missing" header files from 3rd party libraries
|
||||
# you can add them to the REQUIRES section above. If you use some of the build options below
|
||||
# you probably want to remove (NO_GFX) or replace Adafruit-GFX-Library (USE_GFX_ROOT)
|
||||
|
||||
# Example to build with USE_GFX_ROOT or NO_GFX / just uncomment the appropriate line
|
||||
# target_compile_options(${COMPONENT_TARGET} PUBLIC -DUSE_GFX_ROOT)
|
||||
# target_compile_options(${COMPONENT_TARGET} PUBLIC -DNO_GFX)
|
||||
|
||||
# esp-idf does not have any GFX library support yet, so we need to define NO_GFX
|
||||
if(ARDUINO_ARCH_ESP32 OR CONFIG_ESP32_HUB75_USE_GFX)
|
||||
else()
|
||||
target_compile_options(${COMPONENT_TARGET} PUBLIC -DNO_GFX)
|
||||
if(${target} STREQUAL "esp32s3")
|
||||
# Don't enable PSRAM based framebuffer just because it's an S3.
|
||||
# This is an advanced option and should only be used with an S3 with Octal-SPI RAM.
|
||||
# target_compile_options(${COMPONENT_TARGET} PUBLIC -DSPIRAM_FRAMEBUFFER)
|
||||
target_compile_options(${COMPONENT_TARGET} PUBLIC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# You can also use multiple options like this
|
||||
# target_compile_options(${COMPONENT_TARGET} PUBLIC -DNO_GFX -DNO_FAST_FUNCTIONS)
|
||||
|
||||
# All options can be found here:
|
||||
# https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/blob/master/doc/BuildOptions.md
|
||||
|
||||
project(ESP32-HUB75-MatrixPanel-I2S-DMA)
|
||||
@@ -0,0 +1,9 @@
|
||||
menu "ESP32 HUB75 Configuration"
|
||||
|
||||
config ESP32_HUB75_USE_GFX
|
||||
bool "Use Adafruit GFX library."
|
||||
default y
|
||||
help
|
||||
This option enables use of the Adafruit GFX library using the `Adafruit-GFX-Library` component.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2032 Faptastic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
232
libraries/ESP32_HUB75_LED_MATRIX_PANEL_DMA_Display/README.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# HUB75 RGB LED matrix panel library utilizing ESP32 DMA
|
||||
|
||||
__[BUILD OPTIONS](/doc/BuildOptions.md) | [EXAMPLES](/examples/README.md)__ | [](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/actions/workflows/pio_build.yml)
|
||||
|
||||
**Table of Content**
|
||||
|
||||
- [Introduction](#introduction)
|
||||
* [Features](#features)
|
||||
* [ESP32 variants supported](#esp32-variants-supported)
|
||||
* [Required memory](#required-memory)
|
||||
* [Supported Panels](#supported-panels)
|
||||
* [Panel driver chips known to be working well](#driver-chips-known-to-be-working-well)
|
||||
* [Unsupported Panels](#unsupported-panels)
|
||||
- [Getting Started](#getting-started)
|
||||
* [1. Library Installation](#1-library-installation)
|
||||
* [2. Wiring the ESP32 to an LED Matrix Panel](#2-wiring-the-esp32-to-an-led-matrix-panel)
|
||||
* [3. Run a Test Sketch](#3-run-a-test-sketch)
|
||||
- [Further Information](#further-information)
|
||||
* [Can I chain panels?](#can-i-chain-panels)
|
||||
* [Can I use with a larger panel (i.e. 64x64px square panel)?](#can-i-use-with-a-larger-panel-ie-64x64px-square-panel)
|
||||
* [Adjusting Panel Brightness](#adjusting-panel-brightness)
|
||||
* [Build-time options](#build-time-options)
|
||||
* [Latch blanking](#latch-blanking)
|
||||
* [Power, Power and Power!](#power-power-and-power)
|
||||
* [Inspiration](#inspiration)
|
||||
* [Cool uses of this library](#cool-uses-of-this-library)
|
||||
- [Thank you!](#thank-you)
|
||||
|
||||
# Introduction
|
||||
* This is an ESP32 Arduino/IDF library for HUB75 / HUB75E connection based RGB LED panels.
|
||||
* This library 'out of the box' (mostly) supports HUB75 panels where simple TWO rows/lines are updated in parallel... referred to as 'two scan' panels within this documentation.
|
||||
* 'Four scan' panels are also supported - but please refer to the Four Scan Panel example sketch.
|
||||
* The library uses the DMA functionality provided by the ESP32's 'LCD Mode' for fast data output.
|
||||
|
||||
## Features
|
||||
- **Low CPU overhead** - Pixel data is sent directly with the use of hardware-backed DMA, no CPU involvement
|
||||
- **Fast** - Updating pixel data involves only bit-wise logic over DMA buffer memory, no pins manipulation or blocking IO
|
||||
- **Full screen BCM** - Library utilizes [binary-code modulation](http://www.batsocks.co.uk/readme/art_bcm_5.htm) to render pixel color depth / brightness over the entire matrix to give reasonable colour depth
|
||||
- **Variable color depth** - Up to TrueColor 24 bits output is possible depending on matrix size/refresh rate required
|
||||
- **CIE 1931** luminance [correction](https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/) (aka natural LED dimming) implemented
|
||||
- **Adafruit GFX API** - Library can be built with AdafruitGFX, simplified GFX or without a GFX API at all
|
||||
|
||||
## ESP32 variants supported
|
||||
* Original ESP32 - That being the ESP-WROOM-32 module with ESP32‑D0WDQ6 chip from ~2017.
|
||||
* ESP32-S2; and
|
||||
* ESP32-S3
|
||||
|
||||
RISC-V ESP32's (like the C3) are not supported as they do not have the hardware 'LCD mode' support.
|
||||
|
||||
## Required memory
|
||||
"*What's the price for those features?*" - It's [memory](/doc/memcalc.md), you pay it all by precious MCU's internal memory (SRAM) for the DMA buffer.
|
||||
|
||||
Please use the ['Memory Calculator'](/doc/memcalc.md) to see what is *typically* achievable with the typical ESP32. This is only a guide. 
|
||||
|
||||
For the ESP32-S3 only, you can use SPIRAM/PSRAM to drive the HUB75 DMA buffer when using an ESP32-S3 with **OCTAL SPI-RAM (PSTRAM)** (i.e. ESP32 S3 N8R8 variant). However, due to bandwidth limitations, the maximum output frequency is limited to approx. 13Mhz, which will limit the real-world number of panels that can be chained without flicker. Please do not use PSRAM as the DMA buffer if using QUAD SPI (Q-SPI), as it's too slow.
|
||||
|
||||
To enable PSRAM support on the ESP32-S3, refer to [the build options](/doc/BuildOptions.md) to enable.
|
||||
|
||||
For all other ESP32 variants (like the most popular ‘original’ ESP32), [only *internal* SRAM can be used](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/55), so you will be limited to the ~200KB or so of 'free' SRAM (because of the memory used for your sketch amongst other things) regardless of how many megabytes of SPIRAM/PSRAM you may have connected.
|
||||
|
||||
|
||||
## Supported panel can types
|
||||
It is impossible to provide a comprehensive list of what panels are supported (or not supported) as new variations of the chips used to 'drive' these panels are created almost weekly (usually from China). You should contact the seller to confirm the chips used in a panel before purchasing to use with this library.
|
||||
|
||||
* 'Two scan' panels where **two** rows/lines are updated in parallel.
|
||||
* 64x32 (width x height) 'Indoor' panels, which are often referred to as 1/16 'scan panel' as every 16th row is updated in parallel (hence why I refer to it as 'two scan')
|
||||
* 64x64 pixel 1/32 Scan LED Matrix 'Indoor' Panel
|
||||
|
||||
* 'Four scan' panels where **four** rows/lines are updated in parallel.
|
||||
* 32x16 pixel 1/4 Scan LED Matrix 'Indoor' Panel using an ingenious workaround as demonstrated in the Four_Scan_Panel example.
|
||||
* 126x64 [SM5266P](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/164)
|
||||
|
||||
Ones interested in internals of such matrices could find [this article](https://www.sparkfun.com/news/2650) useful.
|
||||
|
||||

|
||||
|
||||
## Specific chips found to work
|
||||
* ICND2012
|
||||
* [RUC7258](http://www.ruichips.com/en/products.html?cateid=17496)
|
||||
* FM6126A AKA ICN2038S, [FM6124](https://datasheet4u.com/datasheet-pdf/FINEMADELECTRONICS/FM6124/pdf.php?id=1309677) (Refer to [PatternPlasma](/examples/2_PatternPlasma) example on how to use.)
|
||||
* SM5266P
|
||||
* DP3246 with SM5368 row addressing registers
|
||||
|
||||
## Specific chips found NOT TO work
|
||||
* ANY panel that uses S-PWM or PWM based chips (such as the RUL6024, MBI6024).
|
||||
* [SM1620B](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/issues/416)
|
||||
* RUL5358 / SHIFTREG_ABC_BIN_DE based panels are not supported.
|
||||
* ICN2053 / FM6353 based panels - Refer to [this library](https://github.com/LAutour/ESP32-HUB75-MatrixPanel-DMA-ICN2053), which is a fork of this library ( [discussion link](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/discussions/324)).
|
||||
* Any other panel not listed above.
|
||||
|
||||
Please use an [alternative library](https://github.com/2dom/PxMatrix) if you bought one of these.
|
||||
|
||||
# Getting Started
|
||||
## 1. Library Installation
|
||||
|
||||
* Dependency: You will need to install Adafruit_GFX from the "Library > Manage Libraries" menu.
|
||||
* Install this library from the Arduino Library manager.
|
||||
|
||||
Library also tested to work fine with PlatformIO, install into your PlatformIO projects' lib/ folder as appropriate. Or just add it into [platformio.ini](/doc/BuildOptions.md) [lib_deps](https://docs.platformio.org/en/latest/projectconf/section_env_library.html#lib-deps) section.
|
||||
|
||||
## 2. Wiring the ESP32 to an LED Matrix Panel
|
||||
|
||||
Refer to the '*default-pins.hpp' file within the [applicable platforms folder](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/tree/master/src/platforms).
|
||||
|
||||
```
|
||||
If you want to change the GPIO mapping at runtime, simply provide the wanted pin mapping as part of the class initialization structure. For example, in your sketch have something like the following:
|
||||
|
||||
// Change these to whatever suits
|
||||
#define R1_PIN 25
|
||||
#define G1_PIN 26
|
||||
#define B1_PIN 27
|
||||
#define R2_PIN 14
|
||||
#define G2_PIN 12
|
||||
#define B2_PIN 13
|
||||
#define A_PIN 23
|
||||
#define B_PIN 19
|
||||
#define C_PIN 5
|
||||
#define D_PIN 17
|
||||
#define E_PIN -1 // required for 1/32 scan panels, like 64x64px. Any available pin would do, i.e. IO32
|
||||
#define LAT_PIN 4
|
||||
#define OE_PIN 15
|
||||
#define CLK_PIN 16
|
||||
|
||||
HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN};
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
64, // Module width
|
||||
32, // Module height
|
||||
2, // chain length
|
||||
_pins, // pin mapping
|
||||
);
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
```
|
||||
|
||||
Make sure you also connect one of the HUB75 interfaces ground pins to a ground pin of the ESP32, otherwise you may get electrical artefacts on LED Matrix Panel.
|
||||
|
||||
Various people have created PCBs for which one can simply connect an ESP32 to a PCB, and then the PCB to the HUB75 connector, such as:
|
||||
|
||||
* Brian Lough's [ESP32 I2S Matrix Shield](http://blough.ie/i2smat/)
|
||||
* Charles Hallard's [WeMos Matrix Shield](https://github.com/hallard/WeMos-Matrix-Shield-DMA)
|
||||
* Bogdan Sass's [Morph Clock Shield](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/110#discussioncomment-861152)
|
||||
|
||||
Please contact or order these products from the respective authors.
|
||||
|
||||
### Can I use with a larger panel (i.e. 64x64px square panel)?
|
||||
If you want to use with a 64x64 pixel panel (typically a HUB75*E* panel) you MUST configure a valid *E_PIN* to your ESP32 and connect it to the E pin of the HUB75 panel! Hence the 'E' in 'HUB75E'
|
||||
|
||||
|
||||
## 3. Run a Test Sketch
|
||||
Below is a bare minimum sketch to draw a single white dot in the top left. You must call begin() before you call ANY pixel-drawing (fonts, lines, colours etc.) function of the MatrixPanel_I2S_DMA class.
|
||||
|
||||
Once this is working, refer to the [PIO Test Patterns](/examples/PIO_TestPatterns) example. This sketch draws simple colors/lines/gradients over the entire matrix and it could help to troubleshoot various issues with ghosting, flickering, etc...
|
||||
|
||||
Note: Requires the use of [PlatformIO](https://platformio.org/), which you should probably use if you aren't already.
|
||||
|
||||
# Further information
|
||||
## Can I chain panels?
|
||||
Yes!
|
||||
|
||||
[Horizontal](https://user-images.githubusercontent.com/12006953/122657476-cd358d00-d15b-11eb-9c6c-99b61378c56a.mp4)
|
||||
|
||||
For example: If you want to chain two of these horizontally to make a 128x32 panel you can do so by connecting the panels in series using the HUB75 ribbon cable. Than you must provide proper configuration structure to the class constructor letting it know that you use "one long virtual matrix chain". Refer to [Pattern Plasma](/examples/2_PatternPlasma/) example for all the details about configuration setup.
|
||||
|
||||
Finally, if you wanted to chain 4 x (64x32px) panels to make 128x64px display (essentially a 2x2 grid of 64x32 LED Matrix modules), a little more magic will be required. Refer to the [Chained Panels](examples/ChainedPanels/) example.
|
||||
|
||||
Resolutions beyond 128x64 are more likely to result in crashes due to [memory](/doc/i2s_memcalc.md) constraints etc. You are on your own after this point - PLEASE do not raise issues about this, the library can't magically defeat the SRAM memory constraints of the ESP32.
|
||||
|
||||

|
||||
|
||||
## Adjusting Panel Brightness
|
||||
|
||||
By default you should not need to change / set the brightness value (which is 128 or 50%) as it should be sufficient for most purposes. Brightness can be changed by calling `setPanelBrightness(xx)` or `setBrightness8(xx)`.
|
||||
|
||||
The value to pass must be a number between 0 (for a black screen) and 255 (max brightness).
|
||||
|
||||
Example:
|
||||
```
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
dma_display->begin(); // setup the LED matrix
|
||||
dma_display->setBrightness8(192); //0-255
|
||||
dma_display->clearScreen();
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
## Build-time options
|
||||
Although Arduino IDE does not [seem](https://github.com/arduino/Arduino/issues/421) to offer any way of specifying compile-time options for external libs there are other IDE's (like [PlatformIO](https://platformio.org/)/[Eclipse](https://www.eclipse.org/ide/)) that could use that. Check [Build Options](doc/BuildOptions.md) document for reference.
|
||||
|
||||
## Latch blanking
|
||||
If you are facing issues with image ghosting when pixels has clones with horizontal offset, than you try to change Latch blanking value. Latch blanking controls for how many clock pulses matrix output is disabled via EO signal before/after toggling LAT signal. It hides row bits transitioning and different panels may require longer times for proper operation. Default value is 1 clock before/after LAT row transition. This could be controlled with `MatrixPanel_I2S_DMA::setLatBlanking(uint8_t v)`. v could be between 1 to 4, default is 1, larger values won't give any benefit other than reducing brightness.
|
||||
|
||||
An example:
|
||||
```
|
||||
dma_display->setLatBlanking(2);
|
||||
```
|
||||
|
||||
## Power, Power and Power!
|
||||
Having a good power supply is CRITICAL, and it is highly recommended, for chains of LED Panels to have a 1000-2000uf capacitor soldered to the back of each LED Panel across the [GND and VCC pins](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/39#issuecomment-720780463), otherwise you WILL run into issues with 'flashy' graphics whereby a large amount of LEDs are turned on and off in succession (due to current/power draw peaks and troughs).
|
||||
|
||||
- Refer to this guide written for the [rpi-rgb-led-matrix library](https://github.com/hzeller/rpi-rgb-led-matrix/blob/master/wiring.md#a-word-about-power) for an explanation.
|
||||
- Refer to this [example](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/39#issuecomment-722691127) issue of what can go wrong with a poor power supply.
|
||||
|
||||
|
||||
- Refer to [this comment](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/35#issuecomment-726419862) in regards to certain panels not playing nice with voltages, and a 3.3volt signal that the ESP32 GPIO can only provide.
|
||||
|
||||
## Inspiration
|
||||
This project was inspired by:
|
||||
* 'SmartMatrix': https://github.com/pixelmatix/SmartMatrix/tree/teensylc
|
||||
* Sprite_TM's demo implementation here: https://www.esp32.com/viewtopic.php?f=17&t=3188
|
||||
|
||||
|
||||
## Cool uses of this library
|
||||
There are a number of great looking LED graphical display projects which leverage this library, these include:
|
||||
* [128x64 Morph Clock](https://github.com/bogd/esp32-morphing-clock)
|
||||
* [FFT Audio Visualisation](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/149)
|
||||
* [Clock, GIF Animator and Audio Visualiser](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/153)
|
||||
* [Aurora Audio Visualiser](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/188)
|
||||
* [Big Visualisation](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/155)
|
||||
* [Clockwise](https://jnthas.github.io/clockwise/)
|
||||
|
||||
# Thank you!
|
||||
* [Brian Lough](https://www.tindie.com/stores/brianlough/) ([youtube link](https://www.youtube.com/c/brianlough)) for providing code contributions, hardware and suggestions
|
||||
* [Vortigont](https://github.com/vortigont) for his game changing code contributions and performance optimisations
|
||||
* [Galaxy Man](https://github.com/Galaxy-Man) for donation of 1/16 scan panels to support the implemenation of led matrix panel chaining (virtual display) support
|
||||
* [Pipimaxi](https://github.com/Pipimaxi) for the donation of a ESP32-S2 and [Radu](https://github.com/juniorradu) for the donation of an ESP32-S3 to enable support for ESP32 S2/S3's to be tested and implemented.
|
||||
* [Mark Donners](https://github.com/donnersm) ('The Electronic Engineer' on [youtube](https://www.youtube.com/watch?v=bQ7c9Vlhyp0&t=118s)) for the donation of a 1/8 scan panel to build and test working support of these led matrix panels!
|
||||
* [PaintYourDragon](https://github.com/PaintYourDragon) for the DMA logic for the ESP32-S3.
|
||||
* And lots of others, let me know if I've missed you.
|
||||
|
||||
If you want to donate money to the project, please refer to [this discussion](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/discussions/349) about it. If you want to donate/buy an LED panel for the library author to improve compatibility and/or testing - please feel free to post in the same [discussion](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/discussions/349).
|
||||
|
||||

|
||||
@@ -0,0 +1 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS = .
|
||||
@@ -0,0 +1,38 @@
|
||||
### Build Options and flags
|
||||
|
||||
This library supports build-time defines to modify its features or enable greater debugging information. Please use the debugging capabilities before raising any issues.
|
||||
|
||||
For example build flags could be set using PlatformIO's .ini file like this
|
||||
|
||||
```
|
||||
[env]
|
||||
framework = arduino
|
||||
platform = espressif32
|
||||
lib_deps =
|
||||
ESP32 HUB75 LED MATRIX PANEL DMA Display
|
||||
build_flags =
|
||||
-DCORE_DEBUG_LEVEL=3
|
||||
-DNO_GFX=1
|
||||
(etc.....)
|
||||
```
|
||||
Or if using Arduino: 'Tools' menu > 'Core Debug Level' > Select 'Debug'
|
||||
|
||||
... and use the Serial output to see the debug information.
|
||||
|
||||
## Build flags
|
||||
|
||||
| Flag | Description | Note |
|
||||
| :------------ |---------------|-----|
|
||||
| **CORE_DEBUG_LEVEL** |Adjust the espressif ESP32 IDF debug level, for which this library leverages to output information on what is going on when allocating memory etc. This will provide detailed information about memory allocations, DMA descriptors setup and color depth [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm) |Set value to at least 3 [(Info)](https://iotespresso.com/core-debug-level-in-esp32/)
|
||||
| **USE_GFX_ROOT** | Use [lightweight](https://github.com/mrfaptastic/Adafruit_GFX_Lite) version of AdafuitGFX, without Adafruit BusIO extensions | You **must** install [Adafruit_GFX_Lite](https://github.com/mrfaptastic/Adafruit_GFX_Lite) library instead of original AdafruitGFX|
|
||||
| **NO_GFX** | Build without AdafuitGFX API, only native methods supported based on manipulating DMA buffer. I.e. no methods of drawing circles/shapes, typing text or using fonts!!! This might save some resources for applications using it's own internal graphics buffer or working solely with per-pixel manipulation. | Use this if you rely on FastLED, Neomatrix or any other API. For example [Aurora](/examples/AuroraDemo/) effects can work fine w/o AdafruitGFX. |
|
||||
| **NO_FAST_FUNCTIONS** | Do not build auxiliary speed-optimized functions. Those are used to speed-up operations like drawing straight lines or rectangles. Otherwise lines/shapes are drawn using drawPixel() method. The trade-off for speed is RAM/code-size, take it or leave it ;) | If you are not using AdafruitGFX than you probably do not need this either|
|
||||
|**NO_CIE1931**|Do not use LED brightness [compensation](https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/) described in [CIE 1931](https://en.wikipedia.org/wiki/CIE_1931_color_space). Normally library would adjust every pixel's RGB888 so that luminance (or brightness control) for the corresponding LED's would appear 'linear' to the human's eye. I.e. a white dot with rgb(128,128,128) would seem to be at 50% brightness between rgb(0,0,0) and rgb(255,255,255). Normally you would like to keep this enabled by default. Not only it makes brightness control "linear", it also makes colours more vivid, otherwise it looks brighter but 'bleached'.|You might want to turn it off in some special cases like: <ul><li>Using some other overlay lib for intermediate calculations that makes it's own compensation, like FastLED's [dimming functions](http://fastled.io/docs/3.1/group___dimming.html).<li>running at low colour depth's - it **might** (or might not) look better in shadows, darker gradients w/o compensation, try it<li>you run for as bright output as possible, no matter what (make sure you have proper powering)<li>you run for speed/save resources at all costs</ul> |
|
||||
| **FORCE_COLOR_DEPTH** |In some cases the library may reduce colour fidelity to increase the refresh rate (i.e. reduce visible flicker). This is most likely to occur with a large chain of panels. However, if you want to force pure 24bpp colour, at the expense of likely noticeable flicker, then set this defined. |Not required in 99% of cases.
|
||||
| **SPIRAM_FRAMEBUFFER** |Use SPIRAM/PSRAM for the HUB75 DMA buffer and not internal SRAM. ONLY SUPPORTED ON ESP32-S3 VARIANTS WITH OCTAL (not quad!) SPIRAM/PSRAM, as ony OCTAL PSRAM an provide the required data rate / bandwidth to drive the panels adequately.|ONLY SUPPORTED ON ESP32-S3 VARIANTS WITH OCTAL (not quad) SPIRAM/PSRAM
|
||||
|
||||
## Build-time variables
|
||||
|
||||
| Flag | Description | Note |
|
||||
| :------------ |---------------|-----|
|
||||
| **PIXEL_COLOR_DEPTH_BITS=8** | Colour depth per pixel in range 2-8. More bit's - more natural colour. But on the other hand every additional bit:<ul><li>eats ~2.5 bits of DMA memory per pixel<li>reduces matrix refresh rate in power of two due to nature of [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm)</ul> | For large chains of panels (i.e. 6 x 64x64 panels) you WILL need to reduce the colour depth, or likely run out of memory. Default is 8 bits per colour per pixel, i.e. True colour 24 bit RGB. <br><br>For higher resolutions, from 64x64 and above it is not possible to provide full 24 bits colour without significant flickering OR reducing dynamic range in shadows. In that case using 5-6 bits at high res make very small difference to the human’s eye actually. Refer to the [I2S memcalc](i2s_memcalc.md) for more details.
|
||||
|
After Width: | Height: | Size: 111 KiB |
@@ -0,0 +1,27 @@
|
||||
## Estimating fillrate
|
||||
|
||||
Here are some results of simple tests on filling DMA buffer with data.
|
||||
Filling DMA buffer requires lots of memory operations on a bit level rather than doing simple byte/word wide store and copy. And it looks like it's quite a task both for esp32 core and compiler.
|
||||
I've done this while optimizing loops and bit logic along with testing compiler results.
|
||||
|
||||
So the testbed is:
|
||||
- Matrix modules: 4 x FM6126A based 64x64 modules chained in 256x64
|
||||
|
||||
A testpatterns sketch:
|
||||
- allocating single DMA buffs for 256x64
|
||||
- allocating (NUM_LEDS*3) bytes for CRGB buffer
|
||||
- measuring microseconds for the following calls:
|
||||
- clearScreen() - full blanking
|
||||
- fillScreenRGB888() with monochrome/gray colors
|
||||
- fill screen using drawPixel()
|
||||
- filling some gradient into CRGB buff
|
||||
- painting CRGB buff into DMA buff with looped drawPixelRGB888()
|
||||
- drawing lines
|
||||
|
||||
|
||||
||clearScreen()|drawPixelRGB888(), ticks|fillScreen()|fillScreen with a drawPixel()|fillRect() over Matrix|V-line with drawPixel|fast-V-line|H-line with drawPixel|fast-H-line|
|
||||
|--|--|--|--|--|--|--|--|--|--|
|
||||
|v1.2.4|1503113 ticks|9244 non-cached, 675 cached|1719 us, 412272 t|47149 us, 11315418 ticks|-|24505 us, 5880209 ticks|-|24200 us|-|
|
||||
|FastLines|1503113 ticks|1350 non-cached, 405 cached|1677 us, 401198 t|28511 us, 6841440 ticks|10395 us|14462 us, 3469605 ticks|10391 us, 2492743 ticks|14575 us|5180 us, 1242041 ticks|
|
||||
|
||||
to be continued...
|
||||
|
After Width: | Height: | Size: 71 KiB |
@@ -0,0 +1,40 @@
|
||||
### Memory Calculator
|
||||
|
||||
I've made this [spreadsheet](memcalc.xlsm) to estimate all of the main parameters for ESP32-HUB75-MatrixPanel-DMA lib driving any combination of matrices/chains so that I do not need to reflash it hundreds of times just to check for the debug info about memory.
|
||||
Be sure to enable embedded macro's to allow refresh rate calculations.
|
||||
|
||||

|
||||
Just fill-in all of the INPUT fields and get the OUTPUTs.
|
||||
|
||||
So there are two main resources used to drive LED matrix
|
||||
- Memory
|
||||
- Bus clock speed (resulting in available bandwidth to pump pixel color data)
|
||||
|
||||
And there are lot's of hogs for those:
|
||||
- matrix resolution (number of pixels)
|
||||
- number of modules in chain
|
||||
- pixel color depth
|
||||
- [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm) LSB to MSB transition
|
||||
- double buffering
|
||||
|
||||
Equalising ones with the others results in **Refresh rate**,
|
||||
|
||||
or (rough approximation)
|
||||
<img src="https://render.githubusercontent.com/render/math?math=RefreshRate=\frac{%20I%20^2S%20_%20{clock}%20}{resolution%20\times%20chain%20\times%20(ColorDepth-LSB2MSB)}">
|
||||
|
||||
[//]: # (github markdown does not like LaTex formulas)
|
||||
[//]: # ($$RefreshRate=\frac{resolution \times chain \times (ColorDepth-LSB2MSB)}{ I ^2S _ {clock} }$$)
|
||||
|
||||
So, how to find optimum balance for all of these? Obviously you can't change *resolution* and *chain length*, it is physical characteristics and there is not much you can do about it except cutting off your chain or pushing it to the memory limits.
|
||||
|
||||
There are 3 parameters you can choose from (actually two:)
|
||||
- **Color Depth** - predefined at [build-time]((/doc/BuildOptions.md)) option
|
||||
|
||||
- I2S clock speed - run-time tunable with a very limited options
|
||||
|
||||
- **LSB-to-MSB** transition - it can't be controlled in any way, library uses it internally trying to balance all of the above
|
||||
|
||||
Using provided table it is possible to estimate all of the parameters before running the library. Besides calculating memory requirements it could help to find **optimum color depth** for your matrix configuration. For higher resolutions default 8 bits could be too much to sustain minimal refresh rate and avoid annoying flickering. So the library would increase MSB transition to keep the balance, thus reducing dynamic range in shadows and dark colors. As a result it is nearly almost the same as just reducing overall color depth. **But** reducing global color depth would also save lot's of precious RAM!
|
||||
Now it's all up to you to decide :)
|
||||
|
||||
/Vortigont/
|
||||
@@ -0,0 +1,166 @@
|
||||
|
||||
// Example sketch which shows how to display some patterns
|
||||
// on a 64x32 LED matrix
|
||||
//
|
||||
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
|
||||
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another
|
||||
|
||||
//MatrixPanel_I2S_DMA dma_display;
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
||||
uint16_t myBLACK = dma_display->color565(0, 0, 0);
|
||||
uint16_t myWHITE = dma_display->color565(255, 255, 255);
|
||||
uint16_t myRED = dma_display->color565(255, 0, 0);
|
||||
uint16_t myGREEN = dma_display->color565(0, 255, 0);
|
||||
uint16_t myBLUE = dma_display->color565(0, 0, 255);
|
||||
|
||||
|
||||
|
||||
// Input a value 0 to 255 to get a color value.
|
||||
// The colours are a transition r - g - b - back to r.
|
||||
// From: https://gist.github.com/davidegironi/3144efdc6d67e5df55438cc3cba613c8
|
||||
uint16_t colorWheel(uint8_t pos) {
|
||||
if(pos < 85) {
|
||||
return dma_display->color565(pos * 3, 255 - pos * 3, 0);
|
||||
} else if(pos < 170) {
|
||||
pos -= 85;
|
||||
return dma_display->color565(255 - pos * 3, 0, pos * 3);
|
||||
} else {
|
||||
pos -= 170;
|
||||
return dma_display->color565(0, pos * 3, 255 - pos * 3);
|
||||
}
|
||||
}
|
||||
|
||||
void drawText(int colorWheelOffset)
|
||||
{
|
||||
|
||||
// draw text with a rotating colour
|
||||
dma_display->setTextSize(1); // size 1 == 8 pixels high
|
||||
dma_display->setTextWrap(false); // Don't wrap at end of line - will do ourselves
|
||||
|
||||
dma_display->setCursor(5, 0); // start at top left, with 8 pixel of spacing
|
||||
uint8_t w = 0;
|
||||
const char *str = "ESP32 DMA";
|
||||
for (w=0; w<strlen(str); w++) {
|
||||
dma_display->setTextColor(colorWheel((w*32)+colorWheelOffset));
|
||||
dma_display->print(str[w]);
|
||||
}
|
||||
|
||||
dma_display->println();
|
||||
dma_display->print(" ");
|
||||
for (w=9; w<18; w++) {
|
||||
dma_display->setTextColor(colorWheel((w*32)+colorWheelOffset));
|
||||
dma_display->print("*");
|
||||
}
|
||||
|
||||
dma_display->println();
|
||||
|
||||
dma_display->setTextColor(dma_display->color444(15,15,15));
|
||||
dma_display->println("LED MATRIX!");
|
||||
|
||||
// print each letter with a fixed rainbow color
|
||||
dma_display->setTextColor(dma_display->color444(0,8,15));
|
||||
dma_display->print('3');
|
||||
dma_display->setTextColor(dma_display->color444(15,4,0));
|
||||
dma_display->print('2');
|
||||
dma_display->setTextColor(dma_display->color444(15,15,0));
|
||||
dma_display->print('x');
|
||||
dma_display->setTextColor(dma_display->color444(8,15,0));
|
||||
dma_display->print('6');
|
||||
dma_display->setTextColor(dma_display->color444(8,0,15));
|
||||
dma_display->print('4');
|
||||
|
||||
// Jump a half character
|
||||
dma_display->setCursor(34, 24);
|
||||
dma_display->setTextColor(dma_display->color444(0,15,15));
|
||||
dma_display->print("*");
|
||||
dma_display->setTextColor(dma_display->color444(15,0,0));
|
||||
dma_display->print('R');
|
||||
dma_display->setTextColor(dma_display->color444(0,15,0));
|
||||
dma_display->print('G');
|
||||
dma_display->setTextColor(dma_display->color444(0,0,15));
|
||||
dma_display->print("B");
|
||||
dma_display->setTextColor(dma_display->color444(15,0,8));
|
||||
dma_display->println("*");
|
||||
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
|
||||
// Module configuration
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN // Chain length
|
||||
);
|
||||
|
||||
//mxconfig.gpio.e = 18;
|
||||
//mxconfig.clkphase = false;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
|
||||
// Display Setup
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
dma_display->begin();
|
||||
dma_display->setBrightness8(90); //0-255
|
||||
dma_display->clearScreen();
|
||||
dma_display->fillScreen(myWHITE);
|
||||
|
||||
// fix the screen with green
|
||||
dma_display->fillRect(0, 0, dma_display->width(), dma_display->height(), dma_display->color444(0, 15, 0));
|
||||
delay(500);
|
||||
|
||||
// draw a box in yellow
|
||||
dma_display->drawRect(0, 0, dma_display->width(), dma_display->height(), dma_display->color444(15, 15, 0));
|
||||
delay(500);
|
||||
|
||||
// draw an 'X' in red
|
||||
dma_display->drawLine(0, 0, dma_display->width()-1, dma_display->height()-1, dma_display->color444(15, 0, 0));
|
||||
dma_display->drawLine(dma_display->width()-1, 0, 0, dma_display->height()-1, dma_display->color444(15, 0, 0));
|
||||
delay(500);
|
||||
|
||||
// draw a blue circle
|
||||
dma_display->drawCircle(10, 10, 10, dma_display->color444(0, 0, 15));
|
||||
delay(500);
|
||||
|
||||
// fill a violet circle
|
||||
dma_display->fillCircle(40, 21, 10, dma_display->color444(15, 0, 15));
|
||||
delay(500);
|
||||
|
||||
// fill the screen with 'black'
|
||||
dma_display->fillScreen(dma_display->color444(0, 0, 0));
|
||||
|
||||
//drawText(0);
|
||||
|
||||
}
|
||||
|
||||
uint8_t wheelval = 0;
|
||||
void loop() {
|
||||
|
||||
// animate by going through the colour wheel for the first two lines
|
||||
drawText(wheelval);
|
||||
wheelval +=1;
|
||||
|
||||
delay(20);
|
||||
/*
|
||||
drawText(0);
|
||||
delay(2000);
|
||||
dma_display->clearScreen();
|
||||
dma_display->fillScreen(myBLACK);
|
||||
delay(2000);
|
||||
dma_display->fillScreen(myBLUE);
|
||||
delay(2000);
|
||||
dma_display->fillScreen(myRED);
|
||||
delay(2000);
|
||||
dma_display->fillScreen(myGREEN);
|
||||
delay(2000);
|
||||
dma_display->fillScreen(myWHITE);
|
||||
dma_display->clearScreen();
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Portions of this code are adapted from Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from LedEffects Plasma by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Plasma.cpp?at=default
|
||||
* Copyright (c) 2013 Robert Atkins
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
// HUB75E pinout
|
||||
// R1 | G1
|
||||
// B1 | GND
|
||||
// R2 | G2
|
||||
// B2 | E
|
||||
// A | B
|
||||
// C | D
|
||||
// CLK| LAT
|
||||
// OE | GND
|
||||
|
||||
/* Default library pin configuration for the reference
|
||||
you can redefine only ones you need later on object creation
|
||||
|
||||
#define R1 25
|
||||
#define G1 26
|
||||
#define BL1 27
|
||||
#define R2 14
|
||||
#define G2 12
|
||||
#define BL2 13
|
||||
#define CH_A 23
|
||||
#define CH_B 19
|
||||
#define CH_C 5
|
||||
#define CH_D 17
|
||||
#define CH_E -1 // assign to any available pin if using two panels or 64x64 panels with 1/32 scan
|
||||
#define CLK 16
|
||||
#define LAT 4
|
||||
#define OE 15
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
#include <FastLED.h>
|
||||
|
||||
// Configure for your panel(s) as appropriate!
|
||||
#define PANEL_WIDTH 64
|
||||
#define PANEL_HEIGHT 64 // Panel height of 64 will required PIN_E to be defined.
|
||||
#define PANELS_NUMBER 2 // Number of chained panels, if just a single panel, obviously set to 1
|
||||
#define PIN_E 32
|
||||
|
||||
#define PANE_WIDTH PANEL_WIDTH * PANELS_NUMBER
|
||||
#define PANE_HEIGHT PANEL_HEIGHT
|
||||
|
||||
|
||||
// placeholder for the matrix object
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
||||
|
||||
uint16_t time_counter = 0, cycles = 0, fps = 0;
|
||||
unsigned long fps_timer;
|
||||
|
||||
CRGB currentColor;
|
||||
CRGBPalette16 palettes[] = {HeatColors_p, LavaColors_p, RainbowColors_p, RainbowStripeColors_p, CloudColors_p};
|
||||
CRGBPalette16 currentPalette = palettes[0];
|
||||
|
||||
|
||||
CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) {
|
||||
return ColorFromPalette(currentPalette, index, brightness, blendType);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println(F("*****************************************************"));
|
||||
Serial.println(F("* ESP32-HUB75-MatrixPanel-I2S-DMA DEMO *"));
|
||||
Serial.println(F("*****************************************************"));
|
||||
|
||||
/*
|
||||
The configuration for MatrixPanel_I2S_DMA object is held in HUB75_I2S_CFG structure,
|
||||
pls refer to the lib header file for full details.
|
||||
All options has it's predefined default values. So we can create a new structure and redefine only the options we need
|
||||
|
||||
// those are the defaults
|
||||
mxconfig.mx_width = 64; // physical width of a single matrix panel module (in pixels, usually it is always 64 ;) )
|
||||
mxconfig.mx_height = 32; // physical height of a single matrix panel module (in pixels, usually almost always it is either 32 or 64)
|
||||
mxconfig.chain_length = 1; // number of chained panels regardless of the topology, default 1 - a single matrix module
|
||||
mxconfig.gpio.r1 = R1; // pin mappings
|
||||
mxconfig.gpio.g1 = G1;
|
||||
mxconfig.gpio.b1 = B1; // etc
|
||||
mxconfig.driver = HUB75_I2S_CFG::SHIFT; // shift reg driver, default is plain shift register
|
||||
mxconfig.double_buff = false; // use double buffer (twice amount of RAM required)
|
||||
mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_10M;// I2S clock speed, better leave as-is unless you want to experiment
|
||||
*/
|
||||
|
||||
/*
|
||||
For example we have two 64x64 panels chained, so we need to customize our setup like this
|
||||
|
||||
*/
|
||||
HUB75_I2S_CFG mxconfig;
|
||||
mxconfig.mx_height = PANEL_HEIGHT; // we have 64 pix heigh panels
|
||||
mxconfig.chain_length = PANELS_NUMBER; // we have 2 panels chained
|
||||
mxconfig.gpio.e = PIN_E; // we MUST assign pin e to some free pin on a board to drive 64 pix height panels with 1/32 scan
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6126A; // in case that we use panels based on FM6126A chip, we can change that
|
||||
|
||||
/*
|
||||
//Another way of creating config structure
|
||||
//Custom pin mapping for all pins
|
||||
HUB75_I2S_CFG::i2s_pins _pins={R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK};
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
64, // width
|
||||
64, // height
|
||||
4, // chain length
|
||||
_pins, // pin mapping
|
||||
HUB75_I2S_CFG::FM6126A // driver chip
|
||||
);
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// OK, now we can create our matrix object
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
|
||||
// let's adjust default brightness to about 75%
|
||||
dma_display->setBrightness8(192); // range is 0-255, 0 - 0%, 255 - 100%
|
||||
|
||||
// Allocate memory and start DMA display
|
||||
if( not dma_display->begin() )
|
||||
Serial.println("****** !KABOOM! I2S memory allocation failed ***********");
|
||||
|
||||
// well, hope we are OK, let's draw some colors first :)
|
||||
Serial.println("Fill screen: RED");
|
||||
dma_display->fillScreenRGB888(255, 0, 0);
|
||||
delay(1000);
|
||||
|
||||
Serial.println("Fill screen: GREEN");
|
||||
dma_display->fillScreenRGB888(0, 255, 0);
|
||||
delay(1000);
|
||||
|
||||
Serial.println("Fill screen: BLUE");
|
||||
dma_display->fillScreenRGB888(0, 0, 255);
|
||||
delay(1000);
|
||||
|
||||
Serial.println("Fill screen: Neutral White");
|
||||
dma_display->fillScreenRGB888(64, 64, 64);
|
||||
delay(1000);
|
||||
|
||||
Serial.println("Fill screen: black");
|
||||
dma_display->fillScreenRGB888(0, 0, 0);
|
||||
delay(1000);
|
||||
|
||||
|
||||
// Set current FastLED palette
|
||||
currentPalette = RainbowColors_p;
|
||||
Serial.println("Starting plasma effect...");
|
||||
fps_timer = millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
for (int x = 0; x < PANE_WIDTH; x++) {
|
||||
for (int y = 0; y < PANE_HEIGHT; y++) {
|
||||
int16_t v = 0;
|
||||
uint8_t wibble = sin8(time_counter);
|
||||
v += sin16(x * wibble * 3 + time_counter);
|
||||
v += cos16(y * (128 - wibble) + time_counter);
|
||||
v += sin16(y * x * cos8(-time_counter) / 8);
|
||||
|
||||
currentColor = ColorFromPalette(currentPalette, (v >> 8) + 127); //, brightness, currentBlendType);
|
||||
dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b);
|
||||
}
|
||||
}
|
||||
|
||||
++time_counter;
|
||||
++cycles;
|
||||
++fps;
|
||||
|
||||
if (cycles >= 1024) {
|
||||
time_counter = 0;
|
||||
cycles = 0;
|
||||
currentPalette = palettes[random(0,sizeof(palettes)/sizeof(palettes[0]))];
|
||||
}
|
||||
|
||||
// print FPS rate every 5 seconds
|
||||
// Note: this is NOT a matrix refresh rate, it's the number of data frames being drawn to the DMA buffer per second
|
||||
if (fps_timer + 5000 < millis()){
|
||||
Serial.printf_P(PSTR("Effect fps: %d\n"), fps/5);
|
||||
fps_timer = millis();
|
||||
fps = 0;
|
||||
}
|
||||
} // end loop
|
||||
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,5 @@
|
||||
# Wave Pattern
|
||||
|
||||
Demo of the colours, and the little flicker.
|
||||
|
||||

|
||||
@@ -0,0 +1,90 @@
|
||||
// Example uses the following configuration: mxconfig.double_buff = true;
|
||||
// to enable double buffering, which means display->flipDMABuffer(); is required.
|
||||
|
||||
// Bounce squares around the screen, doing the re-drawing in the background back-buffer.
|
||||
// Double buffering is not always required in reality.
|
||||
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
|
||||
MatrixPanel_I2S_DMA *display = nullptr;
|
||||
|
||||
uint16_t myDARK = display->color565(64, 64, 64);
|
||||
uint16_t myWHITE = display->color565(192, 192, 192);
|
||||
uint16_t myRED = display->color565(255, 0, 0);
|
||||
uint16_t myGREEN = display->color565(0, 255, 0);
|
||||
uint16_t myBLUE = display->color565(0, 0, 255);
|
||||
|
||||
uint16_t colours[5] = { myDARK, myWHITE, myRED, myGREEN, myBLUE };
|
||||
|
||||
struct Square
|
||||
{
|
||||
float xpos, ypos;
|
||||
float velocityx;
|
||||
float velocityy;
|
||||
boolean xdir, ydir;
|
||||
uint16_t square_size;
|
||||
uint16_t colour;
|
||||
};
|
||||
|
||||
const int numSquares = 25;
|
||||
Square Squares[numSquares];
|
||||
|
||||
void setup()
|
||||
{
|
||||
// put your setup code here, to run once:
|
||||
delay(1000);
|
||||
Serial.begin(115200);
|
||||
delay(200);
|
||||
|
||||
Serial.println("...Starting Display");
|
||||
HUB75_I2S_CFG mxconfig;
|
||||
mxconfig.double_buff = true; // <------------- Turn on double buffer
|
||||
//mxconfig.clkphase = false;
|
||||
|
||||
// OK, now we can create our matrix object
|
||||
display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
display->begin(); // setup display with pins as pre-defined in the library
|
||||
|
||||
// Create some random squares
|
||||
for (int i = 0; i < numSquares; i++)
|
||||
{
|
||||
Squares[i].square_size = random(2,10);
|
||||
Squares[i].xpos = random(0, display->width() - Squares[i].square_size);
|
||||
Squares[i].ypos = random(0, display->height() - Squares[i].square_size);
|
||||
Squares[i].velocityx = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
|
||||
Squares[i].velocityy = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
|
||||
|
||||
int random_num = random(6);
|
||||
Squares[i].colour = colours[random_num];
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels)
|
||||
display->clearScreen(); // Now clear the back-buffer
|
||||
|
||||
delay(16); // <----------- Shouldn't see this clearscreen occur as it happens on the back buffer when double buffering is enabled.
|
||||
|
||||
for (int i = 0; i < numSquares; i++)
|
||||
{
|
||||
// Draw rect and then calculate
|
||||
display->fillRect(Squares[i].xpos, Squares[i].ypos, Squares[i].square_size, Squares[i].square_size, Squares[i].colour);
|
||||
|
||||
if (Squares[i].square_size + Squares[i].xpos >= display->width()) {
|
||||
Squares[i].velocityx *= -1;
|
||||
} else if (Squares[i].xpos <= 0) {
|
||||
Squares[i].velocityx = abs (Squares[i].velocityx);
|
||||
}
|
||||
|
||||
if (Squares[i].square_size + Squares[i].ypos >= display->height()) {
|
||||
Squares[i].velocityy *= -1;
|
||||
} else if (Squares[i].ypos <= 0) {
|
||||
Squares[i].velocityy = abs (Squares[i].velocityy);
|
||||
}
|
||||
|
||||
Squares[i].xpos += Squares[i].velocityx;
|
||||
Squares[i].ypos += Squares[i].velocityy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**********************************************************************
|
||||
* The library by default supports simple 'shift register' based panels
|
||||
* with A,B,C,D,E lines to select a specific row, but there are plenty
|
||||
* of examples of new chips coming on the market that work different.
|
||||
*
|
||||
* Please search through the project's issues. For some of these chips
|
||||
* (you will need to look at the back of your panel to identify), this
|
||||
* library has workarounds. This can be configured through using one of:
|
||||
|
||||
// mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::ICN2038S;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6124;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::MBI5124;
|
||||
*/
|
||||
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
#include <FastLED.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Output resolution and panel chain length configuration
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another
|
||||
|
||||
// placeholder for the matrix object
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
// FastLED variables for pattern output
|
||||
uint16_t time_counter = 0, cycles = 0, fps = 0;
|
||||
unsigned long fps_timer;
|
||||
|
||||
CRGB currentColor;
|
||||
CRGBPalette16 palettes[] = {HeatColors_p, LavaColors_p, RainbowColors_p, RainbowStripeColors_p, CloudColors_p};
|
||||
CRGBPalette16 currentPalette = palettes[0];
|
||||
|
||||
|
||||
CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) {
|
||||
return ColorFromPalette(currentPalette, index, brightness, blendType);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN // Chain length
|
||||
);
|
||||
|
||||
// in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::ICN2038S;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6124;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::MBI5124;
|
||||
|
||||
|
||||
// OK, now we can create our matrix object
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
|
||||
// If you experience ghosting, you will need to reduce the brightness level, not all RGB Matrix
|
||||
// Panels are the same - some seem to display ghosting artefacts at lower brightness levels.
|
||||
// In the setup() function do something like:
|
||||
|
||||
// let's adjust default brightness to about 75%
|
||||
dma_display->setBrightness8(192); // range is 0-255, 0 - 0%, 255 - 100%
|
||||
|
||||
// Allocate memory and start DMA display
|
||||
if( not dma_display->begin() )
|
||||
Serial.println("****** !KABOOM! Insufficient memory - allocation failed ***********");
|
||||
|
||||
fps_timer = millis();
|
||||
|
||||
}
|
||||
|
||||
void loop(){
|
||||
for (int x = 0; x < dma_display->width(); x++) {
|
||||
for (int y = 0; y < dma_display->height(); y++) {
|
||||
int16_t v = 0;
|
||||
uint8_t wibble = sin8(time_counter);
|
||||
v += sin16(x * wibble * 3 + time_counter);
|
||||
v += cos16(y * (128 - wibble) + time_counter);
|
||||
v += sin16(y * x * cos8(-time_counter) / 8);
|
||||
|
||||
currentColor = ColorFromPalette(currentPalette, (v >> 8) + 127); //, brightness, currentBlendType);
|
||||
dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b);
|
||||
}
|
||||
}
|
||||
|
||||
++time_counter;
|
||||
++cycles;
|
||||
++fps;
|
||||
|
||||
if (cycles >= 1024) {
|
||||
time_counter = 0;
|
||||
cycles = 0;
|
||||
currentPalette = palettes[random(0,sizeof(palettes)/sizeof(palettes[0]))];
|
||||
}
|
||||
|
||||
// print FPS rate every 5 seconds
|
||||
// Note: this is NOT a matrix refresh rate, it's the number of data frames being drawn to the DMA buffer per second
|
||||
if (fps_timer + 5000 < millis()){
|
||||
Serial.printf_P(PSTR("Effect fps: %d\n"), fps/5);
|
||||
fps_timer = millis();
|
||||
fps = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FM6126 panel , thanks goes to:
|
||||
// https://github.com/hzeller/rpi-rgb-led-matrix/issues/746
|
||||
@@ -0,0 +1,51 @@
|
||||
## The mystery of control registers for FM6126A chips
|
||||
|
||||
|
||||
The only available Datasheet for this chips is in Chinese and does not shed a light on what those two control regs are.
|
||||
|
||||
An excellent insight could be found here https://github.com/hzeller/rpi-rgb-led-matrix/issues/746#issuecomment-453860510
|
||||
|
||||
|
||||
|
||||
So there are two regs in this chip - **REG1** and **REG2**,
|
||||
one could be written with 12 clock pulses (and usually called reg12, dunno why :))
|
||||
the other one could be written with 13 clock pulses (and usually called reg13, dunno why :))
|
||||
|
||||
|
||||
I've done some measurements on power consumption while toggling bits of **REG1** and it looks that it could provide a fine grained brightness control over the entire matrix with no need for bitbanging over RGB or EO pins.
|
||||
There are 6 bits (6 to 11) giving an increased brightness (compared to all-zeroes) and 4 bits (2-5) giving decreased brightness!!!
|
||||
Still unclear if FM6112A brightness control is internally PWMed or current limited, might require some poking with oscilloscope.
|
||||
|
||||
So it seems that the most bright (and hungry for power) value is bool REG1[16] = {0,0,0,0,0, 1,1,1,1,1,1, 0,0,0,0,0}; and not {0,1,1,1,1, 1,1,1,1,1,1, 1,1,1,1,1} as it is usually used.
|
||||
I'm not sure about bit 1 - it is either not used or I was unable to measure it's influence to brightness/power.
|
||||
|
||||
Giving at least 10 bits of hardware brightness control opens pretty nice options for offloading and simplifying matrix output. Should dig into this more deeper.
|
||||
|
||||
Here are some of the measurements I've took for 2 64x64 panels filled with white color - reg value and corresponding current drain in amps.
|
||||
|
||||
|
||||
|REG1 |bit value|Current, amps |
|
||||
|--|--|--|
|
||||
|REG1| 0111111 00000| >5 amps|
|
||||
|REG1| 0100010 00000| 3.890 amp|
|
||||
|REG1| 0100000 00000| 3.885 amp|
|
||||
|REG1| 0011110 00000| 3.640 amp|
|
||||
|REG1| 0011100 00000| 3.620 amp|
|
||||
|REG1| 0011000 00000| 3.240 amp|
|
||||
|REG1| 0010010 00000| 2.520 amp|
|
||||
|REG1| 0010001 00000| 2.518 amp|
|
||||
|REG1| 0010001 10000| 2.493 amp|
|
||||
|REG1| 0010000 00000| 2.490 amp|
|
||||
|REG1| 0010000 11110| 2.214 amp|
|
||||
|REG1| 0001100 00000| 2.120 amp|
|
||||
|REG1| 0001000 00000| 1.750 amp|
|
||||
|REG1| 0000100 00000| 1.375 amp|
|
||||
|REG1| 0000010 00000| 1.000 amp|
|
||||
|REG1| **0000000 00000**| 0.995 amp|
|
||||
|REG1| 0000001 11111| 0.700 amp|
|
||||
|REG1| 0000000 01111| 0.690 amp|
|
||||
|REG1| 0000000 10000| 0.690 amp|
|
||||
|REG1| 0000000 11110| 0.686 amp|
|
||||
|
||||
|
||||
/Vortigont/
|
||||
@@ -0,0 +1,13 @@
|
||||
## Ohter driver based LED Matrix Panels ##
|
||||
|
||||
Limited support for other panels exists, but requires this to be passed as a configuration option when using the library.
|
||||
|
||||
These panels require a special reset sequence before they can be used, check your panel chipset if you have issues. Refer to the example.
|
||||
|
||||
|
||||
```
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
mxconfig.driver = HUB75_I2S_CFG::ICN2038S;
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6124;
|
||||
mxconfig.driver = HUB75_I2S_CFG::MBI5124;
|
||||
```
|
||||
@@ -0,0 +1,268 @@
|
||||
/*********************************************************************
|
||||
* AnimatedGif LED Matrix Panel example where the GIFs are
|
||||
* stored on a SD card connected to the ESP32 using the
|
||||
* standard GPIO pins used for SD card acces via. SPI.
|
||||
*
|
||||
* Put the gifs into a directory called 'gifs' (case sensitive) on
|
||||
* a FAT32 formatted SDcard.
|
||||
********************************************************************/
|
||||
#include "FS.h"
|
||||
#include "SD.h"
|
||||
#include "SPI.h"
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
#include <AnimatedGIF.h>
|
||||
|
||||
/********************************************************************
|
||||
* Pin mapping below is for LOLIN D32 (ESP 32)
|
||||
*
|
||||
* Default pin mapping used by this library is NOT compatable with the use of the
|
||||
* ESP32-Arduino 'SD' card library (there is overlap). As such, some of the pins
|
||||
* used for the HUB75 panel need to be shifted.
|
||||
*
|
||||
* 'SD' card library requires GPIO 23, 18 and 19
|
||||
* https://github.com/espressif/arduino-esp32/tree/master/libraries/SD
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Connect the SD card to the following pins:
|
||||
*
|
||||
* SD Card | ESP32
|
||||
* D2 -
|
||||
* D3 SS
|
||||
* CMD MOSI
|
||||
* VSS GND
|
||||
* VDD 3.3V
|
||||
* CLK SCK
|
||||
* VSS GND
|
||||
* D0 MISO
|
||||
* D1 -
|
||||
*/
|
||||
|
||||
/**** SD Card GPIO mappings ****/
|
||||
#define SS_PIN 5
|
||||
//#define MOSI_PIN 23
|
||||
//#define MISO_PIN 19
|
||||
//#define CLK_PIN 18
|
||||
|
||||
|
||||
/**** HUB75 GPIO mapping ****/
|
||||
// GPIO 34+ are on the ESP32 are input only!!
|
||||
// https://randomnerdtutorials.com/esp32-pinout-reference-gpios/
|
||||
|
||||
#define A_PIN 33 // remap esp32 library default from 23 to 33
|
||||
#define B_PIN 32 // remap esp32 library default from 19 to 32
|
||||
#define C_PIN 22 // remap esp32 library defaultfrom 5 to 22
|
||||
|
||||
//#define R1_PIN 25 // library default for the esp32, unchanged
|
||||
//#define G1_PIN 26 // library default for the esp32, unchanged
|
||||
//#define B1_PIN 27 // library default for the esp32, unchanged
|
||||
//#define R2_PIN 14 // library default for the esp32, unchanged
|
||||
//#define G2_PIN 12 // library default for the esp32, unchanged
|
||||
//#define B2_PIN 13 // library default for the esp32, unchanged
|
||||
//#define D_PIN 17 // library default for the esp32, unchanged
|
||||
//#define E_PIN -1 // IMPORTANT: Change to a valid pin if using a 64x64px panel.
|
||||
|
||||
//#define LAT_PIN 4 // library default for the esp32, unchanged
|
||||
//#define OE_PIN 15 // library default for the esp32, unchanged
|
||||
//#define CLK_PIN 16 // library default for the esp32, unchanged
|
||||
|
||||
/***************************************************************
|
||||
* HUB 75 LED DMA Matrix Panel Configuration
|
||||
**************************************************************/
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
AnimatedGIF gif;
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
||||
static int totalFiles = 0; // GIF files count
|
||||
|
||||
static File FSGifFile; // temp gif file holder
|
||||
static File GifRootFolder; // directory listing
|
||||
|
||||
std::vector<std::string> GifFiles; // GIF files path
|
||||
|
||||
const int maxGifDuration = 30000; // ms, max GIF duration
|
||||
|
||||
#include "gif_functions.hpp"
|
||||
#include "sdcard_functions.hpp"
|
||||
|
||||
|
||||
/**************************************************************/
|
||||
void draw_test_patterns();
|
||||
int gifPlay( const char* gifPath )
|
||||
{ // 0=infinite
|
||||
|
||||
if( ! gif.open( gifPath, GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw ) ) {
|
||||
log_n("Could not open gif %s", gifPath );
|
||||
}
|
||||
|
||||
Serial.print("Playing: "); Serial.println(gifPath);
|
||||
|
||||
int frameDelay = 0; // store delay for the last frame
|
||||
int then = 0; // store overall delay
|
||||
|
||||
while (gif.playFrame(true, &frameDelay)) {
|
||||
|
||||
then += frameDelay;
|
||||
if( then > maxGifDuration ) { // avoid being trapped in infinite GIF's
|
||||
//log_w("Broke the GIF loop, max duration exceeded");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gif.close();
|
||||
|
||||
return then;
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
// **************************** Setup SD Card access via SPI ****************************
|
||||
if(!SD.begin(SS_PIN)){
|
||||
// bool begin(uint8_t ssPin=SS, SPIClass &spi=SPI, uint32_t frequency=4000000, const char * mountpoint="/sd", uint8_t max_files=5, bool format_if_empty=false);
|
||||
Serial.println("Card Mount Failed");
|
||||
return;
|
||||
}
|
||||
uint8_t cardType = SD.cardType();
|
||||
|
||||
if(cardType == CARD_NONE){
|
||||
Serial.println("No SD card attached");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print("SD Card Type: ");
|
||||
if(cardType == CARD_MMC){
|
||||
Serial.println("MMC");
|
||||
} else if(cardType == CARD_SD){
|
||||
Serial.println("SDSC");
|
||||
} else if(cardType == CARD_SDHC){
|
||||
Serial.println("SDHC");
|
||||
} else {
|
||||
Serial.println("UNKNOWN");
|
||||
}
|
||||
|
||||
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
|
||||
Serial.printf("SD Card Size: %lluMB\n", cardSize);
|
||||
|
||||
//listDir(SD, "/", 1, false);
|
||||
|
||||
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
|
||||
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
|
||||
|
||||
|
||||
|
||||
// **************************** Setup DMA Matrix ****************************
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN // Chain length
|
||||
);
|
||||
|
||||
// Need to remap these HUB75 DMA pins because the SPI SDCard is using them.
|
||||
// Otherwise the SD Card will not work.
|
||||
mxconfig.gpio.a = A_PIN;
|
||||
mxconfig.gpio.b = B_PIN;
|
||||
mxconfig.gpio.c = C_PIN;
|
||||
// mxconfig.gpio.d = D_PIN;
|
||||
|
||||
//mxconfig.clkphase = false;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
|
||||
// Display Setup
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
|
||||
// Allocate memory and start DMA display
|
||||
if( not dma_display->begin() )
|
||||
Serial.println("****** !KABOOM! HUB75 memory allocation failed ***********");
|
||||
|
||||
dma_display->setBrightness8(128); //0-255
|
||||
dma_display->clearScreen();
|
||||
|
||||
|
||||
// **************************** Setup Sketch ****************************
|
||||
Serial.println("Starting AnimatedGIFs Sketch");
|
||||
|
||||
// SD CARD STOPS WORKING WITH DMA DISPLAY ENABLED>...
|
||||
|
||||
File root = SD.open("/gifs");
|
||||
if(!root){
|
||||
Serial.println("Failed to open directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while(file){
|
||||
if(!file.isDirectory())
|
||||
{
|
||||
Serial.print(" FILE: ");
|
||||
Serial.print(file.name());
|
||||
Serial.print(" SIZE: ");
|
||||
Serial.println(file.size());
|
||||
|
||||
std::string filename = "/gifs/" + std::string(file.name());
|
||||
Serial.println(filename.c_str());
|
||||
|
||||
GifFiles.push_back( filename );
|
||||
// Serial.println("Adding to gif list:" + String(filename));
|
||||
totalFiles++;
|
||||
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
|
||||
file.close();
|
||||
Serial.printf("Found %d GIFs to play.", totalFiles);
|
||||
//totalFiles = getGifInventory("/gifs");
|
||||
|
||||
|
||||
|
||||
// This is important - Set the right endianness.
|
||||
gif.begin(LITTLE_ENDIAN_PIXELS);
|
||||
|
||||
}
|
||||
|
||||
void loop(){
|
||||
|
||||
// Iterate over a vector using range based for loop
|
||||
for(auto & elem : GifFiles)
|
||||
{
|
||||
gifPlay( elem.c_str() );
|
||||
gif.reset();
|
||||
delay(500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void draw_test_patterns()
|
||||
{
|
||||
// fix the screen with green
|
||||
dma_display->fillRect(0, 0, dma_display->width(), dma_display->height(), dma_display->color444(0, 15, 0));
|
||||
delay(500);
|
||||
|
||||
// draw a box in yellow
|
||||
dma_display->drawRect(0, 0, dma_display->width(), dma_display->height(), dma_display->color444(15, 15, 0));
|
||||
delay(500);
|
||||
|
||||
// draw an 'X' in red
|
||||
dma_display->drawLine(0, 0, dma_display->width()-1, dma_display->height()-1, dma_display->color444(15, 0, 0));
|
||||
dma_display->drawLine(dma_display->width()-1, 0, 0, dma_display->height()-1, dma_display->color444(15, 0, 0));
|
||||
delay(500);
|
||||
|
||||
// draw a blue circle
|
||||
dma_display->drawCircle(10, 10, 10, dma_display->color444(0, 0, 15));
|
||||
delay(500);
|
||||
|
||||
// fill a violet circle
|
||||
dma_display->fillCircle(40, 21, 10, dma_display->color444(15, 0, 15));
|
||||
delay(500);
|
||||
delay(1000);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# ESP32-HUB75-MatrixPanel-DMA SDCard example
|
||||
|
||||
A very basic example using the 'Animated GIF' library by Larry Bank + the SD / File system library provided for Arduino by Espressif.
|
||||
|
||||
Some default HUB75 pins need to be remapped to accomodate for the SD Card.
|
||||
|
||||

|
||||
|
||||
## How to use it?
|
||||
|
||||
1. Format a SD Card with FAT32 file system (default setting)
|
||||
2. Create a directory called 'gifs'
|
||||
3. Drop your gifs in there. The resolution of the GIFS must match that of the display.
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 150 KiB |
@@ -0,0 +1,132 @@
|
||||
|
||||
// Code copied from AnimatedGIF examples
|
||||
|
||||
#ifndef M5STACK_SD
|
||||
// for custom ESP32 builds
|
||||
#define M5STACK_SD SD
|
||||
#endif
|
||||
|
||||
|
||||
static void * GIFOpenFile(const char *fname, int32_t *pSize)
|
||||
{
|
||||
//log_d("GIFOpenFile( %s )\n", fname );
|
||||
FSGifFile = M5STACK_SD.open(fname);
|
||||
if (FSGifFile) {
|
||||
*pSize = FSGifFile.size();
|
||||
return (void *)&FSGifFile;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void GIFCloseFile(void *pHandle)
|
||||
{
|
||||
File *f = static_cast<File *>(pHandle);
|
||||
if (f != NULL)
|
||||
f->close();
|
||||
}
|
||||
|
||||
|
||||
static int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen)
|
||||
{
|
||||
int32_t iBytesRead;
|
||||
iBytesRead = iLen;
|
||||
File *f = static_cast<File *>(pFile->fHandle);
|
||||
// Note: If you read a file all the way to the last byte, seek() stops working
|
||||
if ((pFile->iSize - pFile->iPos) < iLen)
|
||||
iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around
|
||||
if (iBytesRead <= 0)
|
||||
return 0;
|
||||
iBytesRead = (int32_t)f->read(pBuf, iBytesRead);
|
||||
pFile->iPos = f->position();
|
||||
return iBytesRead;
|
||||
}
|
||||
|
||||
|
||||
static int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition)
|
||||
{
|
||||
int i = micros();
|
||||
File *f = static_cast<File *>(pFile->fHandle);
|
||||
f->seek(iPosition);
|
||||
pFile->iPos = (int32_t)f->position();
|
||||
i = micros() - i;
|
||||
//log_d("Seek time = %d us\n", i);
|
||||
return pFile->iPos;
|
||||
}
|
||||
|
||||
|
||||
// Draw a line of image directly on the LCD
|
||||
void GIFDraw(GIFDRAW *pDraw)
|
||||
{
|
||||
uint8_t *s;
|
||||
uint16_t *d, *usPalette, usTemp[320];
|
||||
int x, y, iWidth;
|
||||
|
||||
iWidth = pDraw->iWidth;
|
||||
if (iWidth > PANEL_RES_X)
|
||||
iWidth = PANEL_RES_X;
|
||||
usPalette = pDraw->pPalette;
|
||||
y = pDraw->iY + pDraw->y; // current line
|
||||
|
||||
s = pDraw->pPixels;
|
||||
if (pDraw->ucDisposalMethod == 2) {// restore to background color
|
||||
for (x=0; x<iWidth; x++) {
|
||||
if (s[x] == pDraw->ucTransparent)
|
||||
s[x] = pDraw->ucBackground;
|
||||
}
|
||||
pDraw->ucHasTransparency = 0;
|
||||
}
|
||||
// Apply the new pixels to the main image
|
||||
if (pDraw->ucHasTransparency) { // if transparency used
|
||||
uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
|
||||
int x, iCount;
|
||||
pEnd = s + iWidth;
|
||||
x = 0;
|
||||
iCount = 0; // count non-transparent pixels
|
||||
while(x < iWidth) {
|
||||
c = ucTransparent-1;
|
||||
d = usTemp;
|
||||
while (c != ucTransparent && s < pEnd) {
|
||||
c = *s++;
|
||||
if (c == ucTransparent) { // done, stop
|
||||
s--; // back up to treat it like transparent
|
||||
} else { // opaque
|
||||
*d++ = usPalette[c];
|
||||
iCount++;
|
||||
}
|
||||
} // while looking for opaque pixels
|
||||
if (iCount) { // any opaque pixels?
|
||||
for(int xOffset = 0; xOffset < iCount; xOffset++ ){
|
||||
dma_display->drawPixel(x + xOffset, y, usTemp[xOffset]); // 565 Color Format
|
||||
}
|
||||
x += iCount;
|
||||
iCount = 0;
|
||||
}
|
||||
// no, look for a run of transparent pixels
|
||||
c = ucTransparent;
|
||||
while (c == ucTransparent && s < pEnd) {
|
||||
c = *s++;
|
||||
if (c == ucTransparent)
|
||||
iCount++;
|
||||
else
|
||||
s--;
|
||||
}
|
||||
if (iCount) {
|
||||
x += iCount; // skip these
|
||||
iCount = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s = pDraw->pPixels;
|
||||
// Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
|
||||
for (x=0; x<iWidth; x++)
|
||||
dma_display->drawPixel(x, y, usPalette[*s++]); // color 565
|
||||
/*
|
||||
usTemp[x] = usPalette[*s++];
|
||||
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
dma_display->drawPixel(x, y, usTemp[*s++]); // color 565
|
||||
} */
|
||||
|
||||
}
|
||||
} /* GIFDraw() */
|
||||
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,102 @@
|
||||
/************************ SD Card Code ************************/
|
||||
// As per: https://github.com/espressif/arduino-esp32/tree/master/libraries/SD/examples/SD_Test
|
||||
|
||||
|
||||
|
||||
void listDir(fs::FS &fs, const char * dirname, uint8_t levels, bool add_to_gif_list = false){
|
||||
Serial.printf("Listing directory: %s\n", dirname);
|
||||
|
||||
File root = fs.open(dirname);
|
||||
if(!root){
|
||||
Serial.println("Failed to open directory");
|
||||
return;
|
||||
}
|
||||
if(!root.isDirectory()){
|
||||
Serial.println("Not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while(file){
|
||||
if(file.isDirectory()){
|
||||
Serial.print(" DIR : ");
|
||||
Serial.println(file.name());
|
||||
if(levels){
|
||||
listDir(fs, file.path(), levels -1, false);
|
||||
}
|
||||
} else {
|
||||
Serial.print(" FILE: ");
|
||||
Serial.print(file.name());
|
||||
Serial.print(" SIZE: ");
|
||||
Serial.println(file.size());
|
||||
|
||||
if (add_to_gif_list && levels == 0)
|
||||
{
|
||||
GifFiles.push_back( std::string(dirname) + file.name() );
|
||||
Serial.println("Adding to gif list:" + String(dirname) +"/" + file.name());
|
||||
totalFiles++;
|
||||
}
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void readFile(fs::FS &fs, const char * path){
|
||||
Serial.printf("Reading file: %s\n", path);
|
||||
|
||||
File file = fs.open(path);
|
||||
if(!file){
|
||||
Serial.println("Failed to open file for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print("Read from file: ");
|
||||
while(file.available()){
|
||||
Serial.write(file.read());
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void testFileIO(fs::FS &fs, const char * path){
|
||||
File file = fs.open(path);
|
||||
static uint8_t buf[512];
|
||||
size_t len = 0;
|
||||
uint32_t start = millis();
|
||||
uint32_t end = start;
|
||||
if(file){
|
||||
len = file.size();
|
||||
size_t flen = len;
|
||||
start = millis();
|
||||
while(len){
|
||||
size_t toRead = len;
|
||||
if(toRead > 512){
|
||||
toRead = 512;
|
||||
}
|
||||
file.read(buf, toRead);
|
||||
len -= toRead;
|
||||
}
|
||||
end = millis() - start;
|
||||
Serial.printf("%u bytes read for %u ms\n", flen, end);
|
||||
file.close();
|
||||
} else {
|
||||
Serial.println("Failed to open file for reading");
|
||||
}
|
||||
|
||||
|
||||
file = fs.open(path, FILE_WRITE);
|
||||
if(!file){
|
||||
Serial.println("Failed to open file for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
start = millis();
|
||||
for(i=0; i<2048; i++){
|
||||
file.write(buf, 512);
|
||||
}
|
||||
end = millis() - start;
|
||||
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
|
||||
file.close();
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
// Example sketch which shows how to display a 64x32 animated GIF image stored in FLASH memory
|
||||
// on a 64x32 LED matrix
|
||||
//
|
||||
// Credits: https://github.com/bitbank2/AnimatedGIF/tree/master/examples/ESP32_LEDMatrix_I2S
|
||||
//
|
||||
|
||||
/* INSTRUCTIONS
|
||||
*
|
||||
* 1. First Run the 'ESP32 Sketch Data Upload Tool' in Arduino from the 'Tools' Menu.
|
||||
* - If you don't know what this is or see it as an option, then read this:
|
||||
* https://github.com/me-no-dev/arduino-esp32fs-plugin
|
||||
* - This tool will upload the contents of the data/ directory in the sketch folder onto
|
||||
* the ESP32 itself.
|
||||
*
|
||||
* 2. You can drop any animated GIF you want in there, but keep it to the resolution of the
|
||||
* MATRIX you're displaying to. To resize a gif, use this online website: https://ezgif.com/
|
||||
*
|
||||
* 3. Have fun.
|
||||
*/
|
||||
|
||||
#define FILESYSTEM SPIFFS
|
||||
#include <SPIFFS.h>
|
||||
#include <AnimatedGIF.h>
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
|
||||
// ----------------------------
|
||||
|
||||
/*
|
||||
* Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class.
|
||||
* i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives.
|
||||
* By default the library assumes a single 64x32 pixel panel is connected.
|
||||
*
|
||||
* Refer to the example '2_PatternPlasma' on the new / correct way to setup this library
|
||||
* for different resolutions / panel chain lengths within the sketch 'setup()'.
|
||||
*
|
||||
*/
|
||||
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another
|
||||
|
||||
//MatrixPanel_I2S_DMA dma_display;
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
||||
uint16_t myBLACK = dma_display->color565(0, 0, 0);
|
||||
uint16_t myWHITE = dma_display->color565(255, 255, 255);
|
||||
uint16_t myRED = dma_display->color565(255, 0, 0);
|
||||
uint16_t myGREEN = dma_display->color565(0, 255, 0);
|
||||
uint16_t myBLUE = dma_display->color565(0, 0, 255);
|
||||
|
||||
|
||||
AnimatedGIF gif;
|
||||
File f;
|
||||
int x_offset, y_offset;
|
||||
|
||||
|
||||
|
||||
// Draw a line of image directly on the LED Matrix
|
||||
void GIFDraw(GIFDRAW *pDraw)
|
||||
{
|
||||
uint8_t *s;
|
||||
uint16_t *d, *usPalette, usTemp[320];
|
||||
int x, y, iWidth;
|
||||
|
||||
iWidth = pDraw->iWidth;
|
||||
if (iWidth > MATRIX_WIDTH)
|
||||
iWidth = MATRIX_WIDTH;
|
||||
|
||||
usPalette = pDraw->pPalette;
|
||||
y = pDraw->iY + pDraw->y; // current line
|
||||
|
||||
s = pDraw->pPixels;
|
||||
if (pDraw->ucDisposalMethod == 2) // restore to background color
|
||||
{
|
||||
for (x=0; x<iWidth; x++)
|
||||
{
|
||||
if (s[x] == pDraw->ucTransparent)
|
||||
s[x] = pDraw->ucBackground;
|
||||
}
|
||||
pDraw->ucHasTransparency = 0;
|
||||
}
|
||||
// Apply the new pixels to the main image
|
||||
if (pDraw->ucHasTransparency) // if transparency used
|
||||
{
|
||||
uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
|
||||
int x, iCount;
|
||||
pEnd = s + pDraw->iWidth;
|
||||
x = 0;
|
||||
iCount = 0; // count non-transparent pixels
|
||||
while(x < pDraw->iWidth)
|
||||
{
|
||||
c = ucTransparent-1;
|
||||
d = usTemp;
|
||||
while (c != ucTransparent && s < pEnd)
|
||||
{
|
||||
c = *s++;
|
||||
if (c == ucTransparent) // done, stop
|
||||
{
|
||||
s--; // back up to treat it like transparent
|
||||
}
|
||||
else // opaque
|
||||
{
|
||||
*d++ = usPalette[c];
|
||||
iCount++;
|
||||
}
|
||||
} // while looking for opaque pixels
|
||||
if (iCount) // any opaque pixels?
|
||||
{
|
||||
for(int xOffset = 0; xOffset < iCount; xOffset++ ){
|
||||
dma_display->drawPixel(x + xOffset, y, usTemp[xOffset]); // 565 Color Format
|
||||
}
|
||||
x += iCount;
|
||||
iCount = 0;
|
||||
}
|
||||
// no, look for a run of transparent pixels
|
||||
c = ucTransparent;
|
||||
while (c == ucTransparent && s < pEnd)
|
||||
{
|
||||
c = *s++;
|
||||
if (c == ucTransparent)
|
||||
iCount++;
|
||||
else
|
||||
s--;
|
||||
}
|
||||
if (iCount)
|
||||
{
|
||||
x += iCount; // skip these
|
||||
iCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // does not have transparency
|
||||
{
|
||||
s = pDraw->pPixels;
|
||||
// Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
|
||||
for (x=0; x<pDraw->iWidth; x++)
|
||||
{
|
||||
dma_display->drawPixel(x, y, usPalette[*s++]); // color 565
|
||||
}
|
||||
}
|
||||
} /* GIFDraw() */
|
||||
|
||||
|
||||
void * GIFOpenFile(const char *fname, int32_t *pSize)
|
||||
{
|
||||
Serial.print("Playing gif: ");
|
||||
Serial.println(fname);
|
||||
f = FILESYSTEM.open(fname);
|
||||
if (f)
|
||||
{
|
||||
*pSize = f.size();
|
||||
return (void *)&f;
|
||||
}
|
||||
return NULL;
|
||||
} /* GIFOpenFile() */
|
||||
|
||||
void GIFCloseFile(void *pHandle)
|
||||
{
|
||||
File *f = static_cast<File *>(pHandle);
|
||||
if (f != NULL)
|
||||
f->close();
|
||||
} /* GIFCloseFile() */
|
||||
|
||||
int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen)
|
||||
{
|
||||
int32_t iBytesRead;
|
||||
iBytesRead = iLen;
|
||||
File *f = static_cast<File *>(pFile->fHandle);
|
||||
// Note: If you read a file all the way to the last byte, seek() stops working
|
||||
if ((pFile->iSize - pFile->iPos) < iLen)
|
||||
iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around
|
||||
if (iBytesRead <= 0)
|
||||
return 0;
|
||||
iBytesRead = (int32_t)f->read(pBuf, iBytesRead);
|
||||
pFile->iPos = f->position();
|
||||
return iBytesRead;
|
||||
} /* GIFReadFile() */
|
||||
|
||||
int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition)
|
||||
{
|
||||
int i = micros();
|
||||
File *f = static_cast<File *>(pFile->fHandle);
|
||||
f->seek(iPosition);
|
||||
pFile->iPos = (int32_t)f->position();
|
||||
i = micros() - i;
|
||||
// Serial.printf("Seek time = %d us\n", i);
|
||||
return pFile->iPos;
|
||||
} /* GIFSeekFile() */
|
||||
|
||||
unsigned long start_tick = 0;
|
||||
|
||||
void ShowGIF(char *name)
|
||||
{
|
||||
start_tick = millis();
|
||||
|
||||
if (gif.open(name, GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw))
|
||||
{
|
||||
x_offset = (MATRIX_WIDTH - gif.getCanvasWidth())/2;
|
||||
if (x_offset < 0) x_offset = 0;
|
||||
y_offset = (MATRIX_HEIGHT - gif.getCanvasHeight())/2;
|
||||
if (y_offset < 0) y_offset = 0;
|
||||
Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight());
|
||||
Serial.flush();
|
||||
while (gif.playFrame(true, NULL))
|
||||
{
|
||||
if ( (millis() - start_tick) > 8000) { // we'll get bored after about 8 seconds of the same looping gif
|
||||
break;
|
||||
}
|
||||
}
|
||||
gif.close();
|
||||
}
|
||||
|
||||
} /* ShowGIF() */
|
||||
|
||||
|
||||
|
||||
/************************* Arduino Sketch Setup and Loop() *******************************/
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN // Chain length
|
||||
);
|
||||
|
||||
// mxconfig.gpio.e = 18;
|
||||
// mxconfig.clkphase = false;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
|
||||
// Display Setup
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
dma_display->begin();
|
||||
dma_display->setBrightness8(128); //0-255
|
||||
dma_display->clearScreen();
|
||||
dma_display->fillScreen(myWHITE);
|
||||
|
||||
Serial.println("Starting AnimatedGIFs Sketch");
|
||||
|
||||
// Start filesystem
|
||||
Serial.println(" * Loading SPIFFS");
|
||||
if(!SPIFFS.begin()){
|
||||
Serial.println("SPIFFS Mount Failed");
|
||||
}
|
||||
|
||||
dma_display->begin();
|
||||
|
||||
/* all other pixel drawing functions can only be called after .begin() */
|
||||
dma_display->fillScreen(dma_display->color565(0, 0, 0));
|
||||
gif.begin(LITTLE_ENDIAN_PIXELS);
|
||||
|
||||
}
|
||||
|
||||
String gifDir = "/gifs"; // play all GIFs in this directory on the SD card
|
||||
char filePath[256] = { 0 };
|
||||
File root, gifFile;
|
||||
|
||||
void loop()
|
||||
{
|
||||
while (1) // run forever
|
||||
{
|
||||
|
||||
root = FILESYSTEM.open(gifDir);
|
||||
if (root)
|
||||
{
|
||||
gifFile = root.openNextFile();
|
||||
while (gifFile)
|
||||
{
|
||||
if (!gifFile.isDirectory()) // play it
|
||||
{
|
||||
|
||||
// C-strings... urghh...
|
||||
memset(filePath, 0x0, sizeof(filePath));
|
||||
strcpy(filePath, gifFile.path());
|
||||
|
||||
// Show it.
|
||||
ShowGIF(filePath);
|
||||
|
||||
}
|
||||
gifFile.close();
|
||||
gifFile = root.openNextFile();
|
||||
}
|
||||
root.close();
|
||||
} // root
|
||||
|
||||
delay(1000); // pause before restarting
|
||||
|
||||
} // while
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
## Animated GIF Decoding Example
|
||||
|
||||
### Prerequisites
|
||||
1. The excellent 'AnimatedGIF' library by Larry Bank needs to be installed: https://github.com/bitbank2/AnimatedGIF
|
||||
|
||||
This is available via the Arduino Library manager, or can be placed in the 'libs' directory with PlatformIO.
|
||||
|
||||
2. The files in the 'data' folder are written to the ESP32's SPIFFS file system.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
https://github.com/bitbank2/AnimatedGIF
|
||||
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Attractor" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/
|
||||
* Copyright (c) 2014 Daniel Shiffman
|
||||
* http://www.shiffman.net
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Vector.h"
|
||||
|
||||
class Attractor {
|
||||
public:
|
||||
float mass; // Mass, tied to size
|
||||
float G; // Gravitational Constant
|
||||
PVector location; // Location
|
||||
|
||||
Attractor() {
|
||||
location = PVector(MATRIX_CENTRE_X, MATRIX_CENTRE_Y);
|
||||
mass = 10;
|
||||
G = .5;
|
||||
}
|
||||
|
||||
PVector attract(Boid m) {
|
||||
PVector force = location - m.location; // Calculate direction of force
|
||||
float d = force.mag(); // Distance between objects
|
||||
d = constrain(d, 5.0, 32.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects
|
||||
force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction)
|
||||
float strength = (G * mass * m.mass) / (d * d); // Calculate gravitational force magnitude
|
||||
force *= strength; // Get force vector --> magnitude * direction
|
||||
return force;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,150 @@
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
|
||||
/*--------------------- MATRIX GPIO CONFIG -------------------------*/
|
||||
#define R1_PIN 25
|
||||
#define G1_PIN 26
|
||||
#define B1_PIN 27
|
||||
#define R2_PIN 14
|
||||
#define G2_PIN 12
|
||||
#define B2_PIN 13
|
||||
#define A_PIN 23
|
||||
#define B_PIN 19 // Changed from library default
|
||||
#define C_PIN 5
|
||||
#define D_PIN 17
|
||||
#define E_PIN -1
|
||||
#define LAT_PIN 4
|
||||
#define OE_PIN 15
|
||||
#define CLK_PIN 16
|
||||
|
||||
|
||||
/*--------------------- MATRIX PANEL CONFIG -------------------------*/
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another
|
||||
|
||||
/*
|
||||
//Another way of creating config structure
|
||||
//Custom pin mapping for all pins
|
||||
HUB75_I2S_CFG::i2s_pins _pins={R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK};
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
64, // width
|
||||
64, // height
|
||||
4, // chain length
|
||||
_pins, // pin mapping
|
||||
HUB75_I2S_CFG::FM6126A // driver chip
|
||||
);
|
||||
|
||||
*/
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
||||
// Module configuration
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN // Chain length
|
||||
);
|
||||
|
||||
|
||||
//mxconfig.gpio.e = -1; // Assign a pin if you have a 64x64 panel
|
||||
//mxconfig.clkphase = false; // Change this if you have issues with ghosting.
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6126A; // Change this according to your pane.
|
||||
|
||||
|
||||
|
||||
#include <FastLED.h>
|
||||
|
||||
#include "Effects.h"
|
||||
Effects effects;
|
||||
|
||||
#include "Drawable.h"
|
||||
#include "Playlist.h"
|
||||
//#include "Geometry.h"
|
||||
|
||||
#include "Patterns.h"
|
||||
Patterns patterns;
|
||||
|
||||
/* -------------------------- Some variables -------------------------- */
|
||||
unsigned long fps = 0, fps_timer; // fps (this is NOT a matrix refresh rate!)
|
||||
unsigned int default_fps = 30, pattern_fps = 30; // default fps limit (this is not a matrix refresh counter!)
|
||||
unsigned long ms_animation_max_duration = 20000; // 20 seconds
|
||||
unsigned long last_frame=0, ms_previous=0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
/************** SERIAL **************/
|
||||
Serial.begin(115200);
|
||||
delay(250);
|
||||
|
||||
/************** DISPLAY **************/
|
||||
Serial.println("...Starting Display");
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
dma_display->begin();
|
||||
dma_display->setBrightness8(90); //0-255
|
||||
|
||||
dma_display->fillScreenRGB888(128,0,0);
|
||||
delay(1000);
|
||||
dma_display->fillScreenRGB888(0,0,128);
|
||||
delay(1000);
|
||||
dma_display->clearScreen();
|
||||
delay(1000);
|
||||
Serial.println("**************** Starting Aurora Effects Demo ****************");
|
||||
|
||||
|
||||
// setup the effects generator
|
||||
effects.Setup();
|
||||
|
||||
delay(500);
|
||||
Serial.println("Effects being loaded: ");
|
||||
listPatterns();
|
||||
|
||||
|
||||
patterns.moveRandom(1); // start from a random pattern
|
||||
|
||||
Serial.print("Starting with pattern: ");
|
||||
Serial.println(patterns.getCurrentPatternName());
|
||||
patterns.start();
|
||||
ms_previous = millis();
|
||||
fps_timer = millis();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// menu.run(mainMenuItems, mainMenuItemCount);
|
||||
|
||||
if ( (millis() - ms_previous) > ms_animation_max_duration )
|
||||
{
|
||||
patterns.stop();
|
||||
patterns.moveRandom(1);
|
||||
//patterns.move(1);
|
||||
patterns.start();
|
||||
|
||||
Serial.print("Changing pattern to: ");
|
||||
Serial.println(patterns.getCurrentPatternName());
|
||||
|
||||
ms_previous = millis();
|
||||
|
||||
// Select a random palette as well
|
||||
//effects.RandomPalette();
|
||||
}
|
||||
|
||||
if ( 1000 / pattern_fps + last_frame < millis()){
|
||||
last_frame = millis();
|
||||
pattern_fps = patterns.drawFrame();
|
||||
if (!pattern_fps)
|
||||
pattern_fps = default_fps;
|
||||
|
||||
++fps;
|
||||
}
|
||||
|
||||
if (fps_timer + 1000 < millis()){
|
||||
Serial.printf_P(PSTR("Effect fps: %ld\n"), fps);
|
||||
fps_timer = millis();
|
||||
fps = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void listPatterns() {
|
||||
patterns.listPatterns();
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Flocking" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/
|
||||
* Copyright (c) 2014 Daniel Shiffman
|
||||
* http://www.shiffman.net
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Flocking
|
||||
// Daniel Shiffman <http://www.shiffman.net>
|
||||
// The Nature of Code, Spring 2009
|
||||
|
||||
// Boid class
|
||||
// Methods for Separation, Cohesion, Alignment added
|
||||
|
||||
class Boid {
|
||||
public:
|
||||
|
||||
PVector location;
|
||||
PVector velocity;
|
||||
PVector acceleration;
|
||||
float maxforce; // Maximum steering force
|
||||
float maxspeed; // Maximum speed
|
||||
|
||||
float desiredseparation = 4;
|
||||
float neighbordist = 8;
|
||||
byte colorIndex = 0;
|
||||
float mass;
|
||||
|
||||
boolean enabled = true;
|
||||
|
||||
Boid() {}
|
||||
|
||||
Boid(float x, float y) {
|
||||
acceleration = PVector(0, 0);
|
||||
velocity = PVector(randomf(), randomf());
|
||||
location = PVector(x, y);
|
||||
maxspeed = 1.5;
|
||||
maxforce = 0.05;
|
||||
}
|
||||
|
||||
static float randomf() {
|
||||
return mapfloat(random(0, 255), 0, 255, -.5, .5);
|
||||
}
|
||||
|
||||
static float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
void run(Boid boids [], uint8_t boidCount) {
|
||||
flock(boids, boidCount);
|
||||
update();
|
||||
// wrapAroundBorders();
|
||||
// render();
|
||||
}
|
||||
|
||||
// Method to update location
|
||||
void update() {
|
||||
// Update velocity
|
||||
velocity += acceleration;
|
||||
// Limit speed
|
||||
velocity.limit(maxspeed);
|
||||
location += velocity;
|
||||
// Reset acceleration to 0 each cycle
|
||||
acceleration *= 0;
|
||||
}
|
||||
|
||||
void applyForce(PVector force) {
|
||||
// We could add mass here if we want A = F / M
|
||||
acceleration += force;
|
||||
}
|
||||
|
||||
void repelForce(PVector obstacle, float radius) {
|
||||
//Force that drives boid away from obstacle.
|
||||
|
||||
PVector futPos = location + velocity; //Calculate future position for more effective behavior.
|
||||
PVector dist = obstacle - futPos;
|
||||
float d = dist.mag();
|
||||
|
||||
if (d <= radius) {
|
||||
PVector repelVec = location - obstacle;
|
||||
repelVec.normalize();
|
||||
if (d != 0) { //Don't divide by zero.
|
||||
// float scale = 1.0 / d; //The closer to the obstacle, the stronger the force.
|
||||
repelVec.normalize();
|
||||
repelVec *= (maxforce * 7);
|
||||
if (repelVec.mag() < 0) { //Don't let the boids turn around to avoid the obstacle.
|
||||
repelVec.y = 0;
|
||||
}
|
||||
}
|
||||
applyForce(repelVec);
|
||||
}
|
||||
}
|
||||
|
||||
// We accumulate a new acceleration each time based on three rules
|
||||
void flock(Boid boids [], uint8_t boidCount) {
|
||||
PVector sep = separate(boids, boidCount); // Separation
|
||||
PVector ali = align(boids, boidCount); // Alignment
|
||||
PVector coh = cohesion(boids, boidCount); // Cohesion
|
||||
// Arbitrarily weight these forces
|
||||
sep *= 1.5;
|
||||
ali *= 1.0;
|
||||
coh *= 1.0;
|
||||
// Add the force vectors to acceleration
|
||||
applyForce(sep);
|
||||
applyForce(ali);
|
||||
applyForce(coh);
|
||||
}
|
||||
|
||||
// Separation
|
||||
// Method checks for nearby boids and steers away
|
||||
PVector separate(Boid boids [], uint8_t boidCount) {
|
||||
PVector steer = PVector(0, 0);
|
||||
int count = 0;
|
||||
// For every boid in the system, check if it's too close
|
||||
for (int i = 0; i < boidCount; i++) {
|
||||
Boid other = boids[i];
|
||||
if (!other.enabled)
|
||||
continue;
|
||||
float d = location.dist(other.location);
|
||||
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
|
||||
if ((d > 0) && (d < desiredseparation)) {
|
||||
// Calculate vector pointing away from neighbor
|
||||
PVector diff = location - other.location;
|
||||
diff.normalize();
|
||||
diff /= d; // Weight by distance
|
||||
steer += diff;
|
||||
count++; // Keep track of how many
|
||||
}
|
||||
}
|
||||
// Average -- divide by how many
|
||||
if (count > 0) {
|
||||
steer /= (float) count;
|
||||
}
|
||||
|
||||
// As long as the vector is greater than 0
|
||||
if (steer.mag() > 0) {
|
||||
// Implement Reynolds: Steering = Desired - Velocity
|
||||
steer.normalize();
|
||||
steer *= maxspeed;
|
||||
steer -= velocity;
|
||||
steer.limit(maxforce);
|
||||
}
|
||||
return steer;
|
||||
}
|
||||
|
||||
// Alignment
|
||||
// For every nearby boid in the system, calculate the average velocity
|
||||
PVector align(Boid boids [], uint8_t boidCount) {
|
||||
PVector sum = PVector(0, 0);
|
||||
int count = 0;
|
||||
for (int i = 0; i < boidCount; i++) {
|
||||
Boid other = boids[i];
|
||||
if (!other.enabled)
|
||||
continue;
|
||||
float d = location.dist(other.location);
|
||||
if ((d > 0) && (d < neighbordist)) {
|
||||
sum += other.velocity;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
sum /= (float) count;
|
||||
sum.normalize();
|
||||
sum *= maxspeed;
|
||||
PVector steer = sum - velocity;
|
||||
steer.limit(maxforce);
|
||||
return steer;
|
||||
}
|
||||
else {
|
||||
return PVector(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Cohesion
|
||||
// For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location
|
||||
PVector cohesion(Boid boids [], uint8_t boidCount) {
|
||||
PVector sum = PVector(0, 0); // Start with empty vector to accumulate all locations
|
||||
int count = 0;
|
||||
for (int i = 0; i < boidCount; i++) {
|
||||
Boid other = boids[i];
|
||||
if (!other.enabled)
|
||||
continue;
|
||||
float d = location.dist(other.location);
|
||||
if ((d > 0) && (d < neighbordist)) {
|
||||
sum += other.location; // Add location
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
sum /= count;
|
||||
return seek(sum); // Steer towards the location
|
||||
}
|
||||
else {
|
||||
return PVector(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// A method that calculates and applies a steering force towards a target
|
||||
// STEER = DESIRED MINUS VELOCITY
|
||||
PVector seek(PVector target) {
|
||||
PVector desired = target - location; // A vector pointing from the location to the target
|
||||
// Normalize desired and scale to maximum speed
|
||||
desired.normalize();
|
||||
desired *= maxspeed;
|
||||
// Steering = Desired minus Velocity
|
||||
PVector steer = desired - velocity;
|
||||
steer.limit(maxforce); // Limit to maximum steering force
|
||||
return steer;
|
||||
}
|
||||
|
||||
// A method that calculates a steering force towards a target
|
||||
// STEER = DESIRED MINUS VELOCITY
|
||||
void arrive(PVector target) {
|
||||
PVector desired = target - location; // A vector pointing from the location to the target
|
||||
float d = desired.mag();
|
||||
// Normalize desired and scale with arbitrary damping within 100 pixels
|
||||
desired.normalize();
|
||||
if (d < 4) {
|
||||
float m = map(d, 0, 100, 0, maxspeed);
|
||||
desired *= m;
|
||||
}
|
||||
else {
|
||||
desired *= maxspeed;
|
||||
}
|
||||
|
||||
// Steering = Desired minus Velocity
|
||||
PVector steer = desired - velocity;
|
||||
steer.limit(maxforce); // Limit to maximum steering force
|
||||
applyForce(steer);
|
||||
//Serial.println(d);
|
||||
}
|
||||
|
||||
void wrapAroundBorders() {
|
||||
if (location.x < 0) location.x = MATRIX_WIDTH - 1;
|
||||
if (location.y < 0) location.y = MATRIX_HEIGHT - 1;
|
||||
if (location.x >= MATRIX_WIDTH) location.x = 0;
|
||||
if (location.y >= MATRIX_HEIGHT) location.y = 0;
|
||||
}
|
||||
|
||||
void avoidBorders() {
|
||||
PVector desired = velocity;
|
||||
|
||||
if (location.x < 8) desired = PVector(maxspeed, velocity.y);
|
||||
if (location.x >= MATRIX_WIDTH - 8) desired = PVector(-maxspeed, velocity.y);
|
||||
if (location.y < 8) desired = PVector(velocity.x, maxspeed);
|
||||
if (location.y >= MATRIX_HEIGHT - 8) desired = PVector(velocity.x, -maxspeed);
|
||||
|
||||
if (desired != velocity) {
|
||||
PVector steer = desired - velocity;
|
||||
steer.limit(maxforce);
|
||||
applyForce(steer);
|
||||
}
|
||||
|
||||
if (location.x < 0) location.x = 0;
|
||||
if (location.y < 0) location.y = 0;
|
||||
if (location.x >= MATRIX_WIDTH) location.x = MATRIX_WIDTH - 1;
|
||||
if (location.y >= MATRIX_HEIGHT) location.y = MATRIX_HEIGHT - 1;
|
||||
}
|
||||
|
||||
bool bounceOffBorders(float bounce) {
|
||||
bool bounced = false;
|
||||
|
||||
if (location.x >= MATRIX_WIDTH) {
|
||||
location.x = MATRIX_WIDTH - 1;
|
||||
velocity.x *= -bounce;
|
||||
bounced = true;
|
||||
}
|
||||
else if (location.x < 0) {
|
||||
location.x = 0;
|
||||
velocity.x *= -bounce;
|
||||
bounced = true;
|
||||
}
|
||||
|
||||
if (location.y >= MATRIX_HEIGHT) {
|
||||
location.y = MATRIX_HEIGHT - 1;
|
||||
velocity.y *= -bounce;
|
||||
bounced = true;
|
||||
}
|
||||
else if (location.y < 0) {
|
||||
location.y = 0;
|
||||
velocity.y *= -bounce;
|
||||
bounced = true;
|
||||
}
|
||||
|
||||
return bounced;
|
||||
}
|
||||
|
||||
void render() {
|
||||
//// Draw a triangle rotated in the direction of velocity
|
||||
//float theta = velocity.heading2D() + radians(90);
|
||||
//fill(175);
|
||||
//stroke(0);
|
||||
//pushMatrix();
|
||||
//translate(location.x,location.y);
|
||||
//rotate(theta);
|
||||
//beginShape(TRIANGLES);
|
||||
//vertex(0, -r*2);
|
||||
//vertex(-r, r*2);
|
||||
//vertex(r, r*2);
|
||||
//endShape();
|
||||
//popMatrix();
|
||||
//dma_display->drawBackgroundPixelRGB888(location.x, location.y, CRGB::Blue);
|
||||
}
|
||||
};
|
||||
|
||||
static const uint8_t AVAILABLE_BOID_COUNT = 40;
|
||||
Boid boids[AVAILABLE_BOID_COUNT];
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Drawable_H
|
||||
#define Drawable_H
|
||||
|
||||
class Drawable{
|
||||
public:
|
||||
char* name;
|
||||
|
||||
virtual bool isRunnable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool isPlaylist() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// a single frame should be drawn as fast as possible, without any delay or blocking
|
||||
// return how many millisecond delay is requested before the next call to drawFrame()
|
||||
virtual unsigned int drawFrame() {
|
||||
dma_display->fillScreen(0);
|
||||
//backgroundLayer.fillScreen({ 0, 0, 0 });
|
||||
return 0;
|
||||
};
|
||||
|
||||
virtual void printTesting()
|
||||
{
|
||||
Serial.println("Testing...");
|
||||
}
|
||||
|
||||
virtual void start() {};
|
||||
virtual void stop() {};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,848 @@
|
||||
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Funky Clouds" by Stefan Petrick: https://gist.github.com/anonymous/876f908333cd95315c35
|
||||
* Portions of this code are adapted from "NoiseSmearing" by Stefan Petrick: https://gist.github.com/StefanPetrick/9ee2f677dbff64e3ba7a
|
||||
* Copyright (c) 2014 Stefan Petrick
|
||||
* http://www.stefan-petrick.de/wordpress_beta
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Effects_H
|
||||
#define Effects_H
|
||||
|
||||
/* ---------------------------- GLOBAL CONSTANTS ----------------------------- */
|
||||
|
||||
const int MATRIX_CENTER_X = MATRIX_WIDTH / 2;
|
||||
const int MATRIX_CENTER_Y = MATRIX_HEIGHT / 2;
|
||||
// US vs GB, huh? :)
|
||||
//const byte MATRIX_CENTRE_X = MATRIX_CENTER_X - 1;
|
||||
//const byte MATRIX_CENTRE_Y = MATRIX_CENTER_Y - 1;
|
||||
#define MATRIX_CENTRE_X MATRIX_CENTER_X
|
||||
#define MATRIX_CENTRE_Y MATRIX_CENTER_Y
|
||||
|
||||
|
||||
const uint16_t NUM_LEDS = (MATRIX_WIDTH * MATRIX_HEIGHT) + 1; // one led spare to capture out of bounds
|
||||
|
||||
// forward declaration
|
||||
uint16_t XY16( uint16_t x, uint16_t y);
|
||||
|
||||
/* Convert x,y co-ordinate to flat array index.
|
||||
* x and y positions start from 0, so must not be >= 'real' panel width or height
|
||||
* (i.e. 64 pixels or 32 pixels.). Max value: MATRIX_WIDTH-1 etc.
|
||||
* Ugh... uint8_t - really??? this weak method can't cope with 256+ pixel matrices :(
|
||||
*/
|
||||
uint16_t XY( uint8_t x, uint8_t y)
|
||||
{
|
||||
return XY16(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* The one for 256+ matrices
|
||||
* otherwise this:
|
||||
* for (uint8_t i = 0; i < MATRIX_WIDTH; i++) {}
|
||||
* turns into an infinite loop
|
||||
*/
|
||||
uint16_t XY16( uint16_t x, uint16_t y)
|
||||
{
|
||||
if( x >= MATRIX_WIDTH) return 0;
|
||||
if( y >= MATRIX_HEIGHT) return 0;
|
||||
|
||||
return (y * MATRIX_WIDTH) + x + 1; // everything offset by one to compute out of bounds stuff - never displayed by ShowFrame()
|
||||
}
|
||||
|
||||
|
||||
uint8_t beatcos8(accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0)
|
||||
{
|
||||
uint8_t beat = beat8(beats_per_minute, timebase);
|
||||
uint8_t beatcos = cos8(beat + phase_offset);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatcos, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t mapsin8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
|
||||
uint8_t beatsin = sin8(theta);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatsin, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t mapcos8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
|
||||
uint8_t beatcos = cos8(theta);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatcos, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Array of temperature readings at each simulation cell
|
||||
//byte heat[NUM_LEDS]; // none of the currently enabled effects uses this
|
||||
|
||||
uint32_t noise_x;
|
||||
uint32_t noise_y;
|
||||
uint32_t noise_z;
|
||||
uint32_t noise_scale_x;
|
||||
uint32_t noise_scale_y;
|
||||
|
||||
//uint8_t noise[MATRIX_WIDTH][MATRIX_HEIGHT];
|
||||
uint8_t **noise = nullptr; // we will allocate mem later
|
||||
uint8_t noisesmoothing;
|
||||
|
||||
class Effects {
|
||||
public:
|
||||
CRGB *leds;
|
||||
//CRGB leds[NUM_LEDS];
|
||||
//CRGB leds2[NUM_LEDS]; // Faptastic: getting rid of this and any dependant effects or algos. to save memory 24*64*32 bytes of ram (50k).
|
||||
|
||||
Effects(){
|
||||
// we do dynamic allocation for leds buffer, otherwise esp32 toolchain can't link static arrays of such a big size for 256+ matrices
|
||||
leds = (CRGB *)malloc(NUM_LEDS * sizeof(CRGB));
|
||||
|
||||
// allocate mem for noise effect
|
||||
// (there should be some guards for malloc errors eventually)
|
||||
noise = (uint8_t **)malloc(MATRIX_WIDTH * sizeof(uint8_t *));
|
||||
for (int i = 0; i < MATRIX_WIDTH; ++i) {
|
||||
noise[i] = (uint8_t *)malloc(MATRIX_HEIGHT * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
ClearFrame();
|
||||
//dma_display->clearScreen();
|
||||
}
|
||||
~Effects(){
|
||||
free(leds);
|
||||
for (int i = 0; i < MATRIX_WIDTH; ++i) {
|
||||
free(noise[i]);
|
||||
}
|
||||
free(noise);
|
||||
}
|
||||
|
||||
/* The only 'framebuffer' we have is what is contained in the leds and leds2 variables.
|
||||
* We don't store what the color a particular pixel might be, other than when it's turned
|
||||
* into raw electrical signal output gobbly-gook (i.e. the DMA matrix buffer), but this * is not reversible.
|
||||
*
|
||||
* As such, any time these effects want to write a pixel color, we first have to update
|
||||
* the leds or leds2 array, and THEN write it to the RGB panel. This enables us to 'look up' the array to see what a pixel color was previously, each drawFrame().
|
||||
*/
|
||||
void drawBackgroundFastLEDPixelCRGB(int16_t x, int16_t y, CRGB color)
|
||||
{
|
||||
leds[XY(x, y)] = color;
|
||||
//dma_display->drawPixelRGB888(x, y, color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
// write one pixel with the specified color from the current palette to coordinates
|
||||
void Pixel(int x, int y, uint8_t colorIndex) {
|
||||
leds[XY(x, y)] = ColorFromCurrentPalette(colorIndex);
|
||||
//dma_display->drawPixelRGB888(x, y, temp.r, temp.g, temp.b); // now draw it?
|
||||
}
|
||||
|
||||
void PrepareFrame() {
|
||||
// leds = (CRGB*) backgroundLayer.backBuffer();
|
||||
}
|
||||
|
||||
void ShowFrame() {
|
||||
//#if (FASTLED_VERSION >= 3001000)
|
||||
// nblendPaletteTowardPalette(currentPalette, targetPalette, 24);
|
||||
//#else
|
||||
currentPalette = targetPalette;
|
||||
//#endif
|
||||
|
||||
// backgroundLayer.swapBuffers();
|
||||
// leds = (CRGB*) backgroundLayer.backBuffer();
|
||||
// LEDS.countFPS();
|
||||
|
||||
for (int y=0; y<MATRIX_HEIGHT; ++y){
|
||||
for (int x=0; x<MATRIX_WIDTH; ++x){
|
||||
//Serial.printf("Flushing x, y coord %d, %d\n", x, y);
|
||||
uint16_t _pixel = XY16(x,y);
|
||||
dma_display->drawPixelRGB888( x, y, leds[_pixel].r, leds[_pixel].g, leds[_pixel].b);
|
||||
} // end loop to copy fast led to the dma matrix
|
||||
}
|
||||
}
|
||||
|
||||
// scale the brightness of the screenbuffer down
|
||||
void DimAll(byte value)
|
||||
{
|
||||
for (int i = 0; i < NUM_LEDS; i++)
|
||||
{
|
||||
leds[i].nscale8(value);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearFrame()
|
||||
{
|
||||
memset(leds, 0x00, NUM_LEDS * sizeof(CRGB)); // flush
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void CircleStream(uint8_t value) {
|
||||
DimAll(value); ShowFrame();
|
||||
|
||||
for (uint8_t offset = 0; offset < MATRIX_CENTER_X; offset++) {
|
||||
boolean hasprev = false;
|
||||
uint16_t prevxy = 0;
|
||||
|
||||
for (uint8_t theta = 0; theta < 255; theta++) {
|
||||
uint8_t x = mapcos8(theta, offset, (MATRIX_WIDTH - 1) - offset);
|
||||
uint8_t y = mapsin8(theta, offset, (MATRIX_HEIGHT - 1) - offset);
|
||||
|
||||
uint16_t xy = XY(x, y);
|
||||
|
||||
if (hasprev) {
|
||||
leds[prevxy] += leds[xy];
|
||||
}
|
||||
|
||||
prevxy = xy;
|
||||
hasprev = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
uint16_t xy = XY(x, y);
|
||||
leds[xy] = leds2[xy];
|
||||
leds[xy].nscale8(value);
|
||||
leds2[xy].nscale8(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// palettes
|
||||
static const int paletteCount = 10;
|
||||
int paletteIndex = -1;
|
||||
TBlendType currentBlendType = LINEARBLEND;
|
||||
CRGBPalette16 currentPalette;
|
||||
CRGBPalette16 targetPalette;
|
||||
char* currentPaletteName;
|
||||
|
||||
static const int HeatColorsPaletteIndex = 6;
|
||||
static const int RandomPaletteIndex = 9;
|
||||
|
||||
void Setup() {
|
||||
currentPalette = RainbowColors_p;
|
||||
loadPalette(0);
|
||||
NoiseVariablesSetup();
|
||||
}
|
||||
|
||||
void CyclePalette(int offset = 1) {
|
||||
loadPalette(paletteIndex + offset);
|
||||
}
|
||||
|
||||
void RandomPalette() {
|
||||
loadPalette(RandomPaletteIndex);
|
||||
}
|
||||
|
||||
void loadPalette(int index) {
|
||||
paletteIndex = index;
|
||||
|
||||
if (paletteIndex >= paletteCount)
|
||||
paletteIndex = 0;
|
||||
else if (paletteIndex < 0)
|
||||
paletteIndex = paletteCount - 1;
|
||||
|
||||
switch (paletteIndex) {
|
||||
case 0:
|
||||
targetPalette = RainbowColors_p;
|
||||
currentPaletteName = (char *)"Rainbow";
|
||||
break;
|
||||
//case 1:
|
||||
// targetPalette = RainbowStripeColors_p;
|
||||
// currentPaletteName = (char *)"RainbowStripe";
|
||||
// break;
|
||||
case 1:
|
||||
targetPalette = OceanColors_p;
|
||||
currentPaletteName = (char *)"Ocean";
|
||||
break;
|
||||
case 2:
|
||||
targetPalette = CloudColors_p;
|
||||
currentPaletteName = (char *)"Cloud";
|
||||
break;
|
||||
case 3:
|
||||
targetPalette = ForestColors_p;
|
||||
currentPaletteName = (char *)"Forest";
|
||||
break;
|
||||
case 4:
|
||||
targetPalette = PartyColors_p;
|
||||
currentPaletteName = (char *)"Party";
|
||||
break;
|
||||
case 5:
|
||||
setupGrayscalePalette();
|
||||
currentPaletteName = (char *)"Grey";
|
||||
break;
|
||||
case HeatColorsPaletteIndex:
|
||||
targetPalette = HeatColors_p;
|
||||
currentPaletteName = (char *)"Heat";
|
||||
break;
|
||||
case 7:
|
||||
targetPalette = LavaColors_p;
|
||||
currentPaletteName = (char *)"Lava";
|
||||
break;
|
||||
case 8:
|
||||
setupIcePalette();
|
||||
currentPaletteName = (char *)"Ice";
|
||||
break;
|
||||
case RandomPaletteIndex:
|
||||
loadPalette(random(0, paletteCount - 1));
|
||||
paletteIndex = RandomPaletteIndex;
|
||||
currentPaletteName = (char *)"Random";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setPalette(String paletteName) {
|
||||
if (paletteName == "Rainbow")
|
||||
loadPalette(0);
|
||||
//else if (paletteName == "RainbowStripe")
|
||||
// loadPalette(1);
|
||||
else if (paletteName == "Ocean")
|
||||
loadPalette(1);
|
||||
else if (paletteName == "Cloud")
|
||||
loadPalette(2);
|
||||
else if (paletteName == "Forest")
|
||||
loadPalette(3);
|
||||
else if (paletteName == "Party")
|
||||
loadPalette(4);
|
||||
else if (paletteName == "Grayscale")
|
||||
loadPalette(5);
|
||||
else if (paletteName == "Heat")
|
||||
loadPalette(6);
|
||||
else if (paletteName == "Lava")
|
||||
loadPalette(7);
|
||||
else if (paletteName == "Ice")
|
||||
loadPalette(8);
|
||||
else if (paletteName == "Random")
|
||||
RandomPalette();
|
||||
}
|
||||
|
||||
void listPalettes() {
|
||||
Serial.println(F("{"));
|
||||
Serial.print(F(" \"count\": "));
|
||||
Serial.print(paletteCount);
|
||||
Serial.println(",");
|
||||
Serial.println(F(" \"results\": ["));
|
||||
|
||||
String paletteNames [] = {
|
||||
"Rainbow",
|
||||
// "RainbowStripe",
|
||||
"Ocean",
|
||||
"Cloud",
|
||||
"Forest",
|
||||
"Party",
|
||||
"Grayscale",
|
||||
"Heat",
|
||||
"Lava",
|
||||
"Ice",
|
||||
"Random"
|
||||
};
|
||||
|
||||
for (int i = 0; i < paletteCount; i++) {
|
||||
Serial.print(F(" \""));
|
||||
Serial.print(paletteNames[i]);
|
||||
if (i == paletteCount - 1)
|
||||
Serial.println(F("\""));
|
||||
else
|
||||
Serial.println(F("\","));
|
||||
}
|
||||
|
||||
Serial.println(" ]");
|
||||
Serial.println("}");
|
||||
}
|
||||
|
||||
void setupGrayscalePalette() {
|
||||
targetPalette = CRGBPalette16(CRGB::Black, CRGB::White);
|
||||
}
|
||||
|
||||
void setupIcePalette() {
|
||||
targetPalette = CRGBPalette16(CRGB::Black, CRGB::Blue, CRGB::Aqua, CRGB::White);
|
||||
}
|
||||
|
||||
// Oscillators and Emitters
|
||||
|
||||
// the oscillators: linear ramps 0-255
|
||||
byte osci[6];
|
||||
|
||||
// sin8(osci) swinging between 0 to MATRIX_WIDTH - 1
|
||||
byte p[6];
|
||||
|
||||
// set the speeds (and by that ratios) of the oscillators here
|
||||
void MoveOscillators() {
|
||||
osci[0] = osci[0] + 5;
|
||||
osci[1] = osci[1] + 2;
|
||||
osci[2] = osci[2] + 3;
|
||||
osci[3] = osci[3] + 4;
|
||||
osci[4] = osci[4] + 1;
|
||||
if (osci[4] % 2 == 0)
|
||||
osci[5] = osci[5] + 1; // .5
|
||||
for (int i = 0; i < 4; i++) {
|
||||
p[i] = map8(sin8(osci[i]), 0, MATRIX_WIDTH - 1); //why? to keep the result in the range of 0-MATRIX_WIDTH (matrix size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// All the caleidoscope functions work directly within the screenbuffer (leds array).
|
||||
// Draw whatever you like in the area x(0-15) and y (0-15) and then copy it arround.
|
||||
|
||||
// rotates the first 16x16 quadrant 3 times onto a 32x32 (+90 degrees rotation for each one)
|
||||
void Caleidoscope1() {
|
||||
for (int x = 0; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < MATRIX_CENTER_Y; y++) {
|
||||
leds[XY16(MATRIX_WIDTH - 1 - x, y)] = leds[XY16(x, y)];
|
||||
leds[XY16(MATRIX_WIDTH - 1 - x, MATRIX_HEIGHT - 1 - y)] = leds[XY16(x, y)];
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1 - y)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// mirror the first 16x16 quadrant 3 times onto a 32x32
|
||||
void Caleidoscope2() {
|
||||
for (int x = 0; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < MATRIX_CENTER_Y; y++) {
|
||||
leds[XY16(MATRIX_WIDTH - 1 - x, y)] = leds[XY16(y, x)];
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1 - y)] = leds[XY16(y, x)];
|
||||
leds[XY16(MATRIX_WIDTH - 1 - x, MATRIX_HEIGHT - 1 - y)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy one diagonal triangle into the other one within a 16x16
|
||||
void Caleidoscope3() {
|
||||
for (int x = 0; x <= MATRIX_CENTRE_X && x < MATRIX_HEIGHT; x++) {
|
||||
for (int y = 0; y <= x && y<MATRIX_HEIGHT; y++) {
|
||||
leds[XY16(x, y)] = leds[XY16(y, x)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy one diagonal triangle into the other one within a 16x16 (90 degrees rotated compared to Caleidoscope3)
|
||||
void Caleidoscope4() {
|
||||
for (int x = 0; x <= MATRIX_CENTRE_X; x++) {
|
||||
for (int y = 0; y <= MATRIX_CENTRE_Y - x; y++) {
|
||||
leds[XY16(MATRIX_CENTRE_Y - y, MATRIX_CENTRE_X - x)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy one diagonal triangle into the other one within a 8x8
|
||||
void Caleidoscope5() {
|
||||
for (int x = 0; x < MATRIX_WIDTH / 4; x++) {
|
||||
for (int y = 0; y <= x && y<=MATRIX_HEIGHT; y++) {
|
||||
leds[XY16(x, y)] = leds[XY16(y, x)];
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = MATRIX_WIDTH / 4; x < MATRIX_WIDTH / 2; x++) {
|
||||
for (int y = MATRIX_HEIGHT / 4; y >= 0; y--) {
|
||||
leds[XY16(x, y)] = leds[XY16(y, x)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Caleidoscope6() {
|
||||
for (int x = 1; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 7)] = leds[XY16(x, 0)];
|
||||
} //a
|
||||
for (int x = 2; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 6)] = leds[XY16(x, 1)];
|
||||
} //b
|
||||
for (int x = 3; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 5)] = leds[XY16(x, 2)];
|
||||
} //c
|
||||
for (int x = 4; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 4)] = leds[XY16(x, 3)];
|
||||
} //d
|
||||
for (int x = 5; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 3)] = leds[XY16(x, 4)];
|
||||
} //e
|
||||
for (int x = 6; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 2)] = leds[XY16(x, 5)];
|
||||
} //f
|
||||
for (int x = 7; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 1)] = leds[XY16(x, 6)];
|
||||
} //g
|
||||
}
|
||||
|
||||
// create a square twister to the left or counter-clockwise
|
||||
// x and y for center, r for radius
|
||||
void SpiralStream(int x, int y, int r, byte dimm) {
|
||||
for (int d = r; d >= 0; d--) { // from the outside to the inside
|
||||
for (int i = x - d; i <= x + d; i++) {
|
||||
leds[XY16(i, y - d)] += leds[XY16(i + 1, y - d)]; // lowest row to the right
|
||||
leds[XY16(i, y - d)].nscale8(dimm);
|
||||
}
|
||||
for (int i = y - d; i <= y + d; i++) {
|
||||
leds[XY16(x + d, i)] += leds[XY16(x + d, i + 1)]; // right column up
|
||||
leds[XY16(x + d, i)].nscale8(dimm);
|
||||
}
|
||||
for (int i = x + d; i >= x - d; i--) {
|
||||
leds[XY16(i, y + d)] += leds[XY16(i - 1, y + d)]; // upper row to the left
|
||||
leds[XY16(i, y + d)].nscale8(dimm);
|
||||
}
|
||||
for (int i = y + d; i >= y - d; i--) {
|
||||
leds[XY16(x - d, i)] += leds[XY16(x - d, i - 1)]; // left column down
|
||||
leds[XY16(x - d, i)].nscale8(dimm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// expand everything within a circle
|
||||
void Expand(int centerX, int centerY, int radius, byte dimm) {
|
||||
if (radius == 0)
|
||||
return;
|
||||
|
||||
int currentRadius = radius;
|
||||
|
||||
while (currentRadius > 0) {
|
||||
int a = radius, b = 0;
|
||||
int radiusError = 1 - a;
|
||||
|
||||
int nextRadius = currentRadius - 1;
|
||||
int nextA = nextRadius - 1, nextB = 0;
|
||||
int nextRadiusError = 1 - nextA;
|
||||
|
||||
while (a >= b)
|
||||
{
|
||||
// move them out one pixel on the radius
|
||||
leds[XY16(a + centerX, b + centerY)] = leds[XY16(nextA + centerX, nextB + centerY)];
|
||||
leds[XY16(b + centerX, a + centerY)] = leds[XY16(nextB + centerX, nextA + centerY)];
|
||||
leds[XY16(-a + centerX, b + centerY)] = leds[XY16(-nextA + centerX, nextB + centerY)];
|
||||
leds[XY16(-b + centerX, a + centerY)] = leds[XY16(-nextB + centerX, nextA + centerY)];
|
||||
leds[XY16(-a + centerX, -b + centerY)] = leds[XY16(-nextA + centerX, -nextB + centerY)];
|
||||
leds[XY16(-b + centerX, -a + centerY)] = leds[XY16(-nextB + centerX, -nextA + centerY)];
|
||||
leds[XY16(a + centerX, -b + centerY)] = leds[XY16(nextA + centerX, -nextB + centerY)];
|
||||
leds[XY16(b + centerX, -a + centerY)] = leds[XY16(nextB + centerX, -nextA + centerY)];
|
||||
|
||||
// dim them
|
||||
leds[XY16(a + centerX, b + centerY)].nscale8(dimm);
|
||||
leds[XY16(b + centerX, a + centerY)].nscale8(dimm);
|
||||
leds[XY16(-a + centerX, b + centerY)].nscale8(dimm);
|
||||
leds[XY16(-b + centerX, a + centerY)].nscale8(dimm);
|
||||
leds[XY16(-a + centerX, -b + centerY)].nscale8(dimm);
|
||||
leds[XY16(-b + centerX, -a + centerY)].nscale8(dimm);
|
||||
leds[XY16(a + centerX, -b + centerY)].nscale8(dimm);
|
||||
leds[XY16(b + centerX, -a + centerY)].nscale8(dimm);
|
||||
|
||||
b++;
|
||||
if (radiusError < 0)
|
||||
radiusError += 2 * b + 1;
|
||||
else
|
||||
{
|
||||
a--;
|
||||
radiusError += 2 * (b - a + 1);
|
||||
}
|
||||
|
||||
nextB++;
|
||||
if (nextRadiusError < 0)
|
||||
nextRadiusError += 2 * nextB + 1;
|
||||
else
|
||||
{
|
||||
nextA--;
|
||||
nextRadiusError += 2 * (nextB - nextA + 1);
|
||||
}
|
||||
}
|
||||
|
||||
currentRadius--;
|
||||
}
|
||||
}
|
||||
|
||||
// give it a linear tail to the right
|
||||
void StreamRight(byte scale, int fromX = 0, int toX = MATRIX_WIDTH, int fromY = 0, int toY = MATRIX_HEIGHT)
|
||||
{
|
||||
for (int x = fromX + 1; x < toX; x++) {
|
||||
for (int y = fromY; y < toY; y++) {
|
||||
leds[XY16(x, y)] += leds[XY16(x - 1, y)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int y = fromY; y < toY; y++)
|
||||
leds[XY16(0, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail to the left
|
||||
void StreamLeft(byte scale, int fromX = MATRIX_WIDTH, int toX = 0, int fromY = 0, int toY = MATRIX_HEIGHT)
|
||||
{
|
||||
for (int x = toX; x < fromX; x++) {
|
||||
for (int y = fromY; y < toY; y++) {
|
||||
leds[XY16(x, y)] += leds[XY16(x + 1, y)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int y = fromY; y < toY; y++)
|
||||
leds[XY16(0, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail downwards
|
||||
void StreamDown(byte scale)
|
||||
{
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = 1; y < MATRIX_HEIGHT; y++) {
|
||||
leds[XY16(x, y)] += leds[XY16(x, y - 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
leds[XY16(x, 0)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail upwards
|
||||
void StreamUp(byte scale)
|
||||
{
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = MATRIX_HEIGHT - 2; y >= 0; y--) {
|
||||
leds[XY16(x, y)] += leds[XY16(x, y + 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail up and to the left
|
||||
void StreamUpAndLeft(byte scale)
|
||||
{
|
||||
for (int x = 0; x < MATRIX_WIDTH - 1; x++) {
|
||||
for (int y = MATRIX_HEIGHT - 2; y >= 0; y--) {
|
||||
leds[XY16(x, y)] += leds[XY16(x + 1, y + 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1)].nscale8(scale);
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++)
|
||||
leds[XY16(MATRIX_WIDTH - 1, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail up and to the right
|
||||
void StreamUpAndRight(byte scale)
|
||||
{
|
||||
for (int x = 0; x < MATRIX_WIDTH - 1; x++) {
|
||||
for (int y = MATRIX_HEIGHT - 2; y >= 0; y--) {
|
||||
leds[XY16(x + 1, y)] += leds[XY16(x, y + 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
// fade the bottom row
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1)].nscale8(scale);
|
||||
|
||||
// fade the right column
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++)
|
||||
leds[XY16(MATRIX_WIDTH - 1, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// just move everything one line down
|
||||
void MoveDown() {
|
||||
for (int y = MATRIX_HEIGHT - 1; y > 0; y--) {
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
leds[XY16(x, y)] = leds[XY16(x, y - 1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// just move everything one line down
|
||||
void VerticalMoveFrom(int start, int end) {
|
||||
for (int y = end; y > start; y--) {
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
leds[XY16(x, y)] = leds[XY16(x, y - 1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy the rectangle defined with 2 points x0, y0, x1, y1
|
||||
// to the rectangle beginning at x2, x3
|
||||
void Copy(byte x0, byte y0, byte x1, byte y1, byte x2, byte y2) {
|
||||
for (int y = y0; y < y1 + 1; y++) {
|
||||
for (int x = x0; x < x1 + 1; x++) {
|
||||
leds[XY16(x + x2 - x0, y + y2 - y0)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rotate + copy triangle (MATRIX_CENTER_X*MATRIX_CENTER_X)
|
||||
void RotateTriangle() {
|
||||
for (int x = 1; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < x; y++) {
|
||||
leds[XY16(x, 7 - y)] = leds[XY16(7 - x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mirror + copy triangle (MATRIX_CENTER_X*MATRIX_CENTER_X)
|
||||
void MirrorTriangle() {
|
||||
for (int x = 1; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < x; y++) {
|
||||
leds[XY16(7 - y, x)] = leds[XY16(7 - x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw static rainbow triangle pattern (MATRIX_CENTER_XxWIDTH / 2)
|
||||
// (just for debugging)
|
||||
void RainbowTriangle() {
|
||||
for (int i = 0; i < MATRIX_CENTER_X; i++) {
|
||||
for (int j = 0; j <= i; j++) {
|
||||
Pixel(7 - i, j, i * j * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BresenhamLine(int x0, int y0, int x1, int y1, byte colorIndex)
|
||||
{
|
||||
BresenhamLine(x0, y0, x1, y1, ColorFromCurrentPalette(colorIndex));
|
||||
}
|
||||
|
||||
void BresenhamLine(int x0, int y0, int x1, int y1, CRGB color)
|
||||
{
|
||||
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
||||
int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
|
||||
int err = dx + dy, e2;
|
||||
for (;;) {
|
||||
leds[XY16(x0, y0)] += color;
|
||||
if (x0 == x1 && y0 == y1) break;
|
||||
e2 = 2 * err;
|
||||
if (e2 > dy) {
|
||||
err += dy;
|
||||
x0 += sx;
|
||||
}
|
||||
if (e2 < dx) {
|
||||
err += dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) {
|
||||
return ColorFromPalette(currentPalette, index, brightness, currentBlendType);
|
||||
}
|
||||
|
||||
CRGB HsvToRgb(uint8_t h, uint8_t s, uint8_t v) {
|
||||
CHSV hsv = CHSV(h, s, v);
|
||||
CRGB rgb;
|
||||
hsv2rgb_spectrum(hsv, rgb);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
void NoiseVariablesSetup() {
|
||||
noisesmoothing = 200;
|
||||
|
||||
noise_x = random16();
|
||||
noise_y = random16();
|
||||
noise_z = random16();
|
||||
noise_scale_x = 6000;
|
||||
noise_scale_y = 6000;
|
||||
}
|
||||
|
||||
void FillNoise() {
|
||||
for (uint16_t i = 0; i < MATRIX_WIDTH; i++) {
|
||||
uint32_t ioffset = noise_scale_x * (i - MATRIX_CENTRE_Y);
|
||||
|
||||
for (uint16_t j = 0; j < MATRIX_HEIGHT; j++) {
|
||||
uint32_t joffset = noise_scale_y * (j - MATRIX_CENTRE_Y);
|
||||
|
||||
byte data = inoise16(noise_x + ioffset, noise_y + joffset, noise_z) >> 8;
|
||||
|
||||
uint8_t olddata = noise[i][j];
|
||||
uint8_t newdata = scale8(olddata, noisesmoothing) + scale8(data, 256 - noisesmoothing);
|
||||
data = newdata;
|
||||
|
||||
noise[i][j] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// non leds2 memory version.
|
||||
void MoveX(byte delta)
|
||||
{
|
||||
|
||||
CRGB tmp = 0;
|
||||
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++)
|
||||
{
|
||||
|
||||
// Shift Left: https://codedost.com/c/arraypointers-in-c/c-program-shift-elements-array-left-direction/
|
||||
// Computationally heavier but doesn't need an entire leds2 array
|
||||
|
||||
tmp = leds[XY16(0, y)];
|
||||
for (int m = 0; m < delta; m++)
|
||||
{
|
||||
// Do this delta time for each row... computationally expensive potentially.
|
||||
for(int x = 0; x < MATRIX_WIDTH; x++)
|
||||
{
|
||||
leds[XY16(x, y)] = leds [XY16(x+1, y)];
|
||||
}
|
||||
|
||||
leds[XY16(MATRIX_WIDTH-1, y)] = tmp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Shift
|
||||
for (int x = 0; x < MATRIX_WIDTH - delta; x++) {
|
||||
leds2[XY(x, y)] = leds[XY(x + delta, y)];
|
||||
}
|
||||
|
||||
// Wrap around
|
||||
for (int x = MATRIX_WIDTH - delta; x < MATRIX_WIDTH; x++) {
|
||||
leds2[XY(x, y)] = leds[XY(x + delta - MATRIX_WIDTH, y)];
|
||||
}
|
||||
*/
|
||||
} // end row loop
|
||||
|
||||
/*
|
||||
// write back to leds
|
||||
for (uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
leds[XY(x, y)] = leds2[XY(x, y)];
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void MoveY(byte delta)
|
||||
{
|
||||
|
||||
CRGB tmp = 0;
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
{
|
||||
tmp = leds[XY16(x, 0)];
|
||||
for (int m = 0; m < delta; m++) // moves
|
||||
{
|
||||
// Do this delta time for each row... computationally expensive potentially.
|
||||
for(int y = 0; y < MATRIX_HEIGHT; y++)
|
||||
{
|
||||
leds[XY16(x, y)] = leds [XY16(x, y+1)];
|
||||
}
|
||||
|
||||
leds[XY16(x, MATRIX_HEIGHT-1)] = tmp;
|
||||
}
|
||||
} // end column loop
|
||||
} /// MoveY
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from Noel Bundy's work: https://github.com/TwystNeko/Object3d
|
||||
* Copyright (c) 2014 Noel Bundy
|
||||
*
|
||||
* Portions of this code are adapted from the Petty library: https://code.google.com/p/peggy/
|
||||
* Copyright (c) 2008 Windell H Oskay. All right reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Geometry_H
|
||||
#define Geometry_H
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
float x, y, z;
|
||||
Vertex()
|
||||
{
|
||||
this->set(0, 0, 0);
|
||||
}
|
||||
|
||||
Vertex(float x, float y, float z)
|
||||
{
|
||||
this->set(x, y, z);
|
||||
}
|
||||
|
||||
void set(float x, float y, float z)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
}
|
||||
};
|
||||
|
||||
struct EdgePoint
|
||||
{
|
||||
int x, y;
|
||||
boolean visible;
|
||||
|
||||
EdgePoint()
|
||||
{
|
||||
this->set(0, 0);
|
||||
this->visible = false;
|
||||
}
|
||||
|
||||
void set(int a, int b)
|
||||
{
|
||||
this->x = a;
|
||||
this->y = b;
|
||||
}
|
||||
};
|
||||
|
||||
struct Point
|
||||
{
|
||||
float x, y;
|
||||
|
||||
Point()
|
||||
{
|
||||
set(0, 0);
|
||||
}
|
||||
|
||||
Point(float x, float y)
|
||||
{
|
||||
set(x, y);
|
||||
}
|
||||
|
||||
void set(float x, float y)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct squareFace
|
||||
{
|
||||
int length;
|
||||
int sommets[4];
|
||||
int ed[4];
|
||||
|
||||
squareFace()
|
||||
{
|
||||
set(-1, -1, -1, -1);
|
||||
}
|
||||
|
||||
squareFace(int a, int b, int c, int d)
|
||||
{
|
||||
this->length = 4;
|
||||
this->sommets[0] = a;
|
||||
this->sommets[1] = b;
|
||||
this->sommets[2] = c;
|
||||
this->sommets[3] = d;
|
||||
}
|
||||
|
||||
void set(int a, int b, int c, int d)
|
||||
{
|
||||
this->length = 4;
|
||||
this->sommets[0] = a;
|
||||
this->sommets[1] = b;
|
||||
this->sommets[2] = c;
|
||||
this->sommets[3] = d;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct triFace
|
||||
{
|
||||
int length;
|
||||
int sommets[3];
|
||||
int ed[3];
|
||||
|
||||
triFace()
|
||||
{
|
||||
set(-1,-1,-1);
|
||||
}
|
||||
triFace(int a, int b, int c)
|
||||
{
|
||||
this->length =3;
|
||||
this->sommets[0]=a;
|
||||
this->sommets[1]=b;
|
||||
this->sommets[2]=c;
|
||||
}
|
||||
void set(int a, int b, int c)
|
||||
{
|
||||
this->length =3;
|
||||
this->sommets[0]=a;
|
||||
this->sommets[1]=b;
|
||||
this->sommets[2]=c;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternAttract_H
|
||||
|
||||
class PatternAttract : public Drawable {
|
||||
private:
|
||||
const int count = 8;
|
||||
Attractor attractor;
|
||||
|
||||
public:
|
||||
PatternAttract() {
|
||||
name = (char *)"Attract";
|
||||
}
|
||||
|
||||
void start() {
|
||||
int direction = random(0, 2);
|
||||
if (direction == 0)
|
||||
direction = -1;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid boid = Boid(15, 31 - i);
|
||||
boid.mass = 1; // random(0.1, 2);
|
||||
boid.velocity.x = ((float) random(40, 50)) / 100.0;
|
||||
boid.velocity.x *= direction;
|
||||
boid.velocity.y = 0;
|
||||
boid.colorIndex = i * 32;
|
||||
boids[i] = boid;
|
||||
//dim = random(170, 250);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// dim all pixels on the display
|
||||
uint8_t dim = beatsin8(2, 170, 250);
|
||||
effects.DimAll(dim);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid boid = boids[i];
|
||||
|
||||
PVector force = attractor.attract(boid);
|
||||
boid.applyForce(force);
|
||||
|
||||
boid.update();
|
||||
effects.drawBackgroundFastLEDPixelCRGB(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex));
|
||||
|
||||
boids[i] = boid;
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternBounce_H
|
||||
|
||||
class PatternBounce : public Drawable {
|
||||
private:
|
||||
static const int count = 32;
|
||||
PVector gravity = PVector(0, 0.0125);
|
||||
|
||||
public:
|
||||
PatternBounce() {
|
||||
name = (char *)"Bounce";
|
||||
}
|
||||
|
||||
void start() {
|
||||
unsigned int colorWidth = 256 / count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid boid = Boid(i, 0);
|
||||
boid.velocity.x = 0;
|
||||
boid.velocity.y = i * -0.01;
|
||||
boid.colorIndex = colorWidth * i;
|
||||
boid.maxforce = 10;
|
||||
boid.maxspeed = 10;
|
||||
boids[i] = boid;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// dim all pixels on the display
|
||||
effects.DimAll(170); effects.ShowFrame();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid boid = boids[i];
|
||||
|
||||
boid.applyForce(gravity);
|
||||
|
||||
boid.update();
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex));
|
||||
|
||||
if (boid.location.y >= MATRIX_HEIGHT - 1) {
|
||||
boid.location.y = MATRIX_HEIGHT - 1;
|
||||
boid.velocity.y *= -1.0;
|
||||
}
|
||||
|
||||
boids[i] = boid;
|
||||
}
|
||||
|
||||
return 15;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from Noel Bundy's work: https://github.com/TwystNeko/Object3d
|
||||
* Copyright (c) 2014 Noel Bundy
|
||||
*
|
||||
* Portions of this code are adapted from the Petty library: https://code.google.com/p/peggy/
|
||||
* Copyright (c) 2008 Windell H Oskay. All right reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternCube_H
|
||||
#define PatternCube_H
|
||||
|
||||
class PatternCube : public Drawable {
|
||||
private:
|
||||
float focal = 30; // Focal of the camera
|
||||
int cubeWidth = 28; // Cube size
|
||||
float Angx = 20.0, AngxSpeed = 0.05; // rotation (angle+speed) around X-axis
|
||||
float Angy = 10.0, AngySpeed = 0.05; // rotation (angle+speed) around Y-axis
|
||||
float Ox = 15.5, Oy = 15.5; // position (x,y) of the frame center
|
||||
int zCamera = 110; // distance from cube to the eye of the camera
|
||||
|
||||
// Local vertices
|
||||
Vertex local[8];
|
||||
// Camera aligned vertices
|
||||
Vertex aligned[8];
|
||||
// On-screen projected vertices
|
||||
Point screen[8];
|
||||
// Faces
|
||||
squareFace face[6];
|
||||
// Edges
|
||||
EdgePoint edge[12];
|
||||
int nbEdges;
|
||||
// ModelView matrix
|
||||
float m00, m01, m02, m10, m11, m12, m20, m21, m22;
|
||||
|
||||
// constructs the cube
|
||||
void make(int w)
|
||||
{
|
||||
nbEdges = 0;
|
||||
|
||||
local[0].set(-w, w, w);
|
||||
local[1].set(w, w, w);
|
||||
local[2].set(w, -w, w);
|
||||
local[3].set(-w, -w, w);
|
||||
local[4].set(-w, w, -w);
|
||||
local[5].set(w, w, -w);
|
||||
local[6].set(w, -w, -w);
|
||||
local[7].set(-w, -w, -w);
|
||||
|
||||
face[0].set(1, 0, 3, 2);
|
||||
face[1].set(0, 4, 7, 3);
|
||||
face[2].set(4, 0, 1, 5);
|
||||
face[3].set(4, 5, 6, 7);
|
||||
face[4].set(1, 2, 6, 5);
|
||||
face[5].set(2, 3, 7, 6);
|
||||
|
||||
int f, i;
|
||||
for (f = 0; f < 6; f++)
|
||||
{
|
||||
for (i = 0; i < face[f].length; i++)
|
||||
{
|
||||
face[f].ed[i] = this->findEdge(face[f].sommets[i], face[f].sommets[i ? i - 1 : face[f].length - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finds edges from faces
|
||||
int findEdge(int a, int b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nbEdges; i++)
|
||||
if ((edge[i].x == a && edge[i].y == b) || (edge[i].x == b && edge[i].y == a))
|
||||
return i;
|
||||
edge[nbEdges++].set(a, b);
|
||||
return i;
|
||||
}
|
||||
|
||||
// rotates according to angle x&y
|
||||
void rotate(float angx, float angy)
|
||||
{
|
||||
int i;
|
||||
float cx = cos(angx);
|
||||
float sx = sin(angx);
|
||||
float cy = cos(angy);
|
||||
float sy = sin(angy);
|
||||
|
||||
m00 = cy;
|
||||
m01 = 0;
|
||||
m02 = -sy;
|
||||
m10 = sx * sy;
|
||||
m11 = cx;
|
||||
m12 = sx * cy;
|
||||
m20 = cx * sy;
|
||||
m21 = -sx;
|
||||
m22 = cx * cy;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
aligned[i].x = m00 * local[i].x + m01 * local[i].y + m02 * local[i].z;
|
||||
aligned[i].y = m10 * local[i].x + m11 * local[i].y + m12 * local[i].z;
|
||||
aligned[i].z = m20 * local[i].x + m21 * local[i].y + m22 * local[i].z + zCamera;
|
||||
|
||||
screen[i].x = floor((Ox + focal * aligned[i].x / aligned[i].z));
|
||||
screen[i].y = floor((Oy - focal * aligned[i].y / aligned[i].z));
|
||||
}
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
edge[i].visible = false;
|
||||
|
||||
Point *pa, *pb, *pc;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
pa = screen + face[i].sommets[0];
|
||||
pb = screen + face[i].sommets[1];
|
||||
pc = screen + face[i].sommets[2];
|
||||
|
||||
boolean back = ((pb->x - pa->x) * (pc->y - pa->y) - (pb->y - pa->y) * (pc->x - pa->x)) < 0;
|
||||
if (!back)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
edge[face[i].ed[j]].visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte hue = 0;
|
||||
int step = 0;
|
||||
|
||||
public:
|
||||
PatternCube() {
|
||||
name = (char *)"Cube";
|
||||
make(cubeWidth);
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
uint8_t blurAmount = beatsin8(2, 10, 255);
|
||||
|
||||
#if FASTLED_VERSION >= 3001000
|
||||
blur2d(effects.leds, MATRIX_WIDTH, MATRIX_HEIGHT, blurAmount);
|
||||
#else
|
||||
effects.DimAll(blurAmount); effects.ShowFrame();
|
||||
#endif
|
||||
|
||||
zCamera = beatsin8(2, 100, 140);
|
||||
AngxSpeed = beatsin8(3, 1, 10) / 100.0f;
|
||||
AngySpeed = beatcos8(5, 1, 10) / 100.0f;
|
||||
|
||||
// Update values
|
||||
Angx += AngxSpeed;
|
||||
Angy += AngySpeed;
|
||||
if (Angx >= TWO_PI)
|
||||
Angx -= TWO_PI;
|
||||
if (Angy >= TWO_PI)
|
||||
Angy -= TWO_PI;
|
||||
|
||||
rotate(Angx, Angy);
|
||||
|
||||
// Draw cube
|
||||
int i;
|
||||
|
||||
CRGB color = effects.ColorFromCurrentPalette(hue, 128);
|
||||
|
||||
// Backface
|
||||
EdgePoint *e;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
e = edge + i;
|
||||
if (!e->visible) {
|
||||
dma_display->drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color);
|
||||
}
|
||||
}
|
||||
|
||||
color = effects.ColorFromCurrentPalette(hue, 255);
|
||||
|
||||
// Frontface
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
e = edge + i;
|
||||
if (e->visible)
|
||||
{
|
||||
dma_display->drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color);
|
||||
}
|
||||
}
|
||||
|
||||
step++;
|
||||
if (step == 8) {
|
||||
step = 0;
|
||||
hue++;
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 20;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Funky Noise" by Stefan Petrick: https://github.com/StefanPetrick/FunkyNoise
|
||||
* Copyright (c) 2014 Stefan Petrick
|
||||
* http://www.stefan-petrick.de/wordpress_beta
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternElectricMandala_H
|
||||
|
||||
class PatternElectricMandala : public Drawable {
|
||||
private:
|
||||
|
||||
// The coordinates for 16-bit noise spaces.
|
||||
#define NUM_LAYERS 1
|
||||
|
||||
// used for the random based animations
|
||||
int16_t dx;
|
||||
int16_t dy;
|
||||
int16_t dz;
|
||||
int16_t dsx;
|
||||
int16_t dsy;
|
||||
|
||||
public:
|
||||
PatternElectricMandala() {
|
||||
name = (char *)"ElectricMandala";
|
||||
}
|
||||
|
||||
void start() {
|
||||
// set to reasonable values to avoid a black out
|
||||
noisesmoothing = 200;
|
||||
|
||||
// just any free input pin
|
||||
//random16_add_entropy(analogRead(18));
|
||||
|
||||
// fill coordinates with random values
|
||||
// set zoom levels
|
||||
noise_x = random16();
|
||||
noise_y = random16();
|
||||
noise_z = random16();
|
||||
noise_scale_x = 6000;
|
||||
noise_scale_y = 6000;
|
||||
|
||||
// for the random movement
|
||||
dx = random8();
|
||||
dy = random8();
|
||||
dz = random8();
|
||||
dsx = random8();
|
||||
dsy = random8();
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
#if FASTLED_VERSION >= 3001000
|
||||
// a new parameter set every 15 seconds
|
||||
EVERY_N_SECONDS(15) {
|
||||
//SetupRandomPalette3();
|
||||
dy = random16(500) - 250; // random16(2000) - 1000 is pretty fast but works fine, too
|
||||
dx = random16(500) - 250;
|
||||
dz = random16(500) - 250;
|
||||
noise_scale_x = random16(10000) + 2000;
|
||||
noise_scale_y = random16(10000) + 2000;
|
||||
}
|
||||
#endif
|
||||
|
||||
noise_y += dy;
|
||||
noise_x += dx;
|
||||
noise_z += dz;
|
||||
|
||||
effects.FillNoise();
|
||||
ShowNoiseLayer(0, 1, 0);
|
||||
|
||||
effects.Caleidoscope3();
|
||||
effects.Caleidoscope1();
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 30;
|
||||
}
|
||||
|
||||
// show just one layer
|
||||
void ShowNoiseLayer(byte layer, byte colorrepeat, byte colorshift) {
|
||||
for (uint16_t i = 0; i < MATRIX_WIDTH; i++) {
|
||||
for (uint16_t j = 0; j < MATRIX_HEIGHT; j++) {
|
||||
|
||||
uint8_t color = noise[i][j];
|
||||
|
||||
uint8_t bri = color;
|
||||
|
||||
// assign a color depending on the actual palette
|
||||
CRGB pixel = ColorFromPalette(effects.currentPalette, colorrepeat * (color + colorshift), bri);
|
||||
|
||||
effects.leds[XY16(i, j)] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from FastLED Fire2012 example by Mark Kriegsman: https://github.com/FastLED/FastLED/tree/master/examples/Fire2012WithPalette
|
||||
* Copyright (c) 2013 FastLED
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternFire_H
|
||||
#define PatternFire_H
|
||||
|
||||
#ifndef Effects_H
|
||||
#include "Effects.h"
|
||||
#endif
|
||||
|
||||
class PatternFire : public Drawable {
|
||||
private:
|
||||
|
||||
public:
|
||||
PatternFire() {
|
||||
name = (char *)"Fire";
|
||||
}
|
||||
|
||||
// There are two main parameters you can play with to control the look and
|
||||
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
|
||||
// in step 3 above).
|
||||
//
|
||||
// cooling: How much does the air cool as it rises?
|
||||
// Less cooling = taller flames. More cooling = shorter flames.
|
||||
// Default 55, suggested range 20-100
|
||||
int cooling = 100;
|
||||
|
||||
// sparking: What chance (out of 255) is there that a new spark will be lit?
|
||||
// Higher chance = more roaring fire. Lower chance = more flickery fire.
|
||||
// Default 120, suggested range 50-200.
|
||||
unsigned int sparking = 100;
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// Add entropy to random number generator; we use a lot of it.
|
||||
random16_add_entropy( random16());
|
||||
|
||||
effects.DimAll(235);
|
||||
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
// Step 1. Cool down every cell a little
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
int xy = XY(x, y);
|
||||
heat[xy] = qsub8(heat[xy], random8(0, ((cooling * 10) / MATRIX_HEIGHT) + 2));
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
heat[XY(x, y)] = (heat[XY(x, y + 1)] + heat[XY(x, y + 2)] + heat[XY(x, y + 2)]) / 3;
|
||||
}
|
||||
|
||||
// Step 2. Randomly ignite new 'sparks' of heat
|
||||
if (random8() < sparking) {
|
||||
// int x = (p[0] + p[1] + p[2]) / 3;
|
||||
|
||||
int xy = XY(x, MATRIX_HEIGHT - 1);
|
||||
heat[xy] = qadd8(heat[xy], random8(160, 255));
|
||||
}
|
||||
|
||||
// Step 4. Map from heat cells to LED colors
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
int xy = XY(x, y);
|
||||
byte colorIndex = heat[xy];
|
||||
|
||||
// Recommend that you use values 0-240 rather than
|
||||
// the usual 0-255, as the last 15 colors will be
|
||||
// 'wrapping around' from the hot end to the cold end,
|
||||
// which looks wrong.
|
||||
colorIndex = scale8(colorIndex, 200);
|
||||
|
||||
// override color 0 to ensure a black background?
|
||||
if (colorIndex != 0)
|
||||
// effects.leds[xy] = CRGB::Black;
|
||||
// else
|
||||
effects.leds[xy] = effects.ColorFromCurrentPalette(colorIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(2);
|
||||
effects.MoveFractionalNoiseX(2);
|
||||
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 15;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Flocking" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/
|
||||
* Copyright (c) 2014 Daniel Shiffman
|
||||
* http://www.shiffman.net
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Flocking
|
||||
// Daniel Shiffman <http://www.shiffman.net>
|
||||
// The Nature of Code, Spring 2009
|
||||
|
||||
// Demonstration of Craig Reynolds' "Flocking" behavior
|
||||
// See: http://www.red3d.com/cwr/
|
||||
// Rules: Cohesion, Separation, Alignment
|
||||
|
||||
#ifndef PatternFlock_H
|
||||
#define PatternFlock_H
|
||||
|
||||
class PatternFlock : public Drawable {
|
||||
public:
|
||||
PatternFlock() {
|
||||
name = (char *)"Flock";
|
||||
}
|
||||
|
||||
static const int boidCount = 10;
|
||||
Boid predator;
|
||||
|
||||
PVector wind;
|
||||
byte hue = 0;
|
||||
bool predatorPresent = true;
|
||||
|
||||
void start() {
|
||||
for (int i = 0; i < boidCount; i++) {
|
||||
boids[i] = Boid(15, 15);
|
||||
boids[i].maxspeed = 0.380;
|
||||
boids[i].maxforce = 0.015;
|
||||
}
|
||||
|
||||
predatorPresent = random(0, 2) >= 1;
|
||||
if (predatorPresent) {
|
||||
predator = Boid(31, 31);
|
||||
predatorPresent = true;
|
||||
predator.maxspeed = 0.385;
|
||||
predator.maxforce = 0.020;
|
||||
predator.neighbordist = 16.0;
|
||||
predator.desiredseparation = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(230); effects.ShowFrame();
|
||||
|
||||
bool applyWind = random(0, 255) > 250;
|
||||
if (applyWind) {
|
||||
wind.x = Boid::randomf() * .015;
|
||||
wind.y = Boid::randomf() * .015;
|
||||
}
|
||||
|
||||
CRGB color = effects.ColorFromCurrentPalette(hue);
|
||||
|
||||
for (int i = 0; i < boidCount; i++) {
|
||||
Boid * boid = &boids[i];
|
||||
|
||||
if (predatorPresent) {
|
||||
// flee from predator
|
||||
boid->repelForce(predator.location, 10);
|
||||
}
|
||||
|
||||
boid->run(boids, boidCount);
|
||||
boid->wrapAroundBorders();
|
||||
PVector location = boid->location;
|
||||
// PVector velocity = boid->velocity;
|
||||
// backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color);
|
||||
// effects.leds[XY(location.x, location.y)] += color;
|
||||
effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color);
|
||||
|
||||
if (applyWind) {
|
||||
boid->applyForce(wind);
|
||||
applyWind = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (predatorPresent) {
|
||||
predator.run(boids, boidCount);
|
||||
predator.wrapAroundBorders();
|
||||
color = effects.ColorFromCurrentPalette(hue + 128);
|
||||
PVector location = predator.location;
|
||||
// PVector velocity = predator.velocity;
|
||||
// backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color);
|
||||
// effects.leds[XY(location.x, location.y)] += color;
|
||||
effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color);
|
||||
}
|
||||
|
||||
EVERY_N_MILLIS(200) {
|
||||
hue++;
|
||||
}
|
||||
|
||||
EVERY_N_SECONDS(30) {
|
||||
predatorPresent = !predatorPresent;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternFlowField_H
|
||||
|
||||
class PatternFlowField : public Drawable {
|
||||
public:
|
||||
PatternFlowField() {
|
||||
name = (char *)"FlowField";
|
||||
}
|
||||
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t z;
|
||||
|
||||
uint16_t speed = 1;
|
||||
uint16_t scale = 26;
|
||||
|
||||
static const int count = 40;
|
||||
|
||||
byte hue = 0;
|
||||
|
||||
void start() {
|
||||
x = random16();
|
||||
y = random16();
|
||||
z = random16();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
boids[i] = Boid(random(MATRIX_WIDTH), 0);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(240);
|
||||
|
||||
// CRGB color = effects.ColorFromCurrentPalette(hue);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid * boid = &boids[i];
|
||||
|
||||
int ioffset = scale * boid->location.x;
|
||||
int joffset = scale * boid->location.y;
|
||||
|
||||
byte angle = inoise8(x + ioffset, y + joffset, z);
|
||||
|
||||
boid->velocity.x = (float) sin8(angle) * 0.0078125 - 1.0;
|
||||
boid->velocity.y = -((float)cos8(angle) * 0.0078125 - 1.0);
|
||||
boid->update();
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(boid->location.x, boid->location.y, effects.ColorFromCurrentPalette(angle + hue)); // color
|
||||
|
||||
if (boid->location.x < 0 || boid->location.x >= MATRIX_WIDTH ||
|
||||
boid->location.y < 0 || boid->location.y >= MATRIX_HEIGHT) {
|
||||
boid->location.x = random(MATRIX_WIDTH);
|
||||
boid->location.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
EVERY_N_MILLIS(200) {
|
||||
hue++;
|
||||
}
|
||||
|
||||
x += speed;
|
||||
y += speed;
|
||||
z += speed;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 50;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternIncrementalDrift_H
|
||||
#define PatternIncrementalDrift_H
|
||||
|
||||
class PatternIncrementalDrift : public Drawable {
|
||||
public:
|
||||
PatternIncrementalDrift() {
|
||||
name = (char *)"Incremental Drift";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
uint8_t dim = beatsin8(2, 230, 250);
|
||||
effects.DimAll(dim); effects.ShowFrame();
|
||||
|
||||
for (int i = 2; i <= MATRIX_WIDTH / 2; i++)
|
||||
{
|
||||
CRGB color = effects.ColorFromCurrentPalette((i - 2) * (240 / (MATRIX_WIDTH / 2)));
|
||||
|
||||
uint8_t x = beatcos8((17 - i) * 2, MATRIX_CENTER_X - i, MATRIX_CENTER_X + i);
|
||||
uint8_t y = beatsin8((17 - i) * 2, MATRIX_CENTER_Y - i, MATRIX_CENTER_Y + i);
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, color);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternIncrementalDrift2_H
|
||||
#define PatternIncrementalDrift2_H
|
||||
|
||||
class PatternIncrementalDrift2 : public Drawable {
|
||||
public:
|
||||
PatternIncrementalDrift2() {
|
||||
name = (char *)"Incremental Drift Rose";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
uint8_t dim = beatsin8(2, 170, 250);
|
||||
effects.DimAll(dim); effects.ShowFrame();
|
||||
|
||||
for (uint8_t i = 0; i < 32; i++)
|
||||
{
|
||||
CRGB color;
|
||||
|
||||
uint8_t x = 0;
|
||||
uint8_t y = 0;
|
||||
|
||||
if (i < 16) {
|
||||
x = beatcos8((i + 1) * 2, i, MATRIX_WIDTH - i);
|
||||
y = beatsin8((i + 1) * 2, i, MATRIX_HEIGHT - i);
|
||||
color = effects.ColorFromCurrentPalette(i * 14);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = beatsin8((32 - i) * 2, MATRIX_WIDTH - i, i + 1);
|
||||
y = beatcos8((32 - i) * 2, MATRIX_HEIGHT - i, i + 1);
|
||||
color = effects.ColorFromCurrentPalette((31 - i) * 14);
|
||||
}
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, color);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternInfinity_H
|
||||
|
||||
class PatternInfinity : public Drawable {
|
||||
public:
|
||||
PatternInfinity() {
|
||||
name = (char *)"Infinity";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// dim all pixels on the display slightly
|
||||
// to 250/255 (98%) of their current brightness
|
||||
blur2d(effects.leds, MATRIX_WIDTH > 255 ? 255 : MATRIX_WIDTH, MATRIX_HEIGHT > 255 ? 255 : MATRIX_HEIGHT, 250);
|
||||
// effects.DimAll(250); effects.ShowFrame();
|
||||
|
||||
|
||||
// the Effects class has some sample oscillators
|
||||
// that move from 0 to 255 at different speeds
|
||||
effects.MoveOscillators();
|
||||
|
||||
// the horizontal position of the head of the infinity sign
|
||||
// oscillates from 0 to the maximum horizontal and back
|
||||
int x = (MATRIX_WIDTH - 1) - effects.p[1];
|
||||
|
||||
// the vertical position of the head oscillates
|
||||
// from 8 to 23 and back (hard-coded for a 32x32 matrix)
|
||||
int y = map8(sin8(effects.osci[3]), 8, 23);
|
||||
|
||||
// the hue oscillates from 0 to 255, overflowing back to 0
|
||||
byte hue = sin8(effects.osci[5]);
|
||||
|
||||
// draw a pixel at x,y using a color from the current palette
|
||||
effects.Pixel(x, y, hue);
|
||||
|
||||
effects.ShowFrame();
|
||||
return 30;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Inspired by 'Space Invader Generator': https://the8bitpimp.wordpress.com/2013/05/07/space-invader-generator
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternInvaders_H
|
||||
#define PatternInvaders_H
|
||||
|
||||
class PatternInvadersSmall : public Drawable {
|
||||
private:
|
||||
uint8_t x = 1;
|
||||
uint8_t y = 1;
|
||||
|
||||
public:
|
||||
PatternInvadersSmall() {
|
||||
name = (char *)"Invaders Small";
|
||||
}
|
||||
|
||||
void start() {
|
||||
dma_display->fillScreen(0);
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
CRGB color1 = effects.ColorFromCurrentPalette(random(0, 255));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 5; j++) {
|
||||
CRGB color = CRGB::Black;
|
||||
|
||||
if (random(0, 2) == 1) color = color1;
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x + i, y + j, color);
|
||||
|
||||
if (i < 2)
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x + (4 - i), y + j, color);
|
||||
}
|
||||
}
|
||||
|
||||
x += 6;
|
||||
if (x > 25) {
|
||||
x = 1;
|
||||
y += 6;
|
||||
}
|
||||
|
||||
if (y > 25) y = x = 1;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 125;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternInvadersMedium : public Drawable {
|
||||
private:
|
||||
uint8_t x = 0;
|
||||
uint8_t y = 0;
|
||||
|
||||
public:
|
||||
PatternInvadersMedium() {
|
||||
name = (char *)"Invaders Medium";
|
||||
}
|
||||
|
||||
void start() {
|
||||
dma_display->fillScreen(0);
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
CRGB color1 = effects.ColorFromCurrentPalette(random(0, 255));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 5; j++) {
|
||||
CRGB color = CRGB::Black;
|
||||
|
||||
if (random(0, 2) == 1) color = color1;
|
||||
|
||||
dma_display->fillRect(x + (i * 2), y + (j * 2), x + (i * 2 + 1), y + (j * 2 + 1), color);
|
||||
|
||||
if (i < 2)
|
||||
dma_display->fillRect(x + (8 - i * 2), y + (j * 2), x + (9 - i * 2), y + (j * 2 + 1), color);
|
||||
}
|
||||
}
|
||||
|
||||
x += 11;
|
||||
if (x > 22) {
|
||||
x = 0;
|
||||
y += 11;
|
||||
}
|
||||
|
||||
if (y > 22) y = x = 0;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 500;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternInvadersLarge : public Drawable {
|
||||
private:
|
||||
|
||||
public:
|
||||
PatternInvadersLarge() {
|
||||
name = (char *)"Invaders Large";
|
||||
}
|
||||
|
||||
void start() {
|
||||
dma_display->fillScreen(0);
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
dma_display->fillScreen(0);
|
||||
|
||||
CRGB color1 = effects.ColorFromCurrentPalette(random(0, 255));
|
||||
|
||||
for (int x = 0; x < 3; x++) {
|
||||
for (int y = 0; y < 5; y++) {
|
||||
CRGB color = CRGB::Black;
|
||||
|
||||
if (random(0, 2) == 1) {
|
||||
color = color1;
|
||||
}
|
||||
|
||||
dma_display->fillRect(1 + x * 6, 1 + y * 6, 5 + x * 6, 5 + y * 6, color);
|
||||
|
||||
if (x < 2)
|
||||
dma_display->fillRect(1 + (4 - x) * 6, 1 + y * 6, 5 + (4 - x) * 6, 5 + y * 6, color);
|
||||
}
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 2000;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from Andrew: http://pastebin.com/f22bfe94d
|
||||
* which, in turn, was "Adapted from the Life example on the Processing.org site"
|
||||
*
|
||||
* Made much more colorful by J.B. Langston: https://github.com/jblang/aurora/commit/6db5a884e3df5d686445c4f6b669f1668841929b
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternLife_H
|
||||
#define PatternLife_H
|
||||
|
||||
class Cell {
|
||||
public:
|
||||
byte alive : 1;
|
||||
byte prev : 1;
|
||||
byte hue: 6;
|
||||
byte brightness;
|
||||
};
|
||||
|
||||
class PatternLife : public Drawable {
|
||||
private:
|
||||
Cell world[MATRIX_WIDTH][MATRIX_HEIGHT];
|
||||
unsigned int density = 50;
|
||||
int generation = 0;
|
||||
|
||||
void randomFillWorld() {
|
||||
for (int i = 0; i < MATRIX_WIDTH; i++) {
|
||||
for (int j = 0; j < MATRIX_HEIGHT; j++) {
|
||||
if (random(100) < density) {
|
||||
world[i][j].alive = 1;
|
||||
world[i][j].brightness = 255;
|
||||
}
|
||||
else {
|
||||
world[i][j].alive = 0;
|
||||
world[i][j].brightness = 0;
|
||||
}
|
||||
world[i][j].prev = world[i][j].alive;
|
||||
world[i][j].hue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int neighbours(int x, int y) {
|
||||
return (world[(x + 1) % MATRIX_WIDTH][y].prev) +
|
||||
(world[x][(y + 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + MATRIX_WIDTH - 1) % MATRIX_WIDTH][y].prev) +
|
||||
(world[x][(y + MATRIX_HEIGHT - 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + 1) % MATRIX_WIDTH][(y + 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + MATRIX_WIDTH - 1) % MATRIX_WIDTH][(y + 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + MATRIX_WIDTH - 1) % MATRIX_WIDTH][(y + MATRIX_HEIGHT - 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + 1) % MATRIX_WIDTH][(y + MATRIX_HEIGHT - 1) % MATRIX_HEIGHT].prev);
|
||||
}
|
||||
|
||||
public:
|
||||
PatternLife() {
|
||||
name = (char *)"Life";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
if (generation == 0) {
|
||||
effects.ClearFrame();
|
||||
|
||||
randomFillWorld();
|
||||
}
|
||||
|
||||
// Display current generation
|
||||
for (int i = 0; i < MATRIX_WIDTH; i++) {
|
||||
for (int j = 0; j < MATRIX_HEIGHT; j++) {
|
||||
effects.leds[XY(i, j)] = effects.ColorFromCurrentPalette(world[i][j].hue * 4, world[i][j].brightness);
|
||||
}
|
||||
}
|
||||
|
||||
// Birth and death cycle
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
// Default is for cell to stay the same
|
||||
if (world[x][y].brightness > 0 && world[x][y].prev == 0)
|
||||
world[x][y].brightness *= 0.9;
|
||||
int count = neighbours(x, y);
|
||||
if (count == 3 && world[x][y].prev == 0) {
|
||||
// A new cell is born
|
||||
world[x][y].alive = 1;
|
||||
world[x][y].hue += 2;
|
||||
world[x][y].brightness = 255;
|
||||
} else if ((count < 2 || count > 3) && world[x][y].prev == 1) {
|
||||
// Cell dies
|
||||
world[x][y].alive = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy next generation into place
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
world[x][y].prev = world[x][y].alive;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
generation++;
|
||||
if (generation >= 256)
|
||||
generation = 0;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 60;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Many thanks to Jamis Buck for the documentation of the Growing Tree maze generation algorithm: http://weblog.jamisbuck.org/2011/1/27/maze-generation-growing-tree-algorithm
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternMaze_H
|
||||
#define PatternMaze_H
|
||||
|
||||
class PatternMaze : public Drawable {
|
||||
private:
|
||||
enum Directions {
|
||||
None = 0,
|
||||
Up = 1,
|
||||
Down = 2,
|
||||
Left = 4,
|
||||
Right = 8,
|
||||
};
|
||||
|
||||
struct Point{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
static Point New(int x, int y) {
|
||||
Point point;
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
return point;
|
||||
}
|
||||
|
||||
Point Move(Directions direction) {
|
||||
switch (direction)
|
||||
{
|
||||
case Up:
|
||||
return New(x, y - 1);
|
||||
|
||||
case Down:
|
||||
return New(x, y + 1);
|
||||
|
||||
case Left:
|
||||
return New(x - 1, y);
|
||||
|
||||
case Right:
|
||||
default:
|
||||
return New(x + 1, y);
|
||||
}
|
||||
}
|
||||
|
||||
static Directions Opposite(Directions direction) {
|
||||
switch (direction) {
|
||||
case Up:
|
||||
return Down;
|
||||
|
||||
case Down:
|
||||
return Up;
|
||||
|
||||
case Left:
|
||||
return Right;
|
||||
|
||||
case Right:
|
||||
default:
|
||||
return Left;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// int width = 16;
|
||||
// int height = 16;
|
||||
|
||||
static const int width = MATRIX_WIDTH / 2;
|
||||
static const int height = MATRIX_HEIGHT / 2;
|
||||
|
||||
|
||||
Directions grid[width][height];
|
||||
|
||||
Point point;
|
||||
|
||||
Point cells[256];
|
||||
int cellCount = 0;
|
||||
|
||||
int algorithm = 0;
|
||||
int algorithmCount = 1;
|
||||
|
||||
byte hue = 0;
|
||||
byte hueOffset = 0;
|
||||
|
||||
Directions directions[4] = { Up, Down, Left, Right };
|
||||
|
||||
void removeCell(int index) {// shift cells after index down one
|
||||
for (int i = index; i < cellCount - 1; i++) {
|
||||
cells[i] = cells[i + 1];
|
||||
}
|
||||
|
||||
cellCount--;
|
||||
}
|
||||
|
||||
void shuffleDirections() {
|
||||
for (int a = 0; a < 4; a++)
|
||||
{
|
||||
int r = random(a, 4);
|
||||
Directions temp = directions[a];
|
||||
directions[a] = directions[r];
|
||||
directions[r] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
Point createPoint(int x, int y) {
|
||||
Point point;
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
return point;
|
||||
}
|
||||
|
||||
CRGB chooseColor(int index) {
|
||||
byte h = index + hueOffset;
|
||||
|
||||
switch (algorithm) {
|
||||
case 0:
|
||||
default:
|
||||
return effects.ColorFromCurrentPalette(h);
|
||||
|
||||
case 1:
|
||||
return effects.ColorFromCurrentPalette(hue++);
|
||||
}
|
||||
}
|
||||
|
||||
int chooseIndex(int max) {
|
||||
switch (algorithm) {
|
||||
case 0:
|
||||
default:
|
||||
// choose newest (recursive backtracker)
|
||||
return max - 1;
|
||||
|
||||
case 1:
|
||||
// choose random(Prim's)
|
||||
return random(max);
|
||||
|
||||
// case 2:
|
||||
// // choose oldest (not good, so disabling)
|
||||
// return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void generateMaze() {
|
||||
while (cellCount > 1) {
|
||||
drawNextCell();
|
||||
}
|
||||
}
|
||||
|
||||
void drawNextCell() {
|
||||
int index = chooseIndex(cellCount);
|
||||
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
point = cells[index];
|
||||
|
||||
Point imagePoint = createPoint(point.x * 2, point.y * 2);
|
||||
|
||||
//effects.drawBackgroundFastLEDPixelCRGB(imagePoint.x, imagePoint.y, CRGB(CRGB::Gray));
|
||||
|
||||
shuffleDirections();
|
||||
|
||||
CRGB color = chooseColor(index);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Directions direction = directions[i];
|
||||
|
||||
Point newPoint = point.Move(direction);
|
||||
if (newPoint.x >= 0 && newPoint.y >= 0 && newPoint.x < width && newPoint.y < height && grid[newPoint.y][newPoint.x] == None) {
|
||||
grid[point.y][point.x] = (Directions) ((int) grid[point.y][point.x] | (int) direction);
|
||||
grid[newPoint.y][newPoint.x] = (Directions) ((int) grid[newPoint.y][newPoint.x] | (int) point.Opposite(direction));
|
||||
|
||||
Point newImagePoint = imagePoint.Move(direction);
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(newImagePoint.x, newImagePoint.y, color);
|
||||
|
||||
cellCount++;
|
||||
cells[cellCount - 1] = newPoint;
|
||||
|
||||
index = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > -1) {
|
||||
Point finishedPoint = cells[index];
|
||||
imagePoint = createPoint(finishedPoint.x * 2, finishedPoint.y * 2);
|
||||
effects.drawBackgroundFastLEDPixelCRGB(imagePoint.x, imagePoint.y, color);
|
||||
|
||||
removeCell(index);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
PatternMaze() {
|
||||
name = (char *)"Maze";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
if (cellCount < 1) {
|
||||
|
||||
effects.ClearFrame();
|
||||
|
||||
// reset the maze grid
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
grid[y][x] = None;
|
||||
}
|
||||
}
|
||||
|
||||
int x = random(width);
|
||||
int y = random(height);
|
||||
|
||||
cells[0] = createPoint(x, y);
|
||||
|
||||
cellCount = 1;
|
||||
|
||||
hue = 0;
|
||||
hueOffset = random(0, 256);
|
||||
|
||||
}
|
||||
|
||||
drawNextCell();
|
||||
|
||||
if (cellCount < 1) {
|
||||
algorithm++;
|
||||
if (algorithm >= algorithmCount)
|
||||
algorithm = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void start() {
|
||||
effects.ClearFrame();
|
||||
cellCount = 0;
|
||||
hue = 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Munch pattern created by J.B. Langston: https://github.com/jblang/aurora/blob/master/PatternMunch.h
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternMunch_H
|
||||
#define PatternMunch_H
|
||||
|
||||
|
||||
class PatternMunch : public Drawable {
|
||||
private:
|
||||
byte count = 0;
|
||||
byte dir = 1;
|
||||
byte flip = 0;
|
||||
byte generation = 0;
|
||||
|
||||
public:
|
||||
PatternMunch() {
|
||||
name = (char *)"Munch";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
for (uint16_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (uint16_t y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
effects.leds[XY16(x, y)] = (x ^ y ^ flip) < count ? effects.ColorFromCurrentPalette(((x ^ y) << 2) + generation) : CRGB::Black;
|
||||
|
||||
// The below is more pleasant
|
||||
// effects.leds[XY(x, y)] = effects.ColorFromCurrentPalette(((x ^ y) << 2) + generation) ;
|
||||
}
|
||||
}
|
||||
|
||||
count += dir;
|
||||
|
||||
if (count <= 0 || count >= MATRIX_WIDTH) {
|
||||
dir = -dir;
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
if (flip == 0)
|
||||
flip = MATRIX_WIDTH-1;
|
||||
else
|
||||
flip = 0;
|
||||
}
|
||||
|
||||
generation++;
|
||||
|
||||
// show it ffs!
|
||||
effects.ShowFrame();
|
||||
return 60;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Noise Smearing" by Stefan Petrick: https://gist.githubusercontent.com/embedded-creations/5cd47d83cb0e04f4574d/raw/ebf6a82b4755d55cfba3bf6598f7b19047f89daf/NoiseSmearing.ino
|
||||
* Copyright (c) 2014 Stefan Petrick
|
||||
* http://www.stefan-petrick.de/wordpress_beta
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternNoiseSmearing_H
|
||||
#define PatternNoiseSmearing_H
|
||||
|
||||
byte patternNoiseSmearingHue = 0;
|
||||
|
||||
class PatternMultipleStream : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream() {
|
||||
name = (char *)"MultipleStream";
|
||||
}
|
||||
|
||||
// this pattern draws two points to the screen based on sin/cos if a counter
|
||||
// (comment out NoiseSmearWithRadius to see pattern of pixels)
|
||||
// these pixels are smeared by a large radius, giving a lot of movement
|
||||
// the image is dimmed before each drawing to not saturate the screen with color
|
||||
// the smear has an offset so the pixels usually have a trail leading toward the upper left
|
||||
unsigned int drawFrame() {
|
||||
static unsigned long counter = 0;
|
||||
#if 0
|
||||
// this counter lets put delays between each frame and still get the same animation
|
||||
counter++;
|
||||
#else
|
||||
// this counter updates in real time and can't be slowed down for debugging
|
||||
counter = millis() / 10;
|
||||
#endif
|
||||
|
||||
byte x1 = 4 + sin8(counter * 2) / 10;
|
||||
byte x2 = 8 + sin8(counter * 2) / 16;
|
||||
byte y2 = 8 + cos8((counter * 2) / 3) / 16;
|
||||
|
||||
effects.leds[XY(x1, x2)] = effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
effects.leds[XY(x2, y2)] = effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 128);
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(8);
|
||||
effects.MoveFractionalNoiseX();
|
||||
|
||||
effects.MoveY(8);
|
||||
effects.MoveFractionalNoiseY();
|
||||
|
||||
patternNoiseSmearingHue++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream2 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream2() {
|
||||
name = (char *)"MultipleStream2";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(230); effects.ShowFrame();
|
||||
|
||||
byte xx = 4 + sin8(millis() / 9) / 10;
|
||||
byte yy = 4 + cos8(millis() / 10) / 10;
|
||||
effects.leds[XY(xx, yy)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
|
||||
xx = 8 + sin8(millis() / 10) / 16;
|
||||
yy = 8 + cos8(millis() / 7) / 16;
|
||||
effects.leds[XY(xx, yy)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 80);
|
||||
|
||||
effects.leds[XY(15, 15)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 160);
|
||||
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
patternNoiseSmearingHue++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream3 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream3() {
|
||||
name = (char *)"MultipleStream3";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
//CLS();
|
||||
effects.DimAll(235); effects.ShowFrame();
|
||||
|
||||
for (uint8_t i = 3; i < 32; i = i + 4) {
|
||||
effects.leds[XY(i, 15)] += effects.ColorFromCurrentPalette(i * 8);
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream4 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream4() {
|
||||
name = (char *)"MultipleStream4";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
//CLS();
|
||||
effects.DimAll(235); effects.ShowFrame();
|
||||
|
||||
effects.leds[XY(15, 15)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(8);
|
||||
effects.MoveFractionalNoiseX();
|
||||
|
||||
effects.MoveY(8);
|
||||
effects.MoveFractionalNoiseY();
|
||||
|
||||
patternNoiseSmearingHue++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream5 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream5() {
|
||||
name = (char *)"MultipleStream5";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
//CLS();
|
||||
effects.DimAll(235); effects.ShowFrame();
|
||||
|
||||
|
||||
for (uint8_t i = 3; i < 32; i = i + 4) {
|
||||
effects.leds[XY(i, 31)] += effects.ColorFromCurrentPalette(i * 8);
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(4);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream8 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream8() {
|
||||
name = (char *)"MultipleStream8";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(230); effects.ShowFrame();
|
||||
|
||||
// draw grid of rainbow dots on top of the dimmed image
|
||||
for (uint8_t y = 1; y < 32; y = y + 6) {
|
||||
for (uint8_t x = 1; x < 32; x = x + 6) {
|
||||
|
||||
effects.leds[XY(x, y)] += effects.ColorFromCurrentPalette((x * y) / 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternPaletteSmear : public Drawable {
|
||||
public:
|
||||
PatternPaletteSmear() {
|
||||
name = (char *)"PaletteSmear";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
effects.DimAll(170); effects.ShowFrame();
|
||||
|
||||
// draw a rainbow color palette
|
||||
for (uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
effects.leds[XY(x, y)] += effects.ColorFromCurrentPalette(x * 8, y * 8 + 7);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
//effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
effects.ShowFrame();
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternRainbowFlag : public Drawable {
|
||||
public:
|
||||
PatternRainbowFlag() {
|
||||
name = (char *)"RainbowFlag";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(10); effects.ShowFrame();
|
||||
|
||||
CRGB rainbow[7] = {
|
||||
CRGB::Red,
|
||||
CRGB::Orange,
|
||||
CRGB::Yellow,
|
||||
CRGB::Green,
|
||||
CRGB::Blue,
|
||||
CRGB::Violet
|
||||
};
|
||||
|
||||
uint8_t y = 2;
|
||||
|
||||
for (uint8_t c = 0; c < 6; c++) {
|
||||
for (uint8_t j = 0; j < 5; j++) {
|
||||
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
effects.leds[XY(x, y)] += rainbow[c];
|
||||
}
|
||||
|
||||
y++;
|
||||
if (y >= MATRIX_HEIGHT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
*
|
||||
* Inspired by and based on a loading animation for Prismata by Lunarch Studios:
|
||||
* http://www.reddit.com/r/gifs/comments/2on8si/connecting_to_server_so_mesmerizing/cmow0sz
|
||||
*
|
||||
* Lunarch Studios Inc. hereby publishes the Actionscript 3 source code pasted in this
|
||||
* comment under the Creative Commons CC0 1.0 Universal Public Domain Dedication.
|
||||
* Lunarch Studios Inc. waives all rights to the work worldwide under copyright law,
|
||||
* including all related and neighboring rights, to the extent allowed by law.
|
||||
* You can copy, modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternPendulumWave_H
|
||||
#define PatternPendulumWave_H
|
||||
|
||||
#define WAVE_BPM 25
|
||||
#define AMP_BPM 2
|
||||
#define SKEW_BPM 4
|
||||
#define WAVE_TIMEMINSKEW MATRIX_WIDTH/8
|
||||
#define WAVE_TIMEMAXSKEW MATRIX_WIDTH/2
|
||||
|
||||
class PatternPendulumWave : public Drawable {
|
||||
public:
|
||||
PatternPendulumWave() {
|
||||
name = (char *)"Pendulum Wave";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.ClearFrame();
|
||||
|
||||
for (int x = 0; x < MATRIX_WIDTH; ++x)
|
||||
{
|
||||
uint16_t amp = beatsin16(AMP_BPM, MATRIX_HEIGHT/8, MATRIX_HEIGHT-1);
|
||||
uint16_t offset = (MATRIX_HEIGHT - beatsin16(AMP_BPM, 0, MATRIX_HEIGHT))/2;
|
||||
|
||||
uint8_t y = beatsin16(WAVE_BPM, 0, amp, x*beatsin16(SKEW_BPM, WAVE_TIMEMINSKEW, WAVE_TIMEMAXSKEW)) + offset;
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, effects.ColorFromCurrentPalette(x * 7));
|
||||
}
|
||||
effects.ShowFrame();
|
||||
return 20;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from LedEffects Plasma by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Plasma.cpp?at=default
|
||||
* Copyright (c) 2013 Robert Atkins
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternPlasma_H
|
||||
#define PatternPlasma_H
|
||||
|
||||
class PatternPlasma : public Drawable {
|
||||
private:
|
||||
int time = 0;
|
||||
int cycles = 0;
|
||||
|
||||
public:
|
||||
PatternPlasma() {
|
||||
name = (char *)"Plasma";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
int16_t v = 0;
|
||||
uint8_t wibble = sin8(time);
|
||||
v += sin16(x * wibble * 2 + time);
|
||||
v += cos16(y * (128 - wibble) * 2 + time);
|
||||
v += sin16(y * x * cos8(-time) / 2);
|
||||
|
||||
effects.Pixel(x, y, (v >> 8) + 127);
|
||||
}
|
||||
}
|
||||
|
||||
time += 1;
|
||||
cycles++;
|
||||
|
||||
if (cycles >= 2048) {
|
||||
time = 0;
|
||||
cycles = 0;
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 30;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Based at least in part on someone else's work that I can no longer find.
|
||||
* Please let me know if you recognize any of this code!
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternPulse_H
|
||||
#define PatternPulse_H
|
||||
|
||||
class PatternPulse : public Drawable {
|
||||
private:
|
||||
int hue;
|
||||
int centerX = 0;
|
||||
int centerY = 0;
|
||||
int step = -1;
|
||||
int maxSteps = 16;
|
||||
float fadeRate = 0.8;
|
||||
int diff;
|
||||
|
||||
public:
|
||||
PatternPulse() {
|
||||
name = (char *)"Pulse";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(235);
|
||||
|
||||
if (step == -1) {
|
||||
centerX = random(32);
|
||||
centerY = random(32);
|
||||
hue = random(256); // 170;
|
||||
step = 0;
|
||||
}
|
||||
|
||||
if (step == 0) {
|
||||
dma_display->drawCircle(centerX, centerY, step, effects.ColorFromCurrentPalette(hue));
|
||||
step++;
|
||||
}
|
||||
else {
|
||||
if (step < maxSteps) {
|
||||
// initial pulse
|
||||
dma_display->drawCircle(centerX, centerY, step, effects.ColorFromCurrentPalette(hue, pow(fadeRate, step - 2) * 255));
|
||||
|
||||
// secondary pulse
|
||||
if (step > 3) {
|
||||
dma_display->drawCircle(centerX, centerY, step - 3, effects.ColorFromCurrentPalette(hue, pow(fadeRate, step - 2) * 255));
|
||||
}
|
||||
step++;
|
||||
}
|
||||
else {
|
||||
step = -1;
|
||||
}
|
||||
}
|
||||
|
||||
effects.standardNoiseSmearing();
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 30;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternRadar_H
|
||||
|
||||
class PatternRadar : public Drawable {
|
||||
private:
|
||||
byte theta = 0;
|
||||
byte hueoffset = 0;
|
||||
|
||||
public:
|
||||
PatternRadar() {
|
||||
name = (char *)"Radar";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(254); effects.ShowFrame();
|
||||
|
||||
for (int offset = 0; offset < MATRIX_CENTER_X; offset++) {
|
||||
byte hue = 255 - (offset * 16 + hueoffset);
|
||||
CRGB color = effects.ColorFromCurrentPalette(hue);
|
||||
uint8_t x = mapcos8(theta, offset, (MATRIX_WIDTH - 1) - offset);
|
||||
uint8_t y = mapsin8(theta, offset, (MATRIX_HEIGHT - 1) - offset);
|
||||
uint16_t xy = XY(x, y);
|
||||
effects.leds[xy] = color;
|
||||
|
||||
EVERY_N_MILLIS(25) {
|
||||
theta += 2;
|
||||
hueoffset += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from FastLED Fire2012 example by Mark Kriegsman: https://github.com/FastLED/FastLED/blob/master/examples/Noise/Noise.ino
|
||||
* Copyright (c) 2013 FastLED
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternSimplexNoise_H
|
||||
#define PatternSimplexNoise_H
|
||||
|
||||
class PatternSimplexNoise : public Drawable {
|
||||
public:
|
||||
PatternSimplexNoise() {
|
||||
name = (char *)"Noise";
|
||||
}
|
||||
|
||||
void start() {
|
||||
// Initialize our coordinates to some random values
|
||||
noise_x = random16();
|
||||
noise_y = random16();
|
||||
noise_z = random16();
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
#if FASTLED_VERSION >= 3001000
|
||||
// a new parameter set every 15 seconds
|
||||
EVERY_N_SECONDS(15) {
|
||||
noise_x = random16();
|
||||
noise_y = random16();
|
||||
noise_z = random16();
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t speed = 100;
|
||||
|
||||
effects.FillNoise();
|
||||
ShowNoiseLayer(0, 1, 0);
|
||||
|
||||
// noise_x += speed;
|
||||
noise_y += speed;
|
||||
noise_z += speed;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 30;
|
||||
}
|
||||
|
||||
// show just one layer
|
||||
void ShowNoiseLayer(byte layer, byte colorrepeat, byte colorshift) {
|
||||
for (uint16_t i = 0; i < MATRIX_WIDTH; i++) {
|
||||
for (uint16_t j = 0; j < MATRIX_HEIGHT; j++) {
|
||||
uint8_t pixel = noise[i][j];
|
||||
|
||||
// assign a color depending on the actual palette
|
||||
effects.leds[XY16(i, j)] = effects.ColorFromCurrentPalette(colorrepeat * (pixel + colorshift), pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from LedEffects Snake by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Snake.cpp?at=default
|
||||
* Copyright (c) 2013 Robert Atkins
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternSnake_H
|
||||
#define PatternSnake_H
|
||||
|
||||
class PatternSnake : public Drawable {
|
||||
private:
|
||||
static const byte SNAKE_LENGTH = 16;
|
||||
|
||||
CRGB colors[SNAKE_LENGTH];
|
||||
uint8_t initialHue;
|
||||
|
||||
enum Direction {
|
||||
UP, DOWN, LEFT, RIGHT
|
||||
};
|
||||
|
||||
struct Pixel {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
};
|
||||
|
||||
struct Snake {
|
||||
Pixel pixels[SNAKE_LENGTH];
|
||||
|
||||
Direction direction;
|
||||
|
||||
void newDirection() {
|
||||
switch (direction) {
|
||||
case UP:
|
||||
case DOWN:
|
||||
direction = random(0, 2) == 1 ? RIGHT : LEFT;
|
||||
break;
|
||||
|
||||
case LEFT:
|
||||
case RIGHT:
|
||||
direction = random(0, 2) == 1 ? DOWN : UP;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void shuffleDown() {
|
||||
for (byte i = SNAKE_LENGTH - 1; i > 0; i--) {
|
||||
pixels[i] = pixels[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
direction = UP;
|
||||
for (int i = 0; i < SNAKE_LENGTH; i++) {
|
||||
pixels[i].x = 0;
|
||||
pixels[i].y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void move() {
|
||||
switch (direction) {
|
||||
case UP:
|
||||
pixels[0].y = (pixels[0].y + 1) % MATRIX_HEIGHT;
|
||||
break;
|
||||
case LEFT:
|
||||
pixels[0].x = (pixels[0].x + 1) % MATRIX_WIDTH;
|
||||
break;
|
||||
case DOWN:
|
||||
pixels[0].y = pixels[0].y == 0 ? MATRIX_HEIGHT - 1 : pixels[0].y - 1;
|
||||
break;
|
||||
case RIGHT:
|
||||
pixels[0].x = pixels[0].x == 0 ? MATRIX_WIDTH - 1 : pixels[0].x - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void draw(CRGB colors[SNAKE_LENGTH]) {
|
||||
for (byte i = 0; i < SNAKE_LENGTH; i++) {
|
||||
effects.leds[XY(pixels[i].x, pixels[i].y)] = colors[i] %= (255 - i * (255 / SNAKE_LENGTH));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static const int snakeCount = 6;
|
||||
Snake snakes[snakeCount];
|
||||
|
||||
public:
|
||||
PatternSnake() {
|
||||
name = (char *)"Snake";
|
||||
for (int i = 0; i < snakeCount; i++) {
|
||||
Snake* snake = &snakes[i];
|
||||
snake->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
effects.ClearFrame();
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
|
||||
fill_palette(colors, SNAKE_LENGTH, initialHue++, 5, effects.currentPalette, 255, LINEARBLEND);
|
||||
|
||||
for (int i = 0; i < snakeCount; i++) {
|
||||
Snake* snake = &snakes[i];
|
||||
|
||||
snake->shuffleDown();
|
||||
|
||||
if (random(10) > 7) {
|
||||
snake->newDirection();
|
||||
}
|
||||
|
||||
snake->move();
|
||||
snake->draw(colors);
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 30;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from FastLED Fire2012 example by Mark Kriegsman: https://github.com/FastLED/FastLED/tree/master/examples/Fire2012WithPalette
|
||||
* Copyright (c) 2013 FastLED
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternSpark_H
|
||||
#define PatternSpark_H
|
||||
|
||||
class PatternSpark : public Drawable {
|
||||
private:
|
||||
|
||||
public:
|
||||
PatternSpark() {
|
||||
name = (char *)"Spark";
|
||||
}
|
||||
|
||||
// There are two main parameters you can play with to control the look and
|
||||
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
|
||||
// in step 3 above).
|
||||
//
|
||||
// COOLING: How much does the air cool as it rises?
|
||||
// Less cooling = taller flames. More cooling = shorter flames.
|
||||
// Default 55, suggested range 20-100
|
||||
uint8_t cooling = 100;
|
||||
|
||||
// SPARKING: What chance (out of 255) is there that a new spark will be lit?
|
||||
// Higher chance = more roaring fire. Lower chance = more flickery fire.
|
||||
// Default 120, suggested range 50-200.
|
||||
uint8_t sparking = 50;
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// Add entropy to random number generator; we use a lot of it.
|
||||
random16_add_entropy( random16());
|
||||
|
||||
effects.DimAll(235); effects.ShowFrame();
|
||||
|
||||
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
// Step 1. Cool down every cell a little
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
int xy = XY(x, y);
|
||||
heat[xy] = qsub8(heat[xy], random8(0, ((cooling * 10) / MATRIX_HEIGHT) + 2));
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
heat[XY(x, y)] = (heat[XY(x, y + 1)] + heat[XY(x, y + 2)] + heat[XY(x, y + 2)]) / 3;
|
||||
}
|
||||
|
||||
// Step 2. Randomly ignite new 'sparks' of heat
|
||||
if (random8() < sparking) {
|
||||
uint8_t xt = random8(MATRIX_CENTRE_X - 2, MATRIX_CENTER_X + 3);
|
||||
|
||||
int xy = XY(xt, MATRIX_HEIGHT - 1);
|
||||
heat[xy] = qadd8(heat[xy], random8(160, 255));
|
||||
}
|
||||
|
||||
// Step 4. Map from heat cells to LED colors
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
int xy = XY(x, y);
|
||||
byte colorIndex = heat[xy];
|
||||
|
||||
// Recommend that you use values 0-240 rather than
|
||||
// the usual 0-255, as the last 15 colors will be
|
||||
// 'wrapping around' from the hot end to the cold end,
|
||||
// which looks wrong.
|
||||
colorIndex = scale8(colorIndex, 240);
|
||||
|
||||
// override color 0 to ensure a black background?
|
||||
if (colorIndex != 0)
|
||||
// effects.leds[xy] = CRGB::Black;
|
||||
// else
|
||||
effects.leds[xy] = effects.ColorFromCurrentPalette(colorIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 15;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternSpin_H
|
||||
|
||||
|
||||
|
||||
class PatternSpin : public Drawable {
|
||||
public:
|
||||
PatternSpin() {
|
||||
name = (char *)"Spin";
|
||||
}
|
||||
|
||||
float degrees = 0;
|
||||
float radius = 16;
|
||||
|
||||
float speedStart = 1;
|
||||
float velocityStart = 0.6;
|
||||
|
||||
float maxSpeed = 30;
|
||||
|
||||
float speed = speedStart;
|
||||
float velocity = velocityStart;
|
||||
|
||||
void start() {
|
||||
speed = speedStart;
|
||||
velocity = velocityStart;
|
||||
degrees = 0;
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(190); effects.ShowFrame();
|
||||
|
||||
CRGB color = effects.ColorFromCurrentPalette(speed * 8);
|
||||
|
||||
// start position
|
||||
int x;
|
||||
int y;
|
||||
|
||||
// target position
|
||||
float targetDegrees = degrees + speed;
|
||||
float targetRadians = radians(targetDegrees);
|
||||
int targetX = (int) (MATRIX_CENTER_X + radius * cos(targetRadians));
|
||||
int targetY = (int) (MATRIX_CENTER_Y - radius * sin(targetRadians));
|
||||
|
||||
float tempDegrees = degrees;
|
||||
|
||||
do{
|
||||
float radians = radians(tempDegrees);
|
||||
x = (int) (MATRIX_CENTER_X + radius * cos(radians));
|
||||
y = (int) (MATRIX_CENTER_Y - radius * sin(radians));
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, color);
|
||||
effects.drawBackgroundFastLEDPixelCRGB(y, x, color);
|
||||
|
||||
tempDegrees += 1;
|
||||
if (tempDegrees >= 360)
|
||||
tempDegrees = 0;
|
||||
} while (x != targetX || y != targetY);
|
||||
|
||||
degrees += speed;
|
||||
|
||||
// add velocity to the particle each pass around the accelerator
|
||||
if (degrees >= 360) {
|
||||
degrees = 0;
|
||||
speed += velocity;
|
||||
if (speed <= speedStart) {
|
||||
speed = speedStart;
|
||||
velocity *= -1;
|
||||
}
|
||||
else if (speed > maxSpeed){
|
||||
speed = maxSpeed - velocity;
|
||||
velocity *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Portions of this code are adapted from "Funky Clouds" by Stefan Petrick:
|
||||
* https://gist.github.com/anonymous/876f908333cd95315c35
|
||||
*
|
||||
* Copyright (c) 2014 Stefan Petrick
|
||||
* http://www.stefan-petrick.de/wordpress_beta
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternSpiral_H
|
||||
#define PatternSpiral_H
|
||||
|
||||
class PatternSpiral : public Drawable {
|
||||
private:
|
||||
// Timer stuff (Oscillators)
|
||||
struct timer {
|
||||
unsigned long takt;
|
||||
unsigned long lastMillis;
|
||||
unsigned long count;
|
||||
int delta;
|
||||
byte up;
|
||||
byte down;
|
||||
};
|
||||
timer multiTimer[5];
|
||||
|
||||
int timers = sizeof(multiTimer) / sizeof(multiTimer[0]);
|
||||
|
||||
// counts all variables with different speeds linear up and down
|
||||
void UpdateTimers()
|
||||
{
|
||||
unsigned long now = millis();
|
||||
for (int i = 0; i < timers; i++)
|
||||
{
|
||||
while (now - multiTimer[i].lastMillis >= multiTimer[i].takt)
|
||||
{
|
||||
multiTimer[i].lastMillis += multiTimer[i].takt;
|
||||
multiTimer[i].count = multiTimer[i].count + multiTimer[i].delta;
|
||||
if ((multiTimer[i].count == multiTimer[i].up) || (multiTimer[i].count == multiTimer[i].down))
|
||||
{
|
||||
multiTimer[i].delta = -multiTimer[i].delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
PatternSpiral() {
|
||||
name = (char *)"Spiral";
|
||||
}
|
||||
|
||||
void start() {
|
||||
// set all counting directions positive for the beginning
|
||||
for (int i = 0; i < timers; i++) multiTimer[i].delta = 1;
|
||||
|
||||
// set range (up/down), speed (takt=ms between steps) and starting point of all oscillators
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
multiTimer[0].lastMillis = now;
|
||||
multiTimer[0].takt = 42; //x1
|
||||
multiTimer[0].up = MATRIX_WIDTH - 1;
|
||||
multiTimer[0].down = 0;
|
||||
multiTimer[0].count = 0;
|
||||
|
||||
multiTimer[1].lastMillis = now;
|
||||
multiTimer[1].takt = 55; //y1
|
||||
multiTimer[1].up = MATRIX_HEIGHT - 1;
|
||||
multiTimer[1].down = 0;
|
||||
multiTimer[1].count = 0;
|
||||
|
||||
multiTimer[2].lastMillis = now;
|
||||
multiTimer[2].takt = 3; //color
|
||||
multiTimer[2].up = 255;
|
||||
multiTimer[2].down = 0;
|
||||
multiTimer[2].count = 0;
|
||||
|
||||
multiTimer[3].lastMillis = now;
|
||||
multiTimer[3].takt = 71; //x2
|
||||
multiTimer[3].up = MATRIX_WIDTH - 1;
|
||||
multiTimer[3].down = 0;
|
||||
multiTimer[3].count = 0;
|
||||
|
||||
multiTimer[4].lastMillis = now;
|
||||
multiTimer[4].takt = 89; //y2
|
||||
multiTimer[4].up = MATRIX_HEIGHT - 1;
|
||||
multiTimer[4].down = 0;
|
||||
multiTimer[4].count = 0;
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// manage the Oscillators
|
||||
UpdateTimers();
|
||||
|
||||
// draw just a line defined by 5 oscillators
|
||||
effects.BresenhamLine(
|
||||
multiTimer[3].count, // x1
|
||||
multiTimer[4].count, // y1
|
||||
multiTimer[0].count, // x2
|
||||
multiTimer[1].count, // y2
|
||||
multiTimer[2].count); // color
|
||||
|
||||
// manipulate the screen buffer
|
||||
// with fixed parameters (could be oscillators too)
|
||||
// Params: center x, y, radius, scale color down
|
||||
// --> NOTE: Affects always a SQUARE with an odd length
|
||||
// effects.SpiralStream(15, 15, 10, 128);
|
||||
|
||||
effects.SpiralStream(31, 15, 64, 128); // for 64 pixel wide matrix!
|
||||
// effects.SpiralStream(47, 15, 10, 128); // for 64 pixel wide matrix!
|
||||
|
||||
// why not several times?!
|
||||
// effects.SpiralStream(16, 6, 6, 128);
|
||||
// effects.SpiralStream(10, 24, 10, 128);
|
||||
|
||||
// increase the contrast
|
||||
effects.DimAll(250); effects.ShowFrame();
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternSpiro_H
|
||||
|
||||
class PatternSpiro : public Drawable {
|
||||
private:
|
||||
byte theta1 = 0;
|
||||
byte theta2 = 0;
|
||||
byte hueoffset = 0;
|
||||
|
||||
uint8_t radiusx = MATRIX_WIDTH / 4;
|
||||
uint8_t radiusy = MATRIX_HEIGHT / 4;
|
||||
uint8_t minx = MATRIX_CENTER_X - radiusx;
|
||||
uint8_t maxx = MATRIX_CENTER_X + radiusx + 1;
|
||||
uint8_t miny = MATRIX_CENTER_Y - radiusy;
|
||||
uint8_t maxy = MATRIX_CENTER_Y + radiusy + 1;
|
||||
|
||||
uint8_t spirocount = 1;
|
||||
uint8_t spirooffset = 256 / spirocount;
|
||||
boolean spiroincrement = true;
|
||||
|
||||
boolean handledChange = false;
|
||||
|
||||
public:
|
||||
PatternSpiro() {
|
||||
name = (char *)"Spiro";
|
||||
}
|
||||
|
||||
void start(){
|
||||
effects.ClearFrame();
|
||||
};
|
||||
|
||||
unsigned int drawFrame() {
|
||||
blur2d(effects.leds, MATRIX_WIDTH > 255 ? 255 : MATRIX_WIDTH, MATRIX_HEIGHT > 255 ? 255 : MATRIX_HEIGHT, 192);
|
||||
|
||||
boolean change = false;
|
||||
|
||||
for (int i = 0; i < spirocount; i++) {
|
||||
uint8_t x = mapsin8(theta1 + i * spirooffset, minx, maxx);
|
||||
uint8_t y = mapcos8(theta1 + i * spirooffset, miny, maxy);
|
||||
|
||||
uint8_t x2 = mapsin8(theta2 + i * spirooffset, x - radiusx, x + radiusx);
|
||||
uint8_t y2 = mapcos8(theta2 + i * spirooffset, y - radiusy, y + radiusy);
|
||||
|
||||
CRGB color = effects.ColorFromCurrentPalette(hueoffset + i * spirooffset, 128);
|
||||
effects.leds[XY(x2, y2)] += color;
|
||||
|
||||
if((x2 == MATRIX_CENTER_X && y2 == MATRIX_CENTER_Y) ||
|
||||
(x2 == MATRIX_CENTRE_X && y2 == MATRIX_CENTRE_Y)) change = true;
|
||||
}
|
||||
|
||||
theta2 += 1;
|
||||
|
||||
EVERY_N_MILLIS(25) {
|
||||
theta1 += 1;
|
||||
}
|
||||
|
||||
EVERY_N_MILLIS(100) {
|
||||
if (change && !handledChange) {
|
||||
handledChange = true;
|
||||
|
||||
if (spirocount >= MATRIX_WIDTH || spirocount == 1) spiroincrement = !spiroincrement;
|
||||
|
||||
if (spiroincrement) {
|
||||
if(spirocount >= 4)
|
||||
spirocount *= 2;
|
||||
else
|
||||
spirocount += 1;
|
||||
}
|
||||
else {
|
||||
if(spirocount > 4)
|
||||
spirocount /= 2;
|
||||
else
|
||||
spirocount -= 1;
|
||||
}
|
||||
|
||||
spirooffset = 256 / spirocount;
|
||||
}
|
||||
|
||||
if(!change) handledChange = false;
|
||||
}
|
||||
|
||||
EVERY_N_MILLIS(33) {
|
||||
hueoffset += 1;
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from SmartMatrixSwirl by Mark Kriegsman: https://gist.github.com/kriegsman/5adca44e14ad025e6d3b
|
||||
* https://www.youtube.com/watch?v=bsGBT-50cts
|
||||
* Copyright (c) 2014 Mark Kriegsman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternSwirl_H
|
||||
|
||||
class PatternSwirl : public Drawable {
|
||||
private:
|
||||
const uint8_t borderWidth = 2;
|
||||
|
||||
public:
|
||||
PatternSwirl() {
|
||||
name = (char *)"Swirl";
|
||||
}
|
||||
|
||||
void start() {
|
||||
effects.ClearFrame();
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// Apply some blurring to whatever's already on the matrix
|
||||
// Note that we never actually clear the matrix, we just constantly
|
||||
// blur it repeatedly. Since the blurring is 'lossy', there's
|
||||
// an automatic trend toward black -- by design.
|
||||
uint8_t blurAmount = beatsin8(2, 10, 255);
|
||||
|
||||
#if FASTLED_VERSION >= 3001000
|
||||
blur2d(effects.leds, MATRIX_WIDTH > 255 ? 255 : MATRIX_WIDTH, MATRIX_HEIGHT > 255 ? 255 : MATRIX_HEIGHT, blurAmount);
|
||||
#else
|
||||
effects.DimAll(blurAmount);
|
||||
#endif
|
||||
|
||||
// Use two out-of-sync sine waves
|
||||
uint8_t i = beatsin8(256/MATRIX_HEIGHT, borderWidth, MATRIX_WIDTH - borderWidth);
|
||||
uint8_t j = beatsin8(2048/MATRIX_WIDTH, borderWidth, MATRIX_HEIGHT - borderWidth);
|
||||
|
||||
// Also calculate some reflections
|
||||
uint8_t ni = (MATRIX_WIDTH - 1) - i;
|
||||
uint8_t nj = (MATRIX_HEIGHT - 1) - j;
|
||||
|
||||
// The color of each point shifts over time, each at a different speed.
|
||||
uint16_t ms = millis();
|
||||
effects.leds[XY(i, j)] += effects.ColorFromCurrentPalette(ms / 11);
|
||||
//effects.leds[XY(j, i)] += effects.ColorFromCurrentPalette(ms / 13); // this doesn't work for non-square matrices
|
||||
effects.leds[XY(ni, nj)] += effects.ColorFromCurrentPalette(ms / 17);
|
||||
//effects.leds[XY(nj, ni)] += effects.ColorFromCurrentPalette(ms / 29); // this doesn't work for non-square matrices
|
||||
effects.leds[XY(i, nj)] += effects.ColorFromCurrentPalette(ms / 37);
|
||||
effects.leds[XY(ni, j)] += effects.ColorFromCurrentPalette(ms / 41);
|
||||
|
||||
|
||||
effects.ShowFrame();
|
||||
return 0;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
#ifndef PatternTest_H
|
||||
#define PatternTest_H
|
||||
|
||||
class PatternTest : public Drawable {
|
||||
private:
|
||||
|
||||
public:
|
||||
PatternTest() {
|
||||
name = (char *)"Test Pattern";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
dma_display->fillScreen(dma_display->color565(128, 0, 0));
|
||||
return 1000;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternWave_H
|
||||
#define PatternWave_H
|
||||
|
||||
class PatternWave : public Drawable {
|
||||
private:
|
||||
byte thetaUpdate = 0;
|
||||
byte thetaUpdateFrequency = 0;
|
||||
byte theta = 0;
|
||||
|
||||
byte hueUpdate = 0;
|
||||
byte hueUpdateFrequency = 0;
|
||||
byte hue = 0;
|
||||
|
||||
byte rotation = 0;
|
||||
|
||||
uint8_t scale = 256 / MATRIX_WIDTH;
|
||||
|
||||
uint8_t maxX = MATRIX_WIDTH - 1;
|
||||
uint8_t maxY = MATRIX_HEIGHT - 1;
|
||||
|
||||
uint8_t waveCount = 1;
|
||||
|
||||
public:
|
||||
PatternWave() {
|
||||
name = (char *)"Wave";
|
||||
}
|
||||
|
||||
void start() {
|
||||
rotation = random(0, 4);
|
||||
waveCount = random(1, 3);
|
||||
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
int n = 0;
|
||||
|
||||
switch (rotation) {
|
||||
case 0:
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
n = quadwave8(x * 2 + theta) / scale;
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, n, effects.ColorFromCurrentPalette(x + hue));
|
||||
if (waveCount == 2)
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, maxY - n, effects.ColorFromCurrentPalette(x + hue));
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
n = quadwave8(y * 2 + theta) / scale;
|
||||
effects.drawBackgroundFastLEDPixelCRGB(n, y, effects.ColorFromCurrentPalette(y + hue));
|
||||
if (waveCount == 2)
|
||||
effects.drawBackgroundFastLEDPixelCRGB(maxX - n, y, effects.ColorFromCurrentPalette(y + hue));
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
n = quadwave8(x * 2 - theta) / scale;
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, n, effects.ColorFromCurrentPalette(x + hue));
|
||||
if (waveCount == 2)
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, maxY - n, effects.ColorFromCurrentPalette(x + hue));
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
n = quadwave8(y * 2 - theta) / scale;
|
||||
effects.drawBackgroundFastLEDPixelCRGB(n, y, effects.ColorFromCurrentPalette(y + hue));
|
||||
if (waveCount == 2)
|
||||
effects.drawBackgroundFastLEDPixelCRGB(maxX - n, y, effects.ColorFromCurrentPalette(y + hue));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
effects.DimAll(254);
|
||||
effects.ShowFrame();
|
||||
|
||||
if (thetaUpdate >= thetaUpdateFrequency) {
|
||||
thetaUpdate = 0;
|
||||
theta++;
|
||||
}
|
||||
else {
|
||||
thetaUpdate++;
|
||||
}
|
||||
|
||||
if (hueUpdate >= hueUpdateFrequency) {
|
||||
hueUpdate = 0;
|
||||
hue++;
|
||||
}
|
||||
else {
|
||||
hueUpdate++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||