#include "Window.h" #include "functions.h" Window* Window::getFullWindow() { static Window win; return &win; } 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 (int i=0; iwidth + 1))<<8), (y<<8), text[i], color); } } void Window::drawSubText(Font* font, accum88 x, accum88 y, String text, CRGB* color) { for (int 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(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, CRGB* color) { // Bresenham algorithm int dx = x2-x1; int dy = y2-y1; int x = x1; int y = y1; int p = 2*dy - dx; while (x < x2) { if (p >= 0) { setPixel(x, y, color); y++; p = p + 2*dy - 2*dx; } else { setPixel(x, y, color); p = p + 2*dy; } x++; } } 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, uint8_t angle, uint8_t length, CRGB* color) { lineWithAngle(x, y, angle, 0, length, color); } void Window::lineWithAngle(uint8_t x, uint8_t y, uint8_t angle, uint8_t startdist, uint8_t length, CRGB* color) { int16_t x1 = x; int16_t y1 = y; if (startdist > 0) { x1 = x + scale8(startdist, cos8(angle)); y1 = y + scale8(startdist, sin8(angle)); } int16_t x2 = x + scale8(startdist + length, cos8(angle)); int16_t y2 = y + scale8(startdist + length, sin8(angle)); 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; } }