enhanced blending modes and antialiasing
This commit is contained in:
parent
758ad73185
commit
4d35218695
@ -45,14 +45,15 @@ const CRGB colorSchemes[colorSchemeCount][4] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Clock settings
|
// Clock settings
|
||||||
|
const bool useEnhancedRenderer = true;
|
||||||
const int buttonClickRepeatDelayMs = 1500;
|
const int buttonClickRepeatDelayMs = 1500;
|
||||||
const int buttonLongPressDelayMs = 300;
|
const int buttonLongPressDelayMs = 300;
|
||||||
const bool showSecondHand = true;
|
const bool showSecondHand = true;
|
||||||
const bool twelveHour = true;
|
const bool twelveHour = true;
|
||||||
|
|
||||||
// Serial
|
// Serial
|
||||||
const int serialPortBaudRate = 115200;
|
const long serialPortBaudRate = 115200;
|
||||||
const int debugMessageIntervalMs = 5000;
|
const int debugMessageIntervalMs = 2000;
|
||||||
|
|
||||||
// Clock modes
|
// Clock modes
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -70,7 +71,7 @@ const uint8_t minBrightness = 4;
|
|||||||
// Run loop
|
// Run loop
|
||||||
const int runLoopIntervalMs = 30;
|
const int runLoopIntervalMs = 30;
|
||||||
|
|
||||||
// EEPROM Addresses
|
// EEPROM addresses
|
||||||
const uint16_t eepromAddrColorScheme = 0;
|
const uint16_t eepromAddrColorScheme = 0;
|
||||||
const uint16_t eepromAddrClockMode = 1;
|
const uint16_t eepromAddrClockMode = 1;
|
||||||
|
|
||||||
@ -93,4 +94,11 @@ const uint8_t PROGMEM gamma[] = {
|
|||||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||||
|
|
||||||
|
// LED blend modes
|
||||||
|
typedef enum {
|
||||||
|
BlendModeOver,
|
||||||
|
BlendModeAlpha,
|
||||||
|
BlendModeAdd
|
||||||
|
} BlendMode;
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
//
|
//
|
||||||
|
// WS2812 LED Analog Clock Firmware
|
||||||
// Copyright (c) 2016-2018 jackw01
|
// Copyright (c) 2016-2018 jackw01
|
||||||
// This code is distrubuted under the MIT License, see LICENSE for details
|
// This code is distrubuted under the MIT License, see LICENSE for details
|
||||||
//
|
//
|
||||||
@ -9,8 +10,9 @@
|
|||||||
#include <EEPROM.h>
|
#include <EEPROM.h>
|
||||||
#include <RTClib.h>
|
#include <RTClib.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "constants.h"
|
||||||
|
|
||||||
|
// LED ring and RTC
|
||||||
CRGB leds[ledRingSize];
|
CRGB leds[ledRingSize];
|
||||||
RTC_DS1307 rtc;
|
RTC_DS1307 rtc;
|
||||||
|
|
||||||
@ -21,6 +23,9 @@ int lastButtonClickTime = 0;
|
|||||||
int lastDebugMessageTime = 0;
|
int lastDebugMessageTime = 0;
|
||||||
uint8_t currentBrightness;
|
uint8_t currentBrightness;
|
||||||
uint8_t previousBrightness[16];
|
uint8_t previousBrightness[16];
|
||||||
|
int lastSecondsValue = 0;
|
||||||
|
int lastMillisecondsSetTime = 0;
|
||||||
|
int milliseconds;
|
||||||
DateTime now;
|
DateTime now;
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
@ -54,7 +59,7 @@ void setup() {
|
|||||||
void loop() {
|
void loop() {
|
||||||
int currentTime = millis();
|
int currentTime = millis();
|
||||||
if (currentTime - lastLoopTime > runLoopIntervalMs) {
|
if (currentTime - lastLoopTime > runLoopIntervalMs) {
|
||||||
lastLoopTime = millis();
|
lastLoopTime = currentTime;
|
||||||
// Handle button
|
// Handle button
|
||||||
if (digitalRead(pinButton) == LOW && currentTime - lastButtonClickTime > buttonClickRepeatDelayMs) {
|
if (digitalRead(pinButton) == LOW && currentTime - lastButtonClickTime > buttonClickRepeatDelayMs) {
|
||||||
delay(buttonLongPressDelayMs);
|
delay(buttonLongPressDelayMs);
|
||||||
@ -87,8 +92,18 @@ void loop() {
|
|||||||
currentBrightness = sum / 16;
|
currentBrightness = sum / 16;
|
||||||
FastLED.setBrightness(currentBrightness);
|
FastLED.setBrightness(currentBrightness);
|
||||||
|
|
||||||
// Show clock
|
// Get time and calculate milliseconds value that is synced with the RTC's second count
|
||||||
now = rtc.now();
|
now = rtc.now();
|
||||||
|
int currentSeconds = now.second();
|
||||||
|
if (currentSeconds != lastSecondsValue) {
|
||||||
|
lastSecondsValue = currentSeconds;
|
||||||
|
milliseconds = 0;
|
||||||
|
}
|
||||||
|
currentTime = millis();
|
||||||
|
milliseconds = (milliseconds + currentTime - lastMillisecondsSetTime);
|
||||||
|
lastMillisecondsSetTime = currentTime;
|
||||||
|
|
||||||
|
// Show clock
|
||||||
clearLeds();
|
clearLeds();
|
||||||
showClock();
|
showClock();
|
||||||
}
|
}
|
||||||
@ -144,30 +159,30 @@ void printDebugMessage() {
|
|||||||
void ringClock() {
|
void ringClock() {
|
||||||
int h = hourPosition();
|
int h = hourPosition();
|
||||||
int m = minutePosition();
|
int m = minutePosition();
|
||||||
int s = secondPosition();
|
float s = floatSecondPosition();
|
||||||
|
|
||||||
if (m > h) {
|
if (m > h) {
|
||||||
for (int i = 0; i < m; i++) leds[i] = minuteColor();
|
for (int i = 0; i < m; i++) setLed(i, minuteColor(), BlendModeOver);
|
||||||
for (int i = 0; i < h; i++) leds[i] = hourColor();
|
for (int i = 0; i < h; i++) setLed(i, hourColor(), BlendModeOver);
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < h; i++) leds[i] = hourColor();
|
for (int i = 0; i < h; i++) setLed(i, hourColor(), BlendModeOver);
|
||||||
for (int i = 0; i < m; i++) leds[i] = minuteColor();
|
for (int i = 0; i < m; i++) setLed(i, minuteColor(), BlendModeOver);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showSecondHand) leds[s] = secondColor();
|
if (showSecondHand) setLed(s, secondColor(), BlendModeAlpha);
|
||||||
|
|
||||||
FastLED.show();
|
FastLED.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show a more traditional dot clock
|
// Show a more traditional dot clock
|
||||||
void dotClock() {
|
void dotClock() {
|
||||||
int h = hourPosition();
|
float h = floatHourPosition();
|
||||||
int m = minutePosition();
|
float m = floatMinutePosition();
|
||||||
int s = secondPosition();
|
float s = floatSecondPosition();
|
||||||
|
|
||||||
for (int i = h - 1; i < h + 2; i++) leds[wrap(i)] = hourColor();
|
for (float i = h - 1; i < h + 2; i++) setLed(i, hourColor(), BlendModeAdd);
|
||||||
leds[m] = minuteColor();
|
setLed(m, minuteColor(), BlendModeAdd);
|
||||||
if (showSecondHand) [s] = secondColor();
|
if (showSecondHand) setLed(s, secondColor(), BlendModeAdd);
|
||||||
|
|
||||||
FastLED.show();
|
FastLED.show();
|
||||||
}
|
}
|
||||||
@ -194,9 +209,9 @@ void timeColorClock() {
|
|||||||
int h = hourPosition();
|
int h = hourPosition();
|
||||||
int m = minutePosition();
|
int m = minutePosition();
|
||||||
int s = secondPosition();
|
int s = secondPosition();
|
||||||
float decHour = decimalHour();
|
float fHour = floatHour();
|
||||||
|
|
||||||
CRGB pixelColor = CHSV((uint8_t)mapFloat(fmod(20.0 - decHour, 24.0), 0.0, 24.0, 0.0, 255.0), 255, 255);
|
CRGB pixelColor = CHSV((uint8_t)mapFloat(fmod(20.0 - fHour, 24.0), 0.0, 24.0, 0.0, 255.0), 255, 255);
|
||||||
|
|
||||||
for (int i = h - 1; i < h + 2; i++) leds[wrap(i)] = pixelColor;
|
for (int i = h - 1; i < h + 2; i++) leds[wrap(i)] = pixelColor;
|
||||||
leds[m] = pixelColor;
|
leds[m] = pixelColor;
|
||||||
@ -235,10 +250,10 @@ int hourPosition() {
|
|||||||
int hour;
|
int hour;
|
||||||
if (now.hour() > 12) hour = (now.hour() - 12) * (ledRingSize / 12);
|
if (now.hour() > 12) hour = (now.hour() - 12) * (ledRingSize / 12);
|
||||||
else hour = now.hour() * (ledRingSize / 12);
|
else hour = now.hour() * (ledRingSize / 12);
|
||||||
return hour + int(map(now.minute(), 0, 59, 0, (ledRingSize / 12) - 1));;
|
return hour + map(now.minute(), 0, 59, 0, (ledRingSize / 12) - 1);
|
||||||
} else {
|
} else {
|
||||||
int hour = now.hour() * (ledRingSize / 24);
|
int hour = now.hour() * (ledRingSize / 24);
|
||||||
return hour + int(map(now.minute(), 0, 59, 0, (ledRingSize / 24) - 1));;
|
return hour + map(now.minute(), 0, 59, 0, (ledRingSize / 24) - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,10 +265,31 @@ int secondPosition() {
|
|||||||
return map(now.second(), 0, 59, 0, ledRingSize - 1);
|
return map(now.second(), 0, 59, 0, ledRingSize - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
float decimalHour() {
|
float floatHour() {
|
||||||
return (float)now.hour() + mapFloat(now.minute() + mapFloat(now.second(), 0.0, 59.0, 0.0, 1.0), 0.0, 59.0, 0.0, 1.0);
|
return (float)now.hour() + mapFloat(now.minute() + mapFloat(now.second(), 0.0, 59.0, 0.0, 1.0), 0.0, 59.0, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get positions as a float mapped to ring size
|
||||||
|
float floatHourPosition() {
|
||||||
|
if (twelveHour) {
|
||||||
|
int hour;
|
||||||
|
if (now.hour() > 12) hour = (now.hour() - 12) * (ledRingSize / 12);
|
||||||
|
else hour = now.hour() * (ledRingSize / 12);
|
||||||
|
return hour + mapFloat(now.minute(), 0.0, 59.0, 0.0, (ledRingSize / 12.0) - 1.0);
|
||||||
|
} else {
|
||||||
|
int hour = now.hour() * (ledRingSize / 24);
|
||||||
|
return hour + mapFloat(now.minute(), 0, 59, 0, (ledRingSize / 24.0) - 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float floatMinutePosition() {
|
||||||
|
return mapFloat(now.minute() + ((1 / 60) * now.second()), 0.0, 59.0, 0.0, (float)ledRingSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
float floatSecondPosition() {
|
||||||
|
return mapFloat(now.second() + (0.001 * milliseconds), 0.0, 60.0, 0.0, (float)ledRingSize);
|
||||||
|
}
|
||||||
|
|
||||||
// Get colors
|
// Get colors
|
||||||
CRGB hourColor() {
|
CRGB hourColor() {
|
||||||
return colorSchemes[colorScheme][0];
|
return colorSchemes[colorScheme][0];
|
||||||
@ -272,11 +308,48 @@ void clearLeds() {
|
|||||||
for (int i = 0; i < ledRingSize; i++) leds[i] = CRGB(0, 0, 0);
|
for (int i = 0; i < ledRingSize; i++) leds[i] = CRGB(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enhanced additive blending
|
// Set LED(s) at a position with enhanced rendering
|
||||||
|
void setLed(float position, CRGB color, BlendMode blendMode) {
|
||||||
|
if (useEnhancedRenderer) {
|
||||||
|
int low = floor(position);
|
||||||
|
int high = ceil(position);
|
||||||
|
float lowFactor = ((float)high - position);
|
||||||
|
float highFactor = (position - (float)low);
|
||||||
|
if (blendMode == BlendModeAdd) {
|
||||||
|
blendAdd(wrap(low), color, lowFactor);
|
||||||
|
blendAdd(wrap(high), color, highFactor);
|
||||||
|
} else if (blendMode == BlendModeAlpha) {
|
||||||
|
blendAlpha(wrap(low), color, lowFactor);
|
||||||
|
blendAlpha(wrap(high), color, highFactor);
|
||||||
|
} else if (blendMode == BlendModeOver) {
|
||||||
|
blendOver(wrap(low), color, lowFactor);
|
||||||
|
blendOver(wrap(high), color, highFactor);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
leds[wrap((int)position)] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additive blending
|
||||||
void blendAdd(int position, CRGB color, float factor) {
|
void blendAdd(int position, CRGB color, float factor) {
|
||||||
leds[position].r += color.r * factor;
|
leds[position].r += min(color.r * factor, 255 - leds[position].r);
|
||||||
leds[position].g += color.g * factor;
|
leds[position].g += min(color.g * factor, 255 - leds[position].g);
|
||||||
leds[position].b += color.b * factor;
|
leds[position].b += min(color.b * factor, 255 - leds[position].b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alpha blending (factor is the alpha value)
|
||||||
|
void blendAlpha(int position, CRGB color, float factor) {
|
||||||
|
leds[position].r = (uint8_t)mapFloat(factor, 0.0, 1.0, leds[position].r, color.r);
|
||||||
|
leds[position].g = (uint8_t)mapFloat(factor, 0.0, 1.0, leds[position].g, color.g);
|
||||||
|
leds[position].b = (uint8_t)mapFloat(factor, 0.0, 1.0, leds[position].b, color.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overlay/replace blending
|
||||||
|
void blendOver(int position, CRGB color, float factor) {
|
||||||
|
leds[position].r = color.r * factor;
|
||||||
|
leds[position].g = color.g * factor;
|
||||||
|
leds[position].b = color.b * factor;
|
||||||
|
leds[position] = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap around LED ring
|
// Wrap around LED ring
|
||||||
|
Loading…
Reference in New Issue
Block a user