Skip to content
Permalink
Browse files

Factored out all common code to Framebuffer::GFX.

  • Loading branch information...
marcmerlin committed May 26, 2019
1 parent 48172cc commit bfcc75bb805d835ed39ec6e6b742d3d596b0c313
Showing with 5 additions and 428 deletions.
  1. +1 −1 README.md
  2. +1 −248 SmartMatrix_GFX.cpp
  3. +2 −94 SmartMatrix_GFX.h
  4. +1 −1 examples/FastLED_NeoMatrix_SmartMatrix_LEDMatrix_GFX_Demos
  5. +0 −54 extras/gamma.c
  6. +0 −30 gamma.h
@@ -166,6 +166,6 @@ so you don't need level shifters.
shield that includes level shifters: https://docs.pixelmatix.com/SmartMatrix/shieldref.html

- If you are using ESP32, you can use SmartMatrx/SmartMatrix::GFX or ESP32-RGB64x32MatrixPanel-I2S-DMA . You should then use
this shield to get level shifters: https://www.evilgeniuslabs.org/hexadecimal-nodemcu-32s-wi-fi-and-ble-led-controller . t
this shield to get level shifters: https://www.evilgeniuslabs.org/hexadecimal-nodemcu-32s-wi-fi-and-ble-led-controller . It
does not plug directly into the RGBpanel, but at least you can wire directly to the level shifters and not worry about the
ever changing pin order of the ESP32 chips.
@@ -2,264 +2,17 @@
Arduino library based on Adafruit_Neomatrix but modified to work with SmartMatrix
by Marc MERLIN <marc_soft@merlins.org>
Original notice and license from Adafruit_Neomatrix:
------------------------------------------------------------------------
Arduino library to control single and tiled matrices of WS2811- and
WS2812-based RGB LED devices such as the Adafruit NeoPixel Shield or
displays assembled from NeoPixel strips, making them compatible with
the Adafruit_GFX graphics library. Requires both the FastLED_NeoPixel
and Adafruit_GFX libraries.
Written by Phil Burgess / Paint Your Dragon for Adafruit Industries.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing products
from Adafruit!
-------------------------------------------------------------------------
This file is part of the Adafruit NeoMatrix library.
NeoMatrix is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoMatrix is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoMatrix. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/

#include <Adafruit_GFX.h>
#include <SmartMatrix_GFX.h>
#include "gamma.h"
#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP8266)
#include <pgmspace.h>
#else
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#endif

#ifndef _swap_uint16_t
#define _swap_uint16_t(a, b) { uint16_t t = a; a = b; b = t; }
#endif


#include "FastLED.h"

SmartMatrix_GFX::SmartMatrix_GFX(CRGB *leds, uint8_t w, uint8_t h, void (* showptr)()):
Adafruit_GFX(w, h),
type(0), matrixWidth(w), matrixHeight(h), tilesX(0), tilesY(0), remapFn(NULL){
_leds = leds;
_show = showptr;
// WARNING: Serial.print seems to crash in the constructor,
// but works in begin()
numpix = matrixWidth * matrixHeight;
}

void SmartMatrix_GFX::begin() {
Serial.print("Num Pixels: ");
Serial.println(numpix);
}

void SmartMatrix_GFX::newLedsPtr(CRGB *new_leds_ptr) {
_leds = new_leds_ptr;
}

// Expand 16-bit input color (Adafruit_GFX colorspace) to 24-bit (NeoPixel)
// (w/gamma adjustment)
static uint32_t expandColor(uint16_t color) {
return ((uint32_t)pgm_read_byte(&gamma5[ color >> 11 ]) << 16) |
((uint32_t)pgm_read_byte(&gamma6[(color >> 5) & 0x3F]) << 8) |
pgm_read_byte(&gamma5[ color & 0x1F]);
}

