Adafruit_GFX Compatible Layers - Modern Font Support coming to SmartMatrix Library 4.0

Adding support for larger fonts has been a popular feature request for years, and I never took on the project as I thought it might be a difficult project. Turns out I was right, but now at least most of the work is done, and you can now run sketches like this using the “teensy4” branch, and this will be coming in the upcoming SmartMatrix Library 4.0 release.

There is now a new SMLayerBackgroundGFX layer (equivalent to SMLayerBackground) and new SMLayerGFXMono layer (equivalent to SMLayerIndexed and SMLayerScrolling combined). Both layers inherit from Adafruit_GFX, so you can use any of the Adafruit_GFX library functions with the new layers. I made both layers backward compatible with the SmartMatrix Library main layer functions, so you should be able to use existing sketches and the new layers with little or no changes. Adafruit_GFX uses uint16_t (equivalent to rgb16 or rgb565) to store colors, which is a downgrade if you’re using rgb24 or rgb48 in SmartMatrix Library to store your colors, so there are wrapper functions in the layers that take the rgb24/48 color, store it while Adafruit_GFX is doing the drawing, and pass it through to the actual drawPixel(rgb24)/drawPixel(rgb48) functions. The layers themselves are overhauled especially the SMLayerGFXMono layer which was rewritten to be much more efficient during refresh.

The examples were updated to show how to use the new layers:

  • Updated example MultipleTextLayers: optionally use Adafruit_GFX layers, improving refresh rate
  • Updated FeatureDemo: add “GFX” layer support option
  • Updated FastLED_Functions: add explicit cast from CRGB to rgb24. With new uint16_t conversions for Adafruit_GFX, the compiler gets confused as to which type we want, even though this sketch doesn’t use the new layers
  • New example Adafruit_GFX: shows how to use Adafruit_GFX functions with the new layers
  • New example MultipleTextLayersGFX: Improved version of MultipleTextLayers, includes Adafruit_GFX fonts (featured in video above)

Backwards Compatibility:

The only change that needs to be made (as of now) is adding explicit casts between FastLED’s CRGB type and rgb24. I’m not sure why this is needed. I merged in some really helpful code from @mrwastl to convert between different rgb types, and this was a side effect. It’s beyond my level of C++ understanding to fix this, but the explicit cast seems to work. See FastLED_Functions for an example.

Testing:

I tested the new code with the above examples on a Teensy 4. I didn’t test Teensy 3 (which I expect to work no problem), and I didn’t test with ESP32. ESP32 could have issues as it uses malloc instead of static allocation of buffers, and I may have made a mistake in the malloc calls. I’d appreciate if you’re using ESP32 if you’d let me know if your sketches are running fine with the latest from teensy4, or if you see any errors.

I tested Adafruit_GFX functions that are included in the Adafruit_GFX sketch (adapted from Adafruit’s own examples), but I don’t think this tests Adafruit_GFX functions 100%. There’s probably some things to fix, please let me know if you run into errors, and include a sample sketch to reproduce it and I’ll try to get a fix done ASAP.

If yo’u’re trying to replace SmartMatrix::GFX by integrating its FastLED+GFX functionality, by all means. I’ll have no problem turning down my code and pointing to yours.
If you were worried about breaking SmartMatrix::GFX, I don’t think it’s much of a worry. I really only use the pointer to your 2 copies of the framebuffer and poke into them directly as they happen to be compatible between SmartMatrix in 24bit mode, and FastLED.

The cast has not been a problem, all I do is this:

Even shorter, it’s really only
matrixleds = (CRGB *)backgroundLayer.backBuffer();

The direct cast works fine since the arrays are compatible.
Once I have a pointer on your array, I take my FastLED CRGB array and point it to that
matrix->newLedsPtr(matrixleds);
which goes there:

I didn’t have to do all the work you did, by defining _fb as an array of CRGB, I get all the FastLED goodness without having to re-write any of it :slight_smile:

Am I missing something?

Ok, if you are trying to do the same thing than me, but have it work with other bit depth than 24bit, then you have to do a fair amount of work. Is that what you’re doing?
If so, I didn’t bother because my existing solution involves so little code, fully reuses the existing code in FastLED and GFX (and updates to it I don’t have to worry about), and 24bpp is the only thing I’ll ever need (at least for storage).
Framebuffer::GFX totally supports downgrading the 24bit framebuffer to a 16bpp display like an LCD, but obviously it can’t go up to 32bits. That said, I have no need for 32bpp on any display. I grew up with 2-4bpp, I was extactic when I got 8bpp, and 24bpp is more than I thought I’d ever need. I feel it’s still true today :slight_smile:

