From c9a8c5070252563a603c6557ce0cd58cbb2a4292 Mon Sep 17 00:00:00 2001
From: mrcodetastic <12006953+mrcodetastic@users.noreply.github.com>
Date: Mon, 17 Mar 2025 20:55:35 +0000
Subject: [PATCH] Create ScrollingTextLayer.ino

---
 .../ScrollingTextLayer/ScrollingTextLayer.ino | 267 ++++++++++++++++++
 1 file changed, 267 insertions(+)
 create mode 100644 examples/ScrollingTextLayer/ScrollingTextLayer.ino

diff --git a/examples/ScrollingTextLayer/ScrollingTextLayer.ino b/examples/ScrollingTextLayer/ScrollingTextLayer.ino
new file mode 100644
index 0000000..60a95a7
--- /dev/null
+++ b/examples/ScrollingTextLayer/ScrollingTextLayer.ino
@@ -0,0 +1,267 @@
+// Modified from: https://github.com/wilson3682/My-HUB75-ESP32-Practice-Files/tree/main 
+// by MrCodetastic
+
+/***************************************************************************************
+ * This sketch does a couple of things, it uses GFX_Lite's GFX_Layer to independently  
+ * draw the background and the text onto separate layers. (memory used for each)
+ * Then these are stacked on top of each other with some opacity, and drawn directly
+ * to the dma_display via a callback (layer_draw_callback).
+ *
+ * These layers are offscreen pixel buffers that use  memory of their own
+ * (approx 3 bytes for each pixel).
+ * 
+ * By using this approach, we don't really need to use DMA double buffering though.
+ *
+ ***************************************************************************************/
+
+#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
+
+// You need to have: https://github.com/mrcodetastic/GFX_Lite
+#include <GFX_Layer.hpp>
+
+//------------------------------------------------------------------------------------------------------------------
+
+// Configure for your panel(s) as appropriate!
+#define PANEL_WIDTH   64
+#define PANEL_HEIGHT  32  	// Panel height of 64 will required PIN_E to be defined.
+#define CHAIN_LENGTH  1 	// Number of chained panels, if just a single panel, obviously set to 1
+
+
+//------------------------------------------------------------------------------------------------------------------
+
+/*
+#define RL1 18
+#define GL1 17
+#define BL1 16
+#define RL2 15
+#define GL2 7
+#define BL2 6
+#define CH_A 4
+#define CH_B 10
+#define CH_C 14
+#define CH_D 21
+#define CH_E 5 // assign to any available pin if using two panels or 64x64 panels with 1/32 scan
+#define CLK 47
+#define LAT 48
+#define OE  38
+*/
+
+
+//------------------------------------------------------------------------------------------------------------------
+
+MatrixPanel_I2S_DMA *dma_display = nullptr;
+
+//------------------------------------------------------------------------------------------------------------------
+
+//====================== Variables For scrolling Text=====================================================
+unsigned long isAnimationDue;
+int delayBetweeenAnimations = 18;             // Smaller == faster
+int textXPosition = PANEL_WIDTH * CHAIN_LENGTH;  // Will start off screen
+int textYPosition = PANEL_HEIGHT / 2 - 7;        // center of screen - 8 (half of the text height)
+//====================== Variables For scrolling Text=====================================================
+
+
+// Pointers to this variable will be passed into getTextBounds,
+// they will be updated from inside the method
+int16_t xOne, yOne;
+uint16_t w, h;
+
+
+//------------------------------------------------------------------------------------------------------------------
+// The layers don't draw to hardware directly, they use a callback function.
+// You could be smart here and additionally draw to the VirtualMatrixPanel_T class...
+void layer_draw_callback(int16_t x, int16_t y, uint8_t r_data, uint8_t g_data, uint8_t b_data) {
+
+       dma_display->drawPixelRGB888(x,y,r_data,g_data,b_data);
+
+}
+
+// Global GFX_Layer object
+GFX_Layer gfx_layer_bg(PANEL_WIDTH*CHAIN_LENGTH, PANEL_HEIGHT, layer_draw_callback); // background
+GFX_Layer gfx_layer_fg(PANEL_WIDTH*CHAIN_LENGTH, PANEL_HEIGHT, layer_draw_callback); // foreground
+
+GFX_LayerCompositor gfx_compositor(layer_draw_callback);
+
+//------------------------------------------------------------------------------------------------------------------
+
+void setup() {
+
+  Serial.begin(115200);
+
+  //Custom pin mapping for all pins
+  HUB75_I2S_CFG::i2s_pins _pins={RL1, GL1, BL1, RL2, GL2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK};
+  HUB75_I2S_CFG mxconfig(
+                          PANEL_WIDTH,    // width
+                          PANEL_HEIGHT,   // height
+                          CHAIN_LENGTH   // chain length
+                        // ,_pins           // pin mapping
+        // ,HUB75_I2S_CFG::FM6126A         // driver chip
+  );
+
+  mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_20M;
+
+  // If you are using a 64x64 matrix you need to pass a value for the E pin
+  // The trinity connects GPIO 18 to E.
+  // This can be commented out for any smaller displays (but should work fine with it)
+  //mxconfig.gpio.e = -1;
+
+  // May or may not be needed depending on your matrix
+  // Example of what needing it looks like:
+  // https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/134#issuecomment-866367216
+  //mxconfig.clkphase = false;
+
+  // Some matrix panels use different ICs for driving them and some of them have strange quirks.
+  // If the display is not working right, try this.
+  //mxconfig.driver = HUB75_I2S_CFG::FM6126A;
+
+  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
+  dma_display->begin();
+  dma_display->setBrightness8(120);  //0-255
+  dma_display->clearScreen();
+
+  // Clear the layers
+  gfx_layer_fg.clear();
+  gfx_layer_fg.setTextWrap(false);
+
+  gfx_layer_bg.clear();
+
+}
+
+void printTextRainbowCentered(int colorWheelOffset, const char *text, int yPos) {
+  gfx_layer_fg.setTextSize(1);  // size 1 == 8 pixels high
+
+  // Calculate the width of the text in pixels
+  int textWidth = strlen(text) * 6;  // Assuming 6 pixels per character for size 1
+
+  // Center the text horizontally
+  int xPos = (gfx_layer_fg.width() - textWidth) / 2;
+
+  gfx_layer_fg.setCursor(xPos, yPos);  // Set cursor position for centered text
+
+  // Draw text with a rotating color
+  for (uint8_t w = 0; w < strlen(text); w++) {
+    gfx_layer_fg.setTextColor(colorWheel((w * 32) + colorWheelOffset));
+    gfx_layer_fg.print(text[w]);
+  }
+}
+
+
+// Code taken from: https://github.com/witnessmenow/ESP32-Trinity/blob/master/examples/BuildingBlocks/Text/ScrollingText/ScrollingText.ino
+//
+void scrollText(int colorWheelOffset, const char *text) {
+
+  const char *str = text;
+  byte offSet = 25;
+  unsigned long now = millis();
+  if (now > isAnimationDue) 
+  {
+
+    gfx_layer_fg.setTextSize(2);  // size 2 == 16 pixels high
+
+    isAnimationDue = now + delayBetweeenAnimations;
+    textXPosition -= 1;
+
+    // Checking is the very right of the text off screen to the left
+    gfx_layer_fg.getTextBounds(str, textXPosition, textYPosition, &xOne, &yOne, &w, &h);
+    if (textXPosition + w <= 0) {
+      textXPosition = gfx_layer_fg.width() + offSet;
+    }
+
+    gfx_layer_fg.setCursor(textXPosition, textYPosition);
+
+    // Clear the area of text to be drawn to
+    gfx_layer_fg.drawRect(1, textYPosition, gfx_layer_fg.width() - 1, 14, gfx_layer_fg.color565(0, 0, 0));
+    gfx_layer_fg.fillRect(1, textYPosition, gfx_layer_fg.width() - 1, 14, gfx_layer_fg.color565(0, 0, 0));
+
+    uint8_t w = 0;
+    for (w = 0; w < strlen(str); w++) {
+      //gfx_layer_fg.setTextColor(colorWheel((w * 32) + colorWheelOffset));
+      gfx_layer_fg.setTextColor(gfx_layer_fg.color565(255, 255, 255));
+      gfx_layer_fg.print(str[w]);
+    }
+
+  }
+}
+
+
+void drawTextCentered(int colorWheelOffset, const char *text, int yPos) {
+
+  // draw text with a rotating colour
+  gfx_layer_fg.setTextSize(1);       // size 1 == 8 pixels high
+                                     // Calculate the width of the text in pixels
+  int textWidth = strlen(text) * 6;  // Assuming 6 pixels per character for size 1
+
+  // Center the text horizontally
+  int xPos = (gfx_layer_fg.width() - textWidth) / 2;
+
+
+  gfx_layer_fg.setCursor(xPos, yPos);  // start at top left, with 8 pixel of spacing
+  uint8_t w = 0;
+  //const char *str = "ESP32 DMA";
+  const char *str = text;
+  for (w = 0; w < strlen(str); w++) {
+    gfx_layer_fg.setTextColor(colorWheel((w * 32) + colorWheelOffset));
+    gfx_layer_fg.print(str[w]);
+  }
+}
+
+// Input a value 0 to 255 to get a color value.
+// The colours are a transition r - g - b - back to r.
+// From: https://gist.github.com/davidegironi/3144efdc6d67e5df55438cc3cba613c8
+uint16_t colorWheel(uint8_t pos) {
+  if (pos < 85) {
+    return dma_display->color565(pos * 3, 255 - pos * 3, 0);
+  } else if (pos < 170) {
+    pos -= 85;
+    return dma_display->color565(255 - pos * 3, 0, pos * 3);
+  } else {
+    pos -= 170;
+    return dma_display->color565(0, pos * 3, 255 - pos * 3);
+  }
+}
+
+unsigned long last_increment = 0;
+unsigned long increment_amt  = 0;
+void updateBackground()
+{
+
+    CRGBPalette16 currentPalette = CloudColors_p;
+
+    if ( (millis() - last_increment) > 20) {
+        increment_amt++;
+        last_increment = millis();
+    } 
+
+    for (int x = 0; x < gfx_layer_bg.width(); x++) {
+        for (int y = 0; y < gfx_layer_bg.height(); y++) {
+
+            int val = sin8(x + increment_amt);
+            val += sin8(y + increment_amt);
+
+            CRGB currentColor = ColorFromPalette(currentPalette, val); //, brightness, currentBlendType);
+
+            // Set a pixel in the back layer
+            gfx_layer_bg.setPixel(x, y, currentColor.r, currentColor.g, currentColor.b);
+
+        }
+    } 
+
+     gfx_layer_bg.dim(192); // darken it a little
+}
+
+uint8_t wheelval = 0;
+void loop() {
+
+  updateBackground();
+
+  scrollText(wheelval, "HAVE A WONDERFUL DAY!");    //Prints Scrolling text with a rainbow color
+  printTextRainbowCentered(wheelval, "ENJOY IT", 24);  //Prints text X-Centered to chosen Y position with rainbow color
+
+  //gfx_layer_fg.display();
+  //gfx_layer_bg.display();
+
+  gfx_compositor.Blend(gfx_layer_bg, gfx_layer_fg); // blend and immediately display
+
+  wheelval += 1;
+
+}