104 Commits

Author SHA1 Message Date
klemek fddb11dbe3 forge (steel) v1.1.2
Clang Build CI / run-video (push) Successful in 1m31s
Clang Build CI / run-no-video (push) Successful in 1m31s
Clang Build CI / build-release (push) Successful in 1m42s
Clang Lint CI / lint-no-video (push) Successful in 2m29s
Clang Lint CI / lint-video (push) Successful in 2m29s
2026-05-16 19:04:47 +02:00
klemek 591bfbe0aa fix: remove not backward compatible snd_lib_log_set_handler
Clang Lint CI / lint-no-video (push) Successful in 55s
Clang Build CI / run-no-video (push) Successful in 1m36s
Clang Build CI / run-video (push) Successful in 1m37s
Clang Build CI / build-release (push) Successful in 1m57s
Clang Lint CI / lint-video (push) Successful in 2m5s
2026-05-16 18:56:45 +02:00
klemek b01314778d docs: add comment for project_free
Clang Lint CI / lint-no-video (push) Failing after 3m4s
Clang Build CI / run-no-video (push) Failing after 3m49s
Clang Build CI / run-video (push) Failing after 3m48s
Clang Build CI / build-release (push) Failing after 4m3s
Clang Lint CI / lint-video (push) Failing after 1m26s
2026-05-16 18:49:44 +02:00
klemek cbdf4c768d fix: const vertex_shader_text
Clang Build CI / build-release (push) Has been cancelled
Clang Build CI / run-no-video (push) Has been cancelled
Clang Build CI / run-video (push) Has been cancelled
Clang Lint CI / lint-video (push) Has been cancelled
Clang Lint CI / lint-no-video (push) Has been cancelled
2026-05-16 18:48:26 +02:00
klemek 9787f468e8 fix: dont shadow stdlib rand 2026-05-16 18:47:51 +02:00
klemek 2a8bd612b3 fix: unnecessary structs 2026-05-16 18:47:16 +02:00
klemek ba44237661 fix: MidiBackgroundListenArgs bad typedef 2026-05-16 18:46:34 +02:00
klemek efb13bb9ea fix: auto random debug string bad practice 2026-05-16 18:45:18 +02:00
klemek d89de9d6dd fix: check_eglerror_ro dead code 2026-05-16 18:42:17 +02:00
klemek 6ff0246f42 fix: GLint uniform location instead of GLuint 2026-05-16 18:40:52 +02:00
klemek c45b5ef405 fix: glGetShaderInfoLog with invalid parameters 2026-05-16 18:38:05 +02:00
klemek 12942267d2 fix: dont allow empty values in string args 2026-05-16 18:35:32 +02:00
klemek 15fb29b673 fix: boundary check in parse_uint 2026-05-16 18:32:44 +02:00
klemek 39e1fcc709 fix: set gl context before freeing shaders 2026-05-16 18:32:08 +02:00
klemek 3ae3b23c2a fix: add default value for tex_resolution width 2026-05-16 18:30:28 +02:00
klemek 61c88aae2a fix: check pthread_create return code 2026-05-16 18:29:38 +02:00
klemek fcb2baf84a fix: check return_code of snd_rawmidi_open 2026-05-16 18:26:37 +02:00
klemek 8e7be2258f fix: handle division by 0 in window_use 2026-05-16 18:24:36 +02:00
klemek dcb334ff81 fix: handle VIDIOC_QBUF error while reading video 2026-05-16 18:22:48 +02:00
klemek aab770ba3d fix: free video capture on early init error 2026-05-16 18:19:17 +02:00
klemek 6a7c9b3aab fix: bound timer counter to uint max on fail 2026-05-16 18:10:31 +02:00
klemek 3b6d4d642d fix: use clock instead of timeofday 2026-05-16 18:09:06 +02:00
klemek 988cf799b4 fix: config_file_read handle file error before hashmap_new 2026-05-16 17:54:05 +02:00
klemek a92cca33ad fix: state_parse_config clamp lengths to ARRAY_SIZE 2026-05-16 17:51:40 +02:00
klemek fd9f94d48a fix: save_to_file array size bound check 2026-05-16 17:51:36 +02:00
klemek 859dfc4307 fix: log tempo error 2026-05-16 17:37:49 +02:00
klemek a85a75f93d fix: sync midi read/write 2026-05-16 17:36:50 +02:00
klemek 7e1328aab0 fix: check for snd_rawmidi_info_malloc 2026-05-16 17:35:21 +02:00
klemek 7cce5babc2 fix: don't log errors while reconnecting 2026-05-16 17:12:40 +02:00
klemek 9969230cd9 fix: free process args in pthread 2026-05-16 16:44:34 +02:00
klemek fb77d8e893 fix: revert project files free (already freed in init) 2026-05-16 16:22:39 +02:00
klemek 0fd78bf4cc fix: unsigned comparison 2026-05-16 16:02:53 +02:00
klemek 20e3d39963 fix: init_single_program check linking status 2026-05-16 16:00:39 +02:00
klemek aa8d6c85c0 fix: shaders_free glDeleteShader 2026-05-16 15:55:18 +02:00
klemek b9fd36debd fix: project files free 2026-05-16 15:52:39 +02:00
klemek 7e8eb187d8 fix: parse_fragment_shader_file free content before overwrite 2026-05-16 15:49:22 +02:00
klemek bd61cb0a2d fix: config_file_read dont initialize hashmap on file error 2026-05-16 15:40:03 +02:00
klemek fe1fc9864c fix: string_replace_at check args validity 2026-05-16 15:39:17 +02:00
klemek 233b75e854 fix: string_replace_at check malloc 2026-05-16 15:38:19 +02:00
klemek 910c122c8d fix: unsigned overflow in string_trim 2026-05-16 15:36:09 +02:00
klemek fbd73ebf4c fix: handle partial reads 2026-05-16 15:34:09 +02:00
klemek 43ce38f2f4 fix: file free dangling pointer 2026-05-16 15:31:30 +02:00
klemek ca3e523f93 fix: ftell failure handling 2026-05-16 13:26:40 +02:00
klemek c68bebfd7c fix: unsigned underflow on empty array 2026-05-16 13:25:02 +02:00
klemek 2843e5e863 fix: better full-clean 2026-05-16 00:36:28 +02:00
klemek 433cf61a91 forge (steel) v1.1.1
Clang Build CI / run-no-video (push) Successful in 1m18s
Clang Build CI / build-release (push) Successful in 1m30s
Clang Build CI / run-video (push) Successful in 1m26s
Clang Lint CI / lint-no-video (push) Successful in 1m22s
Clang Lint CI / lint-video (push) Successful in 1m17s
2026-05-16 00:33:24 +02:00
klemek fe3316f730 feat: better src 4 2026-05-16 00:32:41 +02:00
klemek 96f97d81df fix: update default project with internal buffer swap 2026-05-15 16:36:57 +02:00
klemek 365fee352e tools: better clean 2026-05-15 00:24:16 +02:00
klemek 1b3d6464de forge (steel) v1.1.0
Clang Build CI / run-video (push) Successful in 1m11s
Clang Build CI / run-no-video (push) Successful in 1m14s
Clang Build CI / build-release (push) Successful in 1m36s
Clang Lint CI / lint-no-video (push) Successful in 1m9s
Clang Lint CI / lint-video (push) Successful in 1m19s
2026-05-15 00:20:29 +02:00
klemek bdaf53e259 docs: add cloc 2026-05-15 00:18:06 +02:00
klemek 37a492d00d refactor: specify number of video input buffers
Clang Lint CI / lint-no-video (push) Successful in 1m5s
Clang Build CI / run-no-video (push) Successful in 1m5s
Clang Build CI / run-video (push) Successful in 1m5s
Clang Build CI / build-release (push) Successful in 2m24s
Clang Lint CI / lint-video (push) Successful in 2m22s
2026-05-15 00:09:51 +02:00
klemek 06d175c4fd docs: update DEVELOPMENT.md 2026-05-14 22:52:48 +02:00
klemek 7b9f5ca032 feat: midi/keyboard cross working codes
Clang Lint CI / lint-no-video (push) Successful in 1m17s
Clang Build CI / run-no-video (push) Successful in 1m18s
Clang Build CI / run-video (push) Successful in 1m17s
Clang Build CI / build-release (push) Successful in 1m54s
Clang Lint CI / lint-video (push) Successful in 1m22s
2026-05-14 22:52:08 +02:00
klemek 6abf050bcc refactor: not overlaping keyboard and midi
Clang Lint CI / lint-no-video (push) Successful in 1m0s
Clang Build CI / run-no-video (push) Successful in 1m0s
Clang Build CI / run-video (push) Successful in 1m1s
Clang Build CI / build-release (push) Successful in 1m56s
Clang Lint CI / lint-video (push) Successful in 1m59s
2026-05-14 22:27:39 +02:00
klemek 28b87d316a feat: auto-reconnect midi
Clang Lint CI / lint-no-video (push) Successful in 59s
Clang Build CI / run-no-video (push) Successful in 59s
Clang Build CI / run-video (push) Successful in 59s
Clang Build CI / build-release (push) Successful in 1m31s
Clang Lint CI / lint-video (push) Successful in 1m7s
2026-05-14 15:28:38 +02:00
klemek adc520bc8b refactor: no state_config pointer
Clang Build CI / run-no-video (push) Successful in 1m2s
Clang Lint CI / lint-no-video (push) Successful in 1m1s
Clang Build CI / run-video (push) Successful in 1m2s
Clang Build CI / build-release (push) Successful in 1m50s
Clang Lint CI / lint-video (push) Successful in 1m47s
2026-05-14 14:24:41 +02:00
klemek d4565fa507 feat: video auto reconnect
Clang Lint CI / lint-no-video (push) Successful in 56s
Clang Build CI / run-no-video (push) Successful in 59s
Clang Build CI / run-video (push) Successful in 1m15s
Clang Build CI / build-release (push) Successful in 2m23s
Clang Lint CI / lint-video (push) Successful in 2m14s
2026-05-14 14:03:41 +02:00
klemek 25b7134a43 fix: add debug capabilities for gl and egl
Clang Lint CI / lint-no-video (push) Failing after 44s
Clang Build CI / run-no-video (push) Successful in 1m7s
Clang Build CI / run-video (push) Successful in 1m7s
Clang Build CI / build-release (push) Successful in 1m26s
Clang Lint CI / lint-video (push) Successful in 1m46s
2026-05-14 00:11:49 +02:00
klemek 7da4f27e13 docs: github.com -> git.klemek.fr 2026-05-13 16:45:08 +02:00
klemek 26c90ec928 forge (steel) v1.0.2 2026-05-13 16:41:35 +02:00
klemek e982c9214d fix: PKGBUILD 2026-05-13 16:41:35 +02:00
klemek d640017136 ci: proper CI 2026-05-13 16:32:11 +02:00
klemek 3aaefc3174 fix: remove bsd dependency and make no-video build 2026-05-13 16:32:09 +02:00
klemek a7bc58e94e refactor: store init params in main program
C-lang CI / build-no-video (push) Failing after 32s
C-lang CI / lint (push) Failing after 36s
C-lang CI / build-release (push) Has been skipped
2026-05-11 08:42:36 +02:00
klemek dfefe879c9 feat: video reconnect cli arg 2026-05-11 08:36:32 +02:00
klemek 7d99c617ef refactor: check every gl error 2026-05-11 08:30:21 +02:00
klemek cdc7df3e56 refactor: review format and imports 2026-05-11 07:56:26 +02:00
klemek 8f0da378b0 fix: forks should exit 2026-05-11 07:40:34 +02:00
klemek 7d03c9719e feat: video reconnect (wip egl error 3003) 2026-05-11 07:40:20 +02:00
klemek dd20515e2b style: format glsl files and fix inc_src 2026-05-11 07:34:47 +02:00
klemek 53c5639f92 docs: small linux dev/video help 2026-05-11 07:28:38 +02:00
klemek d85c5b47b6 tools: add more formatting config 2026-05-11 07:28:08 +02:00
klemek 97f768f65e fix(video): alternate read for double buffering 2025-11-24 19:11:59 +01:00
klemek c66a5c166e feat: double buffered video input 2025-11-24 18:52:44 +01:00
klemek aa42e9d2aa docs: README update 2025-11-24 00:28:59 +01:00
klemek 3dceb044aa build: check build no video 2025-11-24 00:28:30 +01:00
klemek d19f5d2d81 fix(video): slightly faster video 2025-11-23 19:11:08 +01:00
klemek 1bf0bfc558 fix(build): remove video args if no video 2025-11-23 19:10:57 +01:00
klemek 06544ee23e refactor: more maintainability 2025-11-23 15:55:43 +01:00
klemek 1f5f502905 ci(sonar): add properties file 2025-11-23 15:39:17 +01:00
klemek 7120bc0207 refactor: clean unused variables 2025-11-23 15:36:21 +01:00
klemek c7ae4191d3 fix(video): better fps for interlaced 2025-11-23 15:04:21 +01:00
klemek 85349598c3 fix(default): debug screen fix 2025-11-23 15:04:10 +01:00
klemek 2f83bbb21e style: identifiers separation 2025-11-23 13:06:40 +01:00
klemek 6b4630f255 feat(video): slightly faster video acquisition with O_NONBLOCK 2025-11-23 12:58:49 +01:00
klemek 01266e7823 feat(video): can build without video 2025-11-23 00:45:54 +01:00
klemek d9074c366e fix(args): vi for video-in 2025-11-23 00:27:05 +01:00
klemek 81c7471226 docs: update todo 2025-11-17 14:07:01 +01:00
klemek 31800e3392 fix: better mix value 2025-11-17 14:06:46 +01:00
klemek 69e34b499c refactor: clearer monitor screen 2025-11-17 14:01:34 +01:00
klemek 8a14ad52bf feat: replace src 4 with circuit 2025-11-17 12:14:00 +01:00
klemek 0fe3b067cb refactor: debug improvements 2025-11-17 12:13:49 +01:00
klemek e1219c316c docs: update tiodo list 2025-11-17 12:13:09 +01:00
klemek 2692bb0f9b refactor: move static function on top of files 2025-11-14 11:52:47 +01:00
klemek d094a6c895 feat: hotkeys in config 2025-11-14 11:49:02 +01:00
klemek 4ddb5241b4 feat: load/save state from number hotkeys 2025-11-14 11:02:21 +01:00
klemek f04fe1f5c1 refactor: staticify state local functions 2025-11-14 10:34:43 +01:00
klemek f0c5ecab16 feat: arrow keys to control bpm/cycle 2025-11-14 10:20:55 +01:00
klemek 7739ac8254 refactor: state read event struct 2025-11-14 09:37:29 +01:00
klemek c229b9bc68 feat: --auto-random-cycle 2025-11-14 09:03:23 +01:00
klemek 2ab0947550 fix: don't black out screen in demo 2025-11-13 19:32:48 +01:00
klemek 116ccb0e84 docs: update schema 2025-11-13 09:06:20 +01:00
klemek ce156e4acf docs: add shields.io badges 2025-11-13 00:14:27 +01:00
81 changed files with 3422 additions and 1836 deletions
+4
View File
@@ -0,0 +1,4 @@
# yaml-language-server: $schema=https://json.schemastore.org/clang-format-21.x.json
---
BasedOnStyle: LLVM
IndentWidth: 2
+19
View File
@@ -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
+74
View File
@@ -0,0 +1,74 @@
name: Clang Build CI
concurrency:
group: build-${{ github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:
push:
paths:
- '.github/workflows/build.yml'
- 'src/*.c'
- 'src/*.h'
- 'configure.ac'
- 'Makefile.am'
env:
GCC_ARGS: src/*.c src/*.h -lglfw -lGL -lm -lasound -Wno-format-truncation -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_NATIVE_INCLUDE_NONE
GCC_ARGS_VIDEO: -DGLFW_EXPOSE_NATIVE_EGL -DVIDEO_IN
PACKAGES: "libglfw3-dev libgl-dev libasound2-dev"
PACKAGES_VIDEO: "libv4l-dev"
TARGET: forge
TEST_ARGS: "--help"
jobs:
build-release:
runs-on: ubuntu-latest
steps:
- name: Install packages
run: apt update && apt install -y $PACKAGES $PACKAGES_VIDEO
- name: Checkout repository
uses: actions/checkout@v5
with:
submodules: 'true'
- name: aclocal
run: aclocal
- name: autoconf
run: autoconf
- name: automake
run: automake --add-missing
- name: configure
run: ./configure
- name: make
run: make
- name: make distcheck
run: make distcheck
run-no-video:
runs-on: ubuntu-latest
steps:
- name: Install packages
run: apt update && apt install -y $PACKAGES
- name: Checkout repository
uses: actions/checkout@v5
with:
submodules: 'true'
- name: gcc
run: mkdir -p build && gcc $GCC_ARGS -o build/$TARGET
- name: run program
run: ./build/$TARGET $TEST_ARGS
run-video:
runs-on: ubuntu-latest
steps:
- name: Install packages
run: apt update && apt install -y $PACKAGES $PACKAGES_VIDEO
- name: Checkout repository
uses: actions/checkout@v5
with:
submodules: 'true'
- name: gcc
run: mkdir -p build && gcc $GCC_ARGS $GCC_ARGS_VIDEO -o build/$TARGET
- name: run program
run: ./build/$TARGET $TEST_ARGS
-41
View File
@@ -1,41 +0,0 @@
name: C-lang CI
on:
push:
branches: ["master"]
pull_request:
branches: ["master"]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: 'true'
- name: install libs
run: sudo apt install -y libglfw3-dev libgl-dev libv4l-dev libasound2-dev libbsd-dev
- 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
build-release:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: 'true'
- name: install libs
run: sudo apt install -y libglfw3-dev libgl-dev libv4l-dev libasound2-dev libbsd-dev
- name: aclocal
run: aclocal
- name: autoconf
run: autoconf
- name: automake
run: automake --add-missing
- name: configure
run: ./configure
- name: make
run: make
- name: make distcheck
run: make distcheck
+44
View File
@@ -0,0 +1,44 @@
name: Clang Lint CI
concurrency:
group: lint-${{ github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:
push:
paths:
- '.github/workflows/lint.yml'
- 'src/*.c'
- 'src/*.h'
env:
GCC_ARGS: src/*.c src/*.h -lglfw -lGL -lm -lasound -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_NATIVE_INCLUDE_NONE
GCC_ARGS_VIDEO: -DGLFW_EXPOSE_NATIVE_EGL -DVIDEO_IN
PACKAGES: "libglfw3-dev libgl-dev libasound2-dev"
PACKAGES_VIDEO: "libv4l-dev"
jobs:
lint-no-video:
runs-on: ubuntu-latest
steps:
- name: Install packages
run: apt update && apt install -y $PACKAGES
- name: Checkout repository
uses: actions/checkout@v5
with:
submodules: 'true'
- name: gcc
run: gcc -Wall -Wextra -Werror -Wno-format-truncation -Wno-unused-parameter $GCC_ARGS
lint-video:
runs-on: ubuntu-latest
steps:
- name: Install packages
run: apt update && apt install -y $PACKAGES $PACKAGES_VIDEO
- name: Checkout repository
uses: actions/checkout@v5
with:
submodules: 'true'
- name: gcc
run: gcc -Wall -Wextra -Werror -Wno-format-truncation $GCC_ARGS $GCC_ARGS_VIDEO
+4 -2
View File
@@ -24,6 +24,8 @@ pkg
forge-*
confdeps.*
conftest.*
forge_saved_state.txt
*.txt
error.glsl
draft/
draft/
*.gch
*.out
+15
View File
@@ -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=
+18 -7
View File
@@ -8,7 +8,7 @@ build build project into build/forge
run run project with test args
demo run project with demo mode
valgrind valgrind analysis
clean-release remove autoconf/automake files
full-clean remove build files and untracked files
test-release try to build release
release-% make full release of version %
release-arch make arch-linux release package
@@ -20,7 +20,7 @@ release-arch make arch-linux release package
# make full build
make -f Makefile.dev release-1.0.0
# push release
git push origin master --tags
git push origin main --tags
# create release from tag on github
# attach .tar.gz to the github release
make -f Makefile.dev release-arch
@@ -117,12 +117,23 @@ make -f Makefile.dev release-arch
- [x] Printable PDF of default scr/fx
- [x] Add NanoKontrol setup file
- [x] Find and fix opengl errors 0500 ?
- [ ] Improvements
- [ ] Extra features
- [x] `--auto-random-cycle=4`
- [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
- [ ] Update README monitor/keymap
- [x] Auto reconnect midi input
- [x] Auto reconnect video device
- [x] Key codes as inputs
- [ ] Mouse position and scroll as inputs
- [ ] Joystick as input
- [ ] Record show as text files
- [ ] Play from record text file
- [ ] Key codes as inputs
- [ ] Mouse position and scroll as inputs
- [ ] Fixes
- [ ] Try to write NanoKontrol config
- [ ] Investigate video device fps loss (bad unregister ?)
- explore libv4l directly [github](https://github.com/philips/libv4l) (with `-lv4l2`)
- [x] Investigate video device fps loss (bad unregister ?)
+6 -6
View File
@@ -1,10 +1,10 @@
AUTOMAKE_OPTIONS = foreign subdir-objects -Wall
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_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_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
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/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 -DVIDEO_IN -DDATADIR=\"$(datadir)/$(PACKAGE)\"
forge_LDADD = -lm -lGL -lglfw -lasound
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/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)
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
+45 -40
View File
@@ -1,72 +1,78 @@
TARGET ?= forge
INSTALL_DIR ?= $(HOME)/.local/bin
TEST_ARGS ?= --video-in=/dev/video0 --video-in=/dev/video1 --video-in=/dev/video2 --video-in=/dev/video3 --video-in=/dev/video4 --video-in=/dev/video5 --video-in=/dev/video6 --video-in=/dev/video7 --video-in=/dev/video8 --video-in=/dev/video9
RUN_ARGS ?= --help
SHELL := /bin/bash
.PHONY: build
clean:
@rm -rf build
build:
build/$(TARGET):
@mkdir -p build
gcc \
src/*.h src/*.c \
-Iinclude \
hashmap.c/hashmap.c \
log.c/src/log.c \
-lm -lGL -lglfw -lasound -lbsd \
-lm -lGL -lglfw -lasound \
-Wall -Wextra \
-Wno-format-truncation \
-DGLFW_INCLUDE_NONE \
-DGLFW_EXPOSE_NATIVE_EGL \
-DGLFW_NATIVE_INCLUDE_NONE \
-DLOG_USE_COLOR \
-DVIDEO_IN \
-o build/$(TARGET) \
-g -Og
.PHONY: run
run: build
./build/$(TARGET) $(TEST_ARGS) --monitor-only --internal-size=480 --video-size=240 --hot-reload
.PHONY: build
build: build/$(TARGET)
.PHONY: demo
demo: build
./build/$(TARGET) $(TEST_ARGS) --demo
.PHONY: build-no-video
build-no-video:
@mkdir -p build
gcc \
src/*.h src/*.c \
-Iinclude \
hashmap.c/hashmap.c \
log.c/src/log.c \
-lm -lGL -lglfw -lasound \
-Wall -Wextra \
-Wno-format-truncation \
-Wno-unused-parameter \
-DGLFW_INCLUDE_NONE \
-DGLFW_NATIVE_INCLUDE_NONE \
-DLOG_USE_COLOR \
-o build/$(TARGET) \
-g -Og
.PHONY: format
format:
clang-format -i src/*
.PHONY: run
run: build/$(TARGET)
./build/$(TARGET) $(RUN_ARGS)
.PHONY: sample
sample: build
./build/$(TARGET) --project=sample
sample: build/$(TARGET)
./build/$(TARGET) --project=sample $(RUN_ARGS)
.PHONY: valgrind
valgrind: build
valgrind: build/$(TARGET)
valgrind \
--show-realloc-size-zero=no \
--undef-value-errors=no \
./build/$(TARGET) $(TEST_ARGS)
./build/$(TARGET) $(RUN_ARGS)
.PHONY: clean-release
clean-release:
@rm -rf \
autom4te.cache \
aclocal.m4 \
compile \
config.* \
configure \
configure~ \
depcomp \
**/.deps \
**/**/.deps \
$(TARGET) \
$(TARGET)-*.tar.gz \
$(TARGET)-*.pkg.tar.zst \
install-sh \
Makefile \
Makefile.in \
missing \
src/.* \
src/*.o
.PHONY: full-clean
full-clean:
git clean -f -x
rm -rf */*/.deps
rm -rf */.deps
.PHONY: test-release
test-release: clean clean-release
test-release: clean full-clean
aclocal
autoconf
automake --add-missing
@@ -76,8 +82,8 @@ test-release: clean clean-release
cp $(TARGET)-steel-*.tar.gz build/
.PHONY: release-%
release-%: clean clean-release
git pull origin master
release-%: clean full-clean
git pull origin main
sed -i -E "s/[0-9]+\\.[0-9]+\\.[0-9]+/$*/g" configure.ac
aclocal
autoconf
@@ -90,8 +96,8 @@ release-%: clean clean-release
sha256sum build/forge-steel-$*.tar.gz | cut -d' ' -f1 | xargs -I{} sed -i -E "s/sha256sums=\\('.*'\\)/sha256sums=\\('{}'\\)/g" PKGBUILD
git add configure.ac PKGBUILD
git commit -am "forge (steel) v$*"
git tag v$* -m "forge (steel) v$*"
@echo "Push release: git push origin master --tags"
git tag v$* -m "FORGE steel-$*"
@echo "Push release: git push origin main --tags"
@echo "Rollback release: git reset HEAD~1 --hard && git tag -d v$*"
@@ -100,4 +106,3 @@ release-arch: clean
mkdir -p build
cp PKGBUILD build
cd build && makepkg
+4 -4
View File
@@ -1,12 +1,12 @@
pkgname=forge-steel
pkgver=1.0.1
pkgver=1.1.2
pkgrel=1
pkgdesc="Fusion Of Real Time Generative Effects"
arch=('i686' 'pentium4' 'x86_64' 'arm' 'armv7h' 'armv6h' 'aarch64' 'riscv64')
depends=('glfw>=1:3', 'v4l-utils>=1.32', 'alsa-lib>=1.2', 'libglvnd>=1.7')
url="https://github.com/klemek/forge-steel"
source=("${pkgname}-steel-${pkgver}.tar.gz::https://github.com/klemek/forge-steel/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
sha256sums=('b2345c1a87f6b5b13dcce6a237a3f9a9ddb7fa9c3e982f5e164e7d7fef5725f3')
url="https://git.klemek.fr/klemek/forge-steel"
source=("${pkgname}-steel-${pkgver}.tar.gz::https://git.klemek.fr/klemek/forge-steel/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
sha256sums=('cf4b280fba47d649ab33596d43872a70dd443ed6d15dc587b9dac4e5db294e06')
srcdir=build
backup=("usr/share/${pkgname}")
+89 -51
View File
@@ -1,5 +1,4 @@
[![CI](https://github.com/klemek/forge-steel/actions/workflows/ci.yml/badge.svg)](https://github.com/klemek/forge-steel/actions/workflows/ci.yml)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=klemek_forge-steel&metric=alert_status&token=b68ccdc07773027cc51403bc5712d9364d64febf)](https://sonarcloud.io/summary/new_code?id=klemek_forge-steel)
[![](https://git.klemek.fr/klemek/forge-steel/actions/workflows/lint.yml/badge.svg?branch=main&style=flat-square)](https://git.klemek.fr/klemek/forge-steel/actions?workflow=lint.yml) [![](https://git.klemek.fr/klemek/forge-steel/actions/workflows/build.yml/badge.svg?branch=main&style=flat-square)](https://git.klemek.fr/klemek/forge-steel/actions?workflow=build.yml) ![LOC](https://img.shields.io/badge/cloc-3.4k-blue?style=flat-square)
<!-- omit from toc -->
# 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)
- [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)
- [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)
## What is FORGE ?
@@ -116,11 +116,10 @@ Here's a quick rundown of the process:
| libGL | libgl-dev | extra/libglvnd |
| libasound | libasound2-dev | extra/alsa-lib |
| libv4l2 | libv4l-dev | extra/v4l-utils |
| libbsd | libbsd-dev | extra/libbsd |
### From release
See [Releases](https://github.com/klemek/forge-steel/releases)
See [Releases](https://git.klemek.fr/klemek/forge-steel/releases)
```shell
tar xvzf forge-steel-x.y.z.tar.gz
@@ -133,7 +132,7 @@ make install
### From repository (PKGBUILD)
```shell
git clone --recursive https://github.com/klemek/forge-steel
git clone --recursive https://git.klemek.fr/klemek/forge-steel
cd forge
makepkg -si
```
@@ -142,7 +141,7 @@ makepkg -si
### From repository (dev version)
```shell
git clone --recursive https://github.com/klemek/forge-steel
git clone --recursive https://git.klemek.fr/klemek/forge-steel
cd forge
aclocal
autoconf
@@ -158,43 +157,58 @@ make install
When running, the following hotkeys are available:
* <kbd>Esc</kbd>: Exit window
* <kbd>R</kbd>: Randomize internal values
* <kbd>0</kbd>: Reset internal values to 0
* <kbd>D</kbd>: Demo mode On/Off
* <kbd>A</kbd>: Auto Random mode On/Off
| Hotkey | Function |
| ------ | -------- |
| <kbd>Esc</kbd> | Exit FORGE |
| <kbd>R</kbd> | Randomize internal values |
| <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>&larr;</kbd> / <kbd>&rarr;</kbd> | Auto Random Cycle -/+ 1 |
| <kbd>&uarr;</kbd> / <kbd>&darr;</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
```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-VERSION
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] [-vb=COUNT] [-vr / -nvr] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-mr / -nmr] [-tm] [-tf]
Fusion Of Real-time Generative Effects.
options:
-h, --help show this help message and exit
-v, --version print version
-p, --project forge project directory (default: /usr/share/forge/default)
-c, --config config file name (default: forge_project.cfg)
-hr, --hot-reload hot reload of shaders scripts
-s, --screen output screen number (default: primary)
-m, --monitor monitor screen number (default: none)
-mo, --monitor-only no output screen
-w, --windowed not fullscreen
-t, --tempo base tempo (default: 60)
-d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random)
-ar, --auto-random randomize state every 4 beats
-nar, --no-auto-random do not randomize state (default)
-v, --video-in path to video capture device (multiple allowed)
-vs, --video-size video capture desired height (default: internal texture height)
-is, --internal-size internal texture height (default: 720)
-sf, --state-file saved state file (default: forge_saved_state.txt)
-ls, --load-state load saved state (default)
-nls, --no-load-state do not load saved state
-ss, --save-state save state (default)
-nss, --no-save-state do not save state
-tm, --trace-midi print midi code and values
-tf, --trace-fps print fps status of subsystems
-h, --help show this help message and exit
-v, --version print version
-p, --project forge project directory (default: ./default)
-c, --config config file name (default: forge_project.cfg)
-hr, --hot-reload hot reload of shaders scripts
-s, --screen output screen number (default: primary)
-m, --monitor monitor screen number (default: none)
-mo, --monitor-only no output screen
-w, --windowed not fullscreen
-t, --tempo base tempo (default: 60)
-d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random)
-ar, --auto-random randomize state every cycle (4 beats)
-nar, --no-auto-random do not randomize state (default)
-arc, --auto-random-cycle auto random cycle length (default: 4)
-vi, --video-in path to video capture device (multiple allowed)
-vb, --video-buffers number of video buffers to use (default: 2)
-vs, --video-size video capture desired height (default: internal texture height)
-vr, --video-reconnect auto-reconnect video (default)
-nvr, --no-video-reconnect do not auto-reconnect video
-is, --internal-size internal texture height (default: 720)
-ls, --load-state load saved state (default)
-nls, --no-load-state do not load saved state
-ss, --save-state save state (default)
-nss, --no-save-state do not save state
-mr, --midi-reconnect auto-reconnect midi (default)
-nmr, --no-midi-reconnect do not auto-reconnect midi
-tm, --trace-midi print midi code and values
-tf, --trace-fps print fps status of subsystems
```
## Default Project
@@ -233,7 +247,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** | 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_ |
| | **3** | Waves | _Spacing_ | _Thickness_ | _Vert. Scroll (R)_ | Colorize | _Black Color_ | _White Color_ | _Shift_ |
| | **3** | Bacteria | _Zoom_ | _Details_ | _Delta details_ | Colorize | _Black Color_ | _White Color_ | _Shift_ |
| | **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_ |
| | **6** | CP437 | _Zoom_ | _Charset_ | _Char. Delta_ | TV | _Lens_ | _Horz. Noise_ | _Dezoom_ |
@@ -269,16 +283,28 @@ We will not dig down all the variables here but feel free to read either:
* [sample/forge_project.cfg](./sample/forge_project.cfg) (beginner oriented)
* [default/forge_project.cfg](./default/forge_project.cfg) (more complete)
#### Midi groups
#### Input codes
FORGE allows you to send the midi data in the form of groups.
Each input code can be either a midi event or a key code.
* 0 - 999 -> midi event
* Keyboard modifiers are encoded like this:
* 1000 -> keyboard event
* 10000 -> shift
* 100000 -> control
* 1000000 -> alt
* (This means 111082 is control+alt+R)
#### Input groups
FORGE allows you to send the midi/keyboard data in the form of groups.
Each group has the following properties:
* A number of layers with `MIDI_X_ACTIVE_COUNT` (default: `1`)
* Each midi code controlling how to change the active layer with `MIDI_X_ACTIVE_Y`
* A number of codes with `MIDI_X_COUNT`
* Each midi code controlling the active layer with `MIDI_X_Y` (as a `vec3`: `_X` / `_Y` / `_Z`)
* A number of layers with `GROUP_X_ACTIVE_COUNT` (default: `1`)
* Each midi/keyboard code controlling how to change the active layer with `GROUP_X_ACTIVE_Y`
* A number of codes with `GROUP_X_COUNT`
* Each midi/keyboard code controlling the active layer with `GROUP_X_Y` (as a `vec3`: `_X` / `_Y` / `_Z`)
#### States
@@ -286,9 +312,9 @@ FORGE allows to define a "state" to a fragment shader.
This combines several parameters:
* `SELECT_PAGE_COUNT` (default: `1`) + `SELECT_PAGE_X`: define midi codes for pages of item.
* `SELECT_ITEM_COUNT` + `SELECT_ITEM_X`: define midi codes for items per page.
* `SELECT_FRAG_X`: define midi codes to "select" a fragment shader.
* `SELECT_PAGE_COUNT` (default: `1`) + `SELECT_PAGE_X`: define midi/keyboard codes for pages of item.
* `SELECT_ITEM_COUNT` + `SELECT_ITEM_X`: define midi/keyboard codes for items per page.
* `SELECT_FRAG_X`: define midi/keyboard codes to "select" a fragment shader.
The selected fragment shader will have its state updated with either:
@@ -329,8 +355,8 @@ uniform float iTime; // the current time
uniform sampler2D iTex0; // texture 1 (0-based)
uniform sampler2D iTex9; // texture 10
uniform int iSeed1;
uniform vec3 iMidi2_3[7]; // midi group 2, layer 3, size 7
uniform vec3 iMidi3_1[2];
uniform vec3 iGroup2_3[7]; // midi group 2, layer 3, size 7
uniform vec3 iGroup3_1[2];
```
#### Working with `#include`
@@ -446,11 +472,11 @@ FORGE (steel) describe the linux version.
Verify you have the correct [requirements](#requirements) installed.
Then if you continue to have problems, you can [open an issue](https://github.com/klemek/forge-steel/issues).
Then if you continue to have problems, you can [open an issue](https://git.klemek.fr/klemek/forge-steel/issues).
### I didn't understand everything about your tutorial
Please [open an issue](https://github.com/klemek/forge-steel/issues) describing what your having trouble with,
Please [open an issue](https://git.klemek.fr/klemek/forge-steel/issues) describing what your having trouble with,
I'll try to answer and update the README.
### My nanoKontrol2 is acting strange
@@ -461,16 +487,28 @@ Use the [KORG KONTROL Editor](https://www.korg.com/us/support/download/software/
### How do I report a bug?
You're free to open a new issue in the [Issues page](https://github.com/klemek/forge-steel/issues).
You're free to open a new issue in the [Issues page](https://git.klemek.fr/klemek/forge-steel/issues).
Don't forget to add all information available to your bug (version, operating system, etc.).
### 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?
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.
### 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/).
+4 -1
View File
@@ -1,4 +1,7 @@
-Iinclude
-DGLFW_INCLUDE_NONE
-DGLFW_EXPOSE_NATIVE_EGL
-DGLFW_NATIVE_INCLUDE_NONE
-DGLFW_NATIVE_INCLUDE_NONE
-DVIDEO_IN
-DEGL_DEBUG
-DGL_DEBUG
+3 -5
View File
@@ -1,4 +1,4 @@
AC_INIT([forge], [steel-1.0.1], [klemek.dev@proton.me])
AC_INIT([forge], [steel-1.1.2], [klemek.dev@proton.me])
AM_INIT_AUTOMAKE
AC_PROG_CC
@@ -11,7 +11,6 @@ AC_CHECK_HEADERS([stdlib.h])
AC_CHECK_HEADERS([sys/ioctl.h])
AC_CHECK_HEADERS([sys/mman.h])
AC_CHECK_HEADERS([sys/stat.h])
AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_HEADERS([sys/types.h])
AC_CHECK_HEADERS([sys/wait.h])
@@ -22,8 +21,7 @@ AC_CHECK_HEADERS([math.h])
AC_CHECK_HEADERS([string.h])
AC_CHECK_HEADERS([time.h])
AC_CHECK_HEADERS([unistd.h])
AC_CHECK_HEADERS([bsd/string.h])
AC_CHECK_HEADERS([pthread.h])
AC_CHECK_HEADERS([linux/videodev2.h])
@@ -33,4 +31,4 @@ AC_CHECK_HEADERS([GLFW/glfw3.h])
AC_CHECK_HEADERS([GLFW/glfw3native.h])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
AC_OUTPUT
+135 -68
View File
@@ -6,7 +6,7 @@
# (shaders, video devices, textures, midi inputs, etc.)
# Every number based constant will be "one-based" (1,2,3,etc.)
# To read more, go to
# https://github.com/klemek/forge-steel
# https://git.klemek.fr/klemek/forge-steel
# ================
@@ -24,7 +24,7 @@
UNIFORM_TIME=iTime
# Current tempo
UNIFORM_TEMPO=iTempo
# Current total beats
# Current total beats
UNIFORM_BEATS=iBeats
# --- uniform int ---
@@ -37,6 +37,8 @@ UNIFORM_IN_FPS_PREFIX=iInputFPS
UNIFORM_DEMO=iDemo
# 0/1 if auto random
UNIFORM_AUTORAND=iAutoRand
# auto random cycle length
UNIFORM_AUTORANDCYCLE=iAutoRandCycle
# Current page
UNIFORM_PAGE=iPage
# Current selected shader
@@ -62,8 +64,8 @@ UNIFORM_IN_RESOLUTION_PREFIX=iInputResolution
# --- uniform vec3 ---
# Midi group X layer Y (beware of group size)
# Injected as "iMidiX_Y[Z]"
UNIFORM_MIDI_PREFIX=iMidi
# Injected as "iGroupX_Y[Z]"
UNIFORM_GROUP_PREFIX=iGroup
# --- uniform sampler2D ---
@@ -91,7 +93,7 @@ SUB_2_PREFIX=fx_
# Total number of internal textures
TEX_COUNT=10
TEX_COUNT=12
# === VIDEO DEVICES
# Video devices will be read from CLI arguments
@@ -105,7 +107,6 @@ IN_2_OUT=2
# === FRAGMENT SHADERS
# 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
FRAG_FILE_PREFIX=frag
@@ -128,10 +129,17 @@ FRAG_OUTPUT=9
FRAG_MONITOR=10
# ========
# MIDI I/O
# ========
# ==========
# I/O Inputs
# ==========
# Each code either maps to a midi event or a key code
# 0 - 999 -> midi event
# Keyboard modifiers are encoded like this:
# 1000 -> keyboard event
# 10000 -> shift
# 100000 -> control
# 1000000 -> alt
# This means 111082 is control+alt+R
# The recognized ALSA name of the midi device
MIDI_HW=hw:CARD=nanoKONTROL2
@@ -187,8 +195,8 @@ SELECT_ITEM_3=42
SELECT_ITEM_4=41
SELECT_ITEM_5=45
# === MIDI INPUT STATES
# Midi inputs will control FORGE's state as follows
# === GROUP INPUT STATES
# Inputs will control FORGE's state as follows
# X groups of Y layers sized Z
# You can manipulate only 1 layer at a time
# Every layer of every groups will be send as uniforms
@@ -196,69 +204,128 @@ SELECT_ITEM_5=45
# with the same codes for nice display
# Total number of groups
MIDI_COUNT=3
GROUP_COUNT=3
# Total number of layers of group 1
MIDI_1_ACTIVE_COUNT=2
GROUP_1_ACTIVE_COUNT=2
# Midi codes to change layer of group 1
MIDI_1_ACTIVE_1=32
MIDI_1_ACTIVE_2=64
GROUP_1_ACTIVE_1=32
GROUP_1_ACTIVE_2=64
# Size of group 1
MIDI_1_COUNT=6
GROUP_1_COUNT=6
# Every code of active layer manipulation of group 1
MIDI_1_1_X=33
MIDI_1_1_Y=49
MIDI_1_1_Z=65
MIDI_1_2_X=1
MIDI_1_2_Y=17
MIDI_1_2_Z=
MIDI_1_3_X=34
MIDI_1_3_Y=50
MIDI_1_3_Z=66
MIDI_1_4_X=2
MIDI_1_4_Y=18
MIDI_1_4_Z=
MIDI_1_5_X=35
MIDI_1_5_Y=51
MIDI_1_5_Z=67
MIDI_1_6_X=3
MIDI_1_6_Y=19
MIDI_1_6_Z=
GROUP_1_1_X=33
GROUP_1_1_Y=49
GROUP_1_1_Z=65
GROUP_1_2_X=1
GROUP_1_2_Y=17
GROUP_1_2_Z=
GROUP_1_3_X=34
GROUP_1_3_Y=50
GROUP_1_3_Z=66
GROUP_1_4_X=2
GROUP_1_4_Y=18
GROUP_1_4_Z=
GROUP_1_5_X=35
GROUP_1_5_Y=51
GROUP_1_5_Z=67
GROUP_1_6_X=3
GROUP_1_6_Y=19
GROUP_1_6_Z=
# Same for group 2
MIDI_2_ACTIVE_COUNT=3
MIDI_2_ACTIVE_1=36
MIDI_2_ACTIVE_2=68
MIDI_2_ACTIVE_3=52
MIDI_2_COUNT=7
MIDI_2_1_X=37
MIDI_2_1_Y=53
MIDI_2_1_Z=69
MIDI_2_2_X=5
MIDI_2_2_Y=21
MIDI_2_2_Z=
MIDI_2_3_X=38
MIDI_2_3_Y=54
MIDI_2_3_Z=70
MIDI_2_4_X=6
MIDI_2_4_Y=22
MIDI_2_4_Z=
MIDI_2_5_X=39
MIDI_2_5_Y=55
MIDI_2_5_Z=71
MIDI_2_6_X=7
MIDI_2_6_Y=23
MIDI_2_6_Z=
MIDI_2_7_X=4
MIDI_2_7_Y=20
MIDI_2_7_Z=59
GROUP_2_ACTIVE_COUNT=3
GROUP_2_ACTIVE_1=36
GROUP_2_ACTIVE_2=68
GROUP_2_ACTIVE_3=52
GROUP_2_COUNT=7
GROUP_2_1_X=37
GROUP_2_1_Y=53
GROUP_2_1_Z=69
GROUP_2_2_X=5
GROUP_2_2_Y=21
GROUP_2_2_Z=
GROUP_2_3_X=38
GROUP_2_3_Y=54
GROUP_2_3_Z=70
GROUP_2_4_X=6
GROUP_2_4_Y=22
GROUP_2_4_Z=
GROUP_2_5_X=39
GROUP_2_5_Y=55
GROUP_2_5_Z=71
GROUP_2_6_X=7
GROUP_2_6_Y=23
GROUP_2_6_Z=
GROUP_2_7_X=4
GROUP_2_7_Y=20
GROUP_2_7_Z=59
# Same for group 3
MIDI_3_COUNT=2
MIDI_3_1_X=48
MIDI_3_1_Y=58
MIDI_3_1_Z=
MIDI_3_2_X=0
MIDI_3_2_Y=16
MIDI_3_2_Z=
GROUP_3_COUNT=2
GROUP_3_1_X=48
GROUP_3_1_Y=58
GROUP_3_1_Z=
GROUP_3_2_X=0
GROUP_3_2_Y=16
GROUP_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
# R on (qwerty)
KEY_RANDOMIZE=1082
# SHIFT+R (qwerty)
KEY_RESET=11082
# D (qwerty)
KEY_DEMO=1068
# A (qwerty)
KEY_AUTORAND=1065
# Left arrow
KEY_AUTORAND_DOWN=1263
# Right arrow
KEY_AUTORAND_UP=1262
# Down arrow
KEY_TEMPO_DOWN=1264
# Up arrow
KEY_TEMPO_UP=1265
# Number of load states keys
KEY_LOAD_COUNT=10
# 1 to 9 then 0 keys
KEY_LOAD_1=1049
KEY_LOAD_2=1050
KEY_LOAD_3=1051
KEY_LOAD_4=1052
KEY_LOAD_5=1053
KEY_LOAD_6=1054
KEY_LOAD_7=1055
KEY_LOAD_8=1056
KEY_LOAD_9=1057
KEY_LOAD_10=1048
# Number of save states keys
KEY_SAVE_COUNT=10
# 1 to 9 then 0 keys with shift
KEY_SAVE_1=11049
KEY_SAVE_2=11050
KEY_SAVE_3=11051
KEY_SAVE_4=11052
KEY_SAVE_5=11053
KEY_SAVE_6=11054
KEY_SAVE_7=11055
KEY_SAVE_8=11056
KEY_SAVE_9=11057
KEY_SAVE_10=11048
+3 -2
View File
@@ -8,10 +8,11 @@
in vec2 vUV;
out vec4 fragColor;
#include inc_yuv.glsl
#include inc_yuyv.glsl
uniform sampler2D iTex0;
uniform sampler2D iTex1;
uniform sampler2D iTex3;
uniform int iInputFormat1;
uniform vec2 iInputResolution1;
@@ -21,4 +22,4 @@ void main() {
} else {
fragColor = texture(iTex0, vUV);
}
}
}
+165 -59
View File
@@ -9,8 +9,6 @@ out vec4 fragColor;
#include inc_debug.glsl
uniform sampler2D iTex0;
uniform sampler2D iTex1;
uniform sampler2D iTex2;
uniform sampler2D iTex3;
uniform sampler2D iTex4;
uniform sampler2D iTex5;
@@ -18,26 +16,101 @@ uniform sampler2D iTex6;
uniform sampler2D iTex7;
uniform sampler2D iTex8;
uniform sampler2D iTex9;
uniform int iFPS;
uniform int iInputFPS1;
uniform int iInputFPS2;
float s(vec2 uv, float x0, float y0) {
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] = {
{0x49, 0x4E, 0x20, 0x41, 0x00}, // IN A
{0x49, 0x4E, 0x20, 0x42, 0x00}, // IN B
{0x53, 0x52, 0x43, 0x20, 0x41}, // SRC A
{0x53, 0x52, 0x43, 0x20, 0x42}, // SRC B
{0x46, 0x58, 0x20, 0x41, 0x00}, // FX A
{0x46, 0x58, 0x20, 0x42, 0x00}, // FX B
{0x41, 0x2B, 0x42, 0x00, 0x00}, // A+B
{0x4D, 0x46, 0x58, 0x00, 0x00}, // MFX
{0x46, 0x50, 0x53, 0x00, 0x00}, // FPS
{0x4F, 0x46, 0x46, 0x00, 0x00}, // OFF
};
const int texts[12][5] = {
{
0x49,
0x4E,
0x20,
0x41,
0x00
}, // IN A
{
0x49,
0x4E,
0x20,
0x42,
0x00
}, // IN B
{
0x53,
0x52,
0x43,
0x20,
0x41
}, // SRC A
{
0x53,
0x52,
0x43,
0x20,
0x42
}, // SRC B
{
0x46,
0x58,
0x20,
0x41,
0x00
}, // FX A
{
0x46,
0x58,
0x20,
0x42,
0x00
}, // FX B
{
0x41,
0x2B,
0x42,
0x00,
0x00
}, // A+B
{
0x4D,
0x46,
0x58,
0x00,
0x00
}, // MFX
{
0x46,
0x50,
0x53,
0x00,
0x00
}, // FPS
{
0x4F,
0x46,
0x46,
0x00,
0x00
}, // OFF
{
0x44,
0x45,
0x4D,
0x4F,
0x00
}, // DEMO
{
0x4C,
0x49,
0x56,
0x45,
0x00
}, // LIVE
};
void main() {
vec2 uv0 = vUV.st;
@@ -48,57 +121,90 @@ void main() {
vec2 uv3 = uv1 * 60;
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,2,1) * texture(iTex8, uv2);
c += s(uv2, 1, 2) * texture(iTex5, uv2);
c += s(uv2, 2, 2) * texture(iTex7, uv2);
c += s(uv2,0,0) * debug(mod(uv2, 1));
c += s(uv2,1,0) * texture(iTex9, uv2);
c += s(uv2,2,0) * texture(iTex0, uv2);
c += s(uv2, 1, 0) * texture(iTex6, uv2);
c += s(uv2, 2, 0) * texture(iTex8, uv2);
c += s(uv2, 0, 1) * debug(mod(uv2, 1));
c += s(uv2, 1, 1) * texture(iTex9, 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 t = 0;
f += rect(uv3, vec2(-51, 28.5), vec2(2.1, 0.7));
t += write_5(uv3, vec2(-53,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]);
f += rect(uv3, vec2(-35, 28.5), vec2(2.1, 0.7));
t += write_5(uv3, vec2(-37, 28), texts[0]);
if (iInputResolution2.x > 0) {
c += s(uv2,0,1) * texture(iTex4, uv2);
f += rect(uv3, vec2(-50.4, 6.5), vec2(2.8, 0.7));
t += write_int(uv3, vec2(-53,6), iInputFPS2, 2);
t += write_5(uv3, vec2(-50.5,6), texts[8]);
if (iInputFormat1 == YUYV_FOURCC) {
c += s(uv2, 0, 2) * texture(iTex3, uv2);
f += rect(uv3, vec2(-35, 26.75), vec2(2.8, 0.7));
t += write_int(uv3, vec2(-37.6, 26.1), iInputFPS1, 2);
t += write_5(uv3, vec2(-35.1, 26.1), texts[8]);
} else {
f += rect(uv3, vec2(-51.5, 6.5), vec2(1.6, 0.7));
t += write_5(uv3, vec2(-53,6), texts[9]);
f += rect(uv3, vec2(-35, 26.75), vec2(1.6, 0.7));
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(iTex4, 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));
}
+3 -2
View File
@@ -8,10 +8,11 @@
in vec2 vUV;
out vec4 fragColor;
#include inc_yuv.glsl
#include inc_yuyv.glsl
uniform sampler2D iTex0;
uniform sampler2D iTex2;
uniform sampler2D iTex4;
uniform int iInputFormat2;
uniform vec2 iInputResolution2;
@@ -21,4 +22,4 @@ void main() {
} else {
fragColor = texture(iTex0, vUV);
}
}
}
+3 -3
View File
@@ -13,8 +13,8 @@ out vec4 fragColor;
subroutine uniform src_stage_sub src_stage;
uniform int iSeed3;
uniform vec3 iMidi1_1[6];
uniform vec3 iGroup1_1[6];
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, iGroup1_1[0], iGroup1_1[1].xy, iGroup1_1[2], iGroup1_1[3].xy, iGroup1_1[4], iGroup1_1[5].xy);
}
+3 -3
View File
@@ -12,8 +12,8 @@ out vec4 fragColor;
subroutine uniform src_stage_sub src_stage;
uniform int iSeed4;
uniform vec3 iMidi1_2[6];
uniform vec3 iGroup1_2[6];
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, iGroup1_2[0], iGroup1_2[1].xy, iGroup1_2[2], iGroup1_2[3].xy, iGroup1_2[4], iGroup1_2[5].xy);
}
+3 -3
View File
@@ -14,8 +14,8 @@ out vec4 fragColor;
uniform sampler2D iTex5;
uniform sampler2D iTex7;
uniform int iSeed5;
uniform vec3 iMidi2_1[7];
uniform vec3 iGroup2_1[7];
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, iTex5, iTex7, iSeed5, iGroup2_1[0], iGroup2_1[1].xy, iGroup2_1[2], iGroup2_1[3].xy, iGroup2_1[4], iGroup2_1[5].xy, iGroup2_1[6]);
}
+3 -3
View File
@@ -14,8 +14,8 @@ out vec4 fragColor;
uniform sampler2D iTex6;
uniform sampler2D iTex8;
uniform int iSeed6;
uniform vec3 iMidi2_2[7];
uniform vec3 iGroup2_2[7];
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, iTex6, iTex8, iSeed6, iGroup2_2[0], iGroup2_2[1].xy, iGroup2_2[2], iGroup2_2[3].xy, iGroup2_2[4], iGroup2_2[5].xy, iGroup2_2[6]);
}
+9 -5
View File
@@ -16,11 +16,11 @@ uniform int iDemo;
uniform sampler2D iTex7;
uniform sampler2D iTex8;
uniform int iSeed7;
uniform vec3 iMidi3_1[2];
uniform vec3 iGroup3_1[2];
void main() {
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);
float mix_value = magic(iGroup3_1[1].xy, vec3(1, 0, 0), iSeed7);
bool mix_type = magic_trigger(vec3(iGroup3_1[0].x, 0, 0), iSeed7 + 10);
vec4 color_a = texture(iTex7, vUV);
vec4 color_b = texture(iTex8, vUV);
@@ -29,5 +29,9 @@ void main() {
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
View File
@@ -14,13 +14,17 @@ out vec4 fragColor;
uniform sampler2D iTex9;
uniform sampler2D iTex0;
uniform int iSeed8;
uniform vec3 iMidi2_3[7];
uniform vec3 iMidi3_1[2];
uniform vec3 iGroup2_3[7];
uniform vec3 iGroup3_1[2];
uniform int iDemo;
uniform int iAutoRand;
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, iTex9, iTex0, iSeed8, iGroup2_3[0], iGroup2_3[1].xy, iGroup2_3[2], iGroup2_3[3].xy, iGroup2_3[4], iGroup2_3[5].xy, iGroup2_3[6]);
color = mix(color, vec4(0), iMidi3_1[0].y);
if (iDemo < 1 && iAutoRand < 1) {
color = mix(color, vec4(0), iGroup3_1[0].y);
}
fragColor = color;
}
}
+1 -1
View File
@@ -10,4 +10,4 @@ uniform sampler2D iTex0;
void main() {
fragColor = texture(iTex0, vUV);
}
}
+19 -5
View File
@@ -94,7 +94,7 @@ const int cp437[] = {
0xE333, 0x1333, 0x0ECC, 0x0100, // 0x59, Y
0x813F, 0x1367, 0x0F6C, 0x0764, // 0x5A, Z
0x666E, 0x0001, 0x0E66, 0x0100, // 0x5B, [
0x8C63, 0x1000, 0x0000, 0x0463, // 0x5C,
0x8C63, 0x1000, 0x0000, 0x0463, // 0x5C,
0x888E, 0x1111, 0x0E88, 0x0111, // 0x5D, ]
0x36C8, 0x6310, 0x0000, 0x0000, // 0x5E, ^
0x0000, 0x0000, 0xF000, 0xF000, // 0x5F, _
@@ -372,13 +372,27 @@ float write_int(vec2 uv, vec2 pos, uint value, uint magnitude)
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)
{
float inv_k = 1 / k;
vec2 tex_uv = floor(uv * k) * inv_k;
tex_uv += vec2(d % 2, floor(d * 0.5)) * 0.5 * inv_k;
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, 1) * inv_k * 0.125)) > t) ? 4 : 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
int bit_count(int u)
int bit_count(int u)
{
int c;
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 b2 = read(tex, uv, k, 2, t);
int b3 = read(tex, uv, k, 3, t);
int mc = 0;
int mb = 100;
int i;
@@ -430,4 +444,4 @@ int guess_char(sampler2D tex, vec2 uv, float k, float t)
return mc;
}
#endif
#endif
+137 -76
View File
@@ -1,13 +1,11 @@
#include inc_magic.glsl
#include inc_functions.glsl
#include inc_yuv.glsl
#include inc_yuyv.glsl
#include inc_cp437.glsl
#ifndef INC_DEBUG
#define INC_DEBUG
uniform int iFPS;
uniform vec2 iInputResolution1;
uniform vec2 iInputResolution2;
uniform int iInputFormat1;
@@ -15,6 +13,7 @@ uniform int iInputFormat2;
uniform int iDemo;
uniform int iAutoRand;
uniform int iAutoRandCycle;
uniform int iPage;
uniform int iSelected;
@@ -36,17 +35,16 @@ uniform int iState8;
uniform int iActive1;
uniform int iActive2;
uniform vec3 iMidi2_1[7];
uniform vec3 iMidi2_2[7];
uniform vec3 iMidi2_3[7];
uniform vec3 iMidi3_1[2];
uniform vec3 iGroup2_1[7];
uniform vec3 iGroup2_2[7];
uniform vec3 iGroup2_3[7];
uniform vec3 iGroup3_1[2];
vec4 debug(vec2 vUV)
{
// start
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -93,30 +91,90 @@ vec4 debug(vec2 vUV)
if (random_mfx) {
selected_mfx = int(randTime(iSeed8 + 100) * 14);
}
float fxa_value = magic(iMidi2_1[6].xy, vec3(1, 0, 0), iSeed5);
bool fxa_invert = magic_trigger(vec3(iMidi2_1[6].z, 0, 0), iSeed5);
float fxb_value = magic(iMidi2_2[6].xy, vec3(1, 0, 0), iSeed6);
bool fxb_invert = magic_trigger(vec3(iMidi2_2[6].z, 0, 0), iSeed6);
float mfx_value = magic(iMidi2_3[6].xy, vec3(1, 0, 0), iSeed8);
bool mfx_invert = magic_trigger(vec3(iMidi2_3[6].z, 0, 0), iSeed8);
float mix_value = magic(iMidi3_1[1].xy, vec3(1, 0, 0), iSeed7);
float fxa_value = magic(iGroup2_1[6].xy, vec3(1, 0, 0), iSeed5);
bool fxa_invert = magic_trigger(vec3(iGroup2_1[6].z, 0, 0), iSeed5);
float fxb_value = magic(iGroup2_2[6].xy, vec3(1, 0, 0), iSeed6);
bool fxb_invert = magic_trigger(vec3(iGroup2_2[6].z, 0, 0), iSeed6);
float mfx_value = magic(iGroup2_3[6].xy, vec3(1, 0, 0), iSeed8);
bool mfx_invert = magic_trigger(vec3(iGroup2_3[6].z, 0, 0), iSeed8);
float mix_value = magic(iGroup3_1[1].xy, vec3(1, 0, 0), iSeed7);
mix_value = mix(mix_value, mix_value * 0.9 + 0.05, iDemo);
bool mix_type = magic_trigger(vec3(iMidi3_1[0].x, 0, 0), iSeed7 + 10);
bool mix_type = magic_trigger(vec3(iGroup3_1[0].x, 0, 0), iSeed7 + 10);
// logic
const int texts[10][5] = {
{0x46, 0x50, 0x53, 0x00, 0x00}, // FPS
{0x54, 0x45, 0x4D, 0x50, 0x4F}, // TEMPO
{0x54, 0x49, 0x4D, 0x45, 0x00}, // TIME
{0x44, 0x45, 0x4D, 0x4F, 0x00}, // DEMO
{0x4C, 0x49, 0x56, 0x45, 0x00}, // LIVE
{0x2B, 0x52, 0x41, 0x4E, 0x44}, // +RAND
{0x53, 0x52, 0x43, 0x00, 0x00}, // SRC
{0x46, 0x58, 0x00, 0x00, 0x00}, // FX
{0x49, 0x4E, 0x00, 0x00, 0x00}, // IN
{0x4D, 0x46, 0x58, 0x00, 0x00}, // MFX
};
{
0x46,
0x50,
0x53,
0x00,
0x00
}, // FPS
{
0x54,
0x45,
0x4D,
0x50,
0x4F
}, // TEMPO
{
0x54,
0x49,
0x4D,
0x45,
0x00
}, // TIME
{
0x44,
0x45,
0x4D,
0x4F,
0x00
}, // DEMO
{
0x4C,
0x49,
0x56,
0x45,
0x00
}, // LIVE
{
0x52,
0x41,
0x4E,
0x44,
0x00
}, // RAND
{
0x53,
0x52,
0x43,
0x00,
0x00
}, // SRC
{
0x46,
0x58,
0x00,
0x00,
0x00
}, // FX
{
0x49,
0x4E,
0x00,
0x00,
0x00
}, // IN
{
0x4D,
0x46,
0x58,
0x00,
0x00
}, // MFX
};
vec2 uv2 = uv1;
@@ -127,22 +185,30 @@ vec4 debug(vec2 vUV)
vec2 uv3 = uv1 * 30;
// base frame
float f =
float f =
h_rect(uv2, vec2(-5, -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)) +
h_rect(uv2, vec2(-5, 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)) +
h_rect(uv2, vec2(2, 0), vec2(1), 0.1) +
h_rect(uv2, vec2(5, 0), vec2(1), 0.1) +
rect(uv2, vec2(3.5, 0), vec2(0.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(0.55, 2), vec2(1.5, 0.1)) +
rect(uv2, vec2(2, 1.55), vec2(0.1, 0.55)) +
rect(uv2, vec2(7.5, 0), vec2(1.5, 0.1)) +
h_rect(uv2, vec2(-9, -3.9), 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)) +
h_rect(uv2, vec2(-5, 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)) +
h_rect(uv2, vec2(2, 0), vec2(1), 0.1) +
h_rect(uv2, vec2(5, 0), vec2(1), 0.1) +
rect(uv2, vec2(3.5, 0), vec2(0.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(0.55, 2), vec2(1.5, 0.1)) +
rect(uv2, vec2(2, 1.55), vec2(0.1, 0.55)) +
rect(uv2, vec2(6.8, 0), vec2(0.75, 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
f += char_at(uv2, vec2(-5.4, 1.45), hex_chars[selected_srca]);
@@ -175,19 +241,19 @@ vec4 debug(vec2 vUV)
// show src/fx
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 += char_at(uv3 * 0.5, vec2(0.5, 0.5), 0x41);
f += char_at(uv3 * 0.5, vec2(0.5, -3), 0x42);
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 += char_at(uv3 * 0.5, vec2(-11.5, 3.5), 0x41);
f += char_at(uv3 * 0.5, vec2(-11.5, -6), 0x42);
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
float line_a_a = rect(uv2, vec2(-8, 2), vec2(2, 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_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_a = rect(uv2, vec2(-7.5, 2), vec2(1.5, 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, 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) {
f += line_a_a;
} else if (selected_srca == 10 && iInputFormat2 == YUYV_FOURCC) {
@@ -195,9 +261,10 @@ vec4 debug(vec2 vUV)
} else if (selected_srca % 5 == 0) {
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_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_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_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) {
f += line_b_a;
} else if (selected_srcb == 10 && iInputFormat2 == YUYV_FOURCC) {
@@ -207,7 +274,9 @@ vec4 debug(vec2 vUV)
}
// 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
float fx_rect = 0;
@@ -225,34 +294,26 @@ vec4 debug(vec2 vUV)
float x = 0;
x = -15;
f += write_5(uv3, vec2(x,13), texts[0]);
f += write_int(uv3, vec2(x - 3.5,13), iFPS, 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);
f += write_5(uv3, vec2(x - 4.5, 13), texts[1]);
f += write_int(uv3, vec2(x + 1.5, 13), int(iTempo), 3);
v = fract(iBeats);
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 = 15;
f += write_5(uv3, vec2(x,13), texts[2]);
f += write_int(uv3, vec2(x - 5.5,13), int(iTime), 5);
v = fract(iTime);
if (iAutoRand > 0) {
f += write_5(uv3, vec2(x - 4.5, 13), texts[5]);
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 += 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);
}
#endif
#endif
+66 -54
View File
@@ -2,6 +2,8 @@
#define PI 3.1415927
#endif
#include inc_time.glsl
#include inc_rand.glsl
#include inc_res.glsl
#ifndef INC_FUNCTIONS
@@ -22,48 +24,48 @@ float iestep(float x, float y) {
}
float ease(float x) {
return 0.5 - cos(max(min(x, 1.0), 0.0)*PI) * 0.5;
return 0.5 - cos(max(min(x, 1.0), 0.0) * PI) * 0.5;
}
vec2 ease(vec2 x) {
return 0.5 - cos(max(min(x, 1.0), 0.0)*PI) * 0.5;
return 0.5 - cos(max(min(x, 1.0), 0.0) * PI) * 0.5;
}
vec3 ease(vec3 x) {
return 0.5 - cos(max(min(x, 1.0), 0.0)*PI) * 0.5;
return 0.5 - cos(max(min(x, 1.0), 0.0) * PI) * 0.5;
}
float saw(float x){
return abs(mod(x+1,2)-1);
float saw(float x) {
return abs(mod(x + 1, 2) - 1);
}
vec2 saw(vec2 x){
return abs(mod(x+1,2)-1);
vec2 saw(vec2 x) {
return abs(mod(x + 1, 2) - 1);
}
vec3 saw(vec3 x){
return abs(mod(x+1,2)-1);
vec3 saw(vec3 x) {
return abs(mod(x + 1, 2) - 1);
}
float cmod(float x, float k){
float cmod(float x, float k) {
return mod(x + k * 0.5, k) - k * 0.5;
}
vec2 cmod(vec2 x, float k){
vec2 cmod(vec2 x, float k) {
return mod(x + k * 0.5, k) - k * 0.5;
}
vec3 cmod(vec3 x, float k){
vec3 cmod(vec3 x, float k) {
return mod(x + k * 0.5, k) - k * 0.5;
}
// COLORS
vec3 col(float x){
vec3 col(float x) {
return vec3(
.5*(sin(x*2.*PI)+1.),
.5*(sin(x*2.*PI+2.*PI/3.)+1.),
.5*(sin(x*2.*PI-2.*PI/3.)+1.)
.5 * (sin(x * 2. * PI) + 1.),
.5 * (sin(x * 2. * PI + 2. * PI / 3.) + 1.),
.5 * (sin(x * 2. * PI - 2. * PI / 3.) + 1.)
);
}
@@ -81,8 +83,7 @@ vec3 shift3(vec3 c, float f) {
vec3 mix3(vec3 c1, vec3 c2, vec3 c3, float x) {
return istep(0.5, x) * mix(c1, c2, x * 2)
+ step(0.5, x) * mix(c2, c3, x * 2 - 1)
;
+ step(0.5, x) * mix(c2, c3, x * 2 - 1);
}
vec3 mix4(vec3 c1, vec3 c2, vec3 c3, vec3 c4, float x) {
@@ -96,8 +97,7 @@ vec3 mix5(vec3 c1, vec3 c2, vec3 c3, vec3 c4, vec3 c5, float x) {
return istep(0.25, x) * mix(c1, c2, x * 4)
+ step(0.25, x) * istep(0.5, x) * mix(c2, c3, x * 4 - 1)
+ step(0.5, x) * istep(0.75, x) * mix(c3, c4, x * 4 - 2)
+ step(0.75, x) * mix(c4, c5, x * 4 - 3)
;
+ step(0.75, x) * mix(c4, c5, x * 4 - 3);
}
vec3 mix6(vec3 c1, vec3 c2, vec3 c3, vec3 c4, vec3 c5, vec3 c6, float x) {
@@ -105,8 +105,7 @@ vec3 mix6(vec3 c1, vec3 c2, vec3 c3, vec3 c4, vec3 c5, vec3 c6, float x) {
+ step(0.2, x) * istep(0.4, x) * mix(c2, c3, x * 5 - 1)
+ step(0.4, x) * istep(0.6, x) * mix(c3, c4, x * 5 - 2)
+ step(0.6, x) * istep(0.8, x) * mix(c4, c5, x * 5 - 3)
+ step(0.8, x) * mix(c5, c6, x * 5 - 4)
;
+ step(0.8, x) * mix(c5, c6, x * 5 - 4);
}
float mean(vec3 v)
@@ -121,10 +120,10 @@ float mean(vec4 v)
// OTHER
mat2 rot(float angle){
mat2 rot(float angle) {
return mat2(
cos(angle*2.*PI),-sin(angle*2.*PI),
sin(angle*2.*PI),cos(angle*2.*PI)
cos(angle * 2. * PI), -sin(angle * 2. * PI),
sin(angle * 2. * PI), cos(angle * 2. * PI)
);
}
@@ -139,18 +138,18 @@ vec2 kal(vec2 uv, float n) {
float q = 3.0 / (2.0 * PI);
t = abs(mod(t + PI / (n), 2 * PI / n) - PI / (n));
return length(uv) * vec2(
cos(t),
sin(t)
);
cos(t),
sin(t)
);
}
vec2 kal2(vec2 uv, float n) {
float t = atan(uv.y, uv.x) + PI * 0.5;
float t2 = abs(mod(t + PI / n, 2 * PI / n) - PI / n);
return length(uv) * vec2(
cos(t2),
sin(t2)
);
cos(t2),
sin(t2)
);
}
// NOISE
@@ -180,23 +179,23 @@ float v_index(vec2 uv) {
return floor(uv.x) + floor(uv.y) * 45;
}
vec2 v_pos(float i) {
int iTimeId = int(iBeats);
float iTimeV = iBeats - iTimeId;
vec2 v_pos(float i, int seed, float time) {
int iTimeId = int(time);
float iTimeV = time - iTimeId;
float x0 = rand(i + seed + iTimeId);
float y0 = rand(i + seed + 10 + iTimeId);
float x1 = rand(i + seed + iTimeId + 1);
float y1 = rand(i + seed + 10 + iTimeId + 1);
float x0 = rand(i + 823 + iTimeId);
float y0 = rand(i + 328 + iTimeId);
float x1 = rand(i + 823 + iTimeId + 1);
float y1 = rand(i + 328 + iTimeId + 1);
return vec2(
mix(x0, x1, ease(ease(iTimeV))),
mix(y0, y1, ease(ease(iTimeV)))
);
}
vec4 voronoi(vec2 uv, float dist) {
vec4 voronoi(vec2 uv, float dist, int seed, float time) {
vec4 o = vec4(0, 0, 2, 0);
vec4 t = vec4(0, 0, 2, 0);
float d, i;
@@ -205,7 +204,7 @@ vec4 voronoi(vec2 uv, float dist) {
for (int dy = -1; dy <= 1; dy++) {
uv2 = vec2(floor(uv.x) + dx, floor(uv.y) + dy);
i = v_index(uv2);
p = uv2 + v_pos(i) * dist;
p = uv2 + v_pos(i, seed, time) * dist;
d = length(p - uv);
if (d < o.z) {
t = o;
@@ -224,6 +223,10 @@ float circle(vec2 uv, vec2 c, float size) {
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)
{
return k2 > k1 ? (1 - step(x, k1)) * (step(x, k2)) : ((1 - step(x, k2)) * (step(x, k1)));
@@ -251,23 +254,23 @@ float line(vec2 uv, vec2 p1, vec2 p2, float thick) {
vec2 p = p2 - p1;
uv -= p1;
vec2 k;
if (abs(p.y) > abs(p.x)) {
k = vec2(
uv.x - p.x * uv.y / p.y,
uv.y / p.y
);
uv.x - p.x * uv.y / p.y,
uv.y / p.y
);
return step(k.x, thick * 0.5)
* step(-k.x, thick * 0.5)
* step(k.y, 1)
* (1 - step(k.y, 0));
} else {
k = vec2(
uv.x / p.x,
uv.y - p.y * uv.x / p.x
);
uv.x / p.x,
uv.y - p.y * uv.x / p.x
);
return step(k.y, thick * 0.5)
* step(-k.y, thick * 0.5)
* step(k.x, 1)
@@ -275,7 +278,16 @@ float line(vec2 uv, vec2 p1, vec2 p2, float thick) {
}
}
const mat2x2 ISOMETRIC_MATRIX = {{0.5, 1}, {0.5, -1}};
const mat2x2 ISOMETRIC_MATRIX = {
{
0.5,
1
},
{
0.5,
-1
}
};
vec2 iso(vec2 p) {
return p * ISOMETRIC_MATRIX;
@@ -296,14 +308,14 @@ vec2 iso(vec3 uv) {
vec4 reframe(sampler2D tex, vec2 uv)
{
uv = uv * vec2(iResolution.y / iResolution.x, 1) + .5;
uv = uv * vec2(iResolution.y / iResolution.x, 1) + .5;
uv = saw(uv);
return texture(tex, uv);
}
vec4 reframe_b(sampler2D tex, vec2 uv)
{
uv = uv * vec2(iResolution.y / iResolution.x, 1) + .5;
uv = uv * vec2(iResolution.y / iResolution.x, 1) + .5;
return texture(tex, uv);
}
+14 -14
View File
@@ -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);
// logic
vec3 c0 = texture(src0, uv0).xyz;
vec2 uv2 = uv1;
uv2 = mix(uv2 * (1 + zoom * 2), uv2 * (zoom), step(0.5, zoom));
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
vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1;
float pixel = (1 - pixel_size) * 250 + 25;
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);
// logic
vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1;
float k1 = lens_v * 0.5;
uv2 *= 1 + zoom * 2;
@@ -235,9 +235,9 @@ subroutine(fx_stage_sub) vec4 fx_8(vec2 vUV, sampler2D previous, sampler2D feedb
// logic
vec3 c0 = texture(previous, uv0).xyz;
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.x = (saw(uv2.x / ratio + 0.5 + h_scroll * 2) - 0.5) * ratio;
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);
vec3 charset_ctrl = magic_b(b2, seed + 20);
float char_delta = magic(f3, b3, seed + 30);
float t = magic(seed + 40);
float t = magic(seed + 40);
// logic
vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1;
float k1 = 100 * (1 - zoom) + 10;
float inv_k = 1 / k1;
@@ -306,7 +306,7 @@ subroutine(fx_stage_sub) vec4 fx_10(vec2 vUV, sampler2D previous, sampler2D feed
// logic
vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1;
uv2 *= 1 + zoom * 2;
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);
// logic
vec3 c0 = texture(previous, uv0).xyz;
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);
// logic
vec3 c0 = texture(previous, uv0).xyz;
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)
alive = n >= 6 || !alive && n == 4 || alive && (n == 3 || n == 5);
}
vec3 cout = vec3(alive ? 1 : 0);
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
+1 -1
View File
@@ -74,4 +74,4 @@ float magic_reverse(float i)
return magic_reverse(vec2(0), vec3(0, 0, 1), i);
}
#endif
#endif
+1 -1
View File
@@ -11,4 +11,4 @@ float rand(vec2 n){
return rand(n.x * 1234 + n.y * 9876);
}
#endif
#endif
+1 -1
View File
@@ -4,4 +4,4 @@
uniform vec2 iResolution;
uniform vec2 iTexResolution;
#endif
#endif
+1 -1
View File
@@ -26,4 +26,4 @@ const int sentences[SENTENCE_COUNT][20] = {
const int lengths[SENTENCE_COUNT] = {
5, 5, 10, 6, 2, 9, 10, 7, 18, 14, 4, 9, 10, 1, 6, 11, 11
};
#endif
#endif
+193 -76
View File
@@ -8,8 +8,8 @@
uniform int iDemo;
uniform sampler2D iTex0;
uniform sampler2D iTex3;
uniform sampler2D iTex4;
uniform sampler2D iTex5;
uniform sampler2D iTex6;
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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
// controls
@@ -36,21 +36,21 @@ vec4 src_thru(vec2 vUV, sampler2D tex, int seed, vec3 b1, vec2 f1, vec3 b2, vec2
// output
return vec4(c, 1.);
return vec4(c, 1.);
}
// 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);
}
// 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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
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;
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);
return vec4(f);
}
// 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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -97,59 +97,176 @@ subroutine(src_stage_sub) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
float k = zoom * 0.1 + 0.05;
uv2 = cmod(uv2, k * 2);
float f = istep(k / (1 + length(uv1) * 2), length(uv2));
return vec4(f);
}
// SRC 4 : waves
subroutine(src_stage_sub) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
// // 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)
// {
// // start
// vec2 uv0 = vUV.st;
// float ratio = iResolution.x / iResolution.y;
// vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
// // controls
// float z = 10 + magic(f1, b1, 123) * 20;
// float h = magic(f2, b2, seed + 20) * 0.8 + 0.1;
// float v = magic_reverse(f3, b3, seed + 30) * 0.8 + 0.1;
// // logic
// uv1 *= z;
// uv1 += iBeats;
// float s0 = rand(floor(mod(uv1, 1000))) * 1000;
// float s1 = rand(floor(mod(uv1 + vec2(0, 1), 1000))) * 1000;
// float s2 = rand(floor(mod(uv1 - vec2(1, 0), 1000))) * 1000;
// bool up = rand(s1 + 1) < h;
// bool left = rand(s2 + 2) < v;
// bool down = rand(s0 + 1) < h;
// bool right = rand(s0 + 2) < v;
// bool up_down = up && down;
// bool left_right = left && right;
// uv1 = mod(uv1, 1.0) - 0.5;
// const float t = 0.1;
// float f = 0;
// int c = 0;
// 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);
// }
// SRC 4 : bacteria
subroutine ( src_stage_sub ) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{
// start
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
// controls
float spacing = magic(f1, b1, seed + 10);
float thickness = magic(f2, b2, seed + 20);
float scroll = magic_reverse(f3, b3, seed + 30);
float zoom = 2 + magic(f1, b1, seed + 10) * 20;
float details = 5 * magic(f2, b2, seed + 20);
float delta = magic(f3, b3, seed + 30);
// logic
vec2 uv2 = uv1;
uv2.y += 0.5;
uv2 *= 2.25;
uv2 = vec2((uv2.x + 1) * 0.5, -uv2.y);
float m1 = spacing * 4.5 + 0.5;
float y = log(-uv2.y) * m1;
y = mod(y + scroll * 5.0 - iBeats / 16, 5.);
float id = floor(y) * 32;
float s = cos(uv2.x * rand(id + 837) * 100 + rand(id + 281) * PI)
+ cos(uv2.x * rand(id + 231) * 100 + rand(id + 526) * PI)
+ cos(uv2.x * rand(id + 746) * 100 + rand(id + 621) * PI)
+ cos(uv2.x * rand(id + 235) * 100 + rand(id + 315) * PI)
+ cos(uv2.x * rand(id + 782) * 100 + rand(id + 314) * PI)
+ cos(uv2.x * rand(id + 241) * 100 + rand(id + 734) * PI)
+ cos(uv2.x * rand(id + 416) * 100 + rand(id + 425) * PI)
+ cos(uv2.x * rand(id + 315) * 100 + rand(id + 525) * PI)
+ cos(uv2.x * rand(id + 423) * 100 + rand(id + 743) * PI)
+ cos(uv2.x * rand(id + 637) * 100 + rand(id + 245) * PI);
s *= 0.1;
float cut = 0.025 + thickness * 0.475;
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));
uv1 *= zoom;
vec4 data = voronoi(uv1, 1, seed + 40, iBeats * 0.25);
float f = ease(data.x) + ease(data.y);
f = saw(f * (1 + data.x * details) - delta * 2.0);
return vec4(f);
}
// 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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -165,33 +282,33 @@ subroutine(src_stage_sub) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
vec2 uv2 = uv1;
uv2 *= zoom * 20 + 3;
uv2.x += iBeats;
vec4 data = voronoi(uv2, voronoi_distort);
vec4 data = voronoi(uv2, voronoi_distort, seed + 50, iBeats);
float f = data.x / (data.x + data.y);
f = sin(f * PI * (details * 20)) * 0.5 + 1;
int nf = int(noise_factor * 6);
f *= mix(1, noise_f(uv2, nf - 1), step(0.0, float(nf)));
return vec4(f);
}
// 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) {
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
// 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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -215,7 +332,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);
uv2 = mod(uv2, 1);
float f = char(uv2, code) ? 1 : 0;
return vec4(f);
}
@@ -223,11 +340,11 @@ subroutine(src_stage_sub) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
#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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -247,16 +364,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.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]);
return vec4(f);
}
// 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;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -287,11 +404,11 @@ subroutine(src_stage_sub) vec4 src_9(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
}
// 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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -319,7 +436,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 u3 = mod(floor(uv3 + vec2(-1, 0)), umax);
vec2 u4 = mod(floor(uv3 + vec2(0, -1)), umax);
float e0 = (rand(floor(u0)) * 2 - 1) * max_elevation;
float e1 = (rand(floor(u1)) * 2 - 1) * max_elevation;
float e2 = (rand(floor(u2)) * 2 - 1) * max_elevation;
@@ -331,29 +448,29 @@ subroutine(src_stage_sub) vec4 src_10(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
float f = 0;
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(-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(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(0, -1) - iso_z(e4), thick);
return vec4(f);
}
// 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) {
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
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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -392,11 +509,11 @@ subroutine(src_stage_sub) vec4 src_12(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
}
// 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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -411,7 +528,7 @@ subroutine(src_stage_sub) vec4 src_13(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
vec2 uv2 = uv1;
uv2 *= zoom;
uv2 = mod(uv2, 2);
uv2 = abs(uv2 - 1);
@@ -419,16 +536,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));
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);
}
// 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
vec2 uv0 = vUV.st;
vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -462,15 +579,15 @@ subroutine(src_stage_sub) vec4 src_14(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
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));
return vec4(f);
}
// 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);
@@ -505,4 +622,4 @@ subroutine(src_stage_sub) vec4 src_15(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
}
}
#endif
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef INC_TEMPLATE
#define INC_TEMPLATE
#endif
#endif
+1 -1
View File
@@ -50,4 +50,4 @@ float cosTime(float k)
return cos(modTime(k, 0.5) * 2 * PI);
}
#endif
#endif
@@ -1,13 +1,13 @@
#ifndef INC_YUV
#define INC_YUV
#ifndef INC_YUYV
#define INC_YUYV
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) {
float w = base_width - 1;
int x = int(vUV.x * w);
int xU = x - x % 2;
@@ -22,7 +22,7 @@ vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) {
tV.y - 0.5
);
return vec4(yuv_to_rgb * yuv, 1.0);
return vec4(yuyv_to_rgb * yuv, 1.0);
}
#endif
#endif
+54 -50
View File
@@ -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">
<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>
<mxCell id="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" />
</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" />
</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" />
</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" />
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-5" value="TEXTURE&lt;br&gt;1...N" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-5" value="TEXTURES&lt;br&gt;1...N" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="290" y="270" width="120" height="60" as="geometry" />
</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" />
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-7" value="SHADER&lt;br&gt;1...N" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-7" value="FRAGMENT&lt;br&gt;SHADERS&lt;br&gt;1...N" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="294" y="430" width="120" height="60" as="geometry" />
</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">
<mxPoint x="333.5" y="340" as="sourcePoint" />
<mxPoint x="333.5" y="400.5" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-11" value="UNIFORM&lt;br&gt;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&lt;br&gt;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">
<mxPoint x="-40" y="-13" as="offset" />
</mxGeometry>
</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">
<mxPoint x="370" y="400" as="sourcePoint" />
<mxPoint x="370" y="340" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-12" value="RENDERS TO&lt;br&gt;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&lt;br&gt;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">
<mxPoint x="62" y="-1" as="offset" />
</mxGeometry>
</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">
<mxPoint x="140" y="300" as="sourcePoint" />
<mxPoint x="260" y="299.5" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-14" value="DMA&lt;div&gt;BUFFERS&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3Uv0AfHo8SbA6Qcxonjd-13">
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-14" value="DMA&lt;div&gt;BUFFERS&lt;/div&gt;" 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">
<mxPoint x="-10" y="-19" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-15" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="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&lt;br&gt;SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-19" value="OUTPUT&lt;br&gt;SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="530" y="270" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-23" value="MONITOR&lt;br&gt;SHADER" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;" vertex="1" parent="1">
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-23" value="MONITOR&lt;br&gt;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" />
</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">
<mxPoint x="420" y="320" as="sourcePoint" />
<mxPoint x="520" y="360" as="targetPoint" />
</mxGeometry>
</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">
<mxPoint x="420" y="290" as="sourcePoint" />
<mxPoint x="520" y="290" as="targetPoint" />
</mxGeometry>
</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">
<mxPoint x="349.5" y="585" as="sourcePoint" />
<mxPoint x="349.5" y="495" as="targetPoint" />
<mxPoint x="350" y="500" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-27" value="COMPILES&lt;br&gt;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&lt;br&gt;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">
<mxPoint x="-55" y="-15" as="offset" />
</mxGeometry>
</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" />
</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" />
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-30" value="GLSL FILE&lt;br&gt;1...N" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-30" value="GLSL FILES&lt;br&gt;1...N" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="294" y="610" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-31" value="MIDI INPUT" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="10" y="420" width="120" height="60" as="geometry" />
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-31" value="MIDI&lt;br&gt;INPUT" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="460" y="610" width="120" height="60" as="geometry" />
</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" />
</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" />
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-38" value="VIDEO DEVICE&lt;br&gt;1...N" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-38" value="VIDEO DEVICE&lt;br&gt;1...N" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="10" y="270" width="120" height="60" as="geometry" />
</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">
<mxPoint x="660" y="299.5" as="sourcePoint" />
<mxPoint x="760" y="299.5" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-40" value="OUTPUT&lt;br&gt;WINDOW" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-40" value="OUTPUT&lt;br&gt;WINDOW" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="770" y="270" width="120" height="60" as="geometry" />
</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">
<mxPoint x="660" y="389.5" as="sourcePoint" />
<mxPoint x="760" y="389.5" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-42" value="MONITOR&lt;br&gt;WINDOW" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;" vertex="1" parent="1">
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-42" value="MONITOR&lt;br&gt;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" />
</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" />
</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">
<mxPoint x="510" y="490" as="sourcePoint" />
<mxPoint x="430" y="450" as="targetPoint" />
</mxGeometry>
</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">
<mxPoint x="25" y="-18" as="offset" />
</mxGeometry>
</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" />
</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">
<mxPoint x="660" y="490" as="sourcePoint" />
<mxPoint x="760" y="490" as="targetPoint" />
</mxGeometry>
</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&lt;br&gt;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>
</mxGraphModel>
</diagram>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.
+40 -6
View File
@@ -1,11 +1,11 @@
/**
* Loader generated by glad 2.0.8 on Sun Sep 21 11:51:45 2025
* Loader generated by glad 2.0.8 on Wed May 13 21:51:29 2026
*
* SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
*
* Generator: C/C++
* Specification: egl
* Extensions: 10
* Extensions: 11
*
* APIs:
* - egl=1.5
@@ -19,10 +19,10 @@
* - ON_DEMAND = False
*
* Commandline:
* --api='egl=1.5' --extensions='EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_KHR_gl_texture_2D_image,EGL_KHR_image,EGL_KHR_image_base,EGL_KHR_platform_android,EGL_KHR_platform_gbm,EGL_KHR_platform_wayland,EGL_KHR_platform_x11,EGL_MESA_drm_image' c --header-only --loader
* --api='egl=1.5' --extensions='EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_KHR_debug,EGL_KHR_gl_texture_2D_image,EGL_KHR_image,EGL_KHR_image_base,EGL_KHR_platform_android,EGL_KHR_platform_gbm,EGL_KHR_platform_wayland,EGL_KHR_platform_x11,EGL_MESA_drm_image' c --header-only --loader
*
* Online:
* http://glad.sh/#api=egl%3D1.5&extensions=EGL_EXT_image_dma_buf_import%2CEGL_EXT_image_dma_buf_import_modifiers%2CEGL_KHR_gl_texture_2D_image%2CEGL_KHR_image%2CEGL_KHR_image_base%2CEGL_KHR_platform_android%2CEGL_KHR_platform_gbm%2CEGL_KHR_platform_wayland%2CEGL_KHR_platform_x11%2CEGL_MESA_drm_image&generator=c&options=HEADER_ONLY%2CLOADER
* http://glad.sh/#api=egl%3D1.5&extensions=EGL_EXT_image_dma_buf_import%2CEGL_EXT_image_dma_buf_import_modifiers%2CEGL_KHR_debug%2CEGL_KHR_gl_texture_2D_image%2CEGL_KHR_image%2CEGL_KHR_image_base%2CEGL_KHR_platform_android%2CEGL_KHR_platform_gbm%2CEGL_KHR_platform_wayland%2CEGL_KHR_platform_x11%2CEGL_MESA_drm_image&generator=c&options=HEADER_ONLY%2CLOADER
*
*/
@@ -201,6 +201,11 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
#define EGL_CORE_NATIVE_ENGINE 0x305B
#define EGL_DEBUG_CALLBACK_KHR 0x33B8
#define EGL_DEBUG_MSG_CRITICAL_KHR 0x33B9
#define EGL_DEBUG_MSG_ERROR_KHR 0x33BA
#define EGL_DEBUG_MSG_INFO_KHR 0x33BC
#define EGL_DEBUG_MSG_WARN_KHR 0x33BB
#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)
#define EGL_DEPTH_SIZE 0x3025
#define EGL_DISPLAY_SCALING 10000
@@ -295,6 +300,13 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)
#define EGL_NO_SYNC EGL_CAST(EGLSync,0)
#define EGL_NO_TEXTURE 0x305C
#define EGL_OBJECT_CONTEXT_KHR 0x33B2
#define EGL_OBJECT_DISPLAY_KHR 0x33B1
#define EGL_OBJECT_IMAGE_KHR 0x33B4
#define EGL_OBJECT_STREAM_KHR 0x33B6
#define EGL_OBJECT_SURFACE_KHR 0x33B3
#define EGL_OBJECT_SYNC_KHR 0x33B5
#define EGL_OBJECT_THREAD_KHR 0x33B0
#define EGL_OPENGL_API 0x30A2
#define EGL_OPENGL_BIT 0x0008
#define EGL_OPENGL_ES2_BIT 0x0004
@@ -934,6 +946,8 @@ GLAD_API_CALL int GLAD_EGL_VERSION_1_5;
GLAD_API_CALL int GLAD_EGL_EXT_image_dma_buf_import;
#define EGL_EXT_image_dma_buf_import_modifiers 1
GLAD_API_CALL int GLAD_EGL_EXT_image_dma_buf_import_modifiers;
#define EGL_KHR_debug 1
GLAD_API_CALL int GLAD_EGL_KHR_debug;
#define EGL_KHR_gl_texture_2D_image 1
GLAD_API_CALL int GLAD_EGL_KHR_gl_texture_2D_image;
#define EGL_KHR_image 1
@@ -968,6 +982,7 @@ typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC)(EGLDisp
typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLAttrib * attrib_list);
typedef EGLSync (GLAD_API_PTR *PFNEGLCREATESYNCPROC)(EGLDisplay dpy, EGLenum type, const EGLAttrib * attrib_list);
typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint * attrib_list);
typedef EGLint (GLAD_API_PTR *PFNEGLDEBUGMESSAGECONTROLKHRPROC)(EGLDEBUGPROCKHR callback, const EGLAttrib * attrib_list);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEPROC)(EGLDisplay dpy, EGLImage image);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEKHRPROC)(EGLDisplay dpy, EGLImageKHR image);
@@ -985,9 +1000,11 @@ typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform
typedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char * procname);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETSYNCATTRIBPROC)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib * value);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint * major, EGLint * minor);
typedef EGLint (GLAD_API_PTR *PFNEGLLABELOBJECTKHRPROC)(EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
typedef EGLenum (GLAD_API_PTR *PFNEGLQUERYAPIPROC)(void);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint * value);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYDEBUGKHRPROC)(EGLint attribute, EGLAttrib * value);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYDMABUFFORMATSEXTPROC)(EGLDisplay dpy, EGLint max_formats, EGLint * formats, EGLint * num_formats);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYDMABUFMODIFIERSEXTPROC)(EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR * modifiers, EGLBoolean * external_only, EGLint * num_modifiers);
typedef const char * (GLAD_API_PTR *PFNEGLQUERYSTRINGPROC)(EGLDisplay dpy, EGLint name);
@@ -1035,6 +1052,8 @@ GLAD_API_CALL PFNEGLCREATESYNCPROC glad_eglCreateSync;
#define eglCreateSync glad_eglCreateSync
GLAD_API_CALL PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface;
#define eglCreateWindowSurface glad_eglCreateWindowSurface
GLAD_API_CALL PFNEGLDEBUGMESSAGECONTROLKHRPROC glad_eglDebugMessageControlKHR;
#define eglDebugMessageControlKHR glad_eglDebugMessageControlKHR
GLAD_API_CALL PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext;
#define eglDestroyContext glad_eglDestroyContext
GLAD_API_CALL PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage;
@@ -1069,12 +1088,16 @@ GLAD_API_CALL PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib;
#define eglGetSyncAttrib glad_eglGetSyncAttrib
GLAD_API_CALL PFNEGLINITIALIZEPROC glad_eglInitialize;
#define eglInitialize glad_eglInitialize
GLAD_API_CALL PFNEGLLABELOBJECTKHRPROC glad_eglLabelObjectKHR;
#define eglLabelObjectKHR glad_eglLabelObjectKHR
GLAD_API_CALL PFNEGLMAKECURRENTPROC glad_eglMakeCurrent;
#define eglMakeCurrent glad_eglMakeCurrent
GLAD_API_CALL PFNEGLQUERYAPIPROC glad_eglQueryAPI;
#define eglQueryAPI glad_eglQueryAPI
GLAD_API_CALL PFNEGLQUERYCONTEXTPROC glad_eglQueryContext;
#define eglQueryContext glad_eglQueryContext
GLAD_API_CALL PFNEGLQUERYDEBUGKHRPROC glad_eglQueryDebugKHR;
#define eglQueryDebugKHR glad_eglQueryDebugKHR
GLAD_API_CALL PFNEGLQUERYDMABUFFORMATSEXTPROC glad_eglQueryDmaBufFormatsEXT;
#define eglQueryDmaBufFormatsEXT glad_eglQueryDmaBufFormatsEXT
GLAD_API_CALL PFNEGLQUERYDMABUFMODIFIERSEXTPROC glad_eglQueryDmaBufModifiersEXT;
@@ -1157,6 +1180,7 @@ int GLAD_EGL_VERSION_1_4 = 0;
int GLAD_EGL_VERSION_1_5 = 0;
int GLAD_EGL_EXT_image_dma_buf_import = 0;
int GLAD_EGL_EXT_image_dma_buf_import_modifiers = 0;
int GLAD_EGL_KHR_debug = 0;
int GLAD_EGL_KHR_gl_texture_2D_image = 0;
int GLAD_EGL_KHR_image = 0;
int GLAD_EGL_KHR_image_base = 0;
@@ -1184,6 +1208,7 @@ PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface = NULL
PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface = NULL;
PFNEGLCREATESYNCPROC glad_eglCreateSync = NULL;
PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface = NULL;
PFNEGLDEBUGMESSAGECONTROLKHRPROC glad_eglDebugMessageControlKHR = NULL;
PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext = NULL;
PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage = NULL;
PFNEGLDESTROYIMAGEKHRPROC glad_eglDestroyImageKHR = NULL;
@@ -1201,9 +1226,11 @@ PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay = NULL;
PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress = NULL;
PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib = NULL;
PFNEGLINITIALIZEPROC glad_eglInitialize = NULL;
PFNEGLLABELOBJECTKHRPROC glad_eglLabelObjectKHR = NULL;
PFNEGLMAKECURRENTPROC glad_eglMakeCurrent = NULL;
PFNEGLQUERYAPIPROC glad_eglQueryAPI = NULL;
PFNEGLQUERYCONTEXTPROC glad_eglQueryContext = NULL;
PFNEGLQUERYDEBUGKHRPROC glad_eglQueryDebugKHR = NULL;
PFNEGLQUERYDMABUFFORMATSEXTPROC glad_eglQueryDmaBufFormatsEXT = NULL;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC glad_eglQueryDmaBufModifiersEXT = NULL;
PFNEGLQUERYSTRINGPROC glad_eglQueryString = NULL;
@@ -1284,6 +1311,12 @@ static void glad_egl_load_EGL_EXT_image_dma_buf_import_modifiers( GLADuserptrloa
glad_eglQueryDmaBufFormatsEXT = (PFNEGLQUERYDMABUFFORMATSEXTPROC) load(userptr, "eglQueryDmaBufFormatsEXT");
glad_eglQueryDmaBufModifiersEXT = (PFNEGLQUERYDMABUFMODIFIERSEXTPROC) load(userptr, "eglQueryDmaBufModifiersEXT");
}
static void glad_egl_load_EGL_KHR_debug( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_EGL_KHR_debug) return;
glad_eglDebugMessageControlKHR = (PFNEGLDEBUGMESSAGECONTROLKHRPROC) load(userptr, "eglDebugMessageControlKHR");
glad_eglLabelObjectKHR = (PFNEGLLABELOBJECTKHRPROC) load(userptr, "eglLabelObjectKHR");
glad_eglQueryDebugKHR = (PFNEGLQUERYDEBUGKHRPROC) load(userptr, "eglQueryDebugKHR");
}
static void glad_egl_load_EGL_KHR_image( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_EGL_KHR_image) return;
glad_eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) load(userptr, "eglCreateImageKHR");
@@ -1338,6 +1371,7 @@ static int glad_egl_find_extensions_egl(EGLDisplay display) {
GLAD_EGL_EXT_image_dma_buf_import = glad_egl_has_extension(extensions, "EGL_EXT_image_dma_buf_import");
GLAD_EGL_EXT_image_dma_buf_import_modifiers = glad_egl_has_extension(extensions, "EGL_EXT_image_dma_buf_import_modifiers");
GLAD_EGL_KHR_debug = glad_egl_has_extension(extensions, "EGL_KHR_debug");
GLAD_EGL_KHR_gl_texture_2D_image = glad_egl_has_extension(extensions, "EGL_KHR_gl_texture_2D_image");
GLAD_EGL_KHR_image = glad_egl_has_extension(extensions, "EGL_KHR_image");
GLAD_EGL_KHR_image_base = glad_egl_has_extension(extensions, "EGL_KHR_image_base");
@@ -1409,6 +1443,7 @@ int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void* userp
if (!glad_egl_find_extensions_egl(display)) return 0;
glad_egl_load_EGL_EXT_image_dma_buf_import_modifiers(load, userptr);
glad_egl_load_EGL_KHR_debug(load, userptr);
glad_egl_load_EGL_KHR_image(load, userptr);
glad_egl_load_EGL_KHR_image_base(load, userptr);
glad_egl_load_EGL_MESA_drm_image(load, userptr);
@@ -1421,7 +1456,7 @@ int gladLoadEGL(EGLDisplay display, GLADloadfunc load) {
return gladLoadEGLUserPtr(display, glad_egl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
}
#ifdef GLAD_EGL
@@ -1572,4 +1607,3 @@ void gladLoaderUnloadEGL(void) {
#endif
#endif /* GLAD_EGL_IMPLEMENTATION */
+30 -7
View File
@@ -1,11 +1,11 @@
/**
* Loader generated by glad 2.0.8 on Sun Sep 21 13:34:57 2025
* Loader generated by glad 2.0.8 on Wed May 13 21:57:23 2026
*
* SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
*
* Generator: C/C++
* Specification: gl
* Extensions: 3
* Extensions: 4
*
* APIs:
* - gl:compatibility=4.6
@@ -19,10 +19,10 @@
* - ON_DEMAND = False
*
* Commandline:
* --api='gl:compatibility=4.6' --extensions='GL_ARB_direct_state_access,GL_EXT_EGL_image_storage,GL_EXT_direct_state_access' c --header-only --loader
* --api='gl:compatibility=4.6' --extensions='GL_ARB_direct_state_access,GL_EXT_EGL_image_storage,GL_EXT_direct_state_access,GL_KHR_debug' c --header-only --loader
*
* Online:
* http://glad.sh/#api=gl%3Acompatibility%3D4.6&extensions=GL_ARB_direct_state_access%2CGL_EXT_EGL_image_storage%2CGL_EXT_direct_state_access&generator=c&options=HEADER_ONLY%2CLOADER
* http://glad.sh/#api=gl%3Acompatibility%3D4.6&extensions=GL_ARB_direct_state_access%2CGL_EXT_EGL_image_storage%2CGL_EXT_direct_state_access%2CGL_KHR_debug&generator=c&options=HEADER_ONLY%2CLOADER
*
*/
@@ -2409,6 +2409,8 @@ GLAD_API_CALL int GLAD_GL_ARB_direct_state_access;
GLAD_API_CALL int GLAD_GL_EXT_EGL_image_storage;
#define GL_EXT_direct_state_access 1
GLAD_API_CALL int GLAD_GL_EXT_direct_state_access;
#define GL_KHR_debug 1
GLAD_API_CALL int GLAD_GL_KHR_debug;
typedef void (GLAD_API_PTR *PFNGLACCUMPROC)(GLenum op, GLfloat value);
@@ -6396,6 +6398,7 @@ int GLAD_GL_VERSION_4_6 = 0;
int GLAD_GL_ARB_direct_state_access = 0;
int GLAD_GL_EXT_EGL_image_storage = 0;
int GLAD_GL_EXT_direct_state_access = 0;
int GLAD_GL_KHR_debug = 0;
@@ -9178,6 +9181,20 @@ static void glad_gl_load_GL_EXT_direct_state_access( GLADuserptrloadfunc load, v
glad_glVertexArrayVertexBindingDivisorEXT = (PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) load(userptr, "glVertexArrayVertexBindingDivisorEXT");
glad_glVertexArrayVertexOffsetEXT = (PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) load(userptr, "glVertexArrayVertexOffsetEXT");
}
static void glad_gl_load_GL_KHR_debug( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GL_KHR_debug) return;
glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) load(userptr, "glDebugMessageCallback");
glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC) load(userptr, "glDebugMessageControl");
glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC) load(userptr, "glDebugMessageInsert");
glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC) load(userptr, "glGetDebugMessageLog");
glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC) load(userptr, "glGetObjectLabel");
glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC) load(userptr, "glGetObjectPtrLabel");
glad_glGetPointerv = (PFNGLGETPOINTERVPROC) load(userptr, "glGetPointerv");
glad_glObjectLabel = (PFNGLOBJECTLABELPROC) load(userptr, "glObjectLabel");
glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC) load(userptr, "glObjectPtrLabel");
glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC) load(userptr, "glPopDebugGroup");
glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC) load(userptr, "glPushDebugGroup");
}
@@ -9276,6 +9293,7 @@ static int glad_gl_find_extensions_gl(void) {
GLAD_GL_ARB_direct_state_access = glad_gl_has_extension(exts, exts_i, "GL_ARB_direct_state_access");
GLAD_GL_EXT_EGL_image_storage = glad_gl_has_extension(exts, exts_i, "GL_EXT_EGL_image_storage");
GLAD_GL_EXT_direct_state_access = glad_gl_has_extension(exts, exts_i, "GL_EXT_direct_state_access");
GLAD_GL_KHR_debug = glad_gl_has_extension(exts, exts_i, "GL_KHR_debug");
glad_gl_free_extensions(exts_i);
@@ -9360,6 +9378,7 @@ int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) {
glad_gl_load_GL_ARB_direct_state_access(load, userptr);
glad_gl_load_GL_EXT_EGL_image_storage(load, userptr);
glad_gl_load_GL_EXT_direct_state_access(load, userptr);
glad_gl_load_GL_KHR_debug(load, userptr);
@@ -9373,7 +9392,7 @@ int gladLoadGL( GLADloadfunc load) {
#ifdef GLAD_GL
@@ -9482,7 +9501,9 @@ static void* glad_gl_dlopen_handle(void) {
"libGL-1.so",
#endif
"libGL.so.1",
"libGL.so"
"libGL.so",
"libEGL.so.1",
"libEGL.so"
};
#endif
@@ -9505,6 +9526,9 @@ static struct _glad_gl_userptr glad_gl_build_userptr(void *handle) {
#else
userptr.gl_get_proc_address_ptr =
(GLADglprocaddrfunc) glad_dlsym_handle(handle, "glXGetProcAddressARB");
if (!userptr.gl_get_proc_address_ptr)
userptr.gl_get_proc_address_ptr =
(GLADglprocaddrfunc) glad_dlsym_handle(handle, "eglGetProcAddress");
#endif
return userptr;
@@ -9547,4 +9571,3 @@ void gladLoaderUnloadGL(void) {
#endif
#endif /* GLAD_GL_IMPLEMENTATION */
+79 -73
View File
@@ -6,7 +6,7 @@
# (shaders, video devices, textures, midi inputs, etc.)
# Every number based constant will be "one-based" (1,2,3,etc.)
# To read more, go to
# https://github.com/klemek/forge-steel
# https://git.klemek.fr/klemek/forge-steel
# ================
@@ -24,7 +24,7 @@
UNIFORM_TIME=iTime
# Current tempo
UNIFORM_TEMPO=iTempo
# Current total beats
# Current total beats
UNIFORM_BEATS=iBeats
# --- uniform int ---
@@ -33,8 +33,6 @@ UNIFORM_BEATS=iBeats
UNIFORM_FPS=iFPS
# 0/1 if demo
UNIFORM_DEMO=iDemo
# 0/1 if auto random
UNIFORM_AUTORAND=iAutoRand
# Seed for shader X
UNIFORM_SEED_PREFIX=iSeed
@@ -46,8 +44,8 @@ UNIFORM_RESOLUTION=iResolution
# --- uniform vec3 ---
# Midi group X layer Y (beware of group size)
# Injected as "iMidiX_Y[Z]"
UNIFORM_MIDI_PREFIX=iMidi
# Injected as "iGroupX_Y[Z]"
UNIFORM_GROUP_PREFIX=iGroup
# --- uniform sampler2D ---
@@ -81,9 +79,17 @@ FRAG_OUTPUT=2
FRAG_MONITOR=2
# ========
# MIDI I/O
# ========
# ==========
# I/O Inputs
# ==========
# Each code either maps to a midi event or a key code
# 0 - 999 -> midi event
# Keyboard modifiers are encoded like this:
# 1000 -> keyboard event
# 10000 -> shift
# 100000 -> control
# 1000000 -> alt
# This means 111082 is control+alt+R
# The recognized ALSA name of the midi device
@@ -116,8 +122,8 @@ FADER_16=23
# Midi code for tap tempo
TAP_TEMPO=46
# === MIDI INPUT STATES
# Midi inputs will control FORGE's state as follows
# === GROUP INPUT STATES
# Inputs will control FORGE's state as follows
# X groups of Y layers sized Z
# You can manipulate only 1 layer at a time
# Every layer of every groups will be send as uniforms
@@ -125,68 +131,68 @@ TAP_TEMPO=46
# with the same codes for nice display
# Total number of groups
MIDI_COUNT=1
GROUP_COUNT=1
# Size of group 1
MIDI_1_COUNT=20
GROUP_1_COUNT=20
# Every code of active layer manipulation of group 1
MIDI_1_1_X=32
MIDI_1_1_Y=48
MIDI_1_1_Z=64
MIDI_1_2_X=0
MIDI_1_2_Y=16
MIDI_1_2_Z=
MIDI_1_3_X=33
MIDI_1_3_Y=49
MIDI_1_3_Z=65
MIDI_1_4_X=1
MIDI_1_4_Y=17
MIDI_1_4_Z=
MIDI_1_5_X=34
MIDI_1_5_Y=50
MIDI_1_5_Z=66
MIDI_1_6_X=2
MIDI_1_6_Y=18
MIDI_1_6_Z=
MIDI_1_7_X=35
MIDI_1_7_Y=51
MIDI_1_7_Z=67
MIDI_1_8_X=3
MIDI_1_8_Y=19
MIDI_1_8_Z=
MIDI_1_9_X=36
MIDI_1_9_Y=52
MIDI_1_9_Z=68
MIDI_1_10_X=4
MIDI_1_10_Y=20
MIDI_1_10_Z=
MIDI_1_11_X=37
MIDI_1_11_Y=53
MIDI_1_11_Z=69
MIDI_1_12_X=5
MIDI_1_12_Y=21
MIDI_1_12_Z=
MIDI_1_13_X=38
MIDI_1_13_Y=54
MIDI_1_13_Z=70
MIDI_1_14_X=6
MIDI_1_14_Y=22
MIDI_1_14_Z=
MIDI_1_15_X=39
MIDI_1_15_Y=55
MIDI_1_15_Z=71
MIDI_1_16_X=7
MIDI_1_16_Y=23
MIDI_1_16_Z=
MIDI_1_17_X=58
MIDI_1_17_Y=59
MIDI_1_17_Z=
MIDI_1_18_X=60
MIDI_1_18_Y=61
MIDI_1_18_Z=62
MIDI_1_19_X=43
MIDI_1_19_Y=44
MIDI_1_19_Z=42
MIDI_1_20_X=41
MIDI_1_20_Y=45
MIDI_1_20_Z=
GROUP_1_1_X=32
GROUP_1_1_Y=48
GROUP_1_1_Z=64
GROUP_1_2_X=0
GROUP_1_2_Y=16
GROUP_1_2_Z=
GROUP_1_3_X=33
GROUP_1_3_Y=49
GROUP_1_3_Z=65
GROUP_1_4_X=1
GROUP_1_4_Y=17
GROUP_1_4_Z=
GROUP_1_5_X=34
GROUP_1_5_Y=50
GROUP_1_5_Z=66
GROUP_1_6_X=2
GROUP_1_6_Y=18
GROUP_1_6_Z=
GROUP_1_7_X=35
GROUP_1_7_Y=51
GROUP_1_7_Z=67
GROUP_1_8_X=3
GROUP_1_8_Y=19
GROUP_1_8_Z=
GROUP_1_9_X=36
GROUP_1_9_Y=52
GROUP_1_9_Z=68
GROUP_1_10_X=4
GROUP_1_10_Y=20
GROUP_1_10_Z=
GROUP_1_11_X=37
GROUP_1_11_Y=53
GROUP_1_11_Z=69
GROUP_1_12_X=5
GROUP_1_12_Y=21
GROUP_1_12_Z=
GROUP_1_13_X=38
GROUP_1_13_Y=54
GROUP_1_13_Z=70
GROUP_1_14_X=6
GROUP_1_14_Y=22
GROUP_1_14_Z=
GROUP_1_15_X=39
GROUP_1_15_Y=55
GROUP_1_15_Z=71
GROUP_1_16_X=7
GROUP_1_16_Y=23
GROUP_1_16_Z=
GROUP_1_17_X=58
GROUP_1_17_Y=59
GROUP_1_17_Z=
GROUP_1_18_X=60
GROUP_1_18_Y=61
GROUP_1_18_Z=62
GROUP_1_19_X=43
GROUP_1_19_Y=44
GROUP_1_19_Z=42
GROUP_1_20_X=41
GROUP_1_20_Y=45
GROUP_1_20_Z=
+29 -30
View File
@@ -10,34 +10,33 @@ uniform float iTempo; // current tempo in bpm
uniform float iBeats; // elapsed beats since last tempo reset
uniform int iFPS; // output window frames per seconds
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 vec2 iResolution; // output window resolution in pixels
uniform vec3 iMidi1_1[20]; // all midi inputs defined
uniform vec3 iGroup1_1[20]; // all midi inputs defined
uniform sampler2D iTex0; // available texture (this code output, so feedback)
void main() {
// all available buttons and faders
vec3 b1 = iMidi1_1[0];
vec2 f1 = iMidi1_1[1].xy;
vec3 b2 = iMidi1_1[2];
vec2 f2 = iMidi1_1[3].xy;
vec3 b3 = iMidi1_1[4];
vec2 f3 = iMidi1_1[5].xy;
vec3 b4 = iMidi1_1[6];
vec2 f4 = iMidi1_1[7].xy;
vec3 b5 = iMidi1_1[8];
vec2 f5 = iMidi1_1[9].xy;
vec3 b6 = iMidi1_1[10];
vec2 f6 = iMidi1_1[11].xy;
vec3 b7 = iMidi1_1[12];
vec2 f7 = iMidi1_1[13].xy;
vec3 b8 = iMidi1_1[14];
vec2 f8 = iMidi1_1[15].xy;
vec3 b9 = iMidi1_1[16];
vec3 b10 = iMidi1_1[17];
vec3 b11 = iMidi1_1[18];
vec3 b12 = iMidi1_1[19];
vec3 b1 = iGroup1_1[0];
vec2 f1 = iGroup1_1[1].xy;
vec3 b2 = iGroup1_1[2];
vec2 f2 = iGroup1_1[3].xy;
vec3 b3 = iGroup1_1[4];
vec2 f3 = iGroup1_1[5].xy;
vec3 b4 = iGroup1_1[6];
vec2 f4 = iGroup1_1[7].xy;
vec3 b5 = iGroup1_1[8];
vec2 f5 = iGroup1_1[9].xy;
vec3 b6 = iGroup1_1[10];
vec2 f6 = iGroup1_1[11].xy;
vec3 b7 = iGroup1_1[12];
vec2 f7 = iGroup1_1[13].xy;
vec3 b8 = iGroup1_1[14];
vec2 f8 = iGroup1_1[15].xy;
vec3 b9 = iGroup1_1[16];
vec3 b10 = iGroup1_1[17];
vec3 b11 = iGroup1_1[18];
vec3 b12 = iGroup1_1[19];
// center UV and scale it to ratio
vec2 uv0 = vUV.st;
@@ -48,19 +47,19 @@ void main() {
float circle_dist = 0.1 + 0.9 * f1.x;
float circle_size = 0.1 + 0.9 * f2.x;
vec2 circle_pos = circle_dist * vec2(
sin(iBeats * 2 * PI),
cos(iBeats * 2 * PI)
);
sin(iBeats * 2 * PI),
cos(iBeats * 2 * PI)
);
float circle = 1 - step(circle_size, length(uv1 - circle_pos));
// fader 3, 4 and 5 controls the color
vec3 color = vec3(
f3.x,
f4.x,
f5.x
);
f3.x,
f4.x,
f5.x
);
vec3 out_color = mix(color, 1 - color, circle);
// fader 8 controls the feedback value
fragColor = mix(vec4(out_color, 1), texture(iTex0, vUV.st), f8.x);
}
}
+121 -72
View File
@@ -1,4 +1,3 @@
#include <bsd/string.h>
#include <limits.h>
#include <log.h>
#include <stdbool.h>
@@ -13,61 +12,74 @@
#include "string.h"
static void print_help(int status_code) {
puts(PACKAGE
" " VERSION "\n\n"
"usage: " PACKAGE " "
"[-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] "
"\n\n"
"Fusion Of Real-time Generative Effects.\n\n"
"options:\n"
" -h, --help show this help message and exit\n"
" -v, --version print version\n"
" -p, --project forge project directory (default: " DATADIR
"/default)\n"
" -c, --config config file name (default: "
"forge_project.cfg)\n"
" -hr, --hot-reload hot reload of shaders scripts\n"
" -s, --screen output screen number (default: primary)\n"
" -m, --monitor monitor screen number (default: none)\n"
" -mo, --monitor-only no output screen\n"
" -w, --windowed not fullscreen\n"
" -t, --tempo base tempo (default: 60)\n"
" -d, --demo demonstration mode (assume "
"--no-save-state, --no-load-state, --auto-random)\n"
" -ar, --auto-random randomize state every 4 beats\n"
" -nar, --no-auto-random do not randomize state (default)\n"
" -v, --video-in path to video capture device (multiple "
"allowed)\n"
" -vs, --video-size video capture desired height (default: "
"internal texture height)\n"
" -is, --internal-size internal texture height (default: 720)\n"
" -sf, --state-file saved state file (default: "
"forge_saved_state.txt)\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");
puts(
PACKAGE
" " VERSION "\n\n"
"usage: " PACKAGE " "
"[-h] "
"[-v] "
"[-p=PROJECT_PATH] "
"[-c=CFG_FILE] "
"[-hr] "
"[-s=SCREEN] "
"[-m=SCREEN] "
"[-mo] "
"[-w] "
"[-t=TEMPO] "
"[-d] "
"[-ar / -nar] "
"[-arc=CYCLES] "
#ifdef VIDEO_IN
"[-vi=FILE] "
"[-vs=SIZE] "
"[-vb=COUNT] "
"[-vr / -nvr] "
#endif /* VIDEO_IN */
"[-is=SIZE] "
"[-ls / -nls] "
"[-ss / -nss] "
"[-mr / -nmr] "
"[-tm] "
"[-tf] "
"\n\n"
"Fusion Of Real-time Generative Effects.\n\n"
"options:\n"
" -h, --help show this help message and exit\n"
" -v, --version print version\n"
" -p, --project forge project directory (default: " DATADIR
"/default)\n"
" -c, --config config file name (default: "
"forge_project.cfg)\n"
" -hr, --hot-reload hot reload of shaders scripts\n"
" -s, --screen output screen number (default: primary)\n"
" -m, --monitor monitor screen number (default: none)\n"
" -mo, --monitor-only no output screen\n"
" -w, --windowed not fullscreen\n"
" -t, --tempo base tempo (default: 60)\n"
" -d, --demo demonstration mode (assume "
"--no-save-state, --no-load-state, --auto-random)\n"
" -ar, --auto-random randomize state every cycle (4 beats)\n"
" -nar, --no-auto-random do not randomize state (default)\n"
" -arc, --auto-random-cycle auto random cycle length (default: 4)\n"
#ifdef VIDEO_IN
" -vi, --video-in path to video capture device (multiple "
"allowed)\n"
" -vb, --video-buffers number of video buffers to use (default: "
"2)\n"
" -vs, --video-size video capture desired height (default: "
"internal texture height)\n"
" -vr, --video-reconnect auto-reconnect video (default)\n"
" -nvr, --no-video-reconnect do not auto-reconnect video\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"
" -mr, --midi-reconnect auto-reconnect midi (default)\n"
" -nmr, --no-midi-reconnect do not auto-reconnect midi\n"
" -tm, --trace-midi print midi code and values\n"
" -tf, --trace-fps print fps status of subsystems\n");
exit(status_code);
}
@@ -102,7 +114,7 @@ static unsigned int parse_uint(const char *arg, const char *value) {
tmp_value = (unsigned long long)atoll(value);
if (tmp_value >= UINT_MAX) {
if (tmp_value > UINT_MAX) {
invalid_value(arg, value);
}
@@ -124,12 +136,17 @@ void args_parse(Parameters *params, int argc, char **argv) {
params->base_tempo = 60.0f;
params->demo = false;
params->auto_random = false;
params->auto_random_cycle = 4;
#ifdef VIDEO_IN
params->video_in.length = 0;
params->video_buffers = 2;
params->video_size = 0;
params->video_reconnect = true;
#endif /* VIDEO_IN */
params->internal_size = 720;
strlcpy(params->state_file, "forge_saved_state.txt", STR_LEN);
params->load_state = true;
params->save_state = true;
params->midi_reconnect = true;
params->trace_midi = false;
params->trace_fps = false;
@@ -142,8 +159,14 @@ void args_parse(Parameters *params, int argc, char **argv) {
puts(PACKAGE " " VERSION);
exit(EXIT_SUCCESS);
} else if (is_arg(arg, "-p") || is_arg(arg, "--project")) {
if (strlen(value) == 0) {
invalid_value(arg, value);
}
strlcpy(params->project_path, value, STR_LEN);
} else if (is_arg(arg, "-c") || is_arg(arg, "--config")) {
if (strlen(value) == 0) {
invalid_value(arg, value);
}
strlcpy(params->config_file, value, STR_LEN);
} else if (is_arg(arg, "-hr") || is_arg(arg, "--hot-reload")) {
params->hot_reload = true;
@@ -168,16 +191,9 @@ void args_parse(Parameters *params, int argc, char **argv) {
params->auto_random = true;
} else if (is_arg(arg, "-nar") || is_arg(arg, "--no-auto-random")) {
params->auto_random = false;
} else if (is_arg(arg, "-v") || is_arg(arg, "--video-in")) {
if (params->video_in.length == MAX_VIDEO) {
log_error("maximum video input reached");
exit(EXIT_FAILURE);
}
strlcpy(params->video_in.values[params->video_in.length++], value,
STR_LEN);
} else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) {
params->video_size = parse_uint(arg, value);
if (params->video_size == 0) {
} 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, "-is") || is_arg(arg, "--internal-size")) {
@@ -185,8 +201,6 @@ void args_parse(Parameters *params, int argc, char **argv) {
if (params->internal_size == 0) {
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")) {
params->load_state = true;
} else if (is_arg(arg, "-nls") || is_arg(arg, "--no-load-state")) {
@@ -195,12 +209,46 @@ void args_parse(Parameters *params, int argc, char **argv) {
params->save_state = true;
} else if (is_arg(arg, "-nss") || is_arg(arg, "--no-save-state")) {
params->save_state = false;
} else if (is_arg(arg, "-mr") || is_arg(arg, "--midi-reconnect")) {
params->midi_reconnect = true;
} else if (is_arg(arg, "-nmr") || is_arg(arg, "--no-midi-reconnect")) {
params->midi_reconnect = false;
} else if (is_arg(arg, "-tm") || is_arg(arg, "--trace-midi")) {
params->trace_midi = true;
} else if (is_arg(arg, "-tf") || is_arg(arg, "--trace-fps")) {
params->trace_fps = true;
} else {
#ifdef VIDEO_IN
if (is_arg(arg, "-vi") || is_arg(arg, "--video-in")) {
if (params->video_in.length == MAX_VIDEO) {
log_error("maximum video input reached");
exit(EXIT_FAILURE);
}
if (strlen(value) == 0) {
invalid_value(arg, value);
}
strlcpy(params->video_in.values[params->video_in.length++], value,
STR_LEN);
} else if (is_arg(arg, "-vb") || is_arg(arg, "--video-buffers")) {
params->video_buffers = parse_uint(arg, value);
if (params->video_buffers == 0) {
invalid_value(arg, value);
}
} else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) {
params->video_size = parse_uint(arg, value);
if (params->video_size == 0) {
invalid_value(arg, value);
}
} else if (is_arg(arg, "-vr") || is_arg(arg, "--video-reconnect")) {
params->video_reconnect = true;
} else if (is_arg(arg, "-nvr") || is_arg(arg, "--no-video-reconnect")) {
params->video_reconnect = false;
} else {
invalid_arg(arg);
}
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
}
}
@@ -209,8 +257,9 @@ void args_parse(Parameters *params, int argc, char **argv) {
log_error("monitor screen cannot be the same as output screen");
exit(EXIT_FAILURE);
}
#ifdef VIDEO_IN
if (params->video_size == 0) {
params->video_size = params->internal_size;
}
}
#endif /* VIDEO_IN */
}
+1 -1
View File
@@ -5,4 +5,4 @@
void args_parse(Parameters *params, int argc, char **argv);
#endif /* ARGS_H */
#endif /* ARGS_H */
+4
View File
@@ -13,6 +13,10 @@ unsigned int arr_uint_index_of(UintArray array, unsigned int value) {
}
unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index) {
if (offsets.length == 0) {
return 0;
}
for (unsigned int i = offsets.length - 1; i > 0; i--) {
if (*index >= offsets.values[i]) {
*index -= offsets.values[i];
+1 -1
View File
@@ -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);
#endif /* ARR_H */
#endif /* ARR_H */
+1 -1
View File
@@ -87,4 +87,4 @@
#define MAX_TAP_VALUES 10
#endif
#endif /* CONFIG_H */
#endif /* CONFIG_H */
+23 -4
View File
@@ -1,4 +1,3 @@
#include <bsd/string.h>
#include <hashmap.h>
#include <log.h>
#include <stdlib.h>
@@ -69,15 +68,20 @@ void config_file_read(ConfigFile *config, const char *path) {
char *line;
char *rest;
config->map = hashmap_new(sizeof(ConfigFileItem), 0, 0, 0, item_hash,
item_compare, NULL, NULL);
config->map = NULL;
file_read(&file, path);
if (file.error) {
config->error = true;
return;
}
config->map = hashmap_new(sizeof(ConfigFileItem), 0, 0, 0, item_hash,
item_compare, NULL, NULL);
config->error = false;
line = strtok_r(file.content, "\n", &rest);
while (line != NULL) {
@@ -88,6 +92,17 @@ void config_file_read(ConfigFile *config, const char *path) {
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 *default_value) {
ConfigFileItem c_key;
@@ -125,4 +140,8 @@ unsigned int config_file_get_int(const ConfigFile *config, const char *key,
return (unsigned int)atoi(item->value);
}
void config_file_free(const ConfigFile *config) { hashmap_free(config->map); }
void config_file_free(const ConfigFile *config) {
if (config->map != NULL) {
hashmap_free(config->map);
}
}
+2
View File
@@ -5,6 +5,8 @@
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 *default_value);
+2 -2
View File
@@ -3,7 +3,7 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H
static char *vertex_shader_text =
static const char *vertex_shader_text =
"#version 460\n"
"const mat4 mvp = "
"{{2.,0.,0.,0.},{0.,2.,0.,0.},{0.,0.,2.,0.},{-1.,-1.,1.,1.}};\n"
@@ -19,4 +19,4 @@ static const Vertex vertices[6] = {{{0.0f, 0.0f}}, {{0.0f, 1.0f}},
{{1.0f, 1.0f}}, {{0.0f, 0.0f}},
{{1.0f, 1.0f}}, {{1.0f, 0.0f}}};
#endif /* CONSTANTS_H */
#endif /* CONSTANTS_H */
+17 -5
View File
@@ -1,4 +1,3 @@
#include <bsd/string.h>
#include <log.h>
#include <stdbool.h>
#include <stdio.h>
@@ -10,7 +9,6 @@
#include "types.h"
#include "file.h"
#include "string.h"
static time_t get_file_time(const File *file) {
struct stat attr;
@@ -28,6 +26,7 @@ bool file_should_update(const File *file) {
bool file_update(File *file) {
long length;
size_t read_length;
FILE *file_pointer;
// free remaining data
@@ -49,6 +48,12 @@ bool file_update(File *file) {
// read file length
fseek(file_pointer, 0, SEEK_END);
length = ftell(file_pointer);
if (length == -1L) {
file->error = true;
fclose(file_pointer);
log_error("Cannot get file length for '%s'", file->path);
return false;
}
// init buffer
fseek(file_pointer, 0, SEEK_SET);
file->content = malloc(length + 1);
@@ -59,7 +64,13 @@ bool file_update(File *file) {
return false;
}
// read file
fread(file->content, sizeof(char), length, file_pointer);
read_length = fread(file->content, sizeof(char), length, file_pointer);
if (read_length != (unsigned)length) {
file->error = true;
fclose(file_pointer);
log_error("Cannot read complete file '%s'", file->path);
return false;
}
// close file
fclose(file_pointer);
// append null byte
@@ -119,8 +130,9 @@ void file_write(const char *path, const StringArray *lines) {
fclose(file_pointer);
}
void file_free(const File *file) {
if (!file->error) {
void file_free(File *file) {
if (!file->error && file->content != NULL) {
free(file->content);
file->content = NULL;
}
}
+2 -2
View File
@@ -13,6 +13,6 @@ void file_write(const char *path, const StringArray *lines);
void file_dump(const char *path, const char *content);
void file_free(const File *file);
void file_free(File *file);
#endif /* FILE_H */
#endif /* FILE_H */
+274 -136
View File
@@ -1,45 +1,47 @@
#include <log.h>
#include <math.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include "types.h"
#include "config.h"
#include "config_file.h"
#include "file.h"
#include "forge.h"
#include "midi.h"
#include "project.h"
#include "shaders.h"
#include "shared.h"
#include "state.h"
#include "tempo.h"
#include "timer.h"
#include "video.h"
#include "window.h"
static SharedContext *context;
static Parameters init_params;
static Context context;
static ShaderProgram program;
static Window *window_output;
static Window *window_monitor;
static VideoCaptureArray inputs;
static Timer timer;
static MidiDevice midi;
static bool trace_midi;
static Project project;
static void compute_fps(bool trace_fps) {
#ifdef VIDEO_IN
static VideoCaptureArray video_captures;
#endif /* VIDEO_IN */
static void compute_fps() {
double fps;
char title[STR_LEN];
if (timer_inc(&timer)) {
fps = timer_reset(&timer);
if (trace_fps) {
if (init_params.trace_fps) {
log_trace("(main) %.2ffps", fps);
}
@@ -53,178 +55,247 @@ static void compute_fps(bool trace_fps) {
window_update_title(window_monitor, title);
}
context->fps = (unsigned int)round(fps);
context.fps = (unsigned int)round(fps);
}
}
static void init_context(const Parameters *params, unsigned int in_count) {
state_init(context, &project.state_config, params->demo, params->auto_random,
params->base_tempo, params->state_file, params->load_state);
static void init_context() {
context.stop = false;
context->monitor = params->monitor;
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_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;
}
}
#ifdef VIDEO_IN
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));
memset(context.input_index, 0, sizeof(context.input_index));
#endif /* VIDEO_IN */
}
static void free_context() { shared_close_context(context); }
static void reload_shader(unsigned int i) {
shaders_update(&program, &project.fragment_shaders[i][0], i, &project);
}
static void init_inputs(const StringArray *video_in, unsigned int video_size) {
inputs.length = video_in->length;
#ifdef VIDEO_IN
for (unsigned int i = 0; i < video_in->length; i++) {
video_init(&inputs.values[i], video_in->values[i], video_size);
}
}
static void init_inputs() {
video_captures.length = init_params.video_in.length;
static bool start_video_captures(unsigned int video_count, bool trace_fps) {
for (unsigned int i = 0; i < video_count; i++) {
if (!inputs.values[i].error &&
!video_background_read(&inputs.values[i], context, i, trace_fps)) {
return false;
for (unsigned int i = 0; i < init_params.video_in.length; i++) {
video_init(&video_captures.values[i], init_params.video_in.values[i],
init_params.video_size, init_params.video_buffers, true);
if (!video_captures.values[i].error) {
context.input_resolutions[i][0] = video_captures.values[i].width;
context.input_resolutions[i][1] = video_captures.values[i].height;
context.input_formats[i] = video_captures.values[i].pixelformat;
video_captures.values[i].needs_reload = false;
video_captures.values[i].disconnected = false;
}
}
return true;
}
static void free_video_captures(unsigned int video_count) {
for (unsigned int i = 0; i < video_count; i++) {
shaders_free_input(&program, &inputs.values[i]);
video_free(&inputs.values[i]);
static void start_video_background_read(VideoCapture *video_capture,
Context *context, int input_index,
bool trace_fps) {
pthread_t thread;
VideoBackgroundReadArgs *process_args =
(VideoBackgroundReadArgs *)malloc(sizeof(VideoBackgroundReadArgs));
process_args->capture = video_capture;
process_args->context = context;
process_args->input_index = input_index;
process_args->trace_fps = trace_fps;
if (pthread_create(&thread, NULL, video_background_read,
(void *)process_args) == 0) {
pthread_detach(thread);
} else {
log_error("background video acquisition failed to start");
free(process_args);
}
}
static void *
background_reconnect_video_captures(__attribute__((unused)) void *args) {
log_info("background video capture reconnect started");
while (!context.stop) {
sleep(1);
for (unsigned int i = 0; i < init_params.video_in.length; i++) {
if (video_captures.values[i].disconnected) {
video_free(&video_captures.values[i]);
video_init(&video_captures.values[i], init_params.video_in.values[i],
init_params.video_size, init_params.video_buffers, false);
if (!video_captures.values[i].error) {
context.input_resolutions[i][0] = video_captures.values[i].width;
context.input_resolutions[i][1] = video_captures.values[i].height;
context.input_formats[i] = video_captures.values[i].pixelformat;
video_captures.values[i].needs_reload = true;
video_captures.values[i].disconnected = false;
start_video_background_read(&video_captures.values[i], &context, i,
init_params.trace_fps);
}
}
}
}
pthread_exit(NULL);
}
static void start_video_captures() {
pthread_t thread;
for (unsigned int i = 0; i < video_captures.length; i++) {
if (!video_captures.values[i].error) {
start_video_background_read(&video_captures.values[i], &context, i,
init_params.trace_fps);
}
}
if (init_params.video_reconnect) {
if (pthread_create(&thread, NULL, background_reconnect_video_captures,
NULL) == 0) {
pthread_detach(thread);
} else {
log_info("background video capture reconnect failed to start");
}
}
}
static void free_video_captures() {
for (unsigned int i = 0; i < video_captures.length; i++) {
shaders_free_input(&program, i);
video_free(&video_captures.values[i]);
}
}
#endif /* VIDEO_IN */
static void error_callback(int error, const char *description) {
log_error("[GLFW] %d: %s", error, description);
window_terminate();
context->stop = true;
context.stop = true;
exit(EXIT_FAILURE);
}
static void key_callback(Window *window, int key,
__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)) {
// close window on escape key
log_info("[ESC] Closing...");
window_close(window);
} else if (window_char_key(key, action, 82)) {
// R: randomize
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;
} else if (event > 0) {
state_key_event(&context, project.state_config, event, midi);
}
}
static void midi_callback(unsigned char code, unsigned char value) {
state_apply_event(context, &project.state_config, &midi, code, value,
trace_midi);
state_midi_event(&context, project.state_config, midi, code, value,
init_params.trace_midi);
}
static void loop(bool hr, bool trace_fps) {
if (hr) {
project_reload(&project, reload_shader);
static void start_state_background_write() {
pthread_t thread;
StateBackgroundWriteArgs *process_args =
(StateBackgroundWriteArgs *)malloc(sizeof(StateBackgroundWriteArgs));
process_args->context = &context;
process_args->state_config = project.state_config;
process_args->midi = &midi;
if (pthread_create(&thread, NULL, state_background_write, process_args) ==
0) {
pthread_detach(thread);
} else {
log_error("background writing failed to start");
free(process_args);
}
compute_fps(trace_fps);
context->time = window_get_time();
context->tempo_total = (float)tempo_total(&context->tempo);
if (window_output != NULL) {
window_use(window_output, context);
shaders_compute(&program, context, false, false);
window_refresh(window_output);
}
if (window_monitor != NULL) {
window_use(window_monitor, context);
shaders_compute(&program, context, true, window_output != NULL);
window_refresh(window_monitor);
}
window_events();
}
void forge_run(const Parameters *params) {
context = shared_init_context("/" PACKAGE "_context");
static void start_midi_background_listen() {
pthread_t thread;
MidiBackgroundListenArgs *process_args =
(MidiBackgroundListenArgs *)malloc(sizeof(MidiBackgroundListenArgs));
process_args->device = &midi;
process_args->context = &context;
process_args->event_callback = midi_callback;
if (pthread_create(&thread, NULL, midi_background_listen, process_args) ==
0) {
pthread_detach(thread);
} else {
log_error("background midi acquisition failed to start");
free(process_args);
}
}
context->stop = false;
static void *background_reconnect_midi(__attribute__((unused)) void *args) {
log_info("background midi reconnect started");
while (!context.stop) {
sleep(1);
if (!midi.connected) {
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"),
false);
if (midi.connected) {
start_midi_background_listen();
}
}
}
pthread_exit(NULL);
}
static void init_midi() {
pthread_t thread;
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"), true);
if (midi.connected) {
start_midi_background_listen();
}
if (init_params.midi_reconnect) {
if (pthread_create(&thread, NULL, background_reconnect_midi, NULL) == 0) {
pthread_detach(thread);
} else {
log_error("background midi reconnect failed to start");
}
}
}
static bool init(const Parameters *params) {
init_params = *params;
project_init(&project, params->project_path, params->config_file);
if (project.error) {
return;
return false;
}
init_inputs(&params->video_in, params->video_size);
init_context();
init_context(params, project.in_count);
#ifdef VIDEO_IN
init_inputs();
if (!start_video_captures(params->video_in.length, params->trace_fps)) {
return;
}
start_video_captures();
#endif /* VIDEO_IN */
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"));
init_midi();
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;
}
start_state_background_write();
window_startup(error_callback);
context->tex_resolution[1] = params->internal_size;
context.tex_resolution[0] = params->internal_size;
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);
window_use(window_output, &context);
shaders_init(&program, &project, context, &inputs, false);
shaders_init(&program, &project, &context, false);
} else {
window_output = NULL;
}
@@ -234,15 +305,20 @@ void forge_run(const Parameters *params) {
window_init(PACKAGE " " VERSION " (monitor)", params->monitor_screen,
params->windowed, window_output, key_callback);
window_use(window_monitor, context);
window_use(window_monitor, &context);
shaders_init(&program, &project, context, &inputs, window_output != NULL);
shaders_init(&program, &project, &context, window_output != NULL);
} else {
window_monitor = NULL;
}
#ifdef VIDEO_IN
shaders_link_inputs(&program, &project, &video_captures,
init_params.video_buffers);
#endif /* VIDEO_IN */
if (program.error) {
context->stop = true;
context.stop = true;
window_terminate();
exit(EXIT_FAILURE);
}
@@ -251,36 +327,98 @@ void forge_run(const Parameters *params) {
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);
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);
}
context->stop = true;
if (params->save_state) {
state_save(context, &project.state_config, params->state_file);
#ifdef VIDEO_IN
if (init_params.video_reconnect) {
for (unsigned int i = 0; i < video_captures.length; i++) {
if (video_captures.values[i].needs_reload) {
shaders_relink_input(&program, &project, &video_captures, i);
video_captures.values[i].needs_reload = false;
}
}
}
#endif /* VIDEO_IN */
shaders_free(&program);
compute_fps();
context.time = window_get_time();
context.tempo_total = (float)tempo_total(&context.tempo);
if (window_output != NULL) {
window_use(window_output, context);
window_use(window_output, &context);
shaders_compute(&program, &context, false, false);
window_refresh(window_output);
}
if (window_monitor != NULL) {
window_use(window_monitor, &context);
shaders_compute(&program, &context, true, window_output != NULL);
window_refresh(window_monitor);
}
window_events();
return true;
}
static void shutdown() {
context.stop = true;
if (init_params.save_state) {
state_save(&context, project.state_config);
}
if (window_output != NULL) {
window_use(window_output, &context);
shaders_free_window(&program, false);
}
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);
shaders_free(&program);
free_context();
#ifdef VIDEO_IN
free_video_captures();
#endif /* VIDEO_IN */
midi_close(&midi);
project_free(&project);
window_terminate();
}
}
void forge_run(const Parameters *params) {
if (!init(params)) {
return;
}
while (!should_close()) {
if (!loop()) {
return;
}
}
shutdown();
}
+1 -1
View File
@@ -5,4 +5,4 @@
void forge_run(const Parameters *params);
#endif /* FORGE_H */
#endif /* FORGE_H */
+1 -1
View File
@@ -17,7 +17,7 @@ int main(int argc, char **argv) {
puts(PACKAGE " " VERSION);
set_seed((unsigned long)time(NULL));
rand_set_seed((unsigned long)time(NULL));
forge_run(&params);
+1 -1
View File
@@ -3,4 +3,4 @@
int main(int argc, char **argv);
#endif /* MAIN_H */
#endif /* MAIN_H */
+65 -31
View File
@@ -1,61 +1,95 @@
#include <GLFW/glfw3.h>
#include <alsa/asoundlib.h>
#include <bsd/string.h>
#include <log.h>
#include <pthread.h>
#include "types.h"
#include "config.h"
#include "log.h"
void midi_open(MidiDevice *device, const char *name) {
void snd_no_log(__attribute__((unused)) int prio,
__attribute__((unused)) int interface,
__attribute__((unused)) const char *file,
__attribute__((unused)) int line,
__attribute__((unused)) const char *function,
__attribute__((unused)) int errcode,
__attribute__((unused)) const char *fmt,
__attribute__((unused)) va_list arg) {}
void midi_open(MidiDevice *device, const char *name, bool log_error) {
strlcpy(device->name, name, STR_LEN);
device->connected = false;
device->input = NULL;
device->output = NULL;
snd_rawmidi_open(&device->input, &device->output, name, SND_RAWMIDI_NONBLOCK);
device->error = device->input == NULL || device->output == NULL;
log_info("(%s) MIDI open", name);
device->connected = snd_rawmidi_open(&device->input, &device->output, name,
SND_RAWMIDI_SYNC) == 0 &&
device->input != NULL && device->output != NULL;
if (log_error) {
if (device->connected) {
log_info("(%s) MIDI open", name);
} else {
log_warn("(%s) MIDI open failed", name);
}
}
}
void midi_write(const MidiDevice *device, unsigned char code,
unsigned char value) {
void midi_write(MidiDevice device, unsigned char code, unsigned char value) {
if (!device.connected) {
return;
}
unsigned char buffer[3];
buffer[0] = 0xB0;
buffer[1] = code;
buffer[2] = value;
snd_rawmidi_write(device->output, buffer, 3);
snd_rawmidi_write(device.output, buffer, 3);
}
bool midi_background_listen(const MidiDevice *device,
const SharedContext *context,
void (*event_callback)(unsigned char code,
unsigned char value)) {
pid_t pid;
void midi_close(MidiDevice *device) {
if (device->connected) {
snd_rawmidi_close(device->input);
snd_rawmidi_close(device->output);
device->connected = false;
}
}
void *midi_background_listen(void *args) {
MidiBackgroundListenArgs *process_args = (MidiBackgroundListenArgs *)args;
MidiDevice *device = process_args->device;
Context *context = process_args->context;
int bytes_read;
snd_rawmidi_info_t *info;
unsigned char buffer[3];
pid = fork();
if (pid < 0) {
log_error("Could not create subprocess");
return false;
}
if (pid == 0) {
return true;
}
log_info("(%s) background acquisition started (pid: %d)", device->name, pid);
log_info("(%s) background acquisition started", device->name);
while (!context->stop) {
snd_rawmidi_info_malloc(&info);
if (info == NULL) {
log_error("(%s) failed to allocate MIDI info", device->name);
free(process_args);
pthread_exit(NULL);
}
while (!context->stop && snd_rawmidi_info(device->output, info) == 0) {
bytes_read = snd_rawmidi_read(device->input, buffer, 3);
if (bytes_read == 3) {
event_callback(buffer[1], buffer[2]);
process_args->event_callback(buffer[1], buffer[2]);
}
}
log_info("(%s) background acquisition stopped by main thread (pid: %d)",
device->name, pid);
return false;
snd_rawmidi_info_free(info);
if (context->stop) {
log_info("(%s) background acquisition stopped by main thread",
device->name);
} else {
log_info("(%s) background acquisition stopped after error", device->name);
midi_close(device);
}
free(process_args);
pthread_exit(NULL);
}
+5 -8
View File
@@ -3,12 +3,9 @@
#ifndef MIDI_H
#define MIDI_H
void midi_open(MidiDevice *device, const char *name);
void midi_write(const MidiDevice *device, unsigned char code,
unsigned char value);
bool midi_background_listen(const MidiDevice *device,
const SharedContext *context,
void (*event_callback)(unsigned char code,
unsigned char value));
void midi_open(MidiDevice *device, const char *name, bool log_error);
void midi_write(MidiDevice device, unsigned char code, unsigned char value);
void *midi_background_listen(void *args);
void midi_close(MidiDevice *device);
#endif /* MIDI_H */
#endif /* MIDI_H */
+12 -4
View File
@@ -1,4 +1,4 @@
#include <bsd/string.h>
#include <log.h>
#include <string.h>
#include "types.h"
@@ -6,7 +6,6 @@
#include "config.h"
#include "config_file.h"
#include "file.h"
#include "log.h"
#include "project.h"
#include "state.h"
#include "string.h"
@@ -49,6 +48,8 @@ static bool parse_fragment_shader_file(Project *project, unsigned int i) {
include_end - project->fragment_shaders[i][0].content,
tmp_file.content);
free(project->fragment_shaders[i][0].content);
project->fragment_shaders[i][0].content = new_content;
file_free(&tmp_file);
@@ -103,6 +104,12 @@ void project_init(Project *project, const char *project_path,
project->sub_counts.length = project->frag_count;
for (unsigned int i = 0; i < project->frag_count; i++) {
for (unsigned int j = 0; j < MAX_SUB_FILE + 1; j++) {
project->fragment_shaders[i][j].content = NULL;
}
}
for (unsigned int i = 0; i < project->frag_count; i++) {
project->sub_counts.values[i] = 0;
if (!read_fragment_shader_file(project, frag_prefix, i)) {
@@ -135,10 +142,11 @@ void project_reload(Project *project, void (*reload_callback)(unsigned int)) {
}
}
void project_free(const Project *project) {
void project_free(Project *project) {
for (unsigned int i = 0; i < project->frag_count; i++) {
file_free(&project->fragment_shaders[i][0]);
// other sub files contents are freed at parse_fragment_shader_file
}
config_file_free(&project->config);
}
}
+2 -2
View File
@@ -8,6 +8,6 @@ void project_init(Project *project, const char *project_path,
void project_reload(Project *project, void (*reload_callback)(unsigned int));
void project_free(const Project *project);
void project_free(Project *project);
#endif /* PROJECT_H */
#endif /* PROJECT_H */
+5 -5
View File
@@ -4,7 +4,7 @@ static unsigned long long mcg_state = 0xcafef00dd15ea5e5u; // Must be odd
static unsigned long long const multiplier = 6364136223846793005u;
// https://en.wikipedia.org/wiki/Permuted_congruential_generator
static unsigned long rand(void) {
static unsigned long fast_rand(void) {
unsigned long long x = mcg_state;
unsigned count = (unsigned)(x >> 61);
@@ -13,11 +13,11 @@ static unsigned long rand(void) {
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;
(void)rand();
(void)fast_rand();
}
unsigned int rand_uint(const unsigned int max) {
return max == 0 ? 0 : (unsigned int)(rand() % max);
}
return max == 0 ? 0 : (unsigned int)(fast_rand() % max);
}
+2 -2
View File
@@ -1,7 +1,7 @@
#ifndef 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);
#endif
#endif
+492 -172
View File
@@ -14,75 +14,202 @@
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
#ifdef VIDEO_IN
#define GLAD_EGL_IMPLEMENTATION
#include <glad/egl.h>
#endif /* VIDEO_IN */
#include <GLFW/glfw3.h>
#ifdef VIDEO_IN
#include <GLFW/glfw3native.h>
#endif /* VIDEO_IN */
static const GLuint unused_uniform = (GLuint)-1;
static const GLint UNUSED_UNIFORM = -1;
bool check_glerror(ShaderProgram *program) {
static bool check_glerror_ro(const char *context) {
unsigned int code;
code = glGetError();
if (code > 0) {
log_warn("GL Error: %04x", code);
program->error = true;
log_warn("GL Error: %04x (%s)", code, context);
return true;
}
return code > 0;
return false;
}
static void init_gl(ShaderProgram *program) {
static bool check_glerror(ShaderProgram *program, const char *context) {
if (check_glerror_ro(context)) {
program->error = true;
return true;
}
return false;
}
#ifdef GL_DEBUG
static void gl_debug_callback(GLenum source, GLenum type, GLuint id,
GLenum severity,
__attribute__((unused)) GLsizei length,
const GLchar *message,
__attribute__((unused)) const void *userParam) {
log_debug("GL Debug: source=%x, type=%x, id=%d, severity=%x, message=%s",
source, type, id, severity, message ? message : "(null)");
}
#endif /* GL_DEBUG */
static bool check_eglerror_ro(const char *context) {
#ifdef VIDEO_IN
unsigned int code;
code = eglGetError();
if (code != EGL_SUCCESS) {
log_warn("EGL Error: %04x (%s)", code, context);
return true;
}
#endif /* VIDEO_IN */
return false;
}
static bool check_eglerror(ShaderProgram *program, const char *context) {
if (check_eglerror_ro(context)) {
program->error = true;
return true;
}
return false;
}
#ifdef VIDEO_IN
#ifdef EGL_DEBUG
static void egl_debug_callback(EGLenum error, const char *command,
EGLint messageType, EGLLabelKHR threadLabel,
EGLLabelKHR objectLabel, const char *message) {
log_debug("EGL Debug: error=%04x, command=%s, type=%d, "
"thread=%p, object=%p, message=%s",
error, command ? command : "(null)", messageType, threadLabel,
objectLabel, message ? message : "(null)");
}
#endif /* EGL_DEBUG */
#endif /* VIDEO_IN */
static bool init_gl(ShaderProgram *program) {
gladLoadGL(glfwGetProcAddress);
#ifdef GL_DEBUG
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(gl_debug_callback, NULL);
#endif /* GL_DEBUG */
#ifdef VIDEO_IN
program->egl_display = glfwGetEGLDisplay();
if (program->egl_display == EGL_NO_DISPLAY) {
log_error("error: glfwGetEGLDisplay no EGLDisplay returned");
program->error = true;
return;
return false;
}
gladLoadEGL(program->egl_display, glfwGetProcAddress);
#ifdef EGL_DEBUG
{
PFNEGLDEBUGMESSAGECONTROLKHRPROC debug_ctrl =
(PFNEGLDEBUGMESSAGECONTROLKHRPROC)glfwGetProcAddress(
"eglDebugMessageControlKHR");
if (debug_ctrl != NULL) {
const EGLAttrib attrib_list[] = {EGL_NONE};
debug_ctrl(egl_debug_callback, attrib_list);
}
}
#endif /* EGL_DEBUG */
#endif /* VIDEO_IN */
return !check_glerror(program, "init_gl") &&
!check_eglerror(program, "init_gl");
}
static void init_textures(ShaderProgram *program,
const SharedContext *context) {
static bool init_textures(ShaderProgram *program, const Context *context) {
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++) {
// selects which texture unit subsequent texture state calls will affect
glActiveTexture(GL_TEXTURE0 + i);
if (check_glerror(program, "init_textures/glActiveTexture")) {
return false;
}
glBindTexture(GL_TEXTURE_2D, program->textures[i]);
if (check_glerror(program, "init_textures/glBindTexture")) {
return false;
}
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
if (check_glerror(program, "init_textures/glDisable")) {
return false;
}
// define texture image as empty
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
if (check_glerror(program, "init_textures/glTexImage2D")) {
return false;
}
// setup mipmap context
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
}
return true;
}
static void rebind_textures(const ShaderProgram *program) {
for (unsigned int i = 0; i < program->tex_count; i++) {
glActiveTexture(GL_TEXTURE0 + i);
check_glerror_ro("rebind_textures/glActiveTexture");
glBindTexture(GL_TEXTURE_2D, program->textures[i]);
check_glerror_ro("rebind_textures/glBindTexture");
}
}
static void link_input_to_texture(ShaderProgram *program, VideoCapture *input,
unsigned int texture_index) {
input->dma_image = EGL_NO_IMAGE_KHR;
#ifdef VIDEO_IN
static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input,
unsigned int input_index,
unsigned int sub_index, bool reload) {
unsigned int texture_index =
program->tex_count + input_index * program->sub_video_count + sub_index;
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
const EGLint attrib_list[] = {EGL_WIDTH,
@@ -92,57 +219,89 @@ static void link_input_to_texture(ShaderProgram *program, VideoCapture *input,
EGL_LINUX_DRM_FOURCC_EXT,
input->pixelformat,
EGL_DMA_BUF_PLANE0_FD_EXT,
input->exp_fd,
input->exp_fd[sub_index],
EGL_DMA_BUF_PLANE0_OFFSET_EXT,
0,
EGL_DMA_BUF_PLANE0_PITCH_EXT,
input->bytesperline,
EGL_NONE};
input->dma_image =
eglCreateImageKHR(program->egl_display, EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT, NULL, attrib_list);
if (input->dma_image == EGL_NO_IMAGE_KHR) {
log_error("(%s) eglCreateImageKHR failed %04x", input->name, eglGetError());
return;
dma_image = eglCreateImageKHR(program->egl_display, EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT, NULL, attrib_list);
if (check_eglerror(program, "link_input_to_texture/eglCreateImageKHR")) {
return false;
}
program->dma_images[input_index * program->sub_video_count + sub_index] =
dma_image;
glActiveTexture(GL_TEXTURE0 + texture_index);
if (check_glerror(program, "link_input_to_texture/glActiveTexture")) {
return false;
}
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,
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
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[%d]", texture_index, input->name,
sub_index);
return true;
}
static void init_input(ShaderProgram *program, const ConfigFile *config,
VideoCaptureArray *inputs) {
static bool init_input(ShaderProgram *program, const ConfigFile *config,
VideoCaptureArray *inputs, unsigned int input_index,
bool reload) {
unsigned int tex_i;
unsigned int sub_index;
char name[STR_LEN];
for (unsigned int i = 0; i < program->in_count; i++) {
if (i < inputs->length && !inputs->values[i].error) {
snprintf(name, STR_LEN, "IN_%d_OUT", i + 1);
tex_i = config_file_get_int(config, name, 0);
link_input_to_texture(program, &inputs->values[i], tex_i);
} else {
log_warn("Cannot link input %d", i + 1);
if (input_index < inputs->length && input_index < program->in_count &&
!inputs->values[input_index].error) {
snprintf(name, STR_LEN, "IN_%d_OUT", input_index + 1);
tex_i = config_file_get_int(config, name, 0);
for (sub_index = 0; sub_index < inputs->values[input_index].buf_count;
sub_index++) {
if (!link_input_to_texture(program, &inputs->values[input_index],
input_index, sub_index, reload)) {
return false;
}
}
program->input_tex_map[input_index] = tex_i;
program->tex_map[tex_i] =
program->tex_count + input_index * program->sub_video_count;
} else {
log_warn("Cannot link input %d", input_index + 1);
}
return true;
}
#endif /* VIDEO_IN */
static void init_framebuffers(ShaderProgram *program,
static bool init_framebuffers(ShaderProgram *program,
const ConfigFile *config) {
unsigned int tex_i;
char name[STR_LEN];
GLenum framebuffer_status;
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++) {
if (i == program->frag_output_index || i == program->frag_monitor_index) {
@@ -150,48 +309,87 @@ static void init_framebuffers(ShaderProgram *program,
}
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);
tex_i = config_file_get_int(config, name, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
program->textures[tex_i], 0);
if (check_glerror(program, "init_framebuffers/glFramebufferTexture2D")) {
return false;
}
// check framebuffer status
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
log_error("Framebuffer %d is KO: %x", i + 1,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
framebuffer_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (check_glerror(program, "init_framebuffers/glCheckFramebufferStatus")) {
return false;
}
if (framebuffer_status != GL_FRAMEBUFFER_COMPLETE) {
log_error("Framebuffer %d is KO: %x", i + 1, framebuffer_status);
program->error = true;
return;
return false;
}
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);
if (check_glerror(program, "init_vertices/glGenBuffers")) {
return false;
}
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);
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);
if (check_glerror(program, "bind_vertices/glBindBuffer")) {
return false;
}
glGenVertexArrays(1, &program->vertex_array[index]);
if (check_glerror(program, "bind_vertices/glGenVertexArrays")) {
return false;
}
glBindVertexArray(program->vertex_array[index]);
if (check_glerror(program, "bind_vertices/glBindVertexArray")) {
return false;
}
for (unsigned int i = 0; i < program->frag_count; i++) {
// enable attribute pointer
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
// attributes to use when rendering
glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE,
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,
@@ -203,13 +401,18 @@ static bool compile_shader(GLuint shader_id, const char *name,
// update shader source code
glShaderSource(shader_id, 1, &source_code, NULL);
check_glerror_ro("compile_shader/glShaderSource");
// compile shader
glCompileShader(shader_id);
check_glerror_ro("compile_shader/glCompileShader");
// get compilation status
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params);
glGetShaderInfoLog(shader_id, 1024, NULL, (GLchar *)&log);
check_glerror_ro("compile_shader/glGetShaderiv");
glGetShaderInfoLog(shader_id, STR_LEN, NULL, (GLchar *)log);
check_glerror_ro("compile_shader/glGetShaderInfoLog");
if (status_params == GL_FALSE) {
log_error("Failed to compile\n%s", log);
@@ -221,9 +424,13 @@ static bool compile_shader(GLuint shader_id, const char *name,
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
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,
"internal vertex shader",
vertex_shader_text);
@@ -231,30 +438,61 @@ static void init_shaders(ShaderProgram *program, const Project *project) {
// compile fragment shaders
for (unsigned int i = 0; i < program->frag_count; i++) {
program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER);
if (check_glerror(program, "init_shaders/glCreateShader")) {
return false;
}
program->error = program->error ||
!compile_shader(program->fragment_shaders[i],
project->fragment_shaders[i][0].path,
project->fragment_shaders[i][0].content);
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 StateConfig *state_config) {
unsigned int index1;
unsigned int index2;
char name[STR_LEN];
const char *prefix;
GLint link_status;
char link_log[STR_LEN];
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->fragment_shaders[i]);
if (check_glerror(program, "init_single_program/glAttachShader")) {
return false;
}
glLinkProgram(program->programs[i]);
if (check_glerror(program, "init_single_program/glLinkProgram")) {
return false;
}
glGetProgramiv(program->programs[i], GL_LINK_STATUS, &link_status);
if (check_glerror(program, "init_single_program/glGetProgramiv")) {
return false;
}
if (link_status != GL_TRUE) {
glGetProgramInfoLog(program->programs[i], STR_LEN, NULL, link_log);
if (check_glerror(program, "init_single_program/glGetProgramInfoLog")) {
return false;
}
log_error("Program %d link error: %s", i + 1, link_log);
return false;
}
// create uniforms pointers
program->itime_locations[i] = glGetUniformLocation(
@@ -280,6 +518,9 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
program->iautorand_locations[i] = glGetUniformLocation(
program->programs[i],
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->programs[i],
config_file_get_str(config, "UNIFORM_PAGE", "iPage"));
@@ -324,18 +565,6 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
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");
for (unsigned int j = 0; j < program->active_count; j++) {
snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
@@ -345,23 +574,24 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
if (program->midi_lengths.length == 0) {
index1 = 0;
for (unsigned int j = 0; j < state_config->midi_active_counts.length; j++) {
for (unsigned int k = 0; k < state_config->midi_active_counts.values[j];
for (unsigned int j = 0; j < state_config->group_active_counts.length;
j++) {
for (unsigned int k = 0; k < state_config->group_active_counts.values[j];
k++) {
program->midi_lengths.values[index1++] =
state_config->midi_counts.values[j];
state_config->group_counts.values[j];
}
}
program->midi_lengths.length = index1;
}
prefix = config_file_get_str(config, "UNIFORM_MIDI_PREFIX", "iMidi");
prefix = config_file_get_str(config, "UNIFORM_GROUP_PREFIX", "iGroup");
index2 = 0;
for (unsigned int j = 0; j < state_config->midi_active_counts.length; j++) {
for (unsigned int k = 0; k < state_config->midi_active_counts.values[j];
for (unsigned int j = 0; j < state_config->group_active_counts.length; j++) {
for (unsigned int k = 0; k < state_config->group_active_counts.values[j];
k++) {
snprintf(name, STR_LEN, "%s%d_%d", prefix, j + 1, k + 1);
program->imidi_locations[i * program->midi_lengths.length + index2++] =
program->igroup_locations[i * program->midi_lengths.length + index2++] =
glGetUniformLocation(program->programs[i], name);
}
}
@@ -374,147 +604,95 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
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
program->vpos_locations[i] =
glGetAttribLocation(program->programs[i], "vPos");
if (check_glerror(program, "init_single_program/glGetAttribLocation")) {
return false;
}
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) {
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;
}
}
return true;
}
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);
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,
const SharedContext *context) {
static void update_viewport(ShaderProgram *program, const Context *context) {
// viewport changed
if (context->resolution[0] != program->last_resolution[0] ||
context->resolution[1] != program->last_resolution[1]) {
// clean and resize all textures
for (unsigned int i = 0; i < program->tex_count; i++) {
glActiveTexture(GL_TEXTURE0 + i);
check_glerror_ro("update_viewport/glActiveTexture");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
check_glerror_ro("update_viewport/glTexImage2D");
}
program->last_resolution[0] = context->resolution[0];
program->last_resolution[1] = context->resolution[1];
}
}
static void write_uniform_1f(GLuint location, float value) {
if (location != unused_uniform) {
static void write_uniform_1f(GLint location, float value) {
if (location != UNUSED_UNIFORM) {
glUniform1f(location, value);
}
}
static void write_uniform_1i(GLuint location, unsigned int value) {
if (location != unused_uniform) {
static void write_uniform_1i(GLint location, unsigned int value) {
if (location != UNUSED_UNIFORM) {
glUniform1i(location, (const GLint)value);
}
}
static void write_uniform_2f(GLuint location, const vec2 *value) {
if (location != unused_uniform) {
static void write_uniform_2f(GLint location, const vec2 *value) {
if (location != UNUSED_UNIFORM) {
glUniform2fv(location, 1, (const GLfloat *)value);
}
}
static void write_uniform_multi_3f(GLuint location, unsigned int count,
static void write_uniform_multi_3f(GLint location, unsigned int count,
const vec3 *value) {
if (location != unused_uniform) {
if (location != UNUSED_UNIFORM) {
glUniform3fv(location, count, (const GLfloat *)value);
}
}
static void use_program(const ShaderProgram *program, int i, bool output,
const SharedContext *context) {
const Context *context) {
unsigned int k;
unsigned int offset;
unsigned int subcount;
@@ -545,6 +723,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->iautorand_locations[i],
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->iselected_locations[i], context->selected + 1);
write_uniform_2f(program->ires_locations[i], &context->resolution);
@@ -555,6 +735,8 @@ static void use_program(const ShaderProgram *program, int i, bool output,
context->active[j] + 1);
}
#ifdef VIDEO_IN
for (unsigned int j = 0; j < program->in_count; j++) {
write_uniform_2f(program->iinres_locations[i * program->in_count + j],
&context->input_resolutions[j]);
@@ -564,6 +746,8 @@ static void use_program(const ShaderProgram *program, int i, bool output,
context->input_fps[j]);
}
#endif /* VIDEO_IN */
// set seeds uniforms
for (unsigned int j = 0; j < program->frag_count; j++) {
write_uniform_1i(program->iseed_locations[i * program->frag_count + j],
@@ -578,7 +762,7 @@ static void use_program(const ShaderProgram *program, int i, bool output,
offset = 0;
for (unsigned int j = 0; j < program->midi_lengths.length; j++) {
write_uniform_multi_3f(
program->imidi_locations[i * program->midi_lengths.length + j],
program->igroup_locations[i * program->midi_lengths.length + j],
program->midi_lengths.values[j], context->values + offset);
offset += program->midi_lengths.values[j];
}
@@ -590,7 +774,7 @@ static void use_program(const ShaderProgram *program, int i, bool output,
if (program->sub_locations[i * program->sub_variant_count *
program->sub_type_count +
j * program->sub_variant_count + k] !=
unused_uniform) {
UNUSED_UNIFORM) {
subroutines[subcount++] =
program->sub_locations[i * program->sub_variant_count *
program->sub_type_count +
@@ -605,15 +789,137 @@ static void use_program(const ShaderProgram *program, int i, bool output,
// set GL_TEXTURE(X) to uniform sampler2D texX
for (unsigned int j = 0; j < program->tex_count; j++) {
write_uniform_1i(program->textures_locations[i * program->tex_count + j],
j);
program->tex_map[j]);
}
// draw output
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void shaders_compute(ShaderProgram *program, const SharedContext *context,
void shaders_init(ShaderProgram *program, const Project *project,
const Context *context, bool rebind) {
unsigned int i;
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);
memset(program->tex_map, 0, sizeof(program->tex_map));
for (i = 0; i < program->tex_count; i++) {
program->tex_map[i] = i;
}
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.group_active_counts.length;
program->midi_lengths.length = 0;
#ifdef VIDEO_IN
memset(program->dma_images, 0, sizeof(program->dma_images));
memset(program->input_tex_map, 0, sizeof(program->input_tex_map));
#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;
}
}
#ifdef VIDEO_IN
void shaders_relink_input(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs, unsigned int input_index) {
shaders_free_input(program, input_index);
init_input(program, &project->config, inputs, input_index, true);
}
void shaders_link_inputs(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs, unsigned int buffer_count) {
unsigned int i;
program->sub_video_count = buffer_count;
for (i = 0; i < program->in_count; i++) {
init_input(program, &project->config, inputs, i, false);
}
}
void shaders_free_input(ShaderProgram *program, unsigned int input_index) {
unsigned int sub_index;
for (sub_index = 0; sub_index < program->sub_video_count; sub_index++) {
if (program->dma_images[input_index * program->sub_video_count +
sub_index] != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(
program->egl_display,
program
->dma_images[input_index * program->sub_video_count + sub_index]);
program->dma_images[input_index * program->sub_video_count + sub_index] =
EGL_NO_IMAGE_KHR;
}
}
check_eglerror_ro("shaders_free_input/eglDestroyImageKHR");
}
static void update_inputs_tex_map(ShaderProgram *program,
const Context *context) {
unsigned int i;
unsigned int tex_i;
for (i = 0; i < program->in_count; i++) {
if (context->input_formats[i] != 0) {
tex_i = program->input_tex_map[i];
program->tex_map[tex_i] = program->tex_count +
i * program->sub_video_count +
context->input_index[i];
}
}
}
#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 Context *context,
bool monitor, bool output_only) {
#ifdef VIDEO_IN
update_inputs_tex_map(program, context);
#endif /* VIDEO_IN */
if (!output_only) {
glBindVertexArray(program->vertex_array[0]);
@@ -634,25 +940,39 @@ void shaders_compute(ShaderProgram *program, const SharedContext *context,
monitor ? program->frag_monitor_index
: program->frag_output_index,
true, context);
check_glerror(program, "shaders_compute");
}
void shaders_free(const ShaderProgram *program) {
for (unsigned int i = 0; i < program->frag_count; i++) {
glDeleteProgram(program->programs[i]);
}
check_glerror_ro("shaders_free/glDeleteProgram");
glDeleteShader(program->vertex_shader);
for (unsigned int i = 0; i < program->frag_count; i++) {
glDeleteShader(program->fragment_shaders[i]);
}
check_glerror_ro("shaders_free/glDeleteShader");
glDeleteFramebuffers(program->frag_count, program->frame_buffers);
check_glerror_ro("shaders_free/glDeleteFramebuffers");
glDeleteTextures(program->tex_count, program->textures);
check_glerror_ro("shaders_free/glDeleteTextures");
#ifdef VIDEO_IN
glDeleteTextures(program->in_count * program->sub_video_count,
program->textures + program->tex_count);
check_glerror_ro("shaders_free/glDeleteTextures");
#endif
glDeleteBuffers(1, &program->vertex_buffer);
check_glerror_ro("shaders_free/glDeleteBuffers");
}
void shaders_free_window(const ShaderProgram *program, bool secondary) {
glDeleteVertexArrays(1, &program->vertex_array[secondary ? 1 : 0]);
check_glerror_ro("shaders_free_window/glDeleteVertexArrays");
}
void shaders_free_input(const ShaderProgram *program,
const VideoCapture *input) {
if (!input->error && input->dma_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(program->egl_display, input->dma_image);
}
}
+15 -7
View File
@@ -4,20 +4,28 @@
#define SHADERS_H
void shaders_init(ShaderProgram *program, const Project *project,
const SharedContext *context, VideoCaptureArray *inputs,
bool rebind);
const Context *context, bool rebind);
#ifdef VIDEO_IN
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, unsigned int buffer_count);
void shaders_free_input(ShaderProgram *program, unsigned int input_index);
#endif /* VIDEO_IN */
void shaders_update(ShaderProgram *program, const File *fragment_shader,
unsigned int i, const Project *project);
void shaders_compute(ShaderProgram *program, const SharedContext *context,
void shaders_compute(ShaderProgram *program, const Context *context,
bool monitor, bool output_only);
void shaders_free(const ShaderProgram *program);
void shaders_free_window(const ShaderProgram *program, bool secondary);
void shaders_free_input(const ShaderProgram *program,
const VideoCapture *input);
#endif /* SHADERS_H */
#endif /* SHADERS_H */
-35
View File
@@ -1,35 +0,0 @@
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "types.h"
#include "shared.h"
static void *open_shared(const char *key, size_t size, int *fd) {
*fd = shm_open(key, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(*fd, size);
return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0);
}
static void close_shared(void *shared, size_t size, int fd) {
munmap(shared, size);
close(fd);
}
SharedContext *shared_init_context(const char *key) {
int shared_fd;
SharedContext *shared;
shared = open_shared(key, sizeof(SharedContext), &shared_fd);
shared->fd = shared_fd;
return shared;
}
void shared_close_context(SharedContext *shared) {
close_shared(shared, sizeof(SharedContext), shared->fd);
}
-9
View File
@@ -1,9 +0,0 @@
#include "types.h"
#ifndef SHARED_H
#define SHARED_H
SharedContext *shared_init_context(const char *key);
void shared_close_context(SharedContext *shared);
#endif /* SHARED_H */
+623 -358
View File
File diff suppressed because it is too large Load Diff
+11 -18
View File
@@ -5,26 +5,19 @@
void state_parse_config(StateConfig *state_config, const ConfigFile *config);
void state_apply_event(SharedContext *context, const StateConfig *state_config,
const MidiDevice *midi, unsigned char code,
unsigned char value, bool trace_midi);
void state_midi_event(Context *context, StateConfig state_config,
MidiDevice midi, unsigned char code,
unsigned char value, bool trace_midi);
bool state_background_write(SharedContext *context,
const StateConfig *state_config,
const MidiDevice *midi);
void state_key_event(Context *context, StateConfig state_config,
unsigned int code, MidiDevice midi);
void state_init(SharedContext *context, const StateConfig *state_config,
bool demo, bool auto_random, unsigned int base_tempo,
const char *state_file, bool load_state);
void *state_background_write(void *args);
void state_reset(SharedContext *context);
void state_init(Context *context, StateConfig state_config, bool demo,
bool auto_random, unsigned int auto_random_cycles,
unsigned int base_tempo, bool load_state);
void state_randomize(SharedContext *context, const StateConfig *state_config);
void state_save(const Context *context, StateConfig state_config);
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 */
#endif /* STATE_H */
+14 -6
View File
@@ -1,4 +1,3 @@
#include <bsd/string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -6,6 +5,8 @@
#include "config.h"
#include "string.h"
static bool is_digit(char c) { return c >= '0' && c <= '9'; }
unsigned int string_trim(char *str) {
// https://www.delftstack.com/howto/c/trim-string-in-c/
unsigned int start;
@@ -14,7 +15,7 @@ unsigned int string_trim(char *str) {
start = 0;
end = strnlen(str, STR_LEN) - 1;
if (end == 0) {
if (end <= 0) {
return 0;
}
@@ -37,8 +38,6 @@ unsigned int string_trim(char *str) {
return end - start + 1;
}
static bool is_digit(char c) { return c >= '0' && c <= '9'; }
bool string_is_number(const char *value) {
unsigned long value_len;
@@ -59,17 +58,26 @@ bool string_is_number(const char *value) {
char *string_replace_at(const char *src, unsigned int from, unsigned int to,
const char *rpl) {
unsigned long src_len, rpl_len;
unsigned long src_len;
unsigned long rpl_len;
char *dst;
if (to < from) {
return "";
}
src_len = strnlen(src, STR_LEN * STR_LEN);
rpl_len = strnlen(rpl, STR_LEN * STR_LEN);
dst = malloc(src_len - (to - from) + rpl_len + 1);
if (dst == NULL) {
return "";
}
strlcpy(dst, src, from + 1);
strlcpy(dst + from, rpl, rpl_len + 1);
strlcpy(dst + from + rpl_len, src + to, src_len - to + 1);
return dst;
}
}
+1 -1
View File
@@ -10,4 +10,4 @@ bool string_is_number(const char *value);
char *string_replace_at(const char *src, unsigned int from, unsigned int to,
const char *rpl);
#endif /* STRINGS_H */
#endif /* STRINGS_H */
+26 -20
View File
@@ -1,19 +1,13 @@
#include <math.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include "types.h"
#include "config.h"
#include "tempo.h"
static long now() {
struct timeval now;
gettimeofday(&now, NULL);
return now.tv_sec * 1000 + now.tv_usec / 1000;
}
static long now_ms() { return 1000 * clock() / CLOCKS_PER_SEC; }
static void reset_tap_chain(Tempo *tempo, long t) {
tempo->last_reset = t;
@@ -25,14 +19,6 @@ static void reset_tap_chain(Tempo *tempo, long t) {
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) {
return (tempo.last_tap + MAX_BEAT_LENGTH) > t &&
(tempo.last_tap + (tempo.beat_length * BEATS_UNTIL_CHAIN_RESET)) > t;
@@ -98,15 +84,35 @@ static void add_tap_to_chain(Tempo *tempo, long t) {
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_ms();
reset_tap_chain(tempo, t);
tempo->tempo = value;
tempo->beat_length = 60000.0 / value;
}
void tempo_set(Tempo *tempo, float value) {
long t;
long progress;
t = now_ms();
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) {
long t;
t = now();
t = now_ms();
if (!is_chain_active(*tempo, t)) {
reset_tap_chain(tempo, t);
@@ -118,11 +124,11 @@ void tempo_tap(Tempo *tempo) {
double tempo_total(const Tempo *tempo) {
long t;
t = now();
t = now_ms();
return (double)(t - tempo->last_reset) / (double)tempo->beat_length;
}
double tempo_progress(const Tempo *tempo, double modulo) {
return fmod(tempo_total(tempo), modulo);
}
}
+2 -2
View File
@@ -3,7 +3,7 @@
#ifndef TEMPO_H
#define TEMPO_H
void tempo_init(Tempo *tempo);
void tempo_init(Tempo *tempo, float value);
void tempo_tap(Tempo *tempo);
@@ -13,4 +13,4 @@ double tempo_total(const Tempo *tempo);
double tempo_progress(const Tempo *tempo, double modulo);
#endif /* TEMPO_H */
#endif /* TEMPO_H */
+10 -10
View File
@@ -1,4 +1,5 @@
#include <sys/time.h>
#include <limits.h>
#include <time.h>
#include "types.h"
@@ -7,27 +8,26 @@
void timer_init(Timer *timer, const unsigned int target) {
timer->counter = 0;
timer->target = target;
gettimeofday(&timer->start, NULL);
timer->start = clock();
}
bool timer_inc(Timer *timer) {
timer->counter += 1;
return timer->counter >= timer->target;
return timer->counter == UINT_MAX || timer->counter >= timer->target;
}
double timer_reset(Timer *timer) {
struct timeval stop;
double secs, per_secs;
clock_t stop;
double secs;
double per_secs;
gettimeofday(&stop, NULL);
stop = clock();
secs = (double)(stop.tv_usec - timer->start.tv_usec) / 1000000 +
(double)(stop.tv_sec - timer->start.tv_sec);
secs = (double)(stop - timer->start) / CLOCKS_PER_SEC;
per_secs = (double)timer->counter / secs;
timer->start = stop;
timer->counter = 0;
return per_secs;
}
}
+1 -1
View File
@@ -9,4 +9,4 @@ bool timer_inc(Timer *timer);
double timer_reset(Timer *timer);
#endif /* TIMER_H */
#endif /* TIMER_H */
+123 -67
View File
@@ -1,12 +1,13 @@
#include <GLFW/glfw3.h>
#include <alsa/asoundlib.h>
#ifdef VIDEO_IN
#include <glad/egl.h>
#include <linux/videodev2.h>
#endif /* VIDEO_IN */
#include <glad/gl.h>
#include <hashmap.h>
#include <linmath.h>
#include <linux/videodev2.h>
#include <stdbool.h>
#include <sys/time.h>
#include <time.h>
#include "config.h"
@@ -43,12 +44,17 @@ typedef struct Parameters {
float base_tempo;
bool demo;
bool auto_random;
unsigned int auto_random_cycle;
#ifdef VIDEO_IN
StringArray video_in;
unsigned int video_buffers;
unsigned int video_size;
bool video_reconnect;
#endif /* VIDEO_IN */
unsigned int internal_size;
char state_file[STR_LEN];
bool load_state;
bool save_state;
bool midi_reconnect;
bool trace_midi;
bool trace_fps;
} Parameters;
@@ -82,6 +88,7 @@ typedef struct ShaderProgram {
GLuint vertex_array[2];
unsigned int tex_count;
unsigned int tex_map[ARRAY_SIZE];
GLuint textures[ARRAY_SIZE];
unsigned int frag_count;
@@ -93,58 +100,46 @@ typedef struct ShaderProgram {
GLuint frame_buffers[ARRAY_SIZE];
GLuint fragment_shaders[ARRAY_SIZE];
GLuint itime_locations[ARRAY_SIZE];
GLuint itempo_locations[ARRAY_SIZE];
GLuint ibeats_locations[ARRAY_SIZE];
GLuint ifps_locations[ARRAY_SIZE];
GLuint ires_locations[ARRAY_SIZE];
GLuint itexres_locations[ARRAY_SIZE];
GLuint iinres_locations[ARRAY_SIZE];
GLuint iinfmt_locations[ARRAY_SIZE];
GLuint iinfps_locations[ARRAY_SIZE];
GLuint idemo_locations[ARRAY_SIZE];
GLuint iautorand_locations[ARRAY_SIZE];
GLuint iseed_locations[ARRAY_SIZE];
GLuint istate_locations[ARRAY_SIZE];
GLuint ipage_locations[ARRAY_SIZE];
GLuint iselected_locations[ARRAY_SIZE];
GLuint iactive_locations[ARRAY_SIZE];
GLint itime_locations[ARRAY_SIZE];
GLint itempo_locations[ARRAY_SIZE];
GLint ibeats_locations[ARRAY_SIZE];
GLint ifps_locations[ARRAY_SIZE];
GLint ires_locations[ARRAY_SIZE];
GLint itexres_locations[ARRAY_SIZE];
GLint iinres_locations[ARRAY_SIZE];
GLint iinfmt_locations[ARRAY_SIZE];
GLint iinfps_locations[ARRAY_SIZE];
GLint idemo_locations[ARRAY_SIZE];
GLint iautorand_locations[ARRAY_SIZE];
GLint iautorandcycle_locations[ARRAY_SIZE];
GLint iseed_locations[ARRAY_SIZE];
GLint istate_locations[ARRAY_SIZE];
GLint ipage_locations[ARRAY_SIZE];
GLint iselected_locations[ARRAY_SIZE];
GLint iactive_locations[ARRAY_SIZE];
UintArray midi_lengths;
GLuint imidi_locations[ARRAY_SIZE];
GLint igroup_locations[ARRAY_SIZE];
GLuint vpos_locations[ARRAY_SIZE];
GLint vpos_locations[ARRAY_SIZE];
GLuint textures_locations[ARRAY_SIZE];
GLint textures_locations[ARRAY_SIZE];
unsigned int sub_type_count;
unsigned int sub_variant_count;
GLuint sub_locations[ARRAY_SIZE];
GLint sub_locations[ARRAY_SIZE];
unsigned int active_count;
unsigned int in_count;
#ifdef VIDEO_IN
unsigned int sub_video_count;
unsigned int input_tex_map[MAX_VIDEO];
EGLDisplay egl_display;
EGLImageKHR dma_images[MAX_VIDEO];
#endif /* VIDEO_IN */
} ShaderProgram;
// video.c
typedef struct VideoCapture {
char name[STR_LEN];
bool error;
int fd;
int exp_fd;
unsigned int width;
unsigned int height;
unsigned int pixelformat;
unsigned int bytesperline;
bool output;
struct v4l2_buffer buf;
EGLImageKHR dma_image;
} VideoCapture;
typedef ARRAY(VideoCaptureArray, VideoCapture);
// window.c
typedef GLFWwindow Window;
@@ -164,15 +159,17 @@ typedef struct Tempo {
// context.c
typedef struct SharedContext {
typedef struct Context {
int fd;
vec2 resolution;
vec2 tex_resolution;
#ifdef VIDEO_IN
vec2 input_resolutions[MAX_VIDEO];
unsigned int input_formats[MAX_VIDEO];
unsigned int input_fps[MAX_VIDEO];
unsigned int input_index[MAX_VIDEO];
#endif /* VIDEO_IN */
double time;
unsigned int fps;
Tempo tempo;
double tempo_total;
UintArray state;
@@ -182,13 +179,60 @@ typedef struct SharedContext {
vec3 values[ARRAY_SIZE];
bool demo;
bool auto_random;
unsigned int auto_random_cycle;
unsigned int seeds[MAX_FRAG];
bool monitor;
unsigned int fps;
_Atomic bool stop;
} Context;
unsigned int input_formats[MAX_VIDEO];
unsigned int input_fps[MAX_VIDEO];
bool stop;
} SharedContext;
// video.c
#ifdef VIDEO_IN
typedef struct VideoCapture {
char name[STR_LEN];
_Atomic bool error;
_Atomic bool disconnected;
_Atomic bool needs_reload;
unsigned int buf_count;
unsigned int buf_index;
int fd;
int exp_fd[ARRAY_SIZE];
unsigned int width;
unsigned int height;
unsigned int pixelformat;
unsigned int bytesperline;
struct v4l2_buffer buf[ARRAY_SIZE];
} VideoCapture;
typedef struct VideoCaptureArray {
VideoCapture values[MAX_VIDEO];
unsigned int length;
} VideoCaptureArray;
typedef struct VideoBackgroundReadArgs {
VideoCapture *capture;
Context *context;
int input_index;
bool trace_fps;
} VideoBackgroundReadArgs;
#endif /* VIDEO_IN */
// midi.c
typedef struct MidiDevice {
_Atomic bool connected;
char name[STR_LEN];
snd_rawmidi_t *input;
snd_rawmidi_t *output;
} MidiDevice;
typedef struct MidiBackgroundListenArgs {
MidiDevice *device;
Context *context;
void (*event_callback)(unsigned char code, unsigned char value);
} MidiBackgroundListenArgs;
// state.c
@@ -198,24 +242,44 @@ typedef struct StateConfig {
UintArray select_page_codes;
UintArray select_item_codes;
UintArray select_frag_codes;
UintArray midi_active_counts;
UintArray midi_active_offsets;
UintArray midi_active_codes;
UintArray midi_counts;
UintArray midi_offsets;
UintArray midi_codes;
UintArray group_active_counts;
UintArray group_active_offsets;
UintArray group_active_codes;
UintArray group_counts;
UintArray group_offsets;
UintArray codes;
UintArray fader_codes;
UintArray values_offsets;
unsigned int value_count;
unsigned int tap_tempo_code;
char save_file_prefix[STR_LEN];
unsigned int key_randomize;
unsigned int key_reset;
unsigned int key_demo;
unsigned int key_autorand;
unsigned int key_autorand_up;
unsigned int key_autorand_down;
unsigned int key_tempo_up;
unsigned int key_tempo_down;
UintArray key_load;
UintArray key_save;
} StateConfig;
typedef struct StateBackgroundWriteArgs {
Context *context;
StateConfig state_config;
MidiDevice *midi;
} StateBackgroundWriteArgs;
// timer.c
typedef struct Timer {
struct timeval start;
clock_t start;
unsigned int counter;
unsigned int target;
} Timer;
@@ -224,6 +288,7 @@ typedef struct Timer {
typedef struct ConfigFile {
struct hashmap *map;
bool error;
} ConfigFile;
typedef struct ConfigFileItem {
@@ -231,15 +296,6 @@ typedef struct ConfigFileItem {
char value[STR_LEN];
} ConfigFileItem;
// midi.c
typedef struct MidiDevice {
bool error;
char name[STR_LEN];
snd_rawmidi_t *input;
snd_rawmidi_t *output;
} MidiDevice;
// project.c
typedef struct Project {
@@ -253,4 +309,4 @@ typedef struct Project {
File fragment_shaders[MAX_FRAG][MAX_SUB_FILE + 1];
} Project;
#endif /* TYPES_H */
#endif /* TYPES_H */
+181 -121
View File
@@ -1,10 +1,11 @@
#include <bsd/string.h>
#ifdef VIDEO_IN
#include <errno.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <log.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
@@ -15,6 +16,9 @@
#include "timer.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,
const char *default_msg) {
if (errno == EINVAL) {
@@ -66,15 +70,18 @@ static void ioctl_error(VideoCapture *video_capture, const char *operation,
video_capture->error = true;
}
static void open_device(VideoCapture *video_capture, const char *name) {
static void open_device(VideoCapture *video_capture, const char *name,
bool log_error) {
strlcpy(video_capture->name, name, STR_LEN);
video_capture->error = false;
video_capture->fd = -1;
video_capture->exp_fd = -1;
video_capture->buf_count = 0;
video_capture->fd = open(name, O_RDWR);
video_capture->fd = open(name, O_RDWR | O_NONBLOCK);
if (video_capture->fd == -1) {
log_warn("(%s) Cannot open device", name);
if (log_error) {
log_warn("(%s) Cannot open device", name);
}
video_capture->error = true;
}
}
@@ -114,7 +121,7 @@ static bool get_available_sizes(VideoCapture *video_capture,
index = 0;
fmt_enum.index = index;
fmt_enum.pixel_format = V4L2_PIX_FMT_YUYV;
fmt_enum.pixel_format = pixel_format;
found = false;
video_capture->width = 0;
@@ -146,7 +153,7 @@ static bool get_available_sizes(VideoCapture *video_capture,
memset(&fmt_enum, 0, sizeof(fmt_enum));
fmt_enum.index = ++index;
fmt_enum.pixel_format = V4L2_PIX_FMT_YUYV;
fmt_enum.pixel_format = pixel_format;
}
if (video_capture->height == 0) {
@@ -161,26 +168,18 @@ static bool get_available_sizes(VideoCapture *video_capture,
static bool set_format(VideoCapture *video_capture) {
struct v4l2_format fmt;
video_capture->output = false;
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.height = video_capture->height;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
fmt.fmt.pix.pixelformat = pixel_format;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) {
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
video_capture->output = true;
if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) {
ioctl_error(video_capture, "VIDIOC_S_FMT",
"Requested buffer type not supported");
return false;
}
ioctl_error(video_capture, "VIDIOC_S_FMT",
"Requested buffer type not supported");
return false;
}
video_capture->width = fmt.fmt.pix.width;
@@ -197,15 +196,15 @@ static bool set_format(VideoCapture *video_capture) {
return true;
}
static bool request_buffers(VideoCapture *video_capture) {
static bool request_buffers(VideoCapture *video_capture,
unsigned int buffer_count) {
struct v4l2_requestbuffers reqbuf;
memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT
: V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.type = buf_type;
reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = 1;
reqbuf.count = buffer_count;
if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
ioctl_error(video_capture, "VIDIOC_REQBUFS",
@@ -215,19 +214,24 @@ static bool request_buffers(VideoCapture *video_capture) {
log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count);
video_capture->buf_count = reqbuf.count;
for (unsigned int i = 0; i < reqbuf.count; i++) {
video_capture->exp_fd[i] = -1;
}
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;
video_capture->exp_fd = -1;
*fd = -1;
memset(&expbuf, 0, sizeof(expbuf));
expbuf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT
: V4L2_BUF_TYPE_VIDEO_CAPTURE;
expbuf.index = 0;
expbuf.type = buf_type;
expbuf.index = index;
expbuf.flags = O_RDONLY;
if (ioctl(video_capture->fd, VIDIOC_EXPBUF, &expbuf) == -1) {
@@ -237,12 +241,22 @@ static bool export_buffer(VideoCapture *video_capture) {
return false;
}
video_capture->exp_fd = expbuf.fd;
*fd = expbuf.fd;
return true;
}
static const enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
static bool export_buffers(VideoCapture *video_capture) {
unsigned int i;
for (i = 0; i < video_capture->buf_count; i++) {
if (!export_buffer(video_capture, &video_capture->exp_fd[i], i)) {
return false;
}
}
return true;
}
static bool open_stream(VideoCapture *video_capture) {
if (ioctl(video_capture->fd, VIDIOC_STREAMON, &buf_type) == -1) {
@@ -255,95 +269,130 @@ static bool open_stream(VideoCapture *video_capture) {
return true;
}
static void create_image_buffer(VideoCapture *video_capture) {
memset(&video_capture->buf, 0, sizeof(video_capture->buf));
static bool create_image_buffer(VideoCapture *video_capture,
struct v4l2_buffer *buf, unsigned int index) {
memset(buf, 0, sizeof(*buf));
video_capture->buf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT
: V4L2_BUF_TYPE_VIDEO_CAPTURE;
video_capture->buf.memory = V4L2_MEMORY_MMAP;
video_capture->buf.index = 0;
buf->type = buf_type;
buf->memory = V4L2_MEMORY_MMAP;
buf->index = index;
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf);
}
static void close_stream(const VideoCapture *video_capture) {
ioctl(video_capture->fd, VIDIOC_STREAMOFF, &buf_type);
}
void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height) {
open_device(video_capture, name);
if (video_capture->error) {
return;
}
if (!check_caps(video_capture)) {
return;
}
if (!get_available_sizes(video_capture, preferred_height)) {
return;
}
if (!set_format(video_capture)) {
return;
}
if (!request_buffers(video_capture)) {
return;
}
if (!export_buffer(video_capture)) {
return;
}
if (!open_stream(video_capture)) {
return;
}
create_image_buffer(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");
if (ioctl(video_capture->fd, VIDIOC_QBUF, buf) == -1) {
ioctl_error(video_capture, "VIDIOC_QBUF", "Could not enqueue buffer");
return false;
}
return true;
}
bool video_background_read(VideoCapture *video_capture, SharedContext *context,
int input_index, bool trace_fps) {
pid_t pid;
static bool create_image_buffers(VideoCapture *video_capture) {
unsigned int i;
for (i = 0; i < video_capture->buf_count; i++) {
if (!create_image_buffer(video_capture, &video_capture->buf[i], i)) {
return false;
}
}
return true;
}
static void close_stream(const VideoCapture *video_capture) {
ioctl(video_capture->fd, VIDIOC_STREAMOFF, &buf_type);
}
static unsigned int read_video(VideoCapture *video_capture) {
struct v4l2_capability cap;
if (ioctl(video_capture->fd, VIDIOC_DQBUF,
&video_capture->buf[video_capture->buf_index]) != -1) {
if (ioctl(video_capture->fd, VIDIOC_QBUF,
&video_capture->buf[video_capture->buf_index]) == -1) {
video_capture->error = true;
return false;
} else {
video_capture->buf_index =
(video_capture->buf_index + 1) % video_capture->buf_count;
return true;
}
}
if (ioctl(video_capture->fd, VIDIOC_QUERYCAP, &cap) == -1) {
video_capture->error = true;
}
return false;
}
void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height, unsigned int buffer_count,
bool log_error) {
open_device(video_capture, name, log_error);
if (video_capture->error) {
return;
}
if (!check_caps(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!get_available_sizes(video_capture, preferred_height)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!set_format(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!request_buffers(video_capture, buffer_count)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!export_buffers(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!open_stream(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!create_image_buffers(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
}
void *video_background_read(void *args) {
VideoBackgroundReadArgs *process_args = (VideoBackgroundReadArgs *)args;
VideoCapture *video_capture = process_args->capture;
Context *context = process_args->context;
int input_index = process_args->input_index;
bool trace_fps = process_args->trace_fps;
Timer timer;
double fps;
bool result;
pid = fork();
if (pid < 0) {
log_error("Could not create subprocess");
return false;
}
if (pid == 0) {
return true;
}
log_info("(%s) background acquisition started (pid: %d)", video_capture->name,
pid);
log_info("(%s) background acquisition started", video_capture->name);
timer_init(&timer, 30);
while (!context->stop && read_video(video_capture)) {
// repeat infinitely
if (timer_inc(&timer)) {
while (!context->stop && !video_capture->error) {
result = read_video(video_capture);
if (result && timer_inc(&timer)) {
fps = timer_reset(&timer);
context->input_fps[input_index] = (unsigned int)round(fps);
@@ -351,26 +400,37 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
log_trace("(%s) %.2ffps", video_capture->name, fps);
}
}
if (result) {
context->input_index[input_index] = video_capture->buf_index;
}
}
if (context->stop) {
log_info("(%s) background acquisition stopped by main thread (pid: %d)",
video_capture->name, pid);
log_info("(%s) background acquisition stopped by main thread",
video_capture->name);
} else {
log_info("(%s) background acquisition stopped after error (pid: %d)",
video_capture->name, pid);
log_info("(%s) background acquisition stopped after error",
video_capture->name);
video_capture->disconnected = true;
context->input_formats[input_index] = 0;
}
exit(context->stop ? EXIT_SUCCESS : EXIT_FAILURE);
return false;
free(process_args);
pthread_exit(NULL);
}
void video_free(const VideoCapture *video_capture) {
if (!video_capture->error) {
close_stream(video_capture);
}
if (video_capture->exp_fd != -1) {
close(video_capture->exp_fd);
unsigned int i;
for (i = 0; i < video_capture->buf_count; i++) {
if (video_capture->exp_fd[i] != -1) {
close(video_capture->exp_fd[i]);
}
}
if (video_capture->fd != -1) {
close_stream(video_capture);
close(video_capture->fd);
}
}
}
#endif /* VIDEO_IN */
+9 -5
View File
@@ -3,12 +3,16 @@
#ifndef VIDEO_H
#define VIDEO_H
void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height);
#ifdef VIDEO_IN
bool video_background_read(VideoCapture *video_capture, SharedContext *context,
int input_index, bool trace_fps);
void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height, unsigned int buffer_count,
bool log_error);
void *video_background_read(void *args);
void video_free(const VideoCapture *video_capture);
#endif /* VIDEO_H */
#endif /* VIDEO_IN */
#endif /* VIDEO_H */
+30 -8
View File
@@ -59,6 +59,9 @@ create_window(GLFWmonitor *monitor, const char *title, Window *shared_context,
// Context related hints
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
#ifdef GL_DEBUG
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
#endif
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// create fullscreen window in selected monitor
@@ -120,16 +123,18 @@ void window_events() { glfwPollEvents(); }
double window_get_time() { return glfwGetTime(); }
void window_use(Window *window, SharedContext *context) {
int width, height;
void window_use(Window *window, Context *context) {
int width;
int height;
glfwMakeContextCurrent(window);
glfwGetFramebufferSize(window, &width, &height);
context->resolution[0] = width;
context->resolution[1] = height;
context->tex_resolution[0] =
(int)(context->tex_resolution[1] * context->resolution[0] /
context->resolution[1]);
if (height > 0) {
context->tex_resolution[0] =
(int)(context->tex_resolution[1] * width / height);
}
}
void window_close(Window *window) {
@@ -145,6 +150,23 @@ bool window_escape_key(int key, int action) {
return key == GLFW_KEY_ESCAPE && action == GLFW_PRESS;
}
bool window_char_key(int key, int action, const int char_code) {
return key == char_code && action == GLFW_PRESS;
}
unsigned int window_read_key(int key, int action, int mods) {
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 = 1000 + key;
if ((mods & GLFW_MOD_SHIFT) > 0) {
result += 10000;
}
if ((mods & GLFW_MOD_CONTROL) > 0) {
result += 100000;
}
if ((mods & GLFW_MOD_ALT) > 0) {
result += 1000000;
}
return result;
}
+3 -3
View File
@@ -15,7 +15,7 @@ void window_update_title(Window *window, const char *title);
double window_get_time();
void window_use(Window *window, SharedContext *context);
void window_use(Window *window, Context *context);
void window_refresh(Window *window);
@@ -27,6 +27,6 @@ bool window_should_close(Window *window);
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 */