diff --git a/examples/GraphicsLayer/GraphicsLayer.ino b/examples/GraphicsLayer/GraphicsLayer.ino deleted file mode 100644 index 61f51bf..0000000 --- a/examples/GraphicsLayer/GraphicsLayer.ino +++ /dev/null @@ -1,157 +0,0 @@ -/* - * An example that writes to a CRGB FastLED pixel buffer before being ultimately sent - * to the DMA Display. - * - * Faptastic 2020 - * - * Note: - * * Layers use lots of RAM (3*WIDTH*HEIGHT bytes per layer to be precise), so use at your own risk. - * * Make sure LAYER_WIDTH and LAYER_HEIGHT are correctly configured in Layer.h !!! - */ - -//#define USE_CUSTOM_PINS // uncomment to use custom pins, then provide below - -#define A_PIN 26 -#define B_PIN 4 -#define C_PIN 27 -#define D_PIN 2 -#define E_PIN 21 - -#define R1_PIN 5 -#define R2_PIN 19 -#define G1_PIN 17 -#define G2_PIN 16 -#define B1_PIN 18 -#define B2_PIN 25 - -#define CLK_PIN 14 -#define LAT_PIN 15 -#define OE_PIN 13 - - -#include // FastLED needs to be installed. -#include "Layer.h" // Layer Library -#include "Fonts/FreeSansBold9pt7b.h" // include adafruit font - -/* - * 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()'. - * - */ -MatrixPanel_I2S_DMA dma_display; // Create HUB75 DMA object - -// Create FastLED based graphic 'layers' -Layer bgLayer(dma_display); // Create background Layer -Layer textLayer(dma_display); // Create foreground Layer - - -int time_counter = 0; -int cycles = 0; -CRGBPalette16 currentPalette; -CRGB currentColor; - - -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("*****************************************************"); - Serial.println(" HELLO !"); - Serial.println("*****************************************************"); - -#ifdef USE_CUSTOM_PINS - dma_display.begin(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 ); // setup the LED matrix -#else - dma_display.begin(); -#endif - - // fill the screen with 'black' - dma_display.fillScreen(dma_display.color444(0, 0, 0)); - - // Set current FastLED palette - currentPalette = RainbowColors_p; - - // Allocate Background Layer - bgLayer.init(); - bgLayer.clear(); - bgLayer.setTransparency(false); - - // Allocate Canvas Layer - textLayer.init(); - textLayer.clear(); - - /* Step 1: Write some pixels to foreground Layer (use custom layer function) - * Only need to do this once as we're not changing it ever again in this example. - */ - textLayer.drawCentreText("COOL!", MIDDLE, &FreeSansBold9pt7b, CRGB(255,255,255)); - textLayer.autoCenterX(); // because I don't trust AdaFruit to perfectly place the contents in the middle - -} - -int LayerCompositor_mode = 0; -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); - - /* - * Step 2: Write to Background layer! Don't show it on the screen just yet. - * Note: Layer class is designed for FastLED 'CRGB' data type. - */ - bgLayer.drawPixel(x, y, currentColor); - - } - } - - time_counter += 1; - cycles++; - - if (cycles >= 2048) { - time_counter = 0; - cycles = 0; - } - - /* - * Step 3: Merge foreground and background layers and send to the matrix panel! - * Use our special sauce LayerCompositor functions - */ - switch (LayerCompositor_mode) - { - case 0: - LayerCompositor::Siloette(dma_display, bgLayer, textLayer); - break; - - case 1: - LayerCompositor::Stack(dma_display, bgLayer, textLayer); - break; - - case 2: - LayerCompositor::Blend(dma_display, bgLayer, textLayer); - break; - } - - EVERY_N_SECONDS(5) { // FastLED Macro - LayerCompositor_mode++; - dma_display.clearScreen(); - if (LayerCompositor_mode > 2) LayerCompositor_mode = 0; - } - - // - // LayerCompositor::Blend(dma_display, bgLayer, textLayer, 127); - -} // end loop diff --git a/examples/GraphicsLayer/GraphicsLayer.jpg b/examples/GraphicsLayer/GraphicsLayer.jpg deleted file mode 100644 index 70dd6da..0000000 Binary files a/examples/GraphicsLayer/GraphicsLayer.jpg and /dev/null differ diff --git a/examples/GraphicsLayer/Layer.cpp b/examples/GraphicsLayer/Layer.cpp deleted file mode 100644 index 4352398..0000000 --- a/examples/GraphicsLayer/Layer.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/** - * Experimental layer class to do play with pixel in an off-screen buffer before painting to the DMA - * - * Requires FastLED - * - * Faptastic 2020 - **/ - -#include "Layer.h" - -// For adafruit -void Layer::drawPixel(int16_t x, int16_t y, uint16_t color) { - - // 565 color conversion - uint8_t r = ((((color >> 11) & 0x1F) * 527) + 23) >> 6; - uint8_t g = ((((color >> 5) & 0x3F) * 259) + 33) >> 6; - uint8_t b = (((color & 0x1F) * 527) + 23) >> 6; - - drawPixel(x, y, CRGB(r,g,b)); -} - -void Layer::drawPixel(int16_t x, int16_t y, int r, int g, int b) { - drawPixel(x, y, CRGB(r,g,b)); -} - -void Layer::drawPixel(int16_t x, int16_t y, CRGB color) { - - if( x >= LAYER_WIDTH || x < 0) return; // 0; - if( y >= LAYER_HEIGHT || y < 0) return; // 0; - - pixels->data[y][x] = color; -} - -/** - * Dim all the pixels in the display. - */ -void Layer::dim(byte value) { - - // nscale8 max value is 255, or it'll flip back to 0 - // (documentation is wrong when it says x/256), it's actually x/255 - for (int y = 0; y < LAYER_HEIGHT; y++) { - for (int x = 0; x < LAYER_WIDTH; x++) { - pixels->data[y][x].nscale8(value); - }} -} - -void Layer::clear() { - - memset(pixels, BLACK_BACKGROUND_PIXEL_COLOUR, sizeof(layerPixels) ); -} - -/** - * Send the layer to the display device. - */ -void Layer::display() { - - CRGB _pixel = 0 ; - for (int y = 0; y < LAYER_HEIGHT; y++) { - for (int x = 0; x < LAYER_WIDTH; x++) - { - //_pixel = pixel[XY(x, y)]; - _pixel = pixels->data[y][x]; - - matrix->drawPixelRGB888( x, y, _pixel.r, _pixel.g, _pixel.b); - - /* - if ( !transparency_enabled ){ - matrix->drawPixelRGB888( x, y, _pixel.r, _pixel.g, _pixel.b); - } else { - if (_pixel != transparency_colour) { - matrix->drawPixelRGB888( x, y, _pixel.r, _pixel.g, _pixel.b); - } - } - */ - } // end loop to copy fast led to the dma matrix - } - -} // display - -void Layer::overridePixelColor(int r, int g, int b) { - CRGB _pixel = 0 ; - for (int y = 0; y < LAYER_HEIGHT; y++) { - for (int x = 0; x < LAYER_WIDTH; x++) - { - //_pixel = pixel[XY(x, y)]; - _pixel = pixels->data[y][x]; - - if (_pixel != transparency_colour) { - matrix->drawPixelRGB888( x, y, _pixel.r, _pixel.g, _pixel.b); - } - - } // end loop to copy fast led to the dma matrix - } -} - - -// default value is in definition -void Layer::drawCentreText(const char *buf, textPosition textPos, const GFXfont *f, CRGB color, int yadjust) -{ - int16_t x1, y1; - uint16_t w, h; - - setTextWrap(false); - - if (f) { // Font struct pointer passed in? - setFont((GFXfont *)f); - } else { // NULL passed. Current font struct defined? - setFont(); // use default - } - - // getTextBounds isn't correct for variable width fonts - getTextBounds(buf, 0, 0, &x1, &y1, &w, &h); //calc width of new string - - //Serial.printf("The width of the text is %d pixels, the height is %d pixels.\n", w,h); - - /* - - From: https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts - - For example, whereas the cursor position when printing with the classic font identified - the top-left corner of the character cell, with new fonts the cursor position indicates the baseline — - the bottom-most row — of subsequent text. Characters may vary in size and width, and don’t - necessarily begin at the exact cursor column (as in below, this character starts one pixel - left of the cursor, but others may be on or to the right of it). - */ - - if (!f) { - if (textPos == TOP) { - setCursor((LAYER_WIDTH - w) / 2, 0); // top - } else if (textPos == BOTTOM) { - setCursor((LAYER_WIDTH - w) / 2, LAYER_HEIGHT - h); - } else { // middle - setCursor((LAYER_WIDTH - w) / 2, (LAYER_HEIGHT - h) / 2); // top - } - } - else // custom font - /* As we can't reliable know what is the actual FIRST and last 'lit' pixel, we need to check what was printed to the layer.*/ - { - int wstart = 0; - -/* - if (w > 42) wstart = (LAYER_WIDTH - w) / 2; - else wstart = (LAYER_WIDTH - w) / 2; -*/ - wstart = (LAYER_WIDTH - w) / 2; - - if (textPos == TOP) { - setCursor(wstart, h+yadjust); // top - } else if (textPos == BOTTOM) { - setCursor(wstart+1, (LAYER_HEIGHT-1)+yadjust); - } else { // middle - setCursor( wstart, ((LAYER_HEIGHT/2) + (h/2)) + yadjust); - } - - //Serial.printf("Layer: x1: %d, y1: %d, w: %d, h: %d.\n", x1, y1, w, h); - } - - // setCursor(0,16); - setTextColor(this->color565(color.r, color.g, color.b)); // Need to confirm from FastLed CRGB to adafruit 565 - print(buf); - -} // end drawCentreText - - - // Move the contents of the screen left (-ve) or right (+ve) - void Layer::moveX(int offset) - { - if(offset > 0) { // move right - // Sprintln("Moving right"); - - for(int x = LAYER_WIDTH - 1; x >= 0; x--){ // 63 to 0 - for(int y = 0; y < LAYER_HEIGHT; y++){ // 0 to 31 - if (x - offset >= 0) - { - // Serial.printf("setting y %d x %d to y %d x %d\n", y, x, y, x-offset); - pixels->data[y][x] = pixels->data[y][x-offset]; - } - else { - pixels->data[y][x] = BLACK_BACKGROUND_PIXEL_COLOUR; - } - } - } - } else { // move left - - // Sprintln("Moving Left"); - for(int x = 0; x <=LAYER_WIDTH - 1; x++){ - for(int y = 0; y < LAYER_HEIGHT; y++){ - if ( x > (LAYER_WIDTH-1)+offset ) - { - pixels->data[y][x] = BLACK_BACKGROUND_PIXEL_COLOUR; - //Serial.println("eh?"); - } - else - { - pixels->data[y][x] = pixels->data[y][x-offset]; - // Serial.println("eh?"); - } - } - } - } - } - -/** - * Centre the contents of the layer based on the leftmost and rightmost pixels. - * Useful if you want to make sure text / graphics IS in the centre of the display. - */ - void Layer::autoCenterX() - { - int leftmost_x = 0, rightmost_x = 0, adjusted_leftmost_x = 0; - - // Find leftmost - for(int x = 0; x < LAYER_WIDTH; x++) { - for(int y = 0; y < LAYER_HEIGHT; y++) { - if (pixels->data[y][x] != BLACK_BACKGROUND_PIXEL_COLOUR) - { - leftmost_x = x; - //Serial.printf("Left most x pixel is %d\n", leftmost_x); - goto rightmost; - } - } - } - - rightmost: - for(int x = LAYER_WIDTH-1; x >= 0; x--) { - for(int y = 0; y < LAYER_HEIGHT; y++) { - if (pixels->data[y][x] != BLACK_BACKGROUND_PIXEL_COLOUR) - { - rightmost_x = x+1; - //Serial.printf("Right most x pixel is %d\n", rightmost_x); - goto centreit; - } - } - } - - centreit: - adjusted_leftmost_x = ( LAYER_WIDTH - (rightmost_x - leftmost_x))/2; - //Serial.printf("Adjusted: %d, Moving x coords by %d pixels.\n", adjusted_leftmost_x, adjusted_leftmost_x-leftmost_x); - moveX(adjusted_leftmost_x-leftmost_x); - } // end autoCentreX - - void Layer::moveY(int delta) - { - // Not implemented - } - - -Layer::~Layer(void) -{ - free(pixels); -} - - - - -/* Merge FastLED layers into a super layer and display. Definition */ -namespace LayerCompositor -{ - /* - * Display the foreground pixels if they're not the background/transparent color. - * If not, then fill with whatever is in the background. - * - * writeToBg = write the result back to the _bgLayer, and not directly to the output device! - * -> no need to do a subsequent bgLayer.display() otherwise. - */ - void Stack(MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer, bool writeBackToBg) - { - for (int y = 0; y < LAYER_HEIGHT; y++) { - for (int x = 0; x < LAYER_WIDTH; x++) - { - //https://www.educative.io/edpresso/how-to-resolve-the-expression-must-have-class-type-error-in-cpp - if (_fgLayer.pixels->data[y][x] == _fgLayer.transparency_colour) // foreground is transparent, show the _bgLayer colors - { - if (writeBackToBg) // write the foreground to the background layer... perhaps so we can do stuff later with the _fgLayer. - _bgLayer.pixels->data[y][x] = _bgLayer.pixels->data[y][x]; - else - disp.drawPixelRGB888(x,y, _bgLayer.pixels->data[y][x].r, _bgLayer.pixels->data[y][x].g, _bgLayer.pixels->data[y][x].b ); - - } // if the foreground is NOT transparent, then print whatever is the bg - else - { - if (writeBackToBg) // write the foreground to the background layer... perhaps so we can do stuff later with the _fgLayer. - _bgLayer.pixels->data[y][x] = _fgLayer.pixels->data[y][x]; - else - disp.drawPixelRGB888(x,y, _fgLayer.pixels->data[y][x].r, _fgLayer.pixels->data[y][x].g, _fgLayer.pixels->data[y][x].b ); - } - - } // end x loop - } // end y loop - } // end stack - - - /* - * Where the foreground pixels are not the background/transparent color, populate with - * whatever is in the background. - */ - void Siloette(MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer) - { - - for (int y = 0; y < LAYER_HEIGHT; y++) { - for (int x = 0; x < LAYER_WIDTH; x++) - { - //https://www.educative.io/edpresso/how-to-resolve-the-expression-must-have-class-type-error-in-cpp - if (_fgLayer.pixels->data[y][x] != _fgLayer.transparency_colour) - { - disp.drawPixelRGB888(x,y, _bgLayer.pixels->data[y][x].r, _bgLayer.pixels->data[y][x].g, _bgLayer.pixels->data[y][x].b ); - } // if the foreground is transparent, then print whatever is the bg - else - { - disp.drawPixelRGB888(x,y, 0,0,0); - } - - } // end x loop - } // end y loop - } // end stack - - - - - - void Blend(MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer, uint8_t ratio) - { - CRGB _pixel = 0 ; - - for (int y = 0; y < LAYER_HEIGHT; y++) - { - for (int x = 0; x < LAYER_WIDTH; x++) - { - - _pixel = _bgLayer.pixels->data[y][x]; - - // (set ratio to 127 for a constant 50% / 50% blend) - //_pixel = blend(_bgLayer.pixels->data[y][x], _fgLayer.pixels->data[y][x], ratio); - - // Blend with background if foreground pixel isn't clear/transparent - if (_fgLayer.pixels->data[y][x] != _fgLayer.transparency_colour) - { - _pixel = blend(_bgLayer.pixels->data[y][x], _fgLayer.pixels->data[y][x], ratio); - } // if the foreground is transparent, then print whatever is the bg - - - // https://gist.github.com/StefanPetrick/0c0d54d0f35ea9cca983 - disp.drawPixelRGB888(x,y, _pixel.r, _pixel.g, _pixel.b ); - - } // end x loop - } // end y loop - - - - } // end blend -} diff --git a/examples/GraphicsLayer/Layer.h b/examples/GraphicsLayer/Layer.h deleted file mode 100644 index 32a31fa..0000000 --- a/examples/GraphicsLayer/Layer.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Experimental layer class to play with pixel in an off-screen buffer before painting to the DMA - * - * Requires FastLED - * - * Faptastic 2020 - **/ - -#ifndef DISPLAY_MATRIX_LAYER -#define DISPLAY_MATRIX_LAYER - - -/* Use GFX_Root (https://github.com/mrfaptastic/GFX_Root) instead of - * Adafruit_GFX library. No real benefit unless you don't want Bus_IO & Wire.h library dependencies. - */ -#define USE_GFX_ROOT 1 - - -#ifdef USE_GFX_ROOT - #include "GFX.h" // Adafruit GFX core class -> https://github.com/mrfaptastic/GFX_Root -#else - #include "Adafruit_GFX.h" // Adafruit class with all the other stuff -#endif - -#include -#include - -/* - * Set the width and height of the layer buffers. This should match exactly that of your output display, or virtual display. - */ -#define LAYER_WIDTH 64 -#define LAYER_HEIGHT 32 - - -#define HALF_WHITE_COLOUR 0x8410 -#define BLACK_BACKGROUND_PIXEL_COLOUR CRGB(0,0,0) - -enum textPosition { TOP, MIDDLE, BOTTOM }; - - -/* To help with direct pixel referencing by width and height */ -struct layerPixels { - CRGB data[LAYER_HEIGHT][LAYER_WIDTH]; -}; - -#ifdef USE_GFX_ROOT -class Layer : public GFX -#else -class Layer : public Adafruit_GFX -#endif -// class Layer : public GFX // use GFX Root for now -{ - public: - - // Static allocation of memory for layer - //CRGB pixels[LAYER_WIDTH][LAYER_HEIGHT] = {{0}}; - - Layer(MatrixPanel_I2S_DMA &disp) : GFX (LAYER_WIDTH, LAYER_HEIGHT) { - matrix = &disp; - } - - inline void init() - { - // https://stackoverflow.com/questions/5914422/proper-way-to-initialize-c-structs - pixels = new layerPixels(); - - //pixels = (layerPixels *) malloc(sizeof(layerPixels)); - // pixel = (CRGB *) &pixels[0]; - //Serial.printf("Allocated %d bytes of memory for standard CRGB (24bit) layer.\r\n", NUM_PIXELS*sizeof(CRGB)); - Serial.printf("Allocated %d bytes of memory for layerPixels.\r\n", sizeof(layerPixels)); - - } // end Layer - - void drawPixel(int16_t x, int16_t y, uint16_t color); // overwrite adafruit implementation - void drawPixel(int16_t x, int16_t y, int r, int g, int b); // Layer implementation - void drawPixel(int16_t x, int16_t y, CRGB color); // Layer implementation - - // Font Stuff - //https://forum.arduino.cc/index.php?topic=642749.0 - void drawCentreText(const char *buf, textPosition textPos = BOTTOM, const GFXfont *f = NULL, CRGB color = 0x8410, int yadjust = 0); // 128,128,128 RGB @ bottom row by default - - - void dim(byte value); - void clear(); - void display(); // flush to display / LED matrix - - // override the color of all pixels that aren't the transparent color - void overridePixelColor(int r, int g, int b); - - inline uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { - return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); - } - - inline void setTransparency(bool t) { transparency_enabled = t; } - - // Effects - void moveX(int delta); - void autoCenterX(); - void moveY(int delta); - - // For layer composition - accessed publically - CRGB transparency_colour = BLACK_BACKGROUND_PIXEL_COLOUR; - bool transparency_enabled = true; - layerPixels *pixels; - - // Release Memory - ~Layer(void); - - private: - MatrixPanel_I2S_DMA *matrix = NULL; -}; - - -/* Merge FastLED layers into a super layer and display. */ -namespace LayerCompositor -{ - void Stack(MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer, bool writeToBgLayer = false); - void Siloette(MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer); - void Blend(MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer, uint8_t ratio = 127); -} - -#endif diff --git a/examples/GraphicsLayer/README.md b/examples/GraphicsLayer/README.md deleted file mode 100644 index 562b151..0000000 --- a/examples/GraphicsLayer/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Layer Class - -Example of using additional pixel buffers / layers based on the FastLed CRGB data type, doing stuff with the pixels, merging the layers prior to sending to the DMA display library for output. - -![It's better in real life](GraphicsLayer.jpg)