aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authormrfaptastic <12006953+mrfaptastic@users.noreply.github.com>2020-12-07 22:42:37 +0000
committermrfaptastic <12006953+mrfaptastic@users.noreply.github.com>2020-12-07 22:42:37 +0000
commit76351960b80ebbace056fad6b1107f92bb461703 (patch)
tree7ebf115b76b00f61b5ecb8e7bc480f5476280613 /examples
parent7683b1d8f3540f90baf0052ef0d82b3c2e88fbd2 (diff)
Added GraphicsLayer example.
Diffstat (limited to 'examples')
-rw-r--r--examples/GraphicsLayer/GraphicsLayer.ino109
-rw-r--r--examples/GraphicsLayer/GraphicsLayer.jpgbin0 -> 84478 bytes
-rw-r--r--examples/GraphicsLayer/Layer.cpp344
-rw-r--r--examples/GraphicsLayer/Layer.h122
-rw-r--r--examples/GraphicsLayer/README.md5
5 files changed, 580 insertions, 0 deletions
diff --git a/examples/GraphicsLayer/GraphicsLayer.ino b/examples/GraphicsLayer/GraphicsLayer.ino
new file mode 100644
index 0000000..e8a16d9
--- /dev/null
+++ b/examples/GraphicsLayer/GraphicsLayer.ino
@@ -0,0 +1,109 @@
+/*
+ * Portions of this code are adapted from Aurora: https://github.com/pixelmatix/aurora
+ * Copyright (c) 2014 Jason Coon
+ *
+ * Portions of this code are adapted from LedEffects Plasma by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Plasma.cpp?at=default
+ * Copyright (c) 2013 Robert Atkins
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+//#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 <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
+MatrixPanel_I2S_DMA dma_display;
+
+#include <FastLED.h>
+
+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;
+
+}
+
+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);
+ dma_display.drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b);
+
+ }
+ }
+
+ time_counter += 1;
+ cycles++;
+
+ if (cycles >= 2048) {
+ time_counter = 0;
+ cycles = 0;
+ }
+
+} // end loop \ No newline at end of file
diff --git a/examples/GraphicsLayer/GraphicsLayer.jpg b/examples/GraphicsLayer/GraphicsLayer.jpg
new file mode 100644
index 0000000..70dd6da
--- /dev/null
+++ b/examples/GraphicsLayer/GraphicsLayer.jpg
Binary files differ
diff --git a/examples/GraphicsLayer/Layer.cpp b/examples/GraphicsLayer/Layer.cpp
new file mode 100644
index 0000000..29ea97f
--- /dev/null
+++ b/examples/GraphicsLayer/Layer.cpp
@@ -0,0 +1,344 @@
+/**
+ * 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;
+
+ 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(RGB64x32MatrixPanel_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(RGB64x32MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer)
+ {
+ //const Layer *bg = &_bgLayer;
+ //const Layer *fg = &_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(RGB64x32MatrixPanel_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++)
+ {
+ /*
+ // set the blend ratio for the video cross fade
+ // (set ratio to 127 for a constant 50% / 50% blend)
+ uint8_t ratio = beatsin8(5);
+ */
+
+ _pixel = blend(_bgLayer.pixels->data[y][x], _fgLayer.pixels->data[y][x], ratio);
+
+ // 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
new file mode 100644
index 0000000..69a5886
--- /dev/null
+++ b/examples/GraphicsLayer/Layer.h
@@ -0,0 +1,122 @@
+/**
+ * Experimental layer class to do 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 <FastLed.h>
+#include <ESP32-RGB64x32MatrixPanel-I2S-DMA.h>
+
+/*
+ * 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(RGB64x32MatrixPanel_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:
+ RGB64x32MatrixPanel_I2S_DMA *matrix = NULL;
+};
+
+
+/* Merge FastLED layers into a super layer and display. */
+namespace LayerCompositor
+{
+ void Stack(RGB64x32MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer, bool writeToBgLayer = false);
+ void Siloette(RGB64x32MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer);
+ void Blend(RGB64x32MatrixPanel_I2S_DMA &disp, const Layer &_bgLayer, const Layer &_fgLayer, uint8_t ratio);
+}
+
+#endif
diff --git a/examples/GraphicsLayer/README.md b/examples/GraphicsLayer/README.md
new file mode 100644
index 0000000..562b151
--- /dev/null
+++ b/examples/GraphicsLayer/README.md
@@ -0,0 +1,5 @@
+# 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)