Compare commits
354 commits
archive-2.
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
8bc420da0e | ||
|
ad3337b3a3 | ||
|
27a319157d | ||
|
ebd8e7d589 | ||
|
807dd4cf9b | ||
|
f77a5cac9c | ||
|
e2f856d713 | ||
|
3960bbed88 | ||
|
d27901565c | ||
|
5454854b53 | ||
|
f2634319ab | ||
|
aa28e2a93b | ||
|
c4ecdcfeeb | ||
|
16f3566137 | ||
|
23853ce216 | ||
|
756002c8fa | ||
|
96ee0204e7 | ||
|
9be1c37da2 | ||
|
fdc9019d99 | ||
|
2f7de5b01c | ||
|
1c4d64aa15 | ||
|
1cccb7f3a3 | ||
|
628ffa8c33 | ||
|
95cda9dbb2 | ||
|
04a1727b23 | ||
|
c55ea57458 | ||
|
41cff62e42 | ||
|
fb9a99339b | ||
|
cee3dca28c | ||
|
e8d92c3ff8 | ||
|
89dc02998f | ||
|
459516b6db | ||
|
0829a284bd | ||
|
249325d532 | ||
|
9b2dd8f3d2 | ||
|
f0b4a6d081 | ||
|
228e742702 | ||
|
54ef607166 | ||
|
b7447b4930 | ||
|
eb755514cd | ||
|
f69fb3ec3a | ||
|
b67bd96067 | ||
|
625fe45e7b | ||
|
1e4b46e939 | ||
|
149b58778a | ||
|
a2b7559b3b | ||
|
da0672ffd8 | ||
|
2f55adbb26 | ||
|
c340c9acee | ||
|
9fb64592da | ||
|
cce11e392f | ||
|
96017b2aec | ||
|
2233394124 | ||
|
533f1507c5 | ||
|
9089c850a7 | ||
|
1e4c80a264 | ||
|
75e9478e7f | ||
|
692078352e | ||
|
987ca1c87d | ||
|
b0e85ff46a | ||
|
61960e1a9b | ||
|
3f0fdc72bc | ||
|
e1025d0df2 | ||
|
767a596ad8 | ||
|
722358ad2d | ||
|
bd555153e8 | ||
|
ad5e2338d0 | ||
|
17293b986b | ||
|
6a960121a5 | ||
|
c428e7ae4e | ||
|
610894cb87 | ||
|
aa9f9a7cef | ||
|
26dcb3f713 | ||
|
f7fa22ccbc | ||
|
d8deb4f041 | ||
|
9ee1346872 | ||
|
10ea729418 | ||
|
813cf53a33 | ||
|
7596b4bbf0 | ||
|
7a100a0a35 | ||
|
41cb8d3ce1 | ||
|
12f22832d5 | ||
|
8f62da2d19 | ||
|
c0b7ca62ff | ||
|
9940c078bd | ||
|
85fc041d54 | ||
|
8e6c69716c | ||
a468ea9d67 | |||
|
3c7173abab | ||
|
d11fe50fc6 | ||
|
4b950041b1 | ||
|
0c70417d70 | ||
|
8555ae1c79 | ||
|
66015862ac | ||
|
0aa1ebca25 | ||
|
9943fcd97d | ||
|
9b4926978e | ||
|
3fc222ff75 | ||
|
0429850835 | ||
|
3d7c2dfa4f | ||
|
41b9117307 | ||
|
9a5742d8e2 | ||
|
e00a622ed1 | ||
|
337f52cd34 | ||
|
32b39653e9 | ||
|
13be9eb9b7 | ||
|
b0df22fc24 | ||
|
e75716400e | ||
|
88a14afa1c | ||
|
71eacfc4f2 | ||
|
cab53b3ef3 | ||
|
ab7d98d7cc | ||
|
ebdf46da19 | ||
|
b56a8a7104 | ||
|
36a9a686ac | ||
|
8b08a28b21 | ||
|
e27231f5ca | ||
|
6ba7c22a63 | ||
|
fa2cb74ba1 | ||
|
85cdb61328 | ||
|
8b6fb5ef23 | ||
|
8deca4418d | ||
|
3a717cd7f0 | ||
|
811d474ef0 | ||
|
d2924444fa | ||
|
5d82b9890c | ||
|
ad41ddd03a | ||
|
004c45d01c | ||
|
ec290f3dba | ||
|
de344347d1 | ||
|
c2885498ee | ||
|
13ac40aaff | ||
|
102eab6eba | ||
|
8b77e3c793 | ||
|
84381838c7 | ||
|
f6fb33d651 | ||
|
ab24a61aba | ||
|
8098af9b66 | ||
|
4bff4955ca | ||
|
a185b72d59 | ||
|
4cb60e0180 | ||
|
2fe0cf0806 | ||
|
921392ce47 | ||
|
8aecce3a85 | ||
|
7c2d527dd8 | ||
|
b101ae6997 | ||
|
0a08debcab | ||
|
cc24c756c1 | ||
|
58610563ee | ||
|
e36b9d8a87 | ||
|
c31a9eaa66 | ||
|
e668d59cc4 | ||
|
53ecf54c56 | ||
|
bd7cc1e217 | ||
|
93b36adf72 | ||
|
1ac5a2209e | ||
|
8b196b452c | ||
|
64b950fabf | ||
|
9f2cb15b53 | ||
|
30b74a246b | ||
|
92bce305f6 | ||
|
a54688df9d | ||
|
3333f0b11d | ||
|
9d36abeeaf | ||
|
9308b59445 | ||
|
0b4d83db47 | ||
|
ab06cae02f | ||
|
4c78112024 | ||
|
7d1841e355 | ||
|
8c4d531db0 | ||
|
264d997618 | ||
|
817d81edae | ||
|
e34087e98b | ||
|
fe5d414825 | ||
|
1d21b165df | ||
|
e15f11ac46 | ||
|
8f5e2e143d | ||
|
112cf6ea47 | ||
|
8d82df45e1 | ||
|
20abf19582 | ||
|
642c064ffd | ||
|
326c9a0de7 | ||
|
efad4c1dfd | ||
|
2fcfaf6ac1 | ||
|
e7a5c1b005 | ||
|
aebccc3090 | ||
|
2b76af4a5a | ||
|
2852ce0e12 | ||
|
9e133918cf | ||
|
c11e5b00b0 | ||
|
63d9e9f9b3 | ||
|
1849aadda6 | ||
|
a5a893e65b | ||
|
548a6183a9 | ||
|
0e64e0d7a7 | ||
|
5bd551f78d | ||
|
edfadc7650 | ||
|
1bb96e0175 | ||
|
e807e622a8 | ||
|
f970b781b9 | ||
|
763aab6f09 | ||
|
da22841fc5 | ||
|
c804f0d7af | ||
|
5393f649fd | ||
|
cd47c77bb3 | ||
|
de27834976 | ||
|
862b4d2f22 | ||
|
c083b94ac5 | ||
|
d345aaf8c4 | ||
|
2abd685b7a | ||
|
fd88ef48d8 | ||
|
85640b2bca | ||
|
14a685e44c | ||
|
57d88db8ae | ||
|
19739da67f | ||
|
e19898280a | ||
|
b262ddeaa1 | ||
|
9a83f26a6f | ||
|
6cd5c72a23 | ||
|
48d89f9d3f | ||
|
1ec3eaecea | ||
|
7bd6c7028f | ||
|
1ee90bcf4a | ||
|
b72de03a74 | ||
|
a5db9e0665 | ||
|
6fbf31ea1c | ||
|
70c2ad6c06 | ||
|
59071660fc | ||
|
cd882d16fc | ||
|
5a12ff59a2 | ||
|
d87ffe3be4 | ||
|
79e1897aed | ||
|
859a250799 | ||
|
29e04d916a | ||
|
0a44e210be | ||
|
da22bb835b | ||
|
62eafc3efb | ||
|
37dd233339 | ||
|
ecc6ef169a | ||
|
fe89cc9e17 | ||
|
15763b12b1 | ||
|
a0f9ab6830 | ||
|
f0929dc135 | ||
|
fbce0fdcbc | ||
|
c23e887818 | ||
|
fd5aba7054 | ||
|
572e310fc4 | ||
|
a85b0e649f | ||
|
fda92b77af | ||
|
9901c2352d | ||
|
2c86ceee73 | ||
|
6378731cbc | ||
|
0f62898bae | ||
|
9b706f9599 | ||
|
035e0e0d2f | ||
|
a775b3a62e | ||
|
28acbea6d3 | ||
|
1ca5ee92c8 | ||
|
15a5aa4ec1 | ||
|
420f653552 | ||
|
21109b74ee | ||
|
cc68027d0d | ||
|
fe1ebbe40f | ||
|
ab13f2692d | ||
|
960e7b1768 | ||
|
bc3f2ce5c0 | ||
|
84c2fbf755 | ||
|
2a85977eba | ||
|
e7f2ac6805 | ||
|
0323b728ae | ||
|
51e44ce4b8 | ||
|
f6ac9357c9 | ||
|
734816f5f3 | ||
|
946206f050 | ||
|
a367a055c9 | ||
|
c66b592e9f | ||
|
ace8d938ee | ||
|
8337c7cf7e | ||
|
58757c1975 | ||
|
9d4d12a43b | ||
|
f074b03e7d | ||
|
dcdd3e8cad | ||
|
9c5737ddf1 | ||
|
76a69e9f84 | ||
|
71a584fb52 | ||
|
9eacd9a656 | ||
|
ff5d69a4fd | ||
|
655b198a78 | ||
|
6687ee7d82 | ||
|
ffd196d9e5 | ||
|
c1d85fad42 | ||
|
4d0cbe437d | ||
|
502110d4bb | ||
|
54ede42310 | ||
|
5f13a3abff | ||
|
9ca210d3ac | ||
|
765d99ea63 | ||
|
e1e2991076 | ||
|
182653727d | ||
|
8d01099fa7 | ||
|
56f47f80ed | ||
|
f9ff4b4078 | ||
|
ce2b6264dd | ||
|
81ee41e15a | ||
|
a2d9e3e035 | ||
|
03a67c2f11 | ||
|
4db9e23b36 | ||
|
5d38b5215a | ||
|
9c47144ec6 | ||
|
642729b5f9 | ||
|
b8367d95d2 | ||
|
361d410ee3 | ||
|
dd15dabf16 | ||
|
f47b7f5723 | ||
|
2760b0098a | ||
|
3c46c7aeb9 | ||
|
2d5d06129a | ||
|
84c250c668 | ||
|
69686a3747 | ||
|
1d29c7b520 | ||
|
be2102c3bc | ||
|
997f3840ba | ||
|
914f8676ec | ||
|
23dd196013 | ||
|
6a6da49c1c | ||
|
99c2c569ef | ||
|
68528d57d8 | ||
|
a993a18cca | ||
|
7c11aaf53e | ||
|
97455a4546 | ||
|
4a9160904a | ||
|
e9405a9ece | ||
|
f9c609b88a | ||
|
f8f28e8385 | ||
|
0cba8a7345 | ||
|
d58ae512b4 | ||
|
062154b4d8 | ||
|
067923a3eb | ||
|
e2b9b6db36 | ||
|
37c55c8708 | ||
|
7628be00c2 | ||
|
157077ab33 | ||
|
8b2e31b1c5 | ||
|
2abb834f82 | ||
|
0744789b26 | ||
|
05fe7eb7d1 | ||
|
cd2430b158 | ||
|
4772d1d643 | ||
|
69e75cde12 | ||
|
f0a5d1ad54 | ||
|
30f0014b0c | ||
|
2db8f26659 | ||
|
b490699eab | ||
|
ebe75dcaba |
11
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
48
.github/workflows/esp-idf-5.1.2_with-gfx.yml
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
name: esp-idf 5.1.2 with Adafruit GFX Library
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'doc/**'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'doc/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: esp-idf with Adafruit GFX
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Checkout ESP32-HUB75-MatrixPanel-I2S-DMA component
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: 'examples/esp-idf/with-gfx/components/ESP32-HUB75-MatrixPanel-I2S-DMA'
|
||||
- name: Checkout Adafruit-GFX-Library repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'adafruit/Adafruit-GFX-Library'
|
||||
path: 'examples/esp-idf/with-gfx/components/Adafruit-GFX-Library'
|
||||
- name: Checkout Adafruit_BusIO repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'adafruit/Adafruit_BusIO'
|
||||
path: 'examples/esp-idf/with-gfx/components/Adafruit_BusIO'
|
||||
- name: Checkout arduino-esp32 repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'espressif/arduino-esp32'
|
||||
path: 'examples/esp-idf/with-gfx/components/arduino'
|
||||
- name: esp-idf build
|
||||
uses: espressif/esp-idf-ci-action@v1
|
||||
with:
|
||||
esp_idf_version: v5.1.2
|
||||
target: esp32
|
||||
path: 'examples/esp-idf/with-gfx'
|
33
.github/workflows/esp-idf-5.1.2_without-gfx.yml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: esp-idf 5.1.2 without Adafruit GFX Library
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'doc/**'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'doc/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: esp-idf 5.1.2 without Adafruit GFX
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Checkout ESP32-HUB75-MatrixPanel-I2S-DMA component
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: 'examples/esp-idf/without-gfx/components/ESP32-HUB75-MatrixPanel-I2S-DMA'
|
||||
- name: esp-idf build
|
||||
uses: espressif/esp-idf-ci-action@v1
|
||||
with:
|
||||
esp_idf_version: v5.1.2
|
||||
target: esp32
|
||||
path: 'examples/esp-idf/without-gfx'
|
64
.github/workflows/pio_arduino_build.yml
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
# Build examples with Platformio
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
# https://docs.platformio.org/en/latest/integration/ci/github-actions.html
|
||||
|
||||
name: PlatformIO 6.1.11 Arduino CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, dev ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'doc/**'
|
||||
pull_request:
|
||||
branches: [ master, dev ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'doc/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
framework: ["Arduino", "IDF"]
|
||||
no_gfx: ["", -DNO_GFX]
|
||||
# no_fast_functions: ["", -DNO_FAST_FUNCTIONS]
|
||||
# no_cie1931: ["", -DNO_CIE1931]
|
||||
# virtual_panel: ["", -DVIRTUAL_PANE]
|
||||
example:
|
||||
- "examples/PIO_TestPatterns"
|
||||
# exclude:
|
||||
# - no_fast_functions: ""
|
||||
# virtual_panel: -DVIRTUAL_PANE
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Cache pip and platformio
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio/.cache
|
||||
key: ${{ runner.os }}-pio
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Platformio
|
||||
run: pip install --upgrade platformio==6.1.11
|
||||
- name: Run PlatformIO CI (Arduino)
|
||||
if: ${{ matrix.framework == 'Arduino'}}
|
||||
env:
|
||||
PLATFORMIO_BUILD_FLAGS: ${{ matrix.no_gfx }} ${{ matrix.no_fast_functions }} ${{ matrix.no_cie1931 }} ${{ matrix.virtual_panel }}
|
||||
PLATFORMIO_CI_SRC: ${{ matrix.example }}
|
||||
run: pio ci -e esp32 -c ${{ matrix.example }}/platformio.ini
|
||||
- name: Run PlatformIO CI (ESP-IDF)
|
||||
if: ${{ matrix.framework == 'IDF'}}
|
||||
env:
|
||||
PLATFORMIO_BUILD_FLAGS: -DIDF_BUILD ${{ matrix.no_gfx }} ${{ matrix.no_fast_functions }} ${{ matrix.no_cie1931 }} ${{ matrix.virtual_panel }}
|
||||
# pio ci doesn't use our sdkconfig, so we have to use pio run
|
||||
#run: pio run -d ${{ matrix.example }} -e esp32idf -c ${{ matrix.example }}/platformio.ini
|
||||
run: pio run -d ${{ matrix.example }}
|
48
.github/workflows/pio_build.yml
vendored
|
@ -1,48 +0,0 @@
|
|||
# Build examples with Platformio
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
# https://docs.platformio.org/en/latest/integration/ci/github-actions.html
|
||||
|
||||
name: PlatformIO CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, dev ]
|
||||
pull_request:
|
||||
branches: [ master, dev ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
example:
|
||||
- "examples/PIO_TestPatterns"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: ${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Platformio
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pio update
|
||||
- name: Run PlatformIO
|
||||
env:
|
||||
PLATFORMIO_CI_SRC: ${{ matrix.example }}
|
||||
run: |
|
||||
pio ci -c ${{ matrix.example }}/platformio.ini
|
|
@ -3,10 +3,40 @@
|
|||
# MIT License
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
idf_component_register(SRCS "esp32_i2s_parallel_dma.c" "ESP32-HUB75-MatrixPanel-I2S-DMA.cpp" "ESP32-HUB75-MatrixPanel-leddrivers.cpp"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES arduino Adafruit-GFX-Library)
|
||||
if(ARDUINO_ARCH_ESP32 OR CONFIG_ESP32_HUB75_USE_GFX)
|
||||
list(APPEND build_dependencies arduino Adafruit-GFX-Library)
|
||||
else()
|
||||
list(APPEND build_dependencies esp_lcd driver)
|
||||
endif()
|
||||
|
||||
if(${target} STREQUAL "esp32s3")
|
||||
list(APPEND extra_srcs src/platforms/${target}/gdma_lcd_parallel16.cpp)
|
||||
|
||||
# Required by gdma_lcd_parallel16.cpp
|
||||
if (NOT esp_lcd IN_LIST build_dependencies)
|
||||
list(APPEND build_dependencies esp_lcd)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "src/platforms/esp32/esp32_i2s_parallel_dma.cpp" "src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp" "src/ESP32-HUB75-MatrixPanel-leddrivers.cpp" ${extra_srcs}
|
||||
INCLUDE_DIRS "./src"
|
||||
)
|
||||
|
||||
# Dependencies cannot be added to the REQUIRES argument of `idf_component_register` because (according to the build process
|
||||
# listed at https://docs.espressif.com/projects/esp-idf/en/v4.2/esp32/api-guides/build-system.html#build-process)
|
||||
# `idf_component_register` is processed during the "Enumeration" stage which happens before the sdkconfig file is loaded
|
||||
# in the "Processing" stage. So if dependencies are going to be loaded based on certain CONFIG_* variables we must
|
||||
# use `target_link_libraries` instead. This is the method used by Arduino's CMakeLists.txt file.
|
||||
idf_build_get_property(components BUILD_COMPONENTS)
|
||||
foreach(component_name IN LISTS build_dependencies)
|
||||
if (NOT ${component_name} IN_LIST components)
|
||||
message(FATAL_ERROR "Missing component: ${component_name}")
|
||||
endif()
|
||||
idf_component_get_property(lib_name ${component_name} COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC ${lib_name})
|
||||
endforeach()
|
||||
|
||||
# In case you are running into issues with "missing" header files from 3rd party libraries
|
||||
# you can add them to the REQUIRES section above. If you use some of the build options below
|
||||
|
@ -16,6 +46,18 @@ idf_component_register(SRCS "esp32_i2s_parallel_dma.c" "ESP32-HUB75-MatrixPanel-
|
|||
# target_compile_options(${COMPONENT_TARGET} PUBLIC -DUSE_GFX_ROOT)
|
||||
# target_compile_options(${COMPONENT_TARGET} PUBLIC -DNO_GFX)
|
||||
|
||||
# esp-idf does not have any GFX library support yet, so we need to define NO_GFX
|
||||
if(ARDUINO_ARCH_ESP32 OR CONFIG_ESP32_HUB75_USE_GFX)
|
||||
else()
|
||||
target_compile_options(${COMPONENT_TARGET} PUBLIC -DNO_GFX)
|
||||
if(${target} STREQUAL "esp32s3")
|
||||
# Don't enable PSRAM based framebuffer just because it's an S3.
|
||||
# This is an advanced option and should only be used with an S3 with Octal-SPI RAM.
|
||||
# target_compile_options(${COMPONENT_TARGET} PUBLIC -DSPIRAM_FRAMEBUFFER)
|
||||
target_compile_options(${COMPONENT_TARGET} PUBLIC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# You can also use multiple options like this
|
||||
# target_compile_options(${COMPONENT_TARGET} PUBLIC -DNO_GFX -DNO_FAST_FUNCTIONS)
|
||||
|
||||
|
|
|
@ -1,820 +0,0 @@
|
|||
#ifndef _ESP32_RGB_64_32_MATRIX_PANEL_I2S_DMA
|
||||
#define _ESP32_RGB_64_32_MATRIX_PANEL_I2S_DMA
|
||||
/***************************************************************************************/
|
||||
/* Core ESP32 hardware / idf includes! */
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp32_i2s_parallel_dma.h"
|
||||
|
||||
#ifdef USE_GFX_ROOT
|
||||
#include <FastLED.h>
|
||||
#include "GFX.h" // Adafruit GFX core class -> https://github.com/mrfaptastic/GFX_Root
|
||||
#elif !defined NO_GFX
|
||||
#include "Adafruit_GFX.h" // Adafruit class with all the other stuff
|
||||
#endif
|
||||
|
||||
/*******************************************************************************************
|
||||
* COMPILE-TIME OPTIONS - MUST BE PROVIDED as part of PlatformIO project build_flags. *
|
||||
* Changing the values just here won't work - as defines needs to persist beyond the scope *
|
||||
* of just this file. *
|
||||
*******************************************************************************************/
|
||||
/* Enable serial debugging of the library, to see how memory is allocated etc. */
|
||||
//#define SERIAL_DEBUG 1
|
||||
|
||||
/* Do NOT build additional methods optimized for fast drawing,
|
||||
* i.e. Adafruits drawFastHLine, drawFastVLine, etc... */
|
||||
//#define NO_FAST_FUNCTIONS
|
||||
|
||||
/* Use GFX_Root (https://github.com/mrfaptastic/GFX_Root) instead of Adafruit_GFX library.
|
||||
* > Removes Bus_IO & Wire.h library dependencies.
|
||||
* > Provides 24bpp (CRGB) colour support for Adafruit_GFX functions like drawCircle etc.
|
||||
* > Requires FastLED.h
|
||||
*/
|
||||
//#define USE_GFX_ROOT 1
|
||||
|
||||
/* Physical / Chained HUB75(s) RGB pixel WIDTH and HEIGHT.
|
||||
*
|
||||
* This library has been tested with a 64x32 and 64x64 RGB panels.
|
||||
* If you want to chain two or more of these horizontally to make a 128x32 panel
|
||||
* you can do so with the cable and then set the CHAIN_LENGTH to '2'.
|
||||
*
|
||||
* Also, if you use a 64x64 panel, then set the MATRIX_HEIGHT to '64' and an E_PIN; it will work!
|
||||
*
|
||||
* All of this is memory permitting of course (dependant on your sketch etc.) ...
|
||||
*
|
||||
*/
|
||||
#ifndef MATRIX_WIDTH
|
||||
#define MATRIX_WIDTH 64 // Single panel of 64 pixel width
|
||||
#endif
|
||||
|
||||
#ifndef MATRIX_HEIGHT
|
||||
#define MATRIX_HEIGHT 32 // CHANGE THIS VALUE to 64 IF USING 64px HIGH panel(s) with E PIN
|
||||
#endif
|
||||
|
||||
#ifndef CHAIN_LENGTH
|
||||
#define CHAIN_LENGTH 1 // Number of modules chained together, i.e. 4 panels chained result in virtualmatrix 64x4=256 px long
|
||||
#endif
|
||||
|
||||
/* ESP32 Default Pin definition. You can change this, but best if you keep it as is and provide custom pin mappings
|
||||
* as part of the begin(...) function.
|
||||
*/
|
||||
// Default pin mapping for ESP32-S2 and ESP32-S3
|
||||
#ifdef ESP32_SXXX
|
||||
|
||||
#define R1_PIN_DEFAULT 45
|
||||
#define G1_PIN_DEFAULT 42
|
||||
#define B1_PIN_DEFAULT 41
|
||||
#define R2_PIN_DEFAULT 40
|
||||
#define G2_PIN_DEFAULT 39
|
||||
#define B2_PIN_DEFAULT 38
|
||||
#define A_PIN_DEFAULT 37
|
||||
#define B_PIN_DEFAULT 36
|
||||
#define C_PIN_DEFAULT 35
|
||||
#define D_PIN_DEFAULT 34
|
||||
#define E_PIN_DEFAULT -1 // required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32
|
||||
#define LAT_PIN_DEFAULT 26
|
||||
#define OE_PIN_DEFAULT 21
|
||||
#define CLK_PIN_DEFAULT 33
|
||||
|
||||
// Else use default pin mapping for ESP32 Original WROOM module.
|
||||
#else
|
||||
|
||||
#define R1_PIN_DEFAULT 25
|
||||
#define G1_PIN_DEFAULT 26
|
||||
#define B1_PIN_DEFAULT 27
|
||||
#define R2_PIN_DEFAULT 14
|
||||
#define G2_PIN_DEFAULT 12
|
||||
#define B2_PIN_DEFAULT 13
|
||||
|
||||
#define A_PIN_DEFAULT 23
|
||||
#define B_PIN_DEFAULT 19
|
||||
#define C_PIN_DEFAULT 5
|
||||
#define D_PIN_DEFAULT 17
|
||||
#define E_PIN_DEFAULT -1 // IMPORTANT: Change to a valid pin if using a 64x64px panel.
|
||||
|
||||
#define LAT_PIN_DEFAULT 4
|
||||
#define OE_PIN_DEFAULT 15
|
||||
#define CLK_PIN_DEFAULT 16
|
||||
|
||||
#endif
|
||||
|
||||
// Interesting Fact: We end up using a uint16_t to send data in parallel to the HUB75... but
|
||||
// given we only map to 14 physical output wires/bits, we waste 2 bits.
|
||||
|
||||
/***************************************************************************************/
|
||||
/* Do not change definitions below unless you pretty sure you know what you are doing! */
|
||||
|
||||
// RGB Panel Constants / Calculated Values
|
||||
#ifndef MATRIX_ROWS_IN_PARALLEL
|
||||
#define MATRIX_ROWS_IN_PARALLEL 2
|
||||
#endif
|
||||
|
||||
// 8bit per RGB color = 24 bit/per pixel,
|
||||
// might be reduced to save DMA RAM
|
||||
#ifndef PIXEL_COLOR_DEPTH_BITS
|
||||
#define PIXEL_COLOR_DEPTH_BITS 8
|
||||
#endif
|
||||
|
||||
#define COLOR_CHANNELS_PER_PIXEL 3
|
||||
|
||||
// #define NO_CIE1931
|
||||
|
||||
|
||||
/***************************************************************************************/
|
||||
/* Definitions below should NOT be ever changed without rewriting library logic */
|
||||
#define ESP32_I2S_DMA_MODE I2S_PARALLEL_WIDTH_16 // From esp32_i2s_parallel_v2.h = 16 bits in parallel
|
||||
#define ESP32_I2S_DMA_STORAGE_TYPE uint16_t // DMA output of one uint16_t at a time.
|
||||
#define CLKS_DURING_LATCH 0 // Not (yet) used.
|
||||
|
||||
// Panel Upper half RGB (numbering according to order in DMA gpio_bus configuration)
|
||||
#define BITS_RGB1_OFFSET 0 // Start point of RGB_X1 bits
|
||||
#define BIT_R1 (1<<0)
|
||||
#define BIT_G1 (1<<1)
|
||||
#define BIT_B1 (1<<2)
|
||||
|
||||
// Panel Lower half RGB
|
||||
#define BITS_RGB2_OFFSET 3 // Start point of RGB_X2 bits
|
||||
#define BIT_R2 (1<<3)
|
||||
#define BIT_G2 (1<<4)
|
||||
#define BIT_B2 (1<<5)
|
||||
|
||||
// Panel Control Signals
|
||||
#define BIT_LAT (1<<6)
|
||||
#define BIT_OE (1<<7)
|
||||
|
||||
// Panel GPIO Pin Addresses (A, B, C, D etc..)
|
||||
#define BITS_ADDR_OFFSET 8 // Start point of address bits
|
||||
#define BIT_A (1<<8)
|
||||
#define BIT_B (1<<9)
|
||||
#define BIT_C (1<<10)
|
||||
#define BIT_D (1<<11)
|
||||
#define BIT_E (1<<12)
|
||||
|
||||
// BitMasks are pre-computed based on the above #define's for performance.
|
||||
#define BITMASK_RGB1_CLEAR (0b1111111111111000) // inverted bitmask for R1G1B1 bit in pixel vector
|
||||
#define BITMASK_RGB2_CLEAR (0b1111111111000111) // inverted bitmask for R2G2B2 bit in pixel vector
|
||||
#define BITMASK_RGB12_CLEAR (0b1111111111000000) // inverted bitmask for R1G1B1R2G2B2 bit in pixel vector
|
||||
#define BITMASK_CTRL_CLEAR (0b1110000000111111) // inverted bitmask for control bits ABCDE,LAT,OE in pixel vector
|
||||
#define BITMASK_OE_CLEAR (0b1111111101111111) // inverted bitmask for control bit OE in pixel vector
|
||||
|
||||
// How many clock cycles to blank OE before/after LAT signal change, default is 1 clock
|
||||
#define DEFAULT_LAT_BLANKING 1
|
||||
// Max clock cycles to blank OE before/after LAT signal change
|
||||
#define MAX_LAT_BLANKING 4
|
||||
|
||||
/***************************************************************************************/
|
||||
// Check compile-time only options
|
||||
#if PIXEL_COLOR_DEPTH_BITS > 8
|
||||
#error "Pixel color depth bits cannot be greater than 8."
|
||||
#elif PIXEL_COLOR_DEPTH_BITS < 2
|
||||
#error "Pixel color depth bits cannot be less than 2."
|
||||
#endif
|
||||
|
||||
/* This library is designed to take an 8 bit / 1 byte value (0-255) for each R G B colour sub-pixel.
|
||||
* The PIXEL_COLOR_DEPTH_BITS should always be '8' as a result.
|
||||
* However, if the library is to be used with lower colour depth (i.e. 6 bit colour), then we need to ensure the 8-bit value passed to the colour masking
|
||||
* is adjusted accordingly to ensure the LSB's are shifted left to MSB, by the difference. Otherwise the colours will be all screwed up.
|
||||
*/
|
||||
#if PIXEL_COLOR_DEPTH_BITS != 8
|
||||
static constexpr uint8_t const MASK_OFFSET = 8-PIXEL_COLOR_DEPTH_BITS;
|
||||
#endif
|
||||
|
||||
/***************************************************************************************/
|
||||
|
||||
/** @brief - Structure holds raw DMA data to drive TWO full rows of pixels spanning through all chained modules
|
||||
* Note: sizeof(data) must be multiple of 32 bits, as ESP32 DMA linked list buffer address pointer must be word-aligned
|
||||
*/
|
||||
struct rowBitStruct {
|
||||
const size_t width;
|
||||
const uint8_t color_depth;
|
||||
const bool double_buff;
|
||||
ESP32_I2S_DMA_STORAGE_TYPE *data;
|
||||
|
||||
/** @brief - returns size of row of data vectorfor a SINGLE buff
|
||||
* size (in bytes) of a vector holding full DMA data for a row of pixels with _dpth color bits
|
||||
* a SINGLE buffer only size is accounted, when using double buffers it actually takes twice as much space
|
||||
* but returned size is for a half of double-buffer
|
||||
*
|
||||
* default - returns full data vector size for a SINGLE buff
|
||||
*
|
||||
*/
|
||||
size_t size(uint8_t _dpth=0 ) { if (!_dpth) _dpth = color_depth; return width * _dpth * sizeof(ESP32_I2S_DMA_STORAGE_TYPE); };
|
||||
|
||||
/** @brief - returns pointer to the row's data vector beginning at pixel[0] for _dpth color bit
|
||||
* default - returns pointer to the data vector's head
|
||||
* NOTE: this call might be very slow in loops. Due to poor instruction caching in esp32 it might be required a reread from flash
|
||||
* every loop cycle, better use inlined #define instead in such cases
|
||||
*/
|
||||
ESP32_I2S_DMA_STORAGE_TYPE* getDataPtr(const uint8_t _dpth=0, const bool buff_id=0) { return &(data[_dpth*width + buff_id*(width*color_depth)]); };
|
||||
|
||||
// constructor - allocates DMA-capable memory to hold the struct data
|
||||
rowBitStruct(const size_t _width, const uint8_t _depth, const bool _dbuff) : width(_width), color_depth(_depth), double_buff(_dbuff) {
|
||||
data = (ESP32_I2S_DMA_STORAGE_TYPE *)heap_caps_malloc( size()+size()*double_buff, MALLOC_CAP_DMA);
|
||||
}
|
||||
~rowBitStruct() { delete data;}
|
||||
};
|
||||
|
||||
|
||||
/* frameStruct
|
||||
* Note: A 'frameStruct' contains ALL the data for a full-frame (i.e. BOTH 2x16-row frames are
|
||||
* are contained in parallel within the one uint16_t that is sent in parallel to the HUB75).
|
||||
*
|
||||
* This structure isn't actually allocated in one memory block anymore, as the library now allocates
|
||||
* memory per row (per rowColorDepthStruct) instead.
|
||||
*/
|
||||
struct frameStruct {
|
||||
uint8_t rows=0; // number of rows held in current frame, not used actually, just to keep the idea of struct
|
||||
std::vector<std::shared_ptr<rowBitStruct> > rowBits;
|
||||
};
|
||||
|
||||
/***************************************************************************************/
|
||||
//C/p'ed from https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/
|
||||
// Example calculator: https://gist.github.com/mathiasvr/19ce1d7b6caeab230934080ae1f1380e
|
||||
// need to make sure this would end up in RAM for fastest access
|
||||
#ifndef NO_CIE1931
|
||||
static const uint8_t DRAM_ATTR lumConvTab[]={
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 27, 27, 28, 28, 29, 30, 30, 31, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 38, 39, 40, 41, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 95, 96, 98, 99, 100, 102, 103, 105, 106, 107, 109, 110, 112, 113, 115, 116, 118, 120, 121, 123, 124, 126, 128, 129, 131, 133, 134, 136, 138, 139, 141, 143, 145, 146, 148, 150, 152, 154, 156, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 192, 194, 196, 198, 200, 203, 205, 207, 209, 212, 214, 216, 218, 221, 223, 226, 228, 230, 233, 235, 238, 240, 243, 245, 248, 250, 253, 255, 255};
|
||||
#endif
|
||||
|
||||
/** @brief - configuration values for HUB75_I2S driver
|
||||
* This structure holds configuration vars that are used as
|
||||
* an initialization values when creating an instance of MatrixPanel_I2S_DMA object.
|
||||
* All params have it's default values.
|
||||
*/
|
||||
struct HUB75_I2S_CFG {
|
||||
|
||||
/**
|
||||
* Enumeration of hardware-specific chips
|
||||
* used to drive matrix modules
|
||||
*/
|
||||
enum shift_driver {SHIFTREG=0, FM6124, FM6126A, ICN2038S, MBI5124, SM5266P};
|
||||
|
||||
/**
|
||||
* I2S clock speed selector
|
||||
*/
|
||||
enum clk_speed {HZ_8M=8000000, HZ_10M=10000000, HZ_20M=20000000};
|
||||
|
||||
// Structure Variables
|
||||
|
||||
// physical width of a single matrix panel module (in pixels, usually it is 64 ;) )
|
||||
uint16_t mx_width;
|
||||
// physical height of a single matrix panel module (in pixels, usually almost always it is either 32 or 64)
|
||||
uint16_t mx_height;
|
||||
// number of chained panels regardless of the topology, default 1 - a single matrix module
|
||||
uint16_t chain_length;
|
||||
|
||||
/**
|
||||
* GPIO pins mapping
|
||||
*/
|
||||
struct i2s_pins{
|
||||
int8_t r1, g1, b1, r2, g2, b2, a, b, c, d, e, lat, oe, clk;
|
||||
} gpio;
|
||||
|
||||
// Matrix driver chip type - default is a plain shift register
|
||||
shift_driver driver;
|
||||
// I2S clock speed
|
||||
clk_speed i2sspeed;
|
||||
// use DMA double buffer (twice as much RAM required)
|
||||
bool double_buff;
|
||||
// How many clock cycles to blank OE before/after LAT signal change, default is 1 clock
|
||||
uint8_t latch_blanking;
|
||||
|
||||
/**
|
||||
* I2S clock phase
|
||||
* 0 - data lines are clocked with negative edge
|
||||
* Clk /¯\_/¯\_/
|
||||
* LAT __/¯¯¯\__
|
||||
* EO ¯¯¯¯¯¯\___
|
||||
*
|
||||
* 1 - data lines are clocked with positive edge (default now as of 10 June 2021)
|
||||
* https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/130
|
||||
* Clk \_/¯\_/¯\
|
||||
* LAT __/¯¯¯\__
|
||||
* EO ¯¯¯¯¯¯\__
|
||||
*
|
||||
*/
|
||||
bool clkphase;
|
||||
|
||||
// Minimum refresh / scan rate needs to be configured on start due to LSBMSB_TRANSITION_BIT calculation in allocateDMAmemory()
|
||||
uint8_t min_refresh_rate;
|
||||
|
||||
// struct constructor
|
||||
HUB75_I2S_CFG (
|
||||
uint16_t _w = MATRIX_WIDTH,
|
||||
uint16_t _h = MATRIX_HEIGHT,
|
||||
uint16_t _chain = CHAIN_LENGTH,
|
||||
i2s_pins _pinmap = {
|
||||
R1_PIN_DEFAULT, G1_PIN_DEFAULT, B1_PIN_DEFAULT, R2_PIN_DEFAULT, G2_PIN_DEFAULT, B2_PIN_DEFAULT,
|
||||
A_PIN_DEFAULT, B_PIN_DEFAULT, C_PIN_DEFAULT, D_PIN_DEFAULT, E_PIN_DEFAULT,
|
||||
LAT_PIN_DEFAULT, OE_PIN_DEFAULT, CLK_PIN_DEFAULT },
|
||||
shift_driver _drv = SHIFTREG,
|
||||
bool _dbuff = false,
|
||||
clk_speed _i2sspeed = HZ_10M,
|
||||
uint8_t _latblk = 1, // Anything > 1 seems to cause artefacts on ICS panels
|
||||
bool _clockphase = true,
|
||||
uint8_t _min_refresh_rate = 85
|
||||
) : mx_width(_w),
|
||||
mx_height(_h),
|
||||
chain_length(_chain),
|
||||
gpio(_pinmap),
|
||||
driver(_drv), i2sspeed(_i2sspeed),
|
||||
double_buff(_dbuff),
|
||||
latch_blanking(_latblk),
|
||||
clkphase(_clockphase),
|
||||
min_refresh_rate (_min_refresh_rate) {}
|
||||
}; // end of structure HUB75_I2S_CFG
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************/
|
||||
#ifdef USE_GFX_ROOT
|
||||
class MatrixPanel_I2S_DMA : public GFX {
|
||||
#elif !defined NO_GFX
|
||||
class MatrixPanel_I2S_DMA : public Adafruit_GFX {
|
||||
#else
|
||||
class MatrixPanel_I2S_DMA {
|
||||
#endif
|
||||
|
||||
// ------- PUBLIC -------
|
||||
public:
|
||||
|
||||
/**
|
||||
* MatrixPanel_I2S_DMA
|
||||
*
|
||||
* default predefined values are used for matrix configuration
|
||||
*
|
||||
*/
|
||||
MatrixPanel_I2S_DMA()
|
||||
#ifdef USE_GFX_ROOT
|
||||
: GFX(MATRIX_WIDTH, MATRIX_HEIGHT)
|
||||
#elif !defined NO_GFX
|
||||
: Adafruit_GFX(MATRIX_WIDTH, MATRIX_HEIGHT)
|
||||
#endif
|
||||
{}
|
||||
|
||||
/**
|
||||
* MatrixPanel_I2S_DMA
|
||||
*
|
||||
* @param {HUB75_I2S_CFG} opts : structure with matrix configuration
|
||||
*
|
||||
*/
|
||||
MatrixPanel_I2S_DMA(const HUB75_I2S_CFG& opts) :
|
||||
#ifdef USE_GFX_ROOT
|
||||
GFX(opts.mx_width*opts.chain_length, opts.mx_height),
|
||||
#elif !defined NO_GFX
|
||||
Adafruit_GFX(opts.mx_width*opts.chain_length, opts.mx_height),
|
||||
#endif
|
||||
m_cfg(opts) {}
|
||||
|
||||
/* Propagate the DMA pin configuration, allocate DMA buffs and start data output, initially blank */
|
||||
bool begin(){
|
||||
|
||||
if (initialized) return true; // we don't do this twice or more!
|
||||
|
||||
// Change 'if' to '1' to enable, 0 to not include this Serial output in compiled program
|
||||
#if SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("Using pin %d for the R1_PIN\n"), m_cfg.gpio.r1);
|
||||
Serial.printf_P(PSTR("Using pin %d for the G1_PIN\n"), m_cfg.gpio.g1);
|
||||
Serial.printf_P(PSTR("Using pin %d for the B1_PIN\n"), m_cfg.gpio.b1);
|
||||
Serial.printf_P(PSTR("Using pin %d for the R2_PIN\n"), m_cfg.gpio.r2);
|
||||
Serial.printf_P(PSTR("Using pin %d for the G2_PIN\n"), m_cfg.gpio.g2);
|
||||
Serial.printf_P(PSTR("Using pin %d for the B2_PIN\n"), m_cfg.gpio.b2);
|
||||
Serial.printf_P(PSTR("Using pin %d for the A_PIN\n"), m_cfg.gpio.a);
|
||||
Serial.printf_P(PSTR("Using pin %d for the B_PIN\n"), m_cfg.gpio.b);
|
||||
Serial.printf_P(PSTR("Using pin %d for the C_PIN\n"), m_cfg.gpio.c);
|
||||
Serial.printf_P(PSTR("Using pin %d for the D_PIN\n"), m_cfg.gpio.d);
|
||||
Serial.printf_P(PSTR("Using pin %d for the E_PIN\n"), m_cfg.gpio.e);
|
||||
Serial.printf_P(PSTR("Using pin %d for the LAT_PIN\n"), m_cfg.gpio.lat);
|
||||
Serial.printf_P(PSTR("Using pin %d for the OE_PIN\n"), m_cfg.gpio.oe);
|
||||
Serial.printf_P(PSTR("Using pin %d for the CLK_PIN\n"), m_cfg.gpio.clk);
|
||||
#endif
|
||||
|
||||
// initialize some specific panel drivers
|
||||
if (m_cfg.driver)
|
||||
shiftDriver(m_cfg);
|
||||
|
||||
|
||||
/* As DMA buffers are dynamically allocated, we must allocated in begin()
|
||||
* Ref: https://github.com/espressif/arduino-esp32/issues/831
|
||||
*/
|
||||
if ( !allocateDMAmemory() ) { return false; } // couldn't even get the basic ram required.
|
||||
|
||||
|
||||
// Flush the DMA buffers prior to configuring DMA - Avoid visual artefacts on boot.
|
||||
resetbuffers(); // Must fill the DMA buffer with the initial output bit sequence or the panel will display garbage
|
||||
|
||||
// Setup the ESP32 DMA Engine. Sprite_TM built this stuff.
|
||||
configureDMA(m_cfg); //DMA and I2S configuration and setup
|
||||
|
||||
//showDMABuffer(); // show backbuf_id of 0
|
||||
|
||||
#if SERIAL_DEBUG
|
||||
if (!initialized)
|
||||
Serial.println(F("MatrixPanel_I2S_DMA::begin() failed."));
|
||||
#endif
|
||||
|
||||
return initialized;
|
||||
|
||||
}
|
||||
|
||||
// Obj destructor
|
||||
~MatrixPanel_I2S_DMA(){
|
||||
stopDMAoutput();
|
||||
|
||||
delete dmadesc_a;
|
||||
|
||||
if (m_cfg.double_buff)
|
||||
delete dmadesc_b;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* overload for compatibility
|
||||
*/
|
||||
bool begin(int r1, int g1 = G1_PIN_DEFAULT, int b1 = B1_PIN_DEFAULT, int r2 = R2_PIN_DEFAULT, int g2 = G2_PIN_DEFAULT, int b2 = B2_PIN_DEFAULT, int a = A_PIN_DEFAULT, int b = B_PIN_DEFAULT, int c = C_PIN_DEFAULT, int d = D_PIN_DEFAULT, int e = E_PIN_DEFAULT, int lat = LAT_PIN_DEFAULT, int oe = OE_PIN_DEFAULT, int clk = CLK_PIN_DEFAULT);
|
||||
|
||||
|
||||
// Adafruit's BASIC DRAW API (565 colour format)
|
||||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color); // overwrite adafruit implementation
|
||||
virtual void fillScreen(uint16_t color); // overwrite adafruit implementation
|
||||
|
||||
/**
|
||||
* A wrapper to fill whatever selected DMA buffer / screen with black
|
||||
*/
|
||||
inline void clearScreen(){ updateMatrixDMABuffer(0,0,0); };
|
||||
|
||||
#ifndef NO_FAST_FUNCTIONS
|
||||
/**
|
||||
* @brief - override Adafruit's FastVLine
|
||||
* this works faster than multiple consecutive pixel by pixel drawPixel() call
|
||||
*/
|
||||
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){
|
||||
uint8_t r, g, b;
|
||||
color565to888(color, r, g, b);
|
||||
vlineDMA(x, y, h, r, g, b);
|
||||
}
|
||||
// rgb888 overload
|
||||
virtual inline void drawFastVLine(int16_t x, int16_t y, int16_t h, uint8_t r, uint8_t g, uint8_t b){ vlineDMA(x, y, h, r, g, b); };
|
||||
|
||||
/**
|
||||
* @brief - override Adafruit's FastHLine
|
||||
* this works faster than multiple consecutive pixel by pixel drawPixel() call
|
||||
*/
|
||||
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){
|
||||
uint8_t r, g, b;
|
||||
color565to888(color, r, g, b);
|
||||
hlineDMA(x, y, w, r, g, b);
|
||||
}
|
||||
// rgb888 overload
|
||||
virtual inline void drawFastHLine(int16_t x, int16_t y, int16_t w, uint8_t r, uint8_t g, uint8_t b){ hlineDMA(x, y, w, r, g, b); };
|
||||
|
||||
/**
|
||||
* @brief - override Adafruit's fillRect
|
||||
* this works much faster than multiple consecutive per-pixel drawPixel() calls
|
||||
*/
|
||||
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
|
||||
uint8_t r, g, b;
|
||||
color565to888(color, r, g, b);
|
||||
fillRectDMA(x, y, w, h, r, g, b);
|
||||
}
|
||||
// rgb888 overload
|
||||
virtual inline void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t r, uint8_t g, uint8_t b){fillRectDMA(x, y, w, h, r, g, b);}
|
||||
#endif
|
||||
|
||||
void fillScreenRGB888(uint8_t r, uint8_t g, uint8_t b);
|
||||
void drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
#ifdef USE_GFX_ROOT
|
||||
// 24bpp FASTLED CRGB colour struct support
|
||||
void fillScreen(CRGB color);
|
||||
void drawPixel(int16_t x, int16_t y, CRGB color);
|
||||
#endif
|
||||
|
||||
void drawIcon (int *ico, int16_t x, int16_t y, int16_t cols, int16_t rows);
|
||||
|
||||
// Color 444 is a 4 bit scale, so 0 to 15, color 565 takes a 0-255 bit value, so scale up by 255/15 (i.e. 17)!
|
||||
static uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { return color565(r*17,g*17,b*17); }
|
||||
|
||||
// Converts RGB888 to RGB565
|
||||
static uint16_t color565(uint8_t r, uint8_t g, uint8_t b); // This is what is used by Adafruit GFX!
|
||||
|
||||
// Converts RGB333 to RGB565
|
||||
static uint16_t color333(uint8_t r, uint8_t g, uint8_t b); // This is what is used by Adafruit GFX! Not sure why they have a capital 'C' for this particular function.
|
||||
|
||||
/**
|
||||
* @brief - convert RGB565 to RGB888
|
||||
* @param uint16_t color - RGB565 input color
|
||||
* @param uint8_t &r, &g, &b - refs to variables where converted colors would be emplaced
|
||||
*/
|
||||
static void color565to888(const uint16_t color, uint8_t &r, uint8_t &g, uint8_t &b);
|
||||
|
||||
|
||||
inline void IRAM_ATTR flipDMABuffer()
|
||||
{
|
||||
if ( !m_cfg.double_buff) return;
|
||||
|
||||
#if SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("Set back buffer to: %d\n"), back_buffer_id);
|
||||
#endif
|
||||
|
||||
i2s_parallel_set_previous_buffer_not_free();
|
||||
// Wait before we allow any writing to the buffer. Stop flicker.
|
||||
while(i2s_parallel_is_previous_buffer_free() == false) { }
|
||||
|
||||
i2s_parallel_flip_to_buffer(ESP32_I2S_DEVICE, back_buffer_id);
|
||||
// Flip to other buffer as the backbuffer.
|
||||
// i.e. Graphic changes happen to this buffer, but aren't displayed until flipDMABuffer() is called again.
|
||||
back_buffer_id ^= 1;
|
||||
|
||||
i2s_parallel_set_previous_buffer_not_free();
|
||||
// Wait before we allow any writing to the buffer. Stop flicker.
|
||||
while(i2s_parallel_is_previous_buffer_free() == false) { }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
inline void setPanelBrightness(int b)
|
||||
{
|
||||
// Change to set the brightness of the display, range of 1 to matrixWidth (i.e. 1 - 64)
|
||||
brightness = b;
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
brtCtrlOE(b);
|
||||
if (m_cfg.double_buff)
|
||||
brtCtrlOE(b, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* this is just a wrapper to control brightness
|
||||
* with an 8-bit value (0-255), very popular in FastLED-based sketches :)
|
||||
* @param uint8_t b - 8-bit brightness value
|
||||
*/
|
||||
void setBrightness8(const uint8_t b)
|
||||
{
|
||||
setPanelBrightness(b * PIXELS_PER_ROW / 256);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains the resulting refresh rate (scan rate) that will be achieved
|
||||
* based on the i2sspeed, colour depth and min_refresh_rate requested.
|
||||
*/
|
||||
int calculated_refresh_rate = 0;
|
||||
|
||||
/**
|
||||
* @brief - Sets how many clock cycles to blank OE before/after LAT signal change
|
||||
* @param uint8_t pulses - clocks before/after OE
|
||||
* default is DEFAULT_LAT_BLANKING
|
||||
* Max is MAX_LAT_BLANKING
|
||||
* @returns - new value for m_cfg.latch_blanking
|
||||
*/
|
||||
uint8_t setLatBlanking(uint8_t pulses);
|
||||
|
||||
/**
|
||||
* Get a class configuration struct
|
||||
*
|
||||
*/
|
||||
const HUB75_I2S_CFG& getCfg() const {return m_cfg;};
|
||||
|
||||
|
||||
/**
|
||||
* Stop the ESP32 DMA Engine. Screen will forever be black until next ESP reboot.
|
||||
*/
|
||||
void stopDMAoutput() {
|
||||
resetbuffers();
|
||||
i2s_parallel_stop_dma(ESP32_I2S_DEVICE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------- PROTECTED -------
|
||||
// those might be useful for child classes, like VirtualMatrixPanel
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief - clears and reinitializes color/control data in DMA buffs
|
||||
* When allocated, DMA buffs might be dirty, so we need to blank it and initialize ABCDE,LAT,OE control bits.
|
||||
* Those control bits are constants during the entire DMA sweep and never changed when updating just pixel color data
|
||||
* so we could set it once on DMA buffs initialization and forget.
|
||||
* This effectively clears buffers to blank BLACK and makes it ready to display output.
|
||||
* (Brightness control via OE bit manipulation is another case)
|
||||
*/
|
||||
void clearFrameBuffer(bool _buff_id = 0);
|
||||
|
||||
/* Update a specific pixel in the DMA buffer to a colour */
|
||||
void updateMatrixDMABuffer(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/* Update the entire DMA buffer (aka. The RGB Panel) a certain colour (wipe the screen basically) */
|
||||
void updateMatrixDMABuffer(uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/**
|
||||
* wipes DMA buffer(s) and reset all color/service bits
|
||||
*/
|
||||
inline void resetbuffers(){
|
||||
clearFrameBuffer();
|
||||
brtCtrlOE(brightness);
|
||||
if (m_cfg.double_buff){
|
||||
clearFrameBuffer(1);
|
||||
brtCtrlOE(brightness, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef NO_FAST_FUNCTIONS
|
||||
/**
|
||||
* @brief - update DMA buff drawing horizontal line at specified coordinates
|
||||
* @param x_ccord - line start coordinate x
|
||||
* @param y_ccord - line start coordinate y
|
||||
* @param l - line length
|
||||
* @param r,g,b, - RGB888 color
|
||||
*/
|
||||
void hlineDMA(int16_t x_coord, int16_t y_coord, int16_t l, uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/**
|
||||
* @brief - update DMA buff drawing horizontal line at specified coordinates
|
||||
* @param x_ccord - line start coordinate x
|
||||
* @param y_ccord - line start coordinate y
|
||||
* @param l - line length
|
||||
* @param r,g,b, - RGB888 color
|
||||
*/
|
||||
void vlineDMA(int16_t x_coord, int16_t y_coord, int16_t l, uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/**
|
||||
* @brief - update DMA buff drawing a rectangular at specified coordinates
|
||||
* uses Fast H/V line draw internally, works faster than multiple consecutive pixel by pixel calls to updateMatrixDMABuffer()
|
||||
* @param int16_t x, int16_t y - coordinates of a top-left corner
|
||||
* @param int16_t w, int16_t h - width and height of a rectangular, min is 1 px
|
||||
* @param uint8_t r - RGB888 color
|
||||
* @param uint8_t g - RGB888 color
|
||||
* @param uint8_t b - RGB888 color
|
||||
*/
|
||||
void fillRectDMA(int16_t x_coord, int16_t y_coord, int16_t w, int16_t h, uint8_t r, uint8_t g, uint8_t b);
|
||||
#endif
|
||||
|
||||
// ------- PRIVATE -------
|
||||
private:
|
||||
|
||||
// Matrix i2s settings
|
||||
HUB75_I2S_CFG m_cfg;
|
||||
|
||||
/* ESP32-HUB75-MatrixPanel-I2S-DMA functioning constants
|
||||
* we can't change those once object instance initialized it's DMA structs
|
||||
*/
|
||||
const uint8_t ROWS_PER_FRAME = m_cfg.mx_height / MATRIX_ROWS_IN_PARALLEL; // RPF - rows per frame, either 16 or 32 depending on matrix module
|
||||
const uint16_t PIXELS_PER_ROW = m_cfg.mx_width * m_cfg.chain_length; // number of pixels in a single row of all chained matrix modules (WIDTH of a combined matrix chain)
|
||||
|
||||
// Other private variables
|
||||
bool initialized = false;
|
||||
int back_buffer_id = 0; // If using double buffer, which one is NOT active (ie. being displayed) to write too?
|
||||
int brightness = 32; // If you get ghosting... reduce brightness level. 60 seems to be the limit before ghosting on a 64 pixel wide physical panel for some panels.
|
||||
int lsbMsbTransitionBit = 0; // For colour depth calculations
|
||||
|
||||
|
||||
// *** DMA FRAMEBUFFER structures
|
||||
|
||||
// ESP 32 DMA Linked List descriptor
|
||||
int desccount = 0;
|
||||
lldesc_t * dmadesc_a = {0};
|
||||
lldesc_t * dmadesc_b = {0};
|
||||
|
||||
/* Pixel data is organized from LSB to MSB sequentially by row, from row 0 to row matrixHeight/matrixRowsInParallel
|
||||
* (two rows of pixels are refreshed in parallel)
|
||||
* Memory is allocated (malloc'd) by the row, and not in one massive chunk, for flexibility.
|
||||
* The whole DMA framebuffer is just a vector of pointers to structs with ESP32_I2S_DMA_STORAGE_TYPE arrays
|
||||
* Since it's dimensions is unknown prior to class initialization, we just declare it here as empty struct and will do all allocations later.
|
||||
* Refer to rowBitStruct to get the idea of it's internal structure
|
||||
*/
|
||||
frameStruct dma_buff;
|
||||
|
||||
|
||||
/* Calculate the memory available for DMA use, do some other stuff, and allocate accordingly */
|
||||
bool allocateDMAmemory();
|
||||
|
||||
/* Setup the DMA Link List chain and initiate the ESP32 DMA engine */
|
||||
void configureDMA(const HUB75_I2S_CFG& opts);
|
||||
|
||||
/**
|
||||
* pre-init procedures for specific drivers
|
||||
*
|
||||
*/
|
||||
void shiftDriver(const HUB75_I2S_CFG& opts);
|
||||
|
||||
/**
|
||||
* @brief - FM6124-family chips initialization routine
|
||||
*/
|
||||
void fm6124init(const HUB75_I2S_CFG& _cfg);
|
||||
|
||||
/**
|
||||
* @brief - reset OE bits in DMA buffer in a way to control brightness
|
||||
* @param brt - brightness level from 0 to row_width
|
||||
* @param _buff_id - buffer id to control
|
||||
*/
|
||||
void brtCtrlOE(int brt, const bool _buff_id=0);
|
||||
|
||||
|
||||
}; // end Class header
|
||||
|
||||
/***************************************************************************************/
|
||||
// https://stackoverflow.com/questions/5057021/why-are-c-inline-functions-in-the-header
|
||||
/* 2. functions declared in the header must be marked inline because otherwise, every translation unit which includes the header will contain a definition of the function, and the linker will complain about multiple definitions (a violation of the One Definition Rule). The inline keyword suppresses this, allowing multiple translation units to contain (identical) definitions. */
|
||||
|
||||
/**
|
||||
* @brief - convert RGB565 to RGB888
|
||||
* @param uint16_t color - RGB565 input color
|
||||
* @param uint8_t &r, &g, &b - refs to variables where converted colours would be emplaced
|
||||
*/
|
||||
inline void MatrixPanel_I2S_DMA::color565to888(const uint16_t color, uint8_t &r, uint8_t &g, uint8_t &b){
|
||||
r = ((((color >> 11) & 0x1F) * 527) + 23) >> 6;
|
||||
g = ((((color >> 5) & 0x3F) * 259) + 33) >> 6;
|
||||
b = (((color & 0x1F) * 527) + 23) >> 6;
|
||||
}
|
||||
|
||||
inline void MatrixPanel_I2S_DMA::drawPixel(int16_t x, int16_t y, uint16_t color) // adafruit virtual void override
|
||||
{
|
||||
uint8_t r,g,b;
|
||||
color565to888(color,r,g,b);
|
||||
|
||||
updateMatrixDMABuffer( x, y, r, g, b);
|
||||
}
|
||||
|
||||
inline void MatrixPanel_I2S_DMA::fillScreen(uint16_t color) // adafruit virtual void override
|
||||
{
|
||||
uint8_t r,g,b;
|
||||
color565to888(color,r,g,b);
|
||||
|
||||
updateMatrixDMABuffer(r, g, b); // RGB only (no pixel coordinate) version of 'updateMatrixDMABuffer'
|
||||
}
|
||||
|
||||
inline void MatrixPanel_I2S_DMA::drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g,uint8_t b)
|
||||
{
|
||||
updateMatrixDMABuffer( x, y, r, g, b);
|
||||
}
|
||||
|
||||
inline void MatrixPanel_I2S_DMA::fillScreenRGB888(uint8_t r, uint8_t g,uint8_t b)
|
||||
{
|
||||
updateMatrixDMABuffer(r, g, b); // RGB only (no pixel coordinate) version of 'updateMatrixDMABuffer'
|
||||
}
|
||||
|
||||
#ifdef USE_GFX_ROOT
|
||||
// Support for CRGB values provided via FastLED
|
||||
inline void MatrixPanel_I2S_DMA::drawPixel(int16_t x, int16_t y, CRGB color)
|
||||
{
|
||||
updateMatrixDMABuffer( x, y, color.red, color.green, color.blue);
|
||||
}
|
||||
|
||||
inline void MatrixPanel_I2S_DMA::fillScreen(CRGB color)
|
||||
{
|
||||
updateMatrixDMABuffer(color.red, color.green, color.blue);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
|
||||
//https://github.com/squix78/ILI9341Buffer/blob/master/ILI9341_SPI.cpp
|
||||
inline uint16_t MatrixPanel_I2S_DMA::color565(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
||||
}
|
||||
|
||||
// Promote 3/3/3 RGB to Adafruit_GFX 5/6/5 RRRrrGGGgggBBBbb
|
||||
inline uint16_t MatrixPanel_I2S_DMA::color333(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return ((r & 0x7) << 13) | ((r & 0x6) << 10) | ((g & 0x7) << 8) | ((g & 0x7) << 5) | ((b & 0x7) << 2) | ((b & 0x6) >> 1);
|
||||
}
|
||||
|
||||
inline void MatrixPanel_I2S_DMA::drawIcon (int *ico, int16_t x, int16_t y, int16_t cols, int16_t rows) {
|
||||
/* drawIcon draws a C style bitmap.
|
||||
// Example 10x5px bitmap of a yellow sun
|
||||
//
|
||||
int half_sun [50] = {
|
||||
0x0000, 0x0000, 0x0000, 0xffe0, 0x0000, 0x0000, 0xffe0, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0xffe0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0x0000, 0x0000, 0x0000,
|
||||
0xffe0, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0x0000, 0xffe0,
|
||||
0x0000, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0x0000, 0x0000,
|
||||
};
|
||||
|
||||
MatrixPanel_I2S_DMA matrix;
|
||||
|
||||
matrix.drawIcon (half_sun, 0,0,10,5);
|
||||
*/
|
||||
|
||||
int i, j;
|
||||
for (i = 0; i < rows; i++) {
|
||||
for (j = 0; j < cols; j++) {
|
||||
drawPixel (x + j, y + i, (uint16_t) ico[i * cols + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
Various LED Driver chips might need some specific code for initialisation/control logic
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h"
|
||||
|
||||
#define CLK_PULSE digitalWrite(_cfg.gpio.clk, HIGH); digitalWrite(_cfg.gpio.clk, LOW);
|
||||
|
||||
/**
|
||||
* @brief - pre-init procedures for specific led-drivers
|
||||
* this method is called before DMA/I2S setup while GPIOs
|
||||
* aint yet assigned for DMA operation
|
||||
*
|
||||
*/
|
||||
void MatrixPanel_I2S_DMA::shiftDriver(const HUB75_I2S_CFG& _cfg){
|
||||
switch (_cfg.driver){
|
||||
case HUB75_I2S_CFG::ICN2038S:
|
||||
case HUB75_I2S_CFG::FM6124:
|
||||
case HUB75_I2S_CFG::FM6126A:
|
||||
fm6124init(_cfg);
|
||||
break;
|
||||
case HUB75_I2S_CFG::MBI5124:
|
||||
/* MBI5124 chips must be clocked with positive-edge, since it's LAT signal
|
||||
* resets on clock's rising edge while high
|
||||
* https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/files/5952216/5a542453754da.pdf
|
||||
*/
|
||||
m_cfg.clkphase=true;
|
||||
break;
|
||||
case HUB75_I2S_CFG::SHIFTREG:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MatrixPanel_I2S_DMA::fm6124init(const HUB75_I2S_CFG& _cfg){
|
||||
#if SERIAL_DEBUG
|
||||
Serial.println( F("MatrixPanel_I2S_DMA - initializing FM6124 driver..."));
|
||||
#endif
|
||||
bool REG1[16] = {0,0,0,0,0, 1,1,1,1,1,1, 0,0,0,0,0}; // this sets global matrix brightness power
|
||||
bool REG2[16] = {0,0,0,0,0, 0,0,0,0,1,0, 0,0,0,0,0}; // a single bit enables the matrix output
|
||||
|
||||
for (uint8_t _pin:{_cfg.gpio.r1, _cfg.gpio.r2, _cfg.gpio.g1, _cfg.gpio.g2, _cfg.gpio.b1, _cfg.gpio.b2, _cfg.gpio.clk, _cfg.gpio.lat, _cfg.gpio.oe}){
|
||||
pinMode(_pin, OUTPUT);
|
||||
digitalWrite(_pin, LOW);
|
||||
}
|
||||
|
||||
digitalWrite(_cfg.gpio.oe, HIGH); // Disable Display
|
||||
|
||||
// Send Data to control register REG1
|
||||
// this sets the matrix brightness actually
|
||||
for (int l = 0; l < PIXELS_PER_ROW; l++){
|
||||
for (uint8_t _pin:{_cfg.gpio.r1, _cfg.gpio.r2, _cfg.gpio.g1, _cfg.gpio.g2, _cfg.gpio.b1, _cfg.gpio.b2})
|
||||
digitalWrite(_pin, REG1[l%16]); // we have 16 bits shifters and write the same value all over the matrix array
|
||||
|
||||
if (l > PIXELS_PER_ROW - 12){ // pull the latch 11 clocks before the end of matrix so that REG1 starts counting to save the value
|
||||
digitalWrite(_cfg.gpio.lat, HIGH);
|
||||
}
|
||||
CLK_PULSE
|
||||
}
|
||||
|
||||
// drop the latch and save data to the REG1 all over the FM6124 chips
|
||||
digitalWrite(_cfg.gpio.lat, LOW);
|
||||
|
||||
// Send Data to control register REG2 (enable LED output)
|
||||
for (int l = 0; l < PIXELS_PER_ROW; l++){
|
||||
for (uint8_t _pin:{_cfg.gpio.r1, _cfg.gpio.r2, _cfg.gpio.g1, _cfg.gpio.g2, _cfg.gpio.b1, _cfg.gpio.b2})
|
||||
digitalWrite(_pin, REG2[l%16]); // we have 16 bits shifters and we write the same value all over the matrix array
|
||||
|
||||
if (l > PIXELS_PER_ROW - 13){ // pull the latch 12 clocks before the end of matrix so that reg2 stars counting to save the value
|
||||
digitalWrite(_cfg.gpio.lat, HIGH);
|
||||
}
|
||||
CLK_PULSE
|
||||
}
|
||||
|
||||
// drop the latch and save data to the REG1 all over the FM6126 chips
|
||||
digitalWrite(_cfg.gpio.lat, LOW);
|
||||
|
||||
// blank data regs to keep matrix clear after manipulations
|
||||
for (uint8_t _pin:{_cfg.gpio.r1, _cfg.gpio.r2, _cfg.gpio.g1, _cfg.gpio.g2, _cfg.gpio.b1, _cfg.gpio.b2})
|
||||
digitalWrite(_pin, LOW);
|
||||
|
||||
for (int l = 0; l < PIXELS_PER_ROW; ++l){
|
||||
CLK_PULSE
|
||||
}
|
||||
|
||||
digitalWrite(_cfg.gpio.lat, HIGH);
|
||||
CLK_PULSE
|
||||
digitalWrite(_cfg.gpio.lat, LOW);
|
||||
digitalWrite(_cfg.gpio.oe, LOW); // Enable Display
|
||||
CLK_PULSE
|
||||
}
|
|
@ -1,355 +0,0 @@
|
|||
#ifndef _ESP32_VIRTUAL_MATRIX_PANEL_I2S_DMA
|
||||
#define _ESP32_VIRTUAL_MATRIX_PANEL_I2S_DMA
|
||||
|
||||
/*******************************************************************
|
||||
Class contributed by Brian Lough, and expanded by Faptastic.
|
||||
|
||||
Originally designed to allow CHAINING of panels together to create
|
||||
a 'bigger' display of panels. i.e. Chaining 4 panels into a 2x2
|
||||
grid.
|
||||
|
||||
However, the function of this class has expanded now to also manage
|
||||
the output for 1/16 scan panels, as the core DMA library is designed
|
||||
ONLY FOR 1/16 scan matrix panels.
|
||||
|
||||
YouTube: https://www.youtube.com/brianlough
|
||||
Tindie: https://www.tindie.com/stores/brianlough/
|
||||
Twitter: https://twitter.com/witnessmenow
|
||||
*******************************************************************/
|
||||
|
||||
#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h"
|
||||
#ifndef NO_GFX
|
||||
#include <Fonts/FreeSansBold12pt7b.h>
|
||||
#endif
|
||||
|
||||
struct VirtualCoords
|
||||
{
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t virt_row; // chain of panels row
|
||||
int16_t virt_col; // chain of panels col
|
||||
|
||||
VirtualCoords() : x(0), y(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
enum PANEL_SCAN_RATE
|
||||
{
|
||||
NORMAL_ONE_SIXTEEN,
|
||||
ONE_EIGHT_32,
|
||||
ONE_EIGHT_16
|
||||
};
|
||||
|
||||
#ifdef USE_GFX_ROOT
|
||||
class VirtualMatrixPanel : public GFX
|
||||
#elif !defined NO_GFX
|
||||
class VirtualMatrixPanel : public Adafruit_GFX
|
||||
#else
|
||||
class VirtualMatrixPanel
|
||||
#endif
|
||||
{
|
||||
|
||||
public:
|
||||
int16_t virtualResX;
|
||||
int16_t virtualResY;
|
||||
|
||||
int16_t vmodule_rows;
|
||||
int16_t vmodule_cols;
|
||||
|
||||
int16_t panelResX;
|
||||
int16_t panelResY;
|
||||
|
||||
int16_t dmaResX; // The width of the chain in pixels (as the DMA engine sees it)
|
||||
|
||||
MatrixPanel_I2S_DMA *display;
|
||||
|
||||
VirtualMatrixPanel(MatrixPanel_I2S_DMA &disp, int _vmodule_rows, int _vmodule_cols, int _panelResX, int _panelResY, bool serpentine_chain = true, bool top_down_chain = false)
|
||||
#ifdef USE_GFX_ROOT
|
||||
: GFX(_vmodule_cols * _panelResX, _vmodule_rows * _panelResY)
|
||||
#elif !defined NO_GFX
|
||||
: Adafruit_GFX(_vmodule_cols * _panelResX, _vmodule_rows * _panelResY)
|
||||
#endif
|
||||
{
|
||||
this->display = &disp;
|
||||
|
||||
panelResX = _panelResX;
|
||||
panelResY = _panelResY;
|
||||
|
||||
vmodule_rows = _vmodule_rows;
|
||||
vmodule_cols = _vmodule_cols;
|
||||
|
||||
virtualResX = vmodule_cols * _panelResX;
|
||||
virtualResY = vmodule_rows * _panelResY;
|
||||
|
||||
dmaResX = panelResX * vmodule_rows * vmodule_cols;
|
||||
|
||||
/* Virtual Display width() and height() will return a real-world value. For example:
|
||||
* Virtual Display width: 128
|
||||
* Virtual Display height: 64
|
||||
*
|
||||
* So, not values that at 0 to X-1
|
||||
*/
|
||||
|
||||
_s_chain_party = serpentine_chain; // serpentine, or 'S' chain?
|
||||
_chain_top_down = top_down_chain;
|
||||
|
||||
coords.x = coords.y = -1; // By default use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer
|
||||
}
|
||||
|
||||
// equivalent methods of the matrix library so it can be just swapped out.
|
||||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||
virtual void fillScreen(uint16_t color); // overwrite adafruit implementation
|
||||
virtual void fillScreenRGB888(uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
void clearScreen() { display->clearScreen(); }
|
||||
void drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
#ifdef USE_GFX_ROOT
|
||||
// 24bpp FASTLED CRGB colour struct support
|
||||
void fillScreen(CRGB color);
|
||||
void drawPixel(int16_t x, int16_t y, CRGB color);
|
||||
#endif
|
||||
|
||||
uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { return display->color444(r, g, b); }
|
||||
uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { return display->color565(r, g, b); }
|
||||
uint16_t color333(uint8_t r, uint8_t g, uint8_t b) { return display->color333(r, g, b); }
|
||||
|
||||
void flipDMABuffer() { display->flipDMABuffer(); }
|
||||
void drawDisplayTest();
|
||||
void setRotate(bool rotate);
|
||||
|
||||
void setPhysicalPanelScanRate(PANEL_SCAN_RATE rate);
|
||||
|
||||
protected:
|
||||
virtual VirtualCoords getCoords(int16_t &x, int16_t &y);
|
||||
VirtualCoords coords;
|
||||
|
||||
bool _s_chain_party = true; // Are we chained? Ain't no party like a...
|
||||
bool _chain_top_down = false; // is the ESP at the top or bottom of the matrix of devices?
|
||||
bool _rotate = false;
|
||||
|
||||
PANEL_SCAN_RATE _panelScanRate = NORMAL_ONE_SIXTEEN;
|
||||
|
||||
}; // end Class header
|
||||
|
||||
/**
|
||||
* Calculate virtual->real co-ordinate mapping to underlying single chain of panels connected to ESP32.
|
||||
* Updates the private class member variable 'coords', so no need to use the return value.
|
||||
* Not thread safe, but not a concern for ESP32 sketch anyway... I think.
|
||||
*/
|
||||
inline VirtualCoords VirtualMatrixPanel::getCoords(int16_t &x, int16_t &y)
|
||||
{
|
||||
// Serial.println("Called Base.");
|
||||
coords.x = coords.y = -1; // By defalt use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer
|
||||
|
||||
// Do we want to rotate?
|
||||
if (_rotate)
|
||||
{
|
||||
int16_t temp_x = x;
|
||||
x = y;
|
||||
y = virtualResY - 1 - temp_x;
|
||||
}
|
||||
|
||||
if (x < 0 || x >= virtualResX || y < 0 || y >= virtualResY)
|
||||
{ // Co-ordinates go from 0 to X-1 remember! otherwise they are out of range!
|
||||
// Serial.printf("VirtualMatrixPanel::getCoords(): Invalid virtual display coordinate. x,y: %d, %d\r\n", x, y);
|
||||
return coords;
|
||||
}
|
||||
|
||||
// Stupidity check
|
||||
if ((vmodule_rows == 1) && (vmodule_cols == 1)) // single panel...
|
||||
{
|
||||
coords.x = x;
|
||||
coords.y = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t row = (y / panelResY) + 1; // a non indexed 0 row number
|
||||
if ((_s_chain_party && !_chain_top_down && (row % 2 == 0)) // serpentine vertically stacked chain starting from bottom row (i.e. ESP closest to ground), upwards
|
||||
||
|
||||
(_s_chain_party && _chain_top_down && (row % 2 != 0)) // serpentine vertically stacked chain starting from the sky downwards
|
||||
)
|
||||
{
|
||||
// First portion gets you to the correct offset for the row you need
|
||||
// Second portion inverts the x on the row
|
||||
coords.x = ((y / panelResY) * (virtualResX)) + (virtualResX - x) - 1;
|
||||
|
||||
// inverts the y the row
|
||||
coords.y = panelResY - 1 - (y % panelResY);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal chain pixel co-ordinate
|
||||
coords.x = x + ((y / panelResY) * (virtualResX));
|
||||
coords.y = y % panelResY;
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse co-ordinates if panel chain from ESP starts from the TOP RIGHT
|
||||
if (_chain_top_down)
|
||||
{
|
||||
/*
|
||||
const HUB75_I2S_CFG _cfg = this->display->getCfg();
|
||||
coords.x = (_cfg.mx_width * _cfg.chain_length - 1) - coords.x;
|
||||
coords.y = (_cfg.mx_height-1) - coords.y;
|
||||
*/
|
||||
coords.x = (dmaResX - 1) - coords.x;
|
||||
coords.y = (panelResY - 1) - coords.y;
|
||||
}
|
||||
|
||||
/* START: Pixel remapping AGAIN to convert 1/16 SCAN output that the
|
||||
* the underlying hardware library is designed for (because
|
||||
* there's only 2 x RGB pins... and convert this to 1/8 or something
|
||||
*/
|
||||
if (_panelScanRate == ONE_EIGHT_32)
|
||||
{
|
||||
/* Convert Real World 'VirtualMatrixPanel' co-ordinates (i.e. Real World pixel you're looking at
|
||||
on the panel or chain of panels, per the chaining configuration) to a 1/8 panels
|
||||
double 'stretched' and 'squished' coordinates which is what needs to be sent from the
|
||||
DMA buffer.
|
||||
|
||||
Note: Look at the One_Eight_1_8_ScanPanel code and you'll see that the DMA buffer is setup
|
||||
as if the panel is 2 * W and 0.5 * H !
|
||||
*/
|
||||
|
||||
/*
|
||||
Serial.print("VirtualMatrixPanel Mapping ("); Serial.print(x, DEC); Serial.print(","); Serial.print(y, DEC); Serial.print(") ");
|
||||
// to
|
||||
Serial.print("to ("); Serial.print(coords.x, DEC); Serial.print(","); Serial.print(coords.y, DEC); Serial.println(") ");
|
||||
*/
|
||||
if ((y & 8) == 0)
|
||||
{
|
||||
coords.x += ((coords.x / panelResX) + 1) * panelResX; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
|
||||
}
|
||||
else
|
||||
{
|
||||
coords.x += (coords.x / panelResX) * panelResX; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
|
||||
}
|
||||
|
||||
// http://cpp.sh/4ak5u
|
||||
// Real number of DMA y rows is half reality
|
||||
// coords.y = (y / 16)*8 + (y & 0b00000111);
|
||||
coords.y = (y >> 4) * 8 + (y & 0b00000111);
|
||||
|
||||
/*
|
||||
Serial.print("OneEightScanPanel Mapping ("); Serial.print(x, DEC); Serial.print(","); Serial.print(y, DEC); Serial.print(") ");
|
||||
// to
|
||||
Serial.print("to ("); Serial.print(coords.x, DEC); Serial.print(","); Serial.print(coords.y, DEC); Serial.println(") ");
|
||||
*/
|
||||
}
|
||||
else if (_panelScanRate == ONE_EIGHT_16)
|
||||
{
|
||||
if ((y & 8) == 0)
|
||||
{
|
||||
coords.x += (panelResX >> 2) * (((coords.x & 0xFFF0) >> 4) + 1); // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
|
||||
}
|
||||
else
|
||||
{
|
||||
coords.x += (panelResX >> 2) * (((coords.x & 0xFFF0) >> 4)); // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
|
||||
}
|
||||
|
||||
if (y < 32)
|
||||
coords.y = (y >> 4) * 8 + (y & 0b00000111);
|
||||
else
|
||||
{
|
||||
coords.y = ((y - 32) >> 4) * 8 + (y & 0b00000111);
|
||||
coords.x += 256;
|
||||
}
|
||||
}
|
||||
|
||||
// Serial.print("Mapping to x: "); Serial.print(coords.x, DEC); Serial.print(", y: "); Serial.println(coords.y, DEC);
|
||||
return coords;
|
||||
}
|
||||
|
||||
inline void VirtualMatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||
{ // adafruit virtual void override
|
||||
getCoords(x, y);
|
||||
this->display->drawPixel(coords.x, coords.y, color);
|
||||
}
|
||||
|
||||
inline void VirtualMatrixPanel::fillScreen(uint16_t color)
|
||||
{ // adafruit virtual void override
|
||||
this->display->fillScreen(color);
|
||||
}
|
||||
|
||||
inline void VirtualMatrixPanel::fillScreenRGB888(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
this->display->fillScreenRGB888(r, g, b);
|
||||
}
|
||||
|
||||
inline void VirtualMatrixPanel::drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
getCoords(x, y);
|
||||
this->display->drawPixelRGB888(coords.x, coords.y, r, g, b);
|
||||
}
|
||||
|
||||
#ifdef USE_GFX_ROOT
|
||||
// Support for CRGB values provided via FastLED
|
||||
inline void VirtualMatrixPanel::drawPixel(int16_t x, int16_t y, CRGB color)
|
||||
{
|
||||
getCoords(x, y);
|
||||
this->display->drawPixel(coords.x, coords.y, color);
|
||||
}
|
||||
|
||||
inline void VirtualMatrixPanel::fillScreen(CRGB color)
|
||||
{
|
||||
this->display->fillScreen(color);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void VirtualMatrixPanel::setRotate(bool rotate)
|
||||
{
|
||||
_rotate = rotate;
|
||||
|
||||
#ifndef NO_GFX
|
||||
// We don't support rotation by degrees.
|
||||
if (rotate)
|
||||
{
|
||||
setRotation(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
setRotation(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void VirtualMatrixPanel::setPhysicalPanelScanRate(PANEL_SCAN_RATE rate)
|
||||
{
|
||||
_panelScanRate = rate;
|
||||
}
|
||||
|
||||
#ifndef NO_GFX
|
||||
inline void VirtualMatrixPanel::drawDisplayTest()
|
||||
{
|
||||
this->display->setFont(&FreeSansBold12pt7b);
|
||||
this->display->setTextColor(this->display->color565(255, 255, 0));
|
||||
this->display->setTextSize(1);
|
||||
|
||||
for (int panel = 0; panel < vmodule_cols * vmodule_rows; panel++)
|
||||
{
|
||||
int top_left_x = (panel == 0) ? 0 : (panel * panelResX);
|
||||
this->display->drawRect(top_left_x, 0, panelResX, panelResY, this->display->color565(0, 255, 0));
|
||||
this->display->setCursor(panel * panelResX, panelResY - 3);
|
||||
this->display->print((vmodule_cols * vmodule_rows) - panel);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
// need to recreate this one, as it wouldn't work to just map where it starts.
|
||||
inline void VirtualMatrixPanel::drawIcon (int *ico, int16_t x, int16_t y, int16_t icon_cols, int16_t icon_rows) {
|
||||
int i, j;
|
||||
for (i = 0; i < icon_rows; i++) {
|
||||
for (j = 0; j < icon_cols; j++) {
|
||||
// This is a call to this libraries version of drawPixel
|
||||
// which will map each pixel, which is what we want.
|
||||
//drawPixelRGB565 (x + j, y + i, ico[i * module_cols + j]);
|
||||
drawPixel (x + j, y + i, ico[i * icon_cols + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
9
Kconfig.projbuild
Normal file
|
@ -0,0 +1,9 @@
|
|||
menu "ESP32 HUB75 Configuration"
|
||||
|
||||
config ESP32_HUB75_USE_GFX
|
||||
bool "Use Adafruit GFX library."
|
||||
default y
|
||||
help
|
||||
This option enables use of the Adafruit GFX library using the `Adafruit-GFX-Library` component.
|
||||
|
||||
endmenu
|
12
LICENSE.txt
|
@ -1,4 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2032 Faptastic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -7,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
245
README.md
|
@ -1,119 +1,110 @@
|
|||
# HUB75 RGB LED matrix library utilizing ESP32 DMA Engine
|
||||
# HUB75 RGB LED matrix panel library utilizing ESP32 DMA
|
||||
|
||||
__[BUILD](/doc/BuildOptions.md) | [EXAMPLES](/examples/README.md)__ | [![PlatformIO CI](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/actions/workflows/pio_build.yml/badge.svg)](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/actions/workflows/pio_build.yml)
|
||||
__[BUILD OPTIONS](/doc/BuildOptions.md) | [EXAMPLES](/examples/README.md)__ | [![PlatformIO CI](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/actions/workflows/pio_arduino_build.yml/badge.svg)](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/actions/workflows/pio_build.yml)
|
||||
|
||||
**Table of Content**
|
||||
**Table of Content**
|
||||
|
||||
- [Introduction](#introduction)
|
||||
* [Features](#features)
|
||||
* [Supported ESP32](#esp32-supported)
|
||||
* [Supported Panels](#panels-supported)
|
||||
* [Panel driver chips known to be working well](#panel-driver-chips-known-to-be-working-well)
|
||||
* [Panels Not Supported](#panels-not-supported)
|
||||
* [Update for 16x32 Panels](#update-for-16x32-panels)
|
||||
* [Cool uses of this library](#cool-uses-of-this-library)
|
||||
* [ESP32 variants supported](#esp32-variants-supported)
|
||||
* [Required memory](#required-memory)
|
||||
* [Supported Panels](#supported-panels)
|
||||
* [Panel driver chips known to be working well](#driver-chips-known-to-be-working-well)
|
||||
* [Unsupported Panels](#unsupported-panels)
|
||||
- [Getting Started](#getting-started)
|
||||
* [1. Library Installation](#1-library-installation)
|
||||
* [2. Wiring ESP32 with the LED Matrix Panel](#2-wiring-esp32-with-the-led-matrix-panel)
|
||||
* [2. Wiring the ESP32 to an LED Matrix Panel](#2-wiring-the-esp32-to-an-led-matrix-panel)
|
||||
* [3. Run a Test Sketch](#3-run-a-test-sketch)
|
||||
- [More Information](#more-information)
|
||||
* [Build-time options](#doc/BuildOptions.md)
|
||||
* [Memory constraints](#memory-constraints)
|
||||
* [Can I use with a larger panel (i.e. 64x64px square panel)?](#can-i-use-with-a-larger-panel-ie-64x64px-square-panel)
|
||||
- [Further Information](#further-information)
|
||||
* [Can I chain panels?](#can-i-chain-panels)
|
||||
* [Panel Brightness](#panel-brightness)
|
||||
* [Can I use with a larger panel (i.e. 64x64px square panel)?](#can-i-use-with-a-larger-panel-ie-64x64px-square-panel)
|
||||
* [Adjusting Panel Brightness](#adjusting-panel-brightness)
|
||||
* [Build-time options](#build-time-options)
|
||||
* [Latch blanking](#latch-blanking)
|
||||
* [Power, Power and Power!](#power--power-and-power)
|
||||
* [Power, Power and Power!](#power-power-and-power)
|
||||
* [Inspiration](#inspiration)
|
||||
- [Thank you!](#thank-you)
|
||||
* [Cool uses of this library](#cool-uses-of-this-library)
|
||||
- [Thank you!](#thank-you)
|
||||
|
||||
## Introduction
|
||||
This ESP32 Arduino/IDF library for HUB75 / HUB75E connector type 64x32 RGB LED 1/16 Scan OR 64x64 RGB LED 1/32 Scan LED Matrix Panel, utilities the DMA functionality provided by the ESP32's I2S 'LCD Mode'.
|
||||
# Introduction
|
||||
* This is an ESP32 Arduino/IDF library for HUB75 / HUB75E connection based RGB LED panels.
|
||||
* This library 'out of the box' (mostly) supports HUB75 panels where simple TWO rows/lines are updated in parallel... referred to as 'two scan' panels within this documentation.
|
||||
* 'Four scan' panels are also supported - but please refer to the Four Scan Panel example sketch.
|
||||
* The library uses the DMA functionality provided by the ESP32's 'LCD Mode' for fast data output.
|
||||
|
||||
### Features
|
||||
- **Low CPU overhead** - once initialized pixel data is pumped to the matrix inputs via DMA engine directly from memory
|
||||
- **Fast** - updating pixel data involves only bit-wise logic over DMA buffer memory, no pins manipulation or blocking IO
|
||||
- **Full screen BCM** - library utilizes [binary-code modulation](http://www.batsocks.co.uk/readme/art_bcm_5.htm) to render pixel color depth / brightness over the entire matrix
|
||||
- **Variable color depth** - up to TrueColor 24 bits output is possible depending on matrix size/refresh rate required
|
||||
- **CIE 1931** luminance [correction](https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/) (aka natural LED dimming)
|
||||
- **Adafruit GFX API** - library could be build with AdafruitGFX, simplified GFX or without GFX API at all
|
||||
## Features
|
||||
- **Low CPU overhead** - Pixel data is sent directly with the use of hardware-backed DMA, no CPU involvement
|
||||
- **Fast** - Updating pixel data involves only bit-wise logic over DMA buffer memory, no pins manipulation or blocking IO
|
||||
- **Full screen BCM** - Library utilizes [binary-code modulation](http://www.batsocks.co.uk/readme/art_bcm_5.htm) to render pixel color depth / brightness over the entire matrix to give reasonable colour depth
|
||||
- **Variable color depth** - Up to TrueColor 24 bits output is possible depending on matrix size/refresh rate required
|
||||
- **CIE 1931** luminance [correction](https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/) (aka natural LED dimming) implemented
|
||||
- **Adafruit GFX API** - Library can be built with AdafruitGFX, simplified GFX or without a GFX API at all
|
||||
|
||||
If you wanna ask "*...OK, OK, than what's the price for those features?*" I'll tell you - "[memory](/doc/i2s_memcalc.md), you pay it all by precious MCU's memory for DMA buffer".
|
||||
## ESP32 variants supported
|
||||
* Original ESP32 - That being the ESP-WROOM-32 module with ESP32‑D0WDQ6 chip from ~2017.
|
||||
* ESP32-S2; and
|
||||
* ESP32-S3
|
||||
|
||||
## ESP32 Supported
|
||||
Espressif have kept the 'ESP32' name for all their chips for brand recognition, but their new variant MCU's are different to the ESP32 this library was built for.
|
||||
RISC-V ESP32's (like the C3) are not supported as they do not have the hardware 'LCD mode' support.
|
||||
|
||||
This library supports the *original* ESP32. That being the ESP-WROOM-32 module with ESP32‑D0WDQ6 chip from 2017. This MCU has 520kB of SRAM which is much more than all the recent 'reboots' of the ESP32 such as the S2, S3, C3 etc. If you want to use this library, use with an original ESP32 as it has the most SRAM for DMA.
|
||||
## Required memory
|
||||
"*What's the price for those features?*" - It's [memory](/doc/memcalc.md), you pay it all by precious MCU's internal memory (SRAM) for the DMA buffer.
|
||||
|
||||
Support also exists for the ESP32-S2.
|
||||
Please use the ['Memory Calculator'](/doc/memcalc.md) to see what is *typically* achievable with the typical ESP32. This is only a guide. ![Memory Calculator](doc/memcalc.jpg)
|
||||
|
||||
ESP32-S3 is currently not supported (as of August 2022), but @mrfaptastic is working on this.
|
||||
For the ESP32-S3 only, you can use SPIRAM/PSRAM to drive the HUB75 DMA buffer when using an ESP32-S3 with **OCTAL SPI-RAM (PSTRAM)** (i.e. ESP32 S3 N8R8 variant). However, due to bandwidth limitations, the maximum output frequency is limited to approx. 13Mhz, which will limit the real-world number of panels that can be chained without flicker. Please do not use PSRAM as the DMA buffer if using QUAD SPI (Q-SPI), as it's too slow.
|
||||
|
||||
RISC-V ESP32's (like the C3) are not, and will never be supported as they do not have parallel DMA output required for this library.
|
||||
To enable PSRAM support on the ESP32-S3, refer to [the build options](/doc/BuildOptions.md) to enable.
|
||||
|
||||
## Panels Supported
|
||||
* 64x32 (width x height) pixel 1/16 Scan LED Matrix 'Indoor' Panel, such as this [typical RGB panel available for purchase](https://www.aliexpress.com/item/256-128mm-64-32-pixels-1-16-Scan-Indoor-3in1-SMD2121-RGB-full-color-P4-led/32810362851.html).
|
||||
* 64x64 pixel 1/32 Scan LED Matrix 'Indoor' Panel.
|
||||
* 32x16 pixel 1/4 Scan LED Matrix 'Indoor' Panel using an ingenious workaround as demonstrated in the 32x16_1_4_ScanPanel example.
|
||||
* 126x64 [SM5266P](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/164) 1/32 Scan Panel
|
||||
For all other ESP32 variants (like the most popular ‘original’ ESP32), [only *internal* SRAM can be used](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/55), so you will be limited to the ~200KB or so of 'free' SRAM (because of the memory used for your sketch amongst other things) regardless of how many megabytes of SPIRAM/PSRAM you may have connected.
|
||||
|
||||
|
||||
## Supported panel can types
|
||||
It is impossible to provide a comprehensive list of what panels are supported (or not supported) as new variations of the chips used to 'drive' these panels are created almost weekly (usually from China). You should contact the seller to confirm the chips used in a panel before purchasing to use with this library.
|
||||
|
||||
* 'Two scan' panels where **two** rows/lines are updated in parallel.
|
||||
* 64x32 (width x height) 'Indoor' panels, which are often referred to as 1/16 'scan panel' as every 16th row is updated in parallel (hence why I refer to it as 'two scan')
|
||||
* 64x64 pixel 1/32 Scan LED Matrix 'Indoor' Panel
|
||||
|
||||
* 'Four scan' panels where **four** rows/lines are updated in parallel.
|
||||
* 32x16 pixel 1/4 Scan LED Matrix 'Indoor' Panel using an ingenious workaround as demonstrated in the Four_Scan_Panel example.
|
||||
* 126x64 [SM5266P](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/164)
|
||||
|
||||
Ones interested in internals of such matrices could find [this article](https://www.sparkfun.com/news/2650) useful.
|
||||
|
||||
Due to the high-speed optimized nature of this library, only specific panels are supported. Please do not raise issues with respect to panels not supported on the list below.
|
||||
|
||||
## Panel driver chips known to be working well
|
||||
![Panel Scan Types](doc/ScanRateGraphic.jpg)
|
||||
|
||||
## Specific chips found to work
|
||||
* ICND2012
|
||||
* [RUC7258](http://www.ruichips.com/en/products.html?cateid=17496)
|
||||
* FM6126A AKA ICN2038S, [FM6124](https://datasheet4u.com/datasheet-pdf/FINEMADELECTRONICS/FM6124/pdf.php?id=1309677) (Refer to [PatternPlasma](/examples/2_PatternPlasma) example on how to use.)
|
||||
* SM5266P
|
||||
* SM5266P
|
||||
* DP3246 with SM5368 row addressing registers
|
||||
|
||||
## Panels Not Supported
|
||||
* 1/8 Scan LED Matrix Panels are not supported.
|
||||
## Specific chips found NOT TO work
|
||||
* ANY panel that uses S-PWM or PWM based chips (such as the RUL6024, MBI6024).
|
||||
* [SM1620B](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/issues/416)
|
||||
* RUL5358 / SHIFTREG_ABC_BIN_DE based panels are not supported.
|
||||
* ICN2053 / FM6353 based panels - Refer to [this library](https://github.com/LAutour/ESP32-HUB75-MatrixPanel-DMA-ICN2053), which is a fork of this library ( [discussion link](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/discussions/324)).
|
||||
* Any other panel not listed above.
|
||||
|
||||
Please use an [alternative library](https://github.com/2dom/PxMatrix) if you bought one of these.
|
||||
|
||||
## Update for 16x32 Panels
|
||||
* There is a virtual panel class available to work with 16x32 panels (see: [examples/16x32 Panel](/examples/P6_32x16_1_4_ScanPanel). This Panel includes drawing lines and rectangles, text and scrolling text
|
||||
|
||||
## Cool uses of this library
|
||||
There are a number of great looking LED graphical display projects which leverage this library, these include:
|
||||
* [128x64 Morph Clock](https://github.com/bogd/esp32-morphing-clock)
|
||||
* [FFT Audio Visualisation](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/149)
|
||||
* [Clock, GIF Animator and Audio Visualiser](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/153)
|
||||
* [Aurora Audio Visualiser](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/188)
|
||||
* [Big Visualisation](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/155)
|
||||
* [Clockwise](https://jnthas.github.io/clockwise/)
|
||||
|
||||
# Getting Started
|
||||
## 1. Library Installation
|
||||
|
||||
* Dependency: You will need to install Adafruit_GFX from the "Library > Manage Libraries" menu.
|
||||
* Download and unzip this repository into your Arduino/libraries folder (or better still, use the Arduino 'add library from .zip' option.
|
||||
* Library also tested to work fine with PlatformIO, install into your PlatformIO projects' lib/ folder as appropriate. Or just add it into [platformio.ini](/doc/BuildOptions.md) [lib_depth](https://docs.platformio.org/en/latest/projectconf/section_env_library.html#lib-deps) section.
|
||||
* Install this library from the Arduino Library manager.
|
||||
|
||||
## 2. Wiring ESP32 with the LED Matrix Panel
|
||||
By default the pin mapping is as follows (defaults defined in ESP32-HUB75-MatrixPanel-I2S-DMA.h).
|
||||
Library also tested to work fine with PlatformIO, install into your PlatformIO projects' lib/ folder as appropriate. Or just add it into [platformio.ini](/doc/BuildOptions.md) [lib_deps](https://docs.platformio.org/en/latest/projectconf/section_env_library.html#lib-deps) section.
|
||||
|
||||
## 2. Wiring the ESP32 to an LED Matrix Panel
|
||||
|
||||
Refer to the '*default-pins.hpp' file within the [applicable platforms folder](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/tree/master/src/platforms).
|
||||
|
||||
```
|
||||
HUB 75 PANEL ESP 32 PIN
|
||||
+----------+
|
||||
| R1 G1 | R1 -> IO25 G1 -> IO26
|
||||
| B1 GND | B1 -> IO27
|
||||
| R2 G2 | R2 -> IO14 G2 -> IO12
|
||||
| B2 E | B2 -> IO13 E -> N/A (required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32 )
|
||||
| A B | A -> IO23 B -> IO19
|
||||
| C D | C -> IO05 D -> IO17
|
||||
| CLK LAT | CLK -> IO16 LAT -> IO 4
|
||||
| OE GND | OE -> IO15 GND -> ESP32 GND
|
||||
+----------+
|
||||
```
|
||||
If you want to change the GPIO mapping at runtime, simply provide the wanted pin mapping as part of the class initialization structure. For example, in your sketch have something like the following:
|
||||
|
||||
However, if you want to change this, simply provide the wanted pin mapping as part of the class initialization structure. For example, in your sketch have something like the following:
|
||||
|
||||
```
|
||||
// Change these to whatever suits
|
||||
#define R1_PIN 25
|
||||
#define G1_PIN 26
|
||||
|
@ -125,7 +116,7 @@ However, if you want to change this, simply provide the wanted pin mapping as pa
|
|||
#define B_PIN 19
|
||||
#define C_PIN 5
|
||||
#define D_PIN 17
|
||||
#define E_PIN -1 // required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32
|
||||
#define E_PIN -1 // required for 1/32 scan panels, like 64x64px. Any available pin would do, i.e. IO32
|
||||
#define LAT_PIN 4
|
||||
#define OE_PIN 15
|
||||
#define CLK_PIN 16
|
||||
|
@ -140,31 +131,72 @@ HUB75_I2S_CFG mxconfig(
|
|||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
```
|
||||
|
||||
Make sure you also connect one of the HUB75 interfaces ground pins to a ground pin of the ESP32, otherwise you may get electrical artefacts on LED Matrix Panel.
|
||||
|
||||
Various people have created PCBs for which one can simply connect an ESP32 to a PCB, and then the PCB to the HUB75 connector, such as:
|
||||
|
||||
* Brian Lough's [ESP32 I2S Matrix Shield](http://blough.ie/i2smat/)
|
||||
* Brian Lough's [ESP32 I2S Matrix Shield](https://github.com/rorosaurus/esp32-hub75-driver)
|
||||
* Charles Hallard's [WeMos Matrix Shield](https://github.com/hallard/WeMos-Matrix-Shield-DMA)
|
||||
* Bogdan Sass's [Morph Clock Shield](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/110#discussioncomment-861152)
|
||||
|
||||
Please contact or order these products from the respective authors.
|
||||
|
||||
### How can I configure it to work with an off-the-shelf board/shield with HUB75 connector, e.g. Adafruit MatrixPortal?
|
||||
|
||||
You need to find the correct pin mapping for your board. For Adafruit boards/shields, you can look in one of the examples provided with the Protomatter library, for example [here](https://github.com/adafruit/Adafruit_Protomatter/blob/master/examples/doublebuffer_scrolltext/doublebuffer_scrolltext.ino). Find your board variant, copy the pin values into the `#define`s described above, and pass the pin mapping into your `mxconfig`.
|
||||
|
||||
For example, for MatrixPortal S3, the Protomatter example file contains the following:
|
||||
|
||||
```
|
||||
uint8_t rgbPins[] = {42, 41, 40, 38, 39, 37};
|
||||
uint8_t addrPins[] = {45, 36, 48, 35, 21};
|
||||
uint8_t clockPin = 2;
|
||||
uint8_t latchPin = 47;
|
||||
uint8_t oePin = 14;
|
||||
```
|
||||
|
||||
which for use with this library, converts to:
|
||||
|
||||
```
|
||||
#define R1_PIN 42
|
||||
#define G1_PIN 41
|
||||
#define B1_PIN 40
|
||||
#define R2_PIN 38
|
||||
#define G2_PIN 39
|
||||
#define B2_PIN 37
|
||||
#define A_PIN 45
|
||||
#define B_PIN 36
|
||||
#define C_PIN 48
|
||||
#define D_PIN 35
|
||||
#define E_PIN 21
|
||||
#define LAT_PIN 47
|
||||
#define OE_PIN 14
|
||||
#define CLK_PIN 2
|
||||
|
||||
HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN};
|
||||
|
||||
// Module configuration
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN, // Chain length
|
||||
_pins // Pin mapping
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
### Can I use with a larger panel (i.e. 64x64px square panel)?
|
||||
If you want to use with a 64x64 pixel panel (typically a HUB75*E* panel) you MUST configure a valid *E_PIN* to your ESP32 and connect it to the E pin of the HUB75 panel! Hence the 'E' in 'HUB75E'
|
||||
|
||||
|
||||
## 3. Run a Test Sketch
|
||||
Below is a bare minimum sketch to draw a single white dot in the top left. You must call begin() before you call ANY pixel-drawing (fonts, lines, colours etc.) function of the MatrixPanel_I2S_DMA class.
|
||||
|
||||
Once this is working, refer to the [PIO Test Patterns](/examples/PIO_TestPatterns) example. This sketch draws simple colors/lines/gradients over the entire matrix and it could help to troubleshoot various issues with ghosting, flickering, etc...
|
||||
>Note: Requires the use of [PlatformIO](https://platformio.org/), which you should probably use if you aren't already.
|
||||
# More Information
|
||||
## Build-time options
|
||||
Although Arduino IDE does not [seem](https://github.com/arduino/Arduino/issues/421) to offer any way of specifying compile-time options for external libs there are other IDE's (like [PlatformIO](https://platformio.org/)/[Eclipse](https://www.eclipse.org/ide/)) that could use that. Check [Build Options](doc/BuildOptions.md) document for reference.
|
||||
|
||||
## Memory constraints
|
||||
If you are going to use large/combined panels make sure to check for [memory constraints](/doc/i2s_memcalc.md).
|
||||
|
||||
NOTE: You *cannot* use PSRAM to expand the amount of memory available to use by this library. ESP32 hardware [only allows DMA transfer from *internal* SRAM](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/55), so you will be limited to the 200KB or so of usable SRAM of the ESP32 regardless of how many megabytes of PSRAM you may have connected.
|
||||
|
||||
## Can I use with a larger panel (i.e. 64x64px square panel)?
|
||||
If you want to use with a 64x64 pixel panel (typically a HUB75*E* panel) you MUST configure a valid *E_PIN* to your ESP32 and connect it to the E pin of the HUB75 panel! Hence the 'E' in 'HUB75E'
|
||||
Note: Requires the use of [PlatformIO](https://platformio.org/), which you should probably use if you aren't already.
|
||||
|
||||
# Further information
|
||||
## Can I chain panels?
|
||||
Yes!
|
||||
|
||||
|
@ -172,34 +204,31 @@ Yes!
|
|||
|
||||
For example: If you want to chain two of these horizontally to make a 128x32 panel you can do so by connecting the panels in series using the HUB75 ribbon cable. Than you must provide proper configuration structure to the class constructor letting it know that you use "one long virtual matrix chain". Refer to [Pattern Plasma](/examples/2_PatternPlasma/) example for all the details about configuration setup.
|
||||
|
||||
Finally, if you wanted to chain 4 x (64x32px) panels to make 128x64px display (essentially a 2x2 grid of 64x32 LED Matrix modules), a little more magic will be required. Refer to the [Chained Panels](examples/ChainedPanels/) example.
|
||||
Finally, if you wanted to chain 4 x (64x32px) panels to make 128x64px display (essentially a 2x2 grid of 64x32 LED Matrix modules), a little more magic will be required. Refer to the [VirtualMatrixPanel](examples/VirtualMatrixPanel/) example and the [AuroraDemo](examples/AuroraDemo/) example of its practical use.
|
||||
|
||||
Resolutions beyond 128x64 are more likely to result in crashes due to [memory](/doc/i2s_memcalc.md) constraints etc. You are on your own after this point - PLEASE do not raise issues about this, the library can't magically defeat the SRAM memory constraints of the ESP32.
|
||||
|
||||
![ezgif com-video-to-gif](https://user-images.githubusercontent.com/12006953/89837358-b64c0480-db60-11ea-870d-4b6482068a3b.gif)
|
||||
|
||||
## Panel Brightness
|
||||
## Adjusting Panel Brightness
|
||||
|
||||
By default you should not need to change / set the brightness setting as the default value (16) is sufficient for most purposes. Brightness can be changed by calling `setPanelBrightness(int XX)` or `setBrightness8(uint8_t XX)`.
|
||||
By default you should not need to change / set the brightness value (which is 128 or 50%) as it should be sufficient for most purposes. Brightness can be changed by calling `setPanelBrightness(xx)` or `setBrightness8(xx)`.
|
||||
|
||||
The value to pass `setPanelBrightness()` must be less than MATRIX_CHAIN_WIDTH in pixels. For example for a single 64x32 LED Matrix Module, a value must be less than 64. For 3 modules 64x32 it must be less than 192. However, if you set the brightness too high, you may experience ghosting.
|
||||
|
||||
Also you may use method `setBrightness8(x)`, where x is a uint8_t value between 0-255. Library will recalculate required brightness level depending on matrix width (mostly useful with FastLED-based sketches).
|
||||
The value to pass must be a number between 0 (for a black screen) and 255 (max brightness).
|
||||
|
||||
Example:
|
||||
```
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
dma_display->begin(); // setup the LED matrix
|
||||
dma_display->setBrightness8(90); //0-255
|
||||
dma_display->setBrightness8(192); //0-255
|
||||
dma_display->clearScreen();
|
||||
}
|
||||
```
|
||||
![Brightness Samples](https://user-images.githubusercontent.com/55933003/211192894-f90311f5-b6fe-4665-bf26-2f363bb36047.png)
|
||||
|
||||
Summary: setPanelBrightness(xx) value can be any number from 0 (display off) to MATRIX_WIDTH-1. So if you are chaining multiple 64x32 panels, then this value may actually be > 64 (or you will have a dim display). Changing the brightness will have a huge impact on power usage.
|
||||
|
||||
![It's better in real life](image.jpg)
|
||||
|
||||
## Build-time options
|
||||
Although Arduino IDE does not [seem](https://github.com/arduino/Arduino/issues/421) to offer any way of specifying compile-time options for external libs there are other IDE's (like [PlatformIO](https://platformio.org/)/[Eclipse](https://www.eclipse.org/ide/)) that could use that. Check [Build Options](doc/BuildOptions.md) document for reference.
|
||||
|
||||
## Latch blanking
|
||||
If you are facing issues with image ghosting when pixels has clones with horizontal offset, than you try to change Latch blanking value. Latch blanking controls for how many clock pulses matrix output is disabled via EO signal before/after toggling LAT signal. It hides row bits transitioning and different panels may require longer times for proper operation. Default value is 1 clock before/after LAT row transition. This could be controlled with `MatrixPanel_I2S_DMA::setLatBlanking(uint8_t v)`. v could be between 1 to 4, default is 1, larger values won't give any benefit other than reducing brightness.
|
||||
|
@ -223,10 +252,26 @@ This project was inspired by:
|
|||
* 'SmartMatrix': https://github.com/pixelmatix/SmartMatrix/tree/teensylc
|
||||
* Sprite_TM's demo implementation here: https://www.esp32.com/viewtopic.php?f=17&t=3188
|
||||
|
||||
|
||||
## Cool uses of this library
|
||||
There are a number of great looking LED graphical display projects which leverage this library, these include:
|
||||
* [128x64 Morph Clock](https://github.com/bogd/esp32-morphing-clock)
|
||||
* [FFT Audio Visualisation](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/149)
|
||||
* [Clock, GIF Animator and Audio Visualiser](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/153)
|
||||
* [Aurora Audio Visualiser](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/188)
|
||||
* [Big Visualisation](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/discussions/155)
|
||||
* [Clockwise](https://jnthas.github.io/clockwise/)
|
||||
* [ZeDMD](https://github.com/PPUC/ZeDMD)
|
||||
|
||||
# Thank you!
|
||||
* [Brian Lough](https://www.tindie.com/stores/brianlough/) ([youtube link](https://www.youtube.com/c/brianlough)) for providing code contributions, hardware and suggestions
|
||||
* [Vortigont](https://github.com/vortigont) for his game changing code contributions and performance optimisations
|
||||
* [Galaxy Man](https://github.com/Galaxy-Man) for donation of 1/16 scan panels to support the implemenation of led matrix panel chaining (virtual display) support
|
||||
* [Pipimaxi](https://github.com/Pipimaxi) for the donation of a ESP32-S2 to enable support for ESP32 S2/S3's to be implemented
|
||||
* [Pipimaxi](https://github.com/Pipimaxi) for the donation of a ESP32-S2 and [Radu](https://github.com/juniorradu) for the donation of an ESP32-S3 to enable support for ESP32 S2/S3's to be tested and implemented.
|
||||
* [Mark Donners](https://github.com/donnersm) ('The Electronic Engineer' on [youtube](https://www.youtube.com/watch?v=bQ7c9Vlhyp0&t=118s)) for the donation of a 1/8 scan panel to build and test working support of these led matrix panels!
|
||||
* [PaintYourDragon](https://github.com/PaintYourDragon) for the DMA logic for the ESP32-S3.
|
||||
* And lots of others, let me know if I've missed you.
|
||||
|
||||
If you want to donate money to the project, please refer to [this discussion](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/discussions/349) about it. If you want to donate/buy an LED panel for the library author to improve compatibility and/or testing - please feel free to post in the same [discussion](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/discussions/349).
|
||||
|
||||
![It's better in real life](image.jpg)
|
||||
|
|
Before Width: | Height: | Size: 71 KiB |
|
@ -1,6 +1,7 @@
|
|||
### Build Options and flags
|
||||
|
||||
This lib supports build-time defines used to set some of the basic key features.
|
||||
This library supports build-time defines to modify its features or enable greater debugging information. Please use the debugging capabilities before raising any issues.
|
||||
|
||||
For example build flags could be set using PlatformIO's .ini file like this
|
||||
|
||||
```
|
||||
|
@ -10,22 +11,28 @@ platform = espressif32
|
|||
lib_deps =
|
||||
ESP32 HUB75 LED MATRIX PANEL DMA Display
|
||||
build_flags =
|
||||
-DSERIAL_DEBUG
|
||||
-DNO_GFX
|
||||
-DCORE_DEBUG_LEVEL=3
|
||||
-DNO_GFX=1
|
||||
(etc.....)
|
||||
```
|
||||
Or if using Arduino: 'Tools' menu > 'Core Debug Level' > Select 'Debug'
|
||||
|
||||
... and use the Serial output to see the debug information.
|
||||
|
||||
## Build flags
|
||||
|
||||
| Flag | Description | Note |
|
||||
| :------------ |---------------|-----|
|
||||
| **SERIAL_DEBUG** |Print out detailed information about memory allocations, DMA descriptors setup and color depth [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm) |
|
||||
| **CORE_DEBUG_LEVEL** |Adjust the espressif ESP32 IDF debug level, for which this library leverages to output information on what is going on when allocating memory etc. This will provide detailed information about memory allocations, DMA descriptors setup and color depth [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm) |Set value to at least 3 [(Info)](https://iotespresso.com/core-debug-level-in-esp32/)
|
||||
| **USE_GFX_ROOT** | Use [lightweight](https://github.com/mrfaptastic/Adafruit_GFX_Lite) version of AdafuitGFX, without Adafruit BusIO extensions | You **must** install [Adafruit_GFX_Lite](https://github.com/mrfaptastic/Adafruit_GFX_Lite) library instead of original AdafruitGFX|
|
||||
| **NO_GFX** | Build without AdafuitGFX API, only native methods supported based on manipulating DMA buffer. I.e. no methods of drawing circles/shapes, typing text or using fonts!!! This might save some resources for applications using it's own internal graphics buffer or working solely with per-pixel manipulation. | Use this if you rely on FastLED, Neomatrix or any other API. For example [Aurora](/examples/AuroraDemo/) effects can work fine w/o AdafruitGFX. |
|
||||
| **NO_FAST_FUNCTIONS** | Do not build auxiliary speed-optimized functions. Those are used to speed-up operations like drawing straight lines or rectangles. Otherwise lines/shapes are drawn using drawPixel() method. The trade-off for speed is RAM/code-size, take it or leave it ;) | If you are not using AdafruitGFX than you probably do not need this either|
|
||||
|**NO_CIE1931**|Do not use LED brightness [compensation](https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/) described in [CIE 1931](https://en.wikipedia.org/wiki/CIE_1931_color_space). Normally library would adjust every pixel's RGB888 so that luminance (or brightness control) for the corresponding LED's would appear 'linear' to the human's eye. I.e. a white dot with rgb(128,128,128) would seem to be at 50% brightness between rgb(0,0,0) and rgb(255,255,255). Normally you would like to keep this enabled by default. Not only it makes brightness control "linear", it also makes colors more vivid, otherwise it looks brighter but 'bleached'.|You might want to turn it off in some special cases like: <ul><li>Using some other overlay lib for intermediate calculations that makes it's own compensation, like FastLED's [dimming functions](http://fastled.io/docs/3.1/group___dimming.html).<li>running at low color depth's - it **might** (or might not) look better in shadows, darker gradients w/o compensation, try it<li>you run for as bright output as possible, no matter what (make sure you have proper powering)<li>you run for speed/save resources at all costs</ul> |
|
||||
|**NO_CIE1931**|Do not use LED brightness [compensation](https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/) described in [CIE 1931](https://en.wikipedia.org/wiki/CIE_1931_color_space). Normally library would adjust every pixel's RGB888 so that luminance (or brightness control) for the corresponding LED's would appear 'linear' to the human's eye. I.e. a white dot with rgb(128,128,128) would seem to be at 50% brightness between rgb(0,0,0) and rgb(255,255,255). Normally you would like to keep this enabled by default. Not only it makes brightness control "linear", it also makes colours more vivid, otherwise it looks brighter but 'bleached'.|You might want to turn it off in some special cases like: <ul><li>Using some other overlay lib for intermediate calculations that makes it's own compensation, like FastLED's [dimming functions](http://fastled.io/docs/3.1/group___dimming.html).<li>running at low colour depth's - it **might** (or might not) look better in shadows, darker gradients w/o compensation, try it<li>you run for as bright output as possible, no matter what (make sure you have proper powering)<li>you run for speed/save resources at all costs</ul> |
|
||||
| **FORCE_COLOR_DEPTH** |In some cases the library may reduce colour fidelity to increase the refresh rate (i.e. reduce visible flicker). This is most likely to occur with a large chain of panels. However, if you want to force pure 24bpp colour, at the expense of likely noticeable flicker, then set this defined. |Not required in 99% of cases.
|
||||
| **SPIRAM_FRAMEBUFFER** |Use SPIRAM/PSRAM for the HUB75 DMA buffer and not internal SRAM. ONLY SUPPORTED ON ESP32-S3 VARIANTS WITH OCTAL (not quad!) SPIRAM/PSRAM, as ony OCTAL PSRAM an provide the required data rate / bandwidth to drive the panels adequately.|ONLY SUPPORTED ON ESP32-S3 VARIANTS WITH OCTAL (not quad) SPIRAM/PSRAM
|
||||
|
||||
## Build-time variables
|
||||
|
||||
| Flag | Description | Note |
|
||||
| :------------ |---------------|-----|
|
||||
| **PIXEL_COLOR_DEPTH_BITS=8** | Color depth per color per pixel in range 2-8. More bit's - more natural color. But on the other hand every additional bit:<ul><li>eats ~2.5 bits of DMA memory per pixel<li>reduces matrix refresh rate in power of two due to nature of [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm)</ul> | Default is 8 bits per color per pixel, i.e. TrueColor 24 bit RGB. For higher resolutions, from 64x64 and above it is not possible to provide full 24 bits color without significant flickering OR reducing dynamic range in shadows. In that case using 5-6 bits at high res make very small difference to the humans eye actually. Refer to the [I2S memcalc](i2s_memcalc.md) for more details|
|
||||
| **PIXEL_COLOR_DEPTH_BITS=8** | Colour depth per pixel in range 2-8. More bit's - more natural colour. But on the other hand every additional bit:<ul><li>eats ~2.5 bits of DMA memory per pixel<li>reduces matrix refresh rate in power of two due to nature of [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm)</ul> | For large chains of panels (i.e. 6 x 64x64 panels) you WILL need to reduce the colour depth, or likely run out of memory. Default is 8 bits per colour per pixel, i.e. True colour 24 bit RGB. <br><br>For higher resolutions, from 64x64 and above it is not possible to provide full 24 bits colour without significant flickering OR reducing dynamic range in shadows. In that case using 5-6 bits at high res make very small difference to the human’s eye actually. Refer to the [I2S memcalc](i2s_memcalc.md) for more details.
|
||||
|
|
BIN
doc/Panel_Chaining_Types.ods
Normal file
BIN
doc/ScanRateGraphic.jpg
Normal file
After Width: | Height: | Size: 111 KiB |
BIN
doc/ScanRateGraphic.odp
Normal file
BIN
doc/VirtualMatrixPanel (old).odp
Normal file
BIN
doc/VirtualMatrixPanel.odp
Normal file
BIN
doc/VirtualMatrixPanel.pdf
Normal file
BIN
doc/i2scalc.png
Before Width: | Height: | Size: 28 KiB |
BIN
doc/memcalc.jpg
Normal file
After Width: | Height: | Size: 71 KiB |
|
@ -1,6 +1,6 @@
|
|||
### I2S HUB75 Calculator
|
||||
### Memory Calculator
|
||||
|
||||
I've made this [spreadsheet](i2s_memcalc.xlsm) to estimate all of the main parameters for ESP32-HUB75-MatrixPanel-I2S-DMA lib driving any combination of matrices/chains so that I do not need to reflash it hundreds of times just to check for the debug info about memory.
|
||||
I've made this [spreadsheet](memcalc.xlsm) to estimate all of the main parameters for ESP32-HUB75-MatrixPanel-DMA lib driving any combination of matrices/chains so that I do not need to reflash it hundreds of times just to check for the debug info about memory.
|
||||
Be sure to enable embedded macro's to allow refresh rate calculations.
|
||||
|
||||
![](i2scalc.png)
|
||||
|
@ -8,7 +8,7 @@ Just fill-in all of the INPUT fields and get the OUTPUTs.
|
|||
|
||||
So there are two main resources used to drive LED matrix
|
||||
- Memory
|
||||
- I2S clock speed (resulting in available bandwidth to pump pixel color data)
|
||||
- Bus clock speed (resulting in available bandwidth to pump pixel color data)
|
||||
|
||||
And there are lot's of hogs for those:
|
||||
- matrix resolution (number of pixels)
|
BIN
doc/memcalc.xlsm
Normal file
|
@ -1,444 +0,0 @@
|
|||
/*
|
||||
* ESP32_I2S_PARALLEL_DMA (Version 3)
|
||||
*
|
||||
* Author: Mrfaptastic @ https://github.com/mrfaptastic/
|
||||
*
|
||||
* Description: Multi-ESP32 product DMA setup functions for WROOM & S2, S3 mcu's.
|
||||
*
|
||||
* Credits:
|
||||
* 1) https://www.esp32.com/viewtopic.php?f=17&t=3188 for original ref. implementation
|
||||
* 2) https://github.com/TobleMiner/esp_i2s_parallel for a cleaner implementation
|
||||
*
|
||||
*/
|
||||
|
||||
// Header
|
||||
#include "esp32_i2s_parallel_dma.h"
|
||||
#include "esp32_i2s_parallel_mcu_def.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/periph_ctrl.h>
|
||||
#include <soc/gpio_sig_map.h>
|
||||
|
||||
// For I2S state management.
|
||||
static i2s_parallel_state_t *i2s_state = NULL;
|
||||
|
||||
// ESP32-S2,S3,C3 only has IS20
|
||||
// Original ESP32 has two I2S's, but we'll stick with the lowest common denominator.
|
||||
|
||||
#ifdef ESP32_ORIG
|
||||
static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
|
||||
#else
|
||||
static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0};
|
||||
#endif
|
||||
|
||||
callback shiftCompleteCallback;
|
||||
void setShiftCompleteCallback(callback f) {
|
||||
shiftCompleteCallback = f;
|
||||
}
|
||||
|
||||
volatile int previousBufferOutputLoopCount = 0;
|
||||
volatile bool previousBufferFree = true;
|
||||
|
||||
static void IRAM_ATTR irq_hndlr(void* arg) { // if we use I2S1 (default)
|
||||
|
||||
//i2s_port_t port = *((i2s_port_t*) arg);
|
||||
|
||||
/* Saves a few cycles, no need to cast void ptr to i2s_port_t and then check 120 times second... */
|
||||
SET_PERI_REG_BITS(I2S_INT_CLR_REG(ESP32_I2S_DEVICE), I2S_OUT_EOF_INT_CLR_V, 1, I2S_OUT_EOF_INT_CLR_S);
|
||||
|
||||
previousBufferFree = true;
|
||||
|
||||
/*
|
||||
if(shiftCompleteCallback) { // we've defined a callback function ?
|
||||
shiftCompleteCallback();
|
||||
}
|
||||
*/
|
||||
|
||||
} // end irq_hndlr
|
||||
|
||||
|
||||
// For peripheral setup and configuration
|
||||
static inline int get_bus_width(i2s_parallel_cfg_bits_t width) {
|
||||
switch(width) {
|
||||
case I2S_PARALLEL_WIDTH_8:
|
||||
return 8;
|
||||
case I2S_PARALLEL_WIDTH_16:
|
||||
return 16;
|
||||
case I2S_PARALLEL_WIDTH_24:
|
||||
return 24;
|
||||
default:
|
||||
return -ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
static void iomux_set_signal(int gpio, int signal) {
|
||||
if(gpio < 0) {
|
||||
return;
|
||||
}
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(gpio, GPIO_MODE_DEF_OUTPUT);
|
||||
gpio_matrix_out(gpio, signal, false, false);
|
||||
|
||||
// More mA the better...
|
||||
gpio_set_drive_capability((gpio_num_t)gpio, (gpio_drive_cap_t)3);
|
||||
|
||||
}
|
||||
|
||||
static void dma_reset(i2s_dev_t* dev) {
|
||||
dev->lc_conf.in_rst = 1;
|
||||
dev->lc_conf.in_rst = 0;
|
||||
dev->lc_conf.out_rst = 1;
|
||||
dev->lc_conf.out_rst = 0;
|
||||
|
||||
dev->lc_conf.ahbm_rst = 1;
|
||||
dev->lc_conf.ahbm_rst = 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void fifo_reset(i2s_dev_t* dev) {
|
||||
dev->conf.rx_fifo_reset = 1;
|
||||
|
||||
#ifdef ESP32_SXXX
|
||||
while(dev->conf.rx_fifo_reset_st); // esp32-s2 only
|
||||
#endif
|
||||
dev->conf.rx_fifo_reset = 0;
|
||||
|
||||
dev->conf.tx_fifo_reset = 1;
|
||||
#ifdef ESP32_SXXX
|
||||
while(dev->conf.tx_fifo_reset_st); // esp32-s2 only
|
||||
#endif
|
||||
|
||||
dev->conf.tx_fifo_reset = 0;
|
||||
}
|
||||
|
||||
static void dev_reset(i2s_dev_t* dev) {
|
||||
fifo_reset(dev);
|
||||
dma_reset(dev);
|
||||
dev->conf.rx_reset=1;
|
||||
dev->conf.tx_reset=1;
|
||||
dev->conf.rx_reset=0;
|
||||
dev->conf.tx_reset=0;
|
||||
}
|
||||
|
||||
// DMA Linked List
|
||||
// Size must be less than DMA_MAX - need to handle breaking long transfer into two descriptors before call
|
||||
// DMA_MAX by the way is the maximum data packet size you can hold in one chunk
|
||||
void link_dma_desc(volatile lldesc_t *dmadesc, volatile lldesc_t *prevdmadesc, void *memory, size_t size)
|
||||
{
|
||||
if(size > DMA_MAX) size = DMA_MAX;
|
||||
|
||||
dmadesc->size = size;
|
||||
dmadesc->length = size;
|
||||
dmadesc->buf = memory;
|
||||
dmadesc->eof = 0;
|
||||
dmadesc->sosf = 0;
|
||||
dmadesc->owner = 1;
|
||||
dmadesc->qe.stqe_next = 0; // will need to set this elsewhere
|
||||
dmadesc->offset = 0;
|
||||
|
||||
// link previous to current
|
||||
if(prevdmadesc)
|
||||
prevdmadesc->qe.stqe_next = (lldesc_t*)dmadesc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* conf) {
|
||||
|
||||
//port = I2S_NUM_0; /// override.
|
||||
|
||||
if(port < I2S_NUM_0 || port >= I2S_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(conf->sample_width < I2S_PARALLEL_WIDTH_8 || conf->sample_width >= I2S_PARALLEL_WIDTH_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(conf->sample_rate > I2S_PARALLEL_CLOCK_HZ || conf->sample_rate < 1) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
uint32_t clk_div_main = I2S_PARALLEL_CLOCK_HZ / conf->sample_rate / i2s_parallel_get_memory_width(port, conf->sample_width);
|
||||
if(clk_div_main < 2 || clk_div_main > 0xFF) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
volatile int iomux_signal_base;
|
||||
volatile int iomux_clock;
|
||||
int irq_source;
|
||||
|
||||
// Initialize I2S0 peripheral
|
||||
if (port == I2S_NUM_0) {
|
||||
periph_module_reset(PERIPH_I2S0_MODULE);
|
||||
periph_module_enable(PERIPH_I2S0_MODULE);
|
||||
iomux_clock = I2S0O_WS_OUT_IDX;
|
||||
irq_source = ETS_I2S0_INTR_SOURCE;
|
||||
|
||||
switch(conf->sample_width) {
|
||||
case I2S_PARALLEL_WIDTH_8:
|
||||
case I2S_PARALLEL_WIDTH_16:
|
||||
iomux_signal_base = I2S0O_DATA_OUT8_IDX;
|
||||
break;
|
||||
case I2S_PARALLEL_WIDTH_24:
|
||||
iomux_signal_base = I2S0O_DATA_OUT0_IDX;
|
||||
break;
|
||||
case I2S_PARALLEL_WIDTH_MAX:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
#ifdef ESP32_ORIG
|
||||
// Can't compile if I2S1 if it doesn't exist with that hardware's IDF....
|
||||
else {
|
||||
// I2S = &I2S1;
|
||||
|
||||
periph_module_reset(PERIPH_I2S1_MODULE);
|
||||
periph_module_enable(PERIPH_I2S1_MODULE);
|
||||
iomux_clock = I2S1O_WS_OUT_IDX;
|
||||
irq_source = ETS_I2S1_INTR_SOURCE;
|
||||
|
||||
switch(conf->sample_width) {
|
||||
case I2S_PARALLEL_WIDTH_16:
|
||||
iomux_signal_base = I2S1O_DATA_OUT8_IDX;
|
||||
break;
|
||||
case I2S_PARALLEL_WIDTH_8:
|
||||
case I2S_PARALLEL_WIDTH_24:
|
||||
iomux_signal_base = I2S1O_DATA_OUT0_IDX;
|
||||
break;
|
||||
case I2S_PARALLEL_WIDTH_MAX:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup GPIOs
|
||||
int bus_width = get_bus_width(conf->sample_width);
|
||||
|
||||
// Setup I2S peripheral
|
||||
i2s_dev_t* dev = I2S[port];
|
||||
//dev_reset(dev);
|
||||
|
||||
|
||||
// Setup GPIO's
|
||||
for(int i = 0; i < bus_width; i++) {
|
||||
iomux_set_signal(conf->gpio_bus[i], iomux_signal_base + i);
|
||||
}
|
||||
iomux_set_signal(conf->gpio_clk, iomux_clock);
|
||||
|
||||
// invert clock phase if required
|
||||
if (conf->clkphase)
|
||||
GPIO.func_out_sel_cfg[conf->gpio_clk].inv_sel = 1;
|
||||
|
||||
// Setup i2s clock
|
||||
dev->sample_rate_conf.val = 0;
|
||||
|
||||
// Third stage config, width of data to be written to IO (I think this should always be the actual data width?)
|
||||
dev->sample_rate_conf.rx_bits_mod = bus_width;
|
||||
dev->sample_rate_conf.tx_bits_mod = bus_width;
|
||||
|
||||
dev->sample_rate_conf.rx_bck_div_num = 2;
|
||||
dev->sample_rate_conf.tx_bck_div_num = 2;
|
||||
|
||||
// Clock configuration
|
||||
dev->clkm_conf.val=0; // Clear the clkm_conf struct
|
||||
|
||||
#ifdef ESP32_SXXX
|
||||
dev->clkm_conf.clk_sel = 2; // esp32-s2 only
|
||||
dev->clkm_conf.clk_en = 1;
|
||||
#endif
|
||||
|
||||
#ifdef ESP32_ORIG
|
||||
dev->clkm_conf.clka_en=0; // Use the 160mhz system clock (PLL_D2_CLK) when '0'
|
||||
#endif
|
||||
|
||||
dev->clkm_conf.clkm_div_b=0; // Clock numerator
|
||||
dev->clkm_conf.clkm_div_a=1; // Clock denominator
|
||||
|
||||
|
||||
// Note: clkm_div_num must only be set here AFTER clkm_div_b, clkm_div_a, etc. Or weird things happen!
|
||||
// On original ESP32, max I2S DMA parallel speed is 20Mhz.
|
||||
dev->clkm_conf.clkm_div_num = clk_div_main;
|
||||
|
||||
|
||||
// I2S conf2 reg
|
||||
dev->conf2.val = 0;
|
||||
dev->conf2.lcd_en = 1;
|
||||
dev->conf2.lcd_tx_wrx2_en=0;
|
||||
dev->conf2.lcd_tx_sdx2_en=0;
|
||||
|
||||
// I2S conf reg
|
||||
dev->conf.val = 0;
|
||||
|
||||
#ifdef ESP32_SXXX
|
||||
dev->conf.tx_dma_equal=1; // esp32-s2 only
|
||||
dev->conf.pre_req_en=1; // esp32-s2 only - enable I2S to prepare data earlier? wtf?
|
||||
#endif
|
||||
|
||||
// Now start setting up DMA FIFO
|
||||
dev->fifo_conf.val = 0;
|
||||
dev->fifo_conf.rx_data_num = 32; // Thresholds.
|
||||
dev->fifo_conf.tx_data_num = 32;
|
||||
dev->fifo_conf.dscr_en = 1;
|
||||
|
||||
#ifdef ESP32_ORIG
|
||||
|
||||
// Enable "One datum will be written twice in LCD mode" - for some reason,
|
||||
// if we don't do this in 8-bit mode, data is updated on half-clocks not clocks
|
||||
if(conf->sample_width == I2S_PARALLEL_WIDTH_8)
|
||||
dev->conf2.lcd_tx_wrx2_en=1;
|
||||
|
||||
// Not really described for non-pcm modes, although datasheet states it should be set correctly even for LCD mode
|
||||
// First stage config. Configures how data is loaded into fifo
|
||||
if(conf->sample_width == I2S_PARALLEL_WIDTH_24) {
|
||||
// Mode 0, single 32-bit channel, linear 32 bit load to fifo
|
||||
dev->fifo_conf.tx_fifo_mod = 3;
|
||||
} else {
|
||||
// Mode 1, single 16-bit channel, load 16 bit sample(*) into fifo and pad to 32 bit with zeros
|
||||
// *Actually a 32 bit read where two samples are read at once. Length of fifo must thus still be word-aligned
|
||||
dev->fifo_conf.tx_fifo_mod = 1;
|
||||
}
|
||||
|
||||
// Dictated by ESP32 datasheet
|
||||
dev->fifo_conf.rx_fifo_mod_force_en = 1;
|
||||
dev->fifo_conf.tx_fifo_mod_force_en = 1;
|
||||
|
||||
// Second stage config
|
||||
dev->conf_chan.val = 0;
|
||||
|
||||
// 16-bit single channel data
|
||||
dev->conf_chan.tx_chan_mod = 1;
|
||||
dev->conf_chan.rx_chan_mod = 1;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Device Reset
|
||||
dev_reset(dev);
|
||||
dev->conf1.val = 0;
|
||||
dev->conf1.tx_stop_en = 0;
|
||||
|
||||
// Allocate I2S status structure for buffer swapping stuff
|
||||
i2s_state = (i2s_parallel_state_t*) malloc(sizeof(i2s_parallel_state_t));
|
||||
assert(i2s_state != NULL);
|
||||
i2s_parallel_state_t *state = i2s_state;
|
||||
|
||||
state->desccount_a = conf->desccount_a;
|
||||
state->desccount_b = conf->desccount_b;
|
||||
state->dmadesc_a = conf->lldesc_a;
|
||||
state->dmadesc_b = conf->lldesc_b;
|
||||
state->i2s_interrupt_port_arg = port; // need to keep this somewhere in static memory for the ISR
|
||||
|
||||
dev->timing.val = 0;
|
||||
|
||||
// We using the double buffering switch logic?
|
||||
if (conf->int_ena_out_eof)
|
||||
{
|
||||
// Get ISR setup
|
||||
esp_err_t err = esp_intr_alloc(irq_source,
|
||||
(int)(ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1),
|
||||
irq_hndlr,
|
||||
&state->i2s_interrupt_port_arg, NULL);
|
||||
|
||||
if(err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
// Setup interrupt handler which is focussed only on the (page 322 of Tech. Ref. Manual)
|
||||
// "I2S_OUT_EOF_INT: Triggered when rxlink has finished sending a packet"
|
||||
// ... whatever the hell that is supposed to mean... One massive linked list? So all pixels in the chain?
|
||||
dev->int_ena.out_eof = 1;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2s_parallel_stop_dma(i2s_port_t port) {
|
||||
if(port < I2S_NUM_0 || port >= I2S_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
i2s_dev_t* dev = I2S[port];
|
||||
|
||||
// Stop all ongoing DMA operations
|
||||
dev->out_link.stop = 1;
|
||||
dev->out_link.start = 0;
|
||||
dev->conf.tx_start = 0;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t i2s_parallel_send_dma(i2s_port_t port, lldesc_t* dma_descriptor) {
|
||||
if(port < I2S_NUM_0 || port >= I2S_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
i2s_dev_t* dev = I2S[port];
|
||||
|
||||
|
||||
// Configure DMA burst mode
|
||||
dev->lc_conf.val = I2S_OUT_DATA_BURST_EN | I2S_OUTDSCR_BURST_EN;
|
||||
|
||||
// Set address of DMA descriptor
|
||||
dev->out_link.addr = (uint32_t) dma_descriptor;
|
||||
|
||||
// Start DMA operation
|
||||
dev->out_link.stop = 0;
|
||||
dev->out_link.start = 1;
|
||||
|
||||
dev->conf.tx_start = 1;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
/*
|
||||
i2s_dev_t* i2s_parallel_get_dev(i2s_port_t port) {
|
||||
if(port < I2S_NUM_0 || port >= I2S_NUM_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef ESP32_ORIG
|
||||
if (port == I2S_NUM_1)
|
||||
return &I2S1;
|
||||
#endif
|
||||
|
||||
return I2S0; // HARCODE THIS TO RETURN &I2S0
|
||||
}
|
||||
*/
|
||||
// Double buffering flipping
|
||||
// Flip to a buffer: 0 for bufa, 1 for bufb
|
||||
// dmadesc_a and dmadesc_b point to the same memory if double buffering isn't enabled.
|
||||
void i2s_parallel_flip_to_buffer(i2s_port_t port, int buffer_id) {
|
||||
|
||||
if (i2s_state == NULL) {
|
||||
return; // :-()
|
||||
}
|
||||
|
||||
lldesc_t *active_dma_chain;
|
||||
if (buffer_id == 0) {
|
||||
active_dma_chain=(lldesc_t*)&i2s_state->dmadesc_a[0];
|
||||
} else {
|
||||
active_dma_chain=(lldesc_t*)&i2s_state->dmadesc_b[0];
|
||||
}
|
||||
|
||||
// setup linked list to refresh from new buffer (continuously) when the end of the current list has been reached
|
||||
i2s_state->dmadesc_a[i2s_state->desccount_a-1].qe.stqe_next = active_dma_chain;
|
||||
i2s_state->dmadesc_b[i2s_state->desccount_b-1].qe.stqe_next = active_dma_chain;
|
||||
|
||||
// we're still shifting out the buffer, so it shouldn't be written to yet.
|
||||
//previousBufferFree = false;
|
||||
i2s_parallel_set_previous_buffer_not_free();
|
||||
}
|
||||
|
||||
bool i2s_parallel_is_previous_buffer_free() {
|
||||
return previousBufferFree;
|
||||
}
|
||||
|
||||
|
||||
void i2s_parallel_set_previous_buffer_not_free() {
|
||||
previousBufferFree = false;
|
||||
previousBufferOutputLoopCount = 0;
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
#pragma once
|
||||
/*
|
||||
* ESP32_I2S_PARALLEL_DMA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(ESP32) || defined(IDF_VER)
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <driver/i2s.h>
|
||||
#include <esp_err.h>
|
||||
//#include <esp32/rom/lldesc.h>
|
||||
//#include <esp32/rom/gpio.h>
|
||||
#include <rom/lldesc.h>
|
||||
#include <rom/gpio.h>
|
||||
|
||||
|
||||
// Get MCU Type and Max CLK Hz for MCU
|
||||
#include <esp32_i2s_parallel_mcu_def.h>
|
||||
|
||||
typedef enum {
|
||||
I2S_PARALLEL_WIDTH_8,
|
||||
I2S_PARALLEL_WIDTH_16,
|
||||
I2S_PARALLEL_WIDTH_24,
|
||||
I2S_PARALLEL_WIDTH_MAX
|
||||
} i2s_parallel_cfg_bits_t;
|
||||
|
||||
typedef struct {
|
||||
int gpio_bus[24]; // The parallel GPIOs to use, set gpio to -1 to disable
|
||||
int gpio_clk;
|
||||
int sample_rate; // 'clockspeed'
|
||||
int sample_width;
|
||||
int desccount_a;
|
||||
lldesc_t * lldesc_a;
|
||||
int desccount_b; // only used with double buffering
|
||||
lldesc_t * lldesc_b; // only used with double buffering
|
||||
bool clkphase; // Clock signal phase
|
||||
bool int_ena_out_eof; // Do we raise an interrupt every time the DMA output loops? Don't do this unless we're doing double buffering!
|
||||
} i2s_parallel_config_t;
|
||||
|
||||
static inline int i2s_parallel_get_memory_width(i2s_port_t port, i2s_parallel_cfg_bits_t width) {
|
||||
switch(width) {
|
||||
case I2S_PARALLEL_WIDTH_8:
|
||||
|
||||
#ifdef ESP32_ORIG
|
||||
// Only I2S1 on the legacy ESP32 WROOM MCU supports space saving single byte 8 bit parallel access
|
||||
if(port == I2S_NUM_1) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
case I2S_PARALLEL_WIDTH_16:
|
||||
return 2;
|
||||
case I2S_PARALLEL_WIDTH_24:
|
||||
return 4;
|
||||
default:
|
||||
return -ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
// DMA Linked List Creation
|
||||
void link_dma_desc(volatile lldesc_t *dmadesc, volatile lldesc_t *prevdmadesc, void *memory, size_t size);
|
||||
|
||||
// I2S DMA Peripheral Setup Functions
|
||||
esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* conf);
|
||||
esp_err_t i2s_parallel_send_dma(i2s_port_t port, lldesc_t* dma_descriptor);
|
||||
esp_err_t i2s_parallel_stop_dma(i2s_port_t port);
|
||||
//i2s_dev_t* i2s_parallel_get_dev(i2s_port_t port);
|
||||
|
||||
// For frame buffer flipping / double buffering
|
||||
typedef struct {
|
||||
volatile lldesc_t *dmadesc_a, *dmadesc_b;
|
||||
int desccount_a, desccount_b;
|
||||
i2s_port_t i2s_interrupt_port_arg;
|
||||
} i2s_parallel_state_t;
|
||||
|
||||
void i2s_parallel_flip_to_buffer(i2s_port_t port, int bufid);
|
||||
bool i2s_parallel_is_previous_buffer_free();
|
||||
void i2s_parallel_set_previous_buffer_not_free();
|
||||
|
||||
// Callback function for when whole length of DMA chain has been sent out.
|
||||
typedef void (*callback)(void);
|
||||
void setShiftCompleteCallback(callback f);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/* Abstract the Espressif IDF ESP32 MCU variant compile-time defines
|
||||
* into another list for the purposes of this library.
|
||||
*
|
||||
* i.e. I couldn't be bothered having to update the library when they
|
||||
* release the ESP32S4,5,6,7, n+1 etc. if they are all fundamentally
|
||||
* the same architecture.
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
|
||||
#define ESP32_SXXX 1
|
||||
#define ESP32_I2S_DEVICE I2S_NUM_0
|
||||
|
||||
#define I2S_PARALLEL_CLOCK_HZ 160000000L
|
||||
#define DMA_MAX (4096-4)
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32 || defined(ESP32)
|
||||
|
||||
// 2016 model that started it all, and this library. The best.
|
||||
#define ESP32_ORIG 1
|
||||
#define ESP32_I2S_DEVICE I2S_NUM_0
|
||||
|
||||
#define I2S_PARALLEL_CLOCK_HZ 80000000L
|
||||
#define DMA_MAX (4096-4)
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
|
||||
|
||||
#error "ESPC-series RISC-V MCU's do not support parallel DMA and not supported by this library!"
|
||||
#define ESP32_CXXX 1
|
||||
|
||||
#else
|
||||
#error "ERROR: No ESP32 or ESP32 Espressif IDF detected at compile time."
|
||||
|
||||
#endif
|
|
@ -100,9 +100,9 @@ void setup() {
|
|||
PANEL_CHAIN // Chain length
|
||||
);
|
||||
|
||||
mxconfig.gpio.e = 18;
|
||||
mxconfig.clkphase = false;
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
//mxconfig.gpio.e = 18;
|
||||
//mxconfig.clkphase = false;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
|
||||
// Display Setup
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
|
|
|
@ -138,7 +138,7 @@ void setup() {
|
|||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
|
||||
// let's adjust default brightness to about 75%
|
||||
dma_display->setBrightness8(192); // range is 0-255, 0 - 0%, 255 - 100%
|
||||
dma_display->setBrightness8(255); // range is 0-255, 0 - 0%, 255 - 100%
|
||||
|
||||
// Allocate memory and start DMA display
|
||||
if( not dma_display->begin() )
|
||||
|
@ -176,13 +176,13 @@ void loop() {
|
|||
|
||||
for (int x = 0; x < PANE_WIDTH; x++) {
|
||||
for (int y = 0; y < PANE_HEIGHT; y++) {
|
||||
int16_t v = 0;
|
||||
int16_t v = 128;
|
||||
uint8_t wibble = sin8(time_counter);
|
||||
v += sin16(x * wibble * 3 + time_counter);
|
||||
v += cos16(y * (128 - wibble) + time_counter);
|
||||
v += sin16(y * x * cos8(-time_counter) / 8);
|
||||
|
||||
currentColor = ColorFromPalette(currentPalette, (v >> 8) + 127); //, brightness, currentBlendType);
|
||||
currentColor = ColorFromPalette(currentPalette, (v >> 8)); //, brightness, currentBlendType);
|
||||
dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Example uses the following configuration: mxconfig.double_buff = true;
|
||||
// to enable double buffering, which means display->flipDMABuffer(); is required.
|
||||
|
||||
// Bounce squares around the screen, doing the re-drawing in the background back-buffer.
|
||||
// Double buffering is not always required in reality.
|
||||
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
|
||||
MatrixPanel_I2S_DMA *display = nullptr;
|
||||
|
@ -32,14 +38,14 @@ void setup()
|
|||
|
||||
Serial.println("...Starting Display");
|
||||
HUB75_I2S_CFG mxconfig;
|
||||
//mxconfig.double_buff = true; // Turn of double buffer
|
||||
mxconfig.clkphase = false;
|
||||
mxconfig.double_buff = true; // <------------- Turn on double buffer
|
||||
//mxconfig.clkphase = false;
|
||||
|
||||
// OK, now we can create our matrix object
|
||||
display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
display->begin(); // setup display with pins as pre-defined in the library
|
||||
|
||||
// Create some Squares
|
||||
// Create some random squares
|
||||
for (int i = 0; i < numSquares; i++)
|
||||
{
|
||||
Squares[i].square_size = random(2,10);
|
||||
|
@ -47,8 +53,6 @@ void setup()
|
|||
Squares[i].ypos = random(0, display->height() - Squares[i].square_size);
|
||||
Squares[i].velocityx = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
|
||||
Squares[i].velocityy = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
|
||||
//Squares[i].xdir = (random(2) == 1) ? true:false;
|
||||
//Squares[i].ydir = (random(2) == 1) ? true:false;
|
||||
|
||||
int random_num = random(6);
|
||||
Squares[i].colour = colours[random_num];
|
||||
|
@ -57,9 +61,11 @@ void setup()
|
|||
|
||||
void loop()
|
||||
{
|
||||
display->flipDMABuffer(); // not used if double buffering isn't enabled
|
||||
delay(25);
|
||||
display->clearScreen();
|
||||
|
||||
display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels)
|
||||
display->clearScreen(); // Now clear the back-buffer
|
||||
|
||||
delay(16); // <----------- Shouldn't see this clearscreen occur as it happens on the back buffer when double buffering is enabled.
|
||||
|
||||
for (int i = 0; i < numSquares; i++)
|
||||
{
|
|
@ -1,3 +0,0 @@
|
|||
## FM6126 based LED Matrix Panel Reset ##
|
||||
|
||||
FM6216 panels require a special reset sequence before they can be used, check your panel chipset if you have issues. Refer to this example.
|
|
@ -1,19 +1,30 @@
|
|||
// How to use this library with a FM6126 panel, thanks goes to:
|
||||
// https://github.com/hzeller/rpi-rgb-led-matrix/issues/746
|
||||
/**********************************************************************
|
||||
* The library by default supports simple 'shift register' based panels
|
||||
* with A,B,C,D,E lines to select a specific row, but there are plenty
|
||||
* of examples of new chips coming on the market that work different.
|
||||
*
|
||||
* Please search through the project's issues. For some of these chips
|
||||
* (you will need to look at the back of your panel to identify), this
|
||||
* library has workarounds. This can be configured through using one of:
|
||||
|
||||
// mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::ICN2038S;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6124;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::MBI5124;
|
||||
*/
|
||||
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
#include <FastLED.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// FM6126 support is still experimental
|
||||
|
||||
// Output resolution and panel chain length configuration
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another
|
||||
|
||||
|
||||
// placeholder for the matrix object
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
||||
|
@ -33,14 +44,6 @@ CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlend
|
|||
}
|
||||
|
||||
void setup(){
|
||||
|
||||
/*
|
||||
The configuration for MatrixPanel_I2S_DMA object is held in HUB75_I2S_CFG structure,
|
||||
All options has it's predefined default values. So we can create a new structure and redefine only the options we need
|
||||
|
||||
Please refer to the '2_PatternPlasma.ino' example for detailed example of how to use the MatrixPanel_I2S_DMA configuration
|
||||
if you need to change the pin mappings etc.
|
||||
*/
|
||||
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
|
@ -48,7 +51,12 @@ void setup(){
|
|||
PANEL_CHAIN // Chain length
|
||||
);
|
||||
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6126A; // in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object
|
||||
// in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::ICN2038S;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6124;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::MBI5124;
|
||||
|
||||
|
||||
// OK, now we can create our matrix object
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
|
@ -99,4 +107,8 @@ void loop(){
|
|||
fps_timer = millis();
|
||||
fps = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FM6126 panel , thanks goes to:
|
||||
// https://github.com/hzeller/rpi-rgb-led-matrix/issues/746
|
13
examples/4_OtherShiftDriverPanel/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
## Ohter driver based LED Matrix Panels ##
|
||||
|
||||
Limited support for other panels exists, but requires this to be passed as a configuration option when using the library.
|
||||
|
||||
These panels require a special reset sequence before they can be used, check your panel chipset if you have issues. Refer to the example.
|
||||
|
||||
|
||||
```
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
mxconfig.driver = HUB75_I2S_CFG::ICN2038S;
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6124;
|
||||
mxconfig.driver = HUB75_I2S_CFG::MBI5124;
|
||||
```
|
|
@ -1,13 +0,0 @@
|
|||
## Animated GIF Decoding Example
|
||||
|
||||
### Prerequisites
|
||||
1. The excellent 'AnimatedGIF' library by Larry Bank needs to be installed: https://github.com/bitbank2/AnimatedGIF
|
||||
|
||||
This is available via the Arduino Library manager, or can be placed in the 'libs' directory with PlatformIO.
|
||||
|
||||
2. The files in the 'data' folder are written to the ESP32's SPIFFS file system.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
https://github.com/bitbank2/AnimatedGIF
|
|
@ -18,26 +18,17 @@
|
|||
* 3. Have fun.
|
||||
*/
|
||||
|
||||
#define FILESYSTEM SPIFFS
|
||||
#include <SPIFFS.h>
|
||||
#include "FS.h"
|
||||
#include <LittleFS.h>
|
||||
#include <AnimatedGIF.h>
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
|
||||
// ----------------------------
|
||||
#define FILESYSTEM LittleFS
|
||||
#define FORMAT_LITTLEFS_IF_FAILED true
|
||||
|
||||
/*
|
||||
* Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class.
|
||||
* i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives.
|
||||
* By default the library assumes a single 64x32 pixel panel is connected.
|
||||
*
|
||||
* Refer to the example '2_PatternPlasma' on the new / correct way to setup this library
|
||||
* for different resolutions / panel chain lengths within the sketch 'setup()'.
|
||||
*
|
||||
*/
|
||||
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another horizontally only.
|
||||
|
||||
//MatrixPanel_I2S_DMA dma_display;
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
@ -48,7 +39,6 @@ uint16_t myRED = dma_display->color565(255, 0, 0);
|
|||
uint16_t myGREEN = dma_display->color565(0, 255, 0);
|
||||
uint16_t myBLUE = dma_display->color565(0, 0, 255);
|
||||
|
||||
|
||||
AnimatedGIF gif;
|
||||
File f;
|
||||
int x_offset, y_offset;
|
||||
|
@ -63,8 +53,8 @@ void GIFDraw(GIFDRAW *pDraw)
|
|||
int x, y, iWidth;
|
||||
|
||||
iWidth = pDraw->iWidth;
|
||||
if (iWidth > MATRIX_WIDTH)
|
||||
iWidth = MATRIX_WIDTH;
|
||||
if (iWidth > dma_display->width())
|
||||
iWidth = dma_display->width();
|
||||
|
||||
usPalette = pDraw->pPalette;
|
||||
y = pDraw->iY + pDraw->y; // current line
|
||||
|
@ -195,9 +185,9 @@ void ShowGIF(char *name)
|
|||
|
||||
if (gif.open(name, GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw))
|
||||
{
|
||||
x_offset = (MATRIX_WIDTH - gif.getCanvasWidth())/2;
|
||||
x_offset = (dma_display->width() - gif.getCanvasWidth())/2;
|
||||
if (x_offset < 0) x_offset = 0;
|
||||
y_offset = (MATRIX_HEIGHT - gif.getCanvasHeight())/2;
|
||||
y_offset = (dma_display->height() - gif.getCanvasHeight())/2;
|
||||
if (y_offset < 0) y_offset = 0;
|
||||
Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight());
|
||||
Serial.flush();
|
||||
|
@ -216,42 +206,31 @@ void ShowGIF(char *name)
|
|||
|
||||
/************************* Arduino Sketch Setup and Loop() *******************************/
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
//
|
||||
if(!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED)){
|
||||
Serial.println("LittleFS Mount Failed");
|
||||
return;
|
||||
}
|
||||
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN // Chain length
|
||||
PANEL_CHAIN // Chain of panels - Horizontal width only.
|
||||
);
|
||||
|
||||
mxconfig.gpio.e = 18;
|
||||
mxconfig.clkphase = false;
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
// mxconfig.gpio.e = 18;
|
||||
// mxconfig.clkphase = false;
|
||||
// mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
|
||||
// Display Setup
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
dma_display->begin();
|
||||
dma_display->setBrightness8(90); //0-255
|
||||
dma_display->setBrightness8(128); //0-255
|
||||
dma_display->clearScreen();
|
||||
dma_display->fillScreen(myWHITE);
|
||||
|
||||
//
|
||||
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println("Starting AnimatedGIFs Sketch");
|
||||
|
||||
// Start filesystem
|
||||
Serial.println(" * Loading SPIFFS");
|
||||
if(!SPIFFS.begin()){
|
||||
Serial.println("SPIFFS Mount Failed");
|
||||
}
|
||||
|
||||
dma_display->begin();
|
||||
|
||||
/* all other pixel drawing functions can only be called after .begin() */
|
||||
dma_display->fillScreen(dma_display->color565(0, 0, 0));
|
||||
// Start going through GIFS
|
||||
gif.begin(LITTLE_ENDIAN_PIXELS);
|
||||
|
||||
}
|
||||
|
@ -291,4 +270,7 @@ void loop()
|
|||
delay(1000); // pause before restarting
|
||||
|
||||
} // while
|
||||
}
|
||||
}
|
||||
|
||||
// Other LittleFS filesystem function examples available at:
|
||||
// https://randomnerdtutorials.com/esp32-write-data-littlefs-arduino/
|
13
examples/AnimatedGIFPanel_LittleFS/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
## Animated GIF Decoding Example
|
||||
|
||||
### Prerequisites
|
||||
1. The excellent 'AnimatedGIF' library by Larry Bank needs to be installed: https://github.com/bitbank2/AnimatedGIF
|
||||
|
||||
2. The files in the 'data' folder are written to the ESP32's SPIFFS file system. In order to be able to do this using the Arduino 2.0 IDE, you need to install the ESP32 LittleFS plugin: https://github.com/lorol/arduino-esp32littlefs-plugin
|
||||
|
||||
Follow the instructions in the link to install the plugin: https://randomnerdtutorials.com/arduino-ide-2-install-esp32-littlefs/
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
https://github.com/bitbank2/AnimatedGIF
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 171 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
268
examples/AnimatedGIFPanel_SD/AnimatedGIFPanel_SD.ino
Normal file
|
@ -0,0 +1,268 @@
|
|||
/*********************************************************************
|
||||
* AnimatedGif LED Matrix Panel example where the GIFs are
|
||||
* stored on a SD card connected to the ESP32 using the
|
||||
* standard GPIO pins used for SD card acces via. SPI.
|
||||
*
|
||||
* Put the gifs into a directory called 'gifs' (case sensitive) on
|
||||
* a FAT32 formatted SDcard.
|
||||
********************************************************************/
|
||||
#include "FS.h"
|
||||
#include "SD.h"
|
||||
#include "SPI.h"
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
#include <AnimatedGIF.h>
|
||||
|
||||
/********************************************************************
|
||||
* Pin mapping below is for LOLIN D32 (ESP 32)
|
||||
*
|
||||
* Default pin mapping used by this library is NOT compatable with the use of the
|
||||
* ESP32-Arduino 'SD' card library (there is overlap). As such, some of the pins
|
||||
* used for the HUB75 panel need to be shifted.
|
||||
*
|
||||
* 'SD' card library requires GPIO 23, 18 and 19
|
||||
* https://github.com/espressif/arduino-esp32/tree/master/libraries/SD
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Connect the SD card to the following pins:
|
||||
*
|
||||
* SD Card | ESP32
|
||||
* D2 -
|
||||
* D3 SS
|
||||
* CMD MOSI
|
||||
* VSS GND
|
||||
* VDD 3.3V
|
||||
* CLK SCK
|
||||
* VSS GND
|
||||
* D0 MISO
|
||||
* D1 -
|
||||
*/
|
||||
|
||||
/**** SD Card GPIO mappings ****/
|
||||
#define SS_PIN 5
|
||||
//#define MOSI_PIN 23
|
||||
//#define MISO_PIN 19
|
||||
//#define CLK_PIN 18
|
||||
|
||||
|
||||
/**** HUB75 GPIO mapping ****/
|
||||
// GPIO 34+ are on the ESP32 are input only!!
|
||||
// https://randomnerdtutorials.com/esp32-pinout-reference-gpios/
|
||||
|
||||
#define A_PIN 33 // remap esp32 library default from 23 to 33
|
||||
#define B_PIN 32 // remap esp32 library default from 19 to 32
|
||||
#define C_PIN 22 // remap esp32 library defaultfrom 5 to 22
|
||||
|
||||
//#define R1_PIN 25 // library default for the esp32, unchanged
|
||||
//#define G1_PIN 26 // library default for the esp32, unchanged
|
||||
//#define B1_PIN 27 // library default for the esp32, unchanged
|
||||
//#define R2_PIN 14 // library default for the esp32, unchanged
|
||||
//#define G2_PIN 12 // library default for the esp32, unchanged
|
||||
//#define B2_PIN 13 // library default for the esp32, unchanged
|
||||
//#define D_PIN 17 // library default for the esp32, unchanged
|
||||
//#define E_PIN -1 // IMPORTANT: Change to a valid pin if using a 64x64px panel.
|
||||
|
||||
//#define LAT_PIN 4 // library default for the esp32, unchanged
|
||||
//#define OE_PIN 15 // library default for the esp32, unchanged
|
||||
//#define CLK_PIN 16 // library default for the esp32, unchanged
|
||||
|
||||
/***************************************************************
|
||||
* HUB 75 LED DMA Matrix Panel Configuration
|
||||
**************************************************************/
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
AnimatedGIF gif;
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
||||
static int totalFiles = 0; // GIF files count
|
||||
|
||||
static File FSGifFile; // temp gif file holder
|
||||
static File GifRootFolder; // directory listing
|
||||
|
||||
std::vector<std::string> GifFiles; // GIF files path
|
||||
|
||||
const int maxGifDuration = 30000; // ms, max GIF duration
|
||||
|
||||
#include "gif_functions.hpp"
|
||||
#include "sdcard_functions.hpp"
|
||||
|
||||
|
||||
/**************************************************************/
|
||||
void draw_test_patterns();
|
||||
int gifPlay( const char* gifPath )
|
||||
{ // 0=infinite
|
||||
|
||||
if( ! gif.open( gifPath, GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw ) ) {
|
||||
log_n("Could not open gif %s", gifPath );
|
||||
}
|
||||
|
||||
Serial.print("Playing: "); Serial.println(gifPath);
|
||||
|
||||
int frameDelay = 0; // store delay for the last frame
|
||||
int then = 0; // store overall delay
|
||||
|
||||
while (gif.playFrame(true, &frameDelay)) {
|
||||
|
||||
then += frameDelay;
|
||||
if( then > maxGifDuration ) { // avoid being trapped in infinite GIF's
|
||||
//log_w("Broke the GIF loop, max duration exceeded");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gif.close();
|
||||
|
||||
return then;
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
// **************************** Setup SD Card access via SPI ****************************
|
||||
if(!SD.begin(SS_PIN)){
|
||||
// bool begin(uint8_t ssPin=SS, SPIClass &spi=SPI, uint32_t frequency=4000000, const char * mountpoint="/sd", uint8_t max_files=5, bool format_if_empty=false);
|
||||
Serial.println("Card Mount Failed");
|
||||
return;
|
||||
}
|
||||
uint8_t cardType = SD.cardType();
|
||||
|
||||
if(cardType == CARD_NONE){
|
||||
Serial.println("No SD card attached");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print("SD Card Type: ");
|
||||
if(cardType == CARD_MMC){
|
||||
Serial.println("MMC");
|
||||
} else if(cardType == CARD_SD){
|
||||
Serial.println("SDSC");
|
||||
} else if(cardType == CARD_SDHC){
|
||||
Serial.println("SDHC");
|
||||
} else {
|
||||
Serial.println("UNKNOWN");
|
||||
}
|
||||
|
||||
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
|
||||
Serial.printf("SD Card Size: %lluMB\n", cardSize);
|
||||
|
||||
//listDir(SD, "/", 1, false);
|
||||
|
||||
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
|
||||
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
|
||||
|
||||
|
||||
|
||||
// **************************** Setup DMA Matrix ****************************
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN // Chain length
|
||||
);
|
||||
|
||||
// Need to remap these HUB75 DMA pins because the SPI SDCard is using them.
|
||||
// Otherwise the SD Card will not work.
|
||||
mxconfig.gpio.a = A_PIN;
|
||||
mxconfig.gpio.b = B_PIN;
|
||||
mxconfig.gpio.c = C_PIN;
|
||||
// mxconfig.gpio.d = D_PIN;
|
||||
|
||||
//mxconfig.clkphase = false;
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
|
||||
// Display Setup
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
|
||||
// Allocate memory and start DMA display
|
||||
if( not dma_display->begin() )
|
||||
Serial.println("****** !KABOOM! HUB75 memory allocation failed ***********");
|
||||
|
||||
dma_display->setBrightness8(128); //0-255
|
||||
dma_display->clearScreen();
|
||||
|
||||
|
||||
// **************************** Setup Sketch ****************************
|
||||
Serial.println("Starting AnimatedGIFs Sketch");
|
||||
|
||||
// SD CARD STOPS WORKING WITH DMA DISPLAY ENABLED>...
|
||||
|
||||
File root = SD.open("/gifs");
|
||||
if(!root){
|
||||
Serial.println("Failed to open directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while(file){
|
||||
if(!file.isDirectory())
|
||||
{
|
||||
Serial.print(" FILE: ");
|
||||
Serial.print(file.name());
|
||||
Serial.print(" SIZE: ");
|
||||
Serial.println(file.size());
|
||||
|
||||
std::string filename = "/gifs/" + std::string(file.name());
|
||||
Serial.println(filename.c_str());
|
||||
|
||||
GifFiles.push_back( filename );
|
||||
// Serial.println("Adding to gif list:" + String(filename));
|
||||
totalFiles++;
|
||||
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
|
||||
file.close();
|
||||
Serial.printf("Found %d GIFs to play.", totalFiles);
|
||||
//totalFiles = getGifInventory("/gifs");
|
||||
|
||||
|
||||
|
||||
// This is important - Set the right endianness.
|
||||
gif.begin(LITTLE_ENDIAN_PIXELS);
|
||||
|
||||
}
|
||||
|
||||
void loop(){
|
||||
|
||||
// Iterate over a vector using range based for loop
|
||||
for(auto & elem : GifFiles)
|
||||
{
|
||||
gifPlay( elem.c_str() );
|
||||
gif.reset();
|
||||
delay(500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void draw_test_patterns()
|
||||
{
|
||||
// fix the screen with green
|
||||
dma_display->fillRect(0, 0, dma_display->width(), dma_display->height(), dma_display->color444(0, 15, 0));
|
||||
delay(500);
|
||||
|
||||
// draw a box in yellow
|
||||
dma_display->drawRect(0, 0, dma_display->width(), dma_display->height(), dma_display->color444(15, 15, 0));
|
||||
delay(500);
|
||||
|
||||
// draw an 'X' in red
|
||||
dma_display->drawLine(0, 0, dma_display->width()-1, dma_display->height()-1, dma_display->color444(15, 0, 0));
|
||||
dma_display->drawLine(dma_display->width()-1, 0, 0, dma_display->height()-1, dma_display->color444(15, 0, 0));
|
||||
delay(500);
|
||||
|
||||
// draw a blue circle
|
||||
dma_display->drawCircle(10, 10, 10, dma_display->color444(0, 0, 15));
|
||||
delay(500);
|
||||
|
||||
// fill a violet circle
|
||||
dma_display->fillCircle(40, 21, 10, dma_display->color444(15, 0, 15));
|
||||
delay(500);
|
||||
delay(1000);
|
||||
|
||||
}
|
15
examples/AnimatedGIFPanel_SD/Readme.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# ESP32-HUB75-MatrixPanel-DMA SDCard example
|
||||
|
||||
A very basic example using the 'Animated GIF' library by Larry Bank + the SD / File system library provided for Arduino by Espressif.
|
||||
|
||||
Some default HUB75 pins need to be remapped to accomodate for the SD Card.
|
||||
|
||||
![image](esp32_sdcard.jpg)
|
||||
|
||||
## How to use it?
|
||||
|
||||
1. Format a SD Card with FAT32 file system (default setting)
|
||||
2. Create a directory called 'gifs'
|
||||
3. Drop your gifs in there. The resolution of the GIFS must match that of the display.
|
||||
|
||||
|
BIN
examples/AnimatedGIFPanel_SD/esp32_sdcard.jpg
Normal file
After Width: | Height: | Size: 150 KiB |
132
examples/AnimatedGIFPanel_SD/gif_functions.hpp
Normal file
|
@ -0,0 +1,132 @@
|
|||
|
||||
// Code copied from AnimatedGIF examples
|
||||
|
||||
#ifndef M5STACK_SD
|
||||
// for custom ESP32 builds
|
||||
#define M5STACK_SD SD
|
||||
#endif
|
||||
|
||||
|
||||
static void * GIFOpenFile(const char *fname, int32_t *pSize)
|
||||
{
|
||||
//log_d("GIFOpenFile( %s )\n", fname );
|
||||
FSGifFile = M5STACK_SD.open(fname);
|
||||
if (FSGifFile) {
|
||||
*pSize = FSGifFile.size();
|
||||
return (void *)&FSGifFile;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void GIFCloseFile(void *pHandle)
|
||||
{
|
||||
File *f = static_cast<File *>(pHandle);
|
||||
if (f != NULL)
|
||||
f->close();
|
||||
}
|
||||
|
||||
|
||||
static int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen)
|
||||
{
|
||||
int32_t iBytesRead;
|
||||
iBytesRead = iLen;
|
||||
File *f = static_cast<File *>(pFile->fHandle);
|
||||
// Note: If you read a file all the way to the last byte, seek() stops working
|
||||
if ((pFile->iSize - pFile->iPos) < iLen)
|
||||
iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around
|
||||
if (iBytesRead <= 0)
|
||||
return 0;
|
||||
iBytesRead = (int32_t)f->read(pBuf, iBytesRead);
|
||||
pFile->iPos = f->position();
|
||||
return iBytesRead;
|
||||
}
|
||||
|
||||
|
||||
static int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition)
|
||||
{
|
||||
int i = micros();
|
||||
File *f = static_cast<File *>(pFile->fHandle);
|
||||
f->seek(iPosition);
|
||||
pFile->iPos = (int32_t)f->position();
|
||||
i = micros() - i;
|
||||
//log_d("Seek time = %d us\n", i);
|
||||
return pFile->iPos;
|
||||
}
|
||||
|
||||
|
||||
// Draw a line of image directly on the LCD
|
||||
void GIFDraw(GIFDRAW *pDraw)
|
||||
{
|
||||
uint8_t *s;
|
||||
uint16_t *d, *usPalette, usTemp[320];
|
||||
int x, y, iWidth;
|
||||
|
||||
iWidth = pDraw->iWidth;
|
||||
if (iWidth > PANEL_RES_X)
|
||||
iWidth = PANEL_RES_X;
|
||||
usPalette = pDraw->pPalette;
|
||||
y = pDraw->iY + pDraw->y; // current line
|
||||
|
||||
s = pDraw->pPixels;
|
||||
if (pDraw->ucDisposalMethod == 2) {// restore to background color
|
||||
for (x=0; x<iWidth; x++) {
|
||||
if (s[x] == pDraw->ucTransparent)
|
||||
s[x] = pDraw->ucBackground;
|
||||
}
|
||||
pDraw->ucHasTransparency = 0;
|
||||
}
|
||||
// Apply the new pixels to the main image
|
||||
if (pDraw->ucHasTransparency) { // if transparency used
|
||||
uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
|
||||
int x, iCount;
|
||||
pEnd = s + iWidth;
|
||||
x = 0;
|
||||
iCount = 0; // count non-transparent pixels
|
||||
while(x < iWidth) {
|
||||
c = ucTransparent-1;
|
||||
d = usTemp;
|
||||
while (c != ucTransparent && s < pEnd) {
|
||||
c = *s++;
|
||||
if (c == ucTransparent) { // done, stop
|
||||
s--; // back up to treat it like transparent
|
||||
} else { // opaque
|
||||
*d++ = usPalette[c];
|
||||
iCount++;
|
||||
}
|
||||
} // while looking for opaque pixels
|
||||
if (iCount) { // any opaque pixels?
|
||||
for(int xOffset = 0; xOffset < iCount; xOffset++ ){
|
||||
dma_display->drawPixel(x + xOffset, y, usTemp[xOffset]); // 565 Color Format
|
||||
}
|
||||
x += iCount;
|
||||
iCount = 0;
|
||||
}
|
||||
// no, look for a run of transparent pixels
|
||||
c = ucTransparent;
|
||||
while (c == ucTransparent && s < pEnd) {
|
||||
c = *s++;
|
||||
if (c == ucTransparent)
|
||||
iCount++;
|
||||
else
|
||||
s--;
|
||||
}
|
||||
if (iCount) {
|
||||
x += iCount; // skip these
|
||||
iCount = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s = pDraw->pPixels;
|
||||
// Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
|
||||
for (x=0; x<iWidth; x++)
|
||||
dma_display->drawPixel(x, y, usPalette[*s++]); // color 565
|
||||
/*
|
||||
usTemp[x] = usPalette[*s++];
|
||||
|
||||
for (x=0; x<pDraw->iWidth; x++) {
|
||||
dma_display->drawPixel(x, y, usTemp[*s++]); // color 565
|
||||
} */
|
||||
|
||||
}
|
||||
} /* GIFDraw() */
|
BIN
examples/AnimatedGIFPanel_SD/gifs/cartoon.gif
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
examples/AnimatedGIFPanel_SD/gifs/ezgif.com-pacmn.gif
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
examples/AnimatedGIFPanel_SD/gifs/loading.io-64x32px.gif
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
examples/AnimatedGIFPanel_SD/gifs/matrix-spin.gif
Normal file
After Width: | Height: | Size: 171 KiB |
BIN
examples/AnimatedGIFPanel_SD/gifs/parasite1.gif
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
examples/AnimatedGIFPanel_SD/gifs/parasite2.gif
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
examples/AnimatedGIFPanel_SD/gifs/shock-gs.gif
Normal file
After Width: | Height: | Size: 34 KiB |
102
examples/AnimatedGIFPanel_SD/sdcard_functions.hpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
/************************ SD Card Code ************************/
|
||||
// As per: https://github.com/espressif/arduino-esp32/tree/master/libraries/SD/examples/SD_Test
|
||||
|
||||
|
||||
|
||||
void listDir(fs::FS &fs, const char * dirname, uint8_t levels, bool add_to_gif_list = false){
|
||||
Serial.printf("Listing directory: %s\n", dirname);
|
||||
|
||||
File root = fs.open(dirname);
|
||||
if(!root){
|
||||
Serial.println("Failed to open directory");
|
||||
return;
|
||||
}
|
||||
if(!root.isDirectory()){
|
||||
Serial.println("Not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while(file){
|
||||
if(file.isDirectory()){
|
||||
Serial.print(" DIR : ");
|
||||
Serial.println(file.name());
|
||||
if(levels){
|
||||
listDir(fs, file.path(), levels -1, false);
|
||||
}
|
||||
} else {
|
||||
Serial.print(" FILE: ");
|
||||
Serial.print(file.name());
|
||||
Serial.print(" SIZE: ");
|
||||
Serial.println(file.size());
|
||||
|
||||
if (add_to_gif_list && levels == 0)
|
||||
{
|
||||
GifFiles.push_back( std::string(dirname) + file.name() );
|
||||
Serial.println("Adding to gif list:" + String(dirname) +"/" + file.name());
|
||||
totalFiles++;
|
||||
}
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void readFile(fs::FS &fs, const char * path){
|
||||
Serial.printf("Reading file: %s\n", path);
|
||||
|
||||
File file = fs.open(path);
|
||||
if(!file){
|
||||
Serial.println("Failed to open file for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print("Read from file: ");
|
||||
while(file.available()){
|
||||
Serial.write(file.read());
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void testFileIO(fs::FS &fs, const char * path){
|
||||
File file = fs.open(path);
|
||||
static uint8_t buf[512];
|
||||
size_t len = 0;
|
||||
uint32_t start = millis();
|
||||
uint32_t end = start;
|
||||
if(file){
|
||||
len = file.size();
|
||||
size_t flen = len;
|
||||
start = millis();
|
||||
while(len){
|
||||
size_t toRead = len;
|
||||
if(toRead > 512){
|
||||
toRead = 512;
|
||||
}
|
||||
file.read(buf, toRead);
|
||||
len -= toRead;
|
||||
}
|
||||
end = millis() - start;
|
||||
Serial.printf("%u bytes read for %u ms\n", flen, end);
|
||||
file.close();
|
||||
} else {
|
||||
Serial.println("Failed to open file for reading");
|
||||
}
|
||||
|
||||
|
||||
file = fs.open(path, FILE_WRITE);
|
||||
if(!file){
|
||||
Serial.println("Failed to open file for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
start = millis();
|
||||
for(i=0; i<2048; i++){
|
||||
file.write(buf, 512);
|
||||
}
|
||||
end = millis() - start;
|
||||
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
|
||||
file.close();
|
||||
}
|
|
@ -24,7 +24,7 @@
|
|||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Vector.h"
|
||||
#include "Vector2.hpp"
|
||||
|
||||
class Attractor {
|
||||
public:
|
||||
|
@ -33,7 +33,7 @@ public:
|
|||
PVector location; // Location
|
||||
|
||||
Attractor() {
|
||||
location = PVector(MATRIX_CENTRE_X, MATRIX_CENTRE_Y);
|
||||
location = PVector(effects.getCenterX(), effects.getCenterY());
|
||||
mass = 10;
|
||||
G = .5;
|
||||
}
|
|
@ -1,150 +1,204 @@
|
|||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
|
||||
/*--------------------- MATRIX GPIO CONFIG -------------------------*/
|
||||
#define R1_PIN 25
|
||||
#define G1_PIN 26
|
||||
#define B1_PIN 27
|
||||
#define R2_PIN 14
|
||||
#define G2_PIN 12
|
||||
#define B2_PIN 13
|
||||
#define A_PIN 23
|
||||
#define B_PIN 19 // Changed from library default
|
||||
#define C_PIN 5
|
||||
#define D_PIN 17
|
||||
#define E_PIN -1
|
||||
#define LAT_PIN 4
|
||||
#define OE_PIN 15
|
||||
#define CLK_PIN 16
|
||||
|
||||
|
||||
/*--------------------- MATRIX PANEL CONFIG -------------------------*/
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
#define PANEL_CHAIN 1 // Total number of panels chained one to another
|
||||
|
||||
/*
|
||||
//Another way of creating config structure
|
||||
//Custom pin mapping for all pins
|
||||
HUB75_I2S_CFG::i2s_pins _pins={R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK};
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
64, // width
|
||||
64, // height
|
||||
4, // chain length
|
||||
_pins, // pin mapping
|
||||
HUB75_I2S_CFG::FM6126A // driver chip
|
||||
);
|
||||
_ _ _ ____ ___ ____ _
|
||||
/ \ | | | | _ \ / _ \| _ \ / \
|
||||
/ _ \ | | | | |_) | | | | |_) | / _ \
|
||||
/ ___ \| |_| | _ <| |_| | _ < / ___ \
|
||||
/_/ \_\\___/|_| \_\\___/|_| \_\/_/ \_\
|
||||
|
||||
____ _____ __ __ ___
|
||||
| _ \| ____| \/ |/ _ \
|
||||
| | | | _| | |\/| | | | |
|
||||
| |_| | |___| | | | |_| |
|
||||
|____/|_____|_| |_|\___/
|
||||
|
||||
Description:
|
||||
* This demonstrates a combination of the following libraries two:
|
||||
- "ESP32-HUB75-MatrixPanel-DMA" to send pixel data to the physical panels in combination with its
|
||||
in-built "VirtualMatrix" class which used to create a virtual display of chained panels, so the
|
||||
graphical effects of the Aurora demonstration can be shown on a 'bigger' grid of physical panels
|
||||
acting as one big display.
|
||||
|
||||
- "GFX_Lite" to provide a simple graphics library for drawing on the virtual display.
|
||||
GFX_Lite is a fork of AdaFruitGFX and FastLED library combined together, with a focus on simplicity and ease of use.
|
||||
|
||||
Instructions:
|
||||
* Use the serial input to advance through the patterns, or to toggle auto advance. Sending 'n' will advance to the next
|
||||
pattern, 'p' will go to the previous pattern. Sending 'a' will toggle auto advance on and off.
|
||||
|
||||
*/
|
||||
MatrixPanel_I2S_DMA *dma_display = nullptr;
|
||||
|
||||
// Module configuration
|
||||
HUB75_I2S_CFG mxconfig(
|
||||
PANEL_RES_X, // module width
|
||||
PANEL_RES_Y, // module height
|
||||
PANEL_CHAIN // Chain length
|
||||
);
|
||||
#define USE_GFX_LITE 1
|
||||
#include <ESP32-VirtualMatrixPanel-I2S-DMA.h>
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
// Step 1) Provide the size of each individual physical panel LED Matrix panel that is chained (or not) together
|
||||
#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
|
||||
#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
|
||||
|
||||
// Step 2) Provide details of the physical panel chaining that is in place.
|
||||
#define NUM_ROWS 2 // Number of rows of chained INDIVIDUAL PANELS
|
||||
#define NUM_COLS 1 // Number of INDIVIDUAL PANELS per ROW
|
||||
#define PANEL_CHAIN NUM_ROWS*NUM_COLS // total number of panels chained one to another
|
||||
|
||||
// Step 3) How are the panels chained together?
|
||||
#define PANEL_CHAIN_TYPE CHAIN_TOP_RIGHT_DOWN
|
||||
|
||||
// Refer to: https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/tree/master/examples/VirtualMatrixPanel
|
||||
// and: https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/blob/master/doc/VirtualMatrixPanel.pdf
|
||||
|
||||
// Virtual Panel dimensions - our combined panel would be a square 4x4 modules with a combined resolution of 128x128 pixels
|
||||
#define VPANEL_W PANEL_RES_X*NUM_COLS // Kosso: All Pattern files have had the MATRIX_WIDTH and MATRIX_HEIGHT replaced by these.
|
||||
#define VPANEL_H PANEL_RES_Y*NUM_ROWS //
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
// The palettes are set to change every 60 seconds.
|
||||
int lastPattern = 0;
|
||||
|
||||
|
||||
//mxconfig.gpio.e = -1; // Assign a pin if you have a 64x64 panel
|
||||
//mxconfig.clkphase = false; // Change this if you have issues with ghosting.
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6126A; // Change this according to your pane.
|
||||
// placeholder for the matrix object
|
||||
MatrixPanel_I2S_DMA *matrix = nullptr;
|
||||
|
||||
// placeholder for the virtual display object
|
||||
VirtualMatrixPanel *virtualDisp = nullptr;
|
||||
|
||||
|
||||
#include "EffectsLayer.hpp" // FastLED CRGB Pixel Buffer for which the patterns are drawn
|
||||
EffectsLayer effects(VPANEL_W, VPANEL_H);
|
||||
|
||||
#include <FastLED.h>
|
||||
#include "Drawable.hpp"
|
||||
#include "Geometry.hpp"
|
||||
|
||||
#include "Effects.h"
|
||||
Effects effects;
|
||||
|
||||
#include "Drawable.h"
|
||||
#include "Playlist.h"
|
||||
//#include "Geometry.h"
|
||||
|
||||
#include "Patterns.h"
|
||||
#include "Patterns.hpp"
|
||||
Patterns patterns;
|
||||
|
||||
/* -------------------------- Some variables -------------------------- */
|
||||
unsigned long fps = 0, fps_timer; // fps (this is NOT a matrix refresh rate!)
|
||||
unsigned int default_fps = 30, pattern_fps = 30; // default fps limit (this is not a matrix refresh counter!)
|
||||
unsigned long ms_animation_max_duration = 20000; // 20 seconds
|
||||
unsigned long last_frame=0, ms_previous=0;
|
||||
unsigned long ms_current = 0;
|
||||
unsigned long ms_previous = 0;
|
||||
unsigned long ms_previous_palette = 0;
|
||||
unsigned long ms_animation_max_duration = 30000; // 10 seconds
|
||||
unsigned long next_frame = 0;
|
||||
|
||||
void listPatterns();
|
||||
|
||||
void setup()
|
||||
{
|
||||
/************** SERIAL **************/
|
||||
// Setup serial interface
|
||||
Serial.begin(115200);
|
||||
delay(250);
|
||||
|
||||
/************** DISPLAY **************/
|
||||
Serial.println("...Starting Display");
|
||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
dma_display->begin();
|
||||
dma_display->setBrightness8(90); //0-255
|
||||
|
||||
dma_display->fillScreenRGB888(128,0,0);
|
||||
delay(1000);
|
||||
dma_display->fillScreenRGB888(0,0,128);
|
||||
delay(1000);
|
||||
dma_display->clearScreen();
|
||||
delay(1000);
|
||||
|
||||
// Configure your matrix setup here
|
||||
HUB75_I2S_CFG mxconfig(PANEL_RES_X, PANEL_RES_Y, PANEL_CHAIN);
|
||||
|
||||
// custom pin mapping (if required)
|
||||
//HUB75_I2S_CFG::i2s_pins _pins={R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK};
|
||||
//mxconfig.gpio = _pins;
|
||||
|
||||
// in case that we use panels based on FM6126A chip, we can change that
|
||||
//mxconfig.driver = HUB75_I2S_CFG::FM6126A;
|
||||
|
||||
// FM6126A panels could be cloked at 20MHz with no visual artefacts
|
||||
// mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_20M;
|
||||
|
||||
// OK, now we can create our matrix object
|
||||
matrix = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
|
||||
// Allocate memory and start DMA display
|
||||
if( not matrix->begin() )
|
||||
Serial.println("****** !KABOOM! I2S memory allocation failed ***********");
|
||||
|
||||
// let's adjust default brightness to about 75%
|
||||
matrix->setBrightness8(192); // range is 0-255, 0 - 0%, 255 - 100%
|
||||
|
||||
// create VirtualDisplay object based on our newly created dma_display object
|
||||
virtualDisp = new VirtualMatrixPanel((*matrix), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, PANEL_CHAIN_TYPE);
|
||||
|
||||
Serial.println("**************** Starting Aurora Effects Demo ****************");
|
||||
|
||||
Serial.print("MATRIX_WIDTH: "); Serial.println(PANEL_RES_X*PANEL_CHAIN);
|
||||
Serial.print("MATRIX_HEIGHT: "); Serial.println(PANEL_RES_Y);
|
||||
|
||||
#ifdef VPANEL_W
|
||||
Serial.println("VIRTUAL PANEL WIDTH " + String(VPANEL_W));
|
||||
Serial.println("VIRTUAL PANEL HEIGHT " + String(VPANEL_H));
|
||||
#endif
|
||||
|
||||
// setup the effects generator
|
||||
effects.Setup();
|
||||
|
||||
delay(500);
|
||||
Serial.println("Effects being loaded: ");
|
||||
listPatterns();
|
||||
|
||||
|
||||
patterns.moveRandom(1); // start from a random pattern
|
||||
patterns.setPattern(0);
|
||||
patterns.start();
|
||||
|
||||
ms_previous = millis();
|
||||
|
||||
Serial.print("Starting with pattern: ");
|
||||
Serial.println(patterns.getCurrentPatternName());
|
||||
patterns.start();
|
||||
ms_previous = millis();
|
||||
fps_timer = millis();
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool autoAdvance = true;
|
||||
char incomingByte = 0;
|
||||
void handleSerialRead()
|
||||
{
|
||||
if (Serial.available() > 0) {
|
||||
|
||||
// read the incoming byte:
|
||||
incomingByte = Serial.read();
|
||||
|
||||
if (incomingByte == 'n') {
|
||||
Serial.println("Going to next pattern");
|
||||
patterns.move(1);
|
||||
}
|
||||
|
||||
if (incomingByte == 'p') {
|
||||
Serial.println("Going to previous pattern");
|
||||
patterns.move(-1);
|
||||
}
|
||||
|
||||
if (incomingByte == 'a') {
|
||||
autoAdvance = !autoAdvance;
|
||||
|
||||
if (autoAdvance)
|
||||
Serial.println("Auto pattern advance is ON");
|
||||
else
|
||||
Serial.println("Auto pattern advance is OFF");
|
||||
}
|
||||
|
||||
ms_previous = millis();
|
||||
}
|
||||
} // end handleSerialRead
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// menu.run(mainMenuItems, mainMenuItemCount);
|
||||
|
||||
if ( (millis() - ms_previous) > ms_animation_max_duration )
|
||||
{
|
||||
patterns.stop();
|
||||
patterns.moveRandom(1);
|
||||
//patterns.move(1);
|
||||
patterns.start();
|
||||
|
||||
Serial.print("Changing pattern to: ");
|
||||
Serial.println(patterns.getCurrentPatternName());
|
||||
|
||||
ms_previous = millis();
|
||||
handleSerialRead();
|
||||
|
||||
// Select a random palette as well
|
||||
//effects.RandomPalette();
|
||||
ms_current = millis();
|
||||
|
||||
if (ms_current - ms_previous_palette > 10000) // change colour palette evert 10 seconds
|
||||
{
|
||||
effects.RandomPalette();
|
||||
ms_previous_palette = ms_current;
|
||||
}
|
||||
|
||||
if ( ((ms_current - ms_previous) > ms_animation_max_duration) && autoAdvance)
|
||||
{
|
||||
|
||||
patterns.move(1);
|
||||
|
||||
ms_previous = ms_current;
|
||||
}
|
||||
|
||||
if ( 1000 / pattern_fps + last_frame < millis()){
|
||||
last_frame = millis();
|
||||
pattern_fps = patterns.drawFrame();
|
||||
if (!pattern_fps)
|
||||
pattern_fps = default_fps;
|
||||
|
||||
++fps;
|
||||
}
|
||||
|
||||
if (fps_timer + 1000 < millis()){
|
||||
Serial.printf_P(PSTR("Effect fps: %ld\n"), fps);
|
||||
fps_timer = millis();
|
||||
fps = 0;
|
||||
}
|
||||
if ( next_frame < ms_current)
|
||||
next_frame = patterns.drawFrame() + ms_current;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void listPatterns() {
|
||||
patterns.listPatterns();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,326 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Flocking" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/
|
||||
* Copyright (c) 2014 Daniel Shiffman
|
||||
* http://www.shiffman.net
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Flocking
|
||||
// Daniel Shiffman <http://www.shiffman.net>
|
||||
// The Nature of Code, Spring 2009
|
||||
|
||||
// Boid class
|
||||
// Methods for Separation, Cohesion, Alignment added
|
||||
|
||||
class Boid {
|
||||
public:
|
||||
|
||||
PVector location;
|
||||
PVector velocity;
|
||||
PVector acceleration;
|
||||
float maxforce; // Maximum steering force
|
||||
float maxspeed; // Maximum speed
|
||||
|
||||
float desiredseparation = 4;
|
||||
float neighbordist = 8;
|
||||
byte colorIndex = 0;
|
||||
float mass;
|
||||
|
||||
boolean enabled = true;
|
||||
|
||||
Boid() {}
|
||||
|
||||
Boid(float x, float y) {
|
||||
acceleration = PVector(0, 0);
|
||||
velocity = PVector(randomf(), randomf());
|
||||
location = PVector(x, y);
|
||||
maxspeed = 1.5;
|
||||
maxforce = 0.05;
|
||||
}
|
||||
|
||||
static float randomf() {
|
||||
return mapfloat(random(0, 255), 0, 255, -.5, .5);
|
||||
}
|
||||
|
||||
static float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
void run(Boid boids [], uint8_t boidCount) {
|
||||
flock(boids, boidCount);
|
||||
update();
|
||||
// wrapAroundBorders();
|
||||
// render();
|
||||
}
|
||||
|
||||
// Method to update location
|
||||
void update() {
|
||||
// Update velocity
|
||||
velocity += acceleration;
|
||||
// Limit speed
|
||||
velocity.limit(maxspeed);
|
||||
location += velocity;
|
||||
// Reset acceleration to 0 each cycle
|
||||
acceleration *= 0;
|
||||
}
|
||||
|
||||
void applyForce(PVector force) {
|
||||
// We could add mass here if we want A = F / M
|
||||
acceleration += force;
|
||||
}
|
||||
|
||||
void repelForce(PVector obstacle, float radius) {
|
||||
//Force that drives boid away from obstacle.
|
||||
|
||||
PVector futPos = location + velocity; //Calculate future position for more effective behavior.
|
||||
PVector dist = obstacle - futPos;
|
||||
float d = dist.mag();
|
||||
|
||||
if (d <= radius) {
|
||||
PVector repelVec = location - obstacle;
|
||||
repelVec.normalize();
|
||||
if (d != 0) { //Don't divide by zero.
|
||||
// float scale = 1.0 / d; //The closer to the obstacle, the stronger the force.
|
||||
repelVec.normalize();
|
||||
repelVec *= (maxforce * 7);
|
||||
if (repelVec.mag() < 0) { //Don't let the boids turn around to avoid the obstacle.
|
||||
repelVec.y = 0;
|
||||
}
|
||||
}
|
||||
applyForce(repelVec);
|
||||
}
|
||||
}
|
||||
|
||||
// We accumulate a new acceleration each time based on three rules
|
||||
void flock(Boid boids [], uint8_t boidCount) {
|
||||
PVector sep = separate(boids, boidCount); // Separation
|
||||
PVector ali = align(boids, boidCount); // Alignment
|
||||
PVector coh = cohesion(boids, boidCount); // Cohesion
|
||||
// Arbitrarily weight these forces
|
||||
sep *= 1.5;
|
||||
ali *= 1.0;
|
||||
coh *= 1.0;
|
||||
// Add the force vectors to acceleration
|
||||
applyForce(sep);
|
||||
applyForce(ali);
|
||||
applyForce(coh);
|
||||
}
|
||||
|
||||
// Separation
|
||||
// Method checks for nearby boids and steers away
|
||||
PVector separate(Boid boids [], uint8_t boidCount) {
|
||||
PVector steer = PVector(0, 0);
|
||||
int count = 0;
|
||||
// For every boid in the system, check if it's too close
|
||||
for (int i = 0; i < boidCount; i++) {
|
||||
Boid other = boids[i];
|
||||
if (!other.enabled)
|
||||
continue;
|
||||
float d = location.dist(other.location);
|
||||
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
|
||||
if ((d > 0) && (d < desiredseparation)) {
|
||||
// Calculate vector pointing away from neighbor
|
||||
PVector diff = location - other.location;
|
||||
diff.normalize();
|
||||
diff /= d; // Weight by distance
|
||||
steer += diff;
|
||||
count++; // Keep track of how many
|
||||
}
|
||||
}
|
||||
// Average -- divide by how many
|
||||
if (count > 0) {
|
||||
steer /= (float) count;
|
||||
}
|
||||
|
||||
// As long as the vector is greater than 0
|
||||
if (steer.mag() > 0) {
|
||||
// Implement Reynolds: Steering = Desired - Velocity
|
||||
steer.normalize();
|
||||
steer *= maxspeed;
|
||||
steer -= velocity;
|
||||
steer.limit(maxforce);
|
||||
}
|
||||
return steer;
|
||||
}
|
||||
|
||||
// Alignment
|
||||
// For every nearby boid in the system, calculate the average velocity
|
||||
PVector align(Boid boids [], uint8_t boidCount) {
|
||||
PVector sum = PVector(0, 0);
|
||||
int count = 0;
|
||||
for (int i = 0; i < boidCount; i++) {
|
||||
Boid other = boids[i];
|
||||
if (!other.enabled)
|
||||
continue;
|
||||
float d = location.dist(other.location);
|
||||
if ((d > 0) && (d < neighbordist)) {
|
||||
sum += other.velocity;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
sum /= (float) count;
|
||||
sum.normalize();
|
||||
sum *= maxspeed;
|
||||
PVector steer = sum - velocity;
|
||||
steer.limit(maxforce);
|
||||
return steer;
|
||||
}
|
||||
else {
|
||||
return PVector(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Cohesion
|
||||
// For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location
|
||||
PVector cohesion(Boid boids [], uint8_t boidCount) {
|
||||
PVector sum = PVector(0, 0); // Start with empty vector to accumulate all locations
|
||||
int count = 0;
|
||||
for (int i = 0; i < boidCount; i++) {
|
||||
Boid other = boids[i];
|
||||
if (!other.enabled)
|
||||
continue;
|
||||
float d = location.dist(other.location);
|
||||
if ((d > 0) && (d < neighbordist)) {
|
||||
sum += other.location; // Add location
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
sum /= count;
|
||||
return seek(sum); // Steer towards the location
|
||||
}
|
||||
else {
|
||||
return PVector(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// A method that calculates and applies a steering force towards a target
|
||||
// STEER = DESIRED MINUS VELOCITY
|
||||
PVector seek(PVector target) {
|
||||
PVector desired = target - location; // A vector pointing from the location to the target
|
||||
// Normalize desired and scale to maximum speed
|
||||
desired.normalize();
|
||||
desired *= maxspeed;
|
||||
// Steering = Desired minus Velocity
|
||||
PVector steer = desired - velocity;
|
||||
steer.limit(maxforce); // Limit to maximum steering force
|
||||
return steer;
|
||||
}
|
||||
|
||||
// A method that calculates a steering force towards a target
|
||||
// STEER = DESIRED MINUS VELOCITY
|
||||
void arrive(PVector target) {
|
||||
PVector desired = target - location; // A vector pointing from the location to the target
|
||||
float d = desired.mag();
|
||||
// Normalize desired and scale with arbitrary damping within 100 pixels
|
||||
desired.normalize();
|
||||
if (d < 4) {
|
||||
float m = map(d, 0, 100, 0, maxspeed);
|
||||
desired *= m;
|
||||
}
|
||||
else {
|
||||
desired *= maxspeed;
|
||||
}
|
||||
|
||||
// Steering = Desired minus Velocity
|
||||
PVector steer = desired - velocity;
|
||||
steer.limit(maxforce); // Limit to maximum steering force
|
||||
applyForce(steer);
|
||||
//Serial.println(d);
|
||||
}
|
||||
|
||||
void wrapAroundBorders() {
|
||||
if (location.x < 0) location.x = MATRIX_WIDTH - 1;
|
||||
if (location.y < 0) location.y = MATRIX_HEIGHT - 1;
|
||||
if (location.x >= MATRIX_WIDTH) location.x = 0;
|
||||
if (location.y >= MATRIX_HEIGHT) location.y = 0;
|
||||
}
|
||||
|
||||
void avoidBorders() {
|
||||
PVector desired = velocity;
|
||||
|
||||
if (location.x < 8) desired = PVector(maxspeed, velocity.y);
|
||||
if (location.x >= MATRIX_WIDTH - 8) desired = PVector(-maxspeed, velocity.y);
|
||||
if (location.y < 8) desired = PVector(velocity.x, maxspeed);
|
||||
if (location.y >= MATRIX_HEIGHT - 8) desired = PVector(velocity.x, -maxspeed);
|
||||
|
||||
if (desired != velocity) {
|
||||
PVector steer = desired - velocity;
|
||||
steer.limit(maxforce);
|
||||
applyForce(steer);
|
||||
}
|
||||
|
||||
if (location.x < 0) location.x = 0;
|
||||
if (location.y < 0) location.y = 0;
|
||||
if (location.x >= MATRIX_WIDTH) location.x = MATRIX_WIDTH - 1;
|
||||
if (location.y >= MATRIX_HEIGHT) location.y = MATRIX_HEIGHT - 1;
|
||||
}
|
||||
|
||||
bool bounceOffBorders(float bounce) {
|
||||
bool bounced = false;
|
||||
|
||||
if (location.x >= MATRIX_WIDTH) {
|
||||
location.x = MATRIX_WIDTH - 1;
|
||||
velocity.x *= -bounce;
|
||||
bounced = true;
|
||||
}
|
||||
else if (location.x < 0) {
|
||||
location.x = 0;
|
||||
velocity.x *= -bounce;
|
||||
bounced = true;
|
||||
}
|
||||
|
||||
if (location.y >= MATRIX_HEIGHT) {
|
||||
location.y = MATRIX_HEIGHT - 1;
|
||||
velocity.y *= -bounce;
|
||||
bounced = true;
|
||||
}
|
||||
else if (location.y < 0) {
|
||||
location.y = 0;
|
||||
velocity.y *= -bounce;
|
||||
bounced = true;
|
||||
}
|
||||
|
||||
return bounced;
|
||||
}
|
||||
|
||||
void render() {
|
||||
//// Draw a triangle rotated in the direction of velocity
|
||||
//float theta = velocity.heading2D() + radians(90);
|
||||
//fill(175);
|
||||
//stroke(0);
|
||||
//pushMatrix();
|
||||
//translate(location.x,location.y);
|
||||
//rotate(theta);
|
||||
//beginShape(TRIANGLES);
|
||||
//vertex(0, -r*2);
|
||||
//vertex(-r, r*2);
|
||||
//vertex(r, r*2);
|
||||
//endShape();
|
||||
//popMatrix();
|
||||
//dma_display->drawBackgroundPixelRGB888(location.x, location.y, CRGB::Blue);
|
||||
}
|
||||
};
|
||||
|
||||
static const uint8_t AVAILABLE_BOID_COUNT = 40;
|
||||
Boid boids[AVAILABLE_BOID_COUNT];
|
|
@ -322,5 +322,5 @@ class Boid {
|
|||
}
|
||||
};
|
||||
|
||||
static const uint8_t AVAILABLE_BOID_COUNT = 40;
|
||||
static const uint8_t AVAILABLE_BOID_COUNT = VPANEL_W;
|
||||
Boid boids[AVAILABLE_BOID_COUNT];
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Drawable_H
|
||||
#define Drawable_H
|
||||
|
||||
class Drawable{
|
||||
public:
|
||||
char* name;
|
||||
|
||||
virtual bool isRunnable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool isPlaylist() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// a single frame should be drawn as fast as possible, without any delay or blocking
|
||||
// return how many millisecond delay is requested before the next call to drawFrame()
|
||||
virtual unsigned int drawFrame() {
|
||||
dma_display->fillScreen(0);
|
||||
//backgroundLayer.fillScreen({ 0, 0, 0 });
|
||||
return 0;
|
||||
};
|
||||
|
||||
virtual void printTesting()
|
||||
{
|
||||
Serial.println("Testing...");
|
||||
}
|
||||
|
||||
virtual void start() {};
|
||||
virtual void stop() {};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,848 +0,0 @@
|
|||
|
||||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Funky Clouds" by Stefan Petrick: https://gist.github.com/anonymous/876f908333cd95315c35
|
||||
* Portions of this code are adapted from "NoiseSmearing" by Stefan Petrick: https://gist.github.com/StefanPetrick/9ee2f677dbff64e3ba7a
|
||||
* Copyright (c) 2014 Stefan Petrick
|
||||
* http://www.stefan-petrick.de/wordpress_beta
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Effects_H
|
||||
#define Effects_H
|
||||
|
||||
/* ---------------------------- GLOBAL CONSTANTS ----------------------------- */
|
||||
|
||||
const int MATRIX_CENTER_X = MATRIX_WIDTH / 2;
|
||||
const int MATRIX_CENTER_Y = MATRIX_HEIGHT / 2;
|
||||
// US vs GB, huh? :)
|
||||
//const byte MATRIX_CENTRE_X = MATRIX_CENTER_X - 1;
|
||||
//const byte MATRIX_CENTRE_Y = MATRIX_CENTER_Y - 1;
|
||||
#define MATRIX_CENTRE_X MATRIX_CENTER_X
|
||||
#define MATRIX_CENTRE_Y MATRIX_CENTER_Y
|
||||
|
||||
|
||||
const uint16_t NUM_LEDS = (MATRIX_WIDTH * MATRIX_HEIGHT) + 1; // one led spare to capture out of bounds
|
||||
|
||||
// forward declaration
|
||||
uint16_t XY16( uint16_t x, uint16_t y);
|
||||
|
||||
/* Convert x,y co-ordinate to flat array index.
|
||||
* x and y positions start from 0, so must not be >= 'real' panel width or height
|
||||
* (i.e. 64 pixels or 32 pixels.). Max value: MATRIX_WIDTH-1 etc.
|
||||
* Ugh... uint8_t - really??? this weak method can't cope with 256+ pixel matrices :(
|
||||
*/
|
||||
uint16_t XY( uint8_t x, uint8_t y)
|
||||
{
|
||||
return XY16(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* The one for 256+ matrices
|
||||
* otherwise this:
|
||||
* for (uint8_t i = 0; i < MATRIX_WIDTH; i++) {}
|
||||
* turns into an infinite loop
|
||||
*/
|
||||
uint16_t XY16( uint16_t x, uint16_t y)
|
||||
{
|
||||
if( x >= MATRIX_WIDTH) return 0;
|
||||
if( y >= MATRIX_HEIGHT) return 0;
|
||||
|
||||
return (y * MATRIX_WIDTH) + x + 1; // everything offset by one to compute out of bounds stuff - never displayed by ShowFrame()
|
||||
}
|
||||
|
||||
|
||||
uint8_t beatcos8(accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0)
|
||||
{
|
||||
uint8_t beat = beat8(beats_per_minute, timebase);
|
||||
uint8_t beatcos = cos8(beat + phase_offset);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatcos, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t mapsin8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
|
||||
uint8_t beatsin = sin8(theta);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatsin, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t mapcos8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
|
||||
uint8_t beatcos = cos8(theta);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatcos, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Array of temperature readings at each simulation cell
|
||||
//byte heat[NUM_LEDS]; // none of the currently enabled effects uses this
|
||||
|
||||
uint32_t noise_x;
|
||||
uint32_t noise_y;
|
||||
uint32_t noise_z;
|
||||
uint32_t noise_scale_x;
|
||||
uint32_t noise_scale_y;
|
||||
|
||||
//uint8_t noise[MATRIX_WIDTH][MATRIX_HEIGHT];
|
||||
uint8_t **noise = nullptr; // we will allocate mem later
|
||||
uint8_t noisesmoothing;
|
||||
|
||||
class Effects {
|
||||
public:
|
||||
CRGB *leds;
|
||||
//CRGB leds[NUM_LEDS];
|
||||
//CRGB leds2[NUM_LEDS]; // Faptastic: getting rid of this and any dependant effects or algos. to save memory 24*64*32 bytes of ram (50k).
|
||||
|
||||
Effects(){
|
||||
// we do dynamic allocation for leds buffer, otherwise esp32 toolchain can't link static arrays of such a big size for 256+ matrices
|
||||
leds = (CRGB *)malloc(NUM_LEDS * sizeof(CRGB));
|
||||
|
||||
// allocate mem for noise effect
|
||||
// (there should be some guards for malloc errors eventually)
|
||||
noise = (uint8_t **)malloc(MATRIX_WIDTH * sizeof(uint8_t *));
|
||||
for (int i = 0; i < MATRIX_WIDTH; ++i) {
|
||||
noise[i] = (uint8_t *)malloc(MATRIX_HEIGHT * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
ClearFrame();
|
||||
//dma_display->clearScreen();
|
||||
}
|
||||
~Effects(){
|
||||
free(leds);
|
||||
for (int i = 0; i < MATRIX_WIDTH; ++i) {
|
||||
free(noise[i]);
|
||||
}
|
||||
free(noise);
|
||||
}
|
||||
|
||||
/* The only 'framebuffer' we have is what is contained in the leds and leds2 variables.
|
||||
* We don't store what the color a particular pixel might be, other than when it's turned
|
||||
* into raw electrical signal output gobbly-gook (i.e. the DMA matrix buffer), but this * is not reversible.
|
||||
*
|
||||
* As such, any time these effects want to write a pixel color, we first have to update
|
||||
* the leds or leds2 array, and THEN write it to the RGB panel. This enables us to 'look up' the array to see what a pixel color was previously, each drawFrame().
|
||||
*/
|
||||
void drawBackgroundFastLEDPixelCRGB(int16_t x, int16_t y, CRGB color)
|
||||
{
|
||||
leds[XY(x, y)] = color;
|
||||
//dma_display->drawPixelRGB888(x, y, color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
// write one pixel with the specified color from the current palette to coordinates
|
||||
void Pixel(int x, int y, uint8_t colorIndex) {
|
||||
leds[XY(x, y)] = ColorFromCurrentPalette(colorIndex);
|
||||
//dma_display->drawPixelRGB888(x, y, temp.r, temp.g, temp.b); // now draw it?
|
||||
}
|
||||
|
||||
void PrepareFrame() {
|
||||
// leds = (CRGB*) backgroundLayer.backBuffer();
|
||||
}
|
||||
|
||||
void ShowFrame() {
|
||||
//#if (FASTLED_VERSION >= 3001000)
|
||||
// nblendPaletteTowardPalette(currentPalette, targetPalette, 24);
|
||||
//#else
|
||||
currentPalette = targetPalette;
|
||||
//#endif
|
||||
|
||||
// backgroundLayer.swapBuffers();
|
||||
// leds = (CRGB*) backgroundLayer.backBuffer();
|
||||
// LEDS.countFPS();
|
||||
|
||||
for (int y=0; y<MATRIX_HEIGHT; ++y){
|
||||
for (int x=0; x<MATRIX_WIDTH; ++x){
|
||||
//Serial.printf("Flushing x, y coord %d, %d\n", x, y);
|
||||
uint16_t _pixel = XY16(x,y);
|
||||
dma_display->drawPixelRGB888( x, y, leds[_pixel].r, leds[_pixel].g, leds[_pixel].b);
|
||||
} // end loop to copy fast led to the dma matrix
|
||||
}
|
||||
}
|
||||
|
||||
// scale the brightness of the screenbuffer down
|
||||
void DimAll(byte value)
|
||||
{
|
||||
for (int i = 0; i < NUM_LEDS; i++)
|
||||
{
|
||||
leds[i].nscale8(value);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearFrame()
|
||||
{
|
||||
memset(leds, 0x00, NUM_LEDS * sizeof(CRGB)); // flush
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void CircleStream(uint8_t value) {
|
||||
DimAll(value); ShowFrame();
|
||||
|
||||
for (uint8_t offset = 0; offset < MATRIX_CENTER_X; offset++) {
|
||||
boolean hasprev = false;
|
||||
uint16_t prevxy = 0;
|
||||
|
||||
for (uint8_t theta = 0; theta < 255; theta++) {
|
||||
uint8_t x = mapcos8(theta, offset, (MATRIX_WIDTH - 1) - offset);
|
||||
uint8_t y = mapsin8(theta, offset, (MATRIX_HEIGHT - 1) - offset);
|
||||
|
||||
uint16_t xy = XY(x, y);
|
||||
|
||||
if (hasprev) {
|
||||
leds[prevxy] += leds[xy];
|
||||
}
|
||||
|
||||
prevxy = xy;
|
||||
hasprev = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
uint16_t xy = XY(x, y);
|
||||
leds[xy] = leds2[xy];
|
||||
leds[xy].nscale8(value);
|
||||
leds2[xy].nscale8(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// palettes
|
||||
static const int paletteCount = 10;
|
||||
int paletteIndex = -1;
|
||||
TBlendType currentBlendType = LINEARBLEND;
|
||||
CRGBPalette16 currentPalette;
|
||||
CRGBPalette16 targetPalette;
|
||||
char* currentPaletteName;
|
||||
|
||||
static const int HeatColorsPaletteIndex = 6;
|
||||
static const int RandomPaletteIndex = 9;
|
||||
|
||||
void Setup() {
|
||||
currentPalette = RainbowColors_p;
|
||||
loadPalette(0);
|
||||
NoiseVariablesSetup();
|
||||
}
|
||||
|
||||
void CyclePalette(int offset = 1) {
|
||||
loadPalette(paletteIndex + offset);
|
||||
}
|
||||
|
||||
void RandomPalette() {
|
||||
loadPalette(RandomPaletteIndex);
|
||||
}
|
||||
|
||||
void loadPalette(int index) {
|
||||
paletteIndex = index;
|
||||
|
||||
if (paletteIndex >= paletteCount)
|
||||
paletteIndex = 0;
|
||||
else if (paletteIndex < 0)
|
||||
paletteIndex = paletteCount - 1;
|
||||
|
||||
switch (paletteIndex) {
|
||||
case 0:
|
||||
targetPalette = RainbowColors_p;
|
||||
currentPaletteName = (char *)"Rainbow";
|
||||
break;
|
||||
//case 1:
|
||||
// targetPalette = RainbowStripeColors_p;
|
||||
// currentPaletteName = (char *)"RainbowStripe";
|
||||
// break;
|
||||
case 1:
|
||||
targetPalette = OceanColors_p;
|
||||
currentPaletteName = (char *)"Ocean";
|
||||
break;
|
||||
case 2:
|
||||
targetPalette = CloudColors_p;
|
||||
currentPaletteName = (char *)"Cloud";
|
||||
break;
|
||||
case 3:
|
||||
targetPalette = ForestColors_p;
|
||||
currentPaletteName = (char *)"Forest";
|
||||
break;
|
||||
case 4:
|
||||
targetPalette = PartyColors_p;
|
||||
currentPaletteName = (char *)"Party";
|
||||
break;
|
||||
case 5:
|
||||
setupGrayscalePalette();
|
||||
currentPaletteName = (char *)"Grey";
|
||||
break;
|
||||
case HeatColorsPaletteIndex:
|
||||
targetPalette = HeatColors_p;
|
||||
currentPaletteName = (char *)"Heat";
|
||||
break;
|
||||
case 7:
|
||||
targetPalette = LavaColors_p;
|
||||
currentPaletteName = (char *)"Lava";
|
||||
break;
|
||||
case 8:
|
||||
setupIcePalette();
|
||||
currentPaletteName = (char *)"Ice";
|
||||
break;
|
||||
case RandomPaletteIndex:
|
||||
loadPalette(random(0, paletteCount - 1));
|
||||
paletteIndex = RandomPaletteIndex;
|
||||
currentPaletteName = (char *)"Random";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setPalette(String paletteName) {
|
||||
if (paletteName == "Rainbow")
|
||||
loadPalette(0);
|
||||
//else if (paletteName == "RainbowStripe")
|
||||
// loadPalette(1);
|
||||
else if (paletteName == "Ocean")
|
||||
loadPalette(1);
|
||||
else if (paletteName == "Cloud")
|
||||
loadPalette(2);
|
||||
else if (paletteName == "Forest")
|
||||
loadPalette(3);
|
||||
else if (paletteName == "Party")
|
||||
loadPalette(4);
|
||||
else if (paletteName == "Grayscale")
|
||||
loadPalette(5);
|
||||
else if (paletteName == "Heat")
|
||||
loadPalette(6);
|
||||
else if (paletteName == "Lava")
|
||||
loadPalette(7);
|
||||
else if (paletteName == "Ice")
|
||||
loadPalette(8);
|
||||
else if (paletteName == "Random")
|
||||
RandomPalette();
|
||||
}
|
||||
|
||||
void listPalettes() {
|
||||
Serial.println(F("{"));
|
||||
Serial.print(F(" \"count\": "));
|
||||
Serial.print(paletteCount);
|
||||
Serial.println(",");
|
||||
Serial.println(F(" \"results\": ["));
|
||||
|
||||
String paletteNames [] = {
|
||||
"Rainbow",
|
||||
// "RainbowStripe",
|
||||
"Ocean",
|
||||
"Cloud",
|
||||
"Forest",
|
||||
"Party",
|
||||
"Grayscale",
|
||||
"Heat",
|
||||
"Lava",
|
||||
"Ice",
|
||||
"Random"
|
||||
};
|
||||
|
||||
for (int i = 0; i < paletteCount; i++) {
|
||||
Serial.print(F(" \""));
|
||||
Serial.print(paletteNames[i]);
|
||||
if (i == paletteCount - 1)
|
||||
Serial.println(F("\""));
|
||||
else
|
||||
Serial.println(F("\","));
|
||||
}
|
||||
|
||||
Serial.println(" ]");
|
||||
Serial.println("}");
|
||||
}
|
||||
|
||||
void setupGrayscalePalette() {
|
||||
targetPalette = CRGBPalette16(CRGB::Black, CRGB::White);
|
||||
}
|
||||
|
||||
void setupIcePalette() {
|
||||
targetPalette = CRGBPalette16(CRGB::Black, CRGB::Blue, CRGB::Aqua, CRGB::White);
|
||||
}
|
||||
|
||||
// Oscillators and Emitters
|
||||
|
||||
// the oscillators: linear ramps 0-255
|
||||
byte osci[6];
|
||||
|
||||
// sin8(osci) swinging between 0 to MATRIX_WIDTH - 1
|
||||
byte p[6];
|
||||
|
||||
// set the speeds (and by that ratios) of the oscillators here
|
||||
void MoveOscillators() {
|
||||
osci[0] = osci[0] + 5;
|
||||
osci[1] = osci[1] + 2;
|
||||
osci[2] = osci[2] + 3;
|
||||
osci[3] = osci[3] + 4;
|
||||
osci[4] = osci[4] + 1;
|
||||
if (osci[4] % 2 == 0)
|
||||
osci[5] = osci[5] + 1; // .5
|
||||
for (int i = 0; i < 4; i++) {
|
||||
p[i] = map8(sin8(osci[i]), 0, MATRIX_WIDTH - 1); //why? to keep the result in the range of 0-MATRIX_WIDTH (matrix size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// All the caleidoscope functions work directly within the screenbuffer (leds array).
|
||||
// Draw whatever you like in the area x(0-15) and y (0-15) and then copy it arround.
|
||||
|
||||
// rotates the first 16x16 quadrant 3 times onto a 32x32 (+90 degrees rotation for each one)
|
||||
void Caleidoscope1() {
|
||||
for (int x = 0; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < MATRIX_CENTER_Y; y++) {
|
||||
leds[XY16(MATRIX_WIDTH - 1 - x, y)] = leds[XY16(x, y)];
|
||||
leds[XY16(MATRIX_WIDTH - 1 - x, MATRIX_HEIGHT - 1 - y)] = leds[XY16(x, y)];
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1 - y)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// mirror the first 16x16 quadrant 3 times onto a 32x32
|
||||
void Caleidoscope2() {
|
||||
for (int x = 0; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < MATRIX_CENTER_Y; y++) {
|
||||
leds[XY16(MATRIX_WIDTH - 1 - x, y)] = leds[XY16(y, x)];
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1 - y)] = leds[XY16(y, x)];
|
||||
leds[XY16(MATRIX_WIDTH - 1 - x, MATRIX_HEIGHT - 1 - y)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy one diagonal triangle into the other one within a 16x16
|
||||
void Caleidoscope3() {
|
||||
for (int x = 0; x <= MATRIX_CENTRE_X && x < MATRIX_HEIGHT; x++) {
|
||||
for (int y = 0; y <= x && y<MATRIX_HEIGHT; y++) {
|
||||
leds[XY16(x, y)] = leds[XY16(y, x)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy one diagonal triangle into the other one within a 16x16 (90 degrees rotated compared to Caleidoscope3)
|
||||
void Caleidoscope4() {
|
||||
for (int x = 0; x <= MATRIX_CENTRE_X; x++) {
|
||||
for (int y = 0; y <= MATRIX_CENTRE_Y - x; y++) {
|
||||
leds[XY16(MATRIX_CENTRE_Y - y, MATRIX_CENTRE_X - x)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy one diagonal triangle into the other one within a 8x8
|
||||
void Caleidoscope5() {
|
||||
for (int x = 0; x < MATRIX_WIDTH / 4; x++) {
|
||||
for (int y = 0; y <= x && y<=MATRIX_HEIGHT; y++) {
|
||||
leds[XY16(x, y)] = leds[XY16(y, x)];
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = MATRIX_WIDTH / 4; x < MATRIX_WIDTH / 2; x++) {
|
||||
for (int y = MATRIX_HEIGHT / 4; y >= 0; y--) {
|
||||
leds[XY16(x, y)] = leds[XY16(y, x)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Caleidoscope6() {
|
||||
for (int x = 1; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 7)] = leds[XY16(x, 0)];
|
||||
} //a
|
||||
for (int x = 2; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 6)] = leds[XY16(x, 1)];
|
||||
} //b
|
||||
for (int x = 3; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 5)] = leds[XY16(x, 2)];
|
||||
} //c
|
||||
for (int x = 4; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 4)] = leds[XY16(x, 3)];
|
||||
} //d
|
||||
for (int x = 5; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 3)] = leds[XY16(x, 4)];
|
||||
} //e
|
||||
for (int x = 6; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 2)] = leds[XY16(x, 5)];
|
||||
} //f
|
||||
for (int x = 7; x < MATRIX_CENTER_X; x++) {
|
||||
leds[XY16(7 - x, 1)] = leds[XY16(x, 6)];
|
||||
} //g
|
||||
}
|
||||
|
||||
// create a square twister to the left or counter-clockwise
|
||||
// x and y for center, r for radius
|
||||
void SpiralStream(int x, int y, int r, byte dimm) {
|
||||
for (int d = r; d >= 0; d--) { // from the outside to the inside
|
||||
for (int i = x - d; i <= x + d; i++) {
|
||||
leds[XY16(i, y - d)] += leds[XY16(i + 1, y - d)]; // lowest row to the right
|
||||
leds[XY16(i, y - d)].nscale8(dimm);
|
||||
}
|
||||
for (int i = y - d; i <= y + d; i++) {
|
||||
leds[XY16(x + d, i)] += leds[XY16(x + d, i + 1)]; // right column up
|
||||
leds[XY16(x + d, i)].nscale8(dimm);
|
||||
}
|
||||
for (int i = x + d; i >= x - d; i--) {
|
||||
leds[XY16(i, y + d)] += leds[XY16(i - 1, y + d)]; // upper row to the left
|
||||
leds[XY16(i, y + d)].nscale8(dimm);
|
||||
}
|
||||
for (int i = y + d; i >= y - d; i--) {
|
||||
leds[XY16(x - d, i)] += leds[XY16(x - d, i - 1)]; // left column down
|
||||
leds[XY16(x - d, i)].nscale8(dimm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// expand everything within a circle
|
||||
void Expand(int centerX, int centerY, int radius, byte dimm) {
|
||||
if (radius == 0)
|
||||
return;
|
||||
|
||||
int currentRadius = radius;
|
||||
|
||||
while (currentRadius > 0) {
|
||||
int a = radius, b = 0;
|
||||
int radiusError = 1 - a;
|
||||
|
||||
int nextRadius = currentRadius - 1;
|
||||
int nextA = nextRadius - 1, nextB = 0;
|
||||
int nextRadiusError = 1 - nextA;
|
||||
|
||||
while (a >= b)
|
||||
{
|
||||
// move them out one pixel on the radius
|
||||
leds[XY16(a + centerX, b + centerY)] = leds[XY16(nextA + centerX, nextB + centerY)];
|
||||
leds[XY16(b + centerX, a + centerY)] = leds[XY16(nextB + centerX, nextA + centerY)];
|
||||
leds[XY16(-a + centerX, b + centerY)] = leds[XY16(-nextA + centerX, nextB + centerY)];
|
||||
leds[XY16(-b + centerX, a + centerY)] = leds[XY16(-nextB + centerX, nextA + centerY)];
|
||||
leds[XY16(-a + centerX, -b + centerY)] = leds[XY16(-nextA + centerX, -nextB + centerY)];
|
||||
leds[XY16(-b + centerX, -a + centerY)] = leds[XY16(-nextB + centerX, -nextA + centerY)];
|
||||
leds[XY16(a + centerX, -b + centerY)] = leds[XY16(nextA + centerX, -nextB + centerY)];
|
||||
leds[XY16(b + centerX, -a + centerY)] = leds[XY16(nextB + centerX, -nextA + centerY)];
|
||||
|
||||
// dim them
|
||||
leds[XY16(a + centerX, b + centerY)].nscale8(dimm);
|
||||
leds[XY16(b + centerX, a + centerY)].nscale8(dimm);
|
||||
leds[XY16(-a + centerX, b + centerY)].nscale8(dimm);
|
||||
leds[XY16(-b + centerX, a + centerY)].nscale8(dimm);
|
||||
leds[XY16(-a + centerX, -b + centerY)].nscale8(dimm);
|
||||
leds[XY16(-b + centerX, -a + centerY)].nscale8(dimm);
|
||||
leds[XY16(a + centerX, -b + centerY)].nscale8(dimm);
|
||||
leds[XY16(b + centerX, -a + centerY)].nscale8(dimm);
|
||||
|
||||
b++;
|
||||
if (radiusError < 0)
|
||||
radiusError += 2 * b + 1;
|
||||
else
|
||||
{
|
||||
a--;
|
||||
radiusError += 2 * (b - a + 1);
|
||||
}
|
||||
|
||||
nextB++;
|
||||
if (nextRadiusError < 0)
|
||||
nextRadiusError += 2 * nextB + 1;
|
||||
else
|
||||
{
|
||||
nextA--;
|
||||
nextRadiusError += 2 * (nextB - nextA + 1);
|
||||
}
|
||||
}
|
||||
|
||||
currentRadius--;
|
||||
}
|
||||
}
|
||||
|
||||
// give it a linear tail to the right
|
||||
void StreamRight(byte scale, int fromX = 0, int toX = MATRIX_WIDTH, int fromY = 0, int toY = MATRIX_HEIGHT)
|
||||
{
|
||||
for (int x = fromX + 1; x < toX; x++) {
|
||||
for (int y = fromY; y < toY; y++) {
|
||||
leds[XY16(x, y)] += leds[XY16(x - 1, y)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int y = fromY; y < toY; y++)
|
||||
leds[XY16(0, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail to the left
|
||||
void StreamLeft(byte scale, int fromX = MATRIX_WIDTH, int toX = 0, int fromY = 0, int toY = MATRIX_HEIGHT)
|
||||
{
|
||||
for (int x = toX; x < fromX; x++) {
|
||||
for (int y = fromY; y < toY; y++) {
|
||||
leds[XY16(x, y)] += leds[XY16(x + 1, y)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int y = fromY; y < toY; y++)
|
||||
leds[XY16(0, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail downwards
|
||||
void StreamDown(byte scale)
|
||||
{
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = 1; y < MATRIX_HEIGHT; y++) {
|
||||
leds[XY16(x, y)] += leds[XY16(x, y - 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
leds[XY16(x, 0)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail upwards
|
||||
void StreamUp(byte scale)
|
||||
{
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = MATRIX_HEIGHT - 2; y >= 0; y--) {
|
||||
leds[XY16(x, y)] += leds[XY16(x, y + 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail up and to the left
|
||||
void StreamUpAndLeft(byte scale)
|
||||
{
|
||||
for (int x = 0; x < MATRIX_WIDTH - 1; x++) {
|
||||
for (int y = MATRIX_HEIGHT - 2; y >= 0; y--) {
|
||||
leds[XY16(x, y)] += leds[XY16(x + 1, y + 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1)].nscale8(scale);
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++)
|
||||
leds[XY16(MATRIX_WIDTH - 1, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail up and to the right
|
||||
void StreamUpAndRight(byte scale)
|
||||
{
|
||||
for (int x = 0; x < MATRIX_WIDTH - 1; x++) {
|
||||
for (int y = MATRIX_HEIGHT - 2; y >= 0; y--) {
|
||||
leds[XY16(x + 1, y)] += leds[XY16(x, y + 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
// fade the bottom row
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
leds[XY16(x, MATRIX_HEIGHT - 1)].nscale8(scale);
|
||||
|
||||
// fade the right column
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++)
|
||||
leds[XY16(MATRIX_WIDTH - 1, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// just move everything one line down
|
||||
void MoveDown() {
|
||||
for (int y = MATRIX_HEIGHT - 1; y > 0; y--) {
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
leds[XY16(x, y)] = leds[XY16(x, y - 1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// just move everything one line down
|
||||
void VerticalMoveFrom(int start, int end) {
|
||||
for (int y = end; y > start; y--) {
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
leds[XY16(x, y)] = leds[XY16(x, y - 1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy the rectangle defined with 2 points x0, y0, x1, y1
|
||||
// to the rectangle beginning at x2, x3
|
||||
void Copy(byte x0, byte y0, byte x1, byte y1, byte x2, byte y2) {
|
||||
for (int y = y0; y < y1 + 1; y++) {
|
||||
for (int x = x0; x < x1 + 1; x++) {
|
||||
leds[XY16(x + x2 - x0, y + y2 - y0)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rotate + copy triangle (MATRIX_CENTER_X*MATRIX_CENTER_X)
|
||||
void RotateTriangle() {
|
||||
for (int x = 1; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < x; y++) {
|
||||
leds[XY16(x, 7 - y)] = leds[XY16(7 - x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mirror + copy triangle (MATRIX_CENTER_X*MATRIX_CENTER_X)
|
||||
void MirrorTriangle() {
|
||||
for (int x = 1; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < x; y++) {
|
||||
leds[XY16(7 - y, x)] = leds[XY16(7 - x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw static rainbow triangle pattern (MATRIX_CENTER_XxWIDTH / 2)
|
||||
// (just for debugging)
|
||||
void RainbowTriangle() {
|
||||
for (int i = 0; i < MATRIX_CENTER_X; i++) {
|
||||
for (int j = 0; j <= i; j++) {
|
||||
Pixel(7 - i, j, i * j * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BresenhamLine(int x0, int y0, int x1, int y1, byte colorIndex)
|
||||
{
|
||||
BresenhamLine(x0, y0, x1, y1, ColorFromCurrentPalette(colorIndex));
|
||||
}
|
||||
|
||||
void BresenhamLine(int x0, int y0, int x1, int y1, CRGB color)
|
||||
{
|
||||
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
||||
int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
|
||||
int err = dx + dy, e2;
|
||||
for (;;) {
|
||||
leds[XY16(x0, y0)] += color;
|
||||
if (x0 == x1 && y0 == y1) break;
|
||||
e2 = 2 * err;
|
||||
if (e2 > dy) {
|
||||
err += dy;
|
||||
x0 += sx;
|
||||
}
|
||||
if (e2 < dx) {
|
||||
err += dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) {
|
||||
return ColorFromPalette(currentPalette, index, brightness, currentBlendType);
|
||||
}
|
||||
|
||||
CRGB HsvToRgb(uint8_t h, uint8_t s, uint8_t v) {
|
||||
CHSV hsv = CHSV(h, s, v);
|
||||
CRGB rgb;
|
||||
hsv2rgb_spectrum(hsv, rgb);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
void NoiseVariablesSetup() {
|
||||
noisesmoothing = 200;
|
||||
|
||||
noise_x = random16();
|
||||
noise_y = random16();
|
||||
noise_z = random16();
|
||||
noise_scale_x = 6000;
|
||||
noise_scale_y = 6000;
|
||||
}
|
||||
|
||||
void FillNoise() {
|
||||
for (uint16_t i = 0; i < MATRIX_WIDTH; i++) {
|
||||
uint32_t ioffset = noise_scale_x * (i - MATRIX_CENTRE_Y);
|
||||
|
||||
for (uint16_t j = 0; j < MATRIX_HEIGHT; j++) {
|
||||
uint32_t joffset = noise_scale_y * (j - MATRIX_CENTRE_Y);
|
||||
|
||||
byte data = inoise16(noise_x + ioffset, noise_y + joffset, noise_z) >> 8;
|
||||
|
||||
uint8_t olddata = noise[i][j];
|
||||
uint8_t newdata = scale8(olddata, noisesmoothing) + scale8(data, 256 - noisesmoothing);
|
||||
data = newdata;
|
||||
|
||||
noise[i][j] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// non leds2 memory version.
|
||||
void MoveX(byte delta)
|
||||
{
|
||||
|
||||
CRGB tmp = 0;
|
||||
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++)
|
||||
{
|
||||
|
||||
// Shift Left: https://codedost.com/c/arraypointers-in-c/c-program-shift-elements-array-left-direction/
|
||||
// Computationally heavier but doesn't need an entire leds2 array
|
||||
|
||||
tmp = leds[XY16(0, y)];
|
||||
for (int m = 0; m < delta; m++)
|
||||
{
|
||||
// Do this delta time for each row... computationally expensive potentially.
|
||||
for(int x = 0; x < MATRIX_WIDTH; x++)
|
||||
{
|
||||
leds[XY16(x, y)] = leds [XY16(x+1, y)];
|
||||
}
|
||||
|
||||
leds[XY16(MATRIX_WIDTH-1, y)] = tmp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Shift
|
||||
for (int x = 0; x < MATRIX_WIDTH - delta; x++) {
|
||||
leds2[XY(x, y)] = leds[XY(x + delta, y)];
|
||||
}
|
||||
|
||||
// Wrap around
|
||||
for (int x = MATRIX_WIDTH - delta; x < MATRIX_WIDTH; x++) {
|
||||
leds2[XY(x, y)] = leds[XY(x + delta - MATRIX_WIDTH, y)];
|
||||
}
|
||||
*/
|
||||
} // end row loop
|
||||
|
||||
/*
|
||||
// write back to leds
|
||||
for (uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
leds[XY(x, y)] = leds2[XY(x, y)];
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void MoveY(byte delta)
|
||||
{
|
||||
|
||||
CRGB tmp = 0;
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++)
|
||||
{
|
||||
tmp = leds[XY16(x, 0)];
|
||||
for (int m = 0; m < delta; m++) // moves
|
||||
{
|
||||
// Do this delta time for each row... computationally expensive potentially.
|
||||
for(int y = 0; y < MATRIX_HEIGHT; y++)
|
||||
{
|
||||
leds[XY16(x, y)] = leds [XY16(x, y+1)];
|
||||
}
|
||||
|
||||
leds[XY16(x, MATRIX_HEIGHT-1)] = tmp;
|
||||
}
|
||||
} // end column loop
|
||||
} /// MoveY
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -7,6 +7,8 @@
|
|||
* Portions of this code are adapted from "NoiseSmearing" by Stefan Petrick: https://gist.github.com/StefanPetrick/9ee2f677dbff64e3ba7a
|
||||
* Copyright (c) 2014 Stefan Petrick
|
||||
* http://www.stefan-petrick.de/wordpress_beta
|
||||
*
|
||||
* Modified by Codetastic 2024
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -29,106 +31,79 @@
|
|||
#ifndef Effects_H
|
||||
#define Effects_H
|
||||
|
||||
/* ---------------------------- GLOBAL CONSTANTS ----------------------------- */
|
||||
|
||||
const int MATRIX_CENTER_X = VPANEL_W / 2;
|
||||
const int MATRIX_CENTER_Y = VPANEL_H / 2;
|
||||
// US vs GB, huh? :)
|
||||
//const byte MATRIX_CENTRE_X = MATRIX_CENTER_X - 1;
|
||||
//const byte MATRIX_CENTRE_Y = MATRIX_CENTER_Y - 1;
|
||||
#define MATRIX_CENTRE_X MATRIX_CENTER_X
|
||||
#define MATRIX_CENTRE_Y MATRIX_CENTER_Y
|
||||
|
||||
|
||||
const uint16_t NUM_LEDS = (VPANEL_W * VPANEL_H) + 1; // one led spare to capture out of bounds
|
||||
/**
|
||||
* The one for 256+ matrices
|
||||
* otherwise this:
|
||||
* for (uint8_t i = 0; i < VPANEL_W; i++) {}
|
||||
* turns into an infinite loop
|
||||
*/
|
||||
uint16_t XY16( uint16_t x, uint16_t y)
|
||||
{
|
||||
if( x >= VPANEL_W) return 0;
|
||||
if( y >= VPANEL_H) return 0;
|
||||
|
||||
// forward declaration
|
||||
uint16_t XY16( uint16_t x, uint16_t y);
|
||||
|
||||
/* Convert x,y co-ordinate to flat array index.
|
||||
* x and y positions start from 0, so must not be >= 'real' panel width or height
|
||||
* (i.e. 64 pixels or 32 pixels.). Max value: VPANEL_W-1 etc.
|
||||
* Ugh... uint8_t - really??? this weak method can't cope with 256+ pixel matrices :(
|
||||
*/
|
||||
uint16_t XY( uint8_t x, uint8_t y)
|
||||
{
|
||||
return XY16(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* The one for 256+ matrices
|
||||
* otherwise this:
|
||||
* for (uint8_t i = 0; i < VPANEL_W; i++) {}
|
||||
* turns into an infinite loop
|
||||
*/
|
||||
uint16_t XY16( uint16_t x, uint16_t y)
|
||||
{
|
||||
if( x >= VPANEL_W) return 0;
|
||||
if( y >= VPANEL_H) return 0;
|
||||
|
||||
return (y * VPANEL_W) + x + 1; // everything offset by one to compute out of bounds stuff - never displayed by ShowFrame()
|
||||
}
|
||||
return (y * VPANEL_W) + x;
|
||||
}
|
||||
|
||||
|
||||
uint8_t beatcos8(accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0)
|
||||
{
|
||||
uint8_t beat = beat8(beats_per_minute, timebase);
|
||||
uint8_t beatcos = cos8(beat + phase_offset);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatcos, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
/* Convert x,y co-ordinate to flat array index.
|
||||
* x and y positions start from 0, so must not be >= 'real' panel width or height
|
||||
* (i.e. 64 pixels or 32 pixels.). Max value: VPANEL_W-1 etc.
|
||||
* Ugh... uint8_t - really??? this weak method can't cope with 256+ pixel matrices :(
|
||||
*/
|
||||
uint16_t XY( uint16_t x, uint16_t y)
|
||||
{
|
||||
return XY16(x, y);
|
||||
}
|
||||
|
||||
uint8_t mapsin8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
|
||||
uint8_t beatsin = sin8(theta);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatsin, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t mapcos8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
|
||||
uint8_t beatcos = cos8(theta);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatcos, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Array of temperature readings at each simulation cell
|
||||
//byte heat[NUM_LEDS]; // none of the currently enabled effects uses this
|
||||
|
||||
uint32_t noise_x;
|
||||
uint32_t noise_y;
|
||||
uint32_t noise_z;
|
||||
uint32_t noise_scale_x;
|
||||
uint32_t noise_scale_y;
|
||||
class EffectsLayer : public GFX {
|
||||
|
||||
//uint8_t noise[VPANEL_W][VPANEL_H];
|
||||
uint8_t **noise = nullptr; // we will allocate mem later
|
||||
uint8_t noisesmoothing;
|
||||
|
||||
class Effects {
|
||||
public:
|
||||
CRGB *leds;
|
||||
|
||||
Effects(){
|
||||
uint32_t noise_x;
|
||||
uint32_t noise_y;
|
||||
uint32_t noise_z;
|
||||
uint32_t noise_scale_x;
|
||||
uint32_t noise_scale_y;
|
||||
|
||||
uint8_t **noise = nullptr; // we will allocate mem later
|
||||
uint8_t noisesmoothing;
|
||||
|
||||
|
||||
CRGB *leds;
|
||||
int width;
|
||||
int height;
|
||||
int num_leds = 0;
|
||||
|
||||
EffectsLayer(int w, int h) : GFX(w, h), width(w), height(h) {
|
||||
|
||||
// we do dynamic allocation for leds buffer, otherwise esp32 toolchain can't link static arrays of such a big size for 256+ matrices
|
||||
leds = (CRGB *)malloc(NUM_LEDS * sizeof(CRGB));
|
||||
leds = (CRGB *)malloc((width * height + 1) * sizeof(CRGB));
|
||||
num_leds = width * height;
|
||||
|
||||
// allocate mem for noise effect
|
||||
// (there should be some guards for malloc errors eventually)
|
||||
noise = (uint8_t **)malloc(VPANEL_W * sizeof(uint8_t *));
|
||||
for (int i = 0; i < VPANEL_W; ++i) {
|
||||
noise[i] = (uint8_t *)malloc(VPANEL_H * sizeof(uint8_t));
|
||||
noise = (uint8_t **)malloc(width * sizeof(uint8_t *));
|
||||
for (int i = 0; i < width; ++i) {
|
||||
noise[i] = (uint8_t *)malloc(height * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
// Set starting palette
|
||||
currentPalette = RainbowColors_p;
|
||||
loadPalette(0);
|
||||
NoiseVariablesSetup();
|
||||
|
||||
ClearFrame();
|
||||
}
|
||||
~Effects(){
|
||||
|
||||
~EffectsLayer(){
|
||||
free(leds);
|
||||
for (int i = 0; i < VPANEL_W; ++i) {
|
||||
for (int i = 0; i < width; ++i) {
|
||||
free(noise[i]);
|
||||
}
|
||||
free(noise);
|
||||
|
@ -141,91 +116,78 @@ public:
|
|||
* As such, any time these effects want to write a pixel color, we first have to update
|
||||
* the leds or leds2 array, and THEN write it to the RGB panel. This enables us to 'look up' the array to see what a pixel color was previously, each drawFrame().
|
||||
*/
|
||||
void drawBackgroundFastLEDPixelCRGB(int16_t x, int16_t y, CRGB color)
|
||||
void setPixel(int16_t x, int16_t y, CRGB color)
|
||||
{
|
||||
leds[XY(x, y)] = color;
|
||||
//matrix.drawPixelRGB888(x, y, color.r, color.g, color.b);
|
||||
leds[XY16(x, y)] = color;
|
||||
}
|
||||
|
||||
// write one pixel with the specified color from the current palette to coordinates
|
||||
void Pixel(int x, int y, uint8_t colorIndex) {
|
||||
leds[XY(x, y)] = ColorFromCurrentPalette(colorIndex);
|
||||
//matrix.drawPixelRGB888(x, y, temp.r, temp.g, temp.b); // now draw it?
|
||||
void setPixelFromPaletteIndex(int x, int y, uint8_t colorIndex) {
|
||||
leds[XY16(x, y)] = ColorFromCurrentPalette(colorIndex);
|
||||
}
|
||||
|
||||
void PrepareFrame() {
|
||||
// leds = (CRGB*) backgroundLayer.backBuffer();
|
||||
}
|
||||
void PrepareFrame() { }
|
||||
|
||||
void ShowFrame() {
|
||||
//#if (FASTLED_VERSION >= 3001000)
|
||||
// nblendPaletteTowardPalette(currentPalette, targetPalette, 24);
|
||||
//#else
|
||||
void ShowFrame() { // send to display
|
||||
currentPalette = targetPalette;
|
||||
//#endif
|
||||
|
||||
// backgroundLayer.swapBuffers();
|
||||
// leds = (CRGB*) backgroundLayer.backBuffer();
|
||||
// LEDS.countFPS();
|
||||
|
||||
for (int y=0; y<VPANEL_H; ++y){
|
||||
for (int x=0; x<VPANEL_W; ++x){
|
||||
//Serial.printf("Flushing x, y coord %d, %d\n", x, y);
|
||||
uint16_t _pixel = XY16(x,y);
|
||||
virtualDisp->drawPixelRGB888( x, y, leds[_pixel].r, leds[_pixel].g, leds[_pixel].b);
|
||||
} // end loop to copy fast led to the dma matrix
|
||||
}
|
||||
|
||||
for (int y=0; y<height; ++y){
|
||||
for (int x=0; x<width; ++x){
|
||||
uint16_t _pixel = XY16(x,y);
|
||||
virtualDisp->drawPixelRGB888( x, y, leds[_pixel].r, leds[_pixel].g, leds[_pixel].b);
|
||||
} // end loop to copy fast led to the dma matrix
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getCenterX() {
|
||||
return width / 2;
|
||||
}
|
||||
|
||||
uint16_t getCenterY() {
|
||||
return height / 2;
|
||||
}
|
||||
|
||||
|
||||
// scale the brightness of the screenbuffer down
|
||||
void DimAll(byte value)
|
||||
{
|
||||
for (int i = 0; i < NUM_LEDS; i++)
|
||||
{
|
||||
leds[i].nscale8(value);
|
||||
}
|
||||
void DimAll(byte value) {
|
||||
for (int i = 0; i < num_leds; i++)
|
||||
leds[i].nscale8(value);
|
||||
}
|
||||
|
||||
void ClearFrame()
|
||||
void ClearFrame() {
|
||||
for (int i = 0; i < num_leds; i++)
|
||||
leds[i]= CRGB(0,0,0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint8_t beatcos8(accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0)
|
||||
{
|
||||
memset(leds, 0x00, NUM_LEDS * sizeof(CRGB)); // flush
|
||||
uint8_t beat = beat8(beats_per_minute, timebase);
|
||||
uint8_t beatcos = cos8(beat + phase_offset);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatcos, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint8_t mapsin8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
|
||||
uint8_t beatsin = sin8(theta);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatsin, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t mapcos8(uint8_t theta, uint8_t lowest = 0, uint8_t highest = 255) {
|
||||
uint8_t beatcos = cos8(theta);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8(beatcos, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void CircleStream(uint8_t value) {
|
||||
DimAll(value); ShowFrame();
|
||||
|
||||
for (uint8_t offset = 0; offset < MATRIX_CENTER_X; offset++) {
|
||||
boolean hasprev = false;
|
||||
uint16_t prevxy = 0;
|
||||
|
||||
for (uint8_t theta = 0; theta < 255; theta++) {
|
||||
uint8_t x = mapcos8(theta, offset, (VPANEL_W - 1) - offset);
|
||||
uint8_t y = mapsin8(theta, offset, (VPANEL_H - 1) - offset);
|
||||
|
||||
uint16_t xy = XY(x, y);
|
||||
|
||||
if (hasprev) {
|
||||
leds[prevxy] += leds[xy];
|
||||
}
|
||||
|
||||
prevxy = xy;
|
||||
hasprev = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t x = 0; x < VPANEL_W; x++) {
|
||||
for (uint8_t y = 0; y < VPANEL_H; y++) {
|
||||
uint16_t xy = XY(x, y);
|
||||
leds[xy] = leds2[xy];
|
||||
leds[xy].nscale8(value);
|
||||
leds2[xy].nscale8(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// palettes
|
||||
static const int paletteCount = 10;
|
||||
|
@ -238,11 +200,6 @@ public:
|
|||
static const int HeatColorsPaletteIndex = 6;
|
||||
static const int RandomPaletteIndex = 9;
|
||||
|
||||
void Setup() {
|
||||
currentPalette = RainbowColors_p;
|
||||
loadPalette(0);
|
||||
NoiseVariablesSetup();
|
||||
}
|
||||
|
||||
void CyclePalette(int offset = 1) {
|
||||
loadPalette(paletteIndex + offset);
|
||||
|
@ -394,7 +351,7 @@ public:
|
|||
if (osci[4] % 2 == 0)
|
||||
osci[5] = osci[5] + 1; // .5
|
||||
for (int i = 0; i < 4; i++) {
|
||||
p[i] = map8(sin8(osci[i]), 0, VPANEL_W - 1); //why? to keep the result in the range of 0-VPANEL_W (matrix size)
|
||||
p[i] = map8(sin8(osci[i]), 0, width - 1); //why? to keep the result in the range of 0-VPANEL_W (matrix size)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,11 +361,11 @@ public:
|
|||
|
||||
// rotates the first 16x16 quadrant 3 times onto a 32x32 (+90 degrees rotation for each one)
|
||||
void Caleidoscope1() {
|
||||
for (int x = 0; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < MATRIX_CENTER_Y; y++) {
|
||||
leds[XY16(VPANEL_W - 1 - x, y)] = leds[XY16(x, y)];
|
||||
leds[XY16(VPANEL_W - 1 - x, VPANEL_H - 1 - y)] = leds[XY16(x, y)];
|
||||
leds[XY16(x, VPANEL_H - 1 - y)] = leds[XY16(x, y)];
|
||||
for (int x = 0; x < width / 2; x++) {
|
||||
for (int y = 0; y < height / 2; y++) {
|
||||
leds[XY16(width - 1 - x, y)] = leds[XY16(x, y)];
|
||||
leds[XY16(width - 1 - x, height - 1 - y)] = leds[XY16(x, y)];
|
||||
leds[XY16(x, height - 1 - y)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -416,19 +373,19 @@ public:
|
|||
|
||||
// mirror the first 16x16 quadrant 3 times onto a 32x32
|
||||
void Caleidoscope2() {
|
||||
for (int x = 0; x < MATRIX_CENTER_X; x++) {
|
||||
for (int y = 0; y < MATRIX_CENTER_Y; y++) {
|
||||
leds[XY16(VPANEL_W - 1 - x, y)] = leds[XY16(y, x)];
|
||||
leds[XY16(x, VPANEL_H - 1 - y)] = leds[XY16(y, x)];
|
||||
leds[XY16(VPANEL_W - 1 - x, VPANEL_H - 1 - y)] = leds[XY16(x, y)];
|
||||
for (int x = 0; x < width / 2; x++) {
|
||||
for (int y = 0; y < height / 2; y++) {
|
||||
leds[XY16(width - 1 - x, y)] = leds[XY16(y, x)];
|
||||
leds[XY16(x, height - 1 - y)] = leds[XY16(y, x)];
|
||||
leds[XY16(width - 1 - x, height - 1 - y)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy one diagonal triangle into the other one within a 16x16
|
||||
void Caleidoscope3() {
|
||||
for (int x = 0; x <= MATRIX_CENTRE_X && x < VPANEL_H; x++) {
|
||||
for (int y = 0; y <= x && y<VPANEL_H; y++) {
|
||||
for (int x = 0; x <= width / 2 - 1 && x < height; x++) {
|
||||
for (int y = 0; y <= x && y<height; y++) {
|
||||
leds[XY16(x, y)] = leds[XY16(y, x)];
|
||||
}
|
||||
}
|
||||
|
@ -436,48 +393,48 @@ public:
|
|||
|
||||
// copy one diagonal triangle into the other one within a 16x16 (90 degrees rotated compared to Caleidoscope3)
|
||||
void Caleidoscope4() {
|
||||
for (int x = 0; x <= MATRIX_CENTRE_X; x++) {
|
||||
for (int y = 0; y <= MATRIX_CENTRE_Y - x; y++) {
|
||||
leds[XY16(MATRIX_CENTRE_Y - y, MATRIX_CENTRE_X - x)] = leds[XY16(x, y)];
|
||||
for (int x = 0; x <= width / 2 - 1; x++) {
|
||||
for (int y = 0; y <= height / 2 - 1 - x; y++) {
|
||||
leds[XY16(height / 2 - 1 - y, width / 2 - 1 - x)] = leds[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy one diagonal triangle into the other one within a 8x8
|
||||
void Caleidoscope5() {
|
||||
for (int x = 0; x < VPANEL_W / 4; x++) {
|
||||
for (int y = 0; y <= x && y<=VPANEL_H; y++) {
|
||||
for (int x = 0; x < width / 4; x++) {
|
||||
for (int y = 0; y <= x && y<=height; y++) {
|
||||
leds[XY16(x, y)] = leds[XY16(y, x)];
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = VPANEL_W / 4; x < VPANEL_W / 2; x++) {
|
||||
for (int y = VPANEL_H / 4; y >= 0; y--) {
|
||||
for (int x = width / 4; x < width / 2; x++) {
|
||||
for (int y = height / 4; y >= 0; y--) {
|
||||
leds[XY16(x, y)] = leds[XY16(y, x)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Caleidoscope6() {
|
||||
for (int x = 1; x < MATRIX_CENTER_X; x++) {
|
||||
for (int x = 1; x < width / 2; x++) {
|
||||
leds[XY16(7 - x, 7)] = leds[XY16(x, 0)];
|
||||
} //a
|
||||
for (int x = 2; x < MATRIX_CENTER_X; x++) {
|
||||
for (int x = 2; x < width / 2; x++) {
|
||||
leds[XY16(7 - x, 6)] = leds[XY16(x, 1)];
|
||||
} //b
|
||||
for (int x = 3; x < MATRIX_CENTER_X; x++) {
|
||||
for (int x = 3; x < width / 2; x++) {
|
||||
leds[XY16(7 - x, 5)] = leds[XY16(x, 2)];
|
||||
} //c
|
||||
for (int x = 4; x < MATRIX_CENTER_X; x++) {
|
||||
for (int x = 4; x < width / 2; x++) {
|
||||
leds[XY16(7 - x, 4)] = leds[XY16(x, 3)];
|
||||
} //d
|
||||
for (int x = 5; x < MATRIX_CENTER_X; x++) {
|
||||
for (int x = 5; x < width / 2; x++) {
|
||||
leds[XY16(7 - x, 3)] = leds[XY16(x, 4)];
|
||||
} //e
|
||||
for (int x = 6; x < MATRIX_CENTER_X; x++) {
|
||||
for (int x = 6; x < width / 2; x++) {
|
||||
leds[XY16(7 - x, 2)] = leds[XY16(x, 5)];
|
||||
} //f
|
||||
for (int x = 7; x < MATRIX_CENTER_X; x++) {
|
||||
for (int x = 7; x < width / 2; x++) {
|
||||
leds[XY16(7 - x, 1)] = leds[XY16(x, 6)];
|
||||
} //g
|
||||
}
|
||||
|
@ -566,7 +523,7 @@ public:
|
|||
}
|
||||
|
||||
// give it a linear tail to the right
|
||||
void StreamRight(byte scale, int fromX = 0, int toX = VPANEL_W, int fromY = 0, int toY = VPANEL_H)
|
||||
void StreamRight(byte scale, int fromX = 0, int toX = 0, int fromY = 0, int toY = 0)
|
||||
{
|
||||
for (int x = fromX + 1; x < toX; x++) {
|
||||
for (int y = fromY; y < toY; y++) {
|
||||
|
@ -579,7 +536,7 @@ public:
|
|||
}
|
||||
|
||||
// give it a linear tail to the left
|
||||
void StreamLeft(byte scale, int fromX = VPANEL_W, int toX = 0, int fromY = 0, int toY = VPANEL_H)
|
||||
void StreamLeft(byte scale, int fromX = 0, int toX = 0, int fromY = 0, int toY = 0)
|
||||
{
|
||||
for (int x = toX; x < fromX; x++) {
|
||||
for (int y = fromY; y < toY; y++) {
|
||||
|
@ -594,66 +551,66 @@ public:
|
|||
// give it a linear tail downwards
|
||||
void StreamDown(byte scale)
|
||||
{
|
||||
for (int x = 0; x < VPANEL_W; x++) {
|
||||
for (int y = 1; y < VPANEL_H; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 1; y < height; y++) {
|
||||
leds[XY16(x, y)] += leds[XY16(x, y - 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < VPANEL_W; x++)
|
||||
for (int x = 0; x < width; x++)
|
||||
leds[XY16(x, 0)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail upwards
|
||||
void StreamUp(byte scale)
|
||||
{
|
||||
for (int x = 0; x < VPANEL_W; x++) {
|
||||
for (int y = VPANEL_H - 2; y >= 0; y--) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = height - 2; y >= 0; y--) {
|
||||
leds[XY16(x, y)] += leds[XY16(x, y + 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < VPANEL_W; x++)
|
||||
leds[XY16(x, VPANEL_H - 1)].nscale8(scale);
|
||||
for (int x = 0; x < width; x++)
|
||||
leds[XY16(x, height - 1)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail up and to the left
|
||||
void StreamUpAndLeft(byte scale)
|
||||
{
|
||||
for (int x = 0; x < VPANEL_W - 1; x++) {
|
||||
for (int y = VPANEL_H - 2; y >= 0; y--) {
|
||||
for (int x = 0; x < width - 1; x++) {
|
||||
for (int y = height - 2; y >= 0; y--) {
|
||||
leds[XY16(x, y)] += leds[XY16(x + 1, y + 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < VPANEL_W; x++)
|
||||
leds[XY16(x, VPANEL_H - 1)].nscale8(scale);
|
||||
for (int y = 0; y < VPANEL_H; y++)
|
||||
leds[XY16(VPANEL_W - 1, y)].nscale8(scale);
|
||||
for (int x = 0; x < width; x++)
|
||||
leds[XY16(x, height - 1)].nscale8(scale);
|
||||
for (int y = 0; y < height; y++)
|
||||
leds[XY16(width - 1, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// give it a linear tail up and to the right
|
||||
void StreamUpAndRight(byte scale)
|
||||
{
|
||||
for (int x = 0; x < VPANEL_W - 1; x++) {
|
||||
for (int y = VPANEL_H - 2; y >= 0; y--) {
|
||||
for (int x = 0; x < width - 1; x++) {
|
||||
for (int y = height - 2; y >= 0; y--) {
|
||||
leds[XY16(x + 1, y)] += leds[XY16(x, y + 1)];
|
||||
leds[XY16(x, y)].nscale8(scale);
|
||||
}
|
||||
}
|
||||
// fade the bottom row
|
||||
for (int x = 0; x < VPANEL_W; x++)
|
||||
leds[XY16(x, VPANEL_H - 1)].nscale8(scale);
|
||||
for (int x = 0; x < width; x++)
|
||||
leds[XY16(x, height - 1)].nscale8(scale);
|
||||
|
||||
// fade the right column
|
||||
for (int y = 0; y < VPANEL_H; y++)
|
||||
leds[XY16(VPANEL_W - 1, y)].nscale8(scale);
|
||||
for (int y = 0; y < height; y++)
|
||||
leds[XY16(width - 1, y)].nscale8(scale);
|
||||
}
|
||||
|
||||
// just move everything one line down
|
||||
void MoveDown() {
|
||||
for (int y = VPANEL_H - 1; y > 0; y--) {
|
||||
for (int x = 0; x < VPANEL_W; x++) {
|
||||
for (int y = height - 1; y > 0; y--) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
leds[XY16(x, y)] = leds[XY16(x, y - 1)];
|
||||
}
|
||||
}
|
||||
|
@ -662,7 +619,7 @@ public:
|
|||
// just move everything one line down
|
||||
void VerticalMoveFrom(int start, int end) {
|
||||
for (int y = end; y > start; y--) {
|
||||
for (int x = 0; x < VPANEL_W; x++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
leds[XY16(x, y)] = leds[XY16(x, y - 1)];
|
||||
}
|
||||
}
|
||||
|
@ -680,18 +637,18 @@ public:
|
|||
|
||||
// rotate + copy triangle (MATRIX_CENTER_X*MATRIX_CENTER_X)
|
||||
void RotateTriangle() {
|
||||
for (int x = 1; x < MATRIX_CENTER_X; x++) {
|
||||
for (int x = 1; x < width / 2; x++) {
|
||||
for (int y = 0; y < x; y++) {
|
||||
leds[XY16(x, 7 - y)] = leds[XY16(7 - x, y)];
|
||||
leds[XY16(x, height / 2 - 1 - y)] = leds[XY16(width / 2 - 1 - x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mirror + copy triangle (MATRIX_CENTER_X*MATRIX_CENTER_X)
|
||||
void MirrorTriangle() {
|
||||
for (int x = 1; x < MATRIX_CENTER_X; x++) {
|
||||
for (int x = 1; x < width / 2; x++) {
|
||||
for (int y = 0; y < x; y++) {
|
||||
leds[XY16(7 - y, x)] = leds[XY16(7 - x, y)];
|
||||
leds[XY16(height / 2 - 1 - y, x)] = leds[XY16(width / 2 - 1 - x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -699,9 +656,9 @@ public:
|
|||
// draw static rainbow triangle pattern (MATRIX_CENTER_XxWIDTH / 2)
|
||||
// (just for debugging)
|
||||
void RainbowTriangle() {
|
||||
for (int i = 0; i < MATRIX_CENTER_X; i++) {
|
||||
for (int i = 0; i < width / 2; i++) {
|
||||
for (int j = 0; j <= i; j++) {
|
||||
Pixel(7 - i, j, i * j * 4);
|
||||
setPixelFromPaletteIndex(height / 2 - 1 - i, j, i * j * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -731,13 +688,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// write one pixel with the specified color from the current palette to coordinates
|
||||
/*
|
||||
void Pixel(int x, int y, uint8_t colorIndex) {
|
||||
leds[XY(x, y)] = ColorFromCurrentPalette(colorIndex);
|
||||
matrix.drawBackgroundPixelRGB888(x,y, leds[XY(x, y)]); // now draw it?
|
||||
}
|
||||
*/
|
||||
|
||||
CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) {
|
||||
return ColorFromPalette(currentPalette, index, brightness, currentBlendType);
|
||||
|
@ -761,11 +711,11 @@ public:
|
|||
}
|
||||
|
||||
void FillNoise() {
|
||||
for (uint16_t i = 0; i < VPANEL_W; i++) {
|
||||
uint32_t ioffset = noise_scale_x * (i - MATRIX_CENTRE_Y);
|
||||
for (uint16_t i = 0; i < width; i++) {
|
||||
uint32_t ioffset = noise_scale_x * (i - width / 2);
|
||||
|
||||
for (uint16_t j = 0; j < VPANEL_H; j++) {
|
||||
uint32_t joffset = noise_scale_y * (j - MATRIX_CENTRE_Y);
|
||||
for (uint16_t j = 0; j < height; j++) {
|
||||
uint32_t joffset = noise_scale_y * (j - height / 2);
|
||||
|
||||
byte data = inoise16(noise_x + ioffset, noise_y + joffset, noise_z) >> 8;
|
||||
|
||||
|
@ -784,7 +734,7 @@ public:
|
|||
|
||||
CRGB tmp = 0;
|
||||
|
||||
for (int y = 0; y < VPANEL_H; y++)
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
|
||||
// Shift Left: https://codedost.com/c/arraypointers-in-c/c-program-shift-elements-array-left-direction/
|
||||
|
@ -794,24 +744,24 @@ public:
|
|||
for (int m = 0; m < delta; m++)
|
||||
{
|
||||
// Do this delta time for each row... computationally expensive potentially.
|
||||
for(int x = 0; x < VPANEL_W; x++)
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
leds[XY16(x, y)] = leds [XY16(x+1, y)];
|
||||
}
|
||||
|
||||
leds[XY16(VPANEL_W-1, y)] = tmp;
|
||||
leds[XY16(width-1, y)] = tmp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Shift
|
||||
for (int x = 0; x < VPANEL_W - delta; x++) {
|
||||
leds2[XY(x, y)] = leds[XY(x + delta, y)];
|
||||
leds2[XY16(x, y)] = leds[XY16(x + delta, y)];
|
||||
}
|
||||
|
||||
// Wrap around
|
||||
for (int x = VPANEL_W - delta; x < VPANEL_W; x++) {
|
||||
leds2[XY(x, y)] = leds[XY(x + delta - VPANEL_W, y)];
|
||||
leds2[XY16(x, y)] = leds[XY16(x + delta - VPANEL_W, y)];
|
||||
}
|
||||
*/
|
||||
} // end row loop
|
||||
|
@ -820,7 +770,7 @@ public:
|
|||
// write back to leds
|
||||
for (uint8_t y = 0; y < VPANEL_H; y++) {
|
||||
for (uint8_t x = 0; x < VPANEL_W; x++) {
|
||||
leds[XY(x, y)] = leds2[XY(x, y)];
|
||||
leds[XY16(x, y)] = leds2[XY16(x, y)];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -830,23 +780,38 @@ public:
|
|||
{
|
||||
|
||||
CRGB tmp = 0;
|
||||
for (int x = 0; x < VPANEL_W; x++)
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
tmp = leds[XY16(x, 0)];
|
||||
for (int m = 0; m < delta; m++) // moves
|
||||
{
|
||||
// Do this delta time for each row... computationally expensive potentially.
|
||||
for(int y = 0; y < VPANEL_H; y++)
|
||||
for(int y = 0; y < height; y++)
|
||||
{
|
||||
leds[XY16(x, y)] = leds [XY16(x, y+1)];
|
||||
}
|
||||
|
||||
leds[XY16(x, VPANEL_H-1)] = tmp;
|
||||
leds[XY16(x, height-1)] = tmp;
|
||||
}
|
||||
} // end column loop
|
||||
} /// MoveY
|
||||
|
||||
|
||||
// Override GFX methods
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color) override {
|
||||
setPixel(x, y, CRGB(color));
|
||||
}
|
||||
|
||||
// Override GFX methods
|
||||
void drawPixel(int16_t x, int16_t y, CRGB color) override {
|
||||
setPixel(x, y, color);
|
||||
}
|
||||
|
||||
void fillScreen(uint16_t color) override {
|
||||
ClearFrame();
|
||||
}
|
||||
|
||||
// Add any other GFX methods you want to override
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternAttract_H
|
||||
|
||||
class PatternAttract : public Drawable {
|
||||
private:
|
||||
const int count = 8;
|
||||
Attractor attractor;
|
||||
|
||||
public:
|
||||
PatternAttract() {
|
||||
name = (char *)"Attract";
|
||||
}
|
||||
|
||||
void start() {
|
||||
int direction = random(0, 2);
|
||||
if (direction == 0)
|
||||
direction = -1;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid boid = Boid(15, 31 - i);
|
||||
boid.mass = 1; // random(0.1, 2);
|
||||
boid.velocity.x = ((float) random(40, 50)) / 100.0;
|
||||
boid.velocity.x *= direction;
|
||||
boid.velocity.y = 0;
|
||||
boid.colorIndex = i * 32;
|
||||
boids[i] = boid;
|
||||
//dim = random(170, 250);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// dim all pixels on the display
|
||||
uint8_t dim = beatsin8(2, 170, 250);
|
||||
effects.DimAll(dim);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid boid = boids[i];
|
||||
|
||||
PVector force = attractor.attract(boid);
|
||||
boid.applyForce(force);
|
||||
|
||||
boid.update();
|
||||
effects.drawBackgroundFastLEDPixelCRGB(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex));
|
||||
|
||||
boids[i] = boid;
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
class PatternAttract : public Drawable {
|
||||
private:
|
||||
const int count = 8;
|
||||
const int count = AVAILABLE_BOID_COUNT-1;
|
||||
Attractor attractor;
|
||||
|
||||
public:
|
||||
|
@ -38,7 +38,7 @@ public:
|
|||
direction = -1;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid boid = Boid(15, 31 - i);
|
||||
Boid boid = Boid(VPANEL_W/2, VPANEL_H - i);
|
||||
boid.mass = 1; // random(0.1, 2);
|
||||
boid.velocity.x = ((float) random(40, 50)) / 100.0;
|
||||
boid.velocity.x *= direction;
|
||||
|
@ -61,7 +61,7 @@ public:
|
|||
boid.applyForce(force);
|
||||
|
||||
boid.update();
|
||||
effects.drawBackgroundFastLEDPixelCRGB(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex));
|
||||
effects.setPixel(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex));
|
||||
|
||||
boids[i] = boid;
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternBounce_H
|
||||
|
||||
class PatternBounce : public Drawable {
|
||||
private:
|
||||
static const int count = 32;
|
||||
PVector gravity = PVector(0, 0.0125);
|
||||
|
||||
public:
|
||||
PatternBounce() {
|
||||
name = (char *)"Bounce";
|
||||
}
|
||||
|
||||
void start() {
|
||||
unsigned int colorWidth = 256 / count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid boid = Boid(i, 0);
|
||||
boid.velocity.x = 0;
|
||||
boid.velocity.y = i * -0.01;
|
||||
boid.colorIndex = colorWidth * i;
|
||||
boid.maxforce = 10;
|
||||
boid.maxspeed = 10;
|
||||
boids[i] = boid;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// dim all pixels on the display
|
||||
effects.DimAll(170); effects.ShowFrame();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid boid = boids[i];
|
||||
|
||||
boid.applyForce(gravity);
|
||||
|
||||
boid.update();
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex));
|
||||
|
||||
if (boid.location.y >= MATRIX_HEIGHT - 1) {
|
||||
boid.location.y = MATRIX_HEIGHT - 1;
|
||||
boid.velocity.y *= -1.0;
|
||||
}
|
||||
|
||||
boids[i] = boid;
|
||||
}
|
||||
|
||||
return 15;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
class PatternBounce : public Drawable {
|
||||
private:
|
||||
static const int count = 32;
|
||||
static const int count = VPANEL_W-1;
|
||||
PVector gravity = PVector(0, 0.0125);
|
||||
|
||||
public:
|
||||
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
boid.update();
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex));
|
||||
effects.setPixel(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex));
|
||||
|
||||
if (boid.location.y >= VPANEL_H - 1) {
|
||||
boid.location.y = VPANEL_H - 1;
|
|
@ -1,219 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from Noel Bundy's work: https://github.com/TwystNeko/Object3d
|
||||
* Copyright (c) 2014 Noel Bundy
|
||||
*
|
||||
* Portions of this code are adapted from the Petty library: https://code.google.com/p/peggy/
|
||||
* Copyright (c) 2008 Windell H Oskay. All right reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternCube_H
|
||||
#define PatternCube_H
|
||||
|
||||
class PatternCube : public Drawable {
|
||||
private:
|
||||
float focal = 30; // Focal of the camera
|
||||
int cubeWidth = 28; // Cube size
|
||||
float Angx = 20.0, AngxSpeed = 0.05; // rotation (angle+speed) around X-axis
|
||||
float Angy = 10.0, AngySpeed = 0.05; // rotation (angle+speed) around Y-axis
|
||||
float Ox = 15.5, Oy = 15.5; // position (x,y) of the frame center
|
||||
int zCamera = 110; // distance from cube to the eye of the camera
|
||||
|
||||
// Local vertices
|
||||
Vertex local[8];
|
||||
// Camera aligned vertices
|
||||
Vertex aligned[8];
|
||||
// On-screen projected vertices
|
||||
Point screen[8];
|
||||
// Faces
|
||||
squareFace face[6];
|
||||
// Edges
|
||||
EdgePoint edge[12];
|
||||
int nbEdges;
|
||||
// ModelView matrix
|
||||
float m00, m01, m02, m10, m11, m12, m20, m21, m22;
|
||||
|
||||
// constructs the cube
|
||||
void make(int w)
|
||||
{
|
||||
nbEdges = 0;
|
||||
|
||||
local[0].set(-w, w, w);
|
||||
local[1].set(w, w, w);
|
||||
local[2].set(w, -w, w);
|
||||
local[3].set(-w, -w, w);
|
||||
local[4].set(-w, w, -w);
|
||||
local[5].set(w, w, -w);
|
||||
local[6].set(w, -w, -w);
|
||||
local[7].set(-w, -w, -w);
|
||||
|
||||
face[0].set(1, 0, 3, 2);
|
||||
face[1].set(0, 4, 7, 3);
|
||||
face[2].set(4, 0, 1, 5);
|
||||
face[3].set(4, 5, 6, 7);
|
||||
face[4].set(1, 2, 6, 5);
|
||||
face[5].set(2, 3, 7, 6);
|
||||
|
||||
int f, i;
|
||||
for (f = 0; f < 6; f++)
|
||||
{
|
||||
for (i = 0; i < face[f].length; i++)
|
||||
{
|
||||
face[f].ed[i] = this->findEdge(face[f].sommets[i], face[f].sommets[i ? i - 1 : face[f].length - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finds edges from faces
|
||||
int findEdge(int a, int b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nbEdges; i++)
|
||||
if ((edge[i].x == a && edge[i].y == b) || (edge[i].x == b && edge[i].y == a))
|
||||
return i;
|
||||
edge[nbEdges++].set(a, b);
|
||||
return i;
|
||||
}
|
||||
|
||||
// rotates according to angle x&y
|
||||
void rotate(float angx, float angy)
|
||||
{
|
||||
int i;
|
||||
float cx = cos(angx);
|
||||
float sx = sin(angx);
|
||||
float cy = cos(angy);
|
||||
float sy = sin(angy);
|
||||
|
||||
m00 = cy;
|
||||
m01 = 0;
|
||||
m02 = -sy;
|
||||
m10 = sx * sy;
|
||||
m11 = cx;
|
||||
m12 = sx * cy;
|
||||
m20 = cx * sy;
|
||||
m21 = -sx;
|
||||
m22 = cx * cy;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
aligned[i].x = m00 * local[i].x + m01 * local[i].y + m02 * local[i].z;
|
||||
aligned[i].y = m10 * local[i].x + m11 * local[i].y + m12 * local[i].z;
|
||||
aligned[i].z = m20 * local[i].x + m21 * local[i].y + m22 * local[i].z + zCamera;
|
||||
|
||||
screen[i].x = floor((Ox + focal * aligned[i].x / aligned[i].z));
|
||||
screen[i].y = floor((Oy - focal * aligned[i].y / aligned[i].z));
|
||||
}
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
edge[i].visible = false;
|
||||
|
||||
Point *pa, *pb, *pc;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
pa = screen + face[i].sommets[0];
|
||||
pb = screen + face[i].sommets[1];
|
||||
pc = screen + face[i].sommets[2];
|
||||
|
||||
boolean back = ((pb->x - pa->x) * (pc->y - pa->y) - (pb->y - pa->y) * (pc->x - pa->x)) < 0;
|
||||
if (!back)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
edge[face[i].ed[j]].visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte hue = 0;
|
||||
int step = 0;
|
||||
|
||||
public:
|
||||
PatternCube() {
|
||||
name = (char *)"Cube";
|
||||
make(cubeWidth);
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
uint8_t blurAmount = beatsin8(2, 10, 255);
|
||||
|
||||
#if FASTLED_VERSION >= 3001000
|
||||
blur2d(effects.leds, MATRIX_WIDTH, MATRIX_HEIGHT, blurAmount);
|
||||
#else
|
||||
effects.DimAll(blurAmount); effects.ShowFrame();
|
||||
#endif
|
||||
|
||||
zCamera = beatsin8(2, 100, 140);
|
||||
AngxSpeed = beatsin8(3, 1, 10) / 100.0f;
|
||||
AngySpeed = beatcos8(5, 1, 10) / 100.0f;
|
||||
|
||||
// Update values
|
||||
Angx += AngxSpeed;
|
||||
Angy += AngySpeed;
|
||||
if (Angx >= TWO_PI)
|
||||
Angx -= TWO_PI;
|
||||
if (Angy >= TWO_PI)
|
||||
Angy -= TWO_PI;
|
||||
|
||||
rotate(Angx, Angy);
|
||||
|
||||
// Draw cube
|
||||
int i;
|
||||
|
||||
CRGB color = effects.ColorFromCurrentPalette(hue, 128);
|
||||
|
||||
// Backface
|
||||
EdgePoint *e;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
e = edge + i;
|
||||
if (!e->visible) {
|
||||
dma_display->drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color);
|
||||
}
|
||||
}
|
||||
|
||||
color = effects.ColorFromCurrentPalette(hue, 255);
|
||||
|
||||
// Frontface
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
e = edge + i;
|
||||
if (e->visible)
|
||||
{
|
||||
dma_display->drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color);
|
||||
}
|
||||
}
|
||||
|
||||
step++;
|
||||
if (step == 8) {
|
||||
step = 0;
|
||||
hue++;
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 20;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -35,7 +35,7 @@ class PatternCube : public Drawable {
|
|||
int cubeWidth = 28; // Cube size
|
||||
float Angx = 20.0, AngxSpeed = 0.05; // rotation (angle+speed) around X-axis
|
||||
float Angy = 10.0, AngySpeed = 0.05; // rotation (angle+speed) around Y-axis
|
||||
float Ox = 15.5, Oy = 15.5; // position (x,y) of the frame center
|
||||
float Ox = VPANEL_W/2, Oy = VPANEL_H/2; // position (x,y) of the frame center
|
||||
int zCamera = 110; // distance from cube to the eye of the camera
|
||||
|
||||
// Local vertices
|
||||
|
@ -151,11 +151,11 @@ class PatternCube : public Drawable {
|
|||
public:
|
||||
PatternCube() {
|
||||
name = (char *)"Cube";
|
||||
make(cubeWidth);
|
||||
make(VPANEL_W);
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
uint8_t blurAmount = beatsin8(2, 10, 255);
|
||||
uint8_t blurAmount = beatsin8(2, 10, 128);
|
||||
|
||||
#if FASTLED_VERSION >= 3001000
|
||||
blur2d(effects.leds, VPANEL_W, VPANEL_H, blurAmount);
|
||||
|
@ -164,8 +164,8 @@ class PatternCube : public Drawable {
|
|||
#endif
|
||||
|
||||
zCamera = beatsin8(2, 100, 140);
|
||||
AngxSpeed = beatsin8(3, 1, 10) / 100.0f;
|
||||
AngySpeed = beatcos8(5, 1, 10) / 100.0f;
|
||||
AngxSpeed = beatsin8(3, 1, 6) / 100.0f;
|
||||
AngySpeed = effects.beatcos8(5, 1, 6) / 100.0f;
|
||||
|
||||
// Update values
|
||||
Angx += AngxSpeed;
|
||||
|
@ -188,7 +188,7 @@ class PatternCube : public Drawable {
|
|||
{
|
||||
e = edge + i;
|
||||
if (!e->visible) {
|
||||
matrix.drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color);
|
||||
effects.drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ class PatternCube : public Drawable {
|
|||
e = edge + i;
|
||||
if (e->visible)
|
||||
{
|
||||
matrix.drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color);
|
||||
effects.drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Funky Noise" by Stefan Petrick: https://github.com/StefanPetrick/FunkyNoise
|
||||
* Copyright (c) 2014 Stefan Petrick
|
||||
* http://www.stefan-petrick.de/wordpress_beta
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternElectricMandala_H
|
||||
|
||||
class PatternElectricMandala : public Drawable {
|
||||
private:
|
||||
|
||||
// The coordinates for 16-bit noise spaces.
|
||||
#define NUM_LAYERS 1
|
||||
|
||||
// used for the random based animations
|
||||
int16_t dx;
|
||||
int16_t dy;
|
||||
int16_t dz;
|
||||
int16_t dsx;
|
||||
int16_t dsy;
|
||||
|
||||
public:
|
||||
PatternElectricMandala() {
|
||||
name = (char *)"ElectricMandala";
|
||||
}
|
||||
|
||||
void start() {
|
||||
// set to reasonable values to avoid a black out
|
||||
noisesmoothing = 200;
|
||||
|
||||
// just any free input pin
|
||||
//random16_add_entropy(analogRead(18));
|
||||
|
||||
// fill coordinates with random values
|
||||
// set zoom levels
|
||||
noise_x = random16();
|
||||
noise_y = random16();
|
||||
noise_z = random16();
|
||||
noise_scale_x = 6000;
|
||||
noise_scale_y = 6000;
|
||||
|
||||
// for the random movement
|
||||
dx = random8();
|
||||
dy = random8();
|
||||
dz = random8();
|
||||
dsx = random8();
|
||||
dsy = random8();
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
#if FASTLED_VERSION >= 3001000
|
||||
// a new parameter set every 15 seconds
|
||||
EVERY_N_SECONDS(15) {
|
||||
//SetupRandomPalette3();
|
||||
dy = random16(500) - 250; // random16(2000) - 1000 is pretty fast but works fine, too
|
||||
dx = random16(500) - 250;
|
||||
dz = random16(500) - 250;
|
||||
noise_scale_x = random16(10000) + 2000;
|
||||
noise_scale_y = random16(10000) + 2000;
|
||||
}
|
||||
#endif
|
||||
|
||||
noise_y += dy;
|
||||
noise_x += dx;
|
||||
noise_z += dz;
|
||||
|
||||
effects.FillNoise();
|
||||
ShowNoiseLayer(0, 1, 0);
|
||||
|
||||
effects.Caleidoscope3();
|
||||
effects.Caleidoscope1();
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 30;
|
||||
}
|
||||
|
||||
// show just one layer
|
||||
void ShowNoiseLayer(byte layer, byte colorrepeat, byte colorshift) {
|
||||
for (uint16_t i = 0; i < MATRIX_WIDTH; i++) {
|
||||
for (uint16_t j = 0; j < MATRIX_HEIGHT; j++) {
|
||||
|
||||
uint8_t color = noise[i][j];
|
||||
|
||||
uint8_t bri = color;
|
||||
|
||||
// assign a color depending on the actual palette
|
||||
CRGB pixel = ColorFromPalette(effects.currentPalette, colorrepeat * (color + colorshift), bri);
|
||||
|
||||
effects.leds[XY16(i, j)] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -39,6 +39,9 @@ class PatternElectricMandala : public Drawable {
|
|||
int16_t dsx;
|
||||
int16_t dsy;
|
||||
|
||||
|
||||
unsigned int last_parameter_change_ms = 0;
|
||||
|
||||
public:
|
||||
PatternElectricMandala() {
|
||||
name = (char *)"ElectricMandala";
|
||||
|
@ -46,18 +49,18 @@ class PatternElectricMandala : public Drawable {
|
|||
|
||||
void start() {
|
||||
// set to reasonable values to avoid a black out
|
||||
noisesmoothing = 200;
|
||||
effects.noisesmoothing = 200;
|
||||
|
||||
// just any free input pin
|
||||
//random16_add_entropy(analogRead(18));
|
||||
|
||||
// fill coordinates with random values
|
||||
// set zoom levels
|
||||
noise_x = random16();
|
||||
noise_y = random16();
|
||||
noise_z = random16();
|
||||
noise_scale_x = 6000;
|
||||
noise_scale_y = 6000;
|
||||
effects.noise_x = random16();
|
||||
effects.noise_y = random16();
|
||||
effects.noise_z = random16();
|
||||
effects.noise_scale_x = 6000;
|
||||
effects.noise_scale_y = 6000;
|
||||
|
||||
// for the random movement
|
||||
dx = random8();
|
||||
|
@ -70,19 +73,20 @@ class PatternElectricMandala : public Drawable {
|
|||
unsigned int drawFrame() {
|
||||
#if FASTLED_VERSION >= 3001000
|
||||
// a new parameter set every 15 seconds
|
||||
EVERY_N_SECONDS(15) {
|
||||
if(millis() - last_parameter_change_ms > 15000) {
|
||||
last_parameter_change_ms = millis();
|
||||
//SetupRandomPalette3();
|
||||
dy = random16(500) - 250; // random16(2000) - 1000 is pretty fast but works fine, too
|
||||
dx = random16(500) - 250;
|
||||
dz = random16(500) - 250;
|
||||
noise_scale_x = random16(10000) + 2000;
|
||||
noise_scale_y = random16(10000) + 2000;
|
||||
effects.noise_scale_x = random16(10000) + 2000;
|
||||
effects.noise_scale_y = random16(10000) + 2000;
|
||||
}
|
||||
#endif
|
||||
|
||||
noise_y += dy;
|
||||
noise_x += dx;
|
||||
noise_z += dz;
|
||||
effects.noise_y += dy;
|
||||
effects.noise_x += dx;
|
||||
effects.noise_z += dz;
|
||||
|
||||
effects.FillNoise();
|
||||
ShowNoiseLayer(0, 1, 0);
|
||||
|
@ -100,7 +104,7 @@ class PatternElectricMandala : public Drawable {
|
|||
for (uint16_t i = 0; i < VPANEL_W; i++) {
|
||||
for (uint16_t j = 0; j < VPANEL_H; j++) {
|
||||
|
||||
uint8_t color = noise[i][j];
|
||||
uint8_t color = effects.noise[i][j];
|
||||
|
||||
uint8_t bri = color;
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from FastLED Fire2012 example by Mark Kriegsman: https://github.com/FastLED/FastLED/tree/master/examples/Fire2012WithPalette
|
||||
* Copyright (c) 2013 FastLED
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternFire_H
|
||||
#define PatternFire_H
|
||||
|
||||
#ifndef Effects_H
|
||||
#include "Effects.h"
|
||||
#endif
|
||||
|
||||
class PatternFire : public Drawable {
|
||||
private:
|
||||
|
||||
public:
|
||||
PatternFire() {
|
||||
name = (char *)"Fire";
|
||||
}
|
||||
|
||||
// There are two main parameters you can play with to control the look and
|
||||
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
|
||||
// in step 3 above).
|
||||
//
|
||||
// cooling: How much does the air cool as it rises?
|
||||
// Less cooling = taller flames. More cooling = shorter flames.
|
||||
// Default 55, suggested range 20-100
|
||||
int cooling = 100;
|
||||
|
||||
// sparking: What chance (out of 255) is there that a new spark will be lit?
|
||||
// Higher chance = more roaring fire. Lower chance = more flickery fire.
|
||||
// Default 120, suggested range 50-200.
|
||||
unsigned int sparking = 100;
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// Add entropy to random number generator; we use a lot of it.
|
||||
random16_add_entropy( random16());
|
||||
|
||||
effects.DimAll(235);
|
||||
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
// Step 1. Cool down every cell a little
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
int xy = XY(x, y);
|
||||
heat[xy] = qsub8(heat[xy], random8(0, ((cooling * 10) / MATRIX_HEIGHT) + 2));
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
heat[XY(x, y)] = (heat[XY(x, y + 1)] + heat[XY(x, y + 2)] + heat[XY(x, y + 2)]) / 3;
|
||||
}
|
||||
|
||||
// Step 2. Randomly ignite new 'sparks' of heat
|
||||
if (random8() < sparking) {
|
||||
// int x = (p[0] + p[1] + p[2]) / 3;
|
||||
|
||||
int xy = XY(x, MATRIX_HEIGHT - 1);
|
||||
heat[xy] = qadd8(heat[xy], random8(160, 255));
|
||||
}
|
||||
|
||||
// Step 4. Map from heat cells to LED colors
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
int xy = XY(x, y);
|
||||
byte colorIndex = heat[xy];
|
||||
|
||||
// Recommend that you use values 0-240 rather than
|
||||
// the usual 0-255, as the last 15 colors will be
|
||||
// 'wrapping around' from the hot end to the cold end,
|
||||
// which looks wrong.
|
||||
colorIndex = scale8(colorIndex, 200);
|
||||
|
||||
// override color 0 to ensure a black background?
|
||||
if (colorIndex != 0)
|
||||
// effects.leds[xy] = CRGB::Black;
|
||||
// else
|
||||
effects.leds[xy] = effects.ColorFromCurrentPalette(colorIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(2);
|
||||
effects.MoveFractionalNoiseX(2);
|
||||
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 15;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,3 +1,117 @@
|
|||
/*
|
||||
Aurora: https://github.com/pixelmatix/aurora
|
||||
Copyright (c) 2014 Jason Coon
|
||||
|
||||
Added by @Kosso. Cobbled together from various places which I can't remember. I'll update this when I track it down.
|
||||
Requires PaletteFireKoz.h
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternFireKoz_H
|
||||
#define PatternFireKoz_H
|
||||
|
||||
const uint8_t PROGMEM palette_fire[] = {/* RGB888 R,G,B,R,G,B,R,G,B,... */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x05,0x00,0x00,0x0a,0x00,0x00,0x10,0x00,0x00,0x15,0x00,0x00,0x1b,0x00,0x00,0x20,0x00,0x00,0x25,0x00,0x00,0x2b,0x00,0x00,0x31,0x00,0x00,0x36,0x00,0x00,0x3c,0x00,0x00,0x41,0x00,0x00,0x46,0x00,0x00,0x4c,0x00,0x00,0x52,0x00,0x00,0x57,0x00,0x00,0x5d,0x00,0x00,0x62,0x00,0x00,0x68,0x00,0x00,0x6d,0x00,0x00,0x73,0x00,0x00,0x79,0x00,0x00,0x7e,0x00,0x00,0x83,0x00,0x00,0x89,0x00,0x00,0x8e,0x00,0x00,0x94,0x00,0x00,0x9a,0x00,0x00,0x9f,0x00,0x00,0xa5,0x00,0x00,0xaa,0x00,0x00,0xb0,0x00,0x00,0xb5,0x00,0x00,0xbb,0x00,0x00,0xc0,0x00,0x00,0xc6,0x00,0x00,0xcb,0x00,0x00,0xd1,0x00,0x00,0xd7,0x00,0x00,0xdc,0x00,0x00,0xe1,0x00,0x00,0xe6,0x00,0x00,0xe8,0x02,0x00,0xe9,0x08,0x00,0xe9,0x0f,0x00,0xe9,0x13,0x00,0xe9,0x16,0x00,0xe9,0x1b,0x00,0xe9,0x21,0x00,0xe9,0x26,0x00,0xe9,0x2a,0x00,0xe9,0x2e,0x00,0xe9,0x32,0x00,0xe9,0x37,0x00,0xe9,0x3b,0x00,0xe9,0x3f,0x00,0xe9,0x44,0x00,0xe9,0x4a,0x00,0xe9,0x4e,0x00,0xe9,0x52,0x00,0xe9,0x56,0x00,0xe9,0x5a,0x00,0xe9,0x5d,0x00,0xe9,0x63,0x00,0xe9,0x67,0x00,0xe9,0x6b,0x00,0xe9,0x71,0x00,0xe9,0x77,0x00,0xe9,0x78,0x00,0xe9,0x7c,0x00,0xe9,0x81,0x00,0xe9,0x86,0x00,0xe9,0x8b,0x00,0xe9,0x8f,0x00,0xe9,0x93,0x00,0xe9,0x99,0x00,0xe9,0x9d,0x00,0xe9,0xa0,0x00,0xe9,0xa4,0x00,0xe9,0xaa,0x00,0xe9,0xb0,0x00,0xe9,0xb4,0x00,0xe9,0xb5,0x00,0xe9,0xb9,0x00,0xe9,0xbe,0x00,0xe9,0xc3,0x00,0xe9,0xc9,0x00,0xe9,0xce,0x00,0xe9,0xd2,0x00,0xe9,0xd6,0x00,0xe9,0xd9,0x00,0xe9,0xdd,0x00,0xe9,0xe2,0x00,0xe9,0xe7,0x02,0xe9,0xe9,0x0e,0xe9,0xe9,0x1c,0xe9,0xe9,0x28,0xe9,0xe9,0x38,0xe9,0xe9,0x48,0xe9,0xe9,0x57,0xe9,0xe9,0x67,0xe9,0xe9,0x73,0xe9,0xe9,0x81,0xe9,0xe9,0x90,0xe9,0xe9,0xa1,0xe9,0xe9,0xb1,0xe9,0xe9,0xbf,0xe9,0xe9,0xcb,0xe9,0xe9,0xcb,0xe9,0xe9,0xcd,0xe9,0xe9,0xd9,0xe9,0xe9,0xe5,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe6,0xe6,0xe6,0xe4,0xe4,0xe4,0xe3,0xe3,0xe3,0xe0,0xe0,0xe0,0xdc,0xdc,0xdc,0xd8,0xd8,0xd8,0xd2,0xd2,0xd2,0xca,0xca,0xca,0xc1,0xc1,0xc1,0xb7,0xb7,0xb7,0xab,0xab,0xab,0x9d,0x9d,0x9d,0x8f,0x8f,0x8f,0x81,0x81,0x81,0x72,0x72,0x72,0x64,0x64,0x64,0x56,0x56,0x56,0x4a,0x4a,0x4a,0x3e,0x3e,0x3e,0x33,0x33,0x33,0x2a,0x2a,0x2a,0x22,0x22,0x22,0x1b,0x1b,0x1b,0x16,0x16,0x16,0x11,0x11,0x11,0x0d,0x0d,0x0d,0x0b,0x0b,0x0b,0x08,0x08,0x08,0x07,0x07,0x07,0x06,0x06,0x06,0x05,0x05,0x05,0x04,0x04,0x04,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x02,0x02,0x02,0x02,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
|
||||
class PatternFireKoz : public Drawable {
|
||||
private:
|
||||
|
||||
const int FIRE_HEIGHT = 800;
|
||||
|
||||
int Bit = 0, NBit = 1;
|
||||
float fire_c;
|
||||
// might not need this buffer here... there some led buffers set up in EffectsLayer.h
|
||||
uint8_t fireBuffer[VPANEL_W][VPANEL_H][2];
|
||||
|
||||
public:
|
||||
PatternFireKoz() {
|
||||
name = (char *)"FireKoz";
|
||||
}
|
||||
|
||||
void start(){
|
||||
effects.ClearFrame();
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
for (int x = 1; x < VPANEL_W - 1; x++)
|
||||
{
|
||||
fireBuffer[x][VPANEL_H - 2][Bit] = random(0, FIRE_HEIGHT);
|
||||
if (random(0, 100) > 80)
|
||||
{
|
||||
fireBuffer[x][VPANEL_H - 2][Bit] = 0;
|
||||
fireBuffer[x][VPANEL_H - 3][Bit] = 0;
|
||||
}
|
||||
}
|
||||
for (int y = 1; y < VPANEL_H - 1; y++)
|
||||
{
|
||||
for (int x = 1; x < VPANEL_W - 1; x++)
|
||||
{
|
||||
fire_c = (fireBuffer[x - 1][y][Bit] +
|
||||
fireBuffer[x + 1][y][Bit] +
|
||||
fireBuffer[x][y - 1][Bit] +
|
||||
fireBuffer[x][y + 1][Bit] +
|
||||
fireBuffer[x][y][Bit]) /
|
||||
5.0;
|
||||
|
||||
fire_c = (fireBuffer[x - 1][y][Bit] +
|
||||
fireBuffer[x + 1][y][Bit] +
|
||||
fireBuffer[x][y - 1][Bit] +
|
||||
fireBuffer[x][y + 1][Bit] +
|
||||
fireBuffer[x][y][Bit]) /
|
||||
5.0;
|
||||
|
||||
if (fire_c > (FIRE_HEIGHT / 2) && fire_c < FIRE_HEIGHT) {
|
||||
fire_c -= 0.2;
|
||||
} else if (fire_c > (FIRE_HEIGHT / 4) && fire_c < (FIRE_HEIGHT / 2)) {
|
||||
fire_c -= 0.4;
|
||||
} else if (fire_c <= (FIRE_HEIGHT / 8)) {
|
||||
fire_c -= 0.7;
|
||||
} else {
|
||||
fire_c -= 1;
|
||||
}
|
||||
if (fire_c < 0)
|
||||
fire_c = 0;
|
||||
if (fire_c >= FIRE_HEIGHT + 1)
|
||||
fire_c = FIRE_HEIGHT - 1;
|
||||
fireBuffer[x][y - 1][NBit] = fire_c;
|
||||
int index = (int)fire_c * 3;
|
||||
if (fire_c == 0)
|
||||
{
|
||||
effects.setPixel(x, y, CRGB(0, 0, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
effects.setPixel(x, y, CRGB(palette_fire[index], palette_fire[index + 1], palette_fire[index + 2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
//display.drawRect(0, 0, VPANEL_W, VPANEL_H, display.color565(25, 25, 25));
|
||||
|
||||
NBit = Bit;
|
||||
Bit = 1 - Bit;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 30; // no idea what this is for...
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
235
examples/AuroraDemo/PatternFireworks.hpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
#ifndef FireWork_H
|
||||
#define FireWork_H
|
||||
|
||||
/****************************************************************
|
||||
* Fireworks Class
|
||||
****************************************************************/
|
||||
// Ripped from: https://github.com/lmirel/MorphingClockRemix
|
||||
|
||||
const int FIREWORKS = 4; // Number of fireworks
|
||||
const int FIREWORK_PARTICLES = 32; // Number of particles per firework
|
||||
|
||||
const float GRAVITY = 0.03f;
|
||||
const float baselineSpeed = -1.2f;
|
||||
const float maxSpeed = -2.0f;
|
||||
|
||||
class Firework
|
||||
{
|
||||
public:
|
||||
float x[FIREWORK_PARTICLES];
|
||||
float y[FIREWORK_PARTICLES];
|
||||
char lx[FIREWORK_PARTICLES], ly[FIREWORK_PARTICLES];
|
||||
float xSpeed[FIREWORK_PARTICLES];
|
||||
float ySpeed[FIREWORK_PARTICLES];
|
||||
|
||||
char red;
|
||||
char blue;
|
||||
char green;
|
||||
char alpha;
|
||||
|
||||
int framesUntilLaunch;
|
||||
|
||||
char particleSize;
|
||||
bool hasExploded;
|
||||
|
||||
Firework(); // Constructor declaration
|
||||
void initialise();
|
||||
void move();
|
||||
void explode();
|
||||
};
|
||||
|
||||
// Constructor implementation
|
||||
Firework::Firework()
|
||||
{
|
||||
initialise();
|
||||
for (int loop = 0; loop < FIREWORK_PARTICLES; loop++)
|
||||
{
|
||||
lx[loop] = 0;
|
||||
ly[loop] = VPANEL_H + 1; // Push the particle location down off the bottom of the screen
|
||||
}
|
||||
}
|
||||
|
||||
void Firework::initialise()
|
||||
{
|
||||
// Pick an initial x location and random x/y speeds
|
||||
float xLoc = (rand() % VPANEL_W);
|
||||
float xSpeedVal = baselineSpeed + (rand() % (int)maxSpeed);
|
||||
float ySpeedVal = baselineSpeed + (rand() % (int)maxSpeed);
|
||||
|
||||
// Set initial x/y location and speeds
|
||||
for (int loop = 0; loop < FIREWORK_PARTICLES; loop++)
|
||||
{
|
||||
x[loop] = xLoc;
|
||||
y[loop] = VPANEL_H + 1; // Push the particle location down off the bottom of the screen
|
||||
xSpeed[loop] = xSpeedVal;
|
||||
ySpeed[loop] = ySpeedVal;
|
||||
//don't reset these otherwise particles won't be removed
|
||||
//lx[loop] = 0;
|
||||
//ly[loop] = LAYER_HEIGHT + 1; // Push the particle location down off the bottom of the screen
|
||||
}
|
||||
|
||||
// Assign a random colour and full alpha (i.e. particle is completely opaque)
|
||||
red = (rand() % 255);/// (float)RAND_MAX);
|
||||
green = (rand() % 255); /// (float)RAND_MAX);
|
||||
blue = (rand() % 255); /// (float)RAND_MAX);
|
||||
alpha = 50;//max particle frames
|
||||
|
||||
// Firework will launch after a random amount of frames between 0 and 400
|
||||
framesUntilLaunch = ((int)rand() % (VPANEL_H));
|
||||
|
||||
// Size of the particle (as thrown to glPointSize) - range is 1.0f to 4.0f
|
||||
particleSize = 1.0f + ((float)rand() / (float)RAND_MAX) * 3.0f;
|
||||
|
||||
// Flag to keep trackof whether the firework has exploded or not
|
||||
hasExploded = false;
|
||||
|
||||
//cout << "Initialised a firework." << endl;
|
||||
}
|
||||
|
||||
void Firework::move()
|
||||
{
|
||||
for (int loop = 0; loop < FIREWORK_PARTICLES; loop++)
|
||||
{
|
||||
// Once the firework is ready to launch start moving the particles
|
||||
if (framesUntilLaunch <= 0)
|
||||
{
|
||||
//draw black on last known position
|
||||
//tl->drawPixel (x[loop], y[loop], cc_blk);
|
||||
lx[loop] = x[loop];
|
||||
ly[loop] = y[loop];
|
||||
//
|
||||
x[loop] += xSpeed[loop];
|
||||
|
||||
y[loop] += ySpeed[loop];
|
||||
|
||||
ySpeed[loop] += GRAVITY;
|
||||
}
|
||||
}
|
||||
framesUntilLaunch--;
|
||||
|
||||
// Once a fireworks speed turns positive (i.e. at top of arc) - blow it up!
|
||||
if (ySpeed[0] > 0.0f)
|
||||
{
|
||||
for (int loop2 = 0; loop2 < FIREWORK_PARTICLES; loop2++)
|
||||
{
|
||||
// Set a random x and y speed beteen -4 and + 4
|
||||
xSpeed[loop2] = -2 + (rand() / (float)RAND_MAX) * 4;
|
||||
ySpeed[loop2] = -2 + (rand() / (float)RAND_MAX) * 4;
|
||||
}
|
||||
|
||||
//cout << "Boom!" << endl;
|
||||
hasExploded = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Firework::explode()
|
||||
{
|
||||
for (int loop = 0; loop < FIREWORK_PARTICLES; loop++)
|
||||
{
|
||||
// Dampen the horizontal speed by 1% per frame
|
||||
xSpeed[loop] *= 0.99;
|
||||
|
||||
//draw black on last known position (NO LONGER USED tl->dim used instead)
|
||||
//tl->drawPixel (x[loop], y[loop], cc_blk);
|
||||
lx[loop] = x[loop];
|
||||
ly[loop] = y[loop];
|
||||
//
|
||||
// Move the particle
|
||||
x[loop] += xSpeed[loop];
|
||||
y[loop] += ySpeed[loop];
|
||||
|
||||
// Apply gravity to the particle's speed
|
||||
ySpeed[loop] += GRAVITY;
|
||||
}
|
||||
|
||||
// Fade out the particles (alpha is stored per firework, not per particle)
|
||||
if (alpha > 0)
|
||||
{
|
||||
alpha -= 1;
|
||||
}
|
||||
else // Once the alpha hits zero reset the firework
|
||||
{
|
||||
initialise();
|
||||
}
|
||||
}
|
||||
|
||||
/*********************** */
|
||||
|
||||
|
||||
|
||||
class PatternFirework : public Drawable {
|
||||
|
||||
public:
|
||||
PatternFirework() {
|
||||
name = (char *)"PatternFirework";
|
||||
|
||||
}
|
||||
|
||||
void start();
|
||||
unsigned int drawFrame();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
// Create our array of fireworks
|
||||
Firework fw[FIREWORKS];
|
||||
|
||||
};
|
||||
|
||||
|
||||
void PatternFirework::start() { }
|
||||
|
||||
void PatternFirework::stop() { }
|
||||
|
||||
unsigned int PatternFirework::drawFrame()
|
||||
{
|
||||
|
||||
effects.DimAll(250);
|
||||
|
||||
CRGB cc_frw;
|
||||
//display.fillScreen (0);
|
||||
// Draw fireworks
|
||||
//cout << "Firework count is: " << Firework::fireworkCount << endl;
|
||||
for (int loop = 0; loop < FIREWORKS; loop++)
|
||||
{
|
||||
for (int particleLoop = 0; particleLoop < FIREWORK_PARTICLES; particleLoop++)
|
||||
{
|
||||
|
||||
// Set colour to yellow on way up, then whatever colour firework should be when exploded
|
||||
if (fw[loop].hasExploded == false)
|
||||
{
|
||||
//glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
cc_frw = CRGB (255, 255, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
//glColor4f(fw[loop].red, fw[loop].green, fw[loop].blue, fw[loop].alpha);
|
||||
//glVertex2f(fw[loop].x[particleLoop], fw[loop].y[particleLoop]);
|
||||
cc_frw = CRGB (fw[loop].red, fw[loop].green, fw[loop].blue);
|
||||
}
|
||||
|
||||
// Draw the point
|
||||
//glVertex2f(fw[loop].x[particleLoop], fw[loop].y[particleLoop]);
|
||||
effects.setPixel (fw[loop].x[particleLoop], fw[loop].y[particleLoop], cc_frw);
|
||||
// effects.setPixel (fw[loop].lx[particleLoop], fw[loop].ly[particleLoop], 0);
|
||||
}
|
||||
// Move the firework appropriately depending on its explosion state
|
||||
if (fw[loop].hasExploded == false)
|
||||
{
|
||||
fw[loop].move();
|
||||
}
|
||||
else
|
||||
{
|
||||
fw[loop].explode();
|
||||
}
|
||||
//
|
||||
//delay (10);
|
||||
} // end loop
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 20;
|
||||
|
||||
} // end drawframe
|
||||
|
||||
|
||||
#endif
|
|
@ -36,12 +36,17 @@
|
|||
#define PatternFlock_H
|
||||
|
||||
class PatternFlock : public Drawable {
|
||||
|
||||
private:
|
||||
unsigned long last_update_hue_ms = 0;
|
||||
unsigned long last_update_predator_ms = 0;
|
||||
|
||||
public:
|
||||
PatternFlock() {
|
||||
name = (char *)"Flock";
|
||||
}
|
||||
|
||||
static const int boidCount = 10;
|
||||
static const int boidCount = VPANEL_W-1;
|
||||
Boid predator;
|
||||
|
||||
PVector wind;
|
||||
|
@ -90,8 +95,8 @@ class PatternFlock : public Drawable {
|
|||
PVector location = boid->location;
|
||||
// PVector velocity = boid->velocity;
|
||||
// backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color);
|
||||
// effects.leds[XY(location.x, location.y)] += color;
|
||||
effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color);
|
||||
// effects.leds[XY16(location.x, location.y)] += color;
|
||||
effects.setPixel(location.x, location.y, color);
|
||||
|
||||
if (applyWind) {
|
||||
boid->applyForce(wind);
|
||||
|
@ -106,15 +111,17 @@ class PatternFlock : public Drawable {
|
|||
PVector location = predator.location;
|
||||
// PVector velocity = predator.velocity;
|
||||
// backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color);
|
||||
// effects.leds[XY(location.x, location.y)] += color;
|
||||
effects.drawBackgroundFastLEDPixelCRGB(location.x, location.y, color);
|
||||
// effects.leds[XY16(location.x, location.y)] += color;
|
||||
effects.setPixel(location.x, location.y, color);
|
||||
}
|
||||
|
||||
EVERY_N_MILLIS(200) {
|
||||
if (millis() - last_update_hue_ms > 200) {
|
||||
last_update_hue_ms = millis();
|
||||
hue++;
|
||||
}
|
||||
|
||||
EVERY_N_SECONDS(30) {
|
||||
if (millis() - last_update_predator_ms > 30000) {
|
||||
last_update_predator_ms = millis();
|
||||
predatorPresent = !predatorPresent;
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternFlowField_H
|
||||
|
||||
class PatternFlowField : public Drawable {
|
||||
public:
|
||||
PatternFlowField() {
|
||||
name = (char *)"FlowField";
|
||||
}
|
||||
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t z;
|
||||
|
||||
uint16_t speed = 1;
|
||||
uint16_t scale = 26;
|
||||
|
||||
static const int count = 40;
|
||||
|
||||
byte hue = 0;
|
||||
|
||||
void start() {
|
||||
x = random16();
|
||||
y = random16();
|
||||
z = random16();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
boids[i] = Boid(random(MATRIX_WIDTH), 0);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(240);
|
||||
|
||||
// CRGB color = effects.ColorFromCurrentPalette(hue);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Boid * boid = &boids[i];
|
||||
|
||||
int ioffset = scale * boid->location.x;
|
||||
int joffset = scale * boid->location.y;
|
||||
|
||||
byte angle = inoise8(x + ioffset, y + joffset, z);
|
||||
|
||||
boid->velocity.x = (float) sin8(angle) * 0.0078125 - 1.0;
|
||||
boid->velocity.y = -((float)cos8(angle) * 0.0078125 - 1.0);
|
||||
boid->update();
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(boid->location.x, boid->location.y, effects.ColorFromCurrentPalette(angle + hue)); // color
|
||||
|
||||
if (boid->location.x < 0 || boid->location.x >= MATRIX_WIDTH ||
|
||||
boid->location.y < 0 || boid->location.y >= MATRIX_HEIGHT) {
|
||||
boid->location.x = random(MATRIX_WIDTH);
|
||||
boid->location.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
EVERY_N_MILLIS(200) {
|
||||
hue++;
|
||||
}
|
||||
|
||||
x += speed;
|
||||
y += speed;
|
||||
z += speed;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 50;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -37,6 +37,7 @@ class PatternFlowField : public Drawable {
|
|||
|
||||
static const int count = 40;
|
||||
|
||||
unsigned long last_update_hue_ms = 0;
|
||||
byte hue = 0;
|
||||
|
||||
void start() {
|
||||
|
@ -66,7 +67,7 @@ class PatternFlowField : public Drawable {
|
|||
boid->velocity.y = -((float)cos8(angle) * 0.0078125 - 1.0);
|
||||
boid->update();
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(boid->location.x, boid->location.y, effects.ColorFromCurrentPalette(angle + hue)); // color
|
||||
effects.setPixel(boid->location.x, boid->location.y, effects.ColorFromCurrentPalette(angle + hue)); // color
|
||||
|
||||
if (boid->location.x < 0 || boid->location.x >= VPANEL_W ||
|
||||
boid->location.y < 0 || boid->location.y >= VPANEL_H) {
|
||||
|
@ -75,7 +76,8 @@ class PatternFlowField : public Drawable {
|
|||
}
|
||||
}
|
||||
|
||||
EVERY_N_MILLIS(200) {
|
||||
if (millis() - last_update_hue_ms > 200) {
|
||||
last_update_hue_ms = millis();
|
||||
hue++;
|
||||
}
|
||||
|
55
examples/AuroraDemo/PatternGreenScroll.hpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Codetastic 2024
|
||||
// ChatGPT was used to create this.
|
||||
// It sucks.
|
||||
|
||||
#ifndef PatternTheMatrix_H
|
||||
#define PatternTheMatrix_H
|
||||
|
||||
// Function to generate a random greenish color for the digital rain
|
||||
CRGB generateRainColor() {
|
||||
return CHSV(96 + random(64), 255, 255); // Greenish colors
|
||||
}
|
||||
|
||||
|
||||
class PatternTheMatrix : public Drawable {
|
||||
|
||||
public:
|
||||
PatternTheMatrix() {
|
||||
name = (char *)"The Matrix";
|
||||
}
|
||||
|
||||
|
||||
// Function to draw the digital rain effect
|
||||
void drawDigitalRain() {
|
||||
// Shift all the LEDs down by one row
|
||||
for (int x = 0; x < VPANEL_W ; x++) {
|
||||
for (int y = VPANEL_H - 1; y > 0; y--) {
|
||||
effects.leds[XY(x, y)] = effects.leds[XY(x, y - 1)];
|
||||
}
|
||||
// Add a new drop at the top of the column randomly
|
||||
if (random(10) > 7) { // Adjust the probability to control density of rain
|
||||
effects.leds[XY(x, 0)] = generateRainColor();
|
||||
} else {
|
||||
effects.leds[XY(x, 0)] = CRGB::Black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void start()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
effects.DimAll(250);
|
||||
|
||||
drawDigitalRain();
|
||||
|
||||
effects.ShowFrame();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternIncrementalDrift_H
|
||||
#define PatternIncrementalDrift_H
|
||||
|
||||
class PatternIncrementalDrift : public Drawable {
|
||||
public:
|
||||
PatternIncrementalDrift() {
|
||||
name = (char *)"Incremental Drift";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
uint8_t dim = beatsin8(2, 230, 250);
|
||||
effects.DimAll(dim); effects.ShowFrame();
|
||||
|
||||
for (int i = 2; i <= MATRIX_WIDTH / 2; i++)
|
||||
{
|
||||
CRGB color = effects.ColorFromCurrentPalette((i - 2) * (240 / (MATRIX_WIDTH / 2)));
|
||||
|
||||
uint8_t x = beatcos8((17 - i) * 2, MATRIX_CENTER_X - i, MATRIX_CENTER_X + i);
|
||||
uint8_t y = beatsin8((17 - i) * 2, MATRIX_CENTER_Y - i, MATRIX_CENTER_Y + i);
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, color);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -31,19 +31,21 @@ class PatternIncrementalDrift : public Drawable {
|
|||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
uint8_t dim = beatsin8(2, 230, 250);
|
||||
effects.DimAll(dim); effects.ShowFrame();
|
||||
//uint8_t dim = beatsin8(2, 230, 250);
|
||||
effects.DimAll(250);
|
||||
|
||||
for (int i = 2; i <= VPANEL_W / 2; i++)
|
||||
{
|
||||
CRGB color = effects.ColorFromCurrentPalette((i - 2) * (240 / (VPANEL_W / 2)));
|
||||
|
||||
uint8_t x = beatcos8((17 - i) * 2, MATRIX_CENTER_X - i, MATRIX_CENTER_X + i);
|
||||
uint8_t y = beatsin8((17 - i) * 2, MATRIX_CENTER_Y - i, MATRIX_CENTER_Y + i);
|
||||
uint8_t x = effects.beatcos8((17 - i) * 2, effects.getCenterX() - i, effects.getCenterX() + i);
|
||||
uint8_t y = beatsin8((17 - i) * 2, effects.getCenterY() - i, effects.getCenterY() + i);
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, color);
|
||||
effects.setPixel(x, y, color);
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternIncrementalDrift2_H
|
||||
#define PatternIncrementalDrift2_H
|
||||
|
||||
class PatternIncrementalDrift2 : public Drawable {
|
||||
public:
|
||||
PatternIncrementalDrift2() {
|
||||
name = (char *)"Incremental Drift Rose";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
uint8_t dim = beatsin8(2, 170, 250);
|
||||
effects.DimAll(dim); effects.ShowFrame();
|
||||
|
||||
for (uint8_t i = 0; i < 32; i++)
|
||||
{
|
||||
CRGB color;
|
||||
|
||||
uint8_t x = 0;
|
||||
uint8_t y = 0;
|
||||
|
||||
if (i < 16) {
|
||||
x = beatcos8((i + 1) * 2, i, MATRIX_WIDTH - i);
|
||||
y = beatsin8((i + 1) * 2, i, MATRIX_HEIGHT - i);
|
||||
color = effects.ColorFromCurrentPalette(i * 14);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = beatsin8((32 - i) * 2, MATRIX_WIDTH - i, i + 1);
|
||||
y = beatcos8((32 - i) * 2, MATRIX_HEIGHT - i, i + 1);
|
||||
color = effects.ColorFromCurrentPalette((31 - i) * 14);
|
||||
}
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, color);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -43,18 +43,18 @@ class PatternIncrementalDrift2 : public Drawable {
|
|||
uint8_t y = 0;
|
||||
|
||||
if (i < 16) {
|
||||
x = beatcos8((i + 1) * 2, i, VPANEL_W - i);
|
||||
x = effects.beatcos8((i + 1) * 2, i, VPANEL_W - i);
|
||||
y = beatsin8((i + 1) * 2, i, VPANEL_H - i);
|
||||
color = effects.ColorFromCurrentPalette(i * 14);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = beatsin8((32 - i) * 2, VPANEL_W - i, i + 1);
|
||||
y = beatcos8((32 - i) * 2, VPANEL_H - i, i + 1);
|
||||
y = effects.beatcos8((32 - i) * 2, VPANEL_H - i, i + 1);
|
||||
color = effects.ColorFromCurrentPalette((31 - i) * 14);
|
||||
}
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, color);
|
||||
effects.setPixel(x, y, color);
|
||||
}
|
||||
|
||||
return 0;
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternInfinity_H
|
||||
|
||||
class PatternInfinity : public Drawable {
|
||||
public:
|
||||
PatternInfinity() {
|
||||
name = (char *)"Infinity";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// dim all pixels on the display slightly
|
||||
// to 250/255 (98%) of their current brightness
|
||||
blur2d(effects.leds, MATRIX_WIDTH > 255 ? 255 : MATRIX_WIDTH, MATRIX_HEIGHT > 255 ? 255 : MATRIX_HEIGHT, 250);
|
||||
// effects.DimAll(250); effects.ShowFrame();
|
||||
|
||||
|
||||
// the Effects class has some sample oscillators
|
||||
// that move from 0 to 255 at different speeds
|
||||
effects.MoveOscillators();
|
||||
|
||||
// the horizontal position of the head of the infinity sign
|
||||
// oscillates from 0 to the maximum horizontal and back
|
||||
int x = (MATRIX_WIDTH - 1) - effects.p[1];
|
||||
|
||||
// the vertical position of the head oscillates
|
||||
// from 8 to 23 and back (hard-coded for a 32x32 matrix)
|
||||
int y = map8(sin8(effects.osci[3]), 8, 23);
|
||||
|
||||
// the hue oscillates from 0 to 255, overflowing back to 0
|
||||
byte hue = sin8(effects.osci[5]);
|
||||
|
||||
// draw a pixel at x,y using a color from the current palette
|
||||
effects.Pixel(x, y, hue);
|
||||
|
||||
effects.ShowFrame();
|
||||
return 30;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -28,30 +28,35 @@ public:
|
|||
name = (char *)"Infinity";
|
||||
}
|
||||
|
||||
void start() {
|
||||
effects.ClearFrame();
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
// dim all pixels on the display slightly
|
||||
// to 250/255 (98%) of their current brightness
|
||||
blur2d(effects.leds, VPANEL_W > 255 ? 255 : VPANEL_W, VPANEL_H > 255 ? 255 : VPANEL_H, 250);
|
||||
//blur2d(effects.leds, VPANEL_W > 255 ? 255 : VPANEL_W, VPANEL_H > 255 ? 255 : VPANEL_H, 250);
|
||||
// effects.DimAll(250); effects.ShowFrame();
|
||||
|
||||
|
||||
// the Effects class has some sample oscillators
|
||||
// the EffectsLayer class has some sample oscillators
|
||||
// that move from 0 to 255 at different speeds
|
||||
effects.MoveOscillators();
|
||||
|
||||
// the horizontal position of the head of the infinity sign
|
||||
// oscillates from 0 to the maximum horizontal and back
|
||||
int x = (VPANEL_W - 1) - effects.p[1];
|
||||
int x = (VPANEL_W - 4) - effects.p[1];
|
||||
|
||||
// the vertical position of the head oscillates
|
||||
// from 8 to 23 and back (hard-coded for a 32x32 matrix)
|
||||
int y = map8(sin8(effects.osci[3]), 8, 23);
|
||||
int y = map8(sin8(effects.osci[3]), 8, VPANEL_H - 8);
|
||||
|
||||
// the hue oscillates from 0 to 255, overflowing back to 0
|
||||
byte hue = sin8(effects.osci[5]);
|
||||
|
||||
// draw a pixel at x,y using a color from the current palette
|
||||
effects.Pixel(x, y, hue);
|
||||
effects.drawTriangle(x,y,x+1,y+1,x+2,y+2,effects.ColorFromCurrentPalette(hue));
|
||||
////effects.setPixelFromPaletteIndex(x, y, hue);
|
||||
|
||||
effects.ShowFrame();
|
||||
return 30;
|
|
@ -1,154 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Inspired by 'Space Invader Generator': https://the8bitpimp.wordpress.com/2013/05/07/space-invader-generator
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternInvaders_H
|
||||
#define PatternInvaders_H
|
||||
|
||||
class PatternInvadersSmall : public Drawable {
|
||||
private:
|
||||
uint8_t x = 1;
|
||||
uint8_t y = 1;
|
||||
|
||||
public:
|
||||
PatternInvadersSmall() {
|
||||
name = (char *)"Invaders Small";
|
||||
}
|
||||
|
||||
void start() {
|
||||
dma_display->fillScreen(0);
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
CRGB color1 = effects.ColorFromCurrentPalette(random(0, 255));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 5; j++) {
|
||||
CRGB color = CRGB::Black;
|
||||
|
||||
if (random(0, 2) == 1) color = color1;
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x + i, y + j, color);
|
||||
|
||||
if (i < 2)
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x + (4 - i), y + j, color);
|
||||
}
|
||||
}
|
||||
|
||||
x += 6;
|
||||
if (x > 25) {
|
||||
x = 1;
|
||||
y += 6;
|
||||
}
|
||||
|
||||
if (y > 25) y = x = 1;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 125;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternInvadersMedium : public Drawable {
|
||||
private:
|
||||
uint8_t x = 0;
|
||||
uint8_t y = 0;
|
||||
|
||||
public:
|
||||
PatternInvadersMedium() {
|
||||
name = (char *)"Invaders Medium";
|
||||
}
|
||||
|
||||
void start() {
|
||||
dma_display->fillScreen(0);
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
CRGB color1 = effects.ColorFromCurrentPalette(random(0, 255));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 5; j++) {
|
||||
CRGB color = CRGB::Black;
|
||||
|
||||
if (random(0, 2) == 1) color = color1;
|
||||
|
||||
dma_display->fillRect(x + (i * 2), y + (j * 2), x + (i * 2 + 1), y + (j * 2 + 1), color);
|
||||
|
||||
if (i < 2)
|
||||
dma_display->fillRect(x + (8 - i * 2), y + (j * 2), x + (9 - i * 2), y + (j * 2 + 1), color);
|
||||
}
|
||||
}
|
||||
|
||||
x += 11;
|
||||
if (x > 22) {
|
||||
x = 0;
|
||||
y += 11;
|
||||
}
|
||||
|
||||
if (y > 22) y = x = 0;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 500;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternInvadersLarge : public Drawable {
|
||||
private:
|
||||
|
||||
public:
|
||||
PatternInvadersLarge() {
|
||||
name = (char *)"Invaders Large";
|
||||
}
|
||||
|
||||
void start() {
|
||||
dma_display->fillScreen(0);
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
dma_display->fillScreen(0);
|
||||
|
||||
CRGB color1 = effects.ColorFromCurrentPalette(random(0, 255));
|
||||
|
||||
for (int x = 0; x < 3; x++) {
|
||||
for (int y = 0; y < 5; y++) {
|
||||
CRGB color = CRGB::Black;
|
||||
|
||||
if (random(0, 2) == 1) {
|
||||
color = color1;
|
||||
}
|
||||
|
||||
dma_display->fillRect(1 + x * 6, 1 + y * 6, 5 + x * 6, 5 + y * 6, color);
|
||||
|
||||
if (x < 2)
|
||||
dma_display->fillRect(1 + (4 - x) * 6, 1 + y * 6, 5 + (4 - x) * 6, 5 + y * 6, color);
|
||||
}
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 2000;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
129
examples/AuroraDemo/PatternJuliaSetFractal.hpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
#ifndef JuliaSet_H
|
||||
#define JuliaSet_H
|
||||
|
||||
// Codetastic 2024
|
||||
|
||||
#define USE_FLOATHACK // To boost float performance, comment if this doesn't work.
|
||||
|
||||
// inspired by
|
||||
// https://en.wikipedia.org/wiki/Fast_inverse_square_root
|
||||
#ifdef USE_FLOATHACK
|
||||
// cast float as int32_t
|
||||
int32_t intfloat(float n){ return *(int32_t *)&n; }
|
||||
// cast int32_t as float
|
||||
float floatint(int32_t n){ return *(float *)&n; }
|
||||
// fast approx sqrt(x)
|
||||
float floatsqrt(float n){ return floatint(0x1fbb4000+(intfloat(n)>>1)); }
|
||||
// fast approx 1/x
|
||||
float floatinv(float n){ return floatint(0x7f000000-intfloat(n)); }
|
||||
// fast approx log2(x)
|
||||
float floatlog2(float n){ return (float)((intfloat(n)<<1)-0x7f000000)*5.9604645e-08f; }
|
||||
#else
|
||||
float floatinv(float n){ return 1.f/n;}
|
||||
float floatsqrt(float n){ return std::sqrt(n); }
|
||||
float floatlog2(float n){ return std::log2f(n); }
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////
|
||||
// Escape time mandelbrot set function,
|
||||
// with arbitrary start point zx, zy
|
||||
// and arbitrary seed point ax, ay
|
||||
//
|
||||
// For julia set
|
||||
// zx = pos_x, zy = pos_y;
|
||||
// ax = seed_x, ay = seed_y;
|
||||
//
|
||||
// For mandelbrot set
|
||||
// zx = 0, zy = 0;
|
||||
// ax = pos_x, ay = pos_y;
|
||||
//
|
||||
const float bailOut = 4; // Escape radius
|
||||
const int32_t itmult = 1<<10; // Color speed
|
||||
//
|
||||
// https://en.wikipedia.org/wiki/Mandelbrot_set
|
||||
int32_t iteratefloat(float ax, float ay, float zx, float zy, uint16_t mxIT) {
|
||||
float zzl = 0;
|
||||
for (int it = 0; it<mxIT; it++) {
|
||||
float zzx = zx * zx;
|
||||
float zzy = zy * zy;
|
||||
// is the point is escaped?
|
||||
if(zzx+zzy>=bailOut){
|
||||
if(it>0){
|
||||
// calculate smooth coloring
|
||||
float zza = floatlog2(zzl);
|
||||
float zzb = floatlog2(zzx+zzy);
|
||||
float zzc = floatlog2(bailOut);
|
||||
float zzd = (zzc-zza)*floatinv(zzb-zza);
|
||||
return it*itmult+zzd*itmult;
|
||||
}
|
||||
};
|
||||
// z -> z*z + c
|
||||
zy = 2.f*zx*zy+ay;
|
||||
zx = zzx-zzy+ax;
|
||||
zzl = zzx+zzy;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
class PatternJuliaSet : public Drawable {
|
||||
|
||||
private:
|
||||
|
||||
float sint[256]; // precalculated sin table, for performance reasons
|
||||
|
||||
public:
|
||||
PatternJuliaSet() {
|
||||
name = (char *)"Julia Set";
|
||||
}
|
||||
|
||||
void start() {
|
||||
|
||||
for(int i=0;i<256;i++){
|
||||
sint[i] = sinf(i/256.f*2.f*PI);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Palette color taken from:
|
||||
// https://editor.p5js.org/Kouzerumatsukite/sketches/DwTiq9D01
|
||||
// color palette originally made by piano_miles, written in p5js
|
||||
// hsv2rgb(IT, cos(4096*it)/2+0.5, 1-sin(2048*it)/2-0.5)
|
||||
void drawPixelPalette(int x, int y, uint32_t m){
|
||||
float r = 0.f, g = 0.f, b = 0.f;
|
||||
if(m){
|
||||
char n = m>> 4 ;
|
||||
float l =abs(sint[m>> 2&255] )*255.f ;
|
||||
float s = (sint[m &255]+ 1.f)*0.5f ;
|
||||
r = (max(min(sint[n &255]+0.5f,1.f),0.f)*s+(1-s))*l;
|
||||
g = (max(min(sint[n+ 85&255]+0.5f,1.f),0.f)*s+(1-s))*l;
|
||||
b = (max(min(sint[n+170&255]+0.5f,1.f),0.f)*s+(1-s))*l;
|
||||
}
|
||||
effects.setPixel(x,y,CRGB(r,g,b));
|
||||
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
uint32_t lastMicros = micros();
|
||||
double t = (double)lastMicros/8000000;
|
||||
double k = sin(t*3.212/2)*sin(t*3.212/2)/16+1;
|
||||
float cosk = (k-cos(t))/2;
|
||||
float xoff = (cos(t)*cosk+k/2-0.25);
|
||||
float yoff = (sin(t)*cosk );
|
||||
for(uint8_t y=0;y<VPANEL_H;y++){
|
||||
for(uint8_t x=0;x<VPANEL_W;x++){
|
||||
uint32_t itcount = iteratefloat(xoff,yoff,((x-64)+1)/64.f,(y)/64.f,64);
|
||||
uint32_t itcolor = itcount?floatsqrt(itcount)*4+t*1024:0;
|
||||
drawPixelPalette(x,y,itcolor);
|
||||
}
|
||||
}
|
||||
|
||||
blur2d(effects.leds, VPANEL_W, VPANEL_H, 64);
|
||||
|
||||
effects.ShowFrame();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from Andrew: http://pastebin.com/f22bfe94d
|
||||
* which, in turn, was "Adapted from the Life example on the Processing.org site"
|
||||
*
|
||||
* Made much more colorful by J.B. Langston: https://github.com/jblang/aurora/commit/6db5a884e3df5d686445c4f6b669f1668841929b
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternLife_H
|
||||
#define PatternLife_H
|
||||
|
||||
class Cell {
|
||||
public:
|
||||
byte alive : 1;
|
||||
byte prev : 1;
|
||||
byte hue: 6;
|
||||
byte brightness;
|
||||
};
|
||||
|
||||
class PatternLife : public Drawable {
|
||||
private:
|
||||
Cell world[MATRIX_WIDTH][MATRIX_HEIGHT];
|
||||
unsigned int density = 50;
|
||||
int generation = 0;
|
||||
|
||||
void randomFillWorld() {
|
||||
for (int i = 0; i < MATRIX_WIDTH; i++) {
|
||||
for (int j = 0; j < MATRIX_HEIGHT; j++) {
|
||||
if (random(100) < density) {
|
||||
world[i][j].alive = 1;
|
||||
world[i][j].brightness = 255;
|
||||
}
|
||||
else {
|
||||
world[i][j].alive = 0;
|
||||
world[i][j].brightness = 0;
|
||||
}
|
||||
world[i][j].prev = world[i][j].alive;
|
||||
world[i][j].hue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int neighbours(int x, int y) {
|
||||
return (world[(x + 1) % MATRIX_WIDTH][y].prev) +
|
||||
(world[x][(y + 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + MATRIX_WIDTH - 1) % MATRIX_WIDTH][y].prev) +
|
||||
(world[x][(y + MATRIX_HEIGHT - 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + 1) % MATRIX_WIDTH][(y + 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + MATRIX_WIDTH - 1) % MATRIX_WIDTH][(y + 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + MATRIX_WIDTH - 1) % MATRIX_WIDTH][(y + MATRIX_HEIGHT - 1) % MATRIX_HEIGHT].prev) +
|
||||
(world[(x + 1) % MATRIX_WIDTH][(y + MATRIX_HEIGHT - 1) % MATRIX_HEIGHT].prev);
|
||||
}
|
||||
|
||||
public:
|
||||
PatternLife() {
|
||||
name = (char *)"Life";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
if (generation == 0) {
|
||||
effects.ClearFrame();
|
||||
|
||||
randomFillWorld();
|
||||
}
|
||||
|
||||
// Display current generation
|
||||
for (int i = 0; i < MATRIX_WIDTH; i++) {
|
||||
for (int j = 0; j < MATRIX_HEIGHT; j++) {
|
||||
effects.leds[XY(i, j)] = effects.ColorFromCurrentPalette(world[i][j].hue * 4, world[i][j].brightness);
|
||||
}
|
||||
}
|
||||
|
||||
// Birth and death cycle
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
// Default is for cell to stay the same
|
||||
if (world[x][y].brightness > 0 && world[x][y].prev == 0)
|
||||
world[x][y].brightness *= 0.9;
|
||||
int count = neighbours(x, y);
|
||||
if (count == 3 && world[x][y].prev == 0) {
|
||||
// A new cell is born
|
||||
world[x][y].alive = 1;
|
||||
world[x][y].hue += 2;
|
||||
world[x][y].brightness = 255;
|
||||
} else if ((count < 2 || count > 3) && world[x][y].prev == 1) {
|
||||
// Cell dies
|
||||
world[x][y].alive = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy next generation into place
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
world[x][y].prev = world[x][y].alive;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
generation++;
|
||||
if (generation >= 256)
|
||||
generation = 0;
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 60;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,264 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Many thanks to Jamis Buck for the documentation of the Growing Tree maze generation algorithm: http://weblog.jamisbuck.org/2011/1/27/maze-generation-growing-tree-algorithm
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternMaze_H
|
||||
#define PatternMaze_H
|
||||
|
||||
class PatternMaze : public Drawable {
|
||||
private:
|
||||
enum Directions {
|
||||
None = 0,
|
||||
Up = 1,
|
||||
Down = 2,
|
||||
Left = 4,
|
||||
Right = 8,
|
||||
};
|
||||
|
||||
struct Point{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
static Point New(int x, int y) {
|
||||
Point point;
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
return point;
|
||||
}
|
||||
|
||||
Point Move(Directions direction) {
|
||||
switch (direction)
|
||||
{
|
||||
case Up:
|
||||
return New(x, y - 1);
|
||||
|
||||
case Down:
|
||||
return New(x, y + 1);
|
||||
|
||||
case Left:
|
||||
return New(x - 1, y);
|
||||
|
||||
case Right:
|
||||
default:
|
||||
return New(x + 1, y);
|
||||
}
|
||||
}
|
||||
|
||||
static Directions Opposite(Directions direction) {
|
||||
switch (direction) {
|
||||
case Up:
|
||||
return Down;
|
||||
|
||||
case Down:
|
||||
return Up;
|
||||
|
||||
case Left:
|
||||
return Right;
|
||||
|
||||
case Right:
|
||||
default:
|
||||
return Left;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// int width = 16;
|
||||
// int height = 16;
|
||||
|
||||
static const int width = MATRIX_WIDTH / 2;
|
||||
static const int height = MATRIX_HEIGHT / 2;
|
||||
|
||||
|
||||
Directions grid[width][height];
|
||||
|
||||
Point point;
|
||||
|
||||
Point cells[256];
|
||||
int cellCount = 0;
|
||||
|
||||
int algorithm = 0;
|
||||
int algorithmCount = 1;
|
||||
|
||||
byte hue = 0;
|
||||
byte hueOffset = 0;
|
||||
|
||||
Directions directions[4] = { Up, Down, Left, Right };
|
||||
|
||||
void removeCell(int index) {// shift cells after index down one
|
||||
for (int i = index; i < cellCount - 1; i++) {
|
||||
cells[i] = cells[i + 1];
|
||||
}
|
||||
|
||||
cellCount--;
|
||||
}
|
||||
|
||||
void shuffleDirections() {
|
||||
for (int a = 0; a < 4; a++)
|
||||
{
|
||||
int r = random(a, 4);
|
||||
Directions temp = directions[a];
|
||||
directions[a] = directions[r];
|
||||
directions[r] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
Point createPoint(int x, int y) {
|
||||
Point point;
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
return point;
|
||||
}
|
||||
|
||||
CRGB chooseColor(int index) {
|
||||
byte h = index + hueOffset;
|
||||
|
||||
switch (algorithm) {
|
||||
case 0:
|
||||
default:
|
||||
return effects.ColorFromCurrentPalette(h);
|
||||
|
||||
case 1:
|
||||
return effects.ColorFromCurrentPalette(hue++);
|
||||
}
|
||||
}
|
||||
|
||||
int chooseIndex(int max) {
|
||||
switch (algorithm) {
|
||||
case 0:
|
||||
default:
|
||||
// choose newest (recursive backtracker)
|
||||
return max - 1;
|
||||
|
||||
case 1:
|
||||
// choose random(Prim's)
|
||||
return random(max);
|
||||
|
||||
// case 2:
|
||||
// // choose oldest (not good, so disabling)
|
||||
// return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void generateMaze() {
|
||||
while (cellCount > 1) {
|
||||
drawNextCell();
|
||||
}
|
||||
}
|
||||
|
||||
void drawNextCell() {
|
||||
int index = chooseIndex(cellCount);
|
||||
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
point = cells[index];
|
||||
|
||||
Point imagePoint = createPoint(point.x * 2, point.y * 2);
|
||||
|
||||
//effects.drawBackgroundFastLEDPixelCRGB(imagePoint.x, imagePoint.y, CRGB(CRGB::Gray));
|
||||
|
||||
shuffleDirections();
|
||||
|
||||
CRGB color = chooseColor(index);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Directions direction = directions[i];
|
||||
|
||||
Point newPoint = point.Move(direction);
|
||||
if (newPoint.x >= 0 && newPoint.y >= 0 && newPoint.x < width && newPoint.y < height && grid[newPoint.y][newPoint.x] == None) {
|
||||
grid[point.y][point.x] = (Directions) ((int) grid[point.y][point.x] | (int) direction);
|
||||
grid[newPoint.y][newPoint.x] = (Directions) ((int) grid[newPoint.y][newPoint.x] | (int) point.Opposite(direction));
|
||||
|
||||
Point newImagePoint = imagePoint.Move(direction);
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(newImagePoint.x, newImagePoint.y, color);
|
||||
|
||||
cellCount++;
|
||||
cells[cellCount - 1] = newPoint;
|
||||
|
||||
index = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > -1) {
|
||||
Point finishedPoint = cells[index];
|
||||
imagePoint = createPoint(finishedPoint.x * 2, finishedPoint.y * 2);
|
||||
effects.drawBackgroundFastLEDPixelCRGB(imagePoint.x, imagePoint.y, color);
|
||||
|
||||
removeCell(index);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
PatternMaze() {
|
||||
name = (char *)"Maze";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
if (cellCount < 1) {
|
||||
|
||||
effects.ClearFrame();
|
||||
|
||||
// reset the maze grid
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
grid[y][x] = None;
|
||||
}
|
||||
}
|
||||
|
||||
int x = random(width);
|
||||
int y = random(height);
|
||||
|
||||
cells[0] = createPoint(x, y);
|
||||
|
||||
cellCount = 1;
|
||||
|
||||
hue = 0;
|
||||
hueOffset = random(0, 256);
|
||||
|
||||
}
|
||||
|
||||
drawNextCell();
|
||||
|
||||
if (cellCount < 1) {
|
||||
algorithm++;
|
||||
if (algorithm >= algorithmCount)
|
||||
algorithm = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void start() {
|
||||
effects.ClearFrame();
|
||||
cellCount = 0;
|
||||
hue = 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -175,7 +175,7 @@ private:
|
|||
|
||||
Point imagePoint = createPoint(point.x * 2, point.y * 2);
|
||||
|
||||
//effects.drawBackgroundFastLEDPixelCRGB(imagePoint.x, imagePoint.y, CRGB(CRGB::Gray));
|
||||
//effects.setPixel(imagePoint.x, imagePoint.y, CRGB(CRGB::Gray));
|
||||
|
||||
shuffleDirections();
|
||||
|
||||
|
@ -191,7 +191,7 @@ private:
|
|||
|
||||
Point newImagePoint = imagePoint.Move(direction);
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(newImagePoint.x, newImagePoint.y, color);
|
||||
effects.setPixel(newImagePoint.x, newImagePoint.y, color);
|
||||
|
||||
cellCount++;
|
||||
cells[cellCount - 1] = newPoint;
|
||||
|
@ -204,7 +204,7 @@ private:
|
|||
if (index > -1) {
|
||||
Point finishedPoint = cells[index];
|
||||
imagePoint = createPoint(finishedPoint.x * 2, finishedPoint.y * 2);
|
||||
effects.drawBackgroundFastLEDPixelCRGB(imagePoint.x, imagePoint.y, color);
|
||||
effects.setPixel(imagePoint.x, imagePoint.y, color);
|
||||
|
||||
removeCell(index);
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Munch pattern created by J.B. Langston: https://github.com/jblang/aurora/blob/master/PatternMunch.h
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternMunch_H
|
||||
#define PatternMunch_H
|
||||
|
||||
|
||||
class PatternMunch : public Drawable {
|
||||
private:
|
||||
byte count = 0;
|
||||
byte dir = 1;
|
||||
byte flip = 0;
|
||||
byte generation = 0;
|
||||
|
||||
public:
|
||||
PatternMunch() {
|
||||
name = (char *)"Munch";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
for (uint16_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (uint16_t y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
effects.leds[XY16(x, y)] = (x ^ y ^ flip) < count ? effects.ColorFromCurrentPalette(((x ^ y) << 2) + generation) : CRGB::Black;
|
||||
|
||||
// The below is more pleasant
|
||||
// effects.leds[XY(x, y)] = effects.ColorFromCurrentPalette(((x ^ y) << 2) + generation) ;
|
||||
}
|
||||
}
|
||||
|
||||
count += dir;
|
||||
|
||||
if (count <= 0 || count >= MATRIX_WIDTH) {
|
||||
dir = -dir;
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
if (flip == 0)
|
||||
flip = MATRIX_WIDTH-1;
|
||||
else
|
||||
flip = 0;
|
||||
}
|
||||
|
||||
generation++;
|
||||
|
||||
// show it ffs!
|
||||
effects.ShowFrame();
|
||||
return 60;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -45,7 +45,7 @@ public:
|
|||
effects.leds[XY16(x, y)] = (x ^ y ^ flip) < count ? effects.ColorFromCurrentPalette(((x ^ y) << 2) + generation) : CRGB::Black;
|
||||
|
||||
// The below is more pleasant
|
||||
// effects.leds[XY(x, y)] = effects.ColorFromCurrentPalette(((x ^ y) << 2) + generation) ;
|
||||
// effects.leds[XY16(x, y)] = effects.ColorFromCurrentPalette(((x ^ y) << 2) + generation) ;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,338 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from "Noise Smearing" by Stefan Petrick: https://gist.githubusercontent.com/embedded-creations/5cd47d83cb0e04f4574d/raw/ebf6a82b4755d55cfba3bf6598f7b19047f89daf/NoiseSmearing.ino
|
||||
* Copyright (c) 2014 Stefan Petrick
|
||||
* http://www.stefan-petrick.de/wordpress_beta
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternNoiseSmearing_H
|
||||
#define PatternNoiseSmearing_H
|
||||
|
||||
byte patternNoiseSmearingHue = 0;
|
||||
|
||||
class PatternMultipleStream : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream() {
|
||||
name = (char *)"MultipleStream";
|
||||
}
|
||||
|
||||
// this pattern draws two points to the screen based on sin/cos if a counter
|
||||
// (comment out NoiseSmearWithRadius to see pattern of pixels)
|
||||
// these pixels are smeared by a large radius, giving a lot of movement
|
||||
// the image is dimmed before each drawing to not saturate the screen with color
|
||||
// the smear has an offset so the pixels usually have a trail leading toward the upper left
|
||||
unsigned int drawFrame() {
|
||||
static unsigned long counter = 0;
|
||||
#if 0
|
||||
// this counter lets put delays between each frame and still get the same animation
|
||||
counter++;
|
||||
#else
|
||||
// this counter updates in real time and can't be slowed down for debugging
|
||||
counter = millis() / 10;
|
||||
#endif
|
||||
|
||||
byte x1 = 4 + sin8(counter * 2) / 10;
|
||||
byte x2 = 8 + sin8(counter * 2) / 16;
|
||||
byte y2 = 8 + cos8((counter * 2) / 3) / 16;
|
||||
|
||||
effects.leds[XY(x1, x2)] = effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
effects.leds[XY(x2, y2)] = effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 128);
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(8);
|
||||
effects.MoveFractionalNoiseX();
|
||||
|
||||
effects.MoveY(8);
|
||||
effects.MoveFractionalNoiseY();
|
||||
|
||||
patternNoiseSmearingHue++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream2 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream2() {
|
||||
name = (char *)"MultipleStream2";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(230); effects.ShowFrame();
|
||||
|
||||
byte xx = 4 + sin8(millis() / 9) / 10;
|
||||
byte yy = 4 + cos8(millis() / 10) / 10;
|
||||
effects.leds[XY(xx, yy)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
|
||||
xx = 8 + sin8(millis() / 10) / 16;
|
||||
yy = 8 + cos8(millis() / 7) / 16;
|
||||
effects.leds[XY(xx, yy)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 80);
|
||||
|
||||
effects.leds[XY(15, 15)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 160);
|
||||
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
patternNoiseSmearingHue++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream3 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream3() {
|
||||
name = (char *)"MultipleStream3";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
//CLS();
|
||||
effects.DimAll(235); effects.ShowFrame();
|
||||
|
||||
for (uint8_t i = 3; i < 32; i = i + 4) {
|
||||
effects.leds[XY(i, 15)] += effects.ColorFromCurrentPalette(i * 8);
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream4 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream4() {
|
||||
name = (char *)"MultipleStream4";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
//CLS();
|
||||
effects.DimAll(235); effects.ShowFrame();
|
||||
|
||||
effects.leds[XY(15, 15)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(8);
|
||||
effects.MoveFractionalNoiseX();
|
||||
|
||||
effects.MoveY(8);
|
||||
effects.MoveFractionalNoiseY();
|
||||
|
||||
patternNoiseSmearingHue++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream5 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream5() {
|
||||
name = (char *)"MultipleStream5";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
//CLS();
|
||||
effects.DimAll(235); effects.ShowFrame();
|
||||
|
||||
|
||||
for (uint8_t i = 3; i < 32; i = i + 4) {
|
||||
effects.leds[XY(i, 31)] += effects.ColorFromCurrentPalette(i * 8);
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(4);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternMultipleStream8 : public Drawable {
|
||||
public:
|
||||
PatternMultipleStream8() {
|
||||
name = (char *)"MultipleStream8";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(230); effects.ShowFrame();
|
||||
|
||||
// draw grid of rainbow dots on top of the dimmed image
|
||||
for (uint8_t y = 1; y < 32; y = y + 6) {
|
||||
for (uint8_t x = 1; x < 32; x = x + 6) {
|
||||
|
||||
effects.leds[XY(x, y)] += effects.ColorFromCurrentPalette((x * y) / 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_z += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternPaletteSmear : public Drawable {
|
||||
public:
|
||||
PatternPaletteSmear() {
|
||||
name = (char *)"PaletteSmear";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
|
||||
effects.DimAll(170); effects.ShowFrame();
|
||||
|
||||
// draw a rainbow color palette
|
||||
for (uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
effects.leds[XY(x, y)] += effects.ColorFromCurrentPalette(x * 8, y * 8 + 7);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
//effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
effects.ShowFrame();
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class PatternRainbowFlag : public Drawable {
|
||||
public:
|
||||
PatternRainbowFlag() {
|
||||
name = (char *)"RainbowFlag";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.DimAll(10); effects.ShowFrame();
|
||||
|
||||
CRGB rainbow[7] = {
|
||||
CRGB::Red,
|
||||
CRGB::Orange,
|
||||
CRGB::Yellow,
|
||||
CRGB::Green,
|
||||
CRGB::Blue,
|
||||
CRGB::Violet
|
||||
};
|
||||
|
||||
uint8_t y = 2;
|
||||
|
||||
for (uint8_t c = 0; c < 6; c++) {
|
||||
for (uint8_t j = 0; j < 5; j++) {
|
||||
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
|
||||
effects.leds[XY(x, y)] += rainbow[c];
|
||||
}
|
||||
|
||||
y++;
|
||||
if (y >= MATRIX_HEIGHT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
noise_scale_x = 4000;
|
||||
noise_scale_y = 4000;
|
||||
effects.FillNoise();
|
||||
|
||||
effects.MoveX(3);
|
||||
effects.MoveFractionalNoiseY(4);
|
||||
|
||||
effects.MoveY(3);
|
||||
effects.MoveFractionalNoiseX(4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
#endif
|
|
@ -54,8 +54,8 @@ public:
|
|||
byte x2 = 8 + sin8(counter * 2) / 16;
|
||||
byte y2 = 8 + cos8((counter * 2) / 3) / 16;
|
||||
|
||||
effects.leds[XY(x1, x2)] = effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
effects.leds[XY(x2, y2)] = effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 128);
|
||||
effects.leds[XY16(x1, x2)] = effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
effects.leds[XY16(x2, y2)] = effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 128);
|
||||
|
||||
// Noise
|
||||
noise_x += 1000;
|
||||
|
@ -87,13 +87,13 @@ public:
|
|||
|
||||
byte xx = 4 + sin8(millis() / 9) / 10;
|
||||
byte yy = 4 + cos8(millis() / 10) / 10;
|
||||
effects.leds[XY(xx, yy)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
effects.leds[XY16(xx, yy)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
|
||||
xx = 8 + sin8(millis() / 10) / 16;
|
||||
yy = 8 + cos8(millis() / 7) / 16;
|
||||
effects.leds[XY(xx, yy)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 80);
|
||||
effects.leds[XY16(xx, yy)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 80);
|
||||
|
||||
effects.leds[XY(15, 15)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 160);
|
||||
effects.leds[XY16(15, 15)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue + 160);
|
||||
|
||||
noise_x += 1000;
|
||||
noise_y += 1000;
|
||||
|
@ -125,7 +125,7 @@ public:
|
|||
effects.DimAll(235); effects.ShowFrame();
|
||||
|
||||
for (uint8_t i = 3; i < 32; i = i + 4) {
|
||||
effects.leds[XY(i, 15)] += effects.ColorFromCurrentPalette(i * 8);
|
||||
effects.leds[XY16(i, 15)] += effects.ColorFromCurrentPalette(i * 8);
|
||||
}
|
||||
|
||||
// Noise
|
||||
|
@ -159,7 +159,7 @@ public:
|
|||
//CLS();
|
||||
effects.DimAll(235); effects.ShowFrame();
|
||||
|
||||
effects.leds[XY(15, 15)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
effects.leds[XY16(15, 15)] += effects.ColorFromCurrentPalette(patternNoiseSmearingHue);
|
||||
|
||||
|
||||
// Noise
|
||||
|
@ -194,7 +194,7 @@ public:
|
|||
|
||||
|
||||
for (uint8_t i = 3; i < 32; i = i + 4) {
|
||||
effects.leds[XY(i, 31)] += effects.ColorFromCurrentPalette(i * 8);
|
||||
effects.leds[XY16(i, 31)] += effects.ColorFromCurrentPalette(i * 8);
|
||||
}
|
||||
|
||||
// Noise
|
||||
|
@ -228,7 +228,7 @@ public:
|
|||
for (uint8_t y = 1; y < 32; y = y + 6) {
|
||||
for (uint8_t x = 1; x < 32; x = x + 6) {
|
||||
|
||||
effects.leds[XY(x, y)] += effects.ColorFromCurrentPalette((x * y) / 4);
|
||||
effects.leds[XY16(x, y)] += effects.ColorFromCurrentPalette((x * y) / 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ public:
|
|||
// draw a rainbow color palette
|
||||
for (uint8_t y = 0; y < VPANEL_H; y++) {
|
||||
for (uint8_t x = 0; x < VPANEL_W; x++) {
|
||||
effects.leds[XY(x, y)] += effects.ColorFromCurrentPalette(x * 8, y * 8 + 7);
|
||||
effects.leds[XY16(x, y)] += effects.ColorFromCurrentPalette(x * 8, y * 8 + 7);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,7 +310,7 @@ public:
|
|||
for (uint8_t c = 0; c < 6; c++) {
|
||||
for (uint8_t j = 0; j < 5; j++) {
|
||||
for (uint8_t x = 0; x < VPANEL_W; x++) {
|
||||
effects.leds[XY(x, y)] += rainbow[c];
|
||||
effects.leds[XY16(x, y)] += rainbow[c];
|
||||
}
|
||||
|
||||
y++;
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Inspired by and based on a loading animation for Prismata by Lunarch Studios:
|
||||
* http://www.reddit.com/r/gifs/comments/2on8si/connecting_to_server_so_mesmerizing/cmow0sz
|
||||
*
|
||||
* Lunarch Studios Inc. hereby publishes the Actionscript 3 source code pasted in this
|
||||
* comment under the Creative Commons CC0 1.0 Universal Public Domain Dedication.
|
||||
* Lunarch Studios Inc. waives all rights to the work worldwide under copyright law,
|
||||
* including all related and neighboring rights, to the extent allowed by law.
|
||||
* You can copy, modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternPendulumWave_H
|
||||
#define PatternPendulumWave_H
|
||||
|
||||
#define WAVE_BPM 25
|
||||
#define AMP_BPM 2
|
||||
#define SKEW_BPM 4
|
||||
#define WAVE_TIMEMINSKEW MATRIX_WIDTH/8
|
||||
#define WAVE_TIMEMAXSKEW MATRIX_WIDTH/2
|
||||
|
||||
class PatternPendulumWave : public Drawable {
|
||||
public:
|
||||
PatternPendulumWave() {
|
||||
name = (char *)"Pendulum Wave";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.ClearFrame();
|
||||
|
||||
for (int x = 0; x < MATRIX_WIDTH; ++x)
|
||||
{
|
||||
uint16_t amp = beatsin16(AMP_BPM, MATRIX_HEIGHT/8, MATRIX_HEIGHT-1);
|
||||
uint16_t offset = (MATRIX_HEIGHT - beatsin16(AMP_BPM, 0, MATRIX_HEIGHT))/2;
|
||||
|
||||
uint8_t y = beatsin16(WAVE_BPM, 0, amp, x*beatsin16(SKEW_BPM, WAVE_TIMEMINSKEW, WAVE_TIMEMAXSKEW)) + offset;
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, effects.ColorFromCurrentPalette(x * 7));
|
||||
}
|
||||
effects.ShowFrame();
|
||||
return 20;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -38,7 +38,7 @@
|
|||
#define AMP_BPM 2
|
||||
#define SKEW_BPM 4
|
||||
#define WAVE_TIMEMINSKEW VPANEL_W/8
|
||||
#define WAVE_TIMEMAXSKEW VPANEL_W/2
|
||||
#define WAVE_TIMEMAXSKEW effects.getCenterX()
|
||||
|
||||
class PatternPendulumWave : public Drawable {
|
||||
public:
|
||||
|
@ -46,8 +46,9 @@ class PatternPendulumWave : public Drawable {
|
|||
name = (char *)"Pendulum Wave";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
effects.ClearFrame();
|
||||
unsigned int drawFrame()
|
||||
{
|
||||
effects.DimAll(192);
|
||||
|
||||
for (int x = 0; x < VPANEL_W; ++x)
|
||||
{
|
||||
|
@ -56,7 +57,7 @@ class PatternPendulumWave : public Drawable {
|
|||
|
||||
uint8_t y = beatsin16(WAVE_BPM, 0, amp, x*beatsin16(SKEW_BPM, WAVE_TIMEMINSKEW, WAVE_TIMEMAXSKEW)) + offset;
|
||||
|
||||
effects.drawBackgroundFastLEDPixelCRGB(x, y, effects.ColorFromCurrentPalette(x * 7));
|
||||
effects.setPixel(x, y, effects.ColorFromCurrentPalette(x * 7));
|
||||
}
|
||||
effects.ShowFrame();
|
||||
return 20;
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Aurora: https://github.com/pixelmatix/aurora
|
||||
* Copyright (c) 2014 Jason Coon
|
||||
*
|
||||
* Portions of this code are adapted from LedEffects Plasma by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Plasma.cpp?at=default
|
||||
* Copyright (c) 2013 Robert Atkins
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PatternPlasma_H
|
||||
#define PatternPlasma_H
|
||||
|
||||
class PatternPlasma : public Drawable {
|
||||
private:
|
||||
int time = 0;
|
||||
int cycles = 0;
|
||||
|
||||
public:
|
||||
PatternPlasma() {
|
||||
name = (char *)"Plasma";
|
||||
}
|
||||
|
||||
unsigned int drawFrame() {
|
||||
for (int x = 0; x < MATRIX_WIDTH; x++) {
|
||||
for (int y = 0; y < MATRIX_HEIGHT; y++) {
|
||||
int16_t v = 0;
|
||||
uint8_t wibble = sin8(time);
|
||||
v += sin16(x * wibble * 2 + time);
|
||||
v += cos16(y * (128 - wibble) * 2 + time);
|
||||
v += sin16(y * x * cos8(-time) / 2);
|
||||
|
||||
effects.Pixel(x, y, (v >> 8) + 127);
|
||||
}
|
||||
}
|
||||
|
||||
time += 1;
|
||||
cycles++;
|
||||
|
||||
if (cycles >= 2048) {
|
||||
time = 0;
|
||||
cycles = 0;
|
||||
}
|
||||
|
||||
effects.ShowFrame();
|
||||
|
||||
return 30;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|