RGBMatrixEmulator 0.16.4__tar.gz → 0.17.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/PKG-INFO +52 -4
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/README.md +51 -3
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/base.py +26 -8
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/static/index.html +5 -6
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/pi5_adapter/__init__.py +5 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/pygame_adapter.py +2 -2
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/tkinter_adapter.py +4 -4
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/turtle_adapter.py +1 -1
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/emulation/canvas.py +5 -4
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/emulation/matrix.py +1 -2
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/emulation/options.py +10 -8
- rgbmatrixemulator-0.17.0/RGBMatrixEmulator/internal/screen.py +44 -0
- rgbmatrixemulator-0.17.0/RGBMatrixEmulator/pixel_mappers/__init__.py +104 -0
- rgbmatrixemulator-0.17.0/RGBMatrixEmulator/pixel_mappers/identity.py +15 -0
- rgbmatrixemulator-0.17.0/RGBMatrixEmulator/pixel_mappers/mirror.py +25 -0
- rgbmatrixemulator-0.17.0/RGBMatrixEmulator/pixel_mappers/rotate.py +35 -0
- rgbmatrixemulator-0.17.0/RGBMatrixEmulator/pixel_mappers/stack_to_row.py +25 -0
- rgbmatrixemulator-0.17.0/RGBMatrixEmulator/pixel_mappers/umapper.py +27 -0
- rgbmatrixemulator-0.17.0/RGBMatrixEmulator/pixel_mappers/vmapper.py +28 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/version.py +1 -1
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/.gitignore +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/LICENSE +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/__init__.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/__init__.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/README.md +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/__init__.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/adapter.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/fps.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/request_handlers/__init__.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/request_handlers/base.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/request_handlers/image.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/request_handlers/image_web_socket.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/request_handlers/main.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/request_handlers/single_file.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/server.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/static/assets/client.js +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/static/assets/icon.ico +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/browser_adapter/static/assets/styles.css +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/pi5_adapter/README.md +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/raw_adapter/README.md +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/raw_adapter/__init__.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/sixel_adapter.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/terminal_adapter.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/cli/__init__.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/cli/command.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/cli/config.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/emulation/__init__.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/graphics/__init__.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/graphics/color.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/graphics/font.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/icon.png +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/internal/adapter_loader.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/internal/emulator_config.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/internal/pixel_style.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/logger.py +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/py.typed +0 -0
- {rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: RGBMatrixEmulator
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.17.0
|
|
4
4
|
Summary: A PC emulator for Raspberry Pi LED matrices driven by rpi-rgb-led-matrix
|
|
5
5
|
Project-URL: Homepage, https://github.com/ty-porter/RGBMatrixEmulator
|
|
6
6
|
Author-email: Tyler Porter <tyler.b.porter@gmail.com>
|
|
@@ -99,6 +99,53 @@ After this, most of the existing command line arguments from the `rpi-rgb-led-ma
|
|
|
99
99
|
|
|
100
100
|
Startup of the existing script will be unchanged.
|
|
101
101
|
|
|
102
|
+
## Multi-Panel Emulation
|
|
103
|
+
|
|
104
|
+
Emulated multi-panel chaining is supported via `rpi-rgb-led-matrix` CLI flags such as `--led-chain`, `--led-parallel`, `--led-pixel-mappers`. RGBME makes the assumption that the desired orientation for a multi-panel arrangement is a rectangular, upright array of panels.
|
|
105
|
+
|
|
106
|
+
### `--led-chain` / `--led-parallel`
|
|
107
|
+
|
|
108
|
+
Single-panel emulation creates an emulated matrix size of `--led-cols` (width) x `--led-rows` (height). For instance, the following command creates a 64x32 emulated matrix.
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
python main.py --led-cols 64 --led-rows 32
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`--led-chain` can be thought of as the number of panels chained horizontally, and `--led-parallel` is the number of parallel chains. This also assumes the chains contain the same number of panels. Thus, these flags create a `--led-cols` x `--led-chain` wide by `--led-rows` x `--led-parallel` high. The following example creates a 128x64 emulated matrix.
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
python main.py --led-cols 64 --led-rows 32 --led-chain 2 --led-parallel 2
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### `--led-pixel-mapper`
|
|
121
|
+
|
|
122
|
+
> [!TIP]
|
|
123
|
+
> Contributions welcome to support more complex mapper behavior!
|
|
124
|
+
|
|
125
|
+
RGBME assumes that the user wants to simulate a physical arrangement of panels such that the image appears continuous and upright. This differs a bit from how `rpi-rgb-led-matrix` treats chains and pixel mappers, which describe the wiring arrangement of the panels and the physical arrangement of panels is not specified.
|
|
126
|
+
|
|
127
|
+
RGBME does **NOT** support pixel mapper chaining:
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
# More than one pixel mapper, V-mapper:Z chained into Rotate:90
|
|
131
|
+
# RGBME will use the first detected mapper.
|
|
132
|
+
python main.py --led-chain 2 --led-parallel 2 --led-pixel-mapper "V-mapper:Z;Rotate:90"
|
|
133
|
+
|
|
134
|
+
# Valid
|
|
135
|
+
python main.py --led-chain 2 --led-parallel 2 --led-pixel-mapper "V-mapper:Z"
|
|
136
|
+
python main.py --led-chain 2 --led-parallel 2 --led-pixel-mapper "Rotate:90"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Instead, RGBME can use a single pixel mapper to alter the emulated dimensions or perform affine transformations over the entire emulated matrix.
|
|
140
|
+
|
|
141
|
+
| Mapper | Parameter | Description |
|
|
142
|
+
| --- | --- | --- |
|
|
143
|
+
| `V-mapper` | `Z` (optional) for zig-zag wiring | Folds a horizontal chain into vertical panel stacks. Changes the dimensions to `(W·parallel/chain) × (H·chain/parallel)`. |
|
|
144
|
+
| `U-mapper` | | Folds a long chain back on itself into a U, halving the width and doubling the height (`W/2 × H·2`). Requires an even chain of at least 2 panels. |
|
|
145
|
+
| `StackToRow` | | Lays parallel chains end-to-end into one wide horizontal row, reshaping the dimensions to `(W·parallel) × (H/parallel)`. |
|
|
146
|
+
| `Rotate` | Angle in degrees, a multiple of 90 (e.g. `90`) | Rotates the displayed image by the given angle. At 90° or 270° the width and height are swapped. |
|
|
147
|
+
| `Mirror` | `H` (default) or `V` | Mirrors the display left/right (`H`) or top/bottom (`V`). Preserves dimensions. |
|
|
148
|
+
|
|
102
149
|
## Customization
|
|
103
150
|
|
|
104
151
|
### Generating a Configuration File
|
|
@@ -228,10 +275,10 @@ Please see the [README for the `browser` display adapter](RGBMatrixEmulator/adap
|
|
|
228
275
|
|
|
229
276
|
### Raspberry Pi 5 Adapter
|
|
230
277
|
|
|
231
|
-
> [!
|
|
232
|
-
> This adapter is
|
|
278
|
+
> [!WARNING]
|
|
279
|
+
> This adapter is deprecated. It will be removed no later than July 1, 2026. Please use native `rpi-rgb-led-matrix` Raspberry Pi 5 support.
|
|
233
280
|
|
|
234
|
-
RGBME can be used to "bridge" scripts written for `rpi-rgb-led-matrix` to Raspberry Pi model 5 through [Adafruit Blinka](https://github.com/adafruit/Adafruit_Blinka) and the [Adafruit-Blinka-Raspberry-Pi5-Piomatter](https://github.com/adafruit/Adafruit_Blinka_Raspberry_Pi5_Piomatter) libraries.
|
|
281
|
+
RGBME can be used to "bridge" scripts written for `rpi-rgb-led-matrix` to Raspberry Pi model 5 through [Adafruit Blinka](https://github.com/adafruit/Adafruit_Blinka) and the [Adafruit-Blinka-Raspberry-Pi5-Piomatter](https://github.com/adafruit/Adafruit_Blinka_Raspberry_Pi5_Piomatter) libraries.
|
|
235
282
|
|
|
236
283
|
Please see the [README for the `pi5` display adapter](RGBMatrixEmulator/adapters/pi5_adapter/README.md) for further information regarding its configuration and usage.
|
|
237
284
|
|
|
@@ -317,6 +364,7 @@ See [Samples README](samples/README.md) for more information about running examp
|
|
|
317
364
|
```
|
|
318
365
|
</details>
|
|
319
366
|
- Drawing large strings is slow, partly because of the `linelimit` parameter in the BDF font parser this emulator uses to prevent multiline text from being rendered unintentionally.
|
|
367
|
+
- `--led-pixel-mapper` emulation differs from `rpi-rgb-led-matrix`. This is due to the assumption made by RGBME for an upright, rectangular emulated matrix. See [Multi-Panel Emulation](#multi-panel-emulation) for details.
|
|
320
368
|
|
|
321
369
|
## Contributing
|
|
322
370
|
|
|
@@ -67,6 +67,53 @@ After this, most of the existing command line arguments from the `rpi-rgb-led-ma
|
|
|
67
67
|
|
|
68
68
|
Startup of the existing script will be unchanged.
|
|
69
69
|
|
|
70
|
+
## Multi-Panel Emulation
|
|
71
|
+
|
|
72
|
+
Emulated multi-panel chaining is supported via `rpi-rgb-led-matrix` CLI flags such as `--led-chain`, `--led-parallel`, `--led-pixel-mappers`. RGBME makes the assumption that the desired orientation for a multi-panel arrangement is a rectangular, upright array of panels.
|
|
73
|
+
|
|
74
|
+
### `--led-chain` / `--led-parallel`
|
|
75
|
+
|
|
76
|
+
Single-panel emulation creates an emulated matrix size of `--led-cols` (width) x `--led-rows` (height). For instance, the following command creates a 64x32 emulated matrix.
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
python main.py --led-cols 64 --led-rows 32
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`--led-chain` can be thought of as the number of panels chained horizontally, and `--led-parallel` is the number of parallel chains. This also assumes the chains contain the same number of panels. Thus, these flags create a `--led-cols` x `--led-chain` wide by `--led-rows` x `--led-parallel` high. The following example creates a 128x64 emulated matrix.
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
python main.py --led-cols 64 --led-rows 32 --led-chain 2 --led-parallel 2
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### `--led-pixel-mapper`
|
|
89
|
+
|
|
90
|
+
> [!TIP]
|
|
91
|
+
> Contributions welcome to support more complex mapper behavior!
|
|
92
|
+
|
|
93
|
+
RGBME assumes that the user wants to simulate a physical arrangement of panels such that the image appears continuous and upright. This differs a bit from how `rpi-rgb-led-matrix` treats chains and pixel mappers, which describe the wiring arrangement of the panels and the physical arrangement of panels is not specified.
|
|
94
|
+
|
|
95
|
+
RGBME does **NOT** support pixel mapper chaining:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
# More than one pixel mapper, V-mapper:Z chained into Rotate:90
|
|
99
|
+
# RGBME will use the first detected mapper.
|
|
100
|
+
python main.py --led-chain 2 --led-parallel 2 --led-pixel-mapper "V-mapper:Z;Rotate:90"
|
|
101
|
+
|
|
102
|
+
# Valid
|
|
103
|
+
python main.py --led-chain 2 --led-parallel 2 --led-pixel-mapper "V-mapper:Z"
|
|
104
|
+
python main.py --led-chain 2 --led-parallel 2 --led-pixel-mapper "Rotate:90"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Instead, RGBME can use a single pixel mapper to alter the emulated dimensions or perform affine transformations over the entire emulated matrix.
|
|
108
|
+
|
|
109
|
+
| Mapper | Parameter | Description |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| `V-mapper` | `Z` (optional) for zig-zag wiring | Folds a horizontal chain into vertical panel stacks. Changes the dimensions to `(W·parallel/chain) × (H·chain/parallel)`. |
|
|
112
|
+
| `U-mapper` | | Folds a long chain back on itself into a U, halving the width and doubling the height (`W/2 × H·2`). Requires an even chain of at least 2 panels. |
|
|
113
|
+
| `StackToRow` | | Lays parallel chains end-to-end into one wide horizontal row, reshaping the dimensions to `(W·parallel) × (H/parallel)`. |
|
|
114
|
+
| `Rotate` | Angle in degrees, a multiple of 90 (e.g. `90`) | Rotates the displayed image by the given angle. At 90° or 270° the width and height are swapped. |
|
|
115
|
+
| `Mirror` | `H` (default) or `V` | Mirrors the display left/right (`H`) or top/bottom (`V`). Preserves dimensions. |
|
|
116
|
+
|
|
70
117
|
## Customization
|
|
71
118
|
|
|
72
119
|
### Generating a Configuration File
|
|
@@ -196,10 +243,10 @@ Please see the [README for the `browser` display adapter](RGBMatrixEmulator/adap
|
|
|
196
243
|
|
|
197
244
|
### Raspberry Pi 5 Adapter
|
|
198
245
|
|
|
199
|
-
> [!
|
|
200
|
-
> This adapter is
|
|
246
|
+
> [!WARNING]
|
|
247
|
+
> This adapter is deprecated. It will be removed no later than July 1, 2026. Please use native `rpi-rgb-led-matrix` Raspberry Pi 5 support.
|
|
201
248
|
|
|
202
|
-
RGBME can be used to "bridge" scripts written for `rpi-rgb-led-matrix` to Raspberry Pi model 5 through [Adafruit Blinka](https://github.com/adafruit/Adafruit_Blinka) and the [Adafruit-Blinka-Raspberry-Pi5-Piomatter](https://github.com/adafruit/Adafruit_Blinka_Raspberry_Pi5_Piomatter) libraries.
|
|
249
|
+
RGBME can be used to "bridge" scripts written for `rpi-rgb-led-matrix` to Raspberry Pi model 5 through [Adafruit Blinka](https://github.com/adafruit/Adafruit_Blinka) and the [Adafruit-Blinka-Raspberry-Pi5-Piomatter](https://github.com/adafruit/Adafruit_Blinka_Raspberry_Pi5_Piomatter) libraries.
|
|
203
250
|
|
|
204
251
|
Please see the [README for the `pi5` display adapter](RGBMatrixEmulator/adapters/pi5_adapter/README.md) for further information regarding its configuration and usage.
|
|
205
252
|
|
|
@@ -285,6 +332,7 @@ See [Samples README](samples/README.md) for more information about running examp
|
|
|
285
332
|
```
|
|
286
333
|
</details>
|
|
287
334
|
- Drawing large strings is slow, partly because of the `linelimit` parameter in the BDF font parser this emulator uses to prevent multiline text from being rendered unintentionally.
|
|
335
|
+
- `--led-pixel-mapper` emulation differs from `rpi-rgb-led-matrix`. This is due to the assumption made by RGBME for an upright, rectangular emulated matrix. See [Multi-Panel Emulation](#multi-panel-emulation) for details.
|
|
288
336
|
|
|
289
337
|
## Contributing
|
|
290
338
|
|
|
@@ -29,7 +29,7 @@ class BaseAdapter:
|
|
|
29
29
|
self.width = width
|
|
30
30
|
self.height = height
|
|
31
31
|
self.options = options
|
|
32
|
-
self.__black = Image.new("RGB", self.
|
|
32
|
+
self.__black = Image.new("RGB", self.scaled_screen_size, "black")
|
|
33
33
|
self.__mask = self.__draw_mask()
|
|
34
34
|
self.loaded = False
|
|
35
35
|
|
|
@@ -38,6 +38,24 @@ class BaseAdapter:
|
|
|
38
38
|
self.default_icon_path = (Path(__file__).parent / ".." / "icon.png").resolve()
|
|
39
39
|
self._set_icon_path()
|
|
40
40
|
|
|
41
|
+
@property
|
|
42
|
+
def scaled_screen_size(self):
|
|
43
|
+
"""On-screen size in pixels: the screen (LED grid) scaled by pixel_size."""
|
|
44
|
+
pixel_size = self.options.pixel_size
|
|
45
|
+
|
|
46
|
+
return (self.width * pixel_size, self.height * pixel_size)
|
|
47
|
+
|
|
48
|
+
def scaled_screen_size_str(self, pixel_text: str = ""):
|
|
49
|
+
width, height = self.scaled_screen_size
|
|
50
|
+
|
|
51
|
+
return "".join([f"{width} x {height}", pixel_text])
|
|
52
|
+
|
|
53
|
+
def screen_size_str(self, pixel_text: str = ""):
|
|
54
|
+
return "".join([f"{self.width} x {self.height}", pixel_text])
|
|
55
|
+
|
|
56
|
+
def panel_size_str(self, pixel_text: str = ""):
|
|
57
|
+
return "".join([f"{self.options.cols} x {self.options.rows}", pixel_text])
|
|
58
|
+
|
|
41
59
|
@classmethod
|
|
42
60
|
def get_instance(cls, *args, **kwargs):
|
|
43
61
|
if cls.INSTANCE is None:
|
|
@@ -74,7 +92,7 @@ class BaseAdapter:
|
|
|
74
92
|
#############################################################
|
|
75
93
|
def _get_masked_image(self, pixels):
|
|
76
94
|
image = Image.fromarray(np.array(pixels, dtype=np.uint8), "RGB")
|
|
77
|
-
image = image.resize(self.
|
|
95
|
+
image = image.resize(self.scaled_screen_size, Image.NEAREST)
|
|
78
96
|
|
|
79
97
|
return Image.composite(image, self.__black, self.__mask)
|
|
80
98
|
|
|
@@ -87,7 +105,7 @@ class BaseAdapter:
|
|
|
87
105
|
return getattr(self, self.MASK_FNS.get(pixel_style, self.DEFAULT_MASK_FN))
|
|
88
106
|
|
|
89
107
|
def __draw_mask(self):
|
|
90
|
-
mask = Image.new("L", self.
|
|
108
|
+
mask = Image.new("L", self.scaled_screen_size)
|
|
91
109
|
|
|
92
110
|
draw_fn = self.__mask_fn(self.options.pixel_style)
|
|
93
111
|
draw_fn(mask)
|
|
@@ -96,7 +114,7 @@ class BaseAdapter:
|
|
|
96
114
|
|
|
97
115
|
def _draw_circle_mask(self, mask):
|
|
98
116
|
pixel_size = self.options.pixel_size
|
|
99
|
-
width, height = self.
|
|
117
|
+
width, height = self.scaled_screen_size
|
|
100
118
|
|
|
101
119
|
drawer = ImageDraw.Draw(mask)
|
|
102
120
|
|
|
@@ -110,7 +128,7 @@ class BaseAdapter:
|
|
|
110
128
|
|
|
111
129
|
def _draw_square_mask(self, mask):
|
|
112
130
|
pixel_size = self.options.pixel_size
|
|
113
|
-
width, height = self.
|
|
131
|
+
width, height = self.scaled_screen_size
|
|
114
132
|
|
|
115
133
|
drawer = ImageDraw.Draw(mask)
|
|
116
134
|
|
|
@@ -124,7 +142,7 @@ class BaseAdapter:
|
|
|
124
142
|
|
|
125
143
|
def _draw_real_mask(self, mask):
|
|
126
144
|
pixel_size = self.options.pixel_size
|
|
127
|
-
width, height = self.
|
|
145
|
+
width, height = self.scaled_screen_size
|
|
128
146
|
pixel_glow = self.options.pixel_glow
|
|
129
147
|
|
|
130
148
|
if pixel_glow == 0:
|
|
@@ -219,8 +237,8 @@ class BaseAdapter:
|
|
|
219
237
|
def __str__(self):
|
|
220
238
|
return self.DEBUG_TEXT_TEMPLATE.format(
|
|
221
239
|
version.__version__,
|
|
222
|
-
self.
|
|
223
|
-
self.
|
|
240
|
+
self.width,
|
|
241
|
+
self.height,
|
|
224
242
|
self.options.chain_length,
|
|
225
243
|
self.options.parallel,
|
|
226
244
|
self.options.pixel_size,
|
|
@@ -26,27 +26,26 @@
|
|
|
26
26
|
<tbody>
|
|
27
27
|
<tr>
|
|
28
28
|
<td>
|
|
29
|
-
|
|
29
|
+
Panel Size:
|
|
30
30
|
</td>
|
|
31
31
|
<td>
|
|
32
|
-
{{ adapter.
|
|
32
|
+
{{ adapter.panel_size_str(pixel_text="px") }}
|
|
33
33
|
</td>
|
|
34
34
|
</tr>
|
|
35
35
|
<tr>
|
|
36
36
|
<td>
|
|
37
|
-
|
|
37
|
+
Overall Size:
|
|
38
38
|
</td>
|
|
39
39
|
<td>
|
|
40
|
-
{{ adapter.
|
|
40
|
+
{{ adapter.screen_size_str(pixel_text="px") }}
|
|
41
41
|
</td>
|
|
42
|
-
</td>
|
|
43
42
|
</tr>
|
|
44
43
|
<tr>
|
|
45
44
|
<td>
|
|
46
45
|
Image Size:
|
|
47
46
|
</td>
|
|
48
47
|
<td>
|
|
49
|
-
{{ adapter.
|
|
48
|
+
{{ adapter.scaled_screen_size_str(pixel_text="px") }}
|
|
50
49
|
</td>
|
|
51
50
|
</tr>
|
|
52
51
|
<tr>
|
|
@@ -13,6 +13,11 @@ except ImportError:
|
|
|
13
13
|
|
|
14
14
|
class Pi5Adapter(BaseAdapter):
|
|
15
15
|
def __init__(self, width, height, options):
|
|
16
|
+
Logger.warning(
|
|
17
|
+
"The Pi5 adapter is deprecated. rpi-rgb-led-matrix now provides Raspberry Pi 5 support natively. "
|
|
18
|
+
"This adapter will be removed no later than July 1, 2026.",
|
|
19
|
+
)
|
|
20
|
+
|
|
16
21
|
super().__init__(width, height, options)
|
|
17
22
|
self.matrix = None
|
|
18
23
|
self.framebuffer = None
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/pygame_adapter.py
RENAMED
|
@@ -31,7 +31,7 @@ class PygameAdapter(BaseAdapter):
|
|
|
31
31
|
return
|
|
32
32
|
|
|
33
33
|
Logger.info(self.emulator_title)
|
|
34
|
-
self.__surface = pygame.display.set_mode(self.
|
|
34
|
+
self.__surface = pygame.display.set_mode(self.scaled_screen_size)
|
|
35
35
|
pygame.init()
|
|
36
36
|
|
|
37
37
|
self.__set_emulator_icon()
|
|
@@ -42,7 +42,7 @@ class PygameAdapter(BaseAdapter):
|
|
|
42
42
|
def draw_to_screen(self, pixels):
|
|
43
43
|
image = self._get_masked_image(pixels)
|
|
44
44
|
pygame_surface = pygame.image.fromstring(
|
|
45
|
-
image.tobytes(), self.
|
|
45
|
+
image.tobytes(), self.scaled_screen_size, "RGB"
|
|
46
46
|
)
|
|
47
47
|
self.__surface.blit(pygame_surface, (0, 0))
|
|
48
48
|
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/tkinter_adapter.py
RENAMED
|
@@ -24,12 +24,12 @@ class TkinterAdapter(BaseAdapter):
|
|
|
24
24
|
self.__set_emulator_icon()
|
|
25
25
|
self.__root.title(self.emulator_title)
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
self.__root.geometry("{}x{}".format(*
|
|
27
|
+
scaled_screen_size = self.scaled_screen_size
|
|
28
|
+
self.__root.geometry("{}x{}".format(*scaled_screen_size))
|
|
29
29
|
self.__canvas = tkinter.Canvas(
|
|
30
30
|
self.__root,
|
|
31
|
-
width=
|
|
32
|
-
height=
|
|
31
|
+
width=scaled_screen_size[0],
|
|
32
|
+
height=scaled_screen_size[1],
|
|
33
33
|
bd=0,
|
|
34
34
|
highlightthickness=0,
|
|
35
35
|
bg="black",
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/turtle_adapter.py
RENAMED
|
@@ -29,7 +29,7 @@ class TurtleAdapter(BaseAdapter):
|
|
|
29
29
|
return
|
|
30
30
|
|
|
31
31
|
Logger.info(self.emulator_title)
|
|
32
|
-
turtle.setup(*self.
|
|
32
|
+
turtle.setup(*self.scaled_screen_size)
|
|
33
33
|
turtle.title(self.emulator_title)
|
|
34
34
|
self.__pen = turtle.Turtle(visible=False)
|
|
35
35
|
self.__screen = self.__pen.getscreen()
|
|
@@ -8,15 +8,16 @@ from RGBMatrixEmulator.emulation.options import RGBMatrixOptions
|
|
|
8
8
|
class Canvas:
|
|
9
9
|
def __init__(self, options: RGBMatrixOptions) -> None:
|
|
10
10
|
self.options = options
|
|
11
|
+
self.__screen = options.screen
|
|
11
12
|
|
|
12
|
-
self.width
|
|
13
|
-
self.height = options.rows * options.parallel
|
|
13
|
+
self.width, self.height = self.__screen.pixel_buffer_size
|
|
14
14
|
|
|
15
15
|
# 3D numpy array -- rows (H), columns (W), 3-tuple RGB
|
|
16
16
|
self.__pdims = (self.height, self.width, 3)
|
|
17
17
|
|
|
18
|
+
screen_w, screen_h = self.__screen.screen_size
|
|
18
19
|
self.display_adapter = options.display_adapter.get_instance(
|
|
19
|
-
|
|
20
|
+
screen_w, screen_h, options
|
|
20
21
|
)
|
|
21
22
|
|
|
22
23
|
self.Clear()
|
|
@@ -88,7 +89,7 @@ class Canvas:
|
|
|
88
89
|
|
|
89
90
|
# These are delegated to the display adapter to handle specific implementation.
|
|
90
91
|
def draw_to_screen(self) -> None:
|
|
91
|
-
self.display_adapter.draw_to_screen(self.__pixels)
|
|
92
|
+
self.display_adapter.draw_to_screen(self.__screen.render(self.__pixels))
|
|
92
93
|
|
|
93
94
|
def check_for_quit_event(self) -> None:
|
|
94
95
|
self.display_adapter.check_for_quit_event()
|
|
@@ -8,8 +8,7 @@ class RGBMatrix:
|
|
|
8
8
|
def __init__(self, options: RGBMatrixOptions = RGBMatrixOptions()) -> None:
|
|
9
9
|
self.options = options
|
|
10
10
|
|
|
11
|
-
self.width
|
|
12
|
-
self.height = options.rows * options.parallel
|
|
11
|
+
self.width, self.height = options.screen.pixel_buffer_size
|
|
13
12
|
|
|
14
13
|
def CreateFrameCanvas(self) -> Canvas:
|
|
15
14
|
self.canvas = Canvas(options=self.options)
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/emulation/options.py
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from RGBMatrixEmulator.internal.emulator_config import RGBMatrixEmulatorConfig
|
|
2
|
+
from RGBMatrixEmulator.internal.screen import Screen
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class RGBMatrixOptions:
|
|
@@ -14,6 +15,7 @@ class RGBMatrixOptions:
|
|
|
14
15
|
self.brightness = 100
|
|
15
16
|
self.pwm_lsb_nanoseconds = 130
|
|
16
17
|
self.led_rgb_sequence = "RGB-EMULATED"
|
|
18
|
+
self.pixel_mapper_config = ""
|
|
17
19
|
self.show_refresh_rate = 0
|
|
18
20
|
self.gpio_slowdown = None
|
|
19
21
|
self.disable_hardware_pulsing = False
|
|
@@ -35,13 +37,13 @@ class RGBMatrixOptions:
|
|
|
35
37
|
# Pi5 Adapter
|
|
36
38
|
self.pi5 = emulator_config.pi5
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
self.rows * self.pixel_size * self.parallel,
|
|
42
|
-
)
|
|
40
|
+
@property
|
|
41
|
+
def screen(self) -> Screen:
|
|
42
|
+
"""The emulated screen model (mapper geometry + render).
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
Built lazily and cached, so it snapshots the configured options rather
|
|
45
|
+
than the defaults present at construction time."""
|
|
46
|
+
if not hasattr(self, "_screen"):
|
|
47
|
+
self._screen = Screen(self)
|
|
46
48
|
|
|
47
|
-
return
|
|
49
|
+
return self._screen
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from RGBMatrixEmulator.pixel_mappers import get_pixel_mapper
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Screen:
|
|
7
|
+
"""
|
|
8
|
+
The emulated screen: how a program's drawn canvas is mapped into the
|
|
9
|
+
displayed window.
|
|
10
|
+
|
|
11
|
+
It resolves the configured pixel mapper once and snapshots the resulting
|
|
12
|
+
geometry. The pipeline is:
|
|
13
|
+
|
|
14
|
+
pixel_buffer_size --(LUT)--> screen_size --(x pixel_size)--> scaled
|
|
15
|
+
|
|
16
|
+
Both sizes here are in LED units; scaling to on-screen pixels by pixel_size
|
|
17
|
+
is a rendering concern owned by the display adapter.
|
|
18
|
+
|
|
19
|
+
pixel_buffer_size -- what the program draws into (SetPixel/SetImage),
|
|
20
|
+
and the size reported as RGBMatrix.width/height
|
|
21
|
+
screen_size -- what the screen shows after the mapper's LUT; a
|
|
22
|
+
content transform may change the dimensions (e.g. a 90
|
|
23
|
+
degree rotation), so this can differ from the buffer
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, options) -> None:
|
|
27
|
+
base_w = options.cols * options.chain_length
|
|
28
|
+
base_h = options.rows * options.parallel
|
|
29
|
+
|
|
30
|
+
mapper = get_pixel_mapper(
|
|
31
|
+
options.pixel_mapper_config, options.chain_length, options.parallel
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
self.pixel_buffer_size = mapper.get_size_mapping(base_w, base_h)
|
|
35
|
+
self._lut, self.screen_size = mapper.build_lut(*self.pixel_buffer_size)
|
|
36
|
+
|
|
37
|
+
def render(self, pixels: np.ndarray) -> np.ndarray:
|
|
38
|
+
"""Map a pixel buffer to screen pixels via the mapper's LUT."""
|
|
39
|
+
if self._lut is None:
|
|
40
|
+
return pixels
|
|
41
|
+
|
|
42
|
+
vy_lut, vx_lut = self._lut
|
|
43
|
+
|
|
44
|
+
return pixels[vy_lut, vx_lut]
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
"""A gather lookup table: a pair of integer index arrays (vy_lut, vx_lut), each shaped
|
|
6
|
+
like the screen, holding the visible coordinate that feeds each screen pixel.
|
|
7
|
+
Apply with `screen_pixels = visible_pixels[vy_lut, vx_lut]`."""
|
|
8
|
+
LUT = tuple[np.ndarray, np.ndarray]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PixelMapper(abc.ABC):
|
|
12
|
+
"""
|
|
13
|
+
A pixel mapper, modeled on rpi-rgb-led-matrix's PixelMapper.
|
|
14
|
+
|
|
15
|
+
The emulator assumes panels are physically arranged as an upright,
|
|
16
|
+
rectangular matrix.
|
|
17
|
+
|
|
18
|
+
A pixel mapper may:
|
|
19
|
+
- resize the canvas relative to the base panel grid (V, U, StackToRow)
|
|
20
|
+
- transform the content the viewer sees within that size (Mirror, Rotate)
|
|
21
|
+
|
|
22
|
+
The emulator never drives real LEDs. Mappers describe where pixels
|
|
23
|
+
end up on screen and not physical panel arrangement.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
@abc.abstractmethod
|
|
27
|
+
def get_size_mapping(self, base_w: int, base_h: int) -> tuple[int, int]:
|
|
28
|
+
"""Return the screen (W, H) produced from the base panel grid size."""
|
|
29
|
+
|
|
30
|
+
@abc.abstractmethod
|
|
31
|
+
def map_visible_to_screen(
|
|
32
|
+
self, draw_w: int, draw_h: int, vx: np.ndarray, vy: np.ndarray
|
|
33
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
34
|
+
"""
|
|
35
|
+
Map drawn coordinates to displayed-screen coordinates, elementwise.
|
|
36
|
+
|
|
37
|
+
`vx` / `vy` are integer arrays of matching shape holding coordinates
|
|
38
|
+
in the drawn pixel buffer (the `get_size_mapping` size the user draws
|
|
39
|
+
into). The return is a pair of same-shape arrays holding screen
|
|
40
|
+
coordinates. `draw_w` / `draw_h` are the drawn-canvas dimensions.
|
|
41
|
+
|
|
42
|
+
Arrangement mappers that only resize return their inputs unchanged. A
|
|
43
|
+
content transform may change the dimensions (e.g. a 90 degree rotation).
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def build_lut(self, draw_w: int, draw_h: int) -> tuple[LUT | None, tuple[int, int]]:
|
|
47
|
+
"""
|
|
48
|
+
Compile this mapper's coordinate transform over a pixel buffer of
|
|
49
|
+
`draw_w` x `draw_h` into a LUT plus the resulting displayed (W, H).
|
|
50
|
+
"""
|
|
51
|
+
vy_grid, vx_grid = np.indices((draw_h, draw_w))
|
|
52
|
+
sx, sy = self.map_visible_to_screen(draw_w, draw_h, vx_grid, vy_grid)
|
|
53
|
+
|
|
54
|
+
# Identity content transform -> no remapping needed
|
|
55
|
+
if np.array_equal(sx, vx_grid) and np.array_equal(sy, vy_grid):
|
|
56
|
+
return None, (draw_w, draw_h)
|
|
57
|
+
|
|
58
|
+
display_w = int(sx.max()) + 1
|
|
59
|
+
display_h = int(sy.max()) + 1
|
|
60
|
+
|
|
61
|
+
vx_lut = np.empty((display_h, display_w), dtype=np.intp)
|
|
62
|
+
vy_lut = np.empty((display_h, display_w), dtype=np.intp)
|
|
63
|
+
vx_lut[sy, sx] = vx_grid
|
|
64
|
+
vy_lut[sy, sx] = vy_grid
|
|
65
|
+
|
|
66
|
+
return (vy_lut, vx_lut), (display_w, display_h)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def get_pixel_mapper(
|
|
70
|
+
config: str, chain_length: int = 1, parallel: int = 1
|
|
71
|
+
) -> PixelMapper:
|
|
72
|
+
"""
|
|
73
|
+
Build a single pixel mapper from a config string ("Name" or "Name:param").
|
|
74
|
+
|
|
75
|
+
Composition (semicolon-separated chains) is not handled yet; only the first
|
|
76
|
+
mapper in the string is used.
|
|
77
|
+
"""
|
|
78
|
+
from RGBMatrixEmulator.pixel_mappers.identity import IdentityMapper
|
|
79
|
+
from RGBMatrixEmulator.pixel_mappers.mirror import MirrorMapper
|
|
80
|
+
from RGBMatrixEmulator.pixel_mappers.rotate import RotateMapper
|
|
81
|
+
from RGBMatrixEmulator.pixel_mappers.stack_to_row import StackToRowMapper
|
|
82
|
+
from RGBMatrixEmulator.pixel_mappers.umapper import UMapper
|
|
83
|
+
from RGBMatrixEmulator.pixel_mappers.vmapper import VMapper
|
|
84
|
+
|
|
85
|
+
if not config:
|
|
86
|
+
return IdentityMapper()
|
|
87
|
+
|
|
88
|
+
spec = config.split(";")[0].strip()
|
|
89
|
+
name, _, param = spec.partition(":")
|
|
90
|
+
key = name.lower().replace("-", "")
|
|
91
|
+
param = param.strip()
|
|
92
|
+
|
|
93
|
+
if key == "mirror":
|
|
94
|
+
return MirrorMapper(horizontal=(param.upper() != "V"))
|
|
95
|
+
if key == "rotate":
|
|
96
|
+
return RotateMapper(angle=int(param) if param else 0)
|
|
97
|
+
if key == "vmapper":
|
|
98
|
+
return VMapper(chain_length, parallel, z=(param.upper() == "Z"))
|
|
99
|
+
if key == "umapper":
|
|
100
|
+
return UMapper(chain_length, parallel)
|
|
101
|
+
if key == "stacktorow":
|
|
102
|
+
return StackToRowMapper(chain_length, parallel)
|
|
103
|
+
|
|
104
|
+
return IdentityMapper()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from RGBMatrixEmulator.pixel_mappers import PixelMapper
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class IdentityMapper(PixelMapper):
|
|
7
|
+
"""No-op mapper. The drawn canvas and the displayed screen are identical."""
|
|
8
|
+
|
|
9
|
+
def get_size_mapping(self, base_w: int, base_h: int) -> tuple[int, int]:
|
|
10
|
+
return (base_w, base_h)
|
|
11
|
+
|
|
12
|
+
def map_visible_to_screen(
|
|
13
|
+
self, screen_w: int, screen_h: int, vx: np.ndarray, vy: np.ndarray
|
|
14
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
15
|
+
return (vx, vy)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from RGBMatrixEmulator.pixel_mappers import PixelMapper
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MirrorMapper(PixelMapper):
|
|
7
|
+
"""
|
|
8
|
+
Mirror the display horizontally (default) or vertically.
|
|
9
|
+
|
|
10
|
+
Vectorized port of rpi-rgb-led-matrix's MirrorPixelMapper ("Mirror").
|
|
11
|
+
Parameter "H" mirrors left/right, "V" mirrors top/bottom. Preserves dimensions.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, horizontal: bool = True):
|
|
15
|
+
self.horizontal = horizontal
|
|
16
|
+
|
|
17
|
+
def get_size_mapping(self, base_w: int, base_h: int) -> tuple[int, int]:
|
|
18
|
+
return (base_w, base_h)
|
|
19
|
+
|
|
20
|
+
def map_visible_to_screen(
|
|
21
|
+
self, screen_w: int, screen_h: int, vx: np.ndarray, vy: np.ndarray
|
|
22
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
23
|
+
if self.horizontal:
|
|
24
|
+
return (screen_w - 1 - vx, vy)
|
|
25
|
+
return (vx, screen_h - 1 - vy)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from RGBMatrixEmulator.pixel_mappers import PixelMapper
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RotateMapper(PixelMapper):
|
|
7
|
+
"""
|
|
8
|
+
Rotate the display by a multiple of 90 degrees.
|
|
9
|
+
|
|
10
|
+
Based on rpi-rgb-led-matrix's RotatePixelMapper ("Rotate"). With panels in a
|
|
11
|
+
normal upright arrangement the viewer sees the rotated image. At 90/270 degrees
|
|
12
|
+
the rotation also swaps the dimensions, so the drawn canvas and the displayed
|
|
13
|
+
screen have transposed dimensions.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, angle: int = 0):
|
|
17
|
+
if angle % 90 != 0:
|
|
18
|
+
raise ValueError("Rotate angle must be a multiple of 90 degrees")
|
|
19
|
+
self.angle = (angle + 360) % 360
|
|
20
|
+
|
|
21
|
+
def get_size_mapping(self, base_w: int, base_h: int) -> tuple[int, int]:
|
|
22
|
+
if self.angle % 180 == 0:
|
|
23
|
+
return (base_w, base_h)
|
|
24
|
+
return (base_h, base_w)
|
|
25
|
+
|
|
26
|
+
def map_visible_to_screen(
|
|
27
|
+
self, draw_w: int, draw_h: int, vx: np.ndarray, vy: np.ndarray
|
|
28
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
29
|
+
if self.angle == 90:
|
|
30
|
+
return (draw_h - 1 - vy, vx)
|
|
31
|
+
if self.angle == 180:
|
|
32
|
+
return (draw_w - 1 - vx, draw_h - 1 - vy)
|
|
33
|
+
if self.angle == 270:
|
|
34
|
+
return (vy, draw_w - 1 - vx)
|
|
35
|
+
return (vx, vy)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from RGBMatrixEmulator.pixel_mappers import PixelMapper
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class StackToRowMapper(PixelMapper):
|
|
7
|
+
"""
|
|
8
|
+
Lay parallel chains end-to-end as one wide horizontal row.
|
|
9
|
+
|
|
10
|
+
Based on rpi-rgb-led-matrix's StackToRowMapper ("StackToRow"). This changes
|
|
11
|
+
the dimensions of the drawn image but the emulator does not model physical
|
|
12
|
+
layout, so it is otherwise unchanged.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, chain_length: int = 1, parallel: int = 1):
|
|
16
|
+
self.chain_length = chain_length
|
|
17
|
+
self.bands = max(parallel, 1)
|
|
18
|
+
|
|
19
|
+
def get_size_mapping(self, base_w: int, base_h: int) -> tuple[int, int]:
|
|
20
|
+
return (base_w * self.bands, base_h // self.bands)
|
|
21
|
+
|
|
22
|
+
def map_visible_to_screen(
|
|
23
|
+
self, screen_w: int, screen_h: int, vx: np.ndarray, vy: np.ndarray
|
|
24
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
25
|
+
return (vx, vy)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from RGBMatrixEmulator.pixel_mappers import PixelMapper
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class UMapper(PixelMapper):
|
|
7
|
+
"""
|
|
8
|
+
U-arrangement mapper: a long chain folded back on itself into a U.
|
|
9
|
+
|
|
10
|
+
Based on rpi-rgb-led-matrix's UArrangementMapper ("U-mapper"). This changes
|
|
11
|
+
the dimensions of the drawn image but the emulator does not model physical
|
|
12
|
+
layout, so it is otherwise unchanged.
|
|
13
|
+
|
|
14
|
+
Requires an even chain of at least 2 panels.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, chain_length: int = 1, parallel: int = 1):
|
|
18
|
+
self.chain_length = chain_length
|
|
19
|
+
self.parallel = parallel
|
|
20
|
+
|
|
21
|
+
def get_size_mapping(self, base_w: int, base_h: int) -> tuple[int, int]:
|
|
22
|
+
return (base_w // 2, base_h * 2)
|
|
23
|
+
|
|
24
|
+
def map_visible_to_screen(
|
|
25
|
+
self, screen_w: int, screen_h: int, vx: np.ndarray, vy: np.ndarray
|
|
26
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
27
|
+
return (vx, vy)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from RGBMatrixEmulator.pixel_mappers import PixelMapper
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class VMapper(PixelMapper):
|
|
7
|
+
"""
|
|
8
|
+
Vertical mapper: a horizontal chain folded into vertical panel stacks.
|
|
9
|
+
|
|
10
|
+
Based on rpi-rgb-led-matrix's VerticalMapper ("V-mapper"). This changes
|
|
11
|
+
the dimensions of the drawn image but the emulator does not model physical
|
|
12
|
+
layout, so it is otherwise unchanged.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, chain_length: int = 1, parallel: int = 1, z: bool = False):
|
|
16
|
+
self.chain_length = chain_length
|
|
17
|
+
self.parallel = parallel
|
|
18
|
+
self.z = z
|
|
19
|
+
|
|
20
|
+
def get_size_mapping(self, base_w: int, base_h: int) -> tuple[int, int]:
|
|
21
|
+
screen_w = base_w * self.parallel // self.chain_length
|
|
22
|
+
screen_h = base_h * self.chain_length // self.parallel
|
|
23
|
+
return (screen_w, screen_h)
|
|
24
|
+
|
|
25
|
+
def map_visible_to_screen(
|
|
26
|
+
self, screen_w: int, screen_h: int, vx: np.ndarray, vy: np.ndarray
|
|
27
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
28
|
+
return (vx, vy)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/sixel_adapter.py
RENAMED
|
File without changes
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/adapters/terminal_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/emulation/__init__.py
RENAMED
|
File without changes
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/graphics/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/internal/adapter_loader.py
RENAMED
|
File without changes
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/internal/emulator_config.py
RENAMED
|
File without changes
|
{rgbmatrixemulator-0.16.4 → rgbmatrixemulator-0.17.0}/RGBMatrixEmulator/internal/pixel_style.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|