#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; xwidth; x++) for(int y=0; yheight; 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; iwidth + 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; iwidth + 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; yheight; y++) for(uint8_t x=0; xwidth; 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; xwidth; 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; xwidth; 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; yheight; 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; yheight; y++) { blur_row(y, intensity); } } void Window::blur_columns(fract8 intensity) { for (uint8_t x=0; xwidth; 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; yheight; 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; xwidth; x++) for(uint8_t y=0; yheight; 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= 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; xwidth; x++) { for(int y=0; yheight; y++) { this->setPixel(x, y, ((x+y+s) % 2)?&pink:&black); } } }