mrcodetastic / ESP32-HUB75-MatrixPanel-DMA

An Adafruit GFX Compatible Library for the ESP32, ESP32-S2, ESP32-S3 to drive HUB75 LED matrix panels using DMA for high refresh rates. Supports panel chaining.
MIT License
891 stars 199 forks source link

Display Text on top of GIF files #443

Open mzashh opened 1 year ago

mzashh commented 1 year ago

Hi there and thank you so much for this library

So i had a question, i am using the Animated GIF SPIFF example. Is there any way to display text on top of the GIF files, like continuously for an entire GIF and not only for a particular frame

board707 commented 1 year ago

Use two display buffers - first with text and second for GIF frames. Combine them before outputs each frame.

mrcodetastic commented 1 year ago

This is a question of how the AnimatedGIF library writes pixels to the display.

The issue is the AnimatedGIF library writes to every pixel for the dimensions of the GIF/Display, so any other 'drawPixels' you do will be overridden for each frame that the AnimatedGIF library wants to print to the display using this DMA library.

I think you will need to write to the display after each GIF frame, around here:

    while (gif.playFrame(true, NULL))
    {      
      dma_display->print("TEST"); /// <---------- ADD something like this I think? Write text after the AnimatedGIF library has written the GIF frame to the display.
      if ( (millis() - start_tick) > 8000) { // we'll get bored after about 8 seconds of the same looping gif
        break;
      }
    }
mzashh commented 1 year ago

Thanks for your help doing it in void ShowGIF(char *name) didnt seem to work like mrfaptastic suggested

so i did it like this and it seemed to work

I did it in the void GIFDraw(GIFDRAW *pDraw) part

{
  s = pDraw->pPixels;
  // Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
  for (x=0; x<pDraw->iWidth; x++)
  {
   OneEightMatrixDisplay->drawPixel(x, y, usPalette[*s++]); // color 565

  }
}
   OneEightMatrixDisplay->setCursor(0, 12); 
   OneEightMatrixDisplay->print("test"); // display text on each frame of GIF after its displayed

In the same way time via NTP can be displayed on top of GIFs

mzashh commented 1 year ago

reopening this issue as i noticed an issue the text seems to flicker (slight but noticeable) for some reason, so is there some other way to do it, as my approach seems to have issues

board707 commented 1 year ago

Use double buffering

mzashh commented 1 year ago

Use double buffering

yes i am going to do that, as far as i understand i have to play the gif normally and then use

display->flipDMABuffer()

and then print the text

but then how do i combine them both?

board707 commented 1 year ago

as far as i understand i have to play the gif normally and then use

display->flipDMABuffer()

and then print the text

No, not in that order. To take advantage of using double buffer you must flip the buffer as the very LAST command after all drawings. So: a) play the gif b) print the text c) display->flipDMABuffer()

mzashh commented 1 year ago

so i did as you suggested and the gif lags like hell with this (my usage of this function is probably wrong)

so then i tried

a) flipDMABuffer b) print GIF c) FlipDMABuffer d) print text

this worked better, but still jittery and flickring

board707 commented 1 year ago

this worked better,

but double buffering doesn't work in this case...

mzashh commented 1 year ago

i honestly ain't sure how to use it correctly, since flipping the buffer always causes major slowdowns for me here is the code i am trying to use it for, its from the AnimatedGIFSPIFF example and just take this part and modify it slightly i honestly am not even sure why the text flickers and the gif dosent

