Compare commits
40 Commits
v1.0.1
..
a7bc58e94e
| Author | SHA1 | Date | |
|---|---|---|---|
| a7bc58e94e | |||
| dfefe879c9 | |||
| 7d99c617ef | |||
| cdc7df3e56 | |||
| 8f0da378b0 | |||
| 7d03c9719e | |||
| dd20515e2b | |||
| 53c5639f92 | |||
| d85c5b47b6 | |||
| 97f768f65e | |||
| c66a5c166e | |||
| aa42e9d2aa | |||
| 3dceb044aa | |||
| d19f5d2d81 | |||
| 1bf0bfc558 | |||
| 06544ee23e | |||
| 1f5f502905 | |||
| 7120bc0207 | |||
| c7ae4191d3 | |||
| 85349598c3 | |||
| 2f83bbb21e | |||
| 6b4630f255 | |||
| 01266e7823 | |||
| d9074c366e | |||
| 81c7471226 | |||
| 31800e3392 | |||
| 69e34b499c | |||
| 8a14ad52bf | |||
| 0fe3b067cb | |||
| e1219c316c | |||
| 2692bb0f9b | |||
| d094a6c895 | |||
| 4ddb5241b4 | |||
| f04fe1f5c1 | |||
| f0c5ecab16 | |||
| 7739ac8254 | |||
| c229b9bc68 | |||
| 2ab0947550 | |||
| 116ccb0e84 | |||
| ce156e4acf |
@@ -0,0 +1,4 @@
|
|||||||
|
# yaml-language-server: $schema=https://json.schemastore.org/clang-format-21.x.json
|
||||||
|
---
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
IndentWidth: 2
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[{*.c,*.h}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[{Makefile.*,Makefile}]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 2
|
||||||
@@ -16,7 +16,18 @@ jobs:
|
|||||||
- name: install libs
|
- name: install libs
|
||||||
run: sudo apt install -y libglfw3-dev libgl-dev libv4l-dev libasound2-dev libbsd-dev
|
run: sudo apt install -y libglfw3-dev libgl-dev libv4l-dev libasound2-dev libbsd-dev
|
||||||
- name: gcc
|
- name: gcc
|
||||||
run: mkdir -p build && gcc -v -Wall -Wextra -Werror -Wno-format-truncation src/*.c src/*.h -lglfw -lGL -lm -lasound -lbsd -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE
|
run: mkdir -p build && gcc -v -Wall -Wextra -Werror -Wno-format-truncation src/*.c src/*.h -lglfw -lGL -lm -lasound -lbsd -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE -DVIDEO_IN
|
||||||
|
|
||||||
|
build-no-video:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
- name: install libs
|
||||||
|
run: sudo apt install -y libglfw3-dev libgl-dev libasound2-dev libbsd-dev
|
||||||
|
- name: gcc
|
||||||
|
run: mkdir -p build && gcc -v -Werror src/*.c src/*.h -lglfw -lGL -lm -lasound -lbsd -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE
|
||||||
|
|
||||||
build-release:
|
build-release:
|
||||||
needs: lint
|
needs: lint
|
||||||
|
|||||||
+1
-1
@@ -24,6 +24,6 @@ pkg
|
|||||||
forge-*
|
forge-*
|
||||||
confdeps.*
|
confdeps.*
|
||||||
conftest.*
|
conftest.*
|
||||||
forge_saved_state.txt
|
*.txt
|
||||||
error.glsl
|
error.glsl
|
||||||
draft/
|
draft/
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Path to sources
|
||||||
|
sonar.sources=src
|
||||||
|
#sonar.exclusions=
|
||||||
|
#sonar.inclusions=
|
||||||
|
|
||||||
|
# Path to tests
|
||||||
|
#sonar.tests=
|
||||||
|
#sonar.test.exclusions=
|
||||||
|
#sonar.test.inclusions=
|
||||||
|
|
||||||
|
# Source encoding
|
||||||
|
sonar.sourceEncoding=UTF-8
|
||||||
|
|
||||||
|
# Exclusions for copy-paste detection
|
||||||
|
#sonar.cpd.exclusions=
|
||||||
+17
-5
@@ -117,12 +117,24 @@ make -f Makefile.dev release-arch
|
|||||||
- [x] Printable PDF of default scr/fx
|
- [x] Printable PDF of default scr/fx
|
||||||
- [x] Add NanoKontrol setup file
|
- [x] Add NanoKontrol setup file
|
||||||
- [x] Find and fix opengl errors 0500 ?
|
- [x] Find and fix opengl errors 0500 ?
|
||||||
- [ ] Improvements
|
- [ ] Extra features
|
||||||
- [ ] Record show as text files
|
- [x] `--auto-random-cycle=4`
|
||||||
- [ ] Play from record text file
|
- [x] Arrows (up-down: bpm / left-right: cycle)
|
||||||
|
- [x] Save states (numkey: load / shift + numkey: save)
|
||||||
|
- [x] (clean) static functions at top of files
|
||||||
|
- [x] Configurable key codes
|
||||||
|
- [x] Monitor improvements
|
||||||
|
- [ ] Ignore some values in auto random
|
||||||
|
- [x] build without video in
|
||||||
|
- [ ] Auto discover video devices
|
||||||
|
- [ ] Update README monitor/keymap
|
||||||
|
- [ ] Auto reconnect midi input
|
||||||
|
- [ ] Auto reconnect video device
|
||||||
- [ ] Key codes as inputs
|
- [ ] Key codes as inputs
|
||||||
- [ ] Mouse position and scroll as inputs
|
- [ ] Mouse position and scroll as inputs
|
||||||
|
- [ ] Joystick as input
|
||||||
|
- [ ] Record show as text files
|
||||||
|
- [ ] Play from record text file
|
||||||
- [ ] Fixes
|
- [ ] Fixes
|
||||||
- [ ] Try to write NanoKontrol config
|
- [ ] Try to write NanoKontrol config
|
||||||
- [ ] Investigate video device fps loss (bad unregister ?)
|
- [x] Investigate video device fps loss (bad unregister ?)
|
||||||
- explore libv4l directly [github](https://github.com/philips/libv4l) (with `-lv4l2`)
|
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
AUTOMAKE_OPTIONS = foreign subdir-objects -Wall
|
AUTOMAKE_OPTIONS = foreign subdir-objects -Wall
|
||||||
bin_PROGRAMS = forge
|
bin_PROGRAMS = forge
|
||||||
forge_SOURCES = src/args.c src/arr.c src/config_file.c src/file.c src/forge.c src/main.c src/midi.c src/project.c src/rand.c src/shaders.c src/shared.c src/state.c src/string.c src/tempo.c src/timer.c src/video.c src/window.c $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/hashmap.c/hashmap.c $(top_srcdir)/log.c/src/log.c
|
forge_SOURCES = src/args.c src/arr.c src/config_file.c src/file.c src/forge.c src/main.c src/midi.c src/project.c src/rand.c src/shaders.c src/shared.c src/state.c src/string.c src/tempo.c src/timer.c src/video.c src/window.c $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/hashmap.c/hashmap.c $(top_srcdir)/log.c/src/log.c
|
||||||
forge_CFLAGS = -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays -fno-exceptions -fopenmp -I$(top_srcdir)/include -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE -DLOG_USE_COLOR -DDATADIR=\"$(datadir)/$(PACKAGE)\"
|
forge_CFLAGS = -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays -fno-exceptions -fopenmp -I$(top_srcdir)/include -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE -DLOG_USE_COLOR -DVIDEO_IN -DDATADIR=\"$(datadir)/$(PACKAGE)\"
|
||||||
forge_LDADD = -lm -lGL -lglfw -lasound -lbsd
|
forge_LDADD = -lm -lGL -lglfw -lasound -lbsd
|
||||||
include_HEADERS = src/args.h src/arr.h src/config.h src/config_file.h src/constants.h src/file.h src/forge.h src/main.h src/midi.h src/project.h src/rand.h src/shaders.h src/shared.h src/state.h src/string.h src/tempo.h src/timer.h src/types.h src/video.h src/window.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/include/linmath.h $(top_srcdir)/include/hashmap.h $(top_srcdir)/include/log.h
|
include_HEADERS = src/args.h src/arr.h src/config.h src/config_file.h src/constants.h src/file.h src/forge.h src/main.h src/midi.h src/project.h src/rand.h src/shaders.h src/shared.h src/state.h src/string.h src/tempo.h src/timer.h src/types.h src/video.h src/window.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/include/linmath.h $(top_srcdir)/include/hashmap.h $(top_srcdir)/include/log.h
|
||||||
|
|
||||||
EXTRA_DIST = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuv.glsl
|
EXTRA_DIST = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuyv.glsl
|
||||||
confdir = $(prefix)/share/$(PACKAGE)
|
confdir = $(prefix)/share/$(PACKAGE)
|
||||||
conf_DATA = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuv.glsl
|
conf_DATA = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuyv.glsl
|
||||||
+5
-1
@@ -21,9 +21,14 @@ build:
|
|||||||
-DGLFW_EXPOSE_NATIVE_EGL \
|
-DGLFW_EXPOSE_NATIVE_EGL \
|
||||||
-DGLFW_NATIVE_INCLUDE_NONE \
|
-DGLFW_NATIVE_INCLUDE_NONE \
|
||||||
-DLOG_USE_COLOR \
|
-DLOG_USE_COLOR \
|
||||||
|
-DVIDEO_IN \
|
||||||
-o build/$(TARGET) \
|
-o build/$(TARGET) \
|
||||||
-g -Og
|
-g -Og
|
||||||
|
|
||||||
|
.PHONY: format
|
||||||
|
format:
|
||||||
|
clang-format -i src/*
|
||||||
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run: build
|
run: build
|
||||||
./build/$(TARGET) $(TEST_ARGS) --monitor-only --internal-size=480 --video-size=240 --hot-reload
|
./build/$(TARGET) $(TEST_ARGS) --monitor-only --internal-size=480 --video-size=240 --hot-reload
|
||||||
@@ -100,4 +105,3 @@ release-arch: clean
|
|||||||
mkdir -p build
|
mkdir -p build
|
||||||
cp PKGBUILD build
|
cp PKGBUILD build
|
||||||
cd build && makepkg
|
cd build && makepkg
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
[](https://github.com/klemek/forge-steel/actions/workflows/ci.yml)
|
[](https://github.com/klemek/forge-steel/releases) [](https://github.com/klemek/forge-steel/releases) [](https://github.com/klemek/forge-steel/commits/master/) [](https://github.com/klemek/forge-steel/actions/workflows/ci.yml) [](https://sonarcloud.io/summary/new_code?id=klemek_forge-steel) 
|
||||||
[](https://sonarcloud.io/summary/new_code?id=klemek_forge-steel)
|
|
||||||
|
|
||||||
<!-- omit from toc -->
|
<!-- omit from toc -->
|
||||||
# F.O.R.G.E. (Steel)
|
# F.O.R.G.E. (Steel)
|
||||||
@@ -83,6 +82,7 @@ Here are some pointers if you want to customize your FORGE experience:
|
|||||||
- [My nanoKontrol2 is acting strange](#my-nanokontrol2-is-acting-strange)
|
- [My nanoKontrol2 is acting strange](#my-nanokontrol2-is-acting-strange)
|
||||||
- [How do I report a bug?](#how-do-i-report-a-bug)
|
- [How do I report a bug?](#how-do-i-report-a-bug)
|
||||||
- [Help I got low FPS on my video device](#help-i-got-low-fps-on-my-video-device)
|
- [Help I got low FPS on my video device](#help-i-got-low-fps-on-my-video-device)
|
||||||
|
- [My video feed got strange lines](#my-video-feed-got-strange-lines)
|
||||||
- [How do I change the default project built-in sentences?](#how-do-i-change-the-default-project-built-in-sentences)
|
- [How do I change the default project built-in sentences?](#how-do-i-change-the-default-project-built-in-sentences)
|
||||||
|
|
||||||
## What is FORGE ?
|
## What is FORGE ?
|
||||||
@@ -158,43 +158,55 @@ make install
|
|||||||
|
|
||||||
When running, the following hotkeys are available:
|
When running, the following hotkeys are available:
|
||||||
|
|
||||||
* <kbd>Esc</kbd>: Exit window
|
| Hotkey | Function |
|
||||||
* <kbd>R</kbd>: Randomize internal values
|
| ------ | -------- |
|
||||||
* <kbd>0</kbd>: Reset internal values to 0
|
| <kbd>Esc</kbd> | Exit FORGE |
|
||||||
* <kbd>D</kbd>: Demo mode On/Off
|
| <kbd>R</kbd> | Randomize internal values |
|
||||||
* <kbd>A</kbd>: Auto Random mode On/Off
|
| <kbd>Shift</kbd> + <kbd>R</kbd> | Reset internal values to 0 |
|
||||||
|
| <kbd>D</kbd> | Demo mode On/Off |
|
||||||
|
| <kbd>A</kbd> | Auto Random mode On/Off |
|
||||||
|
| <kbd>←</kbd> / <kbd>→</kbd> | Auto Random Cycle -/+ 1 |
|
||||||
|
| <kbd>↑</kbd> / <kbd>↓</kbd> | BPM +/- 1 |
|
||||||
|
| <kbd>0</kbd>-<kbd>9</kbd> | Load state 0 to 9 |
|
||||||
|
| <kbd>Shift</kbd> + <kbd>0</kbd>-<kbd>9</kbd> | Save state 0 to 9 |
|
||||||
|
|
||||||
|
These are configurable in the [`forge_project.cfg`](#forge_projectcfg).
|
||||||
|
|
||||||
### CLI arguments
|
### CLI arguments
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-v=FILE] [-vs=SIZE] [-is=SIZE] [-sf=STATE_PATH] [-ls / -nls] [-ss / -nss] [-tm] [-tf]
|
forge steel-dev
|
||||||
|
|
||||||
|
usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-arc=CYCLES] [-vi=FILE] [-vs=SIZE] [-vr / -nvr] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-tm] [-tf]
|
||||||
|
|
||||||
Fusion Of Real-time Generative Effects.
|
Fusion Of Real-time Generative Effects.
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
-v, --version print version
|
-v, --version print version
|
||||||
-p, --project forge project directory (default: /usr/share/forge/default)
|
-p, --project forge project directory (default: ./default)
|
||||||
-c, --config config file name (default: forge_project.cfg)
|
-c, --config config file name (default: forge_project.cfg)
|
||||||
-hr, --hot-reload hot reload of shaders scripts
|
-hr, --hot-reload hot reload of shaders scripts
|
||||||
-s, --screen output screen number (default: primary)
|
-s, --screen output screen number (default: primary)
|
||||||
-m, --monitor monitor screen number (default: none)
|
-m, --monitor monitor screen number (default: none)
|
||||||
-mo, --monitor-only no output screen
|
-mo, --monitor-only no output screen
|
||||||
-w, --windowed not fullscreen
|
-w, --windowed not fullscreen
|
||||||
-t, --tempo base tempo (default: 60)
|
-t, --tempo base tempo (default: 60)
|
||||||
-d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random)
|
-d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random)
|
||||||
-ar, --auto-random randomize state every 4 beats
|
-ar, --auto-random randomize state every cycle (4 beats)
|
||||||
-nar, --no-auto-random do not randomize state (default)
|
-nar, --no-auto-random do not randomize state (default)
|
||||||
-v, --video-in path to video capture device (multiple allowed)
|
-arc, --auto-random-cycle auto random cycle length (default: 4)
|
||||||
-vs, --video-size video capture desired height (default: internal texture height)
|
-vi, --video-in path to video capture device (multiple allowed)
|
||||||
-is, --internal-size internal texture height (default: 720)
|
-vs, --video-size video capture desired height (default: internal texture height)
|
||||||
-sf, --state-file saved state file (default: forge_saved_state.txt)
|
-vr, --video-reconnect auto-reconnect video (default)
|
||||||
-ls, --load-state load saved state (default)
|
-nvr, --no-video-reconnect do not auto-reconnect video
|
||||||
-nls, --no-load-state do not load saved state
|
-is, --internal-size internal texture height (default: 720)
|
||||||
-ss, --save-state save state (default)
|
-ls, --load-state load saved state (default)
|
||||||
-nss, --no-save-state do not save state
|
-nls, --no-load-state do not load saved state
|
||||||
-tm, --trace-midi print midi code and values
|
-ss, --save-state save state (default)
|
||||||
-tf, --trace-fps print fps status of subsystems
|
-nss, --no-save-state do not save state
|
||||||
|
-tm, --trace-midi print midi code and values
|
||||||
|
-tf, --trace-fps print fps status of subsystems
|
||||||
```
|
```
|
||||||
|
|
||||||
## Default Project
|
## Default Project
|
||||||
@@ -233,7 +245,7 @@ Working with pages and items, you can use the following predefined sources and e
|
|||||||
| **1** | **0** | Feedback + Thru | _Hue_ | _Saturation_ | _Light_ | Thru | _Hue_ | _Saturation_ | _Light_ |
|
| **1** | **0** | Feedback + Thru | _Hue_ | _Saturation_ | _Light_ | Thru | _Hue_ | _Saturation_ | _Light_ |
|
||||||
| | **1** | Lines | _Thick. / Dezoom_ | _Rotation_ | _Distortion_ | Feedback + Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
|
| | **1** | Lines | _Thick. / Dezoom_ | _Rotation_ | _Distortion_ | Feedback + Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
|
||||||
| | **2** | Dots | _Zoom_ | _Rotation_ | _Lens_ | Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
|
| | **2** | Dots | _Zoom_ | _Rotation_ | _Lens_ | Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
|
||||||
| | **3** | Waves | _Spacing_ | _Thickness_ | _Vert. Scroll (R)_ | Colorize | _Black Color_ | _White Color_ | _Shift_ |
|
| | **3** | Circuit | _Zoom_ | _H. connect_ | _V. connect_ | Colorize | _Black Color_ | _White Color_ | _Shift_ |
|
||||||
| | **4** | Noise | _Zoom_ | _Voronoi dist._ | _Details_ | Quantize | _Pixel Size_ | _Bit Depth_ | _Blur_ |
|
| | **4** | Noise | _Zoom_ | _Voronoi dist._ | _Details_ | Quantize | _Pixel Size_ | _Bit Depth_ | _Blur_ |
|
||||||
| **2** | **5** | Video In 1 + Thru | _Hue_ | _Saturation_ | _Light_ | Dithering | _Pixel Size_ | _Bit Depth_ | _Blur_ |
|
| **2** | **5** | Video In 1 + Thru | _Hue_ | _Saturation_ | _Light_ | Dithering | _Pixel Size_ | _Bit Depth_ | _Blur_ |
|
||||||
| | **6** | CP437 | _Zoom_ | _Charset_ | _Char. Delta_ | TV | _Lens_ | _Horz. Noise_ | _Dezoom_ |
|
| | **6** | CP437 | _Zoom_ | _Charset_ | _Char. Delta_ | TV | _Lens_ | _Horz. Noise_ | _Dezoom_ |
|
||||||
@@ -467,10 +479,22 @@ Don't forget to add all information available to your bug (version, operating sy
|
|||||||
|
|
||||||
### Help I got low FPS on my video device
|
### Help I got low FPS on my video device
|
||||||
|
|
||||||
There's already an [open issue](https://github.com/klemek/forge-steel/issues/1) on this subject.
|
Unfortunately, V4L2 is very slow compared to driver-specific decoding.
|
||||||
|
|
||||||
|
You can check your device real FPS on [V4L2 UCP](https://github.com/HedgeHawk/v4l2ucp) or [GTK UVC Viewer](https://github.com/jaswdr/guvcview).
|
||||||
|
|
||||||
|
### My video feed got strange lines
|
||||||
|
|
||||||
|
You need to decode the [V4L2 YUYV format](https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-yuyv.html).
|
||||||
|
|
||||||
|
The code is available in the default project [default/inc_yuyv.glsl](./default/inc_yuyv.glsl)
|
||||||
|
|
||||||
### How do I change the default project built-in sentences?
|
### How do I change the default project built-in sentences?
|
||||||
|
|
||||||
The sentences are defined in [default/inc_sentences.glsl](./default/inc_sentences.glsl).
|
The sentences are defined in [default/inc_sentences.glsl](./default/inc_sentences.glsl).
|
||||||
|
|
||||||
The script [scripts/sentences.py](./scripts/sentences.py) can help you update them.
|
The script [scripts/sentences.py](./scripts/sentences.py) can help you update them.
|
||||||
|
|
||||||
|
### My video device keeps changing ID each time it's unplugged
|
||||||
|
|
||||||
|
You should [bind your device to a fixed interface](https://linuxvox.com/blog/linux-bind-camera-to-fixed-devvideo/).
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
-Iinclude
|
-Iinclude
|
||||||
-DGLFW_INCLUDE_NONE
|
-DGLFW_INCLUDE_NONE
|
||||||
-DGLFW_EXPOSE_NATIVE_EGL
|
-DGLFW_EXPOSE_NATIVE_EGL
|
||||||
-DGLFW_NATIVE_INCLUDE_NONE
|
-DGLFW_NATIVE_INCLUDE_NONE
|
||||||
|
-DVIDEO_IN
|
||||||
@@ -37,6 +37,8 @@ UNIFORM_IN_FPS_PREFIX=iInputFPS
|
|||||||
UNIFORM_DEMO=iDemo
|
UNIFORM_DEMO=iDemo
|
||||||
# 0/1 if auto random
|
# 0/1 if auto random
|
||||||
UNIFORM_AUTORAND=iAutoRand
|
UNIFORM_AUTORAND=iAutoRand
|
||||||
|
# auto random cycle length
|
||||||
|
UNIFORM_AUTORANDCYCLE=iAutoRandCycle
|
||||||
# Current page
|
# Current page
|
||||||
UNIFORM_PAGE=iPage
|
UNIFORM_PAGE=iPage
|
||||||
# Current selected shader
|
# Current selected shader
|
||||||
@@ -49,6 +51,8 @@ UNIFORM_STATE_PREFIX=iState
|
|||||||
UNIFORM_ACTIVE_PREFIX=iActive
|
UNIFORM_ACTIVE_PREFIX=iActive
|
||||||
# Input X format raw integer value
|
# Input X format raw integer value
|
||||||
UNIFORM_IN_FORMAT_PREFIX=iInputFormat
|
UNIFORM_IN_FORMAT_PREFIX=iInputFormat
|
||||||
|
# Input X should use swap texture or not (0/1)
|
||||||
|
UNIFORM_IN_SWAP_PREFIX=iInputSwap
|
||||||
|
|
||||||
# --- uniform vec2 ---
|
# --- uniform vec2 ---
|
||||||
|
|
||||||
@@ -91,7 +95,7 @@ SUB_2_PREFIX=fx_
|
|||||||
|
|
||||||
|
|
||||||
# Total number of internal textures
|
# Total number of internal textures
|
||||||
TEX_COUNT=10
|
TEX_COUNT=12
|
||||||
|
|
||||||
# === VIDEO DEVICES
|
# === VIDEO DEVICES
|
||||||
# Video devices will be read from CLI arguments
|
# Video devices will be read from CLI arguments
|
||||||
@@ -102,10 +106,12 @@ IN_COUNT=2
|
|||||||
# To which texture will be bound video device X
|
# To which texture will be bound video device X
|
||||||
IN_1_OUT=1
|
IN_1_OUT=1
|
||||||
IN_2_OUT=2
|
IN_2_OUT=2
|
||||||
|
# To which texture will be bound swap buffers (for double-buffering)
|
||||||
|
IN_1_SWAP_OUT=3
|
||||||
|
IN_2_SWAP_OUT=4
|
||||||
|
|
||||||
# === FRAGMENT SHADERS
|
# === FRAGMENT SHADERS
|
||||||
# Fragment shaders will be read from the CLI directory as "fragX.glsl"
|
# Fragment shaders will be read from the CLI directory as "fragX.glsl"
|
||||||
# Special shader "frag0.glsl" will be prepend to each one
|
|
||||||
|
|
||||||
# Prefix of fragment shaders to detect
|
# Prefix of fragment shaders to detect
|
||||||
FRAG_FILE_PREFIX=frag
|
FRAG_FILE_PREFIX=frag
|
||||||
@@ -114,13 +120,13 @@ FRAG_FILE_PREFIX=frag
|
|||||||
FRAG_COUNT=10
|
FRAG_COUNT=10
|
||||||
|
|
||||||
# To which texture will the shader fragX.glsl will render to
|
# To which texture will the shader fragX.glsl will render to
|
||||||
FRAG_1_OUT=3
|
FRAG_1_OUT=5
|
||||||
FRAG_2_OUT=4
|
FRAG_2_OUT=6
|
||||||
FRAG_3_OUT=5
|
FRAG_3_OUT=7
|
||||||
FRAG_4_OUT=6
|
FRAG_4_OUT=8
|
||||||
FRAG_5_OUT=7
|
FRAG_5_OUT=9
|
||||||
FRAG_6_OUT=8
|
FRAG_6_OUT=10
|
||||||
FRAG_7_OUT=9
|
FRAG_7_OUT=11
|
||||||
FRAG_8_OUT=0
|
FRAG_8_OUT=0
|
||||||
# Which fragment shader renders to output window
|
# Which fragment shader renders to output window
|
||||||
FRAG_OUTPUT=9
|
FRAG_OUTPUT=9
|
||||||
@@ -262,3 +268,66 @@ MIDI_3_1_Z=
|
|||||||
MIDI_3_2_X=0
|
MIDI_3_2_X=0
|
||||||
MIDI_3_2_Y=16
|
MIDI_3_2_Y=16
|
||||||
MIDI_3_2_Z=
|
MIDI_3_2_Z=
|
||||||
|
|
||||||
|
# =====
|
||||||
|
# OTHER
|
||||||
|
# =====
|
||||||
|
|
||||||
|
# === SAVE FILES
|
||||||
|
# When loading/saving from last run or using save states
|
||||||
|
SAVE_FILE_PREFIX=forge_default_save
|
||||||
|
|
||||||
|
# === HOTKEYS
|
||||||
|
# You can change the default keycodes used on runtime
|
||||||
|
# Modifiers are encoded like this:
|
||||||
|
# 1000 -> shift
|
||||||
|
# 10000 -> control
|
||||||
|
# 100000 -> alt
|
||||||
|
# This means 110082 is control+alt+R
|
||||||
|
|
||||||
|
# R on (qwerty)
|
||||||
|
HOTKEY_RANDOMIZE=82
|
||||||
|
# SHIFT+R (qwerty)
|
||||||
|
HOTKEY_RESET=1082
|
||||||
|
# D (qwerty)
|
||||||
|
HOTKEY_DEMO=68
|
||||||
|
# A (qwerty)
|
||||||
|
HOTKEY_AUTORAND=65
|
||||||
|
# Left arrow
|
||||||
|
HOTKEY_AUTORAND_DOWN=263
|
||||||
|
# Right arrow
|
||||||
|
HOTKEY_AUTORAND_UP=262
|
||||||
|
# Down arrow
|
||||||
|
HOTKEY_TEMPO_DOWN=264
|
||||||
|
# Up arrow
|
||||||
|
HOTKEY_TEMPO_UP=265
|
||||||
|
|
||||||
|
# Number of load states keys
|
||||||
|
HOTKEY_LOAD_COUNT=10
|
||||||
|
|
||||||
|
# 1 to 9 then 0 keys
|
||||||
|
HOTKEY_LOAD_1=49
|
||||||
|
HOTKEY_LOAD_2=50
|
||||||
|
HOTKEY_LOAD_3=51
|
||||||
|
HOTKEY_LOAD_4=52
|
||||||
|
HOTKEY_LOAD_5=53
|
||||||
|
HOTKEY_LOAD_6=54
|
||||||
|
HOTKEY_LOAD_7=55
|
||||||
|
HOTKEY_LOAD_8=56
|
||||||
|
HOTKEY_LOAD_9=57
|
||||||
|
HOTKEY_LOAD_10=48
|
||||||
|
|
||||||
|
# Number of save states keys
|
||||||
|
HOTKEY_SAVE_COUNT=10
|
||||||
|
|
||||||
|
# 1 to 9 then 0 keys with shift
|
||||||
|
HOTKEY_SAVE_1=1049
|
||||||
|
HOTKEY_SAVE_2=1050
|
||||||
|
HOTKEY_SAVE_3=1051
|
||||||
|
HOTKEY_SAVE_4=1052
|
||||||
|
HOTKEY_SAVE_5=1053
|
||||||
|
HOTKEY_SAVE_6=1054
|
||||||
|
HOTKEY_SAVE_7=1055
|
||||||
|
HOTKEY_SAVE_8=1056
|
||||||
|
HOTKEY_SAVE_9=1057
|
||||||
|
HOTKEY_SAVE_10=1048
|
||||||
+11
-5
@@ -2,23 +2,29 @@
|
|||||||
|
|
||||||
// VIDEO 1
|
// VIDEO 1
|
||||||
// -----------
|
// -----------
|
||||||
// IN: 1 (RAW IN A)
|
// IN: 1+3 (RAW IN A)
|
||||||
// OUT: 3 (IN A)
|
// OUT: 5 (IN A)
|
||||||
|
|
||||||
in vec2 vUV;
|
in vec2 vUV;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
#include inc_yuv.glsl
|
#include inc_yuyv.glsl
|
||||||
|
|
||||||
uniform sampler2D iTex0;
|
uniform sampler2D iTex0;
|
||||||
uniform sampler2D iTex1;
|
uniform sampler2D iTex1;
|
||||||
|
uniform sampler2D iTex3;
|
||||||
uniform int iInputFormat1;
|
uniform int iInputFormat1;
|
||||||
|
uniform int iInputSwap1;
|
||||||
uniform vec2 iInputResolution1;
|
uniform vec2 iInputResolution1;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
if (iInputFormat1 == YUYV_FOURCC) {
|
if (iInputFormat1 == YUYV_FOURCC) {
|
||||||
fragColor = yuyvTex(iTex1, vUV, int(iInputResolution1.x));
|
if (iInputSwap1 > 0) {
|
||||||
|
fragColor = yuyvTex(iTex3, vUV, int(iInputResolution1.x));
|
||||||
|
} else {
|
||||||
|
fragColor = yuyvTex(iTex1, vUV, int(iInputResolution1.x));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fragColor = texture(iTex0, vUV);
|
fragColor = texture(iTex0, vUV);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+84
-50
@@ -9,24 +9,23 @@ out vec4 fragColor;
|
|||||||
#include inc_debug.glsl
|
#include inc_debug.glsl
|
||||||
|
|
||||||
uniform sampler2D iTex0;
|
uniform sampler2D iTex0;
|
||||||
uniform sampler2D iTex1;
|
|
||||||
uniform sampler2D iTex2;
|
|
||||||
uniform sampler2D iTex3;
|
|
||||||
uniform sampler2D iTex4;
|
|
||||||
uniform sampler2D iTex5;
|
uniform sampler2D iTex5;
|
||||||
uniform sampler2D iTex6;
|
uniform sampler2D iTex6;
|
||||||
uniform sampler2D iTex7;
|
uniform sampler2D iTex7;
|
||||||
uniform sampler2D iTex8;
|
uniform sampler2D iTex8;
|
||||||
uniform sampler2D iTex9;
|
uniform sampler2D iTex9;
|
||||||
|
uniform sampler2D iTex10;
|
||||||
|
uniform sampler2D iTex11;
|
||||||
|
uniform int iFPS;
|
||||||
uniform int iInputFPS1;
|
uniform int iInputFPS1;
|
||||||
uniform int iInputFPS2;
|
uniform int iInputFPS2;
|
||||||
|
|
||||||
float s(vec2 uv, float x0, float y0) {
|
float s(vec2 uv, float x0, float y0) {
|
||||||
return step(x0, uv.x) * step(-x0 - 1, -uv.x) * step(y0, uv.y) *
|
return step(x0, uv.x) * step(-x0 - 1, -uv.x) * step(y0, uv.y) *
|
||||||
step(-y0 - 1, -uv.y);
|
step(-y0 - 1, -uv.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int texts[10][5] = {
|
const int texts[12][5] = {
|
||||||
{0x49, 0x4E, 0x20, 0x41, 0x00}, // IN A
|
{0x49, 0x4E, 0x20, 0x41, 0x00}, // IN A
|
||||||
{0x49, 0x4E, 0x20, 0x42, 0x00}, // IN B
|
{0x49, 0x4E, 0x20, 0x42, 0x00}, // IN B
|
||||||
{0x53, 0x52, 0x43, 0x20, 0x41}, // SRC A
|
{0x53, 0x52, 0x43, 0x20, 0x41}, // SRC A
|
||||||
@@ -37,6 +36,8 @@ const int texts[10][5] = {
|
|||||||
{0x4D, 0x46, 0x58, 0x00, 0x00}, // MFX
|
{0x4D, 0x46, 0x58, 0x00, 0x00}, // MFX
|
||||||
{0x46, 0x50, 0x53, 0x00, 0x00}, // FPS
|
{0x46, 0x50, 0x53, 0x00, 0x00}, // FPS
|
||||||
{0x4F, 0x46, 0x46, 0x00, 0x00}, // OFF
|
{0x4F, 0x46, 0x46, 0x00, 0x00}, // OFF
|
||||||
|
{0x44, 0x45, 0x4D, 0x4F, 0x00}, // DEMO
|
||||||
|
{0x4C, 0x49, 0x56, 0x45, 0x00}, // LIVE
|
||||||
};
|
};
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@@ -48,57 +49,90 @@ void main() {
|
|||||||
vec2 uv3 = uv1 * 60;
|
vec2 uv3 = uv1 * 60;
|
||||||
|
|
||||||
vec4 c = vec4(0);
|
vec4 c = vec4(0);
|
||||||
|
|
||||||
c += s(uv2,1,2) * texture(iTex5, uv2);
|
|
||||||
c += s(uv2,2,2) * texture(iTex7, uv2);
|
|
||||||
|
|
||||||
c += s(uv2,1,1) * texture(iTex6, uv2);
|
c += s(uv2, 1, 2) * texture(iTex7, uv2);
|
||||||
c += s(uv2,2,1) * texture(iTex8, uv2);
|
c += s(uv2, 2, 2) * texture(iTex9, uv2);
|
||||||
|
|
||||||
c += s(uv2,0,0) * debug(mod(uv2, 1));
|
c += s(uv2, 1, 0) * texture(iTex8, uv2);
|
||||||
c += s(uv2,1,0) * texture(iTex9, uv2);
|
c += s(uv2, 2, 0) * texture(iTex10, uv2);
|
||||||
c += s(uv2,2,0) * texture(iTex0, uv2);
|
|
||||||
|
c += s(uv2, 0, 1) * debug(mod(uv2, 1));
|
||||||
|
c += s(uv2, 1, 1) * texture(iTex11, uv2);
|
||||||
|
c += s(uv2, 2, 1) * texture(iTex0, uv2);
|
||||||
|
|
||||||
|
float sel = 0;
|
||||||
|
|
||||||
|
sel += iSelected == 3 ? h_rect(uv2, vec2(1.5, 2.5), vec2(0.5), 0.01) : 0;
|
||||||
|
sel += iSelected == 4 ? h_rect(uv2, vec2(1.5, 0.5), vec2(0.5), 0.01) : 0;
|
||||||
|
sel += iSelected == 5 ? h_rect(uv2, vec2(2.5, 2.5), vec2(0.5), 0.01) : 0;
|
||||||
|
sel += iSelected == 6 ? h_rect(uv2, vec2(2.5, 0.5), vec2(0.5), 0.01) : 0;
|
||||||
|
sel += iSelected == 8 ? h_rect(uv2, vec2(2.5, 1.5), vec2(0.5), 0.01) : 0;
|
||||||
|
|
||||||
|
c = mix(c, 1 - c, sel);
|
||||||
|
|
||||||
float f = 0;
|
float f = 0;
|
||||||
float t = 0;
|
float t = 0;
|
||||||
|
|
||||||
f += rect(uv3, vec2(-51, 28.5), vec2(2.1, 0.7));
|
f += rect(uv3, vec2(-35, 28.5), vec2(2.1, 0.7));
|
||||||
t += write_5(uv3, vec2(-53,28), texts[0]);
|
t += write_5(uv3, vec2(-37, 28), texts[0]);
|
||||||
|
|
||||||
if (iInputResolution1.x > 0) {
|
|
||||||
c += s(uv2,0,2) * texture(iTex3, uv2);
|
|
||||||
f += rect(uv3, vec2(-50.4, 26.5), vec2(2.8, 0.7));
|
|
||||||
t += write_int(uv3, vec2(-53,26), iInputFPS1, 2);
|
|
||||||
t += write_5(uv3, vec2(-50.5,26), texts[8]);
|
|
||||||
} else {
|
|
||||||
f += rect(uv3, vec2(-51.5, 26.5), vec2(1.6, 0.7));
|
|
||||||
t += write_5(uv3, vec2(-53,26), texts[9]);
|
|
||||||
}
|
|
||||||
|
|
||||||
f += rect(uv3, vec2(-51, 8.5), vec2(2.1, 0.7));
|
|
||||||
t += write_5(uv3, vec2(-53,8), texts[1]);
|
|
||||||
|
|
||||||
if (iInputResolution2.x > 0) {
|
if (iInputFormat1 == YUYV_FOURCC) {
|
||||||
c += s(uv2,0,1) * texture(iTex4, uv2);
|
c += s(uv2, 0, 2) * texture(iTex5, uv2);
|
||||||
f += rect(uv3, vec2(-50.4, 6.5), vec2(2.8, 0.7));
|
f += rect(uv3, vec2(-35, 26.75), vec2(2.8, 0.7));
|
||||||
t += write_int(uv3, vec2(-53,6), iInputFPS2, 2);
|
t += write_int(uv3, vec2(-37.6, 26.1), iInputFPS1, 2);
|
||||||
t += write_5(uv3, vec2(-50.5,6), texts[8]);
|
t += write_5(uv3, vec2(-35.1, 26.1), texts[8]);
|
||||||
} else {
|
} else {
|
||||||
f += rect(uv3, vec2(-51.5, 6.5), vec2(1.6, 0.7));
|
f += rect(uv3, vec2(-35, 26.75), vec2(1.6, 0.7));
|
||||||
t += write_5(uv3, vec2(-53,6), texts[9]);
|
t += write_5(uv3, vec2(-36.5, 26.1), texts[9]);
|
||||||
}
|
}
|
||||||
f += rect(uv3, vec2(-14.5, 28.5), vec2(2.6, 0.7));
|
|
||||||
t += write_5(uv3, vec2(-17,28), texts[2]);
|
|
||||||
f += rect(uv3, vec2(-14.5, 8.5), vec2(2.6, 0.7));
|
|
||||||
t += write_5(uv3, vec2(-17,8), texts[3]);
|
|
||||||
f += rect(uv3, vec2(21, 28.5), vec2(2.1, 0.7));
|
|
||||||
t += write_5(uv3, vec2(19,28), texts[4]);
|
|
||||||
f += rect(uv3, vec2(21, 8.5), vec2(2.1, 0.7));
|
|
||||||
t += write_5(uv3, vec2(19,8), texts[5]);
|
|
||||||
f += rect(uv3, vec2(-15.5, -11.5), vec2(1.6, 0.7));
|
|
||||||
t += write_5(uv3, vec2(-17,-12), texts[6]);
|
|
||||||
f += rect(uv3, vec2(20.5, -11.5), vec2(1.6, 0.7));
|
|
||||||
t += write_5(uv3, vec2(19,-12), texts[7]);
|
|
||||||
|
|
||||||
fragColor = mix(c, vec4(f - t), f);
|
f += rect(uv3, vec2(-35, -11.5), vec2(2.1, 0.7));
|
||||||
}
|
t += write_5(uv3, vec2(-37, -12), texts[1]);
|
||||||
|
|
||||||
|
if (iInputFormat2 == YUYV_FOURCC) {
|
||||||
|
c += s(uv2, 0, 0) * texture(iTex6, uv2);
|
||||||
|
f += rect(uv3, vec2(-35, -13.25), vec2(2.8, 0.7));
|
||||||
|
t += write_int(uv3, vec2(-37.6, -13.9), iInputFPS2, 2);
|
||||||
|
t += write_5(uv3, vec2(-35.1, -13.9), texts[8]);
|
||||||
|
} else {
|
||||||
|
f += rect(uv3, vec2(-35, -13.25), vec2(1.6, 0.7));
|
||||||
|
t += write_5(uv3, vec2(-36.5, -13.9), texts[9]);
|
||||||
|
}
|
||||||
|
|
||||||
|
f += rect(uv3, vec2(-35, 8.5), vec2(2.1, 0.7));
|
||||||
|
|
||||||
|
if (iDemo > 0) {
|
||||||
|
t += write_5(uv3, vec2(-37, 8), texts[10]);
|
||||||
|
} else {
|
||||||
|
t += write_5(uv3, vec2(-37, 8), texts[11]);
|
||||||
|
}
|
||||||
|
|
||||||
|
f += rect(uv3, vec2(0, 28.5), vec2(2.6, 0.7));
|
||||||
|
f += iActive1 == 1 ? h_rect(uv3, vec2(0, 28.5), vec2(3, 1), 0.2) : 0;
|
||||||
|
t += write_5(uv3, vec2(-2.5, 28), texts[2]);
|
||||||
|
|
||||||
|
f += rect(uv3, vec2(0, -11.5), vec2(2.6, 0.7));
|
||||||
|
f += iActive1 == 2 ? h_rect(uv3, vec2(0, -11.5), vec2(3, 1), 0.2) : 0;
|
||||||
|
t += write_5(uv3, vec2(-2.5, -12), texts[3]);
|
||||||
|
|
||||||
|
f += rect(uv3, vec2(35, 28.5), vec2(2.1, 0.7));
|
||||||
|
f += iActive2 == 1 ? h_rect(uv3, vec2(35, 28.5), vec2(2.5, 1), 0.2) : 0;
|
||||||
|
t += write_5(uv3, vec2(33, 28), texts[4]);
|
||||||
|
|
||||||
|
f += rect(uv3, vec2(35, -11.5), vec2(2.1, 0.7));
|
||||||
|
f += iActive2 == 2 ? h_rect(uv3, vec2(35, -11.5), vec2(2.5, 1), 0.2) : 0;
|
||||||
|
t += write_5(uv3, vec2(33, -12), texts[5]);
|
||||||
|
|
||||||
|
f += rect(uv3, vec2(0, 8.5), vec2(1.6, 0.7));
|
||||||
|
t += write_5(uv3, vec2(-1.5, 8), texts[6]);
|
||||||
|
|
||||||
|
f += rect(uv3, vec2(35, 8.5), vec2(1.6, 0.7));
|
||||||
|
f += iActive2 == 3 ? h_rect(uv3, vec2(35, 8.5), vec2(2, 1), 0.2) : 0;
|
||||||
|
t += write_5(uv3, vec2(33.5, 8), texts[7]);
|
||||||
|
|
||||||
|
f += rect(uv3, vec2(35, 6.75), vec2(2.8, 0.7));
|
||||||
|
t += write_int(uv3, vec2(32.4, 6.1), iFPS, 2);
|
||||||
|
t += write_5(uv3, vec2(34.9, 6.1), texts[8]);
|
||||||
|
|
||||||
|
fragColor = mix(c, vec4(min(1, f) - t), min(1, f));
|
||||||
|
}
|
||||||
|
|||||||
+11
-5
@@ -2,23 +2,29 @@
|
|||||||
|
|
||||||
// VIDEO 2
|
// VIDEO 2
|
||||||
// -----------
|
// -----------
|
||||||
// IN: 2 (RAW IN B)
|
// IN: 2+4 (RAW IN B)
|
||||||
// OUT: 4 (IN B)
|
// OUT: 6 (IN B)
|
||||||
|
|
||||||
in vec2 vUV;
|
in vec2 vUV;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
#include inc_yuv.glsl
|
#include inc_yuyv.glsl
|
||||||
|
|
||||||
uniform sampler2D iTex0;
|
uniform sampler2D iTex0;
|
||||||
uniform sampler2D iTex2;
|
uniform sampler2D iTex2;
|
||||||
|
uniform sampler2D iTex4;
|
||||||
uniform int iInputFormat2;
|
uniform int iInputFormat2;
|
||||||
|
uniform int iInputSwap2;
|
||||||
uniform vec2 iInputResolution2;
|
uniform vec2 iInputResolution2;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
if (iInputFormat2 == YUYV_FOURCC) {
|
if (iInputFormat2 == YUYV_FOURCC) {
|
||||||
fragColor = yuyvTex(iTex2, vUV, int(iInputResolution2.x));
|
if (iInputSwap2 > 0) {
|
||||||
|
fragColor = yuyvTex(iTex4, vUV, int(iInputResolution2.x));
|
||||||
|
} else {
|
||||||
|
fragColor = yuyvTex(iTex2, vUV, int(iInputResolution2.x));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fragColor = texture(iTex0, vUV);
|
fragColor = texture(iTex0, vUV);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
// SRC A
|
// SRC A
|
||||||
// -----------
|
// -----------
|
||||||
// OUT: 5 (FX A)
|
// OUT: 7 (FX A)
|
||||||
|
|
||||||
in vec2 vUV;
|
in vec2 vUV;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
@@ -17,4 +17,4 @@ uniform vec3 iMidi1_1[6];
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
fragColor = src_stage(vUV, iSeed3, iMidi1_1[0], iMidi1_1[1].xy, iMidi1_1[2], iMidi1_1[3].xy, iMidi1_1[4], iMidi1_1[5].xy);
|
fragColor = src_stage(vUV, iSeed3, iMidi1_1[0], iMidi1_1[1].xy, iMidi1_1[2], iMidi1_1[3].xy, iMidi1_1[4], iMidi1_1[5].xy);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// SRC B
|
// SRC B
|
||||||
// -----------
|
// -----------
|
||||||
// OUT: 6 (FX B)
|
// OUT: 8 (FX B)
|
||||||
|
|
||||||
in vec2 vUV;
|
in vec2 vUV;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
@@ -16,4 +16,4 @@ uniform vec3 iMidi1_2[6];
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
fragColor = src_stage(vUV, iSeed4, iMidi1_2[0], iMidi1_2[1].xy, iMidi1_2[2], iMidi1_2[3].xy, iMidi1_2[4], iMidi1_2[5].xy);
|
fragColor = src_stage(vUV, iSeed4, iMidi1_2[0], iMidi1_2[1].xy, iMidi1_2[2], iMidi1_2[3].xy, iMidi1_2[4], iMidi1_2[5].xy);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -2,20 +2,20 @@
|
|||||||
|
|
||||||
// FX A
|
// FX A
|
||||||
// -------------
|
// -------------
|
||||||
// IN: 5 (SRC A)
|
// IN: 7 (SRC A)
|
||||||
// IN: 7 (FX A)
|
// IN: 9 (FX A)
|
||||||
// OUT: 7 (A+B)
|
// OUT: 9 (A+B)
|
||||||
|
|
||||||
in vec2 vUV;
|
in vec2 vUV;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
#include inc_fx.glsl
|
#include inc_fx.glsl
|
||||||
|
|
||||||
uniform sampler2D iTex5;
|
|
||||||
uniform sampler2D iTex7;
|
uniform sampler2D iTex7;
|
||||||
|
uniform sampler2D iTex9;
|
||||||
uniform int iSeed5;
|
uniform int iSeed5;
|
||||||
uniform vec3 iMidi2_1[7];
|
uniform vec3 iMidi2_1[7];
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
fragColor = fx_stage(vUV, iTex5, iTex7, iSeed5, iMidi2_1[0], iMidi2_1[1].xy, iMidi2_1[2], iMidi2_1[3].xy, iMidi2_1[4], iMidi2_1[5].xy, iMidi2_1[6]);
|
fragColor = fx_stage(vUV, iTex7, iTex9, iSeed5, iMidi2_1[0], iMidi2_1[1].xy, iMidi2_1[2], iMidi2_1[3].xy, iMidi2_1[4], iMidi2_1[5].xy, iMidi2_1[6]);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -2,20 +2,20 @@
|
|||||||
|
|
||||||
// FX B
|
// FX B
|
||||||
// -------------
|
// -------------
|
||||||
// IN: 6 (SRC B)
|
// IN: 8 (SRC B)
|
||||||
// IN: 8 (FX B)
|
// IN: 10 (FX B)
|
||||||
// OUT: 8 (A+B)
|
// OUT: 10 (A+B)
|
||||||
|
|
||||||
in vec2 vUV;
|
in vec2 vUV;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
#include inc_fx.glsl
|
#include inc_fx.glsl
|
||||||
|
|
||||||
uniform sampler2D iTex6;
|
|
||||||
uniform sampler2D iTex8;
|
uniform sampler2D iTex8;
|
||||||
|
uniform sampler2D iTex10;
|
||||||
uniform int iSeed6;
|
uniform int iSeed6;
|
||||||
uniform vec3 iMidi2_2[7];
|
uniform vec3 iMidi2_2[7];
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
fragColor = fx_stage(vUV, iTex6, iTex8, iSeed6, iMidi2_2[0], iMidi2_2[1].xy, iMidi2_2[2], iMidi2_2[3].xy, iMidi2_2[4], iMidi2_2[5].xy, iMidi2_2[6]);
|
fragColor = fx_stage(vUV, iTex8, iTex10, iSeed6, iMidi2_2[0], iMidi2_2[1].xy, iMidi2_2[2], iMidi2_2[3].xy, iMidi2_2[4], iMidi2_2[5].xy, iMidi2_2[6]);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-9
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
// A+B
|
// A+B
|
||||||
// ------------
|
// ------------
|
||||||
// IN: 7 (FX A)
|
// IN: 9 (FX A)
|
||||||
// IN: 8 (FX B)
|
// IN: 10 (FX B)
|
||||||
// OUT: 9 (MFX)
|
// OUT: 11 (MFX)
|
||||||
|
|
||||||
in vec2 vUV;
|
in vec2 vUV;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
@@ -13,8 +13,8 @@ out vec4 fragColor;
|
|||||||
#include inc_functions.glsl
|
#include inc_functions.glsl
|
||||||
|
|
||||||
uniform int iDemo;
|
uniform int iDemo;
|
||||||
uniform sampler2D iTex7;
|
uniform sampler2D iTex9;
|
||||||
uniform sampler2D iTex8;
|
uniform sampler2D iTex10;
|
||||||
uniform int iSeed7;
|
uniform int iSeed7;
|
||||||
uniform vec3 iMidi3_1[2];
|
uniform vec3 iMidi3_1[2];
|
||||||
|
|
||||||
@@ -22,12 +22,16 @@ void main() {
|
|||||||
float mix_value = magic(iMidi3_1[1].xy, vec3(1, 0, 0), iSeed7);
|
float mix_value = magic(iMidi3_1[1].xy, vec3(1, 0, 0), iSeed7);
|
||||||
bool mix_type = magic_trigger(vec3(iMidi3_1[0].x, 0, 0), iSeed7 + 10);
|
bool mix_type = magic_trigger(vec3(iMidi3_1[0].x, 0, 0), iSeed7 + 10);
|
||||||
|
|
||||||
vec4 color_a = texture(iTex7, vUV);
|
vec4 color_a = texture(iTex9, vUV);
|
||||||
vec4 color_b = texture(iTex8, vUV);
|
vec4 color_b = texture(iTex10, vUV);
|
||||||
|
|
||||||
float k = mean(color_a);
|
float k = mean(color_a);
|
||||||
|
|
||||||
mix_value = mix(mix_value, mix_value * 0.9 + 0.05, iDemo);
|
mix_value = mix(mix_value, mix_value * 0.9 + 0.05, iDemo);
|
||||||
|
|
||||||
fragColor = mix(color_b, color_a, mix_type ? step(mix_value, k) : mix_value);
|
if (mix_type) {
|
||||||
}
|
fragColor = mix(color_a, color_b, step(mix_value, k));
|
||||||
|
} else {
|
||||||
|
fragColor = mix(color_b, color_a, mix_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+9
-5
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// MFX
|
// MFX
|
||||||
// ------------
|
// ------------
|
||||||
// IN: 9 (A+B)
|
// IN: 11 (A+B)
|
||||||
// IN: 0 (OUT)
|
// IN: 0 (OUT)
|
||||||
// OUT: 0 (OUT)
|
// OUT: 0 (OUT)
|
||||||
|
|
||||||
@@ -11,16 +11,20 @@ out vec4 fragColor;
|
|||||||
|
|
||||||
#include inc_fx.glsl
|
#include inc_fx.glsl
|
||||||
|
|
||||||
uniform sampler2D iTex9;
|
uniform sampler2D iTex11;
|
||||||
uniform sampler2D iTex0;
|
uniform sampler2D iTex0;
|
||||||
uniform int iSeed8;
|
uniform int iSeed8;
|
||||||
uniform vec3 iMidi2_3[7];
|
uniform vec3 iMidi2_3[7];
|
||||||
uniform vec3 iMidi3_1[2];
|
uniform vec3 iMidi3_1[2];
|
||||||
|
uniform int iDemo;
|
||||||
|
uniform int iAutoRand;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 color = fx_stage(vUV, iTex9, iTex0, iSeed8, iMidi2_3[0], iMidi2_3[1].xy, iMidi2_3[2], iMidi2_3[3].xy, iMidi2_3[4], iMidi2_3[5].xy, iMidi2_3[6]);
|
vec4 color = fx_stage(vUV, iTex11, iTex0, iSeed8, iMidi2_3[0], iMidi2_3[1].xy, iMidi2_3[2], iMidi2_3[3].xy, iMidi2_3[4], iMidi2_3[5].xy, iMidi2_3[6]);
|
||||||
|
|
||||||
color = mix(color, vec4(0), iMidi3_1[0].y);
|
if (iDemo < 1 && iAutoRand < 1) {
|
||||||
|
color = mix(color, vec4(0), iMidi3_1[0].y);
|
||||||
|
}
|
||||||
|
|
||||||
fragColor = color;
|
fragColor = color;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -10,4 +10,4 @@ uniform sampler2D iTex0;
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
fragColor = texture(iTex0, vUV);
|
fragColor = texture(iTex0, vUV);
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-5
@@ -94,7 +94,7 @@ const int cp437[] = {
|
|||||||
0xE333, 0x1333, 0x0ECC, 0x0100, // 0x59, Y
|
0xE333, 0x1333, 0x0ECC, 0x0100, // 0x59, Y
|
||||||
0x813F, 0x1367, 0x0F6C, 0x0764, // 0x5A, Z
|
0x813F, 0x1367, 0x0F6C, 0x0764, // 0x5A, Z
|
||||||
0x666E, 0x0001, 0x0E66, 0x0100, // 0x5B, [
|
0x666E, 0x0001, 0x0E66, 0x0100, // 0x5B, [
|
||||||
0x8C63, 0x1000, 0x0000, 0x0463, // 0x5C,
|
0x8C63, 0x1000, 0x0000, 0x0463, // 0x5C,
|
||||||
0x888E, 0x1111, 0x0E88, 0x0111, // 0x5D, ]
|
0x888E, 0x1111, 0x0E88, 0x0111, // 0x5D, ]
|
||||||
0x36C8, 0x6310, 0x0000, 0x0000, // 0x5E, ^
|
0x36C8, 0x6310, 0x0000, 0x0000, // 0x5E, ^
|
||||||
0x0000, 0x0000, 0xF000, 0xF000, // 0x5F, _
|
0x0000, 0x0000, 0xF000, 0xF000, // 0x5F, _
|
||||||
@@ -372,13 +372,27 @@ float write_int(vec2 uv, vec2 pos, uint value, uint magnitude)
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float write_int_left(vec2 uv, vec2 pos, uint value, uint magnitude)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint m = 1;
|
||||||
|
float d = 0;
|
||||||
|
for (i = 0; i < magnitude; i++) {
|
||||||
|
if (i == 0 || value >= m) {
|
||||||
|
pos.x += 1;
|
||||||
|
m *= 10u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return write_int(uv, pos, value, magnitude);
|
||||||
|
}
|
||||||
|
|
||||||
int read(sampler2D tex, vec2 uv, float k, int d, float t)
|
int read(sampler2D tex, vec2 uv, float k, int d, float t)
|
||||||
{
|
{
|
||||||
float inv_k = 1 / k;
|
float inv_k = 1 / k;
|
||||||
vec2 tex_uv = floor(uv * k) * inv_k;
|
vec2 tex_uv = floor(uv * k) * inv_k;
|
||||||
tex_uv += vec2(d % 2, floor(d * 0.5)) * 0.5 * inv_k;
|
tex_uv += vec2(d % 2, floor(d * 0.5)) * 0.5 * inv_k;
|
||||||
return
|
return
|
||||||
((mean(reframe(tex, tex_uv + vec2(0, 3) * inv_k * 0.125)) > t) ? 1 : 0) +
|
((mean(reframe(tex, tex_uv + vec2(0, 3) * inv_k * 0.125)) > t) ? 1 : 0) +
|
||||||
((mean(reframe(tex, tex_uv + vec2(0, 2) * inv_k * 0.125)) > t) ? 2 : 0) +
|
((mean(reframe(tex, tex_uv + vec2(0, 2) * inv_k * 0.125)) > t) ? 2 : 0) +
|
||||||
((mean(reframe(tex, tex_uv + vec2(0, 1) * inv_k * 0.125)) > t) ? 4 : 0) +
|
((mean(reframe(tex, tex_uv + vec2(0, 1) * inv_k * 0.125)) > t) ? 4 : 0) +
|
||||||
((mean(reframe(tex, tex_uv + vec2(0, 0) * inv_k * 0.125)) > t) ? 8 : 0) +
|
((mean(reframe(tex, tex_uv + vec2(0, 0) * inv_k * 0.125)) > t) ? 8 : 0) +
|
||||||
@@ -397,7 +411,7 @@ int read(sampler2D tex, vec2 uv, float k, int d, float t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://web.archive.org/web/20151229003112/http://blogs.msdn.com/b/jeuge/archive/2005/06/08/hakmem-bit-count.aspx
|
// https://web.archive.org/web/20151229003112/http://blogs.msdn.com/b/jeuge/archive/2005/06/08/hakmem-bit-count.aspx
|
||||||
int bit_count(int u)
|
int bit_count(int u)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
c = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
|
c = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
|
||||||
@@ -410,7 +424,7 @@ int guess_char(sampler2D tex, vec2 uv, float k, float t)
|
|||||||
int b1 = read(tex, uv, k, 1, t);
|
int b1 = read(tex, uv, k, 1, t);
|
||||||
int b2 = read(tex, uv, k, 2, t);
|
int b2 = read(tex, uv, k, 2, t);
|
||||||
int b3 = read(tex, uv, k, 3, t);
|
int b3 = read(tex, uv, k, 3, t);
|
||||||
|
|
||||||
int mc = 0;
|
int mc = 0;
|
||||||
int mb = 100;
|
int mb = 100;
|
||||||
int i;
|
int i;
|
||||||
@@ -430,4 +444,4 @@ int guess_char(sampler2D tex, vec2 uv, float k, float t)
|
|||||||
return mc;
|
return mc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+39
-36
@@ -1,13 +1,11 @@
|
|||||||
#include inc_magic.glsl
|
#include inc_magic.glsl
|
||||||
#include inc_functions.glsl
|
#include inc_functions.glsl
|
||||||
#include inc_yuv.glsl
|
#include inc_yuyv.glsl
|
||||||
#include inc_cp437.glsl
|
#include inc_cp437.glsl
|
||||||
|
|
||||||
#ifndef INC_DEBUG
|
#ifndef INC_DEBUG
|
||||||
#define INC_DEBUG
|
#define INC_DEBUG
|
||||||
|
|
||||||
uniform int iFPS;
|
|
||||||
|
|
||||||
uniform vec2 iInputResolution1;
|
uniform vec2 iInputResolution1;
|
||||||
uniform vec2 iInputResolution2;
|
uniform vec2 iInputResolution2;
|
||||||
uniform int iInputFormat1;
|
uniform int iInputFormat1;
|
||||||
@@ -15,6 +13,7 @@ uniform int iInputFormat2;
|
|||||||
|
|
||||||
uniform int iDemo;
|
uniform int iDemo;
|
||||||
uniform int iAutoRand;
|
uniform int iAutoRand;
|
||||||
|
uniform int iAutoRandCycle;
|
||||||
uniform int iPage;
|
uniform int iPage;
|
||||||
uniform int iSelected;
|
uniform int iSelected;
|
||||||
|
|
||||||
@@ -111,7 +110,7 @@ vec4 debug(vec2 vUV)
|
|||||||
{0x54, 0x49, 0x4D, 0x45, 0x00}, // TIME
|
{0x54, 0x49, 0x4D, 0x45, 0x00}, // TIME
|
||||||
{0x44, 0x45, 0x4D, 0x4F, 0x00}, // DEMO
|
{0x44, 0x45, 0x4D, 0x4F, 0x00}, // DEMO
|
||||||
{0x4C, 0x49, 0x56, 0x45, 0x00}, // LIVE
|
{0x4C, 0x49, 0x56, 0x45, 0x00}, // LIVE
|
||||||
{0x2B, 0x52, 0x41, 0x4E, 0x44}, // +RAND
|
{0x52, 0x41, 0x4E, 0x44, 0x00}, // RAND
|
||||||
{0x53, 0x52, 0x43, 0x00, 0x00}, // SRC
|
{0x53, 0x52, 0x43, 0x00, 0x00}, // SRC
|
||||||
{0x46, 0x58, 0x00, 0x00, 0x00}, // FX
|
{0x46, 0x58, 0x00, 0x00, 0x00}, // FX
|
||||||
{0x49, 0x4E, 0x00, 0x00, 0x00}, // IN
|
{0x49, 0x4E, 0x00, 0x00, 0x00}, // IN
|
||||||
@@ -127,7 +126,7 @@ vec4 debug(vec2 vUV)
|
|||||||
vec2 uv3 = uv1 * 30;
|
vec2 uv3 = uv1 * 30;
|
||||||
|
|
||||||
// base frame
|
// base frame
|
||||||
float f =
|
float f =
|
||||||
h_rect(uv2, vec2(-5, -2), vec2(1), 0.1) +
|
h_rect(uv2, vec2(-5, -2), vec2(1), 0.1) +
|
||||||
h_rect(uv2, vec2(-2, -2), vec2(1), 0.1) +
|
h_rect(uv2, vec2(-2, -2), vec2(1), 0.1) +
|
||||||
rect(uv2, vec2(-3.5, -2), vec2(0.5, 0.1)) +
|
rect(uv2, vec2(-3.5, -2), vec2(0.5, 0.1)) +
|
||||||
@@ -141,8 +140,17 @@ vec4 debug(vec2 vUV)
|
|||||||
rect(uv2, vec2(2, -1.55), vec2(0.1, 0.55)) +
|
rect(uv2, vec2(2, -1.55), vec2(0.1, 0.55)) +
|
||||||
rect(uv2, vec2(0.55, 2), vec2(1.5, 0.1)) +
|
rect(uv2, vec2(0.55, 2), vec2(1.5, 0.1)) +
|
||||||
rect(uv2, vec2(2, 1.55), vec2(0.1, 0.55)) +
|
rect(uv2, vec2(2, 1.55), vec2(0.1, 0.55)) +
|
||||||
rect(uv2, vec2(7.5, 0), vec2(1.5, 0.1)) +
|
rect(uv2, vec2(6.8, 0), vec2(0.75, 0.1)) +
|
||||||
h_rect(uv2, vec2(-9, -3.9), vec2(1), 0.1);
|
h_circle(uv2, vec2(7.8, 0), 0.3, 0.1)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (iDemo < 1 && iInputFormat1 == YUYV_FOURCC) {
|
||||||
|
f += circle(uv2, vec2(-9, 2), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iDemo < 1 && iInputFormat2 == YUYV_FOURCC) {
|
||||||
|
f += circle(uv2, vec2(-9, -2), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
// show selected src/fx
|
// show selected src/fx
|
||||||
f += char_at(uv2, vec2(-5.4, 1.45), hex_chars[selected_srca]);
|
f += char_at(uv2, vec2(-5.4, 1.45), hex_chars[selected_srca]);
|
||||||
@@ -177,17 +185,17 @@ vec4 debug(vec2 vUV)
|
|||||||
|
|
||||||
f += write_5(uv3 * 0.75, vec2(-11.6,-1.8), texts[6]);
|
f += write_5(uv3 * 0.75, vec2(-11.6,-1.8), texts[6]);
|
||||||
f += write_5(uv3 * 0.75, vec2(-4.2,-1.8), texts[7]);
|
f += write_5(uv3 * 0.75, vec2(-4.2,-1.8), texts[7]);
|
||||||
f += char_at(uv3 * 0.5, vec2(0.5, 0.5), 0x41);
|
f += char_at(uv3 * 0.5, vec2(-11.5, 3.5), 0x41);
|
||||||
f += char_at(uv3 * 0.5, vec2(0.5, -3), 0x42);
|
f += char_at(uv3 * 0.5, vec2(-11.5, -6), 0x42);
|
||||||
if (iDemo < 1 && (iInputFormat1 == YUYV_FOURCC || iInputFormat2 == YUYV_FOURCC)) {
|
if (iDemo < 1 && (iInputFormat1 == YUYV_FOURCC || iInputFormat2 == YUYV_FOURCC)) {
|
||||||
f += write_5(uv3 * 0.75, vec2(-19.7,-1.8), texts[8]);
|
f += write_5(uv3 * 0.75, vec2(-19.7,-1.8), texts[8]);
|
||||||
}
|
}
|
||||||
f += write_5(uv3 * 0.75, vec2(10.9,2), texts[9]);
|
f += write_5(uv3 * 0.75, vec2(10.9,2), texts[9]);
|
||||||
|
|
||||||
// show inputs / feedback
|
// show inputs / feedback
|
||||||
float line_a_a = rect(uv2, vec2(-8, 2), vec2(2, 0.1));
|
float line_a_a = rect(uv2, vec2(-7.5, 2), vec2(1.5, 0.1));
|
||||||
float line_a_b = rect(uv2, vec2(-7, 2), vec2(1, 0.1)) + rect(uv2, vec2(-8, 0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-9, -1), vec2(1, 0.1));
|
float line_a_b = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(-8.5, -2), vec2(0.5, 0.1)) + line(uv2, vec2(-7, 2.1), vec2(-8, -2.1), 0.2);
|
||||||
float line_a_f = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, 4), vec2(7, 0.1)) + rect(uv2, vec2(-7, 3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, 2), vec2(0.1, 2.1));
|
float line_a_f = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, 3.6), vec2(7, 0.1)) + rect(uv2, vec2(-7, 2.8), vec2(0.1, 0.9)) + rect(uv2, vec2(7, 1.8), vec2(0.1, 1.9));
|
||||||
if (selected_srca == 5 && iInputFormat1 == YUYV_FOURCC) {
|
if (selected_srca == 5 && iInputFormat1 == YUYV_FOURCC) {
|
||||||
f += line_a_a;
|
f += line_a_a;
|
||||||
} else if (selected_srca == 10 && iInputFormat2 == YUYV_FOURCC) {
|
} else if (selected_srca == 10 && iInputFormat2 == YUYV_FOURCC) {
|
||||||
@@ -195,9 +203,10 @@ vec4 debug(vec2 vUV)
|
|||||||
} else if (selected_srca % 5 == 0) {
|
} else if (selected_srca % 5 == 0) {
|
||||||
f += line_a_f;
|
f += line_a_f;
|
||||||
}
|
}
|
||||||
float line_b_a = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(-7, -0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-8.5, 1), vec2(1.5, 0.1));
|
|
||||||
float line_b_b = rect(uv2, vec2(-8, -2), vec2(2, 0.1));
|
float line_b_a = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(-8.5, 2), vec2(0.5, 0.1)) + line(uv2, vec2(-7, -2.1), vec2(-8, 2.1), 0.2);
|
||||||
float line_b_f = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, -4), vec2(7, 0.1)) + rect(uv2, vec2(-7, -3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, -2), vec2(0.1, 2.1));
|
float line_b_b = rect(uv2, vec2(-7.5, -2), vec2(1.5, 0.1));
|
||||||
|
float line_b_f = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, -3.6), vec2(7, 0.1)) + rect(uv2, vec2(-7, -2.8), vec2(0.1, 0.9)) + rect(uv2, vec2(7, -1.8), vec2(0.1, 1.9));
|
||||||
if (selected_srcb == 5 && iInputFormat1 == YUYV_FOURCC) {
|
if (selected_srcb == 5 && iInputFormat1 == YUYV_FOURCC) {
|
||||||
f += line_b_a;
|
f += line_b_a;
|
||||||
} else if (selected_srcb == 10 && iInputFormat2 == YUYV_FOURCC) {
|
} else if (selected_srcb == 10 && iInputFormat2 == YUYV_FOURCC) {
|
||||||
@@ -207,7 +216,9 @@ vec4 debug(vec2 vUV)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// show page
|
// show page
|
||||||
f += char_at(uv2, vec2(-9.2, -4.3), hex_chars[iPage]);
|
f += iPage == 0 ? circle(uv2, vec2(-0.75, -4.1), 0.3) : h_circle(uv2, vec2(-0.75, -4.1), 0.25, 0.1);
|
||||||
|
f += iPage == 1 ? circle(uv2, vec2(0, -4.1), 0.3) : h_circle(uv2, vec2(0, -4.1), 0.20, 0.1);
|
||||||
|
f += iPage == 2 ? circle(uv2, vec2(0.75, -4.1), 0.3) : h_circle(uv2, vec2(0.75, -4.1), 0.20, 0.1);
|
||||||
|
|
||||||
// show fx values
|
// show fx values
|
||||||
float fx_rect = 0;
|
float fx_rect = 0;
|
||||||
@@ -225,34 +236,26 @@ vec4 debug(vec2 vUV)
|
|||||||
float x = 0;
|
float x = 0;
|
||||||
|
|
||||||
x = -15;
|
x = -15;
|
||||||
f += write_5(uv3, vec2(x,13), texts[0]);
|
f += write_5(uv3, vec2(x - 4.5,13), texts[1]);
|
||||||
f += write_int(uv3, vec2(x - 3.5,13), iFPS, 3);
|
f += write_int(uv3, vec2(x + 1.5,13), int(iTempo), 3);
|
||||||
v = min(1, iFPS/60.0);
|
|
||||||
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
|
|
||||||
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
|
|
||||||
|
|
||||||
x = 0;
|
|
||||||
f += write_5(uv3, vec2(x,13), texts[1]);
|
|
||||||
f += write_int(uv3, vec2(x - 3.5,13), int(iTempo), 3);
|
|
||||||
v = fract(iBeats);
|
v = fract(iBeats);
|
||||||
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
|
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
|
||||||
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
|
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
|
||||||
|
|
||||||
x = 15;
|
x = 15;
|
||||||
f += write_5(uv3, vec2(x,13), texts[2]);
|
if (iAutoRand > 0) {
|
||||||
f += write_int(uv3, vec2(x - 5.5,13), int(iTime), 5);
|
f += write_5(uv3, vec2(x - 4.5,13), texts[5]);
|
||||||
v = fract(iTime);
|
f += write_int(uv3, vec2(x - 0.5,13), int(iAutoRandCycle), 5);
|
||||||
|
v = fract(iBeats / iAutoRandCycle);
|
||||||
|
} else {
|
||||||
|
f += write_int(uv3, vec2(x - 0.5,13), int(iTime), 5);
|
||||||
|
v = fract(iTime);
|
||||||
|
f += write_5(uv3, vec2(x - 4.5,13), texts[2]);
|
||||||
|
}
|
||||||
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
|
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
|
||||||
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
|
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
|
||||||
|
|
||||||
if (iAutoRand > 0) {
|
|
||||||
f += write_5(uv3, vec2(-4,-15), iDemo > 0 ? texts[3] : texts[4]);
|
|
||||||
f += write_5(uv3, vec2(0,-15), texts[5]);
|
|
||||||
} else {
|
|
||||||
f += write_5(uv3, vec2(-2,-15), iDemo > 0 ? texts[3] : texts[4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#define PI 3.1415927
|
#define PI 3.1415927
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include inc_time.glsl
|
||||||
|
#include inc_rand.glsl
|
||||||
#include inc_res.glsl
|
#include inc_res.glsl
|
||||||
|
|
||||||
#ifndef INC_FUNCTIONS
|
#ifndef INC_FUNCTIONS
|
||||||
@@ -186,10 +188,10 @@ vec2 v_pos(float i) {
|
|||||||
|
|
||||||
float x0 = rand(i + 823 + iTimeId);
|
float x0 = rand(i + 823 + iTimeId);
|
||||||
float y0 = rand(i + 328 + iTimeId);
|
float y0 = rand(i + 328 + iTimeId);
|
||||||
|
|
||||||
float x1 = rand(i + 823 + iTimeId + 1);
|
float x1 = rand(i + 823 + iTimeId + 1);
|
||||||
float y1 = rand(i + 328 + iTimeId + 1);
|
float y1 = rand(i + 328 + iTimeId + 1);
|
||||||
|
|
||||||
return vec2(
|
return vec2(
|
||||||
mix(x0, x1, ease(ease(iTimeV))),
|
mix(x0, x1, ease(ease(iTimeV))),
|
||||||
mix(y0, y1, ease(ease(iTimeV)))
|
mix(y0, y1, ease(ease(iTimeV)))
|
||||||
@@ -224,6 +226,10 @@ float circle(vec2 uv, vec2 c, float size) {
|
|||||||
return istep(size, length(uv - c));
|
return istep(size, length(uv - c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float h_circle(vec2 uv, vec2 c, float size, float k) {
|
||||||
|
return circle(uv, c, size + k * 0.5) - circle(uv, c, size - k * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
float stripe(float x, float k1, float k2)
|
float stripe(float x, float k1, float k2)
|
||||||
{
|
{
|
||||||
return k2 > k1 ? (1 - step(x, k1)) * (step(x, k2)) : ((1 - step(x, k2)) * (step(x, k1)));
|
return k2 > k1 ? (1 - step(x, k1)) * (step(x, k2)) : ((1 - step(x, k2)) * (step(x, k1)));
|
||||||
@@ -251,13 +257,13 @@ float line(vec2 uv, vec2 p1, vec2 p2, float thick) {
|
|||||||
vec2 p = p2 - p1;
|
vec2 p = p2 - p1;
|
||||||
uv -= p1;
|
uv -= p1;
|
||||||
vec2 k;
|
vec2 k;
|
||||||
|
|
||||||
if (abs(p.y) > abs(p.x)) {
|
if (abs(p.y) > abs(p.x)) {
|
||||||
k = vec2(
|
k = vec2(
|
||||||
uv.x - p.x * uv.y / p.y,
|
uv.x - p.x * uv.y / p.y,
|
||||||
uv.y / p.y
|
uv.y / p.y
|
||||||
);
|
);
|
||||||
|
|
||||||
return step(k.x, thick * 0.5)
|
return step(k.x, thick * 0.5)
|
||||||
* step(-k.x, thick * 0.5)
|
* step(-k.x, thick * 0.5)
|
||||||
* step(k.y, 1)
|
* step(k.y, 1)
|
||||||
@@ -267,7 +273,7 @@ float line(vec2 uv, vec2 p1, vec2 p2, float thick) {
|
|||||||
uv.x / p.x,
|
uv.x / p.x,
|
||||||
uv.y - p.y * uv.x / p.x
|
uv.y - p.y * uv.x / p.x
|
||||||
);
|
);
|
||||||
|
|
||||||
return step(k.y, thick * 0.5)
|
return step(k.y, thick * 0.5)
|
||||||
* step(-k.y, thick * 0.5)
|
* step(-k.y, thick * 0.5)
|
||||||
* step(k.x, 1)
|
* step(k.x, 1)
|
||||||
|
|||||||
+14
-14
@@ -60,9 +60,9 @@ vec4 fx_shift(vec2 vUV, sampler2D src0, sampler2D src1, int seed, vec3 b1, vec2
|
|||||||
float y_shift = magic(f3, b3, seed + 30);
|
float y_shift = magic(f3, b3, seed + 30);
|
||||||
|
|
||||||
// logic
|
// logic
|
||||||
|
|
||||||
vec3 c0 = texture(src0, uv0).xyz;
|
vec3 c0 = texture(src0, uv0).xyz;
|
||||||
|
|
||||||
vec2 uv2 = uv1;
|
vec2 uv2 = uv1;
|
||||||
uv2 = mix(uv2 * (1 + zoom * 2), uv2 * (zoom), step(0.5, zoom));
|
uv2 = mix(uv2 * (1 + zoom * 2), uv2 * (zoom), step(0.5, zoom));
|
||||||
uv2 += vec2(x_shift * ratio, y_shift) * 2;
|
uv2 += vec2(x_shift * ratio, y_shift) * 2;
|
||||||
@@ -127,7 +127,7 @@ subroutine(fx_stage_sub) vec4 fx_5(vec2 vUV, sampler2D previous, sampler2D feedb
|
|||||||
// logic
|
// logic
|
||||||
|
|
||||||
vec3 c0 = texture(previous, uv0).xyz;
|
vec3 c0 = texture(previous, uv0).xyz;
|
||||||
|
|
||||||
vec2 uv2 = uv1;
|
vec2 uv2 = uv1;
|
||||||
float pixel = (1 - pixel_size) * 250 + 25;
|
float pixel = (1 - pixel_size) * 250 + 25;
|
||||||
uv2 = round(uv2 * pixel) / pixel;
|
uv2 = round(uv2 * pixel) / pixel;
|
||||||
@@ -199,9 +199,9 @@ subroutine(fx_stage_sub) vec4 fx_7(vec2 vUV, sampler2D previous, sampler2D feedb
|
|||||||
float zoom = magic(f3, b3, seed + 30);
|
float zoom = magic(f3, b3, seed + 30);
|
||||||
|
|
||||||
// logic
|
// logic
|
||||||
|
|
||||||
vec3 c0 = texture(previous, uv0).xyz;
|
vec3 c0 = texture(previous, uv0).xyz;
|
||||||
|
|
||||||
vec2 uv2 = uv1;
|
vec2 uv2 = uv1;
|
||||||
float k1 = lens_v * 0.5;
|
float k1 = lens_v * 0.5;
|
||||||
uv2 *= 1 + zoom * 2;
|
uv2 *= 1 + zoom * 2;
|
||||||
@@ -235,9 +235,9 @@ subroutine(fx_stage_sub) vec4 fx_8(vec2 vUV, sampler2D previous, sampler2D feedb
|
|||||||
// logic
|
// logic
|
||||||
|
|
||||||
vec3 c0 = texture(previous, uv0).xyz;
|
vec3 c0 = texture(previous, uv0).xyz;
|
||||||
|
|
||||||
vec2 uv2 = uv1;
|
vec2 uv2 = uv1;
|
||||||
uv2 = mix(uv2, kal2(uv2 * rot(0.25), floor(axes * 9 + 1)) * vec2(1, -2) + vec2(0, -0.5), axes_trigger);
|
uv2 = mix(uv2, kal2(uv2 * rot(0.25), floor(axes * 9 + 1)) * vec2(1, -2) + vec2(0, -0.5), axes_trigger);
|
||||||
uv2 *= rot(rotation);
|
uv2 *= rot(rotation);
|
||||||
uv2.x = (saw(uv2.x / ratio + 0.5 + h_scroll * 2) - 0.5) * ratio;
|
uv2.x = (saw(uv2.x / ratio + 0.5 + h_scroll * 2) - 0.5) * ratio;
|
||||||
vec3 c = reframe(previous, uv2).xyz;
|
vec3 c = reframe(previous, uv2).xyz;
|
||||||
@@ -262,12 +262,12 @@ subroutine(fx_stage_sub) vec4 fx_9(vec2 vUV, sampler2D previous, sampler2D feedb
|
|||||||
vec2 charset = magic_f(f2, b2, seed + 20);
|
vec2 charset = magic_f(f2, b2, seed + 20);
|
||||||
vec3 charset_ctrl = magic_b(b2, seed + 20);
|
vec3 charset_ctrl = magic_b(b2, seed + 20);
|
||||||
float char_delta = magic(f3, b3, seed + 30);
|
float char_delta = magic(f3, b3, seed + 30);
|
||||||
float t = magic(seed + 40);
|
float t = magic(seed + 40);
|
||||||
|
|
||||||
// logic
|
// logic
|
||||||
|
|
||||||
vec3 c0 = texture(previous, uv0).xyz;
|
vec3 c0 = texture(previous, uv0).xyz;
|
||||||
|
|
||||||
vec2 uv2 = uv1;
|
vec2 uv2 = uv1;
|
||||||
float k1 = 100 * (1 - zoom) + 10;
|
float k1 = 100 * (1 - zoom) + 10;
|
||||||
float inv_k = 1 / k1;
|
float inv_k = 1 / k1;
|
||||||
@@ -306,7 +306,7 @@ subroutine(fx_stage_sub) vec4 fx_10(vec2 vUV, sampler2D previous, sampler2D feed
|
|||||||
// logic
|
// logic
|
||||||
|
|
||||||
vec3 c0 = texture(previous, uv0).xyz;
|
vec3 c0 = texture(previous, uv0).xyz;
|
||||||
|
|
||||||
vec2 uv2 = uv1;
|
vec2 uv2 = uv1;
|
||||||
uv2 *= 1 + zoom * 2;
|
uv2 *= 1 + zoom * 2;
|
||||||
uv2 = lens(uv2, -lens_v2 * 10, lens_v1 * 10);
|
uv2 = lens(uv2, -lens_v2 * 10, lens_v1 * 10);
|
||||||
@@ -331,7 +331,7 @@ subroutine(fx_stage_sub) vec4 fx_11(vec2 vUV, sampler2D previous, sampler2D feed
|
|||||||
float angle = magic(f3, b3, seed + 30);
|
float angle = magic(f3, b3, seed + 30);
|
||||||
|
|
||||||
// logic
|
// logic
|
||||||
|
|
||||||
vec3 c0 = texture(previous, uv0).xyz;
|
vec3 c0 = texture(previous, uv0).xyz;
|
||||||
|
|
||||||
vec2 uv2 = uv1;
|
vec2 uv2 = uv1;
|
||||||
@@ -363,7 +363,7 @@ subroutine(fx_stage_sub) vec4 fx_12(vec2 vUV, sampler2D previous, sampler2D feed
|
|||||||
float fb = magic(f3, b3, seed + 30);
|
float fb = magic(f3, b3, seed + 30);
|
||||||
|
|
||||||
// logic
|
// logic
|
||||||
|
|
||||||
vec3 c0 = texture(previous, uv0).xyz;
|
vec3 c0 = texture(previous, uv0).xyz;
|
||||||
|
|
||||||
vec2 uv2 = uv1;
|
vec2 uv2 = uv1;
|
||||||
@@ -452,7 +452,7 @@ subroutine(fx_stage_sub) vec4 fx_12(vec2 vUV, sampler2D previous, sampler2D feed
|
|||||||
} else if (rule == 11) { // B4678/S35678 (Anneal)
|
} else if (rule == 11) { // B4678/S35678 (Anneal)
|
||||||
alive = n >= 6 || !alive && n == 4 || alive && (n == 3 || n == 5);
|
alive = n >= 6 || !alive && n == 4 || alive && (n == 3 || n == 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 cout = vec3(alive ? 1 : 0);
|
vec3 cout = vec3(alive ? 1 : 0);
|
||||||
|
|
||||||
return fx_master(c0, cout, seed, m0);
|
return fx_master(c0, cout, seed, m0);
|
||||||
@@ -559,4 +559,4 @@ subroutine(fx_stage_sub) vec4 fx_15(vec2 vUV, sampler2D previous, sampler2D feed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -74,4 +74,4 @@ float magic_reverse(float i)
|
|||||||
return magic_reverse(vec2(0), vec3(0, 0, 1), i);
|
return magic_reverse(vec2(0), vec3(0, 0, 1), i);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ float rand(vec2 n){
|
|||||||
return rand(n.x * 1234 + n.y * 9876);
|
return rand(n.x * 1234 + n.y * 9876);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,4 +4,4 @@
|
|||||||
uniform vec2 iResolution;
|
uniform vec2 iResolution;
|
||||||
uniform vec2 iTexResolution;
|
uniform vec2 iTexResolution;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -26,4 +26,4 @@ const int sentences[SENTENCE_COUNT][20] = {
|
|||||||
const int lengths[SENTENCE_COUNT] = {
|
const int lengths[SENTENCE_COUNT] = {
|
||||||
5, 5, 10, 6, 2, 9, 10, 7, 18, 14, 4, 9, 10, 1, 6, 11, 11
|
5, 5, 10, 6, 2, 9, 10, 7, 18, 14, 4, 9, 10, 1, 6, 11, 11
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+164
-75
@@ -8,8 +8,8 @@
|
|||||||
uniform int iDemo;
|
uniform int iDemo;
|
||||||
|
|
||||||
uniform sampler2D iTex0;
|
uniform sampler2D iTex0;
|
||||||
uniform sampler2D iTex3;
|
uniform sampler2D iTex5;
|
||||||
uniform sampler2D iTex4;
|
uniform sampler2D iTex6;
|
||||||
|
|
||||||
subroutine vec4 src_stage_sub(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3);
|
subroutine vec4 src_stage_sub(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3);
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ vec4 src_thru(vec2 vUV, sampler2D tex, int seed, vec3 b1, vec2 f1, vec3 b2, vec2
|
|||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
|
|
||||||
// controls
|
// controls
|
||||||
|
|
||||||
@@ -36,21 +36,21 @@ vec4 src_thru(vec2 vUV, sampler2D tex, int seed, vec3 b1, vec2 f1, vec3 b2, vec2
|
|||||||
|
|
||||||
// output
|
// output
|
||||||
|
|
||||||
return vec4(c, 1.);
|
return vec4(c, 1.);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 1: feedback + thru
|
// SRC 1: feedback + thru
|
||||||
subroutine(src_stage_sub) vec4 src_1(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_1(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
return src_thru(vUV, iTex0, seed, b1, f1, b2, f2, b3, f3);
|
return src_thru(vUV, iTex0, seed, b1, f1, b2, f2, b3, f3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 2 : lines
|
// SRC 2 : lines
|
||||||
subroutine(src_stage_sub) vec4 src_2(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_2(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -68,16 +68,16 @@ subroutine(src_stage_sub) vec4 src_2(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
float k = thickness * 2;
|
float k = thickness * 2;
|
||||||
uv2.y = cmod(uv2.y, k * 2 + 0.1);
|
uv2.y = cmod(uv2.y, k * 2 + 0.1);
|
||||||
float f = istep(k * 0.125 + 0.05, uv2.y) * istep(k * 0.125 + 0.01, -uv2.y);
|
float f = istep(k * 0.125 + 0.05, uv2.y) * istep(k * 0.125 + 0.01, -uv2.y);
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 3 : dots
|
// SRC 3 : dots
|
||||||
subroutine(src_stage_sub) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -97,59 +97,148 @@ subroutine(src_stage_sub) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
float k = zoom * 0.1 + 0.05;
|
float k = zoom * 0.1 + 0.05;
|
||||||
uv2 = cmod(uv2, k * 2);
|
uv2 = cmod(uv2, k * 2);
|
||||||
float f = istep(k / (1 + length(uv1) * 2), length(uv2));
|
float f = istep(k / (1 + length(uv1) * 2), length(uv2));
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 4 : waves
|
// SRC 4 : circuit
|
||||||
subroutine(src_stage_sub) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
// controls
|
// controls
|
||||||
|
|
||||||
float spacing = magic(f1, b1, seed + 10);
|
float z = 10 + magic(f1, b1, 123) * 20;
|
||||||
float thickness = magic(f2, b2, seed + 20);
|
float h = magic(f2, b2, seed + 20) * 0.8 + 0.1;
|
||||||
float scroll = magic_reverse(f3, b3, seed + 30);
|
float v = magic_reverse(f3, b3, seed + 30) * 0.8 + 0.1;
|
||||||
|
|
||||||
// logic
|
// logic
|
||||||
|
|
||||||
vec2 uv2 = uv1;
|
uv1 *= z;
|
||||||
uv2.y += 0.5;
|
uv1 += iBeats;
|
||||||
uv2 *= 2.25;
|
|
||||||
uv2 = vec2((uv2.x + 1) * 0.5, -uv2.y);
|
float s0 = rand(floor(mod(uv1, 1000))) * 1000;
|
||||||
float m1 = spacing * 4.5 + 0.5;
|
float s1 = rand(floor(mod(uv1 + vec2(0, 1), 1000))) * 1000;
|
||||||
float y = log(-uv2.y) * m1;
|
float s2 = rand(floor(mod(uv1 - vec2(1, 0), 1000))) * 1000;
|
||||||
y = mod(y + scroll * 5.0 - iBeats / 16, 5.);
|
|
||||||
float id = floor(y) * 32;
|
bool up = rand(s1 + 1) < h;
|
||||||
float s = cos(uv2.x * rand(id + 837) * 100 + rand(id + 281) * PI)
|
bool left = rand(s2 + 2) < v;
|
||||||
+ cos(uv2.x * rand(id + 231) * 100 + rand(id + 526) * PI)
|
bool down = rand(s0 + 1) < h;
|
||||||
+ cos(uv2.x * rand(id + 746) * 100 + rand(id + 621) * PI)
|
bool right = rand(s0 + 2) < v;
|
||||||
+ cos(uv2.x * rand(id + 235) * 100 + rand(id + 315) * PI)
|
bool up_down = up && down;
|
||||||
+ cos(uv2.x * rand(id + 782) * 100 + rand(id + 314) * PI)
|
bool left_right = left && right;
|
||||||
+ cos(uv2.x * rand(id + 241) * 100 + rand(id + 734) * PI)
|
|
||||||
+ cos(uv2.x * rand(id + 416) * 100 + rand(id + 425) * PI)
|
uv1 = mod(uv1, 1.0) - 0.5;
|
||||||
+ cos(uv2.x * rand(id + 315) * 100 + rand(id + 525) * PI)
|
|
||||||
+ cos(uv2.x * rand(id + 423) * 100 + rand(id + 743) * PI)
|
const float t = 0.1;
|
||||||
+ cos(uv2.x * rand(id + 637) * 100 + rand(id + 245) * PI);
|
|
||||||
s *= 0.1;
|
float f = 0;
|
||||||
float cut = 0.025 + thickness * 0.475;
|
int c = 0;
|
||||||
float y2 = min(1.0, -(uv2.y));
|
|
||||||
float f = (0.1 + 0.9 * (cos((y2 + 1.0) * PI) * 0.5 + 0.5)) * istep(0, uv2.y) * istep(cut, fract(y + (s - 1) * (1 - cut) * 0.5));
|
if (up) {
|
||||||
|
f += stripe(uv1.x, -t * 0.5, t * 0.5) * step(-t * 0.5, uv1.y);
|
||||||
|
c += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (down) {
|
||||||
|
f += stripe(uv1.x, -t * 0.5, t * 0.5) * istep(t * 0.5, uv1.y);
|
||||||
|
c += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left) {
|
||||||
|
f += stripe(uv1.y, -t * 0.5, t * 0.5) * istep(t * 0.5, uv1.x);
|
||||||
|
c += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (right) {
|
||||||
|
f += stripe(uv1.y, -t * 0.5, t * 0.5) * step(-t * 0.5, uv1.x);
|
||||||
|
c += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 1) {
|
||||||
|
f += istep(t, length(uv1));
|
||||||
|
}
|
||||||
|
|
||||||
|
f = min(f, 1);
|
||||||
|
|
||||||
|
if ((up_down ^^ left_right) && c == 2) {
|
||||||
|
if (up_down) {
|
||||||
|
uv1.xy = uv1.yx;
|
||||||
|
}
|
||||||
|
if (rand(s0 + 3) < 0.5) {
|
||||||
|
uv1.x = -uv1.x;
|
||||||
|
}
|
||||||
|
float k = rand(s0 + 4) * 60;
|
||||||
|
f -= rect(uv1, vec2(0), vec2(t * 3, t));
|
||||||
|
f = max(0, f);
|
||||||
|
if (k < 10) { // resistor
|
||||||
|
f += line(uv1, vec2(-t * 3.25, -t * 0.5), vec2(-t * 2.5, t * 2), t * 0.75);
|
||||||
|
f += line(uv1, vec2(-t * 2.5, t * 2), vec2(-t * 1.5, -t * 2), t * 0.75);
|
||||||
|
f += line(uv1, vec2(-t * 1.5, -t * 2), vec2(-t * 0.5, t * 2), t * 0.75);
|
||||||
|
f += line(uv1, vec2(-t * 0.5, t * 2), vec2(t * 0.5, -t * 2), t * 0.75);
|
||||||
|
f += line(uv1, vec2(t * 0.5, -t * 2), vec2(t * 1.5, t * 2), t * 0.75);
|
||||||
|
f += line(uv1, vec2(t * 1.5, t * 2), vec2(t * 2.5, -t * 2), t * 0.75);
|
||||||
|
f += line(uv1, vec2(t * 2.5, -t * 2), vec2(t * 3.25, t * 0.5), t * 0.75);
|
||||||
|
} else if (k < 20) { // capacitor
|
||||||
|
f += rect(uv1, vec2(-t * 2, 0), vec2(t, t * 0.5));
|
||||||
|
f += rect(uv1, vec2(t * 2, 0), vec2(t, t * 0.5));
|
||||||
|
f += rect(uv1, vec2(t, 0), vec2(t * 0.5, t * 3.5));
|
||||||
|
f += rect(uv1, vec2(-t, 0), vec2(t * 0.5, t * 3.5));
|
||||||
|
} else if (k < 30) { // diode
|
||||||
|
f += line(uv1, vec2(-t * 2, t * 2.5), vec2(t * 2, 0), t);
|
||||||
|
f += line(uv1, vec2(-t * 2, -t * 2.5), vec2(t * 2, 0), t);
|
||||||
|
f += rect(uv1, vec2(t * 2.5, 0), vec2(t * 0.5, t * 3));
|
||||||
|
f += rect(uv1, vec2(-t * 2.5, 0), vec2(t * 0.5, t * 3));
|
||||||
|
} else if (k < 40) { // lamp
|
||||||
|
f += istep(t * 3.5, length(uv1));
|
||||||
|
f -= istep(t * 2.5, length(uv1));
|
||||||
|
f += line(uv1, vec2(-t * 2), vec2(t * 2), t);
|
||||||
|
f += line(uv1, vec2(-t * 2, t * 2), vec2(t * 2, -t * 2), t);
|
||||||
|
} else if (k < 50) { // inductor
|
||||||
|
f += istep(t * 2, length(uv1 - vec2(t * 2.5, 0)));
|
||||||
|
f += istep(t * 2, length(uv1 - vec2(0, 0)));
|
||||||
|
f += istep(t * 2, length(uv1 - vec2(-t * 2.5, 0)));
|
||||||
|
f -= 2 * istep(t, length(uv1 - vec2(t * 2.5, 0)));
|
||||||
|
f -= 2 * istep(t, length(uv1 - vec2(0, 0)));
|
||||||
|
f -= 2 * istep(t, length(uv1 - vec2(-t * 2.5, 0)));
|
||||||
|
f *= step(-t * 0.5, uv1.y);
|
||||||
|
} else if (k < 60) { // switch
|
||||||
|
f += istep(t, length(uv1 - vec2(t * 2.5, 0)));
|
||||||
|
f += istep(t, length(uv1 + vec2(t * 2.5, 0)));
|
||||||
|
f += line(uv1, vec2(t * 2, 0), vec2(-t * 2.5, t * (k < 55 ? 3 : 1)), t);
|
||||||
|
}
|
||||||
|
} else if (c == 3) {
|
||||||
|
if (left_right) {
|
||||||
|
uv1.xy = uv1.yx;
|
||||||
|
if (up) {
|
||||||
|
uv1.x = -uv1.x;
|
||||||
|
}
|
||||||
|
} else if (right) {
|
||||||
|
uv1.x = -uv1.x;
|
||||||
|
}
|
||||||
|
float k = rand(s0 + 4) * 20;
|
||||||
|
if (k < 10) {
|
||||||
|
f -= rect(uv1, vec2(0), vec2(t * 3));
|
||||||
|
f = max(0, f);
|
||||||
|
f += rect(uv1, vec2(-t * 3, 0), vec2(t * 0.5, t * 3));
|
||||||
|
f += line(uv1, vec2(t * 0.25, t * 3.25), vec2(-t * 3, t), t);
|
||||||
|
f += line(uv1, vec2(t * 0.25, -t * 3.25), vec2(-t * 3, -t), t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 5 : noise
|
// SRC 5 : noise
|
||||||
subroutine(src_stage_sub) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -170,28 +259,28 @@ subroutine(src_stage_sub) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
f = sin(f * PI * (details * 20)) * 0.5 + 1;
|
f = sin(f * PI * (details * 20)) * 0.5 + 1;
|
||||||
int nf = int(noise_factor * 6);
|
int nf = int(noise_factor * 6);
|
||||||
f *= mix(1, noise_f(uv2, nf - 1), step(0.0, float(nf)));
|
f *= mix(1, noise_f(uv2, nf - 1), step(0.0, float(nf)));
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 6 : video in 1 + thru
|
// SRC 6 : video in 1 + thru
|
||||||
subroutine(src_stage_sub) vec4 src_6(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_6(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
if (iDemo > 0) {
|
if (iDemo > 0) {
|
||||||
return src_2(vUV, seed, b1, f1, b2, f2, b3, f3);
|
return src_2(vUV, seed, b1, f1, b2, f2, b3, f3);
|
||||||
}
|
}
|
||||||
|
|
||||||
return src_thru(vUV, iTex3, seed, b1, f1, b2, f2, b3, f3);
|
return src_thru(vUV, iTex5, seed, b1, f1, b2, f2, b3, f3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include inc_cp437.glsl
|
#include inc_cp437.glsl
|
||||||
|
|
||||||
// SRC 7 : cp437
|
// SRC 7 : cp437
|
||||||
subroutine(src_stage_sub) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -215,7 +304,7 @@ subroutine(src_stage_sub) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
int code = ((charset_ctrl.y < 1 || (uv2i.x % 2 ^ uv2i.y % 2) > 0) ? 1 : 0) * (start_char + int((rand(uv2i) + char_delta) * char_span) % char_span);
|
int code = ((charset_ctrl.y < 1 || (uv2i.x % 2 ^ uv2i.y % 2) > 0) ? 1 : 0) * (start_char + int((rand(uv2i) + char_delta) * char_span) % char_span);
|
||||||
uv2 = mod(uv2, 1);
|
uv2 = mod(uv2, 1);
|
||||||
float f = char(uv2, code) ? 1 : 0;
|
float f = char(uv2, code) ? 1 : 0;
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,11 +312,11 @@ subroutine(src_stage_sub) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
|
|
||||||
#include inc_sentences.glsl
|
#include inc_sentences.glsl
|
||||||
|
|
||||||
subroutine(src_stage_sub) vec4 src_8(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_8(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -247,16 +336,16 @@ subroutine(src_stage_sub) vec4 src_8(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
uv2.x += floor(uv2.y) * (h_delta - 0.5) * 2;
|
uv2.x += floor(uv2.y) * (h_delta - 0.5) * 2;
|
||||||
uv2.y = mix(uv2.y, mod(uv2.y, 1), h_delta_b.x);
|
uv2.y = mix(uv2.y, mod(uv2.y, 1), h_delta_b.x);
|
||||||
float f = write_20(uv2, vec2(-float(lengths[s]) * 0.5, 0), sentences[s]);
|
float f = write_20(uv2, vec2(-float(lengths[s]) * 0.5, 0), sentences[s]);
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 9 : sentences repeat
|
// SRC 9 : sentences repeat
|
||||||
subroutine(src_stage_sub) vec4 src_9(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_9(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -287,11 +376,11 @@ subroutine(src_stage_sub) vec4 src_9(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SRC 10 : isometric grid
|
// SRC 10 : isometric grid
|
||||||
subroutine(src_stage_sub) vec4 src_10(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_10(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -319,7 +408,7 @@ subroutine(src_stage_sub) vec4 src_10(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
vec2 u2 = mod(floor(uv3 + vec2(0, 1)), umax);
|
vec2 u2 = mod(floor(uv3 + vec2(0, 1)), umax);
|
||||||
vec2 u3 = mod(floor(uv3 + vec2(-1, 0)), umax);
|
vec2 u3 = mod(floor(uv3 + vec2(-1, 0)), umax);
|
||||||
vec2 u4 = mod(floor(uv3 + vec2(0, -1)), umax);
|
vec2 u4 = mod(floor(uv3 + vec2(0, -1)), umax);
|
||||||
|
|
||||||
float e0 = (rand(floor(u0)) * 2 - 1) * max_elevation;
|
float e0 = (rand(floor(u0)) * 2 - 1) * max_elevation;
|
||||||
float e1 = (rand(floor(u1)) * 2 - 1) * max_elevation;
|
float e1 = (rand(floor(u1)) * 2 - 1) * max_elevation;
|
||||||
float e2 = (rand(floor(u2)) * 2 - 1) * max_elevation;
|
float e2 = (rand(floor(u2)) * 2 - 1) * max_elevation;
|
||||||
@@ -331,29 +420,29 @@ subroutine(src_stage_sub) vec4 src_10(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
float f = 0;
|
float f = 0;
|
||||||
|
|
||||||
f = line(uv3, vec2(0, 0) - iso_z(e0), vec2(1, 0) - iso_z(e1), thick)
|
f = line(uv3, vec2(0, 0) - iso_z(e0), vec2(1, 0) - iso_z(e1), thick)
|
||||||
+ line(uv3, vec2(0, 0) - iso_z(e0), vec2(0, 1) - iso_z(e2), thick)
|
+ line(uv3, vec2(0, 0) - iso_z(e0), vec2(0, 1) - iso_z(e2), thick)
|
||||||
+ line(uv3, vec2(0, 0) - iso_z(e0), vec2(-1, 0) - iso_z(e3), thick)
|
+ line(uv3, vec2(0, 0) - iso_z(e0), vec2(-1, 0) - iso_z(e3), thick)
|
||||||
+ line(uv3, vec2(0, 0) - iso_z(e0), vec2(0, -1) - iso_z(e4), thick);
|
+ line(uv3, vec2(0, 0) - iso_z(e0), vec2(0, -1) - iso_z(e4), thick);
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 11 : video in 2 + thru
|
// SRC 11 : video in 2 + thru
|
||||||
subroutine(src_stage_sub) vec4 src_11(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_11(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
if (iDemo > 0) {
|
if (iDemo > 0) {
|
||||||
return src_3(vUV, seed, b1, f1, b2, f2, b3, f3);
|
return src_3(vUV, seed, b1, f1, b2, f2, b3, f3);
|
||||||
}
|
}
|
||||||
|
|
||||||
return src_thru(vUV, iTex4, seed, b1, f1, b2, f2, b3, f3);
|
return src_thru(vUV, iTex6, seed, b1, f1, b2, f2, b3, f3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 12 : Scales
|
// SRC 12 : Scales
|
||||||
subroutine(src_stage_sub) vec4 src_12(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_12(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -392,11 +481,11 @@ subroutine(src_stage_sub) vec4 src_12(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SRC 13 : Credenza
|
// SRC 13 : Credenza
|
||||||
subroutine(src_stage_sub) vec4 src_13(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_13(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -411,7 +500,7 @@ subroutine(src_stage_sub) vec4 src_13(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
vec2 uv2 = uv1;
|
vec2 uv2 = uv1;
|
||||||
|
|
||||||
uv2 *= zoom;
|
uv2 *= zoom;
|
||||||
|
|
||||||
uv2 = mod(uv2, 2);
|
uv2 = mod(uv2, 2);
|
||||||
|
|
||||||
uv2 = abs(uv2 - 1);
|
uv2 = abs(uv2 - 1);
|
||||||
@@ -419,16 +508,16 @@ subroutine(src_stage_sub) vec4 src_13(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
float f = istep(1, length(uv2)) * istep(1, length(1 - uv2));
|
float f = istep(1, length(uv2)) * istep(1, length(1 - uv2));
|
||||||
|
|
||||||
f *= istep(0.5, saw((length(uv2) + shape + 0.5) * repeat)) * istep(0.5, saw((length(1 - uv2) + shape + 0.5) * repeat));
|
f *= istep(0.5, saw((length(uv2) + shape + 0.5) * repeat)) * istep(0.5, saw((length(1 - uv2) + shape + 0.5) * repeat));
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 14 : Cursor
|
// SRC 14 : Cursor
|
||||||
subroutine(src_stage_sub) vec4 src_14(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_14(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
// start
|
// start
|
||||||
|
|
||||||
vec2 uv0 = vUV.st;
|
vec2 uv0 = vUV.st;
|
||||||
float ratio = iResolution.x / iResolution.y;
|
float ratio = iResolution.x / iResolution.y;
|
||||||
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
|
||||||
|
|
||||||
@@ -462,15 +551,15 @@ subroutine(src_stage_sub) vec4 src_14(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
|
|
||||||
uv2.y += 0.1;
|
uv2.y += 0.1;
|
||||||
|
|
||||||
f -= istep(0, (uv2.x + uv2.y * 3) * (uv2.x - uv2.y * 3)) * istep(0, uv2.y);
|
f -= istep(0, (uv2.x + uv2.y * 3) * (uv2.x - uv2.y * 3)) * istep(0, uv2.y);
|
||||||
|
|
||||||
f += rect(uv2, vec2(0, -0.04), vec2(0.01, 0.04));
|
f += rect(uv2, vec2(0, -0.04), vec2(0.01, 0.04));
|
||||||
|
|
||||||
return vec4(f);
|
return vec4(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRC 15 : Random
|
// SRC 15 : Random
|
||||||
subroutine(src_stage_sub) vec4 src_15(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
subroutine ( src_stage_sub ) vec4 src_15(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
|
||||||
{
|
{
|
||||||
int src = int(randTime(seed + 100) * 14);
|
int src = int(randTime(seed + 100) * 14);
|
||||||
|
|
||||||
@@ -505,4 +594,4 @@ subroutine(src_stage_sub) vec4 src_15(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#ifndef INC_TEMPLATE
|
#ifndef INC_TEMPLATE
|
||||||
#define INC_TEMPLATE
|
#define INC_TEMPLATE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -50,4 +50,4 @@ float cosTime(float k)
|
|||||||
return cos(modTime(k, 0.5) * 2 * PI);
|
return cos(modTime(k, 0.5) * 2 * PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#ifndef INC_YUV
|
#ifndef INC_YUYV
|
||||||
#define INC_YUV
|
#define INC_YUYV
|
||||||
|
|
||||||
const int YUYV_FOURCC = 1448695129;
|
const int YUYV_FOURCC = 1448695129;
|
||||||
|
|
||||||
const mat3x3 yuv_to_rgb = {{1,1,1},{0,-0.39465,2.03211},{1.13983,-0.5806,0}};
|
const mat3x3 yuyv_to_rgb = {{1,1,1},{0,-0.39465,2.03211},{1.13983,-0.5806,0}};
|
||||||
|
|
||||||
vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) {
|
vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) {
|
||||||
float w = base_width - 1;
|
float w = base_width - 1;
|
||||||
|
|
||||||
int x = int(vUV.x * w);
|
int x = int(vUV.x * w);
|
||||||
|
|
||||||
int xU = x - x % 2;
|
int xU = x - x % 2;
|
||||||
@@ -22,7 +22,7 @@ vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) {
|
|||||||
tV.y - 0.5
|
tV.y - 0.5
|
||||||
);
|
);
|
||||||
|
|
||||||
return vec4(yuv_to_rgb * yuv, 1.0);
|
return vec4(yuyv_to_rgb * yuv, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+54
-50
@@ -1,165 +1,169 @@
|
|||||||
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/28.2.8 Chrome/140.0.7339.249 Electron/38.5.0 Safari/537.36" version="28.2.8">
|
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.1 Chrome/112.0.5615.204 Electron/24.6.1 Safari/537.36" modified="2025-11-13T08:04:14.940Z" version="21.6.1" etag="Os_oMlk_pEsBuxfeX0ax" type="device">
|
||||||
<diagram name="Page-1" id="uAijJZJkDDyZqolEMDYd">
|
<diagram name="Page-1" id="uAijJZJkDDyZqolEMDYd">
|
||||||
<mxGraphModel dx="1848" dy="672" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
<mxGraphModel dx="2022" dy="698" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
<root>
|
<root>
|
||||||
<mxCell id="0" />
|
<mxCell id="0" />
|
||||||
<mxCell id="1" parent="0" />
|
<mxCell id="1" parent="0" />
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-1" value="F.O.R.G.E." style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-1" value="F.O.R.G.E." style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;" parent="1" vertex="1">
|
||||||
<mxGeometry x="154" y="210" width="546" height="350" as="geometry" />
|
<mxGeometry x="154" y="210" width="546" height="350" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-2" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-2" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="270" y="250" width="120" height="60" as="geometry" />
|
<mxGeometry x="270" y="250" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-3" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-3" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="274" y="410" width="120" height="60" as="geometry" />
|
<mxGeometry x="274" y="410" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-4" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-4" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="280" y="260" width="120" height="60" as="geometry" />
|
<mxGeometry x="280" y="260" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-5" value="TEXTURE<br>1...N" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-5" value="TEXTURES<br>1...N" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="290" y="270" width="120" height="60" as="geometry" />
|
<mxGeometry x="290" y="270" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-6" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-6" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="284" y="420" width="120" height="60" as="geometry" />
|
<mxGeometry x="284" y="420" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-7" value="SHADER<br>1...N" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-7" value="FRAGMENT<br>SHADERS<br>1...N" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="294" y="430" width="120" height="60" as="geometry" />
|
<mxGeometry x="294" y="430" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-9" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-9" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="333.5" y="340" as="sourcePoint" />
|
<mxPoint x="333.5" y="340" as="sourcePoint" />
|
||||||
<mxPoint x="333.5" y="400.5" as="targetPoint" />
|
<mxPoint x="333.5" y="400.5" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-11" value="UNIFORM<br>SAMPLERS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3Uv0AfHo8SbA6Qcxonjd-9">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-11" value="UNIFORM<br>SAMPLERS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="3Uv0AfHo8SbA6Qcxonjd-9" vertex="1" connectable="0">
|
||||||
<mxGeometry x="0.1111" relative="1" as="geometry">
|
<mxGeometry x="0.1111" relative="1" as="geometry">
|
||||||
<mxPoint x="-40" y="-13" as="offset" />
|
<mxPoint x="-40" y="-13" as="offset" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-10" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-10" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="370" y="400" as="sourcePoint" />
|
<mxPoint x="370" y="400" as="sourcePoint" />
|
||||||
<mxPoint x="370" y="340" as="targetPoint" />
|
<mxPoint x="370" y="340" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-12" value="RENDERS TO<br>FRAMEBUFFERS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3Uv0AfHo8SbA6Qcxonjd-10">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-12" value="RENDERS TO<br>FRAMEBUFFERS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="3Uv0AfHo8SbA6Qcxonjd-10" vertex="1" connectable="0">
|
||||||
<mxGeometry x="-0.3556" y="2" relative="1" as="geometry">
|
<mxGeometry x="-0.3556" y="2" relative="1" as="geometry">
|
||||||
<mxPoint x="62" y="-1" as="offset" />
|
<mxPoint x="62" y="-1" as="offset" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-13" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-13" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="140" y="300" as="sourcePoint" />
|
<mxPoint x="140" y="300" as="sourcePoint" />
|
||||||
<mxPoint x="260" y="299.5" as="targetPoint" />
|
<mxPoint x="260" y="299.5" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-14" value="DMA<div>BUFFERS</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3Uv0AfHo8SbA6Qcxonjd-13">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-14" value="DMA<div>BUFFERS</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="3Uv0AfHo8SbA6Qcxonjd-13" vertex="1" connectable="0">
|
||||||
<mxGeometry x="0.1111" relative="1" as="geometry">
|
<mxGeometry x="0.1111" relative="1" as="geometry">
|
||||||
<mxPoint x="-10" y="-19" as="offset" />
|
<mxPoint x="-10" y="-19" as="offset" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-15" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-19" value="OUTPUT<br>SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
|
||||||
<mxPoint x="140" y="450.5" as="sourcePoint" />
|
|
||||||
<mxPoint x="260" y="450" as="targetPoint" />
|
|
||||||
</mxGeometry>
|
|
||||||
</mxCell>
|
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-16" value="UNIFORMS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3Uv0AfHo8SbA6Qcxonjd-15">
|
|
||||||
<mxGeometry x="0.1111" relative="1" as="geometry">
|
|
||||||
<mxPoint x="-10" y="-19" as="offset" />
|
|
||||||
</mxGeometry>
|
|
||||||
</mxCell>
|
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-19" value="OUTPUT<br>SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
|
||||||
<mxGeometry x="530" y="270" width="120" height="60" as="geometry" />
|
<mxGeometry x="530" y="270" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-23" value="MONITOR<br>SHADER" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-23" value="MONITOR<br>SHADER" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="530" y="360" width="120" height="60" as="geometry" />
|
<mxGeometry x="530" y="360" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-24" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;dashed=1;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-24" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;dashed=1;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="420" y="320" as="sourcePoint" />
|
<mxPoint x="420" y="320" as="sourcePoint" />
|
||||||
<mxPoint x="520" y="360" as="targetPoint" />
|
<mxPoint x="520" y="360" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-25" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-25" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="420" y="290" as="sourcePoint" />
|
<mxPoint x="420" y="290" as="sourcePoint" />
|
||||||
<mxPoint x="520" y="290" as="targetPoint" />
|
<mxPoint x="520" y="290" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-26" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-26" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="349.5" y="585" as="sourcePoint" />
|
<mxPoint x="349.5" y="585" as="sourcePoint" />
|
||||||
<mxPoint x="349.5" y="495" as="targetPoint" />
|
<mxPoint x="350" y="500" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-27" value="COMPILES<br>TO" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3Uv0AfHo8SbA6Qcxonjd-26">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-27" value="COMPILES<br>TO" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="3Uv0AfHo8SbA6Qcxonjd-26" vertex="1" connectable="0">
|
||||||
<mxGeometry x="0.1111" relative="1" as="geometry">
|
<mxGeometry x="0.1111" relative="1" as="geometry">
|
||||||
<mxPoint x="-55" y="-15" as="offset" />
|
<mxPoint x="-55" y="-15" as="offset" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-28" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-28" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="274" y="590" width="120" height="60" as="geometry" />
|
<mxGeometry x="274" y="590" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-29" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-29" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="284" y="600" width="120" height="60" as="geometry" />
|
<mxGeometry x="284" y="600" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-30" value="GLSL FILE<br>1...N" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-30" value="GLSL FILES<br>1...N" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="294" y="610" width="120" height="60" as="geometry" />
|
<mxGeometry x="294" y="610" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-31" value="MIDI INPUT" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-31" value="MIDI<br>INPUT" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="10" y="420" width="120" height="60" as="geometry" />
|
<mxGeometry x="460" y="610" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-36" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-36" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-10" y="250" width="120" height="60" as="geometry" />
|
<mxGeometry x="-10" y="250" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-37" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-37" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry y="260" width="120" height="60" as="geometry" />
|
<mxGeometry y="260" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-38" value="VIDEO DEVICE<br>1...N" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-38" value="VIDEO DEVICE<br>1...N" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="10" y="270" width="120" height="60" as="geometry" />
|
<mxGeometry x="10" y="270" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-39" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-39" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="660" y="299.5" as="sourcePoint" />
|
<mxPoint x="660" y="299.5" as="sourcePoint" />
|
||||||
<mxPoint x="760" y="299.5" as="targetPoint" />
|
<mxPoint x="760" y="299.5" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-40" value="OUTPUT<br>WINDOW" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-40" value="OUTPUT<br>WINDOW" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="770" y="270" width="120" height="60" as="geometry" />
|
<mxGeometry x="770" y="270" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-41" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;dashed=1;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-41" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;dashed=1;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="660" y="389.5" as="sourcePoint" />
|
<mxPoint x="660" y="389.5" as="sourcePoint" />
|
||||||
<mxPoint x="760" y="389.5" as="targetPoint" />
|
<mxPoint x="760" y="389.5" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-42" value="MONITOR<br>WINDOW" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-42" value="MONITOR<br>WINDOW" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="770" y="360" width="120" height="60" as="geometry" />
|
<mxGeometry x="770" y="360" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-43" value="CONTEXT" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-43" value="STATE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="530" y="460" width="120" height="60" as="geometry" />
|
<mxGeometry x="530" y="460" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-46" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-46" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="510" y="490" as="sourcePoint" />
|
<mxPoint x="510" y="490" as="sourcePoint" />
|
||||||
<mxPoint x="430" y="450" as="targetPoint" />
|
<mxPoint x="430" y="450" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-47" value="UNIFORMS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3Uv0AfHo8SbA6Qcxonjd-46">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-47" value="UNIFORMS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="3Uv0AfHo8SbA6Qcxonjd-46" vertex="1" connectable="0">
|
||||||
<mxGeometry x="0.1111" relative="1" as="geometry">
|
<mxGeometry x="0.1111" relative="1" as="geometry">
|
||||||
<mxPoint x="25" y="-18" as="offset" />
|
<mxPoint x="25" y="-18" as="offset" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-52" value="MIDI OUTPUT" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-52" value="MIDI OUTPUT" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="770" y="460" width="120" height="60" as="geometry" />
|
<mxGeometry x="770" y="460" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-55" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-55" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
|
||||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="660" y="490" as="sourcePoint" />
|
<mxPoint x="660" y="490" as="sourcePoint" />
|
||||||
<mxPoint x="760" y="490" as="targetPoint" />
|
<mxPoint x="760" y="490" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
|
<mxCell id="WElHySgPOBnYc4yB3MP0-2" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;entryX=0.744;entryY=0.914;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" target="3Uv0AfHo8SbA6Qcxonjd-1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="520" y="600" as="sourcePoint" />
|
||||||
|
<mxPoint x="539.58" y="530" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="WElHySgPOBnYc4yB3MP0-4" value="KEYBOARD<br>INPUT" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="620" y="610" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="WElHySgPOBnYc4yB3MP0-5" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;entryX=0.872;entryY=0.914;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" target="3Uv0AfHo8SbA6Qcxonjd-1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="680" y="600" as="sourcePoint" />
|
||||||
|
<mxPoint x="679.58" y="530" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
</root>
|
</root>
|
||||||
</mxGraphModel>
|
</mxGraphModel>
|
||||||
</diagram>
|
</diagram>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 71 KiB |
@@ -33,8 +33,6 @@ UNIFORM_BEATS=iBeats
|
|||||||
UNIFORM_FPS=iFPS
|
UNIFORM_FPS=iFPS
|
||||||
# 0/1 if demo
|
# 0/1 if demo
|
||||||
UNIFORM_DEMO=iDemo
|
UNIFORM_DEMO=iDemo
|
||||||
# 0/1 if auto random
|
|
||||||
UNIFORM_AUTORAND=iAutoRand
|
|
||||||
# Seed for shader X
|
# Seed for shader X
|
||||||
UNIFORM_SEED_PREFIX=iSeed
|
UNIFORM_SEED_PREFIX=iSeed
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ uniform float iTempo; // current tempo in bpm
|
|||||||
uniform float iBeats; // elapsed beats since last tempo reset
|
uniform float iBeats; // elapsed beats since last tempo reset
|
||||||
uniform int iFPS; // output window frames per seconds
|
uniform int iFPS; // output window frames per seconds
|
||||||
uniform int iDemo; // 0/1 if demo mode
|
uniform int iDemo; // 0/1 if demo mode
|
||||||
uniform int iAutoRand; // 0/1 if auto random mode
|
|
||||||
uniform int iSeed1; // a random seed assigned at start
|
uniform int iSeed1; // a random seed assigned at start
|
||||||
uniform vec2 iResolution; // output window resolution in pixels
|
uniform vec2 iResolution; // output window resolution in pixels
|
||||||
uniform vec3 iMidi1_1[20]; // all midi inputs defined
|
uniform vec3 iMidi1_1[20]; // all midi inputs defined
|
||||||
|
|||||||
+91
-61
@@ -1,4 +1,3 @@
|
|||||||
#include <bsd/string.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -13,61 +12,68 @@
|
|||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
static void print_help(int status_code) {
|
static void print_help(int status_code) {
|
||||||
puts(PACKAGE
|
puts(
|
||||||
" " VERSION "\n\n"
|
PACKAGE
|
||||||
"usage: " PACKAGE " "
|
" " VERSION "\n\n"
|
||||||
"[-h] "
|
"usage: " PACKAGE " "
|
||||||
"[-v] "
|
"[-h] "
|
||||||
"[-p=PROJECT_PATH] "
|
"[-v] "
|
||||||
"[-c=CFG_FILE] "
|
"[-p=PROJECT_PATH] "
|
||||||
"[-hr] "
|
"[-c=CFG_FILE] "
|
||||||
"[-s=SCREEN] "
|
"[-hr] "
|
||||||
"[-m=SCREEN] "
|
"[-s=SCREEN] "
|
||||||
"[-mo] "
|
"[-m=SCREEN] "
|
||||||
"[-w] "
|
"[-mo] "
|
||||||
"[-t=TEMPO] "
|
"[-w] "
|
||||||
"[-d] "
|
"[-t=TEMPO] "
|
||||||
"[-ar / -nar] "
|
"[-d] "
|
||||||
"[-v=FILE] "
|
"[-ar / -nar] "
|
||||||
"[-vs=SIZE] "
|
"[-arc=CYCLES] "
|
||||||
"[-is=SIZE] "
|
#ifdef VIDEO_IN
|
||||||
"[-sf=STATE_PATH] "
|
"[-vi=FILE] "
|
||||||
"[-ls / -nls] "
|
"[-vs=SIZE] "
|
||||||
"[-ss / -nss] "
|
"[-vr / -nvr] "
|
||||||
"[-tm] "
|
#endif /* VIDEO_IN */
|
||||||
"[-tf] "
|
"[-is=SIZE] "
|
||||||
"\n\n"
|
"[-ls / -nls] "
|
||||||
"Fusion Of Real-time Generative Effects.\n\n"
|
"[-ss / -nss] "
|
||||||
"options:\n"
|
"[-tm] "
|
||||||
" -h, --help show this help message and exit\n"
|
"[-tf] "
|
||||||
" -v, --version print version\n"
|
"\n\n"
|
||||||
" -p, --project forge project directory (default: " DATADIR
|
"Fusion Of Real-time Generative Effects.\n\n"
|
||||||
"/default)\n"
|
"options:\n"
|
||||||
" -c, --config config file name (default: "
|
" -h, --help show this help message and exit\n"
|
||||||
"forge_project.cfg)\n"
|
" -v, --version print version\n"
|
||||||
" -hr, --hot-reload hot reload of shaders scripts\n"
|
" -p, --project forge project directory (default: " DATADIR
|
||||||
" -s, --screen output screen number (default: primary)\n"
|
"/default)\n"
|
||||||
" -m, --monitor monitor screen number (default: none)\n"
|
" -c, --config config file name (default: "
|
||||||
" -mo, --monitor-only no output screen\n"
|
"forge_project.cfg)\n"
|
||||||
" -w, --windowed not fullscreen\n"
|
" -hr, --hot-reload hot reload of shaders scripts\n"
|
||||||
" -t, --tempo base tempo (default: 60)\n"
|
" -s, --screen output screen number (default: primary)\n"
|
||||||
" -d, --demo demonstration mode (assume "
|
" -m, --monitor monitor screen number (default: none)\n"
|
||||||
"--no-save-state, --no-load-state, --auto-random)\n"
|
" -mo, --monitor-only no output screen\n"
|
||||||
" -ar, --auto-random randomize state every 4 beats\n"
|
" -w, --windowed not fullscreen\n"
|
||||||
" -nar, --no-auto-random do not randomize state (default)\n"
|
" -t, --tempo base tempo (default: 60)\n"
|
||||||
" -v, --video-in path to video capture device (multiple "
|
" -d, --demo demonstration mode (assume "
|
||||||
"allowed)\n"
|
"--no-save-state, --no-load-state, --auto-random)\n"
|
||||||
" -vs, --video-size video capture desired height (default: "
|
" -ar, --auto-random randomize state every cycle (4 beats)\n"
|
||||||
"internal texture height)\n"
|
" -nar, --no-auto-random do not randomize state (default)\n"
|
||||||
" -is, --internal-size internal texture height (default: 720)\n"
|
" -arc, --auto-random-cycle auto random cycle length (default: 4)\n"
|
||||||
" -sf, --state-file saved state file (default: "
|
#ifdef VIDEO_IN
|
||||||
"forge_saved_state.txt)\n"
|
" -vi, --video-in path to video capture device (multiple "
|
||||||
" -ls, --load-state load saved state (default)\n"
|
"allowed)\n"
|
||||||
" -nls, --no-load-state do not load saved state\n"
|
" -vs, --video-size video capture desired height (default: "
|
||||||
" -ss, --save-state save state (default)\n"
|
"internal texture height)\n"
|
||||||
" -nss, --no-save-state do not save state\n"
|
" -vr, --video-reconnect auto-reconnect video (default)\n"
|
||||||
" -tm, --trace-midi print midi code and values\n"
|
" -nvr, --no-video-reconnect do not auto-reconnect video\n"
|
||||||
" -tf, --trace-fps print fps status of subsystems\n");
|
#endif /* VIDEO_IN */
|
||||||
|
" -is, --internal-size internal texture height (default: 720)\n"
|
||||||
|
" -ls, --load-state load saved state (default)\n"
|
||||||
|
" -nls, --no-load-state do not load saved state\n"
|
||||||
|
" -ss, --save-state save state (default)\n"
|
||||||
|
" -nss, --no-save-state do not save state\n"
|
||||||
|
" -tm, --trace-midi print midi code and values\n"
|
||||||
|
" -tf, --trace-fps print fps status of subsystems\n");
|
||||||
exit(status_code);
|
exit(status_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,10 +130,11 @@ void args_parse(Parameters *params, int argc, char **argv) {
|
|||||||
params->base_tempo = 60.0f;
|
params->base_tempo = 60.0f;
|
||||||
params->demo = false;
|
params->demo = false;
|
||||||
params->auto_random = false;
|
params->auto_random = false;
|
||||||
|
params->auto_random_cycle = 4;
|
||||||
params->video_in.length = 0;
|
params->video_in.length = 0;
|
||||||
params->video_size = 0;
|
params->video_size = 0;
|
||||||
|
params->video_reconnect = true;
|
||||||
params->internal_size = 720;
|
params->internal_size = 720;
|
||||||
strlcpy(params->state_file, "forge_saved_state.txt", STR_LEN);
|
|
||||||
params->load_state = true;
|
params->load_state = true;
|
||||||
params->save_state = true;
|
params->save_state = true;
|
||||||
params->trace_midi = false;
|
params->trace_midi = false;
|
||||||
@@ -168,25 +175,48 @@ void args_parse(Parameters *params, int argc, char **argv) {
|
|||||||
params->auto_random = true;
|
params->auto_random = true;
|
||||||
} else if (is_arg(arg, "-nar") || is_arg(arg, "--no-auto-random")) {
|
} else if (is_arg(arg, "-nar") || is_arg(arg, "--no-auto-random")) {
|
||||||
params->auto_random = false;
|
params->auto_random = false;
|
||||||
} else if (is_arg(arg, "-v") || is_arg(arg, "--video-in")) {
|
} else if (is_arg(arg, "-arc") || is_arg(arg, "--auto-random-cycle")) {
|
||||||
|
params->auto_random_cycle = parse_uint(arg, value);
|
||||||
|
if (params->auto_random_cycle == 0) {
|
||||||
|
invalid_value(arg, value);
|
||||||
|
}
|
||||||
|
} else if (is_arg(arg, "-vi") || is_arg(arg, "--video-in")) {
|
||||||
|
#ifdef VIDEO_IN
|
||||||
if (params->video_in.length == MAX_VIDEO) {
|
if (params->video_in.length == MAX_VIDEO) {
|
||||||
log_error("maximum video input reached");
|
log_error("maximum video input reached");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
strlcpy(params->video_in.values[params->video_in.length++], value,
|
strlcpy(params->video_in.values[params->video_in.length++], value,
|
||||||
STR_LEN);
|
STR_LEN);
|
||||||
|
#else
|
||||||
|
invalid_arg(arg);
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
} else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) {
|
} else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) {
|
||||||
|
#ifdef VIDEO_IN
|
||||||
params->video_size = parse_uint(arg, value);
|
params->video_size = parse_uint(arg, value);
|
||||||
if (params->video_size == 0) {
|
if (params->video_size == 0) {
|
||||||
invalid_value(arg, value);
|
invalid_value(arg, value);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
invalid_arg(arg);
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
} else if (is_arg(arg, "-vr") || is_arg(arg, "--video-reconnect")) {
|
||||||
|
#ifdef VIDEO_IN
|
||||||
|
params->video_reconnect = true;
|
||||||
|
#else
|
||||||
|
invalid_arg(arg);
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
} else if (is_arg(arg, "-nvr") || is_arg(arg, "--no-video-reconnect")) {
|
||||||
|
#ifdef VIDEO_IN
|
||||||
|
params->video_reconnect = false;
|
||||||
|
#else
|
||||||
|
invalid_arg(arg);
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
} else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) {
|
} else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) {
|
||||||
params->internal_size = parse_uint(arg, value);
|
params->internal_size = parse_uint(arg, value);
|
||||||
if (params->internal_size == 0) {
|
if (params->internal_size == 0) {
|
||||||
invalid_value(arg, value);
|
invalid_value(arg, value);
|
||||||
}
|
}
|
||||||
} else if (is_arg(arg, "-sf") || is_arg(arg, "--state-file")) {
|
|
||||||
strlcpy(params->state_file, value, STR_LEN);
|
|
||||||
} else if (is_arg(arg, "-ls") || is_arg(arg, "--load-state")) {
|
} else if (is_arg(arg, "-ls") || is_arg(arg, "--load-state")) {
|
||||||
params->load_state = true;
|
params->load_state = true;
|
||||||
} else if (is_arg(arg, "-nls") || is_arg(arg, "--no-load-state")) {
|
} else if (is_arg(arg, "-nls") || is_arg(arg, "--no-load-state")) {
|
||||||
@@ -213,4 +243,4 @@ void args_parse(Parameters *params, int argc, char **argv) {
|
|||||||
if (params->video_size == 0) {
|
if (params->video_size == 0) {
|
||||||
params->video_size = params->internal_size;
|
params->video_size = params->internal_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -5,4 +5,4 @@
|
|||||||
|
|
||||||
void args_parse(Parameters *params, int argc, char **argv);
|
void args_parse(Parameters *params, int argc, char **argv);
|
||||||
|
|
||||||
#endif /* ARGS_H */
|
#endif /* ARGS_H */
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ unsigned int arr_uint_index_of(UintArray array, unsigned int value);
|
|||||||
|
|
||||||
unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index);
|
unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index);
|
||||||
|
|
||||||
#endif /* ARR_H */
|
#endif /* ARR_H */
|
||||||
|
|||||||
+1
-1
@@ -87,4 +87,4 @@
|
|||||||
#define MAX_TAP_VALUES 10
|
#define MAX_TAP_VALUES 10
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* CONFIG_H */
|
#endif /* CONFIG_H */
|
||||||
|
|||||||
+15
-2
@@ -1,4 +1,3 @@
|
|||||||
#include <bsd/string.h>
|
|
||||||
#include <hashmap.h>
|
#include <hashmap.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -75,9 +74,12 @@ void config_file_read(ConfigFile *config, const char *path) {
|
|||||||
file_read(&file, path);
|
file_read(&file, path);
|
||||||
|
|
||||||
if (file.error) {
|
if (file.error) {
|
||||||
|
config->error = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config->error = false;
|
||||||
|
|
||||||
line = strtok_r(file.content, "\n", &rest);
|
line = strtok_r(file.content, "\n", &rest);
|
||||||
|
|
||||||
while (line != NULL) {
|
while (line != NULL) {
|
||||||
@@ -88,6 +90,17 @@ void config_file_read(ConfigFile *config, const char *path) {
|
|||||||
file_free(&file);
|
file_free(&file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool config_file_has(const ConfigFile *config, const char *key) {
|
||||||
|
ConfigFileItem c_key;
|
||||||
|
const ConfigFileItem *item;
|
||||||
|
|
||||||
|
strlcpy(c_key.key, key, STR_LEN);
|
||||||
|
|
||||||
|
item = (const ConfigFileItem *)hashmap_get(config->map, &c_key);
|
||||||
|
|
||||||
|
return item != NULL && strnlen(item->value, STR_LEN) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *config_file_get_str(const ConfigFile *config, const char *key,
|
const char *config_file_get_str(const ConfigFile *config, const char *key,
|
||||||
const char *default_value) {
|
const char *default_value) {
|
||||||
ConfigFileItem c_key;
|
ConfigFileItem c_key;
|
||||||
@@ -125,4 +138,4 @@ unsigned int config_file_get_int(const ConfigFile *config, const char *key,
|
|||||||
return (unsigned int)atoi(item->value);
|
return (unsigned int)atoi(item->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_file_free(const ConfigFile *config) { hashmap_free(config->map); }
|
void config_file_free(const ConfigFile *config) { hashmap_free(config->map); }
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
void config_file_read(ConfigFile *config, const char *path);
|
void config_file_read(ConfigFile *config, const char *path);
|
||||||
|
|
||||||
|
bool config_file_has(const ConfigFile *config, const char *key);
|
||||||
|
|
||||||
const char *config_file_get_str(const ConfigFile *config, const char *key,
|
const char *config_file_get_str(const ConfigFile *config, const char *key,
|
||||||
const char *default_value);
|
const char *default_value);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#include <bsd/string.h>
|
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -10,7 +9,6 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "string.h"
|
|
||||||
|
|
||||||
static time_t get_file_time(const File *file) {
|
static time_t get_file_time(const File *file) {
|
||||||
struct stat attr;
|
struct stat attr;
|
||||||
|
|||||||
+1
-1
@@ -15,4 +15,4 @@ void file_dump(const char *path, const char *content);
|
|||||||
|
|
||||||
void file_free(const File *file);
|
void file_free(const File *file);
|
||||||
|
|
||||||
#endif /* FILE_H */
|
#endif /* FILE_H */
|
||||||
|
|||||||
+209
-140
@@ -4,13 +4,12 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/wait.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "config_file.h"
|
#include "config_file.h"
|
||||||
#include "file.h"
|
|
||||||
#include "forge.h"
|
#include "forge.h"
|
||||||
#include "midi.h"
|
#include "midi.h"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
@@ -22,24 +21,24 @@
|
|||||||
#include "video.h"
|
#include "video.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
|
static Parameters init_params;
|
||||||
static SharedContext *context;
|
static SharedContext *context;
|
||||||
static ShaderProgram program;
|
static ShaderProgram program;
|
||||||
static Window *window_output;
|
static Window *window_output;
|
||||||
static Window *window_monitor;
|
static Window *window_monitor;
|
||||||
static VideoCaptureArray inputs;
|
|
||||||
static Timer timer;
|
static Timer timer;
|
||||||
static MidiDevice midi;
|
static MidiDevice midi;
|
||||||
static bool trace_midi;
|
static bool trace_midi;
|
||||||
static Project project;
|
static Project project;
|
||||||
|
|
||||||
static void compute_fps(bool trace_fps) {
|
static void compute_fps() {
|
||||||
double fps;
|
double fps;
|
||||||
char title[STR_LEN];
|
char title[STR_LEN];
|
||||||
|
|
||||||
if (timer_inc(&timer)) {
|
if (timer_inc(&timer)) {
|
||||||
fps = timer_reset(&timer);
|
fps = timer_reset(&timer);
|
||||||
|
|
||||||
if (trace_fps) {
|
if (init_params.trace_fps) {
|
||||||
log_trace("(main) %.2ffps", fps);
|
log_trace("(main) %.2ffps", fps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,23 +56,16 @@ static void compute_fps(bool trace_fps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_context(const Parameters *params, unsigned int in_count) {
|
static void init_context() {
|
||||||
state_init(context, &project.state_config, params->demo, params->auto_random,
|
context = shared_init_context("/" PACKAGE "_context");
|
||||||
params->base_tempo, params->state_file, params->load_state);
|
|
||||||
|
|
||||||
context->monitor = params->monitor;
|
context->stop = false;
|
||||||
|
|
||||||
|
state_init(context, &project.state_config, init_params.demo,
|
||||||
|
init_params.auto_random, init_params.auto_random_cycle,
|
||||||
|
init_params.base_tempo, init_params.load_state);
|
||||||
|
|
||||||
memset(context->input_resolutions, 0, sizeof(context->input_resolutions));
|
memset(context->input_resolutions, 0, sizeof(context->input_resolutions));
|
||||||
memset(context->input_formats, 0, sizeof(context->input_formats));
|
|
||||||
memset(context->input_fps, 0, sizeof(context->input_fps));
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < in_count; i++) {
|
|
||||||
if (!inputs.values[i].error) {
|
|
||||||
context->input_resolutions[i][0] = inputs.values[i].width;
|
|
||||||
context->input_resolutions[i][1] = inputs.values[i].height;
|
|
||||||
context->input_formats[i] = inputs.values[i].pixelformat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_context() { shared_close_context(context); }
|
static void free_context() { shared_close_context(context); }
|
||||||
@@ -82,33 +74,86 @@ static void reload_shader(unsigned int i) {
|
|||||||
shaders_update(&program, &project.fragment_shaders[i][0], i, &project);
|
shaders_update(&program, &project.fragment_shaders[i][0], i, &project);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_inputs(const StringArray *video_in, unsigned int video_size) {
|
#ifdef VIDEO_IN
|
||||||
inputs.length = video_in->length;
|
static void init_inputs() {
|
||||||
|
context->inputs.length = init_params.video_in.length;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < video_in->length; i++) {
|
for (unsigned int i = 0; i < init_params.video_in.length; i++) {
|
||||||
video_init(&inputs.values[i], video_in->values[i], video_size);
|
video_init(&context->inputs.values[i], init_params.video_in.values[i],
|
||||||
|
init_params.video_size);
|
||||||
|
|
||||||
|
if (!context->inputs.values[i].error) {
|
||||||
|
context->input_resolutions[i][0] = context->inputs.values[i].width;
|
||||||
|
context->input_resolutions[i][1] = context->inputs.values[i].height;
|
||||||
|
context->inputs.values[i].needs_reload = false;
|
||||||
|
context->inputs.values[i].disconnected = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool start_video_captures(unsigned int video_count, bool trace_fps) {
|
static bool reconnect_video_captures() {
|
||||||
for (unsigned int i = 0; i < video_count; i++) {
|
for (unsigned int i = 0; i < init_params.video_in.length; i++) {
|
||||||
if (!inputs.values[i].error &&
|
if (context->inputs.values[i].disconnected) {
|
||||||
!video_background_read(&inputs.values[i], context, i, trace_fps)) {
|
video_init(&context->inputs.values[i], init_params.video_in.values[i],
|
||||||
return false;
|
init_params.video_size);
|
||||||
|
|
||||||
|
if (!context->inputs.values[i].error) {
|
||||||
|
context->input_resolutions[i][0] = context->inputs.values[i].width;
|
||||||
|
context->input_resolutions[i][1] = context->inputs.values[i].height;
|
||||||
|
|
||||||
|
if (!video_background_read(&context->inputs.values[i], context, i,
|
||||||
|
init_params.trace_fps)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->inputs.values[i].needs_reload = true;
|
||||||
|
context->inputs.values[i].disconnected = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_video_captures(unsigned int video_count) {
|
static bool start_video_captures() {
|
||||||
for (unsigned int i = 0; i < video_count; i++) {
|
pid_t pid;
|
||||||
shaders_free_input(&program, &inputs.values[i]);
|
for (unsigned int i = 0; i < context->inputs.length; i++) {
|
||||||
|
if (!context->inputs.values[i].error &&
|
||||||
|
!video_background_read(&context->inputs.values[i], context, i,
|
||||||
|
init_params.trace_fps)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!init_params.video_reconnect) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
log_error("Could not create subprocess");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pid == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
log_info("background reconnect acquisition started (pid: %d)", pid);
|
||||||
|
while (!context->stop) {
|
||||||
|
sleep(1);
|
||||||
|
if (!reconnect_video_captures()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
video_free(&inputs.values[i]);
|
static void free_video_captures() {
|
||||||
|
for (unsigned int i = 0; i < context->inputs.length; i++) {
|
||||||
|
shaders_free_input(&program, i);
|
||||||
|
|
||||||
|
video_free(&context->inputs.values[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
static void error_callback(int error, const char *description) {
|
static void error_callback(int error, const char *description) {
|
||||||
log_error("[GLFW] %d: %s", error, description);
|
log_error("[GLFW] %d: %s", error, description);
|
||||||
window_terminate();
|
window_terminate();
|
||||||
@@ -118,44 +163,126 @@ static void error_callback(int error, const char *description) {
|
|||||||
|
|
||||||
static void key_callback(Window *window, int key,
|
static void key_callback(Window *window, int key,
|
||||||
__attribute__((unused)) int scancode, int action,
|
__attribute__((unused)) int scancode, int action,
|
||||||
__attribute__((unused)) int mods) {
|
int mods) {
|
||||||
|
unsigned int event;
|
||||||
|
|
||||||
|
event = window_read_key(key, action, mods);
|
||||||
|
|
||||||
if (window_escape_key(key, action)) {
|
if (window_escape_key(key, action)) {
|
||||||
// close window on escape key
|
// close window on escape key
|
||||||
log_info("[ESC] Closing...");
|
log_info("[ESC] Closing...");
|
||||||
window_close(window);
|
window_close(window);
|
||||||
} else if (window_char_key(key, action, 82)) {
|
} else if (event > 0) {
|
||||||
// R: randomize
|
state_key_event(context, &project.state_config, event, &midi);
|
||||||
log_info("[R] Randomized");
|
|
||||||
state_randomize(context, &project.state_config);
|
|
||||||
state_apply(context, &project.state_config, &midi);
|
|
||||||
} else if (window_char_key(key, action, 48)) {
|
|
||||||
// 0: reset
|
|
||||||
log_info("[0] Reset");
|
|
||||||
state_reset(context);
|
|
||||||
state_apply(context, &project.state_config, &midi);
|
|
||||||
} else if (window_char_key(key, action, 68)) {
|
|
||||||
// D: demo on/off
|
|
||||||
log_info((context->demo ? "[D] Demo OFF" : "[D] Demo ON"));
|
|
||||||
context->demo = !context->demo;
|
|
||||||
} else if (window_char_key(key, action, 65)) {
|
|
||||||
// A: auto random on/off
|
|
||||||
log_info(
|
|
||||||
(context->auto_random ? "[A] Auto Random OFF" : "[A] Auto Random ON"));
|
|
||||||
context->auto_random = !context->auto_random;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void midi_callback(unsigned char code, unsigned char value) {
|
static void midi_callback(unsigned char code, unsigned char value) {
|
||||||
state_apply_event(context, &project.state_config, &midi, code, value,
|
state_midi_event(context, &project.state_config, &midi, code, value,
|
||||||
trace_midi);
|
trace_midi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loop(bool hr, bool trace_fps) {
|
static bool init(const Parameters *params) {
|
||||||
if (hr) {
|
init_params = *params;
|
||||||
|
|
||||||
|
project_init(&project, params->project_path, params->config_file);
|
||||||
|
|
||||||
|
if (project.error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_context();
|
||||||
|
|
||||||
|
#ifdef VIDEO_IN
|
||||||
|
init_inputs();
|
||||||
|
|
||||||
|
if (!start_video_captures()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
|
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"));
|
||||||
|
|
||||||
|
if (midi.error) {
|
||||||
|
context->demo = true;
|
||||||
|
} else {
|
||||||
|
trace_midi = params->trace_midi;
|
||||||
|
|
||||||
|
if (!midi_background_listen(&midi, context, midi_callback)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state_background_write(context, &project.state_config, &midi)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_startup(error_callback);
|
||||||
|
|
||||||
|
context->tex_resolution[1] = params->internal_size;
|
||||||
|
|
||||||
|
if (params->output) {
|
||||||
|
window_output = window_init(PACKAGE " " VERSION, params->output_screen,
|
||||||
|
params->windowed, NULL, key_callback);
|
||||||
|
|
||||||
|
window_use(window_output, context);
|
||||||
|
|
||||||
|
shaders_init(&program, &project, context, false);
|
||||||
|
} else {
|
||||||
|
window_output = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->monitor) {
|
||||||
|
window_monitor =
|
||||||
|
window_init(PACKAGE " " VERSION " (monitor)", params->monitor_screen,
|
||||||
|
params->windowed, window_output, key_callback);
|
||||||
|
|
||||||
|
window_use(window_monitor, context);
|
||||||
|
|
||||||
|
shaders_init(&program, &project, context, window_output != NULL);
|
||||||
|
} else {
|
||||||
|
window_monitor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VIDEO_IN
|
||||||
|
shaders_link_inputs(&program, &project, &context->inputs);
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
|
if (program.error) {
|
||||||
|
context->stop = true;
|
||||||
|
window_terminate();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_init(&timer, 30);
|
||||||
|
|
||||||
|
log_info("Initialized");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool should_close() {
|
||||||
|
return (window_output != NULL && window_should_close(window_output)) ||
|
||||||
|
(window_monitor != NULL && window_should_close(window_monitor));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool loop() {
|
||||||
|
if (init_params.hot_reload) {
|
||||||
project_reload(&project, reload_shader);
|
project_reload(&project, reload_shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
compute_fps(trace_fps);
|
#ifdef VIDEO_IN
|
||||||
|
if (init_params.video_reconnect) {
|
||||||
|
for (unsigned int i = 0; i < context->inputs.length; i++) {
|
||||||
|
if (context->inputs.values[i].needs_reload) {
|
||||||
|
shaders_relink_input(&program, &project, &context->inputs, i);
|
||||||
|
context->inputs.values[i].needs_reload = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
|
compute_fps();
|
||||||
|
|
||||||
context->time = window_get_time();
|
context->time = window_get_time();
|
||||||
context->tempo_total = (float)tempo_total(&context->tempo);
|
context->tempo_total = (float)tempo_total(&context->tempo);
|
||||||
@@ -177,89 +304,15 @@ static void loop(bool hr, bool trace_fps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
window_events();
|
window_events();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void forge_run(const Parameters *params) {
|
static void shutdown() {
|
||||||
context = shared_init_context("/" PACKAGE "_context");
|
|
||||||
|
|
||||||
context->stop = false;
|
|
||||||
|
|
||||||
project_init(&project, params->project_path, params->config_file);
|
|
||||||
|
|
||||||
if (project.error) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_inputs(¶ms->video_in, params->video_size);
|
|
||||||
|
|
||||||
init_context(params, project.in_count);
|
|
||||||
|
|
||||||
if (!start_video_captures(params->video_in.length, params->trace_fps)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"));
|
|
||||||
|
|
||||||
if (midi.error) {
|
|
||||||
context->demo = true;
|
|
||||||
} else {
|
|
||||||
trace_midi = params->trace_midi;
|
|
||||||
|
|
||||||
if (!midi_background_listen(&midi, context, midi_callback)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state_background_write(context, &project.state_config, &midi)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_startup(error_callback);
|
|
||||||
|
|
||||||
context->tex_resolution[1] = params->internal_size;
|
|
||||||
|
|
||||||
if (params->output) {
|
|
||||||
window_output = window_init(PACKAGE " " VERSION, params->output_screen,
|
|
||||||
params->windowed, NULL, key_callback);
|
|
||||||
|
|
||||||
window_use(window_output, context);
|
|
||||||
|
|
||||||
shaders_init(&program, &project, context, &inputs, false);
|
|
||||||
} else {
|
|
||||||
window_output = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params->monitor) {
|
|
||||||
window_monitor =
|
|
||||||
window_init(PACKAGE " " VERSION " (monitor)", params->monitor_screen,
|
|
||||||
params->windowed, window_output, key_callback);
|
|
||||||
|
|
||||||
window_use(window_monitor, context);
|
|
||||||
|
|
||||||
shaders_init(&program, &project, context, &inputs, window_output != NULL);
|
|
||||||
} else {
|
|
||||||
window_monitor = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (program.error) {
|
|
||||||
context->stop = true;
|
|
||||||
window_terminate();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
timer_init(&timer, 30);
|
|
||||||
|
|
||||||
log_info("Initialized");
|
|
||||||
|
|
||||||
while ((window_output == NULL || !window_should_close(window_output)) &&
|
|
||||||
(window_monitor == NULL || !window_should_close(window_monitor))) {
|
|
||||||
loop(params->hot_reload, params->trace_fps);
|
|
||||||
}
|
|
||||||
|
|
||||||
context->stop = true;
|
context->stop = true;
|
||||||
|
|
||||||
if (params->save_state) {
|
if (init_params.save_state) {
|
||||||
state_save(context, &project.state_config, params->state_file);
|
state_save(context, &project.state_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
shaders_free(&program);
|
shaders_free(&program);
|
||||||
@@ -273,14 +326,30 @@ void forge_run(const Parameters *params) {
|
|||||||
if (window_monitor != NULL) {
|
if (window_monitor != NULL) {
|
||||||
window_use(window_monitor, context);
|
window_use(window_monitor, context);
|
||||||
|
|
||||||
shaders_free_window(&program, params->output);
|
shaders_free_window(&program, init_params.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_video_captures(params->video_in.length);
|
#ifdef VIDEO_IN
|
||||||
|
free_video_captures();
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
free_context();
|
free_context();
|
||||||
|
|
||||||
project_free(&project);
|
project_free(&project);
|
||||||
|
|
||||||
window_terminate();
|
window_terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void forge_run(const Parameters *params) {
|
||||||
|
if (!init(params)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!should_close()) {
|
||||||
|
if (!loop()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -5,4 +5,4 @@
|
|||||||
|
|
||||||
void forge_run(const Parameters *params);
|
void forge_run(const Parameters *params);
|
||||||
|
|
||||||
#endif /* FORGE_H */
|
#endif /* FORGE_H */
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
puts(PACKAGE " " VERSION);
|
puts(PACKAGE " " VERSION);
|
||||||
|
|
||||||
set_seed((unsigned long)time(NULL));
|
rand_set_seed((unsigned long)time(NULL));
|
||||||
|
|
||||||
forge_run(¶ms);
|
forge_run(¶ms);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,4 +3,4 @@
|
|||||||
|
|
||||||
int main(int argc, char **argv);
|
int main(int argc, char **argv);
|
||||||
|
|
||||||
#endif /* MAIN_H */
|
#endif /* MAIN_H */
|
||||||
|
|||||||
+7
-4
@@ -1,11 +1,10 @@
|
|||||||
#include <GLFW/glfw3.h>
|
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#include <bsd/string.h>
|
#include <log.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
void midi_open(MidiDevice *device, const char *name) {
|
void midi_open(MidiDevice *device, const char *name) {
|
||||||
strlcpy(device->name, name, STR_LEN);
|
strlcpy(device->name, name, STR_LEN);
|
||||||
@@ -21,6 +20,10 @@ void midi_open(MidiDevice *device, const char *name) {
|
|||||||
|
|
||||||
void midi_write(const MidiDevice *device, unsigned char code,
|
void midi_write(const MidiDevice *device, unsigned char code,
|
||||||
unsigned char value) {
|
unsigned char value) {
|
||||||
|
if (device->error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char buffer[3];
|
unsigned char buffer[3];
|
||||||
|
|
||||||
buffer[0] = 0xB0;
|
buffer[0] = 0xB0;
|
||||||
@@ -57,5 +60,5 @@ bool midi_background_listen(const MidiDevice *device,
|
|||||||
|
|
||||||
log_info("(%s) background acquisition stopped by main thread (pid: %d)",
|
log_info("(%s) background acquisition stopped by main thread (pid: %d)",
|
||||||
device->name, pid);
|
device->name, pid);
|
||||||
return false;
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -11,4 +11,4 @@ bool midi_background_listen(const MidiDevice *device,
|
|||||||
void (*event_callback)(unsigned char code,
|
void (*event_callback)(unsigned char code,
|
||||||
unsigned char value));
|
unsigned char value));
|
||||||
|
|
||||||
#endif /* MIDI_H */
|
#endif /* MIDI_H */
|
||||||
|
|||||||
+2
-3
@@ -1,4 +1,4 @@
|
|||||||
#include <bsd/string.h>
|
#include <log.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "config_file.h"
|
#include "config_file.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "log.h"
|
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
@@ -141,4 +140,4 @@ void project_free(const Project *project) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config_file_free(&project->config);
|
config_file_free(&project->config);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -10,4 +10,4 @@ void project_reload(Project *project, void (*reload_callback)(unsigned int));
|
|||||||
|
|
||||||
void project_free(const Project *project);
|
void project_free(const Project *project);
|
||||||
|
|
||||||
#endif /* PROJECT_H */
|
#endif /* PROJECT_H */
|
||||||
|
|||||||
+2
-2
@@ -13,11 +13,11 @@ static unsigned long rand(void) {
|
|||||||
return (unsigned long)(x >> (22 + count));
|
return (unsigned long)(x >> (22 + count));
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_seed(unsigned long long seed) {
|
void rand_set_seed(unsigned long long seed) {
|
||||||
mcg_state = 2 * seed + 1;
|
mcg_state = 2 * seed + 1;
|
||||||
(void)rand();
|
(void)rand();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int rand_uint(const unsigned int max) {
|
unsigned int rand_uint(const unsigned int max) {
|
||||||
return max == 0 ? 0 : (unsigned int)(rand() % max);
|
return max == 0 ? 0 : (unsigned int)(rand() % max);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
#ifndef RAND_H
|
#ifndef RAND_H
|
||||||
#define RAND_H
|
#define RAND_H
|
||||||
|
|
||||||
void set_seed(unsigned long long seed);
|
void rand_set_seed(unsigned long long seed);
|
||||||
unsigned int rand_uint(unsigned int max);
|
unsigned int rand_uint(unsigned int max);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+368
-143
@@ -14,75 +14,153 @@
|
|||||||
#define GLAD_GL_IMPLEMENTATION
|
#define GLAD_GL_IMPLEMENTATION
|
||||||
#include <glad/gl.h>
|
#include <glad/gl.h>
|
||||||
|
|
||||||
|
#ifdef VIDEO_IN
|
||||||
#define GLAD_EGL_IMPLEMENTATION
|
#define GLAD_EGL_IMPLEMENTATION
|
||||||
#include <glad/egl.h>
|
#include <glad/egl.h>
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
#ifdef VIDEO_IN
|
||||||
#include <GLFW/glfw3native.h>
|
#include <GLFW/glfw3native.h>
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
static const GLuint unused_uniform = (GLuint)-1;
|
static const GLuint unused_uniform = (GLuint)-1;
|
||||||
|
|
||||||
bool check_glerror(ShaderProgram *program) {
|
bool check_glerror_ro(const char *context) {
|
||||||
unsigned int code;
|
unsigned int code;
|
||||||
|
|
||||||
code = glGetError();
|
code = glGetError();
|
||||||
|
|
||||||
if (code > 0) {
|
if (code > 0) {
|
||||||
log_warn("GL Error: %04x", code);
|
log_warn("GL Error: %04x (%s)", code, context);
|
||||||
program->error = true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return code > 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_gl(ShaderProgram *program) {
|
bool check_glerror(ShaderProgram *program, const char *context) {
|
||||||
|
if (check_glerror_ro(context)) {
|
||||||
|
program->error = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_eglerror_ro(const char *context) {
|
||||||
|
unsigned int code;
|
||||||
|
|
||||||
|
code = eglGetError();
|
||||||
|
|
||||||
|
if (code > 0 && code != EGL_SUCCESS) {
|
||||||
|
log_warn("EGL Error: %04x (%s)", code, context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_eglerror(ShaderProgram *program, const char *context) {
|
||||||
|
if (check_eglerror_ro(context)) {
|
||||||
|
program->error = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool init_gl(ShaderProgram *program) {
|
||||||
gladLoadGL(glfwGetProcAddress);
|
gladLoadGL(glfwGetProcAddress);
|
||||||
|
|
||||||
|
#ifdef VIDEO_IN
|
||||||
program->egl_display = glfwGetEGLDisplay();
|
program->egl_display = glfwGetEGLDisplay();
|
||||||
if (program->egl_display == EGL_NO_DISPLAY) {
|
if (program->egl_display == EGL_NO_DISPLAY) {
|
||||||
log_error("error: glfwGetEGLDisplay no EGLDisplay returned");
|
log_error("error: glfwGetEGLDisplay no EGLDisplay returned");
|
||||||
program->error = true;
|
program->error = true;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
gladLoadEGL(program->egl_display, glfwGetProcAddress);
|
gladLoadEGL(program->egl_display, glfwGetProcAddress);
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
|
return !check_glerror(program, "init_gl") &&
|
||||||
|
!check_eglerror(program, "init_gl");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_textures(ShaderProgram *program,
|
static bool init_textures(ShaderProgram *program,
|
||||||
const SharedContext *context) {
|
const SharedContext *context) {
|
||||||
glGenTextures(program->tex_count, program->textures);
|
glGenTextures(program->tex_count, program->textures);
|
||||||
|
if (check_glerror(program, "init_textures/glGenTextures")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < program->tex_count; i++) {
|
for (unsigned int i = 0; i < program->tex_count; i++) {
|
||||||
// selects which texture unit subsequent texture state calls will affect
|
// selects which texture unit subsequent texture state calls will affect
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
if (check_glerror(program, "init_textures/glActiveTexture")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, program->textures[i]);
|
glBindTexture(GL_TEXTURE_2D, program->textures[i]);
|
||||||
|
if (check_glerror(program, "init_textures/glBindTexture")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
if (check_glerror(program, "init_textures/glDisable")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// define texture image as empty
|
// define texture image as empty
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
|
||||||
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
||||||
|
if (check_glerror(program, "init_textures/glTexImage2D")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// setup mipmap context
|
// setup mipmap context
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
if (check_glerror(program, "init_textures/glTexParameteri")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
log_info("Texture %d initialized", i);
|
log_info("Texture %d initialized", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rebind_textures(const ShaderProgram *program) {
|
static void rebind_textures(const ShaderProgram *program) {
|
||||||
for (unsigned int i = 0; i < program->tex_count; i++) {
|
for (unsigned int i = 0; i < program->tex_count; i++) {
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
check_glerror_ro("rebind_textures/glActiveTexture");
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, program->textures[i]);
|
glBindTexture(GL_TEXTURE_2D, program->textures[i]);
|
||||||
|
check_glerror_ro("rebind_textures/glBindTexture");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void link_input_to_texture(ShaderProgram *program, VideoCapture *input,
|
#ifdef VIDEO_IN
|
||||||
unsigned int texture_index) {
|
static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input,
|
||||||
input->dma_image = EGL_NO_IMAGE_KHR;
|
unsigned int input_index,
|
||||||
|
unsigned int texture_index, bool swap,
|
||||||
|
bool reload) {
|
||||||
|
if (reload) {
|
||||||
|
glDeleteTextures(1, program->textures + texture_index);
|
||||||
|
if (check_glerror(program, "link_input_to_texture/glDeleteTextures")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glGenTextures(1, program->textures + texture_index);
|
||||||
|
if (check_glerror(program, "link_input_to_texture/glGenTextures")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLImageKHR dma_image;
|
||||||
|
|
||||||
|
dma_image = EGL_NO_IMAGE_KHR;
|
||||||
|
|
||||||
// https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
|
// https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
|
||||||
const EGLint attrib_list[] = {EGL_WIDTH,
|
const EGLint attrib_list[] = {EGL_WIDTH,
|
||||||
@@ -92,57 +170,90 @@ static void link_input_to_texture(ShaderProgram *program, VideoCapture *input,
|
|||||||
EGL_LINUX_DRM_FOURCC_EXT,
|
EGL_LINUX_DRM_FOURCC_EXT,
|
||||||
input->pixelformat,
|
input->pixelformat,
|
||||||
EGL_DMA_BUF_PLANE0_FD_EXT,
|
EGL_DMA_BUF_PLANE0_FD_EXT,
|
||||||
input->exp_fd,
|
swap ? input->exp_fd_swap : input->exp_fd,
|
||||||
EGL_DMA_BUF_PLANE0_OFFSET_EXT,
|
EGL_DMA_BUF_PLANE0_OFFSET_EXT,
|
||||||
0,
|
0,
|
||||||
EGL_DMA_BUF_PLANE0_PITCH_EXT,
|
EGL_DMA_BUF_PLANE0_PITCH_EXT,
|
||||||
input->bytesperline,
|
input->bytesperline,
|
||||||
EGL_NONE};
|
EGL_NONE};
|
||||||
|
|
||||||
input->dma_image =
|
dma_image = eglCreateImageKHR(program->egl_display, EGL_NO_CONTEXT,
|
||||||
eglCreateImageKHR(program->egl_display, EGL_NO_CONTEXT,
|
EGL_LINUX_DMA_BUF_EXT, NULL, attrib_list);
|
||||||
EGL_LINUX_DMA_BUF_EXT, NULL, attrib_list);
|
if (check_eglerror(program, "link_input_to_texture/eglCreateImageKHR")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (input->dma_image == EGL_NO_IMAGE_KHR) {
|
if (swap) {
|
||||||
log_error("(%s) eglCreateImageKHR failed %04x", input->name, eglGetError());
|
program->dma_images_swap[input_index] = dma_image;
|
||||||
return;
|
} else {
|
||||||
|
program->dma_images[input_index] = dma_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + texture_index);
|
glActiveTexture(GL_TEXTURE0 + texture_index);
|
||||||
|
if (check_glerror(program, "link_input_to_texture/glActiveTexture")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, program->textures[texture_index]);
|
glBindTexture(GL_TEXTURE_2D, program->textures[texture_index]);
|
||||||
|
if (check_glerror(program, "link_input_to_texture/glBindTexture")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, input->width, input->height, 0, GL_RGB,
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, input->width, input->height, 0, GL_RGB,
|
||||||
GL_UNSIGNED_BYTE, 0);
|
GL_UNSIGNED_BYTE, 0);
|
||||||
|
if (check_glerror(program, "link_input_to_texture/glTexImage2D")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt
|
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt
|
||||||
glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, input->dma_image, NULL);
|
glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, dma_image, NULL);
|
||||||
|
if (check_eglerror(program,
|
||||||
|
"link_input_to_texture/glEGLImageTargetTexStorageEXT")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
log_info("Texture %d linked to %s", texture_index, input->name);
|
log_info("Texture %d linked to %s", texture_index, input->name);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_input(ShaderProgram *program, const ConfigFile *config,
|
static bool init_input(ShaderProgram *program, const ConfigFile *config,
|
||||||
VideoCaptureArray *inputs) {
|
VideoCaptureArray *inputs, unsigned int i, bool reload) {
|
||||||
unsigned int tex_i;
|
unsigned int tex_i;
|
||||||
char name[STR_LEN];
|
char name[STR_LEN];
|
||||||
|
|
||||||
for (unsigned int i = 0; i < program->in_count; i++) {
|
if (i < inputs->length && !inputs->values[i].error) {
|
||||||
if (i < inputs->length && !inputs->values[i].error) {
|
snprintf(name, STR_LEN, "IN_%d_OUT", i + 1);
|
||||||
snprintf(name, STR_LEN, "IN_%d_OUT", i + 1);
|
tex_i = config_file_get_int(config, name, 0);
|
||||||
tex_i = config_file_get_int(config, name, 0);
|
if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, false,
|
||||||
link_input_to_texture(program, &inputs->values[i], tex_i);
|
reload)) {
|
||||||
} else {
|
return false;
|
||||||
log_warn("Cannot link input %d", i + 1);
|
|
||||||
}
|
}
|
||||||
|
if (inputs->values[i].with_swap) {
|
||||||
|
snprintf(name, STR_LEN, "IN_%d_SWAP_OUT", i + 1);
|
||||||
|
tex_i = config_file_get_int(config, name, 0);
|
||||||
|
if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, true,
|
||||||
|
reload)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log_warn("Cannot link input %d", i + 1);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
static void init_framebuffers(ShaderProgram *program,
|
static bool init_framebuffers(ShaderProgram *program,
|
||||||
const ConfigFile *config) {
|
const ConfigFile *config) {
|
||||||
unsigned int tex_i;
|
unsigned int tex_i;
|
||||||
char name[STR_LEN];
|
char name[STR_LEN];
|
||||||
|
GLenum framebuffer_status;
|
||||||
|
|
||||||
glGenFramebuffers(program->frag_count, program->frame_buffers);
|
glGenFramebuffers(program->frag_count, program->frame_buffers);
|
||||||
|
if (check_glerror(program, "init_framebuffers/glGenFramebuffers")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < program->frag_count; i++) {
|
for (unsigned int i = 0; i < program->frag_count; i++) {
|
||||||
if (i == program->frag_output_index || i == program->frag_monitor_index) {
|
if (i == program->frag_output_index || i == program->frag_monitor_index) {
|
||||||
@@ -150,48 +261,87 @@ static void init_framebuffers(ShaderProgram *program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, program->frame_buffers[i]);
|
glBindFramebuffer(GL_FRAMEBUFFER, program->frame_buffers[i]);
|
||||||
|
if (check_glerror(program, "init_framebuffers/glBindFramebuffer")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(name, STR_LEN, "FRAG_%d_OUT", i + 1);
|
snprintf(name, STR_LEN, "FRAG_%d_OUT", i + 1);
|
||||||
tex_i = config_file_get_int(config, name, 0);
|
tex_i = config_file_get_int(config, name, 0);
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||||
program->textures[tex_i], 0);
|
program->textures[tex_i], 0);
|
||||||
|
if (check_glerror(program, "init_framebuffers/glFramebufferTexture2D")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// check framebuffer status
|
// check framebuffer status
|
||||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
framebuffer_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
log_error("Framebuffer %d is KO: %x", i + 1,
|
if (check_glerror(program, "init_framebuffers/glCheckFramebufferStatus")) {
|
||||||
glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
return false;
|
||||||
|
}
|
||||||
|
if (framebuffer_status != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
log_error("Framebuffer %d is KO: %x", i + 1, framebuffer_status);
|
||||||
program->error = true;
|
program->error = true;
|
||||||
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("Framebuffer %d initialized", i);
|
log_info("Framebuffer %d initialized", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_vertices(ShaderProgram *program) {
|
static bool init_vertices(ShaderProgram *program) {
|
||||||
glGenBuffers(1, &program->vertex_buffer);
|
glGenBuffers(1, &program->vertex_buffer);
|
||||||
|
if (check_glerror(program, "init_vertices/glGenBuffers")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer);
|
||||||
|
if (check_glerror(program, "init_vertices/glBindBuffer")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||||
|
if (check_glerror(program, "init_vertices/glBufferData")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bind_vertices(ShaderProgram *program, unsigned int index) {
|
static bool bind_vertices(ShaderProgram *program, unsigned int index) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer);
|
||||||
|
if (check_glerror(program, "bind_vertices/glBindBuffer")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glGenVertexArrays(1, &program->vertex_array[index]);
|
glGenVertexArrays(1, &program->vertex_array[index]);
|
||||||
|
if (check_glerror(program, "bind_vertices/glGenVertexArrays")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glBindVertexArray(program->vertex_array[index]);
|
glBindVertexArray(program->vertex_array[index]);
|
||||||
|
if (check_glerror(program, "bind_vertices/glBindVertexArray")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < program->frag_count; i++) {
|
for (unsigned int i = 0; i < program->frag_count; i++) {
|
||||||
// enable attribute pointer
|
// enable attribute pointer
|
||||||
glEnableVertexAttribArray(program->vpos_locations[i]);
|
glEnableVertexAttribArray(program->vpos_locations[i]);
|
||||||
|
if (check_glerror(program, "bind_vertices/glEnableVertexAttribArray")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// specify the location and data format of the array of generic vertex
|
// specify the location and data format of the array of generic vertex
|
||||||
// attributes to use when rendering
|
// attributes to use when rendering
|
||||||
glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE,
|
glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE,
|
||||||
sizeof(Vertex), (void *)offsetof(Vertex, pos));
|
sizeof(Vertex), (void *)offsetof(Vertex, pos));
|
||||||
|
if (check_glerror(program, "bind_vertices/glVertexAttribPointer")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool compile_shader(GLuint shader_id, const char *name,
|
static bool compile_shader(GLuint shader_id, const char *name,
|
||||||
@@ -203,13 +353,18 @@ static bool compile_shader(GLuint shader_id, const char *name,
|
|||||||
|
|
||||||
// update shader source code
|
// update shader source code
|
||||||
glShaderSource(shader_id, 1, &source_code, NULL);
|
glShaderSource(shader_id, 1, &source_code, NULL);
|
||||||
|
check_glerror_ro("compile_shader/glShaderSource");
|
||||||
|
|
||||||
// compile shader
|
// compile shader
|
||||||
glCompileShader(shader_id);
|
glCompileShader(shader_id);
|
||||||
|
check_glerror_ro("compile_shader/glCompileShader");
|
||||||
|
|
||||||
// get compilation status
|
// get compilation status
|
||||||
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params);
|
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params);
|
||||||
|
check_glerror_ro("compile_shader/glGetShaderiv");
|
||||||
|
|
||||||
glGetShaderInfoLog(shader_id, 1024, NULL, (GLchar *)&log);
|
glGetShaderInfoLog(shader_id, 1024, NULL, (GLchar *)&log);
|
||||||
|
check_glerror_ro("compile_shader/glGetShaderInfoLog");
|
||||||
|
|
||||||
if (status_params == GL_FALSE) {
|
if (status_params == GL_FALSE) {
|
||||||
log_error("Failed to compile\n%s", log);
|
log_error("Failed to compile\n%s", log);
|
||||||
@@ -221,9 +376,13 @@ static bool compile_shader(GLuint shader_id, const char *name,
|
|||||||
return status_params == GL_TRUE;
|
return status_params == GL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_shaders(ShaderProgram *program, const Project *project) {
|
static bool init_shaders(ShaderProgram *program, const Project *project) {
|
||||||
// compile vertex shader
|
// compile vertex shader
|
||||||
program->vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
program->vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
if (check_glerror(program, "init_shaders/glCreateShader")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
program->error = program->error || !compile_shader(program->vertex_shader,
|
program->error = program->error || !compile_shader(program->vertex_shader,
|
||||||
"internal vertex shader",
|
"internal vertex shader",
|
||||||
vertex_shader_text);
|
vertex_shader_text);
|
||||||
@@ -231,18 +390,24 @@ static void init_shaders(ShaderProgram *program, const Project *project) {
|
|||||||
// compile fragment shaders
|
// compile fragment shaders
|
||||||
for (unsigned int i = 0; i < program->frag_count; i++) {
|
for (unsigned int i = 0; i < program->frag_count; i++) {
|
||||||
program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER);
|
program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
if (check_glerror(program, "init_shaders/glCreateShader")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
program->error = program->error ||
|
program->error = program->error ||
|
||||||
!compile_shader(program->fragment_shaders[i],
|
!compile_shader(program->fragment_shaders[i],
|
||||||
project->fragment_shaders[i][0].path,
|
project->fragment_shaders[i][0].path,
|
||||||
project->fragment_shaders[i][0].content);
|
project->fragment_shaders[i][0].content);
|
||||||
|
|
||||||
if (program->error) {
|
if (program->error) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_single_program(ShaderProgram *program, unsigned int i,
|
static bool init_single_program(ShaderProgram *program, unsigned int i,
|
||||||
const ConfigFile *config,
|
const ConfigFile *config,
|
||||||
const StateConfig *state_config) {
|
const StateConfig *state_config) {
|
||||||
unsigned int index1;
|
unsigned int index1;
|
||||||
@@ -251,10 +416,20 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
|
|||||||
const char *prefix;
|
const char *prefix;
|
||||||
|
|
||||||
program->programs[i] = glCreateProgram();
|
program->programs[i] = glCreateProgram();
|
||||||
|
if (check_glerror(program, "init_single_program/glCreateProgram")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glAttachShader(program->programs[i], program->vertex_shader);
|
glAttachShader(program->programs[i], program->vertex_shader);
|
||||||
glAttachShader(program->programs[i], program->fragment_shaders[i]);
|
glAttachShader(program->programs[i], program->fragment_shaders[i]);
|
||||||
|
if (check_glerror(program, "init_single_program/glAttachShader")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glLinkProgram(program->programs[i]);
|
glLinkProgram(program->programs[i]);
|
||||||
|
if (check_glerror(program, "init_single_program/glLinkProgram")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// create uniforms pointers
|
// create uniforms pointers
|
||||||
program->itime_locations[i] = glGetUniformLocation(
|
program->itime_locations[i] = glGetUniformLocation(
|
||||||
@@ -280,6 +455,9 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
|
|||||||
program->iautorand_locations[i] = glGetUniformLocation(
|
program->iautorand_locations[i] = glGetUniformLocation(
|
||||||
program->programs[i],
|
program->programs[i],
|
||||||
config_file_get_str(config, "UNIFORM_AUTORAND", "iAutoRand"));
|
config_file_get_str(config, "UNIFORM_AUTORAND", "iAutoRand"));
|
||||||
|
program->iautorandcycle_locations[i] = glGetUniformLocation(
|
||||||
|
program->programs[i],
|
||||||
|
config_file_get_str(config, "UNIFORM_AUTORANDCYCLE", "iAutoRandCycle"));
|
||||||
program->ipage_locations[i] = glGetUniformLocation(
|
program->ipage_locations[i] = glGetUniformLocation(
|
||||||
program->programs[i],
|
program->programs[i],
|
||||||
config_file_get_str(config, "UNIFORM_PAGE", "iPage"));
|
config_file_get_str(config, "UNIFORM_PAGE", "iPage"));
|
||||||
@@ -310,6 +488,13 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
|
|||||||
glGetUniformLocation(program->programs[i], name);
|
glGetUniformLocation(program->programs[i], name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prefix = config_file_get_str(config, "UNIFORM_IN_SWAP_PREFIX", "iInputSwap");
|
||||||
|
for (unsigned int j = 0; j < program->in_count; j++) {
|
||||||
|
snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
|
||||||
|
program->iinswap_locations[i * program->in_count + j] =
|
||||||
|
glGetUniformLocation(program->programs[i], name);
|
||||||
|
}
|
||||||
|
|
||||||
prefix = config_file_get_str(config, "UNIFORM_SEED_PREFIX", "iSeed");
|
prefix = config_file_get_str(config, "UNIFORM_SEED_PREFIX", "iSeed");
|
||||||
for (unsigned int j = 0; j < program->frag_count; j++) {
|
for (unsigned int j = 0; j < program->frag_count; j++) {
|
||||||
snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
|
snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
|
||||||
@@ -324,18 +509,6 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
|
|||||||
glGetUniformLocation(program->programs[i], name);
|
glGetUniformLocation(program->programs[i], name);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int j = 0; j < program->sub_type_count; j++) {
|
|
||||||
snprintf(name, STR_LEN, "SUB_%d_PREFIX", j + 1);
|
|
||||||
prefix = config_file_get_str(config, name, 0);
|
|
||||||
for (unsigned int k = 0; k < program->sub_variant_count; k++) {
|
|
||||||
snprintf(name, STR_LEN, "%s%d", prefix, k + 1);
|
|
||||||
program->sub_locations[i * program->sub_variant_count *
|
|
||||||
program->sub_type_count +
|
|
||||||
j * program->sub_variant_count + k] =
|
|
||||||
glGetSubroutineIndex(program->programs[i], GL_FRAGMENT_SHADER, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix = config_file_get_str(config, "UNIFORM_ACTIVE_PREFIX", "iActive");
|
prefix = config_file_get_str(config, "UNIFORM_ACTIVE_PREFIX", "iActive");
|
||||||
for (unsigned int j = 0; j < program->active_count; j++) {
|
for (unsigned int j = 0; j < program->active_count; j++) {
|
||||||
snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
|
snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
|
||||||
@@ -374,102 +547,48 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
|
|||||||
glGetUniformLocation(program->programs[i], name);
|
glGetUniformLocation(program->programs[i], name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_glerror(program, "init_single_program/glGetUniformLocation")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < program->sub_type_count; j++) {
|
||||||
|
snprintf(name, STR_LEN, "SUB_%d_PREFIX", j + 1);
|
||||||
|
prefix = config_file_get_str(config, name, 0);
|
||||||
|
for (unsigned int k = 0; k < program->sub_variant_count; k++) {
|
||||||
|
snprintf(name, STR_LEN, "%s%d", prefix, k + 1);
|
||||||
|
program->sub_locations[i * program->sub_variant_count *
|
||||||
|
program->sub_type_count +
|
||||||
|
j * program->sub_variant_count + k] =
|
||||||
|
glGetSubroutineIndex(program->programs[i], GL_FRAGMENT_SHADER, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_glerror(program, "init_single_program/glGetSubroutineIndex")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// create attribute pointer
|
// create attribute pointer
|
||||||
program->vpos_locations[i] =
|
program->vpos_locations[i] =
|
||||||
glGetAttribLocation(program->programs[i], "vPos");
|
glGetAttribLocation(program->programs[i], "vPos");
|
||||||
|
|
||||||
|
if (check_glerror(program, "init_single_program/glGetAttribLocation")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
log_info("Program %d initialized", i + 1);
|
log_info("Program %d initialized", i + 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_programs(ShaderProgram *program, const ConfigFile *config,
|
static bool init_programs(ShaderProgram *program, const ConfigFile *config,
|
||||||
const StateConfig *state_config) {
|
const StateConfig *state_config) {
|
||||||
for (unsigned int i = 0; i < program->frag_count; i++) {
|
for (unsigned int i = 0; i < program->frag_count; i++) {
|
||||||
init_single_program(program, i, config, state_config);
|
if (!init_single_program(program, i, config, state_config)) {
|
||||||
}
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
void shaders_init(ShaderProgram *program, const Project *project,
|
|
||||||
const SharedContext *context, VideoCaptureArray *inputs,
|
|
||||||
bool rebind) {
|
|
||||||
if (!rebind) {
|
|
||||||
program->error = false;
|
|
||||||
program->last_resolution[0] = context->resolution[0];
|
|
||||||
program->last_resolution[1] = context->resolution[1];
|
|
||||||
program->tex_count = config_file_get_int(&project->config, "TEX_COUNT", 9);
|
|
||||||
program->frag_count = project->frag_count;
|
|
||||||
program->frag_output_index =
|
|
||||||
config_file_get_int(&project->config, "FRAG_OUTPUT", 1) - 1;
|
|
||||||
program->frag_monitor_index =
|
|
||||||
config_file_get_int(&project->config, "FRAG_MONITOR", 1) - 1;
|
|
||||||
program->sub_type_count =
|
|
||||||
config_file_get_int(&project->config, "SUB_TYPE_COUNT", 0);
|
|
||||||
program->in_count = config_file_get_int(&project->config, "IN_COUNT", 0);
|
|
||||||
program->sub_variant_count = project->state_config.state_max;
|
|
||||||
program->active_count = project->state_config.midi_active_counts.length;
|
|
||||||
program->midi_lengths.length = 0;
|
|
||||||
|
|
||||||
init_gl(program);
|
|
||||||
|
|
||||||
if (check_glerror(program)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_shaders(program, project);
|
|
||||||
|
|
||||||
if (program->error || check_glerror(program)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_textures(program, context);
|
|
||||||
|
|
||||||
if (check_glerror(program)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_input(program, &project->config, inputs);
|
|
||||||
|
|
||||||
if (check_glerror(program)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_framebuffers(program, &project->config);
|
|
||||||
|
|
||||||
if (check_glerror(program)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_programs(program, &project->config, &project->state_config);
|
|
||||||
|
|
||||||
if (check_glerror(program)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_vertices(program);
|
|
||||||
|
|
||||||
if (check_glerror(program)) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bind_vertices(program, rebind ? 1 : 0);
|
return true;
|
||||||
|
|
||||||
if (check_glerror(program)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void shaders_update(ShaderProgram *program, const File *fragment_shader,
|
|
||||||
unsigned int i, const Project *project) {
|
|
||||||
bool result;
|
|
||||||
|
|
||||||
result = compile_shader(program->fragment_shaders[i], fragment_shader->path,
|
|
||||||
fragment_shader->content);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
init_single_program(program, i, &project->config, &project->state_config);
|
|
||||||
|
|
||||||
log_info("Program %d updated", i + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_viewport(ShaderProgram *program,
|
static void update_viewport(ShaderProgram *program,
|
||||||
@@ -480,8 +599,12 @@ static void update_viewport(ShaderProgram *program,
|
|||||||
// clean and resize all textures
|
// clean and resize all textures
|
||||||
for (unsigned int i = 0; i < program->tex_count; i++) {
|
for (unsigned int i = 0; i < program->tex_count; i++) {
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
check_glerror_ro("update_viewport/glActiveTexture");
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
|
||||||
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
||||||
|
check_glerror_ro(
|
||||||
|
"update_viewport/glTexImage2D"); // TODO dont remap input textures
|
||||||
}
|
}
|
||||||
program->last_resolution[0] = context->resolution[0];
|
program->last_resolution[0] = context->resolution[0];
|
||||||
program->last_resolution[1] = context->resolution[1];
|
program->last_resolution[1] = context->resolution[1];
|
||||||
@@ -545,6 +668,8 @@ static void use_program(const ShaderProgram *program, int i, bool output,
|
|||||||
write_uniform_1i(program->idemo_locations[i], context->demo ? 1 : 0);
|
write_uniform_1i(program->idemo_locations[i], context->demo ? 1 : 0);
|
||||||
write_uniform_1i(program->iautorand_locations[i],
|
write_uniform_1i(program->iautorand_locations[i],
|
||||||
context->auto_random ? 1 : 0);
|
context->auto_random ? 1 : 0);
|
||||||
|
write_uniform_1i(program->iautorandcycle_locations[i],
|
||||||
|
context->auto_random_cycle);
|
||||||
write_uniform_1i(program->ipage_locations[i], context->page);
|
write_uniform_1i(program->ipage_locations[i], context->page);
|
||||||
write_uniform_1i(program->iselected_locations[i], context->selected + 1);
|
write_uniform_1i(program->iselected_locations[i], context->selected + 1);
|
||||||
write_uniform_2f(program->ires_locations[i], &context->resolution);
|
write_uniform_2f(program->ires_locations[i], &context->resolution);
|
||||||
@@ -559,9 +684,11 @@ static void use_program(const ShaderProgram *program, int i, bool output,
|
|||||||
write_uniform_2f(program->iinres_locations[i * program->in_count + j],
|
write_uniform_2f(program->iinres_locations[i * program->in_count + j],
|
||||||
&context->input_resolutions[j]);
|
&context->input_resolutions[j]);
|
||||||
write_uniform_1i(program->iinfmt_locations[i * program->in_count + j],
|
write_uniform_1i(program->iinfmt_locations[i * program->in_count + j],
|
||||||
context->input_formats[j]);
|
context->inputs.values[j].pixelformat);
|
||||||
write_uniform_1i(program->iinfps_locations[i * program->in_count + j],
|
write_uniform_1i(program->iinfps_locations[i * program->in_count + j],
|
||||||
context->input_fps[j]);
|
context->inputs.values[j].fps);
|
||||||
|
write_uniform_1i(program->iinswap_locations[i * program->in_count + j],
|
||||||
|
context->inputs.values[j].swap ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set seeds uniforms
|
// set seeds uniforms
|
||||||
@@ -612,6 +739,87 @@ static void use_program(const ShaderProgram *program, int i, bool output,
|
|||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void shaders_init(ShaderProgram *program, const Project *project,
|
||||||
|
const SharedContext *context, bool rebind) {
|
||||||
|
if (!rebind) {
|
||||||
|
program->error = false;
|
||||||
|
program->last_resolution[0] = context->resolution[0];
|
||||||
|
program->last_resolution[1] = context->resolution[1];
|
||||||
|
program->tex_count = config_file_get_int(&project->config, "TEX_COUNT", 9);
|
||||||
|
program->frag_count = project->frag_count;
|
||||||
|
program->frag_output_index =
|
||||||
|
config_file_get_int(&project->config, "FRAG_OUTPUT", 1) - 1;
|
||||||
|
program->frag_monitor_index =
|
||||||
|
config_file_get_int(&project->config, "FRAG_MONITOR", 1) - 1;
|
||||||
|
program->sub_type_count =
|
||||||
|
config_file_get_int(&project->config, "SUB_TYPE_COUNT", 0);
|
||||||
|
program->in_count = config_file_get_int(&project->config, "IN_COUNT", 0);
|
||||||
|
program->sub_variant_count = project->state_config.state_max;
|
||||||
|
program->active_count = project->state_config.midi_active_counts.length;
|
||||||
|
program->midi_lengths.length = 0;
|
||||||
|
|
||||||
|
#ifdef VIDEO_IN
|
||||||
|
memset(program->dma_images, 0, sizeof(program->dma_images));
|
||||||
|
memset(program->dma_images_swap, 0, sizeof(program->dma_images_swap));
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|
||||||
|
if (!init_gl(program)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init_shaders(program, project)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init_textures(program, context)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init_framebuffers(program, &project->config)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init_programs(program, &project->config, &project->state_config)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init_vertices(program)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bind_vertices(program, rebind ? 1 : 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shaders_relink_input(ShaderProgram *program, const Project *project,
|
||||||
|
VideoCaptureArray *inputs, unsigned int i) {
|
||||||
|
#ifdef VIDEO_IN
|
||||||
|
// shaders_free_input(program, i);
|
||||||
|
init_input(program, &project->config, inputs, i, true);
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
}
|
||||||
|
|
||||||
|
void shaders_link_inputs(ShaderProgram *program, const Project *project,
|
||||||
|
VideoCaptureArray *inputs) {
|
||||||
|
#ifdef VIDEO_IN
|
||||||
|
for (unsigned int i = 0; i < program->in_count; i++) {
|
||||||
|
init_input(program, &project->config, inputs, i, false);
|
||||||
|
}
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
}
|
||||||
|
|
||||||
|
void shaders_update(ShaderProgram *program, const File *fragment_shader,
|
||||||
|
unsigned int i, const Project *project) {
|
||||||
|
if (compile_shader(program->fragment_shaders[i], fragment_shader->path,
|
||||||
|
fragment_shader->content) &&
|
||||||
|
init_single_program(program, i, &project->config,
|
||||||
|
&project->state_config)) {
|
||||||
|
log_info("Program %d updated", i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void shaders_compute(ShaderProgram *program, const SharedContext *context,
|
void shaders_compute(ShaderProgram *program, const SharedContext *context,
|
||||||
bool monitor, bool output_only) {
|
bool monitor, bool output_only) {
|
||||||
if (!output_only) {
|
if (!output_only) {
|
||||||
@@ -634,25 +842,42 @@ void shaders_compute(ShaderProgram *program, const SharedContext *context,
|
|||||||
monitor ? program->frag_monitor_index
|
monitor ? program->frag_monitor_index
|
||||||
: program->frag_output_index,
|
: program->frag_output_index,
|
||||||
true, context);
|
true, context);
|
||||||
|
|
||||||
|
check_glerror(program, "shaders_compute");
|
||||||
}
|
}
|
||||||
|
|
||||||
void shaders_free(const ShaderProgram *program) {
|
void shaders_free(const ShaderProgram *program) {
|
||||||
for (unsigned int i = 0; i < program->frag_count; i++) {
|
for (unsigned int i = 0; i < program->frag_count; i++) {
|
||||||
glDeleteProgram(program->programs[i]);
|
glDeleteProgram(program->programs[i]);
|
||||||
}
|
}
|
||||||
|
check_glerror_ro("shaders_free/glDeleteProgram");
|
||||||
|
|
||||||
glDeleteFramebuffers(program->frag_count, program->frame_buffers);
|
glDeleteFramebuffers(program->frag_count, program->frame_buffers);
|
||||||
|
check_glerror_ro("shaders_free/glDeleteFramebuffers");
|
||||||
|
|
||||||
glDeleteTextures(program->tex_count, program->textures);
|
glDeleteTextures(program->tex_count, program->textures);
|
||||||
|
check_glerror_ro("shaders_free/glDeleteTextures");
|
||||||
|
|
||||||
glDeleteBuffers(1, &program->vertex_buffer);
|
glDeleteBuffers(1, &program->vertex_buffer);
|
||||||
|
check_glerror_ro("shaders_free/glDeleteBuffers");
|
||||||
}
|
}
|
||||||
|
|
||||||
void shaders_free_window(const ShaderProgram *program, bool secondary) {
|
void shaders_free_window(const ShaderProgram *program, bool secondary) {
|
||||||
glDeleteVertexArrays(1, &program->vertex_array[secondary ? 1 : 0]);
|
glDeleteVertexArrays(1, &program->vertex_array[secondary ? 1 : 0]);
|
||||||
|
check_glerror_ro("shaders_free_window/glDeleteVertexArrays");
|
||||||
}
|
}
|
||||||
|
|
||||||
void shaders_free_input(const ShaderProgram *program,
|
void shaders_free_input(ShaderProgram *program, unsigned int input_index) {
|
||||||
const VideoCapture *input) {
|
#ifdef VIDEO_IN
|
||||||
if (!input->error && input->dma_image != EGL_NO_IMAGE_KHR) {
|
if (program->dma_images[input_index] != EGL_NO_IMAGE_KHR) {
|
||||||
eglDestroyImageKHR(program->egl_display, input->dma_image);
|
eglDestroyImageKHR(program->egl_display, program->dma_images[input_index]);
|
||||||
|
program->dma_images[input_index] = EGL_NO_IMAGE_KHR;
|
||||||
}
|
}
|
||||||
}
|
if (program->dma_images_swap[input_index] != EGL_NO_IMAGE_KHR) {
|
||||||
|
eglDestroyImageKHR(program->egl_display,
|
||||||
|
program->dma_images_swap[input_index]);
|
||||||
|
program->dma_images_swap[input_index] = EGL_NO_IMAGE_KHR;
|
||||||
|
}
|
||||||
|
check_eglerror_ro("shaders_free_input/eglDestroyImageKHR");
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
}
|
||||||
|
|||||||
+9
-5
@@ -4,8 +4,13 @@
|
|||||||
#define SHADERS_H
|
#define SHADERS_H
|
||||||
|
|
||||||
void shaders_init(ShaderProgram *program, const Project *project,
|
void shaders_init(ShaderProgram *program, const Project *project,
|
||||||
const SharedContext *context, VideoCaptureArray *inputs,
|
const SharedContext *context, bool rebind);
|
||||||
bool rebind);
|
|
||||||
|
void shaders_relink_input(ShaderProgram *program, const Project *project,
|
||||||
|
VideoCaptureArray *inputs, unsigned int i);
|
||||||
|
|
||||||
|
void shaders_link_inputs(ShaderProgram *program, const Project *project,
|
||||||
|
VideoCaptureArray *inputs);
|
||||||
|
|
||||||
void shaders_update(ShaderProgram *program, const File *fragment_shader,
|
void shaders_update(ShaderProgram *program, const File *fragment_shader,
|
||||||
unsigned int i, const Project *project);
|
unsigned int i, const Project *project);
|
||||||
@@ -17,7 +22,6 @@ void shaders_free(const ShaderProgram *program);
|
|||||||
|
|
||||||
void shaders_free_window(const ShaderProgram *program, bool secondary);
|
void shaders_free_window(const ShaderProgram *program, bool secondary);
|
||||||
|
|
||||||
void shaders_free_input(const ShaderProgram *program,
|
void shaders_free_input(ShaderProgram *program, unsigned int input_index);
|
||||||
const VideoCapture *input);
|
|
||||||
|
|
||||||
#endif /* SHADERS_H */
|
#endif /* SHADERS_H */
|
||||||
|
|||||||
+1
-1
@@ -32,4 +32,4 @@ SharedContext *shared_init_context(const char *key) {
|
|||||||
|
|
||||||
void shared_close_context(SharedContext *shared) {
|
void shared_close_context(SharedContext *shared) {
|
||||||
close_shared(shared, sizeof(SharedContext), shared->fd);
|
close_shared(shared, sizeof(SharedContext), shared->fd);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -6,4 +6,4 @@
|
|||||||
SharedContext *shared_init_context(const char *key);
|
SharedContext *shared_init_context(const char *key);
|
||||||
void shared_close_context(SharedContext *shared);
|
void shared_close_context(SharedContext *shared);
|
||||||
|
|
||||||
#endif /* SHARED_H */
|
#endif /* SHARED_H */
|
||||||
|
|||||||
+361
-187
@@ -1,5 +1,6 @@
|
|||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
@@ -12,6 +13,233 @@
|
|||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "tempo.h"
|
#include "tempo.h"
|
||||||
|
|
||||||
|
static void safe_midi_write(const MidiDevice *midi, unsigned int code,
|
||||||
|
unsigned char value) {
|
||||||
|
if (code != UNSET_MIDI_CODE) {
|
||||||
|
midi_write(midi, code, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_page(const SharedContext *context,
|
||||||
|
const StateConfig *state_config,
|
||||||
|
const MidiDevice *midi) {
|
||||||
|
unsigned int page_item_min;
|
||||||
|
unsigned int page_item_max;
|
||||||
|
// SHOW PAGE
|
||||||
|
for (unsigned int i = 0; i < state_config->select_page_codes.length; i++) {
|
||||||
|
safe_midi_write(midi, state_config->select_page_codes.values[i],
|
||||||
|
i == context->page ? MIDI_MAX : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHOW PAGE ITEM
|
||||||
|
page_item_min = state_config->select_item_codes.length * context->page;
|
||||||
|
page_item_max = page_item_min + state_config->select_item_codes.length;
|
||||||
|
|
||||||
|
if (context->state.values[context->selected] >= page_item_min &&
|
||||||
|
context->state.values[context->selected] < page_item_max) {
|
||||||
|
for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) {
|
||||||
|
safe_midi_write(midi, state_config->select_item_codes.values[i],
|
||||||
|
i == context->state.values[context->selected] -
|
||||||
|
page_item_min
|
||||||
|
? MIDI_MAX
|
||||||
|
: 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) {
|
||||||
|
safe_midi_write(midi, state_config->select_item_codes.values[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_active(const SharedContext *context,
|
||||||
|
const StateConfig *state_config,
|
||||||
|
const MidiDevice *midi) {
|
||||||
|
unsigned int k;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
|
||||||
|
for (unsigned int j = 0; j < state_config->midi_active_counts.values[i];
|
||||||
|
j++) {
|
||||||
|
k = state_config->midi_active_offsets.values[i] + j;
|
||||||
|
safe_midi_write(midi, state_config->midi_active_codes.values[k],
|
||||||
|
context->active[i] == j ? MIDI_MAX : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_values(const SharedContext *context,
|
||||||
|
const StateConfig *state_config,
|
||||||
|
const MidiDevice *midi) {
|
||||||
|
unsigned int j;
|
||||||
|
unsigned int k;
|
||||||
|
unsigned int part;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->midi_codes.length; i++) {
|
||||||
|
j = i / 3;
|
||||||
|
part = arr_uint_remap_index(state_config->midi_offsets, &j);
|
||||||
|
k = state_config->values_offsets.values[part] +
|
||||||
|
context->active[part] * state_config->midi_counts.values[part] + j;
|
||||||
|
safe_midi_write(midi, state_config->midi_codes.values[i],
|
||||||
|
context->values[k][i % 3] * MIDI_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reset(SharedContext *context) {
|
||||||
|
memset(context->values, 0, sizeof(context->values));
|
||||||
|
memset(context->state.values, 0, sizeof(context->state.values));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void randomize(SharedContext *context, const StateConfig *state_config) {
|
||||||
|
unsigned int j;
|
||||||
|
unsigned int l;
|
||||||
|
unsigned int part;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->midi_codes.length; i++) {
|
||||||
|
j = i / 3;
|
||||||
|
part = arr_uint_remap_index(state_config->midi_offsets, &j);
|
||||||
|
for (unsigned int k = 0; k < state_config->midi_active_counts.values[part];
|
||||||
|
k++) {
|
||||||
|
l = state_config->values_offsets.values[part] +
|
||||||
|
k * state_config->midi_counts.values[part] + j;
|
||||||
|
|
||||||
|
if (arr_uint_index_of(state_config->fader_codes,
|
||||||
|
state_config->midi_codes.values[i]) !=
|
||||||
|
ARRAY_NOT_FOUND) {
|
||||||
|
context->values[l][i % 3] = (float)rand_uint(MIDI_MAX + 1) / MIDI_MAX;
|
||||||
|
} else {
|
||||||
|
context->values[l][i % 3] = rand_uint(2) == 1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < context->state.length; i++) {
|
||||||
|
context->state.values[i] = rand_uint(state_config->state_max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_from_file(SharedContext *context,
|
||||||
|
const StateConfig *state_config,
|
||||||
|
const char *state_file) {
|
||||||
|
ConfigFile saved_state;
|
||||||
|
char key[STR_LEN];
|
||||||
|
|
||||||
|
config_file_read(&saved_state, state_file);
|
||||||
|
|
||||||
|
if (saved_state.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tempo_set(&context->tempo,
|
||||||
|
config_file_get_int(&saved_state, "tempo", context->tempo.tempo));
|
||||||
|
context->page = config_file_get_int(&saved_state, "page", 0);
|
||||||
|
context->selected = config_file_get_int(&saved_state, "selected", 0);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < context->state.length; i++) {
|
||||||
|
snprintf(key, STR_LEN, "seed_%d", i);
|
||||||
|
context->seeds[i] =
|
||||||
|
config_file_get_int(&saved_state, key, context->seeds[i]);
|
||||||
|
snprintf(key, STR_LEN, "state_%d", i);
|
||||||
|
context->state.values[i] = config_file_get_int(&saved_state, key, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
|
||||||
|
snprintf(key, STR_LEN, "active_%d", i);
|
||||||
|
context->active[i] = config_file_get_int(&saved_state, key, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->value_count; i++) {
|
||||||
|
snprintf(key, STR_LEN, "value_%d_x", i);
|
||||||
|
context->values[i][0] =
|
||||||
|
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
|
||||||
|
snprintf(key, STR_LEN, "value_%d_y", i);
|
||||||
|
context->values[i][1] =
|
||||||
|
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
|
||||||
|
snprintf(key, STR_LEN, "value_%d_z", i);
|
||||||
|
context->values[i][2] =
|
||||||
|
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_file_free(&saved_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_from_default_file(SharedContext *context,
|
||||||
|
const StateConfig *state_config) {
|
||||||
|
char state_file[STR_LEN];
|
||||||
|
|
||||||
|
snprintf(state_file, STR_LEN, "%s.txt", state_config->save_file_prefix);
|
||||||
|
|
||||||
|
load_from_file(context, state_config, state_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_from_index_file(SharedContext *context,
|
||||||
|
const StateConfig *state_config,
|
||||||
|
unsigned int index) {
|
||||||
|
char state_file[STR_LEN];
|
||||||
|
|
||||||
|
snprintf(state_file, STR_LEN, "%s.%d.txt", state_config->save_file_prefix,
|
||||||
|
index);
|
||||||
|
|
||||||
|
load_from_file(context, state_config, state_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_to_file(const SharedContext *context,
|
||||||
|
const StateConfig *state_config,
|
||||||
|
const char *state_file) {
|
||||||
|
StringArray lines;
|
||||||
|
|
||||||
|
log_info("Saving state to '%s'...", state_file);
|
||||||
|
|
||||||
|
lines.length = 0;
|
||||||
|
|
||||||
|
snprintf(lines.values[lines.length++], STR_LEN, "tempo=%d",
|
||||||
|
(unsigned int)context->tempo.tempo);
|
||||||
|
snprintf(lines.values[lines.length++], STR_LEN, "page=%d", context->page);
|
||||||
|
snprintf(lines.values[lines.length++], STR_LEN, "selected=%d",
|
||||||
|
context->selected);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < context->state.length; i++) {
|
||||||
|
snprintf(lines.values[lines.length++], STR_LEN, "seed_%d=%d", i,
|
||||||
|
context->seeds[i]);
|
||||||
|
snprintf(lines.values[lines.length++], STR_LEN, "state_%d=%d", i,
|
||||||
|
context->state.values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
|
||||||
|
snprintf(lines.values[lines.length++], STR_LEN, "active_%d=%d", i,
|
||||||
|
context->active[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->value_count; i++) {
|
||||||
|
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_x=%d", i,
|
||||||
|
(unsigned int)(context->values[i][0] * MIDI_MAX));
|
||||||
|
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_y=%d", i,
|
||||||
|
(unsigned int)(context->values[i][1] * MIDI_MAX));
|
||||||
|
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_z=%d", i,
|
||||||
|
(unsigned int)(context->values[i][2] * MIDI_MAX));
|
||||||
|
}
|
||||||
|
|
||||||
|
file_write(state_file, &lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_to_default_file(const SharedContext *context,
|
||||||
|
const StateConfig *state_config) {
|
||||||
|
char state_file[STR_LEN];
|
||||||
|
|
||||||
|
snprintf(state_file, STR_LEN, "%s.txt", state_config->save_file_prefix);
|
||||||
|
|
||||||
|
save_to_file(context, state_config, state_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_to_index_file(const SharedContext *context,
|
||||||
|
const StateConfig *state_config,
|
||||||
|
unsigned int index) {
|
||||||
|
char state_file[STR_LEN];
|
||||||
|
|
||||||
|
snprintf(state_file, STR_LEN, "%s.%d.txt", state_config->save_file_prefix,
|
||||||
|
index);
|
||||||
|
|
||||||
|
save_to_file(context, state_config, state_file);
|
||||||
|
}
|
||||||
|
|
||||||
void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
|
void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
@@ -118,82 +346,81 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
|
|||||||
|
|
||||||
state_config->tap_tempo_code =
|
state_config->tap_tempo_code =
|
||||||
config_file_get_int(config, "TAP_TEMPO", UNSET_MIDI_CODE);
|
config_file_get_int(config, "TAP_TEMPO", UNSET_MIDI_CODE);
|
||||||
}
|
|
||||||
|
|
||||||
static void safe_midi_write(const MidiDevice *midi, unsigned int code,
|
strlcpy(state_config->save_file_prefix,
|
||||||
unsigned char value) {
|
config_file_get_str(config, "SAVE_FILE_PREFIX", "forge_save"),
|
||||||
if (code != UNSET_MIDI_CODE) {
|
STR_LEN);
|
||||||
midi_write(midi, code, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_page(const SharedContext *context,
|
state_config->hotkey_randomize =
|
||||||
const StateConfig *state_config,
|
config_file_get_int(config, "HOTKEY_RANDOMIZE", 82);
|
||||||
const MidiDevice *midi) {
|
state_config->hotkey_reset =
|
||||||
unsigned int page_item_min;
|
config_file_get_int(config, "HOTKEY_RESET", 1082);
|
||||||
unsigned int page_item_max;
|
state_config->hotkey_demo = config_file_get_int(config, "HOTKEY_DEMO", 68);
|
||||||
// SHOW PAGE
|
state_config->hotkey_autorand =
|
||||||
for (unsigned int i = 0; i < state_config->select_page_codes.length; i++) {
|
config_file_get_int(config, "HOTKEY_AUTORAND", 65);
|
||||||
safe_midi_write(midi, state_config->select_page_codes.values[i],
|
state_config->hotkey_autorand_down =
|
||||||
i == context->page ? MIDI_MAX : 0);
|
config_file_get_int(config, "HOTKEY_AUTORAND_DOWN", 263);
|
||||||
}
|
state_config->hotkey_autorand_up =
|
||||||
|
config_file_get_int(config, "HOTKEY_AUTORAND_UP", 262);
|
||||||
|
state_config->hotkey_tempo_down =
|
||||||
|
config_file_get_int(config, "HOTKEY_TEMPO_DOWN", 264);
|
||||||
|
state_config->hotkey_tempo_up =
|
||||||
|
config_file_get_int(config, "HOTKEY_TEMPO_UP", 265);
|
||||||
|
|
||||||
// SHOW PAGE ITEM
|
if (config_file_has(config, "HOTKEY_LOAD_COUNT")) {
|
||||||
page_item_min = state_config->select_item_codes.length * context->page;
|
state_config->hotkey_load.length =
|
||||||
page_item_max = page_item_min + state_config->select_item_codes.length;
|
config_file_get_int(config, "HOTKEY_LOAD_COUNT", 0);
|
||||||
|
|
||||||
if (context->state.values[context->selected] >= page_item_min &&
|
for (unsigned int i = 0; i < state_config->hotkey_load.length; i++) {
|
||||||
context->state.values[context->selected] < page_item_max) {
|
snprintf(name, STR_LEN, "HOTKEY_LOAD_%d", i + 1);
|
||||||
for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) {
|
state_config->hotkey_load.values[i] =
|
||||||
safe_midi_write(midi, state_config->select_item_codes.values[i],
|
config_file_get_int(config, name, 0);
|
||||||
i == context->state.values[context->selected] -
|
|
||||||
page_item_min
|
|
||||||
? MIDI_MAX
|
|
||||||
: 0);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) {
|
state_config->hotkey_load.length = 10;
|
||||||
safe_midi_write(midi, state_config->select_item_codes.values[i], 0);
|
state_config->hotkey_load.values[0] = 49;
|
||||||
|
state_config->hotkey_load.values[1] = 50;
|
||||||
|
state_config->hotkey_load.values[2] = 51;
|
||||||
|
state_config->hotkey_load.values[3] = 52;
|
||||||
|
state_config->hotkey_load.values[4] = 53;
|
||||||
|
state_config->hotkey_load.values[5] = 54;
|
||||||
|
state_config->hotkey_load.values[6] = 55;
|
||||||
|
state_config->hotkey_load.values[7] = 56;
|
||||||
|
state_config->hotkey_load.values[8] = 57;
|
||||||
|
state_config->hotkey_load.values[9] = 48;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_file_has(config, "HOTKEY_SAVE_COUNT")) {
|
||||||
|
state_config->hotkey_save.length =
|
||||||
|
config_file_get_int(config, "HOTKEY_SAVE_COUNT", 0);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->hotkey_save.length; i++) {
|
||||||
|
snprintf(name, STR_LEN, "HOTKEY_SAVE_%d", i + 1);
|
||||||
|
state_config->hotkey_save.values[i] =
|
||||||
|
config_file_get_int(config, name, 0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
state_config->hotkey_save.length = 10;
|
||||||
|
state_config->hotkey_save.values[0] = 1049;
|
||||||
|
state_config->hotkey_save.values[1] = 1050;
|
||||||
|
state_config->hotkey_save.values[2] = 1051;
|
||||||
|
state_config->hotkey_save.values[3] = 1052;
|
||||||
|
state_config->hotkey_save.values[4] = 1053;
|
||||||
|
state_config->hotkey_save.values[5] = 1054;
|
||||||
|
state_config->hotkey_save.values[6] = 1055;
|
||||||
|
state_config->hotkey_save.values[7] = 1056;
|
||||||
|
state_config->hotkey_save.values[8] = 1057;
|
||||||
|
state_config->hotkey_save.values[9] = 1048;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_active(const SharedContext *context,
|
void state_midi_event(SharedContext *context, const StateConfig *state_config,
|
||||||
const StateConfig *state_config,
|
const MidiDevice *midi, unsigned char code,
|
||||||
const MidiDevice *midi) {
|
unsigned char value, bool trace_midi) {
|
||||||
unsigned int k;
|
unsigned int i;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
|
|
||||||
for (unsigned int j = 0; j < state_config->midi_active_counts.values[i];
|
|
||||||
j++) {
|
|
||||||
k = state_config->midi_active_offsets.values[i] + j;
|
|
||||||
safe_midi_write(midi, state_config->midi_active_codes.values[k],
|
|
||||||
context->active[i] == j ? MIDI_MAX : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_values(const SharedContext *context,
|
|
||||||
const StateConfig *state_config,
|
|
||||||
const MidiDevice *midi) {
|
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
unsigned int k;
|
unsigned int k;
|
||||||
unsigned int part;
|
unsigned int part;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < state_config->midi_codes.length; i++) {
|
|
||||||
j = i / 3;
|
|
||||||
part = arr_uint_remap_index(state_config->midi_offsets, &j);
|
|
||||||
k = state_config->values_offsets.values[part] +
|
|
||||||
context->active[part] * state_config->midi_counts.values[part] + j;
|
|
||||||
safe_midi_write(midi, state_config->midi_codes.values[i],
|
|
||||||
context->values[k][i % 3] * MIDI_MAX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void state_apply_event(SharedContext *context, const StateConfig *state_config,
|
|
||||||
const MidiDevice *midi, unsigned char code,
|
|
||||||
unsigned char value, bool trace_midi) {
|
|
||||||
unsigned int i, j, k, part;
|
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
found = false;
|
found = false;
|
||||||
@@ -281,10 +508,60 @@ void state_apply_event(SharedContext *context, const StateConfig *state_config,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void state_apply(const SharedContext *context, const StateConfig *state_config,
|
void state_key_event(SharedContext *context, const StateConfig *state_config,
|
||||||
const MidiDevice *midi) {
|
unsigned int code, const MidiDevice *midi) {
|
||||||
if (!midi->error) {
|
unsigned int index;
|
||||||
|
|
||||||
|
if (code == state_config->hotkey_randomize) {
|
||||||
|
log_info("[%d] Randomized", code);
|
||||||
|
randomize(context, state_config);
|
||||||
update_values(context, state_config, midi);
|
update_values(context, state_config, midi);
|
||||||
|
} else if (code == state_config->hotkey_reset) {
|
||||||
|
log_info("[%d] Reset", code);
|
||||||
|
reset(context);
|
||||||
|
update_values(context, state_config, midi);
|
||||||
|
} else if (code == state_config->hotkey_demo) {
|
||||||
|
log_info((context->demo ? "[%d] Demo OFF" : "[%d] Demo ON"), code);
|
||||||
|
context->demo = !context->demo;
|
||||||
|
} else if (code == state_config->hotkey_autorand) {
|
||||||
|
log_info(
|
||||||
|
(context->auto_random ? "[%d] Auto Random OFF" : "[%d] Auto Random ON"),
|
||||||
|
code);
|
||||||
|
context->auto_random = !context->auto_random;
|
||||||
|
} else if (code == state_config->hotkey_autorand_down) {
|
||||||
|
if (context->auto_random_cycle > 1) {
|
||||||
|
context->auto_random_cycle -= 1;
|
||||||
|
}
|
||||||
|
log_info("[%d] Auto Random Cycle: %d", code, context->auto_random_cycle);
|
||||||
|
} else if (code == state_config->hotkey_autorand_up) {
|
||||||
|
context->auto_random_cycle += 1;
|
||||||
|
log_info("[%d] Auto Random Cycle: %d", code, context->auto_random_cycle);
|
||||||
|
} else if (code == state_config->hotkey_tempo_up) {
|
||||||
|
tempo_set(&context->tempo, context->tempo.tempo + 1);
|
||||||
|
log_info("[%d] Tempo: %f", code, context->tempo);
|
||||||
|
} else if (code == state_config->hotkey_tempo_down) {
|
||||||
|
if (context->tempo.tempo > 0) {
|
||||||
|
tempo_set(&context->tempo, context->tempo.tempo - 1);
|
||||||
|
}
|
||||||
|
log_info("[%d] Tempo: %f", code, context->tempo);
|
||||||
|
} else {
|
||||||
|
index = arr_uint_index_of(state_config->hotkey_load, code);
|
||||||
|
|
||||||
|
if (index != ARRAY_NOT_FOUND) {
|
||||||
|
log_info("[%d] Loading state %d", code, index + 1);
|
||||||
|
load_from_index_file(context, state_config, index + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = arr_uint_index_of(state_config->hotkey_save, code);
|
||||||
|
|
||||||
|
if (index != ARRAY_NOT_FOUND) {
|
||||||
|
log_info("[%d] Saving state %d", code, index + 1);
|
||||||
|
save_to_index_file(context, state_config, index + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("[%d] No hotkey defined", code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +569,10 @@ bool state_background_write(SharedContext *context,
|
|||||||
const StateConfig *state_config,
|
const StateConfig *state_config,
|
||||||
const MidiDevice *midi) {
|
const MidiDevice *midi) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
bool beat_active, last_active, change, last_change;
|
bool beat_active;
|
||||||
|
bool last_active;
|
||||||
|
bool change;
|
||||||
|
bool last_change;
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
@@ -314,7 +594,7 @@ bool state_background_write(SharedContext *context,
|
|||||||
last_change = false;
|
last_change = false;
|
||||||
|
|
||||||
while (!context->stop) {
|
while (!context->stop) {
|
||||||
beat_active = tempo_progress(&context->tempo, 1.0) < 0.25;
|
beat_active = tempo_progress(&context->tempo, 1.0) < 0.5;
|
||||||
|
|
||||||
if (!midi->error && beat_active != last_active) {
|
if (!midi->error && beat_active != last_active) {
|
||||||
safe_midi_write(midi, state_config->tap_tempo_code,
|
safe_midi_write(midi, state_config->tap_tempo_code,
|
||||||
@@ -327,74 +607,35 @@ bool state_background_write(SharedContext *context,
|
|||||||
|
|
||||||
last_active = beat_active;
|
last_active = beat_active;
|
||||||
|
|
||||||
change = tempo_progress(&context->tempo, 4.0) < 0.25;
|
change = tempo_progress(&context->tempo,
|
||||||
|
(double)context->auto_random_cycle) < 0.5;
|
||||||
|
|
||||||
if (context->auto_random && change && !last_change) {
|
if (context->auto_random && change && !last_change) {
|
||||||
state_randomize(context, state_config);
|
randomize(context, state_config);
|
||||||
|
|
||||||
state_apply(context, state_config, midi);
|
update_values(context, state_config, midi);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_change = change;
|
last_change = change;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("(state) background writing stopped by main thread (pid: %d)", pid);
|
log_info("(state) background writing stopped by main thread (pid: %d)", pid);
|
||||||
return false;
|
exit(EXIT_SUCCESS);
|
||||||
}
|
|
||||||
|
|
||||||
static void state_load(SharedContext *context, const StateConfig *state_config,
|
|
||||||
const char *state_file) {
|
|
||||||
ConfigFile saved_state;
|
|
||||||
char key[STR_LEN];
|
|
||||||
|
|
||||||
config_file_read(&saved_state, state_file);
|
|
||||||
|
|
||||||
tempo_set(&context->tempo,
|
|
||||||
config_file_get_int(&saved_state, "tempo", context->tempo.tempo));
|
|
||||||
context->page = config_file_get_int(&saved_state, "page", 0);
|
|
||||||
context->selected = config_file_get_int(&saved_state, "selected", 0);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < context->state.length; i++) {
|
|
||||||
snprintf(key, STR_LEN, "seed_%d", i);
|
|
||||||
context->seeds[i] =
|
|
||||||
config_file_get_int(&saved_state, key, context->seeds[i]);
|
|
||||||
snprintf(key, STR_LEN, "state_%d", i);
|
|
||||||
context->state.values[i] = config_file_get_int(&saved_state, key, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
|
|
||||||
snprintf(key, STR_LEN, "active_%d", i);
|
|
||||||
context->active[i] = config_file_get_int(&saved_state, key, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < state_config->value_count; i++) {
|
|
||||||
snprintf(key, STR_LEN, "value_%d_x", i);
|
|
||||||
context->values[i][0] =
|
|
||||||
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
|
|
||||||
snprintf(key, STR_LEN, "value_%d_y", i);
|
|
||||||
context->values[i][1] =
|
|
||||||
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
|
|
||||||
snprintf(key, STR_LEN, "value_%d_z", i);
|
|
||||||
context->values[i][2] =
|
|
||||||
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
config_file_free(&saved_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void state_init(SharedContext *context, const StateConfig *state_config,
|
void state_init(SharedContext *context, const StateConfig *state_config,
|
||||||
bool demo, bool auto_random, unsigned int base_tempo,
|
bool demo, bool auto_random, unsigned int auto_random_cycles,
|
||||||
const char *state_file, bool load_state) {
|
unsigned int base_tempo, bool load_state) {
|
||||||
tempo_init(&context->tempo);
|
tempo_init(&context->tempo, base_tempo);
|
||||||
tempo_set(&context->tempo, base_tempo);
|
|
||||||
context->demo = demo;
|
context->demo = demo;
|
||||||
context->auto_random = auto_random;
|
context->auto_random = auto_random;
|
||||||
|
context->auto_random_cycle = auto_random_cycles;
|
||||||
|
|
||||||
context->state.length = state_config->select_frag_codes.length;
|
context->state.length = state_config->select_frag_codes.length;
|
||||||
memset(context->state.values, 0, sizeof(context->state.values));
|
memset(context->state.values, 0, sizeof(context->state.values));
|
||||||
|
|
||||||
if (auto_random) {
|
if (auto_random) {
|
||||||
state_randomize(context, state_config);
|
randomize(context, state_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(context->active, 0, sizeof(context->active));
|
memset(context->active, 0, sizeof(context->active));
|
||||||
@@ -410,77 +651,10 @@ void state_init(SharedContext *context, const StateConfig *state_config,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (load_state) {
|
if (load_state) {
|
||||||
state_load(context, state_config, state_file);
|
load_from_default_file(context, state_config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void state_reset(SharedContext *context) {
|
void state_save(const SharedContext *context, const StateConfig *state_config) {
|
||||||
memset(context->values, 0, sizeof(context->values));
|
save_to_default_file(context, state_config);
|
||||||
memset(context->state.values, 0, sizeof(context->state.values));
|
|
||||||
}
|
|
||||||
|
|
||||||
void state_randomize(SharedContext *context, const StateConfig *state_config) {
|
|
||||||
unsigned int j;
|
|
||||||
unsigned int l;
|
|
||||||
unsigned int part;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < state_config->midi_codes.length; i++) {
|
|
||||||
j = i / 3;
|
|
||||||
part = arr_uint_remap_index(state_config->midi_offsets, &j);
|
|
||||||
for (unsigned int k = 0; k < state_config->midi_active_counts.values[part];
|
|
||||||
k++) {
|
|
||||||
l = state_config->values_offsets.values[part] +
|
|
||||||
k * state_config->midi_counts.values[part] + j;
|
|
||||||
|
|
||||||
if (arr_uint_index_of(state_config->fader_codes,
|
|
||||||
state_config->midi_codes.values[i]) !=
|
|
||||||
ARRAY_NOT_FOUND) {
|
|
||||||
context->values[l][i % 3] = (float)rand_uint(MIDI_MAX + 1) / MIDI_MAX;
|
|
||||||
} else {
|
|
||||||
context->values[l][i % 3] = rand_uint(2) == 1 ? 1 : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < context->state.length; i++) {
|
|
||||||
context->state.values[i] = rand_uint(state_config->state_max);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void state_save(const SharedContext *context, const StateConfig *state_config,
|
|
||||||
const char *state_file) {
|
|
||||||
StringArray lines;
|
|
||||||
|
|
||||||
log_info("Saving state to '%s'...", state_file);
|
|
||||||
|
|
||||||
lines.length = 0;
|
|
||||||
|
|
||||||
snprintf(lines.values[lines.length++], STR_LEN, "tempo=%d",
|
|
||||||
(unsigned int)context->tempo.tempo);
|
|
||||||
snprintf(lines.values[lines.length++], STR_LEN, "page=%d", context->page);
|
|
||||||
snprintf(lines.values[lines.length++], STR_LEN, "selected=%d",
|
|
||||||
context->selected);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < context->state.length; i++) {
|
|
||||||
snprintf(lines.values[lines.length++], STR_LEN, "seed_%d=%d", i,
|
|
||||||
context->seeds[i]);
|
|
||||||
snprintf(lines.values[lines.length++], STR_LEN, "state_%d=%d", i,
|
|
||||||
context->state.values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
|
|
||||||
snprintf(lines.values[lines.length++], STR_LEN, "active_%d=%d", i,
|
|
||||||
context->active[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < state_config->value_count; i++) {
|
|
||||||
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_x=%d", i,
|
|
||||||
(unsigned int)(context->values[i][0] * MIDI_MAX));
|
|
||||||
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_y=%d", i,
|
|
||||||
(unsigned int)(context->values[i][1] * MIDI_MAX));
|
|
||||||
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_z=%d", i,
|
|
||||||
(unsigned int)(context->values[i][2] * MIDI_MAX));
|
|
||||||
}
|
|
||||||
|
|
||||||
file_write(state_file, &lines);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-15
@@ -5,26 +5,21 @@
|
|||||||
|
|
||||||
void state_parse_config(StateConfig *state_config, const ConfigFile *config);
|
void state_parse_config(StateConfig *state_config, const ConfigFile *config);
|
||||||
|
|
||||||
void state_apply_event(SharedContext *context, const StateConfig *state_config,
|
void state_midi_event(SharedContext *context, const StateConfig *state_config,
|
||||||
const MidiDevice *midi, unsigned char code,
|
const MidiDevice *midi, unsigned char code,
|
||||||
unsigned char value, bool trace_midi);
|
unsigned char value, bool trace_midi);
|
||||||
|
|
||||||
|
void state_key_event(SharedContext *context, const StateConfig *state_config,
|
||||||
|
unsigned int code, const MidiDevice *midi);
|
||||||
|
|
||||||
bool state_background_write(SharedContext *context,
|
bool state_background_write(SharedContext *context,
|
||||||
const StateConfig *state_config,
|
const StateConfig *state_config,
|
||||||
const MidiDevice *midi);
|
const MidiDevice *midi);
|
||||||
|
|
||||||
void state_init(SharedContext *context, const StateConfig *state_config,
|
void state_init(SharedContext *context, const StateConfig *state_config,
|
||||||
bool demo, bool auto_random, unsigned int base_tempo,
|
bool demo, bool auto_random, unsigned int auto_random_cycles,
|
||||||
const char *state_file, bool load_state);
|
unsigned int base_tempo, bool load_state);
|
||||||
|
|
||||||
void state_reset(SharedContext *context);
|
void state_save(const SharedContext *context, const StateConfig *state_config);
|
||||||
|
|
||||||
void state_randomize(SharedContext *context, const StateConfig *state_config);
|
#endif /* STATE_H */
|
||||||
|
|
||||||
void state_apply(const SharedContext *context, const StateConfig *state_config,
|
|
||||||
const MidiDevice *midi);
|
|
||||||
|
|
||||||
void state_save(const SharedContext *context, const StateConfig *state_config,
|
|
||||||
const char *state_file);
|
|
||||||
|
|
||||||
#endif /* STATE_H */
|
|
||||||
|
|||||||
+5
-5
@@ -1,4 +1,3 @@
|
|||||||
#include <bsd/string.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -6,6 +5,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
|
static bool is_digit(char c) { return c >= '0' && c <= '9'; }
|
||||||
|
|
||||||
unsigned int string_trim(char *str) {
|
unsigned int string_trim(char *str) {
|
||||||
// https://www.delftstack.com/howto/c/trim-string-in-c/
|
// https://www.delftstack.com/howto/c/trim-string-in-c/
|
||||||
unsigned int start;
|
unsigned int start;
|
||||||
@@ -37,8 +38,6 @@ unsigned int string_trim(char *str) {
|
|||||||
return end - start + 1;
|
return end - start + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_digit(char c) { return c >= '0' && c <= '9'; }
|
|
||||||
|
|
||||||
bool string_is_number(const char *value) {
|
bool string_is_number(const char *value) {
|
||||||
unsigned long value_len;
|
unsigned long value_len;
|
||||||
|
|
||||||
@@ -59,7 +58,8 @@ bool string_is_number(const char *value) {
|
|||||||
|
|
||||||
char *string_replace_at(const char *src, unsigned int from, unsigned int to,
|
char *string_replace_at(const char *src, unsigned int from, unsigned int to,
|
||||||
const char *rpl) {
|
const char *rpl) {
|
||||||
unsigned long src_len, rpl_len;
|
unsigned long src_len;
|
||||||
|
unsigned long rpl_len;
|
||||||
char *dst;
|
char *dst;
|
||||||
|
|
||||||
src_len = strnlen(src, STR_LEN * STR_LEN);
|
src_len = strnlen(src, STR_LEN * STR_LEN);
|
||||||
@@ -72,4 +72,4 @@ char *string_replace_at(const char *src, unsigned int from, unsigned int to,
|
|||||||
strlcpy(dst + from + rpl_len, src + to, src_len - to + 1);
|
strlcpy(dst + from + rpl_len, src + to, src_len - to + 1);
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -10,4 +10,4 @@ bool string_is_number(const char *value);
|
|||||||
char *string_replace_at(const char *src, unsigned int from, unsigned int to,
|
char *string_replace_at(const char *src, unsigned int from, unsigned int to,
|
||||||
const char *rpl);
|
const char *rpl);
|
||||||
|
|
||||||
#endif /* STRINGS_H */
|
#endif /* STRINGS_H */
|
||||||
|
|||||||
+22
-10
@@ -25,14 +25,6 @@ static void reset_tap_chain(Tempo *tempo, long t) {
|
|||||||
memset(tempo->tap_durations, 0, sizeof(tempo->tap_durations));
|
memset(tempo->tap_durations, 0, sizeof(tempo->tap_durations));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tempo_init(Tempo *tempo) {
|
|
||||||
long t;
|
|
||||||
|
|
||||||
t = now();
|
|
||||||
|
|
||||||
reset_tap_chain(tempo, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_chain_active(const Tempo tempo, long t) {
|
static bool is_chain_active(const Tempo tempo, long t) {
|
||||||
return (tempo.last_tap + MAX_BEAT_LENGTH) > t &&
|
return (tempo.last_tap + MAX_BEAT_LENGTH) > t &&
|
||||||
(tempo.last_tap + (tempo.beat_length * BEATS_UNTIL_CHAIN_RESET)) > t;
|
(tempo.last_tap + (tempo.beat_length * BEATS_UNTIL_CHAIN_RESET)) > t;
|
||||||
@@ -98,11 +90,31 @@ static void add_tap_to_chain(Tempo *tempo, long t) {
|
|||||||
tempo->tempo = 60000.0 / tempo->beat_length;
|
tempo->tempo = 60000.0 / tempo->beat_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tempo_set(Tempo *tempo, float value) {
|
void tempo_init(Tempo *tempo, float value) {
|
||||||
|
long t;
|
||||||
|
|
||||||
|
t = now();
|
||||||
|
|
||||||
|
reset_tap_chain(tempo, t);
|
||||||
|
|
||||||
tempo->tempo = value;
|
tempo->tempo = value;
|
||||||
tempo->beat_length = 60000.0 / value;
|
tempo->beat_length = 60000.0 / value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tempo_set(Tempo *tempo, float value) {
|
||||||
|
long t;
|
||||||
|
long progress;
|
||||||
|
|
||||||
|
t = now();
|
||||||
|
|
||||||
|
progress = (t - tempo->last_reset) % tempo->beat_length;
|
||||||
|
|
||||||
|
tempo->tempo = value;
|
||||||
|
tempo->beat_length = 60000.0 / value;
|
||||||
|
|
||||||
|
reset_tap_chain(tempo, t - progress);
|
||||||
|
}
|
||||||
|
|
||||||
void tempo_tap(Tempo *tempo) {
|
void tempo_tap(Tempo *tempo) {
|
||||||
long t;
|
long t;
|
||||||
|
|
||||||
@@ -125,4 +137,4 @@ double tempo_total(const Tempo *tempo) {
|
|||||||
|
|
||||||
double tempo_progress(const Tempo *tempo, double modulo) {
|
double tempo_progress(const Tempo *tempo, double modulo) {
|
||||||
return fmod(tempo_total(tempo), modulo);
|
return fmod(tempo_total(tempo), modulo);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -3,7 +3,7 @@
|
|||||||
#ifndef TEMPO_H
|
#ifndef TEMPO_H
|
||||||
#define TEMPO_H
|
#define TEMPO_H
|
||||||
|
|
||||||
void tempo_init(Tempo *tempo);
|
void tempo_init(Tempo *tempo, float value);
|
||||||
|
|
||||||
void tempo_tap(Tempo *tempo);
|
void tempo_tap(Tempo *tempo);
|
||||||
|
|
||||||
@@ -13,4 +13,4 @@ double tempo_total(const Tempo *tempo);
|
|||||||
|
|
||||||
double tempo_progress(const Tempo *tempo, double modulo);
|
double tempo_progress(const Tempo *tempo, double modulo);
|
||||||
|
|
||||||
#endif /* TEMPO_H */
|
#endif /* TEMPO_H */
|
||||||
|
|||||||
+3
-2
@@ -18,7 +18,8 @@ bool timer_inc(Timer *timer) {
|
|||||||
|
|
||||||
double timer_reset(Timer *timer) {
|
double timer_reset(Timer *timer) {
|
||||||
struct timeval stop;
|
struct timeval stop;
|
||||||
double secs, per_secs;
|
double secs;
|
||||||
|
double per_secs;
|
||||||
|
|
||||||
gettimeofday(&stop, NULL);
|
gettimeofday(&stop, NULL);
|
||||||
|
|
||||||
@@ -30,4 +31,4 @@ double timer_reset(Timer *timer) {
|
|||||||
timer->counter = 0;
|
timer->counter = 0;
|
||||||
|
|
||||||
return per_secs;
|
return per_secs;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -9,4 +9,4 @@ bool timer_inc(Timer *timer);
|
|||||||
|
|
||||||
double timer_reset(Timer *timer);
|
double timer_reset(Timer *timer);
|
||||||
|
|
||||||
#endif /* TIMER_H */
|
#endif /* TIMER_H */
|
||||||
|
|||||||
+43
-14
@@ -1,12 +1,13 @@
|
|||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
|
#ifdef VIDEO_IN
|
||||||
#include <glad/egl.h>
|
#include <glad/egl.h>
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
#include <glad/gl.h>
|
#include <glad/gl.h>
|
||||||
#include <hashmap.h>
|
#include <hashmap.h>
|
||||||
#include <linmath.h>
|
#include <linmath.h>
|
||||||
#include <linux/videodev2.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -43,10 +44,11 @@ typedef struct Parameters {
|
|||||||
float base_tempo;
|
float base_tempo;
|
||||||
bool demo;
|
bool demo;
|
||||||
bool auto_random;
|
bool auto_random;
|
||||||
|
unsigned int auto_random_cycle;
|
||||||
StringArray video_in;
|
StringArray video_in;
|
||||||
unsigned int video_size;
|
unsigned int video_size;
|
||||||
unsigned int internal_size;
|
unsigned int internal_size;
|
||||||
char state_file[STR_LEN];
|
bool video_reconnect;
|
||||||
bool load_state;
|
bool load_state;
|
||||||
bool save_state;
|
bool save_state;
|
||||||
bool trace_midi;
|
bool trace_midi;
|
||||||
@@ -102,8 +104,10 @@ typedef struct ShaderProgram {
|
|||||||
GLuint iinres_locations[ARRAY_SIZE];
|
GLuint iinres_locations[ARRAY_SIZE];
|
||||||
GLuint iinfmt_locations[ARRAY_SIZE];
|
GLuint iinfmt_locations[ARRAY_SIZE];
|
||||||
GLuint iinfps_locations[ARRAY_SIZE];
|
GLuint iinfps_locations[ARRAY_SIZE];
|
||||||
|
GLuint iinswap_locations[ARRAY_SIZE];
|
||||||
GLuint idemo_locations[ARRAY_SIZE];
|
GLuint idemo_locations[ARRAY_SIZE];
|
||||||
GLuint iautorand_locations[ARRAY_SIZE];
|
GLuint iautorand_locations[ARRAY_SIZE];
|
||||||
|
GLuint iautorandcycle_locations[ARRAY_SIZE];
|
||||||
GLuint iseed_locations[ARRAY_SIZE];
|
GLuint iseed_locations[ARRAY_SIZE];
|
||||||
GLuint istate_locations[ARRAY_SIZE];
|
GLuint istate_locations[ARRAY_SIZE];
|
||||||
GLuint ipage_locations[ARRAY_SIZE];
|
GLuint ipage_locations[ARRAY_SIZE];
|
||||||
@@ -124,7 +128,11 @@ typedef struct ShaderProgram {
|
|||||||
unsigned int active_count;
|
unsigned int active_count;
|
||||||
|
|
||||||
unsigned int in_count;
|
unsigned int in_count;
|
||||||
|
#ifdef VIDEO_IN
|
||||||
EGLDisplay egl_display;
|
EGLDisplay egl_display;
|
||||||
|
EGLImageKHR dma_images[MAX_VIDEO];
|
||||||
|
EGLImageKHR dma_images_swap[MAX_VIDEO];
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
} ShaderProgram;
|
} ShaderProgram;
|
||||||
|
|
||||||
// video.c
|
// video.c
|
||||||
@@ -132,18 +140,28 @@ typedef struct ShaderProgram {
|
|||||||
typedef struct VideoCapture {
|
typedef struct VideoCapture {
|
||||||
char name[STR_LEN];
|
char name[STR_LEN];
|
||||||
bool error;
|
bool error;
|
||||||
|
bool disconnected;
|
||||||
|
bool needs_reload;
|
||||||
|
bool with_swap;
|
||||||
|
bool swap;
|
||||||
|
unsigned int fps;
|
||||||
int fd;
|
int fd;
|
||||||
int exp_fd;
|
int exp_fd;
|
||||||
|
int exp_fd_swap;
|
||||||
unsigned int width;
|
unsigned int width;
|
||||||
unsigned int height;
|
unsigned int height;
|
||||||
unsigned int pixelformat;
|
unsigned int pixelformat;
|
||||||
unsigned int bytesperline;
|
unsigned int bytesperline;
|
||||||
bool output;
|
#ifdef VIDEO_IN
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf;
|
||||||
EGLImageKHR dma_image;
|
struct v4l2_buffer buf_swap;
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
} VideoCapture;
|
} VideoCapture;
|
||||||
|
|
||||||
typedef ARRAY(VideoCaptureArray, VideoCapture);
|
typedef struct VideoCaptureArray {
|
||||||
|
VideoCapture values[MAX_VIDEO];
|
||||||
|
unsigned int length;
|
||||||
|
} VideoCaptureArray;
|
||||||
|
|
||||||
// window.c
|
// window.c
|
||||||
|
|
||||||
@@ -166,13 +184,10 @@ typedef struct Tempo {
|
|||||||
|
|
||||||
typedef struct SharedContext {
|
typedef struct SharedContext {
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
vec2 resolution;
|
vec2 resolution;
|
||||||
vec2 tex_resolution;
|
vec2 tex_resolution;
|
||||||
vec2 input_resolutions[MAX_VIDEO];
|
vec2 input_resolutions[MAX_VIDEO];
|
||||||
|
|
||||||
double time;
|
double time;
|
||||||
unsigned int fps;
|
|
||||||
Tempo tempo;
|
Tempo tempo;
|
||||||
double tempo_total;
|
double tempo_total;
|
||||||
UintArray state;
|
UintArray state;
|
||||||
@@ -182,11 +197,10 @@ typedef struct SharedContext {
|
|||||||
vec3 values[ARRAY_SIZE];
|
vec3 values[ARRAY_SIZE];
|
||||||
bool demo;
|
bool demo;
|
||||||
bool auto_random;
|
bool auto_random;
|
||||||
|
unsigned int auto_random_cycle;
|
||||||
unsigned int seeds[MAX_FRAG];
|
unsigned int seeds[MAX_FRAG];
|
||||||
bool monitor;
|
unsigned int fps;
|
||||||
|
VideoCaptureArray inputs;
|
||||||
unsigned int input_formats[MAX_VIDEO];
|
|
||||||
unsigned int input_fps[MAX_VIDEO];
|
|
||||||
bool stop;
|
bool stop;
|
||||||
} SharedContext;
|
} SharedContext;
|
||||||
|
|
||||||
@@ -210,6 +224,20 @@ typedef struct StateConfig {
|
|||||||
unsigned int value_count;
|
unsigned int value_count;
|
||||||
|
|
||||||
unsigned int tap_tempo_code;
|
unsigned int tap_tempo_code;
|
||||||
|
|
||||||
|
char save_file_prefix[STR_LEN];
|
||||||
|
|
||||||
|
unsigned int hotkey_randomize;
|
||||||
|
unsigned int hotkey_reset;
|
||||||
|
unsigned int hotkey_demo;
|
||||||
|
unsigned int hotkey_autorand;
|
||||||
|
unsigned int hotkey_autorand_up;
|
||||||
|
unsigned int hotkey_autorand_down;
|
||||||
|
unsigned int hotkey_tempo_up;
|
||||||
|
unsigned int hotkey_tempo_down;
|
||||||
|
|
||||||
|
UintArray hotkey_load;
|
||||||
|
UintArray hotkey_save;
|
||||||
} StateConfig;
|
} StateConfig;
|
||||||
|
|
||||||
// timer.c
|
// timer.c
|
||||||
@@ -224,6 +252,7 @@ typedef struct Timer {
|
|||||||
|
|
||||||
typedef struct ConfigFile {
|
typedef struct ConfigFile {
|
||||||
struct hashmap *map;
|
struct hashmap *map;
|
||||||
|
bool error;
|
||||||
} ConfigFile;
|
} ConfigFile;
|
||||||
|
|
||||||
typedef struct ConfigFileItem {
|
typedef struct ConfigFileItem {
|
||||||
@@ -253,4 +282,4 @@ typedef struct Project {
|
|||||||
File fragment_shaders[MAX_FRAG][MAX_SUB_FILE + 1];
|
File fragment_shaders[MAX_FRAG][MAX_SUB_FILE + 1];
|
||||||
} Project;
|
} Project;
|
||||||
|
|
||||||
#endif /* TYPES_H */
|
#endif /* TYPES_H */
|
||||||
|
|||||||
+95
-65
@@ -1,4 +1,5 @@
|
|||||||
#include <bsd/string.h>
|
#ifdef VIDEO_IN
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
@@ -15,6 +16,9 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "video.h"
|
#include "video.h"
|
||||||
|
|
||||||
|
static const unsigned int pixel_format = V4L2_PIX_FMT_YUYV;
|
||||||
|
static const enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
static void ioctl_error(VideoCapture *video_capture, const char *operation,
|
static void ioctl_error(VideoCapture *video_capture, const char *operation,
|
||||||
const char *default_msg) {
|
const char *default_msg) {
|
||||||
if (errno == EINVAL) {
|
if (errno == EINVAL) {
|
||||||
@@ -70,9 +74,8 @@ static void open_device(VideoCapture *video_capture, const char *name) {
|
|||||||
strlcpy(video_capture->name, name, STR_LEN);
|
strlcpy(video_capture->name, name, STR_LEN);
|
||||||
video_capture->error = false;
|
video_capture->error = false;
|
||||||
video_capture->fd = -1;
|
video_capture->fd = -1;
|
||||||
video_capture->exp_fd = -1;
|
|
||||||
|
|
||||||
video_capture->fd = open(name, O_RDWR);
|
video_capture->fd = open(name, O_RDWR | O_NONBLOCK);
|
||||||
if (video_capture->fd == -1) {
|
if (video_capture->fd == -1) {
|
||||||
log_warn("(%s) Cannot open device", name);
|
log_warn("(%s) Cannot open device", name);
|
||||||
video_capture->error = true;
|
video_capture->error = true;
|
||||||
@@ -114,7 +117,7 @@ static bool get_available_sizes(VideoCapture *video_capture,
|
|||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
fmt_enum.index = index;
|
fmt_enum.index = index;
|
||||||
fmt_enum.pixel_format = V4L2_PIX_FMT_YUYV;
|
fmt_enum.pixel_format = pixel_format;
|
||||||
|
|
||||||
found = false;
|
found = false;
|
||||||
video_capture->width = 0;
|
video_capture->width = 0;
|
||||||
@@ -146,7 +149,7 @@ static bool get_available_sizes(VideoCapture *video_capture,
|
|||||||
|
|
||||||
memset(&fmt_enum, 0, sizeof(fmt_enum));
|
memset(&fmt_enum, 0, sizeof(fmt_enum));
|
||||||
fmt_enum.index = ++index;
|
fmt_enum.index = ++index;
|
||||||
fmt_enum.pixel_format = V4L2_PIX_FMT_YUYV;
|
fmt_enum.pixel_format = pixel_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video_capture->height == 0) {
|
if (video_capture->height == 0) {
|
||||||
@@ -161,26 +164,18 @@ static bool get_available_sizes(VideoCapture *video_capture,
|
|||||||
static bool set_format(VideoCapture *video_capture) {
|
static bool set_format(VideoCapture *video_capture) {
|
||||||
struct v4l2_format fmt;
|
struct v4l2_format fmt;
|
||||||
|
|
||||||
video_capture->output = false;
|
|
||||||
|
|
||||||
memset(&fmt, 0, sizeof(fmt));
|
memset(&fmt, 0, sizeof(fmt));
|
||||||
|
|
||||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
fmt.type = buf_type;
|
||||||
fmt.fmt.pix.width = video_capture->width;
|
fmt.fmt.pix.width = video_capture->width;
|
||||||
fmt.fmt.pix.height = video_capture->height;
|
fmt.fmt.pix.height = video_capture->height;
|
||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
fmt.fmt.pix.pixelformat = pixel_format;
|
||||||
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||||
|
|
||||||
if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) {
|
if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) {
|
||||||
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
|
ioctl_error(video_capture, "VIDIOC_S_FMT",
|
||||||
|
"Requested buffer type not supported");
|
||||||
video_capture->output = true;
|
return false;
|
||||||
|
|
||||||
if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) {
|
|
||||||
ioctl_error(video_capture, "VIDIOC_S_FMT",
|
|
||||||
"Requested buffer type not supported");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
video_capture->width = fmt.fmt.pix.width;
|
video_capture->width = fmt.fmt.pix.width;
|
||||||
@@ -202,10 +197,9 @@ static bool request_buffers(VideoCapture *video_capture) {
|
|||||||
|
|
||||||
memset(&reqbuf, 0, sizeof(reqbuf));
|
memset(&reqbuf, 0, sizeof(reqbuf));
|
||||||
|
|
||||||
reqbuf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT
|
reqbuf.type = buf_type;
|
||||||
: V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
reqbuf.memory = V4L2_MEMORY_MMAP;
|
reqbuf.memory = V4L2_MEMORY_MMAP;
|
||||||
reqbuf.count = 1;
|
reqbuf.count = 2;
|
||||||
|
|
||||||
if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
|
if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
|
||||||
ioctl_error(video_capture, "VIDIOC_REQBUFS",
|
ioctl_error(video_capture, "VIDIOC_REQBUFS",
|
||||||
@@ -215,19 +209,21 @@ static bool request_buffers(VideoCapture *video_capture) {
|
|||||||
|
|
||||||
log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count);
|
log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count);
|
||||||
|
|
||||||
|
video_capture->with_swap = reqbuf.count > 1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool export_buffer(VideoCapture *video_capture) {
|
static bool export_buffer(VideoCapture *video_capture, int *fd,
|
||||||
|
unsigned int index) {
|
||||||
struct v4l2_exportbuffer expbuf;
|
struct v4l2_exportbuffer expbuf;
|
||||||
|
|
||||||
video_capture->exp_fd = -1;
|
*fd = -1;
|
||||||
|
|
||||||
memset(&expbuf, 0, sizeof(expbuf));
|
memset(&expbuf, 0, sizeof(expbuf));
|
||||||
|
|
||||||
expbuf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT
|
expbuf.type = buf_type;
|
||||||
: V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
expbuf.index = index;
|
||||||
expbuf.index = 0;
|
|
||||||
expbuf.flags = O_RDONLY;
|
expbuf.flags = O_RDONLY;
|
||||||
|
|
||||||
if (ioctl(video_capture->fd, VIDIOC_EXPBUF, &expbuf) == -1) {
|
if (ioctl(video_capture->fd, VIDIOC_EXPBUF, &expbuf) == -1) {
|
||||||
@@ -237,12 +233,23 @@ static bool export_buffer(VideoCapture *video_capture) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
video_capture->exp_fd = expbuf.fd;
|
*fd = expbuf.fd;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
static bool export_buffers(VideoCapture *video_capture) {
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
result = export_buffer(video_capture, &video_capture->exp_fd, 0);
|
||||||
|
|
||||||
|
if (result && video_capture->with_swap) {
|
||||||
|
result =
|
||||||
|
result && export_buffer(video_capture, &video_capture->exp_fd_swap, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static bool open_stream(VideoCapture *video_capture) {
|
static bool open_stream(VideoCapture *video_capture) {
|
||||||
if (ioctl(video_capture->fd, VIDIOC_STREAMON, &buf_type) == -1) {
|
if (ioctl(video_capture->fd, VIDIOC_STREAMON, &buf_type) == -1) {
|
||||||
@@ -255,21 +262,53 @@ static bool open_stream(VideoCapture *video_capture) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_image_buffer(VideoCapture *video_capture) {
|
static void create_image_buffer(const VideoCapture *video_capture,
|
||||||
memset(&video_capture->buf, 0, sizeof(video_capture->buf));
|
struct v4l2_buffer *buf, unsigned int index) {
|
||||||
|
memset(buf, 0, sizeof(*buf));
|
||||||
|
|
||||||
video_capture->buf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT
|
buf->type = buf_type;
|
||||||
: V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
buf->memory = V4L2_MEMORY_MMAP;
|
||||||
video_capture->buf.memory = V4L2_MEMORY_MMAP;
|
buf->index = index;
|
||||||
video_capture->buf.index = 0;
|
|
||||||
|
|
||||||
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf);
|
ioctl(video_capture->fd, VIDIOC_QBUF, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_image_buffers(VideoCapture *video_capture) {
|
||||||
|
create_image_buffer(video_capture, &video_capture->buf, 0);
|
||||||
|
|
||||||
|
if (video_capture->with_swap) {
|
||||||
|
create_image_buffer(video_capture, &video_capture->buf_swap, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_stream(const VideoCapture *video_capture) {
|
static void close_stream(const VideoCapture *video_capture) {
|
||||||
ioctl(video_capture->fd, VIDIOC_STREAMOFF, &buf_type);
|
ioctl(video_capture->fd, VIDIOC_STREAMOFF, &buf_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int read_video(VideoCapture *video_capture) {
|
||||||
|
unsigned int result;
|
||||||
|
struct v4l2_capability cap;
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
if ((video_capture->swap || !video_capture->with_swap) &&
|
||||||
|
ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf) != -1) {
|
||||||
|
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf);
|
||||||
|
|
||||||
|
result = 1;
|
||||||
|
} else if (!video_capture->swap && video_capture->with_swap &&
|
||||||
|
ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf_swap) !=
|
||||||
|
-1) {
|
||||||
|
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf_swap);
|
||||||
|
|
||||||
|
result = 2;
|
||||||
|
} else if (ioctl(video_capture->fd, VIDIOC_QUERYCAP, &cap) == -1) {
|
||||||
|
video_capture->error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void video_init(VideoCapture *video_capture, const char *name,
|
void video_init(VideoCapture *video_capture, const char *name,
|
||||||
unsigned int preferred_height) {
|
unsigned int preferred_height) {
|
||||||
open_device(video_capture, name);
|
open_device(video_capture, name);
|
||||||
@@ -294,7 +333,7 @@ void video_init(VideoCapture *video_capture, const char *name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!export_buffer(video_capture)) {
|
if (!export_buffers(video_capture)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,25 +341,7 @@ void video_init(VideoCapture *video_capture, const char *name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
create_image_buffer(video_capture);
|
create_image_buffers(video_capture);
|
||||||
}
|
|
||||||
|
|
||||||
static bool read_video(VideoCapture *video_capture) {
|
|
||||||
if (ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf) == -1) {
|
|
||||||
ioctl_error(video_capture, "VIDIOC_DQBUF",
|
|
||||||
"buffer type not supported or no buffer allocated or the index "
|
|
||||||
"is out of bounds");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf) == -1) {
|
|
||||||
ioctl_error(video_capture, "VIDIOC_QBUF",
|
|
||||||
"buffer type not supported or no buffer allocated or the index "
|
|
||||||
"is out of bounds");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool video_background_read(VideoCapture *video_capture, SharedContext *context,
|
bool video_background_read(VideoCapture *video_capture, SharedContext *context,
|
||||||
@@ -328,6 +349,7 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
Timer timer;
|
Timer timer;
|
||||||
double fps;
|
double fps;
|
||||||
|
unsigned int video_result;
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
@@ -341,16 +363,19 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
|
|||||||
pid);
|
pid);
|
||||||
timer_init(&timer, 30);
|
timer_init(&timer, 30);
|
||||||
|
|
||||||
while (!context->stop && read_video(video_capture)) {
|
while (!context->stop && !video_capture->error) {
|
||||||
// repeat infinitely
|
video_result = read_video(video_capture);
|
||||||
if (timer_inc(&timer)) {
|
if (video_result > 0 && timer_inc(&timer)) {
|
||||||
fps = timer_reset(&timer);
|
fps = timer_reset(&timer);
|
||||||
|
|
||||||
context->input_fps[input_index] = (unsigned int)round(fps);
|
context->inputs.values[input_index].fps = (unsigned int)round(fps);
|
||||||
if (trace_fps) {
|
if (trace_fps) {
|
||||||
log_trace("(%s) %.2ffps", video_capture->name, fps);
|
log_trace("(%s) %.2ffps", video_capture->name, fps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (video_result > 0) {
|
||||||
|
video_capture->swap = video_result == 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (context->stop) {
|
if (context->stop) {
|
||||||
log_info("(%s) background acquisition stopped by main thread (pid: %d)",
|
log_info("(%s) background acquisition stopped by main thread (pid: %d)",
|
||||||
@@ -358,19 +383,24 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
|
|||||||
} else {
|
} else {
|
||||||
log_info("(%s) background acquisition stopped after error (pid: %d)",
|
log_info("(%s) background acquisition stopped after error (pid: %d)",
|
||||||
video_capture->name, pid);
|
video_capture->name, pid);
|
||||||
|
video_capture->disconnected = true;
|
||||||
|
video_capture->pixelformat = 0;
|
||||||
|
video_free(video_capture);
|
||||||
}
|
}
|
||||||
exit(context->stop ? EXIT_SUCCESS : EXIT_FAILURE);
|
exit(context->stop ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void video_free(const VideoCapture *video_capture) {
|
void video_free(const VideoCapture *video_capture) {
|
||||||
if (!video_capture->error) {
|
close_stream(video_capture);
|
||||||
close_stream(video_capture);
|
|
||||||
}
|
|
||||||
if (video_capture->exp_fd != -1) {
|
if (video_capture->exp_fd != -1) {
|
||||||
close(video_capture->exp_fd);
|
close(video_capture->exp_fd);
|
||||||
}
|
}
|
||||||
|
if (video_capture->exp_fd_swap != -1) {
|
||||||
|
close(video_capture->exp_fd);
|
||||||
|
}
|
||||||
if (video_capture->fd != -1) {
|
if (video_capture->fd != -1) {
|
||||||
close(video_capture->fd);
|
close(video_capture->fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* VIDEO_IN */
|
||||||
|
|||||||
+1
-1
@@ -11,4 +11,4 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
|
|||||||
|
|
||||||
void video_free(const VideoCapture *video_capture);
|
void video_free(const VideoCapture *video_capture);
|
||||||
|
|
||||||
#endif /* VIDEO_H */
|
#endif /* VIDEO_H */
|
||||||
|
|||||||
+22
-4
@@ -121,7 +121,8 @@ void window_events() { glfwPollEvents(); }
|
|||||||
double window_get_time() { return glfwGetTime(); }
|
double window_get_time() { return glfwGetTime(); }
|
||||||
|
|
||||||
void window_use(Window *window, SharedContext *context) {
|
void window_use(Window *window, SharedContext *context) {
|
||||||
int width, height;
|
int width;
|
||||||
|
int height;
|
||||||
|
|
||||||
glfwMakeContextCurrent(window);
|
glfwMakeContextCurrent(window);
|
||||||
glfwGetFramebufferSize(window, &width, &height);
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
@@ -145,6 +146,23 @@ bool window_escape_key(int key, int action) {
|
|||||||
return key == GLFW_KEY_ESCAPE && action == GLFW_PRESS;
|
return key == GLFW_KEY_ESCAPE && action == GLFW_PRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool window_char_key(int key, int action, const int char_code) {
|
unsigned int window_read_key(int key, int action, int mods) {
|
||||||
return key == char_code && action == GLFW_PRESS;
|
unsigned int result;
|
||||||
}
|
if (action == GLFW_RELEASE || key == GLFW_KEY_LEFT_SHIFT ||
|
||||||
|
key == GLFW_KEY_RIGHT_SHIFT || key == GLFW_KEY_LEFT_CONTROL ||
|
||||||
|
key == GLFW_KEY_RIGHT_CONTROL || key == GLFW_KEY_LEFT_ALT ||
|
||||||
|
key == GLFW_KEY_RIGHT_ALT) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
result = key;
|
||||||
|
if ((mods & GLFW_MOD_SHIFT) > 0) {
|
||||||
|
result += 1000;
|
||||||
|
}
|
||||||
|
if ((mods & GLFW_MOD_CONTROL) > 0) {
|
||||||
|
result += 10000;
|
||||||
|
}
|
||||||
|
if ((mods & GLFW_MOD_ALT) > 0) {
|
||||||
|
result += 100000;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -27,6 +27,6 @@ bool window_should_close(Window *window);
|
|||||||
|
|
||||||
bool window_escape_key(int key, int action);
|
bool window_escape_key(int key, int action);
|
||||||
|
|
||||||
bool window_char_key(int key, int action, const int char_code);
|
unsigned int window_read_key(int key, int action, int mods);
|
||||||
|
|
||||||
#endif /* WINDOW_H */
|
#endif /* WINDOW_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user