GCC Code Coverage Report


Directory: ./
File: overlays/PolarBufferMap.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 3 3 100.0%
Functions: 1 1 100.0%
Branches: 3 6 50.0%

Line Branch Exec Source
1 #pragma once
2 /*
3 * This file is part of the Falcon Player (FPP) and is Copyright (C)
4 * 2013-2025 by the Falcon Player Developers.
5 *
6 * The Falcon Player (FPP) is free software, and is covered under
7 * multiple Open Source licenses. Please see the included 'LICENSES'
8 * file for descriptions of what files are covered by each license.
9 *
10 * This source file is covered under the LGPL v2.1 as described in the
11 * included LICENSE.LGPL file.
12 */
13
14 #include <cstdint>
15 #include <string>
16 #include <string_view>
17 #include <vector>
18
19 /*
20 * A POLAR view of a pixel overlay model's buffer, so WLED effects sweep
21 * outward from (or around) the centre of a circular model rather than
22 * left-to-right across its wiring order.
23 *
24 * The existing "Buffer Mapping" values choose row-major vs column-major and
25 * mirror an axis (see BUFFERMAPS in WLEDEffects.cpp, consumed by Bus:: in
26 * wled/wled.cpp). Radius cannot join them as a fifth value, because they
27 * operate in BUFFER space: a circular model's buffer is wiring order, so the
28 * distance from buffer cell (x,y) to the buffer's centre says nothing about the
29 * distance from that pixel to the centre of the model.
30 *
31 * What is missing is per-pixel geometry, and FPP already has it —
32 * config/virtualdisplaymap carries x,y,z plus an absolute channel for every
33 * node. So instead of a new way to walk the buffer, this builds a LUT whose
34 * axes ARE polar and hands it to the same Bus indexing the other mappings use.
35 *
36 * The LUT points at the model's own buffer cells, NOT at output channels, which
37 * is what keeps this contained: by the time doOverlay(), flushOverlayBuffer(),
38 * getDataJson(), setData(), text, image export or the web pixel editor run, the
39 * pixels are already sitting in the model's normal buffer. None of them can
40 * tell a polar effect from a horizontal one.
41 */
42
43 /** Which polar layout an effect asked for. None means "not a polar mapping". */
44 enum class PolarMode {
45 None = 0,
46 RadialOut, // x = radius, centre first
47 RadialIn, // x = radius, rim first
48 AngularCW, // x = angle, clockwise on screen
49 AngularCCW, // x = angle, anticlockwise
50 };
51
52 /**
53 * The built layout: a dense width*height LUT from the WLED linear index to a
54 * buffer CELL index (y * model width + x) — or Empty where no pixel occupies
55 * that polar cell, which is common because polar binning is inherently sparse.
56 */
57 struct PolarBufferMap {
58 static constexpr uint32_t Empty = 0xFFFFFFFFu;
59
60 int width = 0; // fastest-varying axis: radius for Radial*, angle for Angular*
61 int height = 0;
62 std::vector<uint32_t> indexToCell;
63
64 17 bool valid() const {
65
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
34 return width > 0 && height > 0 &&
66
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
34 indexToCell.size() == static_cast<size_t>(width) * height;
67 }
68 };
69
70 /** One positioned buffer cell: where it is, and which cell it is. */
71 struct PolarPixel {
72 float x = 0.0f;
73 float y = 0.0f;
74 uint32_t cell = 0; // y * model width + x
75 };
76
77 /**
78 * Map a "Buffer Mapping" argument to a polar mode.
79 * Returns PolarMode::None for the four original values and for anything
80 * unrecognised, which is what makes an unknown value degrade to Horizontal
81 * rather than fail.
82 */
83 PolarMode PolarModeFromName(std::string_view name);
84
85 /**
86 * Lay pixels out in polar order.
87 *
88 * Returns an INVALID map (valid() == false) whenever the geometry will not
89 * support one — no positioned pixels, everything at a single point, or a buffer
90 * that would be absurdly large. Callers must treat that as "use the ordinary
91 * mapping", never as an error: a player with no xLights layout has no
92 * virtualdisplaymap and must keep behaving exactly as it does today.
93 */
94 PolarBufferMap BuildPolarBufferMap(const std::vector<PolarPixel>& pixels, PolarMode mode);
95
96 /**
97 * Read config/virtualdisplaymap into a 0-based absolute channel -> (x, y) index.
98 * Returns false when the file is absent or unreadable — the no-xLights case.
99 */
100 bool LoadVirtualDisplayPositions(std::vector<std::pair<uint32_t, std::pair<float, float>>>& out);
101