Open Beersatron opened 6 years ago
Just do a nested loop and call SetPixel(). There is no SetImage() functionality in C++ as the API does not want to impose a particular way how you store the image. The SetImage() functionality in Python is only there because Python is so slow that calling SetPixel() in a loop would be too terrible there.
I have never set eyes on c++ until I stumbled across this fantastic library a months ago ... so with that in mind, what rookie mistakes am I doing with this? It works (see attached picture) but I feel like it is sub-optimal as I have read other posts talking about "buffers" etc.
Also, and this is only important for this test, how to a define the "led-slowdown-gpio" default? I presume it is not part of RGBMatrix, instead it is GPIO?
#include "led-matrix.h"
#include "pixel-mapper.h"
#include <Magick++.h>
#include <iostream>
#include <signal.h>
using namespace Magick;
using namespace std;
using rgb_matrix::GPIO;
using rgb_matrix::RGBMatrix;
using rgb_matrix::Canvas;
volatile bool interrupt_received = false;
static void InterruptHandler(int signo) {
interrupt_received = true;
}
int main(int argc, char **argv) {
RGBMatrix::Options defaults;
//--led-pixel-mapper=""U-mapper"" --led-rows=32 --led-cols=64 --led-chain=6 --led-parallel=2 --led-slowdown-gpio=2 --led-no-hardware-pulse
defaults.pixel_mapper_config = "U-mapper";
defaults.rows = 32;
defaults.cols = 64;
defaults.chain_length = 6;
defaults.parallel = 2;
//GPIO::Options defaults;
//defaults.gpio_slowdown = 2;
RGBMatrix *matrix = rgb_matrix::CreateMatrixFromFlags(&argc, &argv, &defaults);
signal(SIGTERM, InterruptHandler);
signal(SIGINT, InterruptHandler);
while (!interrupt_received) {
try {
InitializeMagick(*argv);
//Team 1 Logo
Image img_t1("/home/pi/Desktop/Houston-square-32.png");
int nx_t1 = img_t1.columns();
int ny_t1 = img_t1.rows();
for (int i = 0; i < ny_t1; ++i) {
for (int j = 0; j < nx_t1; ++j) {
ColorRGB rgb(img_t1.pixelColor(i, j));
matrix->SetPixel(i, j, ScaleQuantumToChar(rgb.redQuantum()),
ScaleQuantumToChar(rgb.greenQuantum()),
ScaleQuantumToChar(rgb.blueQuantum()));
}
}
//Team 2 logo
//offset it to other panel
Image img_t2("/home/pi/Desktop/BatonRouge-square-32.png");
int nx_t2 = img_t2.columns();
int ny_t2 = img_t2.rows();
for (int a = 0; a < ny_t2; ++a) {
for (int b = 0; b < nx_t2; ++b) {
ColorRGB rgb(img_t2.pixelColor(a, b));
matrix->SetPixel(a+32, b, ScaleQuantumToChar(rgb.redQuantum()),
ScaleQuantumToChar(rgb.greenQuantum()),
ScaleQuantumToChar(rgb.blueQuantum()));
}
}
}
catch ( Magick::Exception & error) {
cerr << "Caught Magick++ exception: " << error.what() << endl;
}
}
matrix->Clear();
delete matrix;
return 0;
}
I worked on this until 2am last night and just before going to bed I wrote a reply asking for thoughts on why the following color issues would happen when I combining the above Magick example with my existing scoreboard code. Unfortunately I only hit "Preview" and forgot to hit "Comment" so I have lost my original train of thought and since I am at work do not have my complete code to paste - I do have the pics though.
Could there be a conflict between eixisting "Color" objects and something in Magick? When doing MAKE on scoreboard.cc I include Magick and it was initialing complaining about existing "Color" declarations, which I fixed by prefixing with "RGBMatrix::".
I will post my full code when I get home from work, but was hoping somebody might have insights before then.
Thanks!
You have to convert the color of whatever ImageMagic is using into RGB the matrix uses; the ScaleQuantumToChar() looks like the right thing - it converts whatever rgb internal representation is in Magick to uint8_t If the original image has transparent pixels, I think you need to test for that separately and don't set these pixel. IIRC, ImageMagick might just return random values. Look at the relevant code in the led-image-viewer.cc where it looks at alphaQuantum()
for (size_t y = 0; y < img.rows(); ++y) {
for (size_t x = 0; x < img.columns(); ++x) {
const Magick::Color &c = img.pixelColor(x, y);
if (c.alphaQuantum() < 256) {
scratch->SetPixel(x + x_offset, y + y_offset,
ScaleQuantumToChar(c.redQuantum()),
ScaleQuantumToChar(c.greenQuantum()),
ScaleQuantumToChar(c.blueQuantum()));
}
}
}
For reference, this is the code (originally based on the clock example):
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
// Example of a clock. This is very similar to the text-example,
// except that it shows the time :)
//
// This code is public domain
// (but note, that the led-matrix library this depends on is GPL v2)
#include "led-matrix.h"
#include "graphics.h"
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <iostream>
#include <Magick++.h>
#include <fstream>
using namespace Magick;
using namespace rgb_matrix;
using namespace std;
volatile bool interrupt_received = false;
static void InterruptHandler(int signo) {
interrupt_received = true;
}
static int usage(const char *progname) {
fprintf(stderr, "usage: %s [options]\n", progname);
fprintf(stderr, "Reads text from stdin and displays it. "
"Empty string: clear screen\n");
fprintf(stderr, "Options:\n");
rgb_matrix::PrintMatrixFlags(stderr);
fprintf(stderr,
"\t-d <time-format> : Default '%%H:%%M:%%S'. See strftime()\n"
"\t-f <font-file> : Use given font.\n"
"\t-b <brightness> : Sets brightness percent. Default: 100.\n"
"\t-x <x-origin> : X-Origin of displaying text (Default: 0)\n"
"\t-y <y-origin> : Y-Origin of displaying text (Default: 0)\n"
"\t-S <spacing> : Spacing pixels between letters (Default: 0)\n"
"\t-C <r,g,b> : Color. Default 255,255,0\n"
"\t-B <r,g,b> : Background-Color. Default 0,0,0\n"
"\t-O <r,g,b> : Outline-Color, e.g. to increase contrast.\n"
);
return 1;
}
static bool parseColor(rgb_matrix::Color *c, const char *str) {
return sscanf(str, "%hhu,%hhu,%hhu", &c->r, &c->g, &c->b) == 3;
}
static bool FullSaturation(const rgb_matrix::Color &c) {
return (c.r == 0 || c.r == 255)
&& (c.g == 0 || c.g == 255)
&& (c.b == 0 || c.b == 255);
}
int main(int argc, char *argv[]) {
RGBMatrix::Options matrix_options;
rgb_matrix::RuntimeOptions runtime_opt;
if (!rgb_matrix::ParseOptionsFromFlags(&argc, &argv,
&matrix_options, &runtime_opt)) {
return usage(argv[0]);
}
const char *time_format = "%H:%M:%S";
rgb_matrix::Color color(255, 255, 0);
rgb_matrix::Color bg_color(0, 0, 0);
rgb_matrix::Color outline_color(0,0,0);
bool with_outline = false;
const char *bdf_font_file = NULL;
int brightness = 100;
int letter_spacing = 0;
int opt;
while ((opt = getopt(argc, argv, "x:y:f:C:B:O:b:S:d:")) != -1) {
switch (opt) {
case 'd': time_format = strdup(optarg); break;
case 'b': brightness = atoi(optarg); break;
case 'f': bdf_font_file = strdup(optarg); break;
case 'S': letter_spacing = atoi(optarg); break;
case 'C':
if (!parseColor(&color, optarg)) {
fprintf(stderr, "Invalid color spec: %s\n", optarg);
return usage(argv[0]);
}
break;
case 'B':
if (!parseColor(&bg_color, optarg)) {
fprintf(stderr, "Invalid background color spec: %s\n", optarg);
return usage(argv[0]);
}
break;
case 'O':
if (!parseColor(&outline_color, optarg)) {
fprintf(stderr, "Invalid outline color spec: %s\n", optarg);
return usage(argv[0]);
}
with_outline = true;
break;
default:
return usage(argv[0]);
}
}
if (bdf_font_file == NULL) {
fprintf(stderr, "Need to specify BDF font-file with -f\n");
return usage(argv[0]);
}
/*
* Load font. This needs to be a filename with a bdf bitmap font.
*/
rgb_matrix::Font font;
if (!font.LoadFont(bdf_font_file)) {
fprintf(stderr, "Couldn't load font '%s'\n", bdf_font_file);
return 1;
}
rgb_matrix::Font *outline_font = NULL;
if (with_outline) {
outline_font = font.CreateOutlineFont();
}
if (brightness < 1 || brightness > 100) {
fprintf(stderr, "Brightness is outside usable range.\n");
return 1;
}
RGBMatrix *matrix = rgb_matrix::CreateMatrixFromOptions(matrix_options,
runtime_opt);
if (matrix == NULL)
return 1;
matrix->SetBrightness(brightness);
const bool all_extreme_colors = (brightness == 100)
&& FullSaturation(color)
&& FullSaturation(bg_color)
&& FullSaturation(outline_color);
if (all_extreme_colors)
matrix->SetPWMBits(1);
FrameCanvas *offscreen = matrix->CreateFrameCanvas();
char teamOneName[8];
char teamTwoName[8];
char thePeriod[4];
char thePeriodType[4];
int startSeconds;
startSeconds = 0;
char text_buffer[256];
char debugOutput[256];
int teamOneGoals, teamOneBehinds;
char teamOneScore[256];
int teamTwoGoals, teamTwoBehinds;
char teamTwoScore[256];
time_t start;
time_t now;
time_t timePaused;
time_t timeResumed;
struct tm tm;
int elapsedseconds, seconds, minutes, pausedSeconds, totalPausedSeconds, pausedByWebsite;
pausedSeconds = 0;
totalPausedSeconds = 0;
pausedByWebsite = 0;
bool paused;
paused = false;
// used by the web interface to break out of the while loop and clear/delete the MATRIX
int killedByWebsite;
killedByWebsite = 0;
start = time(NULL);
signal(SIGTERM, InterruptHandler);
signal(SIGINT, InterruptHandler);
while (!interrupt_received) {
if (paused == true) {
pausedSeconds = difftime(now,timePaused);
}
now = time(NULL);
elapsedseconds = difftime(now,start) + startSeconds - totalPausedSeconds - pausedSeconds;
seconds = int(elapsedseconds%60);
minutes = int(elapsedseconds/60);
sprintf(text_buffer, "%02d:%02d", minutes, seconds);
offscreen->Fill(bg_color.r, bg_color.g, bg_color.b);
if (outline_font) {
rgb_matrix::DrawText(offscreen, *outline_font,
70 - 1, 38 + font.baseline(),
outline_color, NULL, text_buffer,
letter_spacing - 2);
}
//stopwatch
rgb_matrix::DrawText(offscreen, font, 70, 38 + font.baseline(),
color, NULL, text_buffer,
letter_spacing);
//team one
std::ifstream t1nInFile("/var/www/html/scoreboard/variables/t1n.txt");
t1nInFile.getline(teamOneName,8);
rgb_matrix::DrawText(offscreen, font, 0, 69 + font.baseline(),
color, NULL, teamOneName,
letter_spacing);
//team one score
std::ifstream t1gInFile("/var/www/html/scoreboard/variables/t1g.txt");
t1gInFile>>teamOneGoals;
std::ifstream t1bInFile("/var/www/html/scoreboard/variables/t1b.txt");
t1bInFile>>teamOneBehinds;
sprintf(teamOneScore, "%02d %02d %03d", teamOneGoals, teamOneBehinds, teamOneGoals*6 + teamOneBehinds);
rgb_matrix::DrawText(offscreen, font, 0, 101 + font.baseline(),
color, NULL, teamOneScore,
letter_spacing);
//team two
std::ifstream t2nInFile("/var/www/html/scoreboard/variables/t2n.txt");
t2nInFile.getline(teamTwoName,8);
rgb_matrix::DrawText(offscreen, font, 118, 69 + font.baseline(),
color, NULL, teamTwoName,
letter_spacing);
//team score
std::ifstream t2gInFile("/var/www/html/scoreboard/variables/t2g.txt");
t2gInFile>>teamTwoGoals;
std::ifstream t2bInFile("/var/www/html/scoreboard/variables/t2b.txt");
t2bInFile>>teamTwoBehinds;
sprintf(teamTwoScore, "%02d %02d %03d", teamTwoGoals, teamTwoBehinds, teamTwoGoals*6 + teamTwoBehinds);
rgb_matrix::DrawText(offscreen, font, 102, 101 + font.baseline(),
color, NULL, teamTwoScore,
letter_spacing);
//period (QTR or HLF)
std::ifstream pInFile("/var/www/html/scoreboard/variables/p.txt");
pInFile.getline(thePeriod,4);
rgb_matrix::DrawText(offscreen, font, 66, 6 + font.baseline(),
color, NULL, thePeriod,
letter_spacing);
std::ifstream ptInFile("/var/www/html/scoreboard/variables/pt.txt");
ptInFile.getline(thePeriodType,4);
rgb_matrix::DrawText(offscreen, font, 98, 6 + font.baseline(),
color, NULL, thePeriodType,
letter_spacing);
// logos
InitializeMagick(*argv);
//Team 1 Logo
Image img_t1("/home/pi/Desktop/Houston-square-64.png");
int nx_t1 = img_t1.columns();
int ny_t1 = img_t1.rows();
for (int i = 0; i < ny_t1; ++i) {
for (int j = 0; j < nx_t1; ++j) {
ColorRGB rgb(img_t1.pixelColor(i, j));
matrix->SetPixel(i, j, ScaleQuantumToChar(rgb.redQuantum()),
ScaleQuantumToChar(rgb.greenQuantum()),
ScaleQuantumToChar(rgb.blueQuantum()));
}
}
//Team 2 logo
//offset it to other panel
Image img_t2("/home/pi/Desktop/BatonRouge-square-64.png");
int nx_t2 = img_t2.columns();
int ny_t2 = img_t2.rows();
for (int a = 0; a < ny_t2; ++a) {
for (int b = 0; b < nx_t2; ++b) {
ColorRGB rgb(img_t2.pixelColor(a, b));
matrix->SetPixel(a+128, b, ScaleQuantumToChar(rgb.redQuantum()),
ScaleQuantumToChar(rgb.greenQuantum()),
ScaleQuantumToChar(rgb.blueQuantum()));
}
}
// Atomic swap with double buffer
offscreen = matrix->SwapOnVSync(offscreen);
std::ifstream pauseInFile("/var/www/html/scoreboard/variables/pause.txt");
pauseInFile>>pausedByWebsite;
if (pausedByWebsite == 1 && paused == false) {
paused = true;
timePaused = time(NULL);
localtime_r(&timePaused, &tm);
strftime(debugOutput, sizeof(debugOutput), time_format, &tm);
cout << "Paused @ " << debugOutput << endl;
}
if (pausedByWebsite == 0 && paused == true) {
paused = false;
timeResumed = time(NULL);
localtime_r(&timeResumed, &tm);
strftime(debugOutput, sizeof(debugOutput), time_format, &tm);
cout << "Resumed @ " << debugOutput << endl;
totalPausedSeconds = pausedSeconds + totalPausedSeconds;
pausedSeconds = 0;
}
std::ifstream killInFile("/var/www/html/scoreboard/variables/kill.txt");
killInFile>>killedByWebsite;
if (killedByWebsite != 0) {
break;
}
}
// Finished. Shut down the RGB matrix.
matrix->Clear();
delete matrix;
write(STDOUT_FILENO, "\n", 1); // Create a fresh new line after ^C on screen
return 0;
}
You want to remove the
const bool all_extreme_colors = (brightness == 100)
&& FullSaturation(color)
&& FullSaturation(bg_color)
&& FullSaturation(outline_color);
if (all_extreme_colors)
matrix->SetPWMBits(1);
part, as you don't want to 1-bit PWM (i.e. 8 colors).
Thanks! That fixed the colors. The flickering is pretty bad, but I suspect a large part of that is with me running Jessie with GUI. Plus, I am pretty sure my code is not optimal in any way.
Short video: https://photos.app.goo.gl/ut2oKTUspaboxFE47
--led-show-refresh has it hovering around 100/120 Hz with some dips to 80 Hz (likely Jessie background processes) and a max of 47132 usec after a couple of minutes runtime.
I might order a RPi 3b and load up Raspian Lite to see what the extra oomph and reduced background noise can poduce - but that may be a few weeks from now.
I moved all of this out of the while loop, since the logo will "probably" not change during the game that the scoreboard will be tracking. It seems to have improved the refresh to average of 140 Hz with max of 18794 usec.
InitializeMagick(*argv);
Image img_t1("/home/pi/Desktop/Houston-square-64.png");
int nx_t1 = img_t1.columns();
int ny_t1 = img_t1.rows();
Image img_t2("/home/pi/Desktop/BatonRouge-square-64.png");
int nx_t2 = img_t2.columns();
int ny_t2 = img_t2.rows();
I am thinking that maybe I should create a new object/class to hold the image pixel array so I can remove the call to "ColorRGB rgb(img_t1.pixelColor(i, j));" and also the ScaleQuantumToChar and redQuantum() invocations. Being new to c++ though, I don't know if that will produce a noticeable performance boost?
for (int i = 0; i < ny_t1; ++i) {
for (int j = 0; j < nx_t1; ++j) {
ColorRGB rgb(img_t1.pixelColor(i, j));
matrix->SetPixel(i, j, ScaleQuantumToChar(rgb.redQuantum()),
ScaleQuantumToChar(rgb.greenQuantum()),
ScaleQuantumToChar(rgb.blueQuantum()));
}
}
Maybe something like this? I have no idea if this is valid syntax.
Before the while loop:
for (int i = 0; i < ny_t1; ++i) {
for (int j = 0; j < nx_t1; ++j) {
ColorRGB rgb(img_t1.pixelColor(i, j));
pixelColorArray[i][j].red = ScaleQuantumToChar(rgb.redQuantum();
pixelColorArray[i][j].green = ScaleQuantumToChar(rgb.greenQuantum());
pixelColorArray[i][j].blue = ScaleQuantumToChar(rgb.blueQuantum());
}
}
In the while loop
for (int i = 0; i < ny_t1; ++i) {
for (int j = 0; j < nx_t1; ++j) {
matrix->SetPixel(i, j,
pixelColorArray[i][j].red,
pixelColorArray[i][j].green,
pixelColorArray[i][j].blue);
}
}
if you have it pre-generated, it will be much faster, yes, as the ImageMagick stuff is actually quite slow to access.
You can also pre-generate a bunch of FrameCanvas beforehand and then swap them out with SwapOnVSync()
I am using SwapOnVSync() for the text/numbers on the scoreboard but for some reason I was using SetPixel on "matrix" for the logos, instead of "offscreen"
//Team 1 Logo
for (int i = 0; i < ny_t1; ++i) {
for (int j = 0; j < nx_t1; ++j) {
ColorRGB rgb(img_t1.pixelColor(i, j));
matrix->SetPixel(i, j,
ScaleQuantumToChar(rgb.redQuantum()),
ScaleQuantumToChar(rgb.greenQuantum()),
ScaleQuantumToChar(rgb.blueQuantum()));
}
}
Fixed:
//Team 1 Logo
for (int i = 0; i < ny_t1; ++i) {
for (int j = 0; j < nx_t1; ++j) {
ColorRGB rgb(img_t1.pixelColor(i, j));
offscreen->SetPixel(i, j,
ScaleQuantumToChar(rgb.redQuantum()),
ScaleQuantumToChar(rgb.greenQuantum()),
ScaleQuantumToChar(rgb.blueQuantum()));
}
}
The logos are now displaying a lot better/clearer! I still get flickering, but like I said before, that might clear up if I went with a headless Pi and a LITE OS.
I tried increasing "--led-slowdown-gpio=2" to 3 or 4 but it doesn't seem to be used?
The slowdown gpio only make a difference if you see noise in your output, as it is mostly if the LED panels are too slow. In fact, you should set it to the lowest value that still produces a good image -- that way the panels are operated fastest.
The refresh rate you can see on the terminal if you specify --led-show-refresh
; if it gets below 200Hz, it is possible to see flicker if you move your head quickly.
I see in one of your earlier code posts that you use 2 parallel chains with 6 panels each, which might already create borderline flickery images. I would actually use three chains with only four panels each (but then you have to write your own custom pixel mapper which might be too much effort). It doesn't cost any extra CPU to run panels in parallel. Longer chains however require to shift in a long string of data which is limited by the panel and GPIO speed.
You can do a dry-run to estimate if it will be worthwhile: with the led-show-refresh option on how the speed changes comparing --led-chain=6
and --led-chain=4
.
You can play modify the refresh rate with various options (see detailed description in the README). In particular slightly reducing --led-pwm-bits
while the colors still look good (in your ealier experiments, you had it at --led-pwm-bits=1
, which didn't look good anymore :) ). Also --led-pwm-dither-bits
might result in a slight improvement in refresh rate.
If you have slight regular flickers, see the troubleshooting section.
Also make sure to set the isolcpus=3
setting if you haven't already.
Good luck!
I have enabled isolcpus=3 but am not sure what I can do to confirm that it is working? Is there a specific command that lists what is on each CPU?
I did a make clean
and then updated DFIXED_FRAME_MICROSECONDS
to be 16000, which is high but improves the flickering considerably .. while reducing the refresh to a little over 60hz. My wife says it looks cool though, so who am I to argue with that?
Before doing that, I did change to --led-pwm-lsb-nanoseconds=90 --led-pwm-bits=7
which kind of helped a bit.
Would cable length have an effect? I am using short IDC cables between panels but only had access to 100cm IDC cables for the RPi to panel connections and then the "loops". I should probably get some shorter cables.
Reference that helped me: #483
I am triggering the program by calling a py file that does:
directory = "/home/pi/rpi-rgb-led-matrix/examples-api-use/"
os.system("sudo " + directory + "scoreboard -f /home/pi/rpi-rgb-led-matrix/fonts/10x20.bdf --led-pwm-lsb-nanoseconds=90 --led-pwm-bits=7 --led-show-refresh --led-pixel-mapper=""U-mapper"" --led-rows=32 --led-cols=64 --led-chain=6 --led-parallel=2 --led-slowdown-gpio=2")
I saw in another post that you mention python garbage collection can be an issue, should I stop using this method of invocation whilst testing? My long term goal is to have PHP trigger the scoreboard.
if you run top
you see the process usage of each process. If you now press the key 1
, you see a list of the load of each CPU-core. The Raspberry Pi 3 has four cores, so you see four of these.
If the matrix is not running, you see occasional load on the first three, but the last one is essentially not doing anything, because you isolated it with isolcpus=3. When you run the matrix, you see that the last core is under load to update things.
The cable length will not influence the frequency, but it might influence the maximum speed you can run at. So maybe a shorter cable would allow slowdown-gpio=1 (might not be wothwhile).
If you have to go to fixed frame microseconds to 16000 something is seriously bogging down your system. The worst case I have seen so far was maybe 5000. So it is crucial, that you get a headless system (don't forget to create an empty file ssh
in the boot partition so that you can log-in via the network).
I would probably not start and stop the LED matrix via Python or PHP, because it will cause flicker whenever you stop or restart it. Instead, I'd run it continuously and receive commands via a pipe or socket (I presume that you want to change the score-display or show the scoring teams' logo briefly in large when they score or something). Then have your PHP program send these commands to the local matrix for update.
Depending on how comfortable you are with C++, using libmicrohttpd might be even simpler, as you then can have everything in one single program.
For anybody interested in my progress, I am working on the frame for my scoreboard before I order a new RPi and configure it for headless use. We have a Metro game this Sunday and then our last Home game next Saturday and I didn't want to throw in too many extra variables until I tested things out.
Testing settings for our Metro (Red vs Blue) - short video.
Pics of the frame being built:
The pre-punched holes line up about 75% of the time, a simple metal file enlarges on the holes as needed.
@hzeller I got a new RPi 3B+ and flashed it with Stretch Lite, then disabled sound. I haven't done any other tweaks yet, like disabling bluetooth or reserving one of the cores. Below is video from the new RPi, it was showing ~144hz and I think 9600usec.
Video: https://photos.app.goo.gl/7P8fmE2pgy3i9kVv6
This is a marked improvement from the full Jessie that was on the RPi 3B that was barely running at 60hz after heavy tweaking. I couldn't even get the display to show on pictures or videos because the camera was too good!
I am trying to display an image (32x32 team logo) to the left of each teams stats on a setup that is 192x128. So there would be one logo at 0x0 and then another at 0x32.
I see that there is a SetImage() for Python but I do not see a similar function in the original c++ code? I have compiled and ran the led-image-viewer but that is a standalone function, right? Plus, it stretches the 32x32 logo onto the 192x128 setup.
I would appreciate a pointer in the right direction for implementing something myself. But if I have missed something obvious that has already been implemented, then I would gladly take that too :)
Code snippet from my scoreboard.cc that reads in the name of Team One and Team Two:
//team one std::ifstream t1nInFile("variables/t1n.txt"); t1nInFile.getline(teamOneName,4); rgb_matrix::DrawText(offscreen, font, 33, 0 + font.baseline(), color, NULL, teamOneName, letter_spacing);
//team two std::ifstream t2nInFile("variables/t2n.txt"); t2nInFile.getline(teamTwoName,4); rgb_matrix::DrawText(offscreen, font, 33, 33 + font.baseline(), color, NULL, teamTwoName, letter_spacing);