pitrix/src/Window.cpp

286 lines
7.8 KiB
C++

#include "Window.h"
#include "functions.h"
Window Window::window_full = Window();
Window Window::window_with_clock = Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
Window Window::window_clock = Window(0, LED_HEIGHT-6, LED_WIDTH, 6);
void Window::setPixel(uint8_t x, uint8_t y, CRGB* color) {
if (x>=this->width || y>=this->height) return;
leds[this->coordsToGlobalIndex(x, y)] = *color;
}
void Window::raisePixel(uint8_t x, uint8_t y, CRGB* color) {
if (x>=this->width || y>=this->height) return;
leds[this->coordsToGlobalIndex(x, y)] |= *color;
}
void Window::setPixelByIndex(uint16_t index, CRGB* color) {
uint8_t x = index % this->width;
uint8_t y = index / this->width;
this->setPixel(x, y, color);
}
uint16_t Window::coordsToGlobalIndex(uint8_t x, uint8_t y) {
return XYsafe(x + this->x, y+this->y);
}
uint16_t Window::localToGlobalIndex(uint16_t index) {
uint8_t x = index % this->width;
uint8_t y = index / this->width;
return coordsToGlobalIndex(x, y);
}
void Window::clear() {
CRGB black(0x000000);
this->clear(&black);
}
void Window::clear(CRGB* color) {
for(int x=0; x<this->width; x++) for(int y=0; y<this->height; y++) this->setPixel(x, y, color);
}
void Window::drawText(Font* font, uint16_t x, uint16_t y, String text, CRGB* color) {
for (uint16_t i=0; i<text.length(); i++) {
drawChar(font, (x+((i*(font->width + 1))<<8)), (y<<8), text[i], color);
}
}
void Window::drawSubText(Font* font, accum88 x, accum88 y, String text, CRGB* color) {
for (uint16_t i=0; i<text.length(); i++) {
drawChar(font, x+(i*((font->width + 1)<<8)), y, text[i], color);
}
}
void Window::drawChar(Font* font, accum88 xPos, accum88 yPos, const char c, CRGB* color, bool mask) {
SubpixelRenderingMode mode = mask ? SUBPIXEL_RENDERING_SET : SUBPIXEL_RENDERING_ADD;
if (!font->isCharAllowed(c)) return;
uint16_t position = font->getCharPosition(c);
uint8_t* data = new uint8_t[font->width];
memcpy_P(data, font->data + (position*font->width), font->width);
for(uint8_t y=0; y<font->height; y++) for(uint8_t x=0; x<font->width; x++) {
bool on = (data[x]>>(font->height - 1 - y) & 1) * 255;
if (mask) on = !on;
if (on) this->setSubPixel(xPos + (x<<8), yPos + (y<<8), color, mode);
}
free(data);
}
void Window::clear_row(uint8_t y) {
CRGB black(0x000000);
for (uint8_t x=0; x<this->width; x++) this->setPixel(x, y, &black);
}
void Window::shift_down() {
for (uint8_t y=this->height-1; y>=1; y--) {
for (uint8_t x=0; x<this->width; x++) {
leds[coordsToGlobalIndex(x, y)] = leds[coordsToGlobalIndex(x, y-1)];
}
}
clear_row(0);
}
void Window::shift_down_and_blur() {
shift_down();
for (uint8_t y=1; y<this->height; y++) {
blur_row(y, 128);
}
}
void Window::blur(fract8 intensity) {
blur_rows(intensity);
blur_columns(intensity);
}
void Window::blur_rows(fract8 intensity) {
for (uint8_t y=0; y<this->height; y++) {
blur_row(y, intensity);
}
}
void Window::blur_columns(fract8 intensity) {
for (uint8_t x=0; x<this->width; x++) {
blur_column(x, intensity);
}
}
void Window::blur_row(uint8_t y, fract8 intensity) {
uint16_t idx1 = coordsToGlobalIndex(0, y);
uint16_t idx2 = coordsToGlobalIndex(this->width - 1, y);
blur1d(&(leds[idx1 < idx2 ? idx1 : idx2]), this->width, intensity);
}
void Window::blur_column(uint8_t x, fract8 intensity) {
// Reimplementation from FastLEDs blurColumns
uint8_t keep = 255 - intensity;
uint8_t seep = intensity >> 1;
CRGB carryover = CRGB::Black;
for (uint8_t y=0; y<this->height; y++) {
CRGB cur = leds[coordsToGlobalIndex(x, y)];
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if (y>0) leds[coordsToGlobalIndex(x, y-1)] += part;
leds[coordsToGlobalIndex(x, y)] = cur;
carryover = part;
}
}
void Window::addPixelColor(uint16_t index, CRGB* color) {
leds[localToGlobalIndex(index)] += *color;
}
void Window::addPixelColor(uint8_t x, uint8_t y, CRGB* color) {
leds[coordsToGlobalIndex(x, y)] += *color;
}
CRGB Window::get_pixel(uint8_t x, uint8_t y) {
return leds[coordsToGlobalIndex(x, y)];
}
void Window::fadeToBlackBy(fract8 speed) {
for (uint8_t x=0; x<this->width; x++) for(uint8_t y=0; y<this->height; y++) {
leds[coordsToGlobalIndex(x, y)].nscale8(255 - speed);
}
}
void Window::line(saccum78 x1, saccum78 y1, saccum78 x2, saccum78 y2, CRGB* color) {
// Bresenham algorithm
const uint8_t stepsize = 64;
saccum78 dx = abs(x2 - x1);
saccum78 dy = -abs(y2 - y1);
int8_t sx = x1<x2 ? 1 : -1;
int8_t sy = y1<y2 ? 1 : -1;
saccum78 err = dx + dy;
saccum78 e2;
uint8_t step = 0;
while (1) {
if (step == 0) setSubPixel(x1, y1, color, SUBPIXEL_RENDERING_RAISE);
if (++step >= stepsize) step=0;
if (x1>>8==x2>>8 && y1>>8==y2>>8) break;
e2 = 2*err;
if (e2 > dy) {
err += dy;
x1 += sx;
}
if (e2 < dx) {
err += dx;
y1 += sy;
}
}
}
void Window::_circle_point(int x0, int y0, int x1, int y1, CRGB* color) {
setPixel(x0+x1, y0+y1, color);
setPixel(x0-x1, y0+y1, color);
setPixel(x0+x1, y0-y1, color);
setPixel(x0-x1, y0-y1, color);
setPixel(x0+y1, y0+x1, color);
setPixel(x0-y1, y0+x1, color);
setPixel(x0+y1, y0-x1, color);
setPixel(x0-y1, y0-x1, color);
}
void Window::circle(uint8_t x0, uint8_t y0, uint8_t radius, CRGB* color) {
// Again, Bresenham
int x=0, y=radius;
int d=3 - 2*radius;
_circle_point(x0, y0, x, y, color);
while (y >= x) {
x++;
if (d>0) {
y--;
d = d + 4*(x-y) + 10;
} else {
d = d + 4*x + 6;
}
_circle_point(x0, y0, x, y, color);
}
}
void Window::lineWithAngle(uint8_t x, uint8_t y, uint16_t angle, uint8_t length, CRGB* color) {
lineWithAngle(x, y, angle, 0, length, color);
}
void Window::lineWithAngle(uint8_t x, uint8_t y, uint16_t angle, uint8_t startdist, uint8_t length, CRGB* color) {
//LOGln("lineWithAngle called. x: %d.%03d, y: %d.%03d, angle: %d", x>>8, x&0xFF, y>>8, y&0xFF, angle);
saccum78 x1 = x<<8;
saccum78 y1 = y<<8;
if (startdist > 0) {
x1 = (x<<8) + (startdist<<8) * cos16(angle) / 0x10000;
y1 = (y<<8) + (startdist<<8) * sin16(angle) / 0x10000;
}
if (length==0) {
setSubPixel(x1, y1, color);
return;
}
saccum78 x2 = (x<<8) + ((startdist + length)<<8) * cos16(angle) / 0x10000;
saccum78 y2 = (y<<8) + ((startdist + length)<<8) * sin16(angle) / 0x10000;
//LOGln("x1: %d.%03d, y1: %d.%03d, x2: %d.%03d, y2: %d.%03d", x1>>8, x1&0xFF, y1>>8, y1&0xFF, x2>>8, x2&0xFF, y2>>8, y2&0xFF);
line(x1, y1, x2, y2, color);
}
void Window::setSubPixel(accum88 x, accum88 y, CRGB* color, SubpixelRenderingMode mode) {
uint8_t px, py;
// px = Part of next pixel to fill
// x = "Origin pixel"
px = x & 0xFF;
py = y & 0xFF;
x = x >> 8;
y = y >> 8;
CRGB c;
c = CRGB(scale8( scale8( color->r, 255-py), 255-px),
scale8( scale8( color->g, 255-py), 255-px),
scale8( scale8( color->b, 255-py), 255-px));
_subpixel_render(x, y, &c, mode);
if (px) {
c = CRGB(scale8( scale8( color->r, 255-py), px),
scale8( scale8( color->g, 255-py), px),
scale8( scale8( color->b, 255-py), px));
_subpixel_render(x+1, y, &c, mode);
}
if (py) {
c = CRGB(scale8( scale8( color->r, py), 255-px),
scale8( scale8( color->g, py), 255-px),
scale8( scale8( color->b, py), 255-px));
_subpixel_render(x, y+1, &c, mode);
}
if (px || py) {
c = CRGB(scale8( scale8( color->r, py), px),
scale8( scale8( color->g, py), px),
scale8( scale8( color->b, py), px));
_subpixel_render(x+1, y+1, &c, mode);
}
}
void Window::_subpixel_render(uint8_t x, uint8_t y, CRGB* color, SubpixelRenderingMode mode) {
switch(mode) {
case SUBPIXEL_RENDERING_ADD: addPixelColor(x, y, color); break;
case SUBPIXEL_RENDERING_RAISE: raisePixel(x, y, color); break;
case SUBPIXEL_RENDERING_SET: setPixel(x, y, color); break;
}
}
void Window::fill_with_checkerboard() {
CRGB pink(0xFF00FF);
CRGB black(0x000000);
uint8_t s = (uint8_t)(millis() / 1000);
for(int x=0; x<this->width; x++) {
for(int y=0; y<this->height; y++) {
this->setPixel(x, y, ((x+y+s) % 2)?&pink:&black);
}
}
}