Skip to content

Commit e5f311c

Browse files
author
KryQ
committedJul 6, 2020
font width getter
1 parent 420c04f commit e5f311c

File tree

3 files changed

+730
-649
lines changed

3 files changed

+730
-649
lines changed
 

‎include/graphics.h

+131-126
Original file line numberDiff line numberDiff line change
@@ -12,131 +12,136 @@
1212
#include <map>
1313
#include <stdint.h>
1414

15-
namespace rgb_matrix {
16-
struct Color {
17-
Color() : r(0), g(0), b(0) {}
18-
Color(uint8_t rr, uint8_t gg, uint8_t bb) : r(rr), g(gg), b(bb) {}
19-
uint8_t r;
20-
uint8_t g;
21-
uint8_t b;
22-
};
23-
24-
// Font loading bdf files. If this ever becomes more types, just make virtual
25-
// base class.
26-
class Font {
27-
public:
28-
// Initialize font, but it is only usable after LoadFont() has been called.
29-
Font();
30-
~Font();
31-
32-
bool LoadFont(const char *path);
33-
34-
// Return height of font in pixels. Returns -1 if font has not been loaded.
35-
int height() const { return font_height_; }
36-
37-
// Return baseline. Pixels from the topline to the baseline.
38-
int baseline() const { return base_line_; }
39-
40-
// Return width of given character, or -1 if font is not loaded or character
41-
// does not exist.
42-
int CharacterWidth(uint32_t unicode_codepoint) const;
43-
44-
// Draws the unicode character at position "x","y"
45-
// with "color" on "background_color" (background_color can be NULL for
46-
// transparency.
47-
// The "y" position is the baseline of the font.
48-
// If we don't have it in the font, draws the replacement character "�" if
49-
// available.
50-
// Returns how much we advance on the screen, which is the width of the
51-
// character or 0 if we didn't draw any chracter.
52-
int DrawGlyph(Canvas *c, int x, int y,
53-
const Color &color, const Color *background_color,
54-
uint32_t unicode_codepoint) const;
15+
namespace rgb_matrix
16+
{
17+
struct Color
18+
{
19+
Color() : r(0), g(0), b(0) {}
20+
Color(uint8_t rr, uint8_t gg, uint8_t bb) : r(rr), g(gg), b(bb) {}
21+
uint8_t r;
22+
uint8_t g;
23+
uint8_t b;
24+
};
25+
26+
// Font loading bdf files. If this ever becomes more types, just make virtual
27+
// base class.
28+
class Font
29+
{
30+
public:
31+
// Initialize font, but it is only usable after LoadFont() has been called.
32+
Font();
33+
~Font();
34+
35+
bool LoadFont(const char *path);
36+
37+
// Return height of font in pixels. Returns -1 if font has not been loaded.
38+
int height() const { return font_height_; }
39+
int width() const { return font_width_; }
40+
41+
// Return baseline. Pixels from the topline to the baseline.
42+
int baseline() const { return base_line_; }
43+
44+
// Return width of given character, or -1 if font is not loaded or character
45+
// does not exist.
46+
int CharacterWidth(uint32_t unicode_codepoint) const;
47+
48+
// Draws the unicode character at position "x","y"
49+
// with "color" on "background_color" (background_color can be NULL for
50+
// transparency.
51+
// The "y" position is the baseline of the font.
52+
// If we don't have it in the font, draws the replacement character "�" if
53+
// available.
54+
// Returns how much we advance on the screen, which is the width of the
55+
// character or 0 if we didn't draw any chracter.
56+
int DrawGlyph(Canvas *c, int x, int y,
57+
const Color &color, const Color *background_color,
58+
uint32_t unicode_codepoint) const;
59+
60+
// Same without background. Deprecated, use the one above instead.
61+
int DrawGlyph(Canvas *c, int x, int y, const Color &color,
62+
uint32_t unicode_codepoint) const;
63+
64+
// Create a new font derived from this font, which represents an outline
65+
// of the original font, essentially pixels tracing around the original
66+
// letter.
67+
// This can be used in situations in which it is desirable to frame a letter
68+
// in a different color to increase contrast.
69+
// The ownership of the returned pointer is passed to the caller.
70+
Font *CreateOutlineFont() const;
71+
72+
private:
73+
Font(const Font &x); // No copy constructor. Use references or pointer instead.
74+
75+
struct Glyph;
76+
typedef std::map<uint32_t, Glyph *> CodepointGlyphMap;
77+
78+
const Glyph *FindGlyph(uint32_t codepoint) const;
79+
80+
int font_height_;
81+
int font_width_;
82+
int base_line_;
83+
CodepointGlyphMap glyphs_;
84+
};
85+
86+
// -- Some utility functions.
87+
88+
// Utility function: set an image from the given buffer containting pixels.
89+
//
90+
// Draw image of size "image_width" and "image_height" from pixel at
91+
// canvas-offset "canvas_offset_x", "canvas_offset_y". Image will be shown
92+
// cropped on the edges if needed.
93+
//
94+
// The canvas offset can be negative, i.e. the image start can be shifted
95+
// outside the image frame on the left/top edge.
96+
//
97+
// The buffer needs to be organized as rows with columns of three bytes
98+
// organized as rgb or bgr. Thus the size of the buffer needs to be exactly
99+
// (3 * image_width * image_height) bytes.
100+
//
101+
// The "image_buffer" parameters contains the data, "buffer_size_bytes" the
102+
// size in bytes.
103+
//
104+
// If "is_bgr" is true, the buffer is treated as BGR pixel arrangement instead
105+
// of RGB.
106+
// Returns 'true' if image was shown within canvas.
107+
bool SetImage(Canvas *c, int canvas_offset_x, int canvas_offset_y,
108+
const uint8_t *image_buffer, size_t buffer_size_bytes,
109+
int image_width, int image_height,
110+
bool is_bgr);
111+
112+
// Draw text, a standard NUL terminated C-string encoded in UTF-8,
113+
// with given "font" at "x","y" with "color".
114+
// "color" always needs to be set (hence it is a reference),
115+
// "background_color" is a pointer to optionally be NULL for transparency.
116+
// "kerning_offset" allows for additional spacing between characters (can be
117+
// negative)
118+
// Returns how many pixels we advanced on the screen.
119+
int DrawText(Canvas *c, const Font &font, int x, int y,
120+
const Color &color, const Color *background_color,
121+
const char *utf8_text, int kerning_offset = 0);
55122

56123
// Same without background. Deprecated, use the one above instead.
57-
int DrawGlyph(Canvas *c, int x, int y, const Color &color,
58-
uint32_t unicode_codepoint) const;
59-
60-
// Create a new font derived from this font, which represents an outline
61-
// of the original font, essentially pixels tracing around the original
62-
// letter.
63-
// This can be used in situations in which it is desirable to frame a letter
64-
// in a different color to increase contrast.
65-
// The ownership of the returned pointer is passed to the caller.
66-
Font *CreateOutlineFont() const;
67-
68-
private:
69-
Font(const Font& x); // No copy constructor. Use references or pointer instead.
70-
71-
struct Glyph;
72-
typedef std::map<uint32_t, Glyph*> CodepointGlyphMap;
73-
74-
const Glyph *FindGlyph(uint32_t codepoint) const;
75-
76-
int font_height_;
77-
int base_line_;
78-
CodepointGlyphMap glyphs_;
79-
};
80-
81-
// -- Some utility functions.
82-
83-
// Utility function: set an image from the given buffer containting pixels.
84-
//
85-
// Draw image of size "image_width" and "image_height" from pixel at
86-
// canvas-offset "canvas_offset_x", "canvas_offset_y". Image will be shown
87-
// cropped on the edges if needed.
88-
//
89-
// The canvas offset can be negative, i.e. the image start can be shifted
90-
// outside the image frame on the left/top edge.
91-
//
92-
// The buffer needs to be organized as rows with columns of three bytes
93-
// organized as rgb or bgr. Thus the size of the buffer needs to be exactly
94-
// (3 * image_width * image_height) bytes.
95-
//
96-
// The "image_buffer" parameters contains the data, "buffer_size_bytes" the
97-
// size in bytes.
98-
//
99-
// If "is_bgr" is true, the buffer is treated as BGR pixel arrangement instead
100-
// of RGB.
101-
// Returns 'true' if image was shown within canvas.
102-
bool SetImage(Canvas *c, int canvas_offset_x, int canvas_offset_y,
103-
const uint8_t *image_buffer, size_t buffer_size_bytes,
104-
int image_width, int image_height,
105-
bool is_bgr);
106-
107-
// Draw text, a standard NUL terminated C-string encoded in UTF-8,
108-
// with given "font" at "x","y" with "color".
109-
// "color" always needs to be set (hence it is a reference),
110-
// "background_color" is a pointer to optionally be NULL for transparency.
111-
// "kerning_offset" allows for additional spacing between characters (can be
112-
// negative)
113-
// Returns how many pixels we advanced on the screen.
114-
int DrawText(Canvas *c, const Font &font, int x, int y,
115-
const Color &color, const Color *background_color,
116-
const char *utf8_text, int kerning_offset = 0);
117-
118-
// Same without background. Deprecated, use the one above instead.
119-
int DrawText(Canvas *c, const Font &font, int x, int y, const Color &color,
120-
const char *utf8_text);
121-
122-
// Draw text, a standard NUL terminated C-string encoded in UTF-8,
123-
// with given "font" at "x","y" with "color".
124-
// Draw text as above, but vertically (top down).
125-
// The text is a standard NUL terminated C-string encoded in UTF-8.
126-
// "font, "x", "y", "color" and "background_color" are same as DrawText().
127-
// "kerning_offset" allows for additional spacing between characters (can be
128-
// negative).
129-
// Returns font height to advance up on the screen.
130-
int VerticalDrawText(Canvas *c, const Font &font, int x, int y,
131-
const Color &color, const Color *background_color,
132-
const char *utf8_text, int kerning_offset = 0);
133-
134-
// Draw a circle centered at "x", "y", with a radius of "radius" and with "color"
135-
void DrawCircle(Canvas *c, int x, int y, int radius, const Color &color);
136-
137-
// Draw a line from "x0", "y0" to "x1", "y1" and with "color"
138-
void DrawLine(Canvas *c, int x0, int y0, int x1, int y1, const Color &color);
139-
140-
} // namespace rgb_matrix
141-
142-
#endif // RPI_GRAPHICS_H
124+
int DrawText(Canvas *c, const Font &font, int x, int y, const Color &color,
125+
const char *utf8_text);
126+
127+
// Draw text, a standard NUL terminated C-string encoded in UTF-8,
128+
// with given "font" at "x","y" with "color".
129+
// Draw text as above, but vertically (top down).
130+
// The text is a standard NUL terminated C-string encoded in UTF-8.
131+
// "font, "x", "y", "color" and "background_color" are same as DrawText().
132+
// "kerning_offset" allows for additional spacing between characters (can be
133+
// negative).
134+
// Returns font height to advance up on the screen.
135+
int VerticalDrawText(Canvas *c, const Font &font, int x, int y,
136+
const Color &color, const Color *background_color,
137+
const char *utf8_text, int kerning_offset = 0);
138+
139+
// Draw a circle centered at "x", "y", with a radius of "radius" and with "color"
140+
void DrawCircle(Canvas *c, int x, int y, int radius, const Color &color);
141+
142+
// Draw a line from "x0", "y0" to "x1", "y1" and with "color"
143+
void DrawLine(Canvas *c, int x0, int y0, int x1, int y1, const Color &color);
144+
145+
} // namespace rgb_matrix
146+
147+
#endif // RPI_GRAPHICS_H