// Downgrade 24-bit color to 16-bit (add reverse gamma lookup here?)
uint16_t SmartMatrix_GFX::Color(uint8_t r, uint8_t g, uint8_t b) {
return ((uint16_t)(r & 0xF8) << 8) |
((uint16_t)(g & 0xFC) << 3) |
(b >> 3);
Framebuffer_GFX(leds, w, h, showptr) {
}

// Pass-through is a kludge that lets you override the current drawing
// color with a 'raw' RGB (or RGBW) value that's issued directly to
// pixel(s), side-stepping the 16-bit color limitation of Adafruit_GFX.
// This is not without some limitations of its own -- for example, it
// won't work in conjunction with the background color feature when
// drawing text or bitmaps (you'll just get a solid rect of color),
// only 'transparent' text/bitmaps. Also, no gamma correction.
// Remember to UNSET the passthrough color immediately when done with
// it (call with no value)!

// Pass raw color value to set/enable passthrough
void SmartMatrix_GFX::setPassThruColor(CRGB c) {
passThruColor = c.r*65536+c.g*256+c.b;
passThruFlag = true;
}

void SmartMatrix_GFX::setPassThruColor(uint32_t c) {
passThruColor = c;
passThruFlag = true;
}

// Call without a value to reset (disable passthrough)
void SmartMatrix_GFX::setPassThruColor(void) {
passThruFlag = false;
}

int SmartMatrix_GFX::XY(int16_t x, int16_t y) {

// If you send an out of bounds value, you get an special result
// pointing to the last pixel. It doesn't look great, but better
// than crashing. Still, fix the upstream code.
// DrawPixel is able to reject the write, but here we have to return an index
// which has to be inbounds.
if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return numpix-1;

int16_t t;
switch(rotation) {
case 1:
t = x;
x = WIDTH - 1 - y;
y = t;
break;
case 2:
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
break;
case 3:
t = x;
x = y;
y = HEIGHT - 1 - t;
break;
}

int tileOffset = 0, pixelOffset;

if(remapFn) { // Custom X/Y remapping function
pixelOffset = (*remapFn)(x, y);
} else { // Standard single matrix or tiled matrices

uint8_t corner = type & NEO_MATRIX_CORNER;
uint16_t minor, major, majorScale;

if(tilesX) { // Tiled display, multiple matrices
uint16_t tile;

minor = x / matrixWidth; // Tile # X/Y; presume row major to
major = y / matrixHeight, // start (will swap later if needed)
x = x - (minor * matrixWidth); // Pixel X/Y within tile
y = y - (major * matrixHeight); // (-* is less math than modulo)

// Determine corner of entry, flip axes if needed
if(type & NEO_TILE_RIGHT) minor = tilesX - 1 - minor;
if(type & NEO_TILE_BOTTOM) major = tilesY - 1 - major;

// Determine actual major axis of tiling
if((type & NEO_TILE_AXIS) == NEO_TILE_ROWS) {
majorScale = tilesX;
} else {
_swap_uint16_t(major, minor);
majorScale = tilesY;
}

// Determine tile number
if((type & NEO_TILE_SEQUENCE) == NEO_TILE_PROGRESSIVE) {
// All tiles in same order
tile = major * majorScale + minor;
} else {
// Zigzag; alternate rows change direction. On these rows,
// this also flips the starting corner of the matrix for the
// pixel math later.
if(major & 1) {
corner ^= NEO_MATRIX_CORNER;
tile = (major + 1) * majorScale - 1 - minor;
} else {
tile = major * majorScale + minor;
}
}

// Index of first pixel in tile
tileOffset = tile * matrixWidth * matrixHeight;

} // else no tiling (handle as single tile)

// Find pixel number within tile
minor = x; // Presume row major to start (will swap later if needed)
major = y;

// Determine corner of entry, flip axes if needed
if(corner & NEO_MATRIX_RIGHT) minor = matrixWidth - 1 - minor;
if(corner & NEO_MATRIX_BOTTOM) major = matrixHeight - 1 - major;

// Determine actual major axis of matrix
if((type & NEO_MATRIX_AXIS) == NEO_MATRIX_ROWS) {
majorScale = matrixWidth;
} else {
_swap_uint16_t(major, minor);
majorScale = matrixHeight;
}

// Determine pixel number within tile/matrix
if((type & NEO_MATRIX_SEQUENCE) == NEO_MATRIX_PROGRESSIVE) {
// All lines in same order
pixelOffset = major * majorScale + minor;
} else {
// Zigzag; alternate rows change direction.
if(major & 1) pixelOffset = (major + 1) * majorScale - 1 - minor;
else pixelOffset = major * majorScale + minor;
}
}

return(tileOffset + pixelOffset);
}

void SmartMatrix_GFX::drawPixel(int16_t x, int16_t y, uint16_t color) {

if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

_leds[XY(x,y)] = passThruFlag ? passThruColor : expandColor(color);
}

void SmartMatrix_GFX::drawPixel(int16_t x, int16_t y, uint32_t color) {

if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

_leds[XY(x,y)] = color;
}

void SmartMatrix_GFX::drawPixel(int16_t x, int16_t y, CRGB c) {

if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

_leds[XY(x,y)] = c.r*65536+c.g*256+c.b;
}


void SmartMatrix_GFX::fillScreen(uint16_t color) {
uint32_t c;

c = passThruFlag ? passThruColor : expandColor(color);
for (uint16_t i=0; i<numpix; i++) { _leds[i]=c; }
}

void SmartMatrix_GFX::setRemapFunction(uint16_t (*fn)(uint16_t, uint16_t)) {
remapFn = fn;
}

// After setting gamma, this is used with
// CRGB color = CRGB(matrix->gamma[red], matrix->gamma[green], matrix->gamma[blue]);
void SmartMatrix_GFX::precal_gamma(float gam) {
for (uint8_t i =0; i<255; i++) {
gamma[i] = applyGamma_video(i, gam);
}
}

// vim:sts=2:sw=2
@@ -20,105 +20,13 @@

#ifndef _SMARTMATRIX_GFX_H_
#define _SMARTMATRIX_GFX_H_

#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#include <pins_arduino.h>
#endif
#include <Adafruit_GFX.h>
// Ideally this lib wouldn't require FastLED, but in order to be compatible
// with FastLED Matrix code, it's much easier to just use its CRGB definition
#include "Framebuffer_GFX.h"
#include "FastLED.h"

// Matrix layout information is passed in the 'matrixType' parameter for
// each constructor (the parameter immediately following is the LED type
// from NeoPixel.h).

// These define the layout for a single 'unified' matrix (e.g. one made
// from NeoPixel strips, or a single NeoPixel shield), or for the pixels
// within each matrix of a tiled display (e.g. multiple NeoPixel shields).

#define NEO_MATRIX_TOP 0x00 // Pixel 0 is at top of matrix
#define NEO_MATRIX_BOTTOM 0x01 // Pixel 0 is at bottom of matrix
#define NEO_MATRIX_LEFT 0x00 // Pixel 0 is at left of matrix
#define NEO_MATRIX_RIGHT 0x02 // Pixel 0 is at right of matrix
#define NEO_MATRIX_CORNER 0x03 // Bitmask for pixel 0 matrix corner
#define NEO_MATRIX_ROWS 0x00 // Matrix is row major (horizontal)
#define NEO_MATRIX_COLUMNS 0x04 // Matrix is column major (vertical)
#define NEO_MATRIX_AXIS 0x04 // Bitmask for row/column layout
#define NEO_MATRIX_PROGRESSIVE 0x00 // Same pixel order across each line
#define NEO_MATRIX_ZIGZAG 0x08 // Pixel order reverses between lines
#define NEO_MATRIX_SEQUENCE 0x08 // Bitmask for pixel line order

// These apply only to tiled displays (multiple matrices):

#define NEO_TILE_TOP 0x00 // First tile is at top of matrix
#define NEO_TILE_BOTTOM 0x10 // First tile is at bottom of matrix
#define NEO_TILE_LEFT 0x00 // First tile is at left of matrix
#define NEO_TILE_RIGHT 0x20 // First tile is at right of matrix
#define NEO_TILE_CORNER 0x30 // Bitmask for first tile corner
#define NEO_TILE_ROWS 0x00 // Tiles ordered in rows
#define NEO_TILE_COLUMNS 0x40 // Tiles ordered in columns
#define NEO_TILE_AXIS 0x40 // Bitmask for tile H/V orientation
#define NEO_TILE_PROGRESSIVE 0x00 // Same tile order across each line
#define NEO_TILE_ZIGZAG 0x80 // Tile order reverses between lines
#define NEO_TILE_SEQUENCE 0x80 // Bitmask for tile line order

class SmartMatrix_GFX : public Adafruit_GFX {
class SmartMatrix_GFX : public Framebuffer_GFX {

public:
// pre-computed gamma table
uint8_t gamma[256];

SmartMatrix_GFX(CRGB *, uint8_t w, uint8_t h, void (* showptr)());

int XY(int16_t x, int16_t y); // compat with FastLED code, returns 1D offset
void
drawPixel(int16_t x, int16_t y, uint16_t color),
drawPixel(int16_t x, int16_t y, uint32_t color),
drawPixel(int16_t x, int16_t y, CRGB color),
fillScreen(uint16_t color),
setPassThruColor(CRGB c),
setPassThruColor(uint32_t c),
setPassThruColor(void),
setRemapFunction(uint16_t (*fn)(uint16_t, uint16_t)),
precal_gamma(float);

static uint16_t
Color(uint8_t r, uint8_t g, uint8_t b);

void clear() { fillScreen(0); };
void show() { _show(); };

void setBrightness(int b) {
Serial.println("please call matrixLayer.setBrightness() instead");
};


void begin(); // no-op in this lib, left for compat
void newLedsPtr(CRGB *);


private:

// 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 _leds
// into the SmartMatrix object, and pass that function to us by pointer.
void (* _show)();

CRGB *_leds;
const uint8_t
type;
const uint8_t
matrixWidth, matrixHeight, tilesX, tilesY;
uint16_t
numpix,
(*remapFn)(uint16_t x, uint16_t y);

uint32_t passThruColor;
boolean passThruFlag = false;
};

#endif // _SMARTMATRIX_GFX_H_

0 comments on commit bfcc75b

Please sign in to comment.
You can’t perform that action at this time.