| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of the Falcon Player (FPP) and is Copyright (C) | ||
| 3 | * 2013-2022 by the Falcon Player Developers. | ||
| 4 | * | ||
| 5 | * The Falcon Player (FPP) is free software, and is covered under | ||
| 6 | * multiple Open Source licenses. Please see the included 'LICENSES' | ||
| 7 | * file for descriptions of what files are covered by each license. | ||
| 8 | * | ||
| 9 | * This source file is covered under the LGPL v2.1 as described in the | ||
| 10 | * included LICENSE.LGPL file. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include "fpp-pch.h" | ||
| 14 | |||
| 15 | #include "../common.h" | ||
| 16 | #include "../log.h" | ||
| 17 | |||
| 18 | #include "../Sequence.h" | ||
| 19 | #include "PanelMatrix.h" | ||
| 20 | |||
| 21 | 118 | PanelMatrix::PanelMatrix(int panelWidth, int panelHeight, int invertedData) : | |
| 22 | 118 | m_width(0), | |
| 23 | 118 | m_height(0), | |
| 24 | 118 | m_outputCount(0), | |
| 25 | 118 | m_pixelCount(0), | |
| 26 | 118 | m_panelCount(0), | |
| 27 | 118 | m_panelWidth(panelWidth), | |
| 28 | 118 | m_panelHeight(panelHeight), | |
| 29 |
2/2✓ Branch 0 taken 67968 times.
✓ Branch 1 taken 118 times.
|
68086 | m_invertedData(invertedData) { |
| 30 | 118 | } | |
| 31 | |||
| 32 |
3/6✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 118 times.
✗ Branch 5 not taken.
|
73986 | PanelMatrix::~PanelMatrix() { |
| 33 |
6/6✓ Branch 0 taken 67968 times.
✓ Branch 1 taken 118 times.
✓ Branch 2 taken 2832 times.
✓ Branch 3 taken 118 times.
✓ Branch 4 taken 2832 times.
✓ Branch 5 taken 118 times.
|
74001 | } |
| 34 | |||
| 35 | ✗ | int PanelMatrix::ConfigurePanels(std::string layout) { | |
| 36 | ✗ | int result = 1; | |
| 37 | |||
| 38 | ✗ | LogDebug(VB_CHANNELOUT, "Parsing Config: '%s'\n", layout.c_str()); | |
| 39 | |||
| 40 | ✗ | std::vector<std::string> panels = split(layout, '|'); | |
| 41 | |||
| 42 | ✗ | for (int i = 0; i < panels.size(); i++) { | |
| 43 | ✗ | result &= AddPanel(panels[i]); | |
| 44 | } | ||
| 45 | |||
| 46 | ✗ | if (result) | |
| 47 | ✗ | CalculateMaps(); | |
| 48 | |||
| 49 | ✗ | return result; | |
| 50 | ✗ | } | |
| 51 | |||
| 52 | ✗ | int PanelMatrix::AddPanel(std::string config) { | |
| 53 | ✗ | int output = 0; | |
| 54 | ✗ | int chain = 0; | |
| 55 | ✗ | int xOffset = 0; | |
| 56 | ✗ | int yOffset = 0; | |
| 57 | ✗ | char orientation = 'N'; | |
| 58 | |||
| 59 | ✗ | std::vector<std::string> elems = split(config, ':'); | |
| 60 | |||
| 61 | ✗ | if (elems.size() == 5) { | |
| 62 | ✗ | output = atoi(elems[0].c_str()); | |
| 63 | ✗ | chain = atoi(elems[1].c_str()); | |
| 64 | ✗ | xOffset = atoi(elems[3].c_str()); | |
| 65 | ✗ | yOffset = atoi(elems[4].c_str()); | |
| 66 | |||
| 67 | ✗ | if (elems[2].size()) | |
| 68 | ✗ | orientation = elems[2].c_str()[0]; | |
| 69 | } else { | ||
| 70 | ✗ | LogErr(VB_CHANNELOUT, "Invalid Panel Config: '%s'\n", config.c_str()); | |
| 71 | ✗ | return 0; | |
| 72 | } | ||
| 73 | |||
| 74 | ✗ | return AddPanel(output, chain, orientation, xOffset, yOffset); | |
| 75 | ✗ | } | |
| 76 | |||
| 77 | 150 | int PanelMatrix::AddPanel(int output, int chain, char orientation, | |
| 78 | int xOffset, int yOffset, FPPColorOrder colorOrder) { | ||
| 79 | 150 | int pWidth = m_panelWidth; | |
| 80 | 150 | int pHeight = m_panelHeight; | |
| 81 | |||
| 82 | // These come straight from the config. The UI only produces valid ones, | ||
| 83 | // but out of range they index m_outputPanels and the drivers' per-output | ||
| 84 | // tables, and a negative offset puts pixels before the frame. | ||
| 85 |
6/10✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 149 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 149 times.
✗ Branch 9 not taken.
|
150 | if (output < 0 || output >= MAX_MATRIX_OUTPUTS || chain < 0 || chain >= MAX_PANELS_PER_OUTPUT || |
| 86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
|
149 | xOffset < 0 || yOffset < 0) { |
| 87 | 1 | LogErr(VB_CHANNELOUT, "Invalid panel: output %d, chain %d, offset %d,%d\n", output, chain, xOffset, yOffset); | |
| 88 | 1 | return 0; | |
| 89 | } | ||
| 90 | |||
| 91 | // Orientation, Left, Right, Normal, Upside down | ||
| 92 |
2/4✓ Branch 0 taken 149 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 149 times.
|
149 | if ((orientation == 'L') || (orientation == 'R')) { |
| 93 | ✗ | pWidth = m_panelHeight; | |
| 94 | ✗ | pHeight = m_panelWidth; | |
| 95 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 146 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
|
149 | } else if ((orientation != 'N') && (orientation != 'U')) { |
| 96 | 1 | LogErr(VB_CHANNELOUT, "Invalid orientation '%c'\n", | |
| 97 | orientation); | ||
| 98 | 1 | return 0; | |
| 99 | } | ||
| 100 | |||
| 101 | // Nor may an offset grow the matrix past what the channel buffer holds: | ||
| 102 | // m_width * m_height * 3 is the outputs' channel count, and offsets in | ||
| 103 | // the millions overflowed it (and the pixel maps sized from it). | ||
| 104 | 148 | int64_t newWidth = std::max<int64_t>(m_width, (int64_t)xOffset + pWidth); | |
| 105 | 148 | int64_t newHeight = std::max<int64_t>(m_height, (int64_t)yOffset + pHeight); | |
| 106 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 147 times.
|
148 | if (newWidth * newHeight * 3 > (int64_t)FPPD_MAX_CHANNELS) { |
| 107 | 1 | LogErr(VB_CHANNELOUT, "Invalid panel: offset %d,%d makes the matrix %lldx%lld, more than %d channels\n", | |
| 108 | xOffset, yOffset, (long long)newWidth, (long long)newHeight, FPPD_MAX_CHANNELS); | ||
| 109 | 1 | return 0; | |
| 110 | } | ||
| 111 | |||
| 112 |
2/2✓ Branch 0 taken 139 times.
✓ Branch 1 taken 8 times.
|
147 | if ((xOffset + pWidth) > m_width) { |
| 113 | 139 | m_width = xOffset + pWidth; | |
| 114 | 139 | m_pixelCount = m_width * m_height; | |
| 115 | } | ||
| 116 | |||
| 117 |
2/2✓ Branch 0 taken 124 times.
✓ Branch 1 taken 23 times.
|
147 | if ((yOffset + pHeight) > m_height) { |
| 118 | 124 | m_height = yOffset + pHeight; | |
| 119 | 124 | m_pixelCount = m_width * m_height; | |
| 120 | } | ||
| 121 | |||
| 122 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 141 times.
|
147 | if (output > m_outputCount) |
| 123 | 6 | m_outputCount = output; | |
| 124 | |||
| 125 |
3/6✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 147 times.
✗ Branch 5 not taken.
|
294 | if ((m_panelCount < MAX_MATRIX_PANELS) && |
| 126 | 147 | (m_outputPanels[output].size() < MAX_PANELS_PER_OUTPUT)) { | |
| 127 | 147 | m_panels[m_panelCount].output = output; | |
| 128 | 147 | m_panels[m_panelCount].chain = chain; | |
| 129 | 147 | m_panels[m_panelCount].width = pWidth; | |
| 130 | 147 | m_panels[m_panelCount].height = pHeight; | |
| 131 | 147 | m_panels[m_panelCount].orientation = orientation; | |
| 132 | 147 | m_panels[m_panelCount].xOffset = xOffset; | |
| 133 | 147 | m_panels[m_panelCount].yOffset = yOffset; | |
| 134 | 147 | m_panels[m_panelCount].colorOrder = colorOrder; | |
| 135 | |||
| 136 | 147 | m_panels[m_panelCount].pixelMap.resize(pWidth * pHeight * 3); | |
| 137 | |||
| 138 | 147 | m_outputPanels[output].push_back(m_panelCount); | |
| 139 | |||
| 140 |
2/4✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
✗ Branch 3 not taken.
|
147 | LogDebug(VB_CHANNELOUT, "Added Panel %d of size %dx%d at %dx%d facing '%c'. Color Order: %s (%d). Matrix size now: %dx%d. Panel Count: %d, Output: %d, Chain: %d\n", |
| 141 | m_panelCount, pWidth, pHeight, xOffset, yOffset, orientation, ColorOrderToString(colorOrder).c_str(), (int)colorOrder, m_width, m_height, m_panelCount, output, chain); | ||
| 142 | 147 | m_panelCount++; | |
| 143 | } | ||
| 144 | |||
| 145 | 147 | CalculateMaps(); | |
| 146 | |||
| 147 | 147 | return 1; | |
| 148 | } | ||
| 149 | |||
| 150 | 147 | int PanelMatrix::CalculateMaps(void) { | |
| 151 | 147 | LogDebug(VB_CHANNELOUT, "PanelMatrix::CalculateMaps(), %d panels\n", | |
| 152 | m_panelCount); | ||
| 153 | |||
| 154 |
2/2✓ Branch 0 taken 305 times.
✓ Branch 1 taken 147 times.
|
452 | for (int panel = 0; panel < m_panelCount; panel++) { |
| 155 | 305 | int mOffset = 0; | |
| 156 | 305 | int pOffset = 0; | |
| 157 | 305 | int xOffset = m_panels[panel].xOffset; | |
| 158 | 305 | int yOffset = m_panels[panel].yOffset; | |
| 159 | 305 | int pWidth = m_panels[panel].width; | |
| 160 | 305 | int pHeight = m_panels[panel].height; | |
| 161 | |||
| 162 | 305 | FPPColorOrder colorOrder = m_panels[panel].colorOrder; | |
| 163 | |||
| 164 | // LogDebug(VB_CHANNELOUT, "P: %d, O: %c, Pos: %dx%d, w: %d, h: %d\n", panel, m_panels[panel].orientation, xOffset, yOffset, pWidth, pHeight); | ||
| 165 |
1/2✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
|
305 | m_panels[panel].pixelMap.resize(pWidth * pHeight * 3); |
| 166 | |||
| 167 |
2/2✓ Branch 0 taken 5832 times.
✓ Branch 1 taken 305 times.
|
6137 | for (int y = 0; y < pHeight; y++) { |
| 168 |
2/2✓ Branch 0 taken 247936 times.
✓ Branch 1 taken 5832 times.
|
253768 | for (int x = 0; x < pWidth; x++) { |
| 169 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 247936 times.
|
247936 | if (m_invertedData) |
| 170 | ✗ | mOffset = (((m_height - (yOffset + y) - 1) * m_width) + (xOffset + x)); | |
| 171 | else | ||
| 172 | 247936 | mOffset = (((yOffset + y) * m_width) + (xOffset + x)); | |
| 173 | |||
| 174 |
2/5✓ Branch 0 taken 245888 times.
✓ Branch 1 taken 2048 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
247936 | switch (m_panels[panel].orientation) { |
| 175 | 245888 | case 'N': | |
| 176 | 245888 | pOffset = (y * pWidth) + x; | |
| 177 | 245888 | break; | |
| 178 | 2048 | case 'U': | |
| 179 | 2048 | pOffset = (pWidth * pHeight) - ((y * pWidth) + x) - 1; | |
| 180 | 2048 | break; | |
| 181 | ✗ | case 'L': | |
| 182 | ✗ | pOffset = (x * pHeight) + (pHeight - y - 1); | |
| 183 | ✗ | break; | |
| 184 | ✗ | case 'R': | |
| 185 | ✗ | pOffset = ((pWidth - x - 1) * pHeight) + y; | |
| 186 | ✗ | break; | |
| 187 | } | ||
| 188 | |||
| 189 | 247936 | mOffset *= 3; | |
| 190 | 247936 | pOffset *= 3; | |
| 191 | |||
| 192 |
2/2✓ Branch 0 taken 244352 times.
✓ Branch 1 taken 3584 times.
|
247936 | if (colorOrder == FPPColorOrder::kColorOrderRGB) { |
| 193 | 244352 | m_panels[panel].pixelMap[pOffset] = mOffset; | |
| 194 | 244352 | m_panels[panel].pixelMap[pOffset + 1] = mOffset + 1; | |
| 195 | 244352 | m_panels[panel].pixelMap[pOffset + 2] = mOffset + 2; | |
| 196 |
2/2✓ Branch 0 taken 512 times.
✓ Branch 1 taken 3072 times.
|
3584 | } else if (colorOrder == FPPColorOrder::kColorOrderRBG) { |
| 197 | 512 | m_panels[panel].pixelMap[pOffset] = mOffset; | |
| 198 | 512 | m_panels[panel].pixelMap[pOffset + 2] = mOffset + 1; | |
| 199 | 512 | m_panels[panel].pixelMap[pOffset + 1] = mOffset + 2; | |
| 200 |
2/2✓ Branch 0 taken 1536 times.
✓ Branch 1 taken 1536 times.
|
3072 | } else if (colorOrder == FPPColorOrder::kColorOrderGRB) { |
| 201 | 1536 | m_panels[panel].pixelMap[pOffset + 1] = mOffset; | |
| 202 | 1536 | m_panels[panel].pixelMap[pOffset] = mOffset + 1; | |
| 203 | 1536 | m_panels[panel].pixelMap[pOffset + 2] = mOffset + 2; | |
| 204 |
2/2✓ Branch 0 taken 512 times.
✓ Branch 1 taken 1024 times.
|
1536 | } else if (colorOrder == FPPColorOrder::kColorOrderGBR) { |
| 205 | 512 | m_panels[panel].pixelMap[pOffset + 2] = mOffset; | |
| 206 | 512 | m_panels[panel].pixelMap[pOffset] = mOffset + 1; | |
| 207 | 512 | m_panels[panel].pixelMap[pOffset + 1] = mOffset + 2; | |
| 208 |
2/2✓ Branch 0 taken 512 times.
✓ Branch 1 taken 512 times.
|
1024 | } else if (colorOrder == FPPColorOrder::kColorOrderBRG) { |
| 209 | 512 | m_panels[panel].pixelMap[pOffset + 1] = mOffset; | |
| 210 | 512 | m_panels[panel].pixelMap[pOffset + 2] = mOffset + 1; | |
| 211 | 512 | m_panels[panel].pixelMap[pOffset] = mOffset + 2; | |
| 212 |
1/2✓ Branch 0 taken 512 times.
✗ Branch 1 not taken.
|
512 | } else if (colorOrder == FPPColorOrder::kColorOrderBGR) { |
| 213 | 512 | m_panels[panel].pixelMap[pOffset + 2] = mOffset; | |
| 214 | 512 | m_panels[panel].pixelMap[pOffset + 1] = mOffset + 1; | |
| 215 | 512 | m_panels[panel].pixelMap[pOffset] = mOffset + 2; | |
| 216 | } else // Assume RGB if somehow invalid | ||
| 217 | { | ||
| 218 | ✗ | m_panels[panel].pixelMap[pOffset] = mOffset; | |
| 219 | ✗ | m_panels[panel].pixelMap[pOffset + 1] = mOffset + 1; | |
| 220 | ✗ | m_panels[panel].pixelMap[pOffset + 2] = mOffset + 2; | |
| 221 | } | ||
| 222 | } | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | 147 | return 1; | |
| 227 | } | ||
| 228 | |||
| 229 | 560 | void LEDPanel::drawTestPattern(unsigned char* channelData, int cycleNum, float percentOfCycle, int testType) { | |
| 230 | // Test types match the ids the pixel-string test dropdown uses so the UIs | ||
| 231 | // can present a consistent list: 1 = panel layout/ID pattern, 4-7 = | ||
| 232 | // red/green/blue/white fades. Anything else draws the layout pattern. | ||
| 233 |
3/4✓ Branch 0 taken 482 times.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 482 times.
✗ Branch 3 not taken.
|
560 | if (testType >= 4 && testType <= 7) { |
| 234 |
1/2✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
|
482 | drawFadePattern(channelData, percentOfCycle, testType); |
| 235 | 482 | return; | |
| 236 | } | ||
| 237 | unsigned char clr[3]; | ||
| 238 |
3/3✓ Branch 0 taken 73 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
|
78 | switch (cycleNum % 3) { |
| 239 | 73 | case 0: | |
| 240 | 73 | clr[0] = clr[2] = 0; | |
| 241 | 73 | clr[1] = 255; | |
| 242 | 73 | break; | |
| 243 | 3 | case 1: | |
| 244 | 3 | clr[2] = clr[1] = 0; | |
| 245 | 3 | clr[0] = 255; | |
| 246 | 3 | break; | |
| 247 | 2 | default: | |
| 248 | 2 | clr[0] = clr[1] = 0; | |
| 249 | 2 | clr[2] = 255; | |
| 250 | 2 | break; | |
| 251 | } | ||
| 252 | |||
| 253 | 78 | int actualHeight = height; | |
| 254 | 78 | int actualWidth = width; | |
| 255 | |||
| 256 |
2/4✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
|
78 | if ((orientation == 'L') || (orientation == 'R')) { |
| 257 | ✗ | actualHeight = width; | |
| 258 | ✗ | actualWidth = height; | |
| 259 | } | ||
| 260 | |||
| 261 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 78 times.
|
702 | for (int y = 0; y < (actualHeight / 2); y++) { |
| 262 | 624 | int yw1 = y * actualWidth * 3; | |
| 263 | 624 | int yw2 = (y + (actualHeight / 2)) * actualWidth * 3; | |
| 264 | |||
| 265 |
2/2✓ Branch 0 taken 19968 times.
✓ Branch 1 taken 624 times.
|
20592 | for (int x = 0; x < actualWidth; ++x) { |
| 266 | 19968 | int r = 0, g = 0, b = 0; | |
| 267 | 19968 | int r2 = 0, g2 = 0, b2 = 0; | |
| 268 | // Left Column | ||
| 269 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 19344 times.
|
19968 | if (x == 0) { |
| 270 | 624 | r = r2 = clr[0]; | |
| 271 | 624 | g = g2 = clr[1]; | |
| 272 | 624 | b = b2 = clr[2]; | |
| 273 | } | ||
| 274 | // Right Column | ||
| 275 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 19344 times.
|
19968 | if (x == (actualWidth - 1)) { |
| 276 | 624 | r = r2 = clr[1]; | |
| 277 | 624 | g = g2 = clr[2]; | |
| 278 | 624 | b = b2 = clr[0]; | |
| 279 | } | ||
| 280 | // Top Row (for yw1) | ||
| 281 |
2/2✓ Branch 0 taken 2496 times.
✓ Branch 1 taken 17472 times.
|
19968 | if (y == 0) { |
| 282 | 2496 | r = clr[2]; | |
| 283 | 2496 | g = clr[0]; | |
| 284 | 2496 | b = clr[1]; | |
| 285 | } | ||
| 286 | // Bottom Row (for yw2) | ||
| 287 |
2/2✓ Branch 0 taken 2496 times.
✓ Branch 1 taken 17472 times.
|
19968 | if (y == (actualHeight / 2 - 1)) { |
| 288 | 2496 | r2 = clr[2]; | |
| 289 | 2496 | g2 = clr[0]; | |
| 290 | 2496 | b2 = clr[1]; | |
| 291 | } | ||
| 292 | // Diagonal Top-Left to Middle | ||
| 293 |
4/4✓ Branch 0 taken 19344 times.
✓ Branch 1 taken 624 times.
✓ Branch 2 taken 624 times.
✓ Branch 3 taken 18720 times.
|
19968 | if (x == (2 * y) || x == (2 * y + 1)) { |
| 294 | 1248 | r = g = 255; | |
| 295 | } | ||
| 296 | // Diagonal Bottom-Left to Middle (part1) | ||
| 297 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 19344 times.
|
19968 | if (x == (2 * (actualHeight / 2 - 1 - y))) { |
| 298 | 624 | b2 = g2 = 255; | |
| 299 | } | ||
| 300 | // Diagonal Bottom-Left to Middle (part2) | ||
| 301 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 19344 times.
|
19968 | if (x == (2 * (actualHeight / 2 - 1 - y) + 1)) { |
| 302 | 624 | b2 = g2 = 255; | |
| 303 | } | ||
| 304 | // Square in middle | ||
| 305 |
4/4✓ Branch 0 taken 11232 times.
✓ Branch 1 taken 8736 times.
✓ Branch 2 taken 2496 times.
✓ Branch 3 taken 8736 times.
|
19968 | if (x >= (actualWidth / 2 - 2) && x <= (actualWidth / 2 + 1)) { |
| 306 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 1872 times.
|
2496 | if (y <= 1) { |
| 307 | 624 | r2 = g2 = b2 = 255; | |
| 308 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 1248 times.
|
1872 | } else if (y >= (actualHeight / 2 - 2)) { |
| 309 | 624 | r = g = b = 255; | |
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 |
1/2✓ Branch 0 taken 19968 times.
✗ Branch 1 not taken.
|
19968 | setPixel(channelData, yw1 + x * 3, r, g, b); |
| 314 |
1/2✓ Branch 0 taken 19968 times.
✗ Branch 1 not taken.
|
19968 | setPixel(channelData, yw2 + x * 3, r2, g2, b2); |
| 315 | } | ||
| 316 | } | ||
| 317 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
|
78 | drawNumber(output + 1, width / 2 + 1, height > 16 ? 2 : 1, channelData); |
| 318 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
|
78 | drawNumber(chain + 1, width / 2 + 8, height > 16 ? 2 : 1, channelData); |
| 319 | } | ||
| 320 | |||
| 321 | // Write r,g,b to the pixel's own channels so the output applies the color order | ||
| 322 | 286720 | void LEDPanel::setPixel(unsigned char* channelData, int idx, int r, int g, int b) { | |
| 323 | 286720 | int base = std::min(pixelMap[idx], std::min(pixelMap[idx + 1], pixelMap[idx + 2])); | |
| 324 | 286720 | channelData[base] = r; | |
| 325 | 286720 | channelData[base + 1] = g; | |
| 326 | 286720 | channelData[base + 2] = b; | |
| 327 | 286720 | } | |
| 328 | |||
| 329 | 482 | void LEDPanel::drawFadePattern(unsigned char* channelData, float percentOfCycle, int testType) { | |
| 330 | // Same triangle fade the pixel-string testers use (PixelFadeStringTester). | ||
| 331 | uint8_t fade; | ||
| 332 |
2/2✓ Branch 0 taken 282 times.
✓ Branch 1 taken 200 times.
|
482 | if (percentOfCycle < 0.50f) { |
| 333 | 282 | fade = percentOfCycle * 508.0f + 1; | |
| 334 | } else { | ||
| 335 | 200 | fade = 255 - (percentOfCycle - 0.5f) * 508.0f; | |
| 336 | } | ||
| 337 | // 4 = red, 5 = green, 6 = blue, 7 = white. | ||
| 338 |
4/4✓ Branch 0 taken 351 times.
✓ Branch 1 taken 131 times.
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 250 times.
|
482 | uint8_t r = (testType == 4 || testType == 7) ? fade : 0; |
| 339 |
4/4✓ Branch 0 taken 357 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 256 times.
|
482 | uint8_t g = (testType == 5 || testType == 7) ? fade : 0; |
| 340 |
4/4✓ Branch 0 taken 357 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 256 times.
|
482 | uint8_t b = (testType == 6 || testType == 7) ? fade : 0; |
| 341 | |||
| 342 | 482 | int actualHeight = height; | |
| 343 | 482 | int actualWidth = width; | |
| 344 |
2/4✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 482 times.
|
482 | if ((orientation == 'L') || (orientation == 'R')) { |
| 345 | ✗ | actualHeight = width; | |
| 346 | ✗ | actualWidth = height; | |
| 347 | } | ||
| 348 |
2/2✓ Branch 0 taken 7712 times.
✓ Branch 1 taken 482 times.
|
8194 | for (int y = 0; y < actualHeight; y++) { |
| 349 | 7712 | int yw = y * actualWidth * 3; | |
| 350 |
2/2✓ Branch 0 taken 246784 times.
✓ Branch 1 taken 7712 times.
|
254496 | for (int x = 0; x < actualWidth; ++x) { |
| 351 | 246784 | setPixel(channelData, yw + x * 3, r, g, b); | |
| 352 | } | ||
| 353 | } | ||
| 354 | 482 | } | |
| 355 | |||
| 356 | 156 | void LEDPanel::drawNumber(int v, int x, int y, unsigned char* channelData) { | |
| 357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
|
156 | if (v >= 20) { |
| 358 | ✗ | drawNumber(2, x, y, channelData); | |
| 359 | ✗ | x += 4; | |
| 360 | ✗ | v -= 20; | |
| 361 | } | ||
| 362 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
|
156 | if (v >= 10) { |
| 363 | ✗ | drawNumber(1, x, y, channelData); | |
| 364 | ✗ | x += 2; | |
| 365 | ✗ | v -= 10; | |
| 366 | } | ||
| 367 | |||
| 368 | int yw1; | ||
| 369 | 156 | int actualWidth = width; | |
| 370 | |||
| 371 |
2/4✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
|
156 | if ((orientation == 'L') || (orientation == 'R')) { |
| 372 | ✗ | actualWidth = height; | |
| 373 | } | ||
| 374 | |||
| 375 |
1/2✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
|
156 | if (v == 1) { |
| 376 |
2/2✓ Branch 0 taken 780 times.
✓ Branch 1 taken 156 times.
|
936 | for (int yo = 0; yo < 5; yo++) { |
| 377 | 780 | int yw1 = (y + yo) * actualWidth * 3; | |
| 378 | 780 | channelData[pixelMap[yw1 + x * 3]] = 255; | |
| 379 | 780 | channelData[pixelMap[yw1 + x * 3 + 1]] = 255; | |
| 380 | 780 | channelData[pixelMap[yw1 + x * 3 + 2]] = 255; | |
| 381 | } | ||
| 382 | 156 | return; | |
| 383 | } | ||
| 384 | ✗ | if (v == 4) { | |
| 385 | ✗ | for (int yo = 0; yo < 5; yo++) { | |
| 386 | ✗ | int yw1 = (y + yo) * actualWidth * 3; | |
| 387 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3]] = 255; | |
| 388 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3 + 1]] = 255; | |
| 389 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3 + 2]] = 255; | |
| 390 | ✗ | if (yo < 3) { | |
| 391 | ✗ | channelData[pixelMap[yw1 + x * 3]] = 255; | |
| 392 | ✗ | channelData[pixelMap[yw1 + x * 3 + 1]] = 255; | |
| 393 | ✗ | channelData[pixelMap[yw1 + x * 3 + 2]] = 255; | |
| 394 | } | ||
| 395 | } | ||
| 396 | ✗ | yw1 = (y + 2) * actualWidth * 3; | |
| 397 | ✗ | for (int x2 = 0; x2 < 3; x2++) { | |
| 398 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3]] = 255; | |
| 399 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 1]] = 255; | |
| 400 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 2]] = 255; | |
| 401 | } | ||
| 402 | ✗ | return; | |
| 403 | } | ||
| 404 | ✗ | if (v == 7) { | |
| 405 | ✗ | for (int yo = 0; yo < 5; yo++) { | |
| 406 | ✗ | int yw1 = (y + yo) * actualWidth * 3; | |
| 407 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3]] = 255; | |
| 408 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3 + 1]] = 255; | |
| 409 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3 + 2]] = 255; | |
| 410 | } | ||
| 411 | ✗ | yw1 = y * actualWidth * 3; | |
| 412 | ✗ | for (int x2 = 0; x2 < 3; x2++) { | |
| 413 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3]] = 255; | |
| 414 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 1]] = 255; | |
| 415 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 2]] = 255; | |
| 416 | } | ||
| 417 | ✗ | return; | |
| 418 | } | ||
| 419 | ✗ | yw1 = y * actualWidth * 3; | |
| 420 | ✗ | for (int x2 = 0; x2 < 3; x2++) { | |
| 421 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3]] = 255; | |
| 422 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 1]] = 255; | |
| 423 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 2]] = 255; | |
| 424 | |||
| 425 | ✗ | if (x2 != 1 || v != 0) { | |
| 426 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + actualWidth * 6]] = 255; | |
| 427 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 1 + actualWidth * 6]] = 255; | |
| 428 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 2 + actualWidth * 6]] = 255; | |
| 429 | } | ||
| 430 | |||
| 431 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + actualWidth * 12]] = 255; | |
| 432 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 1 + actualWidth * 12]] = 255; | |
| 433 | ✗ | channelData[pixelMap[yw1 + (x + x2) * 3 + 2 + actualWidth * 12]] = 255; | |
| 434 | } | ||
| 435 | ✗ | yw1 = (y + 1) * actualWidth * 3; | |
| 436 | ✗ | if (v == 5 || v == 6 || v == 9 || v == 8 || v == 0) { | |
| 437 | ✗ | channelData[pixelMap[yw1 + x * 3]] = 255; | |
| 438 | ✗ | channelData[pixelMap[yw1 + x * 3 + 1]] = 255; | |
| 439 | ✗ | channelData[pixelMap[yw1 + x * 3 + 2]] = 255; | |
| 440 | } | ||
| 441 | ✗ | if (v == 2 || v == 3 || v == 9 || v == 8 || v == 0) { | |
| 442 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3]] = 255; | |
| 443 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3 + 1]] = 255; | |
| 444 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3 + 2]] = 255; | |
| 445 | } | ||
| 446 | ✗ | yw1 = (y + 3) * actualWidth * 3; | |
| 447 | ✗ | if (v == 2 || v == 6 || v == 8 || v == 0) { | |
| 448 | ✗ | channelData[pixelMap[yw1 + x * 3]] = 255; | |
| 449 | ✗ | channelData[pixelMap[yw1 + x * 3 + 1]] = 255; | |
| 450 | ✗ | channelData[pixelMap[yw1 + x * 3 + 2]] = 255; | |
| 451 | } | ||
| 452 | ✗ | if (v == 3 || v == 5 || v == 6 || v == 8 | v == 9 || v == 0) { | |
| 453 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3]] = 255; | |
| 454 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3 + 1]] = 255; | |
| 455 | ✗ | channelData[pixelMap[yw1 + (x + 2) * 3 + 2]] = 255; | |
| 456 | } | ||
| 457 | } | ||
| 458 |