void GIFDraw(GIFDRAW pDraw) { uint8_t s; uint16_t d, usPalette, usTemp[320]; int x, y, iWidth; iWidth = pDraw->iWidth; if (iWidth > MATRIX_WIDTH) iWidth = MATRIX_WIDTH; usPalette = pDraw->pPalette; y = pDraw->iY + pDraw->y; // current line s = pDraw->pPixels; if (pDraw->ucDisposalMethod == 2) // restore to background color { for (x=0; x<iWidth; x++) { if (s[x] == pDraw->ucTransparent) s[x] = pDraw->ucBackground; } pDraw->ucHasTransparency = 0; } // Apply the new pixels to the main image if (pDraw->ucHasTransparency) // if transparency used { uint8_t pEnd, c, ucTransparent = pDraw->ucTransparent; int x, iCount; pEnd = s + pDraw->iWidth; x = 0; iCount = 0; // count non-transparent pixels while(x < pDraw->iWidth) { c = ucTransparent-1; d = usTemp; while (c != ucTransparent && s < pEnd) { c = s++; if (c == ucTransparent) // done, stop { s--; // back up to treat it like transparent } else // opaque { d++ = usPalette[c]; iCount++; } } // while looking for opaque pixels if (iCount) // any opaque pixels? { for(int xOffset = 0; xOffset < iCount; xOffset++ ){ dma_display->drawPixel(x + xOffset, y, usTemp[xOffset]); // 565 Color Format } x += iCount; iCount = 0; } // no, look for a run of transparent pixels c = ucTransparent; while (c == ucTransparent && s < pEnd) { c = s++; if (c == ucTransparent) iCount++; else s--; } if (iCount) { x += iCount; // skip these iCount = 0; } } } else // does not have transparency { s = pDraw->pPixels; // Translate the 8-bit pixels through the RGB565 palette (already byte reversed) for (x=0; xiWidth; x++) { dma_display->drawPixel(x, y, usPalette[*s++]); // color 565 } } dma_display->setTextSize(2); // modified part dma_display->setCursor(7, 22); dma_display->setTextColor(dma_display->color565(250, 250, 250)); dma_display->print("8 3"); // test text that i want to print dma_display->setCursor(35, 22); dma_display->setTextColor(dma_display->color565(250, 250, 250)); dma_display->print("0 8"); } // GIFDraw()

mzashh commented 1 year ago

so i managed to get a video of the issue, i had to add a delay after the draw function so that it could be slow enough to capture, irl its fast but still visible flicker, its on text only, so any idea what could be the issue

https://user-images.githubusercontent.com/58217787/234651043-1fd6dc96-7722-44da-acdb-366a6e66db06.mp4

mrcodetastic commented 1 year ago

This is a behavior of the AnimatedGif library that's outside the scope of this repo.... but from my experimentation GIFDraw is called multiple times for each frame because the GIF decoder doesn't decode a whole frame at once, but in 'chunks'.

So it's re-drawing that text many times for each GifFrame, slowing stuff down I think.

You need to some how re-write the sketch to write to an 'off-screen' buffer and apply the text over the top and then display it. I can't help you with that however.

mzashh commented 1 year ago

yes it seems like so, according to bitbank2

The concept is very simple - as you decode each line, draw the pixels of the text which should appear on that line on top of the decoded pixels, then send it to the display. No flickering. If you try to draw text on the display AFTER transmitting the GIF pixels, you'll see the flicker.

so will have to try this solution or try to properly implement a double buffer.

mrcodetastic commented 1 year ago

Zip up your project / sketch and I'll take a look if I get a moment to look at it if you can't figure it out.

mzashh commented 1 year ago

Sure, appreciate it.

Here ya go test_firmware.zip

wydmynd commented 8 months ago

Hi, I am using the Aurora demo, managed to "brute force" the text overlay by shoving print commands in the drawFrame function. apparently it works well for some effects, but flickers for others.

void ShowFrame() {
    //#if (FASTLED_VERSION >= 3001000)
    //      nblendPaletteTowardPalette(currentPalette, targetPalette, 24);
    //#else
    currentPalette = targetPalette;
    //#endif

    //  backgroundLayer.swapBuffers();
    // leds = (CRGB*) backgroundLayer.backBuffer();
    // LEDS.countFPS();

    for (int y = 0; y < MATRIX_HEIGHT; ++y) {
      for (int x = 0; x < MATRIX_WIDTH; ++x) {
        //Serial.printf("Flushing x, y coord %d, %d\n", x, y);
        uint16_t _pixel = XY16(x, y);
        dma_display->drawPixelRGB888(x, y, leds[_pixel].r, leds[_pixel].g, leds[_pixel].b);
      }  // end loop to copy fast led to the dma matrix
    }

    dma_display->setTextSize(2);              // size 1 == 8 pixels high
    dma_display->setCursor(10, text_height);  // start at top left, with 8 pixel of spacing
    dma_display->setTextColor(dma_display->color444(15, 15, 15));
    dma_display->print("ICST");
    dma_display->setTextSize(1);                   // size 1 == 8 pixels high
    dma_display->setCursor(12, text_height + 25);  // start at top left, with 8 pixel of spacing
    dma_display->print("Taub CS");
  }