‎lib/bdf-font.cc

+163-135
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
// Some old g++ installations need this macro to be defined for PRIx64.
1717
#ifndef __STDC_FORMAT_MACROS
18-
# define __STDC_FORMAT_MACROS
18+
#define __STDC_FORMAT_MACROS
1919
#endif
2020
#include <inttypes.h>
2121

@@ -32,157 +32,185 @@ static const uint32_t kUnicodeReplacementCodepoint = 0xFFFD;
3232
// Make wider if running into trouble.
3333
typedef uint64_t rowbitmap_t;
3434

35-
namespace rgb_matrix {
36-
struct Font::Glyph {
37-
int device_width, device_height;
38-
int width, height;
39-
int x_offset, y_offset;
40-
rowbitmap_t bitmap[0]; // contains 'height' elements.
41-
};
35+
namespace rgb_matrix
36+
{
37+
struct Font::Glyph
38+
{
39+
int device_width, device_height;
40+
int width, height;
41+
int x_offset, y_offset;
42+
rowbitmap_t bitmap[0]; // contains 'height' elements.
43+
};
4244

43-
Font::Font() : font_height_(-1), base_line_(0) {}
44-
Font::~Font() {
45-
for (CodepointGlyphMap::iterator it = glyphs_.begin();
46-
it != glyphs_.end(); ++it) {
47-
free(it->second);
45+
Font::Font() : font_height_(-1), font_width_(-1), base_line_(0) {}
46+
Font::~Font()
47+
{
48+
for (CodepointGlyphMap::iterator it = glyphs_.begin();
49+
it != glyphs_.end(); ++it)
50+
{
51+
free(it->second);
52+
}
4853
}
49-
}
5054

51-
// TODO: that might not be working for all input files yet.
52-
bool Font::LoadFont(const char *path) {
53-
if (!path || !*path) return false;
54-
FILE *f = fopen(path, "r");
55-
if (f == NULL)
56-
return false;
57-
uint32_t codepoint;
58-
char buffer[1024];
59-
int dummy;
60-
Glyph tmp;
61-
Glyph *current_glyph = NULL;
62-
int row = 0;
55+
// TODO: that might not be working for all input files yet.
56+
bool Font::LoadFont(const char *path)
57+
{
58+
if (!path || !*path)
59+
return false;
60+
FILE *f = fopen(path, "r");
61+
if (f == NULL)
62+
return false;
63+
uint32_t codepoint;
64+
char buffer[1024];
65+
int dummy;
66+
Glyph tmp;
67+
Glyph *current_glyph = NULL;
68+
int row = 0;
6369

64-
int bitmap_shift = 0;
65-
while (fgets(buffer, sizeof(buffer), f)) {
66-
if (sscanf(buffer, "FONTBOUNDINGBOX %d %d %d %d",
67-
&dummy, &font_height_, &dummy, &base_line_) == 4) {
68-
base_line_ += font_height_;
69-
}
70-
else if (sscanf(buffer, "ENCODING %ud", &codepoint) == 1) {
71-
// parsed.
72-
}
73-
else if (sscanf(buffer, "DWIDTH %d %d", &tmp.device_width, &tmp.device_height
74-
) == 2) {
75-
// parsed.
76-
}
77-
else if (sscanf(buffer, "BBX %d %d %d %d", &tmp.width, &tmp.height,
78-
&tmp.x_offset, &tmp.y_offset) == 4) {
79-
current_glyph = (Glyph*) malloc(sizeof(Glyph)
80-
+ tmp.height * sizeof(rowbitmap_t));
81-
*current_glyph = tmp;
82-
// We only get number of bytes large enough holding our width. We want
83-
// it always left-aligned.
84-
bitmap_shift =
85-
8 * (sizeof(rowbitmap_t) - ((current_glyph->width + 7) / 8))
86-
- current_glyph->x_offset;
87-
row = -1; // let's not start yet, wait for BITMAP
88-
}
89-
else if (strncmp(buffer, "BITMAP", strlen("BITMAP")) == 0) {
90-
row = 0;
91-
}
92-
else if (current_glyph && row >= 0 && row < current_glyph->height
93-
&& (sscanf(buffer, "%" PRIx64, &current_glyph->bitmap[row]) == 1)) {
94-
current_glyph->bitmap[row] <<= bitmap_shift;
95-
row++;
96-
}
97-
else if (strncmp(buffer, "ENDCHAR", strlen("ENDCHAR")) == 0) {
98-
if (current_glyph && row == current_glyph->height) {
99-
free(glyphs_[codepoint]); // just in case there was one.
100-
glyphs_[codepoint] = current_glyph;
101-
current_glyph = NULL;
70+
int bitmap_shift = 0;
71+
while (fgets(buffer, sizeof(buffer), f))
72+
{
73+
if (sscanf(buffer, "FONTBOUNDINGBOX %d %d %d %d",
74+
&dummy, &font_height_, &dummy, &base_line_) == 4)
75+
{
76+
base_line_ += font_height_;
77+
}
78+
else if (sscanf(buffer, "ENCODING %ud", &codepoint) == 1)
79+
{
80+
// parsed.
81+
}
82+
else if (sscanf(buffer, "DWIDTH %d %d", &tmp.device_width, &tmp.device_height) == 2)
83+
{
84+
// parsed.
85+
}
86+
else if (sscanf(buffer, "BBX %d %d %d %d", &tmp.width, &tmp.height,
87+
&tmp.x_offset, &tmp.y_offset) == 4)
88+
{
89+
current_glyph = (Glyph *)malloc(sizeof(Glyph) + tmp.height * sizeof(rowbitmap_t));
90+
*current_glyph = tmp;
91+
// We only get number of bytes large enough holding our width. We want
92+
// it always left-aligned.
93+
bitmap_shift =
94+
8 * (sizeof(rowbitmap_t) - ((current_glyph->width + 7) / 8)) - current_glyph->x_offset;
95+
row = -1; // let's not start yet, wait for BITMAP
96+
}
97+
else if (strncmp(buffer, "BITMAP", strlen("BITMAP")) == 0)
98+
{
99+
row = 0;
100+
}
101+
else if (current_glyph && row >= 0 && row < current_glyph->height && (sscanf(buffer, "%" PRIx64, &current_glyph->bitmap[row]) == 1))
102+
{
103+
current_glyph->bitmap[row] <<= bitmap_shift;
104+
row++;
105+
}
106+
else if (strncmp(buffer, "ENDCHAR", strlen("ENDCHAR")) == 0)
107+
{
108+
if (current_glyph && row == current_glyph->height)
109+
{
110+
free(glyphs_[codepoint]); // just in case there was one.
111+
glyphs_[codepoint] = current_glyph;
112+
current_glyph = NULL;
113+
}
102114
}
103115
}
116+
fclose(f);
117+
return true;
104118
}
105-
fclose(f);
106-
return true;
107-
}
108119

109-
Font *Font::CreateOutlineFont() const {
110-
Font *r = new Font();
111-
const int kBorder = 1;
112-
r->font_height_ = font_height_ + 2*kBorder;
113-
r->base_line_ = base_line_ + kBorder;
114-
for (CodepointGlyphMap::const_iterator it = glyphs_.begin();
115-
it != glyphs_.end(); ++it) {
116-
const Glyph *orig = it->second;
117-
const int height = orig->height + 2 * kBorder;
118-
const size_t alloc_size = sizeof(Glyph) + height * sizeof(rowbitmap_t);
119-
Glyph *const tmp_glyph = (Glyph*) calloc(1, alloc_size);
120-
tmp_glyph->width = orig->width + 2*kBorder;
121-
tmp_glyph->height = height;
122-
tmp_glyph->device_width = orig->device_width + 2*kBorder;
123-
tmp_glyph->device_height = height;
124-
tmp_glyph->y_offset = orig->y_offset - kBorder;
125-
// TODO: we don't really need bounding box, right ?
126-
const rowbitmap_t fill_pattern = 0b111;
127-
const rowbitmap_t start_mask = 0b010;
128-
// Fill the border
129-
for (int h = 0; h < orig->height; ++h) {
130-
rowbitmap_t fill = fill_pattern;
131-
rowbitmap_t orig_bitmap = orig->bitmap[h] >> kBorder;
132-
for (rowbitmap_t m = start_mask; m; m <<= 1, fill <<= 1) {
133-
if (orig_bitmap & m) {
134-
tmp_glyph->bitmap[h+kBorder-1] |= fill;
135-
tmp_glyph->bitmap[h+kBorder+0] |= fill;
136-
tmp_glyph->bitmap[h+kBorder+1] |= fill;
120+
Font *Font::CreateOutlineFont() const
121+
{
122+
Font *r = new Font();
123+
const int kBorder = 1;
124+
r->font_height_ = font_height_ + 2 * kBorder;
125+
r->base_line_ = base_line_ + kBorder;
126+
for (CodepointGlyphMap::const_iterator it = glyphs_.begin();
127+
it != glyphs_.end(); ++it)
128+
{
129+
const Glyph *orig = it->second;
130+
const int height = orig->height + 2 * kBorder;
131+
const size_t alloc_size = sizeof(Glyph) + height * sizeof(rowbitmap_t);
132+
Glyph *const tmp_glyph = (Glyph *)calloc(1, alloc_size);
133+
tmp_glyph->width = orig->width + 2 * kBorder;
134+
tmp_glyph->height = height;
135+
tmp_glyph->device_width = orig->device_width + 2 * kBorder;
136+
tmp_glyph->device_height = height;
137+
tmp_glyph->y_offset = orig->y_offset - kBorder;
138+
// TODO: we don't really need bounding box, right ?
139+
const rowbitmap_t fill_pattern = 0b111;
140+
const rowbitmap_t start_mask = 0b010;
141+
// Fill the border
142+
for (int h = 0; h < orig->height; ++h)
143+
{
144+
rowbitmap_t fill = fill_pattern;
145+
rowbitmap_t orig_bitmap = orig->bitmap[h] >> kBorder;
146+
for (rowbitmap_t m = start_mask; m; m <<= 1, fill <<= 1)
147+
{
148+
if (orig_bitmap & m)
149+
{
150+
tmp_glyph->bitmap[h + kBorder - 1] |= fill;
151+
tmp_glyph->bitmap[h + kBorder + 0] |= fill;
152+
tmp_glyph->bitmap[h + kBorder + 1] |= fill;
153+
}
137154
}
138155
}
156+
// Remove original font again.
157+
for (int h = 0; h < orig->height; ++h)
158+
{
159+
rowbitmap_t orig_bitmap = orig->bitmap[h] >> kBorder;
160+
tmp_glyph->bitmap[h + kBorder] &= ~orig_bitmap;
161+
}
162+
r->glyphs_[it->first] = tmp_glyph;
139163
}
140-
// Remove original font again.
141-
for (int h = 0; h < orig->height; ++h) {
142-
rowbitmap_t orig_bitmap = orig->bitmap[h] >> kBorder;
143-
tmp_glyph->bitmap[h+kBorder] &= ~orig_bitmap;
144-
}
145-
r->glyphs_[it->first] = tmp_glyph;
164+
return r;
146165
}
147-
return r;
148-
}
149166

150-
const Font::Glyph *Font::FindGlyph(uint32_t unicode_codepoint) const {
151-
CodepointGlyphMap::const_iterator found = glyphs_.find(unicode_codepoint);
152-
if (found == glyphs_.end())
153-
return NULL;
154-
return found->second;
155-
}
167+
const Font::Glyph *Font::FindGlyph(uint32_t unicode_codepoint) const
168+
{
169+
CodepointGlyphMap::const_iterator found = glyphs_.find(unicode_codepoint);
170+
if (found == glyphs_.end())
171+
return NULL;
172+
return found->second;
173+
}
156174

157-
int Font::CharacterWidth(uint32_t unicode_codepoint) const {
158-
const Glyph *g = FindGlyph(unicode_codepoint);
159-
return g ? g->device_width : -1;
160-
}
175+
int Font::CharacterWidth(uint32_t unicode_codepoint) const
176+
{
177+
const Glyph *g = FindGlyph(unicode_codepoint);
178+
return g ? g->device_width : -1;
179+
}
161180

162-
int Font::DrawGlyph(Canvas *c, int x_pos, int y_pos,
163-
const Color &color, const Color *bgcolor,
164-
uint32_t unicode_codepoint) const {
165-
const Glyph *g = FindGlyph(unicode_codepoint);
166-
if (g == NULL) g = FindGlyph(kUnicodeReplacementCodepoint);
167-
if (g == NULL) return 0;
168-
y_pos = y_pos - g->height - g->y_offset;
169-
for (int y = 0; y < g->height; ++y) {
170-
const rowbitmap_t row = g->bitmap[y];
171-
rowbitmap_t x_mask = (1LL<<63);
172-
for (int x = 0; x < g->device_width; ++x, x_mask >>= 1) {
173-
if (row & x_mask) {
174-
c->SetPixel(x_pos + x, y_pos + y, color.r, color.g, color.b);
175-
} else if (bgcolor) {
176-
c->SetPixel(x_pos + x, y_pos + y, bgcolor->r, bgcolor->g, bgcolor->b);
181+
int Font::DrawGlyph(Canvas *c, int x_pos, int y_pos,
182+
const Color &color, const Color *bgcolor,
183+
uint32_t unicode_codepoint) const
184+
{
185+
const Glyph *g = FindGlyph(unicode_codepoint);
186+
if (g == NULL)
187+
g = FindGlyph(kUnicodeReplacementCodepoint);
188+
if (g == NULL)
189+
return 0;
190+
y_pos = y_pos - g->height - g->y_offset;
191+
for (int y = 0; y < g->height; ++y)
192+
{
193+
const rowbitmap_t row = g->bitmap[y];
194+
rowbitmap_t x_mask = (1LL << 63);
195+
for (int x = 0; x < g->device_width; ++x, x_mask >>= 1)
196+
{
197+
if (row & x_mask)
198+
{
199+
c->SetPixel(x_pos + x, y_pos + y, color.r, color.g, color.b);
200+
}
201+
else if (bgcolor)
202+
{
203+
c->SetPixel(x_pos + x, y_pos + y, bgcolor->r, bgcolor->g, bgcolor->b);
204+
}
177205
}
178206
}
207+
return g->device_width;
179208
}
180-
return g->device_width;
181-
}
182209

183-
int Font::DrawGlyph(Canvas *c, int x_pos, int y_pos, const Color &color,
184-
uint32_t unicode_codepoint) const {
185-
return DrawGlyph(c, x_pos, y_pos, color, NULL, unicode_codepoint);
186-
}
210+
int Font::DrawGlyph(Canvas *c, int x_pos, int y_pos, const Color &color,
211+
uint32_t unicode_codepoint) const
212+
{
213+
return DrawGlyph(c, x_pos, y_pos, color, NULL, unicode_codepoint);
214+
}
187215

188-
} // namespace rgb_matrix
216+
} // namespace rgb_matrix

‎lib/multiplex-mappers.cc

+436-388
Original file line numberDiff line numberDiff line change
@@ -15,73 +15,78 @@
1515

1616
#include "multiplex-mappers-internal.h"
1717

18-
namespace rgb_matrix {
19-
namespace internal {
20-
// A Pixel Mapper maps physical pixels locations to the internal logical
21-
// mapping in a panel or panel-assembly, which depends on the wiring.
22-
class MultiplexMapperBase : public MultiplexMapper {
23-
public:
24-
MultiplexMapperBase(const char *name, int stretch_factor)
25-
: name_(name), panel_stretch_factor_(stretch_factor) {}
26-
27-
// This method is const, but we sneakily remember the original size
28-
// of the panels so that we can more easily quantize things.
29-
// So technically, we're stateful, but let's pretend we're not changing
30-
// state. In the context this is used, it is never accessed in multiple
31-
// threads.
32-
virtual void EditColsRows(int *cols, int *rows) const {
33-
panel_rows_ = *rows;
34-
panel_cols_ = *cols;
35-
36-
*rows /= panel_stretch_factor_;
37-
*cols *= panel_stretch_factor_;
38-
}
39-
40-
virtual bool GetSizeMapping(int matrix_width, int matrix_height,
41-
int *visible_width, int *visible_height) const {
42-
// Matrix width has been altered. Alter it back.
43-
*visible_width = matrix_width / panel_stretch_factor_;
44-
*visible_height = matrix_height * panel_stretch_factor_;
45-
return true;
46-
}
47-
48-
virtual const char *GetName() const { return name_; }
49-
50-
// The MapVisibleToMatrix() as required by PanelMatrix here breaks it
51-
// down to the individual panel, so that derived classes only need to
52-
// implement MapSinglePanel().
53-
virtual void MapVisibleToMatrix(int matrix_width, int matrix_height,
54-
int visible_x, int visible_y,
55-
int *matrix_x, int *matrix_y) const {
56-
const int chained_panel = visible_x / panel_cols_;
57-
const int parallel_panel = visible_y / panel_rows_;
58-
59-
const int within_panel_x = visible_x % panel_cols_;
60-
const int within_panel_y = visible_y % panel_rows_;
61-
62-
int new_x, new_y;
63-
MapSinglePanel(within_panel_x, within_panel_y, &new_x, &new_y);
64-
*matrix_x = chained_panel * panel_stretch_factor_*panel_cols_ + new_x;
65-
*matrix_y = parallel_panel * panel_rows_/panel_stretch_factor_ + new_y;
66-
}
67-
68-
// Map the coordinates for a single panel. This is to be overridden in
69-
// derived classes.
70-
// Input parameter is the visible position on the matrix, and this method
71-
// should return the internal multiplexed position.
72-
virtual void MapSinglePanel(int visible_x, int visible_y,
73-
int *matrix_x, int *matrix_y) const = 0;
74-
75-
protected:
76-
const char *const name_;
77-
const int panel_stretch_factor_;
78-
79-
mutable int panel_cols_;
80-
mutable int panel_rows_;
81-
};
82-
83-
84-
/* ========================================================================
18+
namespace rgb_matrix
19+
{
20+
namespace internal
21+
{
22+
// A Pixel Mapper maps physical pixels locations to the internal logical
23+
// mapping in a panel or panel-assembly, which depends on the wiring.
24+
class MultiplexMapperBase : public MultiplexMapper
25+
{
26+
public:
27+
MultiplexMapperBase(const char *name, int stretch_factor)
28+
: name_(name), panel_stretch_factor_(stretch_factor) {}
29+
30+
// This method is const, but we sneakily remember the original size
31+
// of the panels so that we can more easily quantize things.
32+
// So technically, we're stateful, but let's pretend we're not changing
33+
// state. In the context this is used, it is never accessed in multiple
34+
// threads.
35+
virtual void EditColsRows(int *cols, int *rows) const
36+
{
37+
panel_rows_ = *rows;
38+
panel_cols_ = *cols;
39+
40+
*rows /= panel_stretch_factor_;
41+
*cols *= panel_stretch_factor_;
42+
}
43+
44+
virtual bool GetSizeMapping(int matrix_width, int matrix_height,
45+
int *visible_width, int *visible_height) const
46+
{
47+
// Matrix width has been altered. Alter it back.
48+
*visible_width = matrix_width / panel_stretch_factor_;
49+
*visible_height = matrix_height * panel_stretch_factor_;
50+
return true;
51+
}
52+
53+
virtual const char *GetName() const { return name_; }
54+
55+
// The MapVisibleToMatrix() as required by PanelMatrix here breaks it
56+
// down to the individual panel, so that derived classes only need to
57+
// implement MapSinglePanel().
58+
virtual void MapVisibleToMatrix(int matrix_width, int matrix_height,
59+
int visible_x, int visible_y,
60+
int *matrix_x, int *matrix_y) const
61+
{
62+
const int chained_panel = visible_x / panel_cols_;
63+
const int parallel_panel = visible_y / panel_rows_;
64+
65+
const int within_panel_x = visible_x % panel_cols_;
66+
const int within_panel_y = visible_y % panel_rows_;
67+
68+
int new_x, new_y;
69+
MapSinglePanel(within_panel_x, within_panel_y, &new_x, &new_y);
70+
*matrix_x = chained_panel * panel_stretch_factor_ * panel_cols_ + new_x;
71+
*matrix_y = parallel_panel * panel_rows_ / panel_stretch_factor_ + new_y;
72+
}
73+
74+
// Map the coordinates for a single panel. This is to be overridden in
75+
// derived classes.
76+
// Input parameter is the visible position on the matrix, and this method
77+
// should return the internal multiplexed position.
78+
virtual void MapSinglePanel(int visible_x, int visible_y,
79+
int *matrix_x, int *matrix_y) const = 0;
80+
81+
protected:
82+
const char *const name_;
83+
const int panel_stretch_factor_;
84+
85+
mutable int panel_cols_;
86+
mutable int panel_rows_;
87+
};
88+
89+
/* ========================================================================
8590
* Multiplexer implementations.
8691
*
8792
* Extend MultiplexMapperBase and implement MapSinglePanel. You only have
@@ -92,350 +97,393 @@ class MultiplexMapperBase : public MultiplexMapper {
9297
* below. After that, the new mapper is available in the --led-multiplexing
9398
* option.
9499
*/
95-
class StripeMultiplexMapper : public MultiplexMapperBase {
96-
public:
97-
StripeMultiplexMapper() : MultiplexMapperBase("Stripe", 2) {}
98-
99-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
100-
const bool is_top_stripe = (y % (panel_rows_/2)) < panel_rows_/4;
101-
*matrix_x = is_top_stripe ? x + panel_cols_ : x;
102-
*matrix_y = ((y / (panel_rows_/2)) * (panel_rows_/4)
103-
+ y % (panel_rows_/4));
104-
}
105-
};
106-
107-
class CheckeredMultiplexMapper : public MultiplexMapperBase {
108-
public:
109-
CheckeredMultiplexMapper() : MultiplexMapperBase("Checkered", 2) {}
110-
111-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
112-
const bool is_top_check = (y % (panel_rows_/2)) < panel_rows_/4;
113-
const bool is_left_check = (x < panel_cols_/2);
114-
if (is_top_check) {
115-
*matrix_x = is_left_check ? x+panel_cols_/2 : x+panel_cols_;
116-
} else {
117-
*matrix_x = is_left_check ? x : x + panel_cols_/2;
118-
}
119-
*matrix_y = ((y / (panel_rows_/2)) * (panel_rows_/4)
120-
+ y % (panel_rows_/4));
121-
}
122-
};
123-
124-
class SpiralMultiplexMapper : public MultiplexMapperBase {
125-
public:
126-
SpiralMultiplexMapper() : MultiplexMapperBase("Spiral", 2) {}
127-
128-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
129-
const bool is_top_stripe = (y % (panel_rows_/2)) < panel_rows_/4;
130-
const int panel_quarter = panel_cols_/4;
131-
const int quarter = x / panel_quarter;
132-
const int offset = x % panel_quarter;
133-
*matrix_x = ((2*quarter*panel_quarter)
134-
+ (is_top_stripe
135-
? panel_quarter - 1 - offset
136-
: panel_quarter + offset));
137-
*matrix_y = ((y / (panel_rows_/2)) * (panel_rows_/4)
138-
+ y % (panel_rows_/4));
139-
}
140-
};
141-
142-
class ZStripeMultiplexMapper : public MultiplexMapperBase {
143-
public:
144-
ZStripeMultiplexMapper(const char *name, int even_vblock_offset, int odd_vblock_offset)
145-
: MultiplexMapperBase(name, 2),
146-
even_vblock_offset_(even_vblock_offset),
147-
odd_vblock_offset_(odd_vblock_offset) {}
148-
149-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
150-
static const int tile_width = 8;
151-
static const int tile_height = 4;
152-
153-
const int vert_block_is_odd = ((y / tile_height) % 2);
154-
155-
const int even_vblock_shift = (1 - vert_block_is_odd) * even_vblock_offset_;
156-
const int odd_vblock_shitf = vert_block_is_odd * odd_vblock_offset_;
157-
158-
*matrix_x = x + ((x + even_vblock_shift) / tile_width) * tile_width + odd_vblock_shitf;
159-
*matrix_y = (y % tile_height) + tile_height * (y / (tile_height * 2));
160-
}
161-
162-
private:
163-
const int even_vblock_offset_;
164-
const int odd_vblock_offset_;
165-
};
166-
167-
class CoremanMapper : public MultiplexMapperBase {
168-
public:
169-
CoremanMapper() : MultiplexMapperBase("coreman", 2) {}
170-
171-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
172-
const bool is_left_check = (x < panel_cols_/2);
173-
174-
if ((y <= 7) || ((y >= 16) && (y <= 23))){
175-
*matrix_x = ((x / (panel_cols_/2)) * panel_cols_) + (x % (panel_cols_/2));
176-
if ((y & (panel_rows_/4)) == 0) {
177-
*matrix_y = (y / (panel_rows_/2)) * (panel_rows_/4) + (y % (panel_rows_/4));
100+
class StripeMultiplexMapper : public MultiplexMapperBase
101+
{
102+
public:
103+
StripeMultiplexMapper() : MultiplexMapperBase("Stripe", 2) {}
104+
105+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
106+
{
107+
const bool is_top_stripe = (y % (panel_rows_ / 2)) < panel_rows_ / 4;
108+
*matrix_x = is_top_stripe ? x + panel_cols_ : x;
109+
*matrix_y = ((y / (panel_rows_ / 2)) * (panel_rows_ / 4) + y % (panel_rows_ / 4));
178110
}
179-
} else {
180-
*matrix_x = is_left_check ? x + panel_cols_/2 : x + panel_cols_;
181-
*matrix_y = (y / (panel_rows_/2)) * (panel_rows_/4) + y % (panel_rows_/4);
182-
}
183-
}
184-
};
185-
186-
class Kaler2ScanMapper : public MultiplexMapperBase {
187-
public:
188-
Kaler2ScanMapper() : MultiplexMapperBase("Kaler2Scan", 4) {}
189-
190-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
191-
// Now we have a 128x4 matrix
192-
int offset = ((y%4)/2) == 0 ? -1 : 1;// Add o substract
193-
int deltaOffset = offset < 0 ? 7:8;
194-
int deltaColumn = ((y%8)/4)== 0 ? 64 : 0;
195-
196-
*matrix_y = (y%2+(y/8)*2);
197-
*matrix_x = deltaColumn + (16 * (x/8)) + deltaOffset + ((x%8) * offset);
198-
199-
}
200-
};
201-
202-
class P10MapperZ : public MultiplexMapperBase {
203-
public:
204-
P10MapperZ() : MultiplexMapperBase("P10-128x4-Z", 4) {}
205-
// supports this panel: https://www.aliexpress.com/item/2017-Special-Offer-P10-Outdoor-Smd-Full-Color-Led-Display-Module-320x160mm-1-2-Scan-Outdoor/32809267439.html?spm=a2g0s.9042311.0.0.Ob0jEw
206-
// with --led-row-addr-type=2 flag
207-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
208-
int yComp = 0;
209-
if (y == 0 || y == 1 || y == 8 || y == 9) {
210-
yComp = 127;
211-
}
212-
else if (y == 2 || y == 3 || y == 10 || y == 11) {
213-
yComp = 112;
214-
}
215-
else if (y == 4 || y == 5 || y == 12 || y == 13) {
216-
yComp = 111;
217-
}
218-
else if (y == 6 || y == 7 || y == 14 || y == 15) {
219-
yComp = 96;
220-
}
111+
};
221112

222-
if (y == 0 || y == 1 || y == 4 || y == 5 ||
223-
y == 8 || y == 9 || y == 12 || y == 13) {
224-
*matrix_x = yComp - x;
225-
*matrix_x -= (24 * ((int)(x / 8)));
226-
}
227-
else {
228-
*matrix_x = yComp + x;
229-
*matrix_x -= (40 * ((int)(x / 8)));
230-
}
113+
class CheckeredMultiplexMapper : public MultiplexMapperBase
114+
{
115+
public:
116+
CheckeredMultiplexMapper() : MultiplexMapperBase("Checkered", 2) {}
117+
118+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
119+
{
120+
const bool is_top_check = (y % (panel_rows_ / 2)) < panel_rows_ / 4;
121+
const bool is_left_check = (x < panel_cols_ / 2);
122+
if (is_top_check)
123+
{
124+
*matrix_x = is_left_check ? x + panel_cols_ / 2 : x + panel_cols_;
125+
}
126+
else
127+
{
128+
*matrix_x = is_left_check ? x : x + panel_cols_ / 2;
129+
}
130+
*matrix_y = ((y / (panel_rows_ / 2)) * (panel_rows_ / 4) + y % (panel_rows_ / 4));
131+
}
132+
};
231133

232-
if (y == 0 || y == 2 || y == 4 || y == 6) {
233-
*matrix_y = 3;
234-
}
235-
else if (y == 1 || y == 3 || y == 5 || y == 7) {
236-
*matrix_y = 2;
237-
}
238-
else if (y == 8 || y == 10 || y == 12 || y == 14) {
239-
*matrix_y = 1;
240-
}
241-
else if (y == 9 || y == 11 || y == 13 || y == 15) {
242-
*matrix_y = 0;
243-
}
244-
}
245-
};
246-
247-
class QiangLiQ8 : public MultiplexMapperBase {
248-
public:
249-
QiangLiQ8() : MultiplexMapperBase("QiangLiQ8", 2) {}
250-
251-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
252-
const int column = x + (4+ 4*(x/4));
253-
*matrix_x = column;
254-
if ((y >= 15 && y <=19) || (y >= 5 && y <= 9)) {
255-
const int reverseColumn = x + (4*(x/4));
256-
*matrix_x = reverseColumn;
257-
}
258-
*matrix_y = y % 5 + (y/10) *5;
259-
}
260-
};
134+
class SpiralMultiplexMapper : public MultiplexMapperBase
135+
{
136+
public:
137+
SpiralMultiplexMapper() : MultiplexMapperBase("Spiral", 2) {}
138+
139+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
140+
{
141+
const bool is_top_stripe = (y % (panel_rows_ / 2)) < panel_rows_ / 4;
142+
const int panel_quarter = panel_cols_ / 4;
143+
const int quarter = x / panel_quarter;
144+
const int offset = x % panel_quarter;
145+
*matrix_x = ((2 * quarter * panel_quarter) + (is_top_stripe
146+
? panel_quarter - 1 - offset
147+
: panel_quarter + offset));
148+
*matrix_y = ((y / (panel_rows_ / 2)) * (panel_rows_ / 4) + y % (panel_rows_ / 4));
149+
}
150+
};
261151

262-
class InversedZStripe : public MultiplexMapperBase {
263-
public:
264-
InversedZStripe() : MultiplexMapperBase("InversedZStripe", 2) {}
152+
class ZStripeMultiplexMapper : public MultiplexMapperBase
153+
{
154+
public:
155+
ZStripeMultiplexMapper(const char *name, int even_vblock_offset, int odd_vblock_offset)
156+
: MultiplexMapperBase(name, 2),
157+
even_vblock_offset_(even_vblock_offset),
158+
odd_vblock_offset_(odd_vblock_offset) {}
265159

266-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
267-
static const int tile_width = 8;
268-
static const int tile_height = 4;
160+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
161+
{
162+
static const int tile_width = 8;
163+
static const int tile_height = 4;
269164

270-
const int vert_block_is_odd = ((y / tile_height) % 2);
271-
const int evenOffset[8] = {7, 5, 3, 1, -1, -3, -5, -7};
165+
const int vert_block_is_odd = ((y / tile_height) % 2);
272166

273-
if (vert_block_is_odd) {
274-
*matrix_x = x + (x / tile_width) * tile_width;
275-
} else {
276-
*matrix_x = x + (x / tile_width) * tile_width + 8 + evenOffset[x % 8];
277-
}
278-
*matrix_y = (y % tile_height) + tile_height * (y / (tile_height * 2));
279-
}
280-
};
167+
const int even_vblock_shift = (1 - vert_block_is_odd) * even_vblock_offset_;
168+
const int odd_vblock_shitf = vert_block_is_odd * odd_vblock_offset_;
281169

170+
*matrix_x = x + ((x + even_vblock_shift) / tile_width) * tile_width + odd_vblock_shitf;
171+
*matrix_y = (y % tile_height) + tile_height * (y / (tile_height * 2));
172+
}
173+
174+
private:
175+
const int even_vblock_offset_;
176+
const int odd_vblock_offset_;
177+
};
178+
179+
class CoremanMapper : public MultiplexMapperBase
180+
{
181+
public:
182+
CoremanMapper() : MultiplexMapperBase("coreman", 2) {}
183+
184+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
185+
{
186+
const bool is_left_check = (x < panel_cols_ / 2);
187+
188+
if ((y <= 7) || ((y >= 16) && (y <= 23)))
189+
{
190+
*matrix_x = ((x / (panel_cols_ / 2)) * panel_cols_) + (x % (panel_cols_ / 2));
191+
if ((y & (panel_rows_ / 4)) == 0)
192+
{
193+
*matrix_y = (y / (panel_rows_ / 2)) * (panel_rows_ / 4) + (y % (panel_rows_ / 4));
194+
}
195+
}
196+
else
197+
{
198+
*matrix_x = is_left_check ? x + panel_cols_ / 2 : x + panel_cols_;
199+
*matrix_y = (y / (panel_rows_ / 2)) * (panel_rows_ / 4) + y % (panel_rows_ / 4);
200+
}
201+
}
202+
};
282203

283-
/*
204+
class Kaler2ScanMapper : public MultiplexMapperBase
205+
{
206+
public:
207+
Kaler2ScanMapper() : MultiplexMapperBase("Kaler2Scan", 4) {}
208+
209+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
210+
{
211+
// Now we have a 128x4 matrix
212+
int offset = ((y % 4) / 2) == 0 ? -1 : 1; // Add o substract
213+
int deltaOffset = offset < 0 ? 7 : 8;
214+
int deltaColumn = ((y % 8) / 4) == 0 ? 64 : 0;
215+
216+
*matrix_y = (y % 2 + (y / 8) * 2);
217+
*matrix_x = deltaColumn + (16 * (x / 8)) + deltaOffset + ((x % 8) * offset);
218+
}
219+
};
220+
221+
class P10MapperZ : public MultiplexMapperBase
222+
{
223+
public:
224+
P10MapperZ() : MultiplexMapperBase("P10-128x4-Z", 4) {}
225+
// supports this panel: https://www.aliexpress.com/item/2017-Special-Offer-P10-Outdoor-Smd-Full-Color-Led-Display-Module-320x160mm-1-2-Scan-Outdoor/32809267439.html?spm=a2g0s.9042311.0.0.Ob0jEw
226+
// with --led-row-addr-type=2 flag
227+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
228+
{
229+
int yComp = 0;
230+
if (y == 0 || y == 1 || y == 8 || y == 9)
231+
{
232+
yComp = 127;
233+
}
234+
else if (y == 2 || y == 3 || y == 10 || y == 11)
235+
{
236+
yComp = 112;
237+
}
238+
else if (y == 4 || y == 5 || y == 12 || y == 13)
239+
{
240+
yComp = 111;
241+
}
242+
else if (y == 6 || y == 7 || y == 14 || y == 15)
243+
{
244+
yComp = 96;
245+
}
246+
247+
if (y == 0 || y == 1 || y == 4 || y == 5 ||
248+
y == 8 || y == 9 || y == 12 || y == 13)
249+
{
250+
*matrix_x = yComp - x;
251+
*matrix_x -= (24 * ((int)(x / 8)));
252+
}
253+
else
254+
{
255+
*matrix_x = yComp + x;
256+
*matrix_x -= (40 * ((int)(x / 8)));
257+
}
258+
259+
if (y == 0 || y == 2 || y == 4 || y == 6)
260+
{
261+
*matrix_y = 3;
262+
}
263+
else if (y == 1 || y == 3 || y == 5 || y == 7)
264+
{
265+
*matrix_y = 2;
266+
}
267+
else if (y == 8 || y == 10 || y == 12 || y == 14)
268+
{
269+
*matrix_y = 1;
270+
}
271+
else if (y == 9 || y == 11 || y == 13 || y == 15)
272+
{
273+
*matrix_y = 0;
274+
}
275+
}
276+
};
277+
278+
class QiangLiQ8 : public MultiplexMapperBase
279+
{
280+
public:
281+
QiangLiQ8() : MultiplexMapperBase("QiangLiQ8", 2) {}
282+
283+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
284+
{
285+
const int column = x + (4 + 4 * (x / 4));
286+
*matrix_x = column;
287+
if ((y >= 15 && y <= 19) || (y >= 5 && y <= 9))
288+
{
289+
const int reverseColumn = x + (4 * (x / 4));
290+
*matrix_x = reverseColumn;
291+
}
292+
*matrix_y = y % 5 + (y / 10) * 5;
293+
}
294+
};
295+
296+
class InversedZStripe : public MultiplexMapperBase
297+
{
298+
public:
299+
InversedZStripe() : MultiplexMapperBase("InversedZStripe", 2) {}
300+
301+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
302+
{
303+
static const int tile_width = 8;
304+
static const int tile_height = 4;
305+
306+
const int vert_block_is_odd = ((y / tile_height) % 2);
307+
const int evenOffset[8] = {7, 5, 3, 1, -1, -3, -5, -7};
308+
309+
if (vert_block_is_odd)
310+
{
311+
*matrix_x = x + (x / tile_width) * tile_width;
312+
}
313+
else
314+
{
315+
*matrix_x = x + (x / tile_width) * tile_width + 8 + evenOffset[x % 8];
316+
}
317+
*matrix_y = (y % tile_height) + tile_height * (y / (tile_height * 2));
318+
}
319+
};
320+
321+
/*
284322
* Vairous P10 1R1G1B Outdoor implementations for 16x16 modules with separate
285323
* RGB LEDs, e.g.:
286324
* https://www.ledcontrollercard.com/english/p10-outdoor-rgb-led-module-160x160mm-dip.html
287325
*
288326
*/
289-
class P10Outdoor1R1G1BMultiplexBase : public MultiplexMapperBase {
290-
public:
291-
P10Outdoor1R1G1BMultiplexBase(const char *name)
292-
: MultiplexMapperBase(name, 2) {}
293-
294-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
295-
const int vblock_is_odd = (y / tile_height_) % 2;
296-
const int vblock_is_even = 1 - vblock_is_odd;
297-
const int even_vblock_shift = vblock_is_even * even_vblock_offset_;
298-
const int odd_vblock_shift = vblock_is_odd * odd_vblock_offset_;
299-
300-
MapPanel(x, y, matrix_x, matrix_y,
301-
vblock_is_even, vblock_is_odd,
302-
even_vblock_shift, odd_vblock_shift);
303-
}
304-
305-
protected:
306-
virtual void MapPanel(int x, int y, int *matrix_x, int *matrix_y,
307-
int vblock_is_even, int vblock_is_odd,
308-
int even_vblock_shift, int odd_vblock_shift) const = 0;
309-
310-
static const int tile_width_ = 8;
311-
static const int tile_height_ = 4;
312-
static const int even_vblock_offset_ = 0;
313-
static const int odd_vblock_offset_ = 8;
314-
};
315-
316-
class P10Outdoor1R1G1BMultiplexMapper1 : public P10Outdoor1R1G1BMultiplexBase {
317-
public:
318-
P10Outdoor1R1G1BMultiplexMapper1()
319-
: P10Outdoor1R1G1BMultiplexBase("P10Outdoor1R1G1-1") {}
320-
321-
protected:
322-
void MapPanel(int x, int y, int *matrix_x, int *matrix_y,
323-
const int vblock_is_even, const int vblock_is_odd,
324-
const int even_vblock_shift, const int odd_vblock_shift) const {
325-
*matrix_x = tile_width_ * (1 + vblock_is_even + 2 * (x / tile_width_))
326-
- (x % tile_width_) - 1;
327-
*matrix_y = (y % tile_height_) + tile_height_ * (y / (tile_height_ * 2));
328-
}
329-
};
330-
331-
class P10Outdoor1R1G1BMultiplexMapper2 : public P10Outdoor1R1G1BMultiplexBase {
332-
public:
333-
P10Outdoor1R1G1BMultiplexMapper2()
334-
: P10Outdoor1R1G1BMultiplexBase("P10Outdoor1R1G1-2") {}
335-
336-
protected:
337-
void MapPanel(int x, int y, int *matrix_x, int *matrix_y,
338-
const int vblock_is_even, const int vblock_is_odd,
339-
const int even_vblock_shift, const int odd_vblock_shift) const {
340-
*matrix_x = vblock_is_even
341-
? tile_width_ * (1 + 2 * (x / tile_width_)) - (x % tile_width_) - 1
342-
: x + ((x + even_vblock_shift) / tile_width_) * tile_width_ + odd_vblock_shift;
343-
*matrix_y = (y % tile_height_) + tile_height_ * (y / (tile_height_ * 2));
344-
}
345-
};
346-
347-
class P10Outdoor1R1G1BMultiplexMapper3 : public P10Outdoor1R1G1BMultiplexBase {
348-
public:
349-
P10Outdoor1R1G1BMultiplexMapper3()
350-
: P10Outdoor1R1G1BMultiplexBase("P10Outdoor1R1G1-3") {}
351-
352-
protected:
353-
void MapPanel(int x, int y, int *matrix_x, int *matrix_y,
354-
const int vblock_is_even, const int vblock_is_odd,
355-
const int even_vblock_shift, const int odd_vblock_shift) const {
356-
*matrix_x = vblock_is_odd
357-
? tile_width_ * (2 + 2 * (x / tile_width_)) - (x % tile_width_) - 1
358-
: x + ((x + even_vblock_shift) / tile_width_) * tile_width_ + odd_vblock_shift;
359-
*matrix_y = (y % tile_height_) + tile_height_ * (y / (tile_height_ * 2));
360-
}
361-
};
362-
363-
class P10CoremanMapper : public MultiplexMapperBase {
364-
public:
365-
P10CoremanMapper() : MultiplexMapperBase("P10CoremanMapper", 4) {}
366-
367-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const {
368-
//Row offset 8,8,8,8,0,0,0,0,8,8,8,8,0,0,0,0
369-
int mulY = (y & 4) > 0 ? 0 : 8;
370-
371-
//Row offset 9,9,8,8,1,1,0,0,9,9,8,8,1,1,0,0
372-
mulY += (y & 2) > 0 ? 0 : 1;
373-
mulY += (x >> 2) & ~1; //Drop lsb
374-
375-
*matrix_x = (mulY << 3) + x % 8;
376-
*matrix_y = (y & 1) + ((y >> 2) & ~1);
377-
}
378-
};
379-
380-
class P8KryQMapper : public MultiplexMapperBase
381-
{
382-
public:
383-
P8KryQMapper() : MultiplexMapperBase("P8KryQMapper", 2) {}
327+
class P10Outdoor1R1G1BMultiplexBase : public MultiplexMapperBase
328+
{
329+
public:
330+
P10Outdoor1R1G1BMultiplexBase(const char *name)
331+
: MultiplexMapperBase(name, 2) {}
332+
333+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
334+
{
335+
const int vblock_is_odd = (y / tile_height_) % 2;
336+
const int vblock_is_even = 1 - vblock_is_odd;
337+
const int even_vblock_shift = vblock_is_even * even_vblock_offset_;
338+
const int odd_vblock_shift = vblock_is_odd * odd_vblock_offset_;
339+
340+
MapPanel(x, y, matrix_x, matrix_y,
341+
vblock_is_even, vblock_is_odd,
342+
even_vblock_shift, odd_vblock_shift);
343+
}
384344

385-
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
386-
{
387-
static const int tile_width = 8;
388-
static const int tile_height = 5;
345+
protected:
346+
virtual void MapPanel(int x, int y, int *matrix_x, int *matrix_y,
347+
int vblock_is_even, int vblock_is_odd,
348+
int even_vblock_shift, int odd_vblock_shift) const = 0;
389349

390-
const int vert_block_is_odd = ((y / tile_height) % 2);
391-
const int evenOffset[8] = {7, 5, 3, 1, -1, -3, -5, -7};
350+
static const int tile_width_ = 8;
351+
static const int tile_height_ = 4;
352+
static const int even_vblock_offset_ = 0;
353+
static const int odd_vblock_offset_ = 8;
354+
};
392355

393-
if (!vert_block_is_odd)
356+
class P10Outdoor1R1G1BMultiplexMapper1 : public P10Outdoor1R1G1BMultiplexBase
394357
{
395-
x = x + (x / tile_width) * tile_width;
396-
}
397-
else
358+
public:
359+
P10Outdoor1R1G1BMultiplexMapper1()
360+
: P10Outdoor1R1G1BMultiplexBase("P10Outdoor1R1G1-1") {}
361+
362+
protected:
363+
void MapPanel(int x, int y, int *matrix_x, int *matrix_y,
364+
const int vblock_is_even, const int vblock_is_odd,
365+
const int even_vblock_shift, const int odd_vblock_shift) const
366+
{
367+
*matrix_x = tile_width_ * (1 + vblock_is_even + 2 * (x / tile_width_)) - (x % tile_width_) - 1;
368+
*matrix_y = (y % tile_height_) + tile_height_ * (y / (tile_height_ * 2));
369+
}
370+
};
371+
372+
class P10Outdoor1R1G1BMultiplexMapper2 : public P10Outdoor1R1G1BMultiplexBase
398373
{
399-
x = x + (x / tile_width) * tile_width + 8 + evenOffset[x % 8];
400-
}
374+
public:
375+
P10Outdoor1R1G1BMultiplexMapper2()
376+
: P10Outdoor1R1G1BMultiplexBase("P10Outdoor1R1G1-2") {}
377+
378+
protected:
379+
void MapPanel(int x, int y, int *matrix_x, int *matrix_y,
380+
const int vblock_is_even, const int vblock_is_odd,
381+
const int even_vblock_shift, const int odd_vblock_shift) const
382+
{
383+
*matrix_x = vblock_is_even
384+
? tile_width_ * (1 + 2 * (x / tile_width_)) - (x % tile_width_) - 1
385+
: x + ((x + even_vblock_shift) / tile_width_) * tile_width_ + odd_vblock_shift;
386+
*matrix_y = (y % tile_height_) + tile_height_ * (y / (tile_height_ * 2));
387+
}
388+
};
389+
390+
class P10Outdoor1R1G1BMultiplexMapper3 : public P10Outdoor1R1G1BMultiplexBase
391+
{
392+
public:
393+
P10Outdoor1R1G1BMultiplexMapper3()
394+
: P10Outdoor1R1G1BMultiplexBase("P10Outdoor1R1G1-3") {}
395+
396+
protected:
397+
void MapPanel(int x, int y, int *matrix_x, int *matrix_y,
398+
const int vblock_is_even, const int vblock_is_odd,
399+
const int even_vblock_shift, const int odd_vblock_shift) const
400+
{
401+
*matrix_x = vblock_is_odd
402+
? tile_width_ * (2 + 2 * (x / tile_width_)) - (x % tile_width_) - 1
403+
: x + ((x + even_vblock_shift) / tile_width_) * tile_width_ + odd_vblock_shift;
404+
*matrix_y = (y % tile_height_) + tile_height_ * (y / (tile_height_ * 2));
405+
}
406+
};
407+
408+
class P10CoremanMapper : public MultiplexMapperBase
409+
{
410+
public:
411+
P10CoremanMapper() : MultiplexMapperBase("P10CoremanMapper", 4) {}
412+
413+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
414+
{
415+
//Row offset 8,8,8,8,0,0,0,0,8,8,8,8,0,0,0,0
416+
int mulY = (y & 4) > 0 ? 0 : 8;
401417

418+
//Row offset 9,9,8,8,1,1,0,0,9,9,8,8,1,1,0,0
419+
mulY += (y & 2) > 0 ? 0 : 1;
420+
mulY += (x >> 2) & ~1; //Drop lsb
402421

403-
*matrix_x = ((x/tile_width)+1)*tile_width-(x%tile_width)-1;
404-
*matrix_y = (y % tile_height) + tile_height * (y / (tile_height * 2));
405-
}
406-
};
422+
*matrix_x = (mulY << 3) + x % 8;
423+
*matrix_y = (y & 1) + ((y >> 2) & ~1);
424+
}
425+
};
407426

408-
/*
427+
class P8KryQMapper : public MultiplexMapperBase
428+
{
429+
public:
430+
P8KryQMapper() : MultiplexMapperBase("P8KryQMapper", 2) {}
431+
432+
void MapSinglePanel(int x, int y, int *matrix_x, int *matrix_y) const
433+
{
434+
static const int tile_width = 8;
435+
static const int tile_height = 5;
436+
437+
const int vert_block_is_odd = ((y / tile_height) % 2);
438+
const int evenOffset[8] = {7, 5, 3, 1, -1, -3, -5, -7};
439+
440+
if (!vert_block_is_odd)
441+
{
442+
x = x + (x / tile_width) * tile_width;
443+
}
444+
else
445+
{
446+
x = x + (x / tile_width) * tile_width + 8 + evenOffset[x % 8];
447+
}
448+
449+
*matrix_x = ((*matrix_x / 8) + 1) * 8 - (*matrix_x % 8) - 1;
450+
*matrix_y = (y % tile_height) + tile_height * (y / (tile_height * 2));
451+
}
452+
};
453+
454+
/*
409455
* Here is where the registration happens.
410456
* If you add an instance of the mapper here, it will automatically be
411457
* made available in the --led-multiplexing commandline option.
412458
*/
413-
static MuxMapperList *CreateMultiplexMapperList() {
414-
MuxMapperList *result = new MuxMapperList();
415-
416-
// Here, register all multiplex mappers from above.
417-
result->push_back(new StripeMultiplexMapper());
418-
result->push_back(new CheckeredMultiplexMapper());
419-
result->push_back(new SpiralMultiplexMapper());
420-
result->push_back(new ZStripeMultiplexMapper("ZStripe", 0, 8));
421-
result->push_back(new ZStripeMultiplexMapper("ZnMirrorZStripe", 4, 4));
422-
result->push_back(new CoremanMapper());
423-
result->push_back(new Kaler2ScanMapper());
424-
result->push_back(new ZStripeMultiplexMapper("ZStripeUneven", 8, 0));
425-
result->push_back(new P10MapperZ());
426-
result->push_back(new QiangLiQ8());
427-
result->push_back(new InversedZStripe());
428-
result->push_back(new P10Outdoor1R1G1BMultiplexMapper1());
429-
result->push_back(new P10Outdoor1R1G1BMultiplexMapper2());
430-
result->push_back(new P10Outdoor1R1G1BMultiplexMapper3());
431-
result->push_back(new P10CoremanMapper());
432-
result->push_back(new P8KryQMapper());
433-
return result;
434-
}
435-
436-
const MuxMapperList &GetRegisteredMultiplexMappers() {
437-
static const MuxMapperList *all_mappers = CreateMultiplexMapperList();
438-
return *all_mappers;
439-
}
440-
} // namespace internal
441-
} // namespace rgb_matrix
459+
static MuxMapperList *CreateMultiplexMapperList()
460+
{
461+
MuxMapperList *result = new MuxMapperList();
462+
463+
// Here, register all multiplex mappers from above.
464+
result->push_back(new StripeMultiplexMapper());
465+
result->push_back(new CheckeredMultiplexMapper());
466+
result->push_back(new SpiralMultiplexMapper());
467+
result->push_back(new ZStripeMultiplexMapper("ZStripe", 0, 8));
468+
result->push_back(new ZStripeMultiplexMapper("ZnMirrorZStripe", 4, 4));
469+
result->push_back(new CoremanMapper());
470+
result->push_back(new Kaler2ScanMapper());
471+
result->push_back(new ZStripeMultiplexMapper("ZStripeUneven", 8, 0));
472+
result->push_back(new P10MapperZ());
473+
result->push_back(new QiangLiQ8());
474+
result->push_back(new InversedZStripe());
475+
result->push_back(new P10Outdoor1R1G1BMultiplexMapper1());
476+
result->push_back(new P10Outdoor1R1G1BMultiplexMapper2());
477+
result->push_back(new P10Outdoor1R1G1BMultiplexMapper3());
478+
result->push_back(new P10CoremanMapper());
479+
result->push_back(new P8KryQMapper());
480+
return result;
481+
}
482+
483+
const MuxMapperList &GetRegisteredMultiplexMappers()
484+
{
485+
static const MuxMapperList *all_mappers = CreateMultiplexMapperList();
486+
return *all_mappers;
487+
}
488+
} // namespace internal
489+
} // namespace rgb_matrix

0 commit comments

Comments
 (0)
Please sign in to comment.