Sure enough, your MatrixGFXDemo sketch works with the new layer with just two lines changed.

There’s really no need for that now, but if I do update the new GFX layers to support rgb8 and rgb16, then I think the best way to integrate Framebuffer::GFX with the GFX layers using non-24 bit color is probably to make the GFX layers compatible with Framebuffer::GFX. I’m not working on that now, so I’m satisfied with the fact that SmartMatrix::GFX still works.

  // Because SmartMatrix uses templates so heavily, its object cannot be passed to us
  // However the main function can create a show function that copies our data from _fb
  // into the SmartMatrix object, and pass that function to us by pointer.
  void (* _show)();

From your comments it seemed like you weren’t happy with the _show() call in SmartMatrix:GFX. I did have to figure out how pass a Layer object to a function to add a randomization feature in the MultipleTextLayersGFX sketch, and it seems like that might work for SmartMatrix:GFX. Here’s that code in case it helps you:

Great to hear the sketch “just works” (after changing the top config bit).

I didn’t love it, I’m not a fan of all the limitations that templates introduce, but I got over it :slight_smile:

interesting, I thought it wasn’t actually possible. I’m not sure if I want to change the interface in an incompatible way, now, Still, worth having a look.

Thanks

Loving the modern font support. It looks great! Is this feature now included in the ESP32 SmartMatrix library?

Yes, it’s on the teensy4 branch which supports ESP32 and is hopefully going to be pushed to the main branch and released later today.

I decided to change the API for GFX layers after @marcmerlin pointed out some issues. It’s now simpler, just define USE_ADAFRUIT_GFX_LAYERS at the top of a sketch, and your sketch is now using the new GFX layers. (Before you had to define SUPPORT_ADAFRUIT_GFX_LIBRARY, and change the ALLOCATE_* macros to ALLOCATE_GFX* macros in your sketch)

I didn’t want to have a breaking API change days after the release of SmartMatrix Library 4.0, but I think Marc’s suggestion was good enough to make the change before more people started using the library.

In the process of making that change, I updated the MultipleTextLayersGfx Example to show some of the issues with using GFX layers (memory allocation is more complex), and added a helper function to help determine how large a Layer needs to be based on the text you want to scroll.

I’ll be adding more details to the documentation in the Wiki as these new layers have some pitfalls, plus they haven’t been tested as much and there’s likely bugs (I found and fixed a couple in the process of doing the above changes)

Cool. Sorry that I didn’t have the time to look at this sooner, and thanks for the quick update.

I started on the Adafruit_GFX section of the documentation here. If you take a look please let me know if you have any feedback or if anything seems missing in this section:

Hey, Louis. Do you have a small tutorial about the steps I need to take to add this extremely cool font support to one of my sketches? I am able to run the MultipleTextLayersGfx sketch with no problems on my ESP32-based setup, but trying to figure out what needs to be included in my own sketch is causing me to realize I’m not as clever as I want to be.

I added #define USE_ADAFRUIT_GFX_LAYERS at the very top of the sketch. I’m assuming I will also need to add something like this:
SMARTMATRIX_ALLOCATE_GFX_MONO_LAYER(scrollingLayer, kMatrixWidth, kMatrixHeight, kMatrixWidth*3, kMatrixHeight, COLOR_DEPTH, kScrollingLayerOptions);

and also this (for example):
#include <Fonts/FreeMonoBoldOblique24pt7b.h>

But, even though I have the proper libraries loaded, it craps out when I compile. I could probably start with your sketch and try to modify it to add all of my own code, but I would rather understand what is needed and what is not.

Just for simplicity’s sake, let’s say I only want support the one font I list above. Can you point me in the right direction, please?

My apologies ahead of time for my ignorance.

I would rather understand what is needed and what is not.

I’d just start with the example sketch and delete it down until you have a minimal sketch using FreeMonoBoldOblique24pt7b. Sorry I don’t have a better answer than that, to answer your question I’d have to go into the example sketch and do the same thing myself.

If you want to ask questions as you’re doing that, or give feedback on how to make it better next time, I’d appreciate it.