120 Commits

Author SHA1 Message Date
klemek f124cfacfb forge (steel) v1.2.1
Clang Build CI / run-no-video (push) Successful in 2m44s
Clang Build CI / build-release (push) Failing after 52s
Clang Build CI / run-video (push) Successful in 2m41s
Clang Lint CI / lint-no-video (push) Successful in 2m38s
Clang Lint CI / lint-video (push) Successful in 1m22s
2026-05-24 23:32:25 +02:00
klemek 4e14404726 docs: add projection mapping docs 2026-05-24 23:31:55 +02:00
klemek db77846f1b feat: default project up to 4 masks 2026-05-24 23:29:41 +02:00
klemek 57fa627bed forge (steel) v1.2.0
Clang Build CI / run-no-video (push) Successful in 1m8s
Clang Lint CI / lint-no-video (push) Successful in 1m7s
Clang Build CI / build-release (push) Successful in 1m48s
Clang Build CI / run-video (push) Successful in 1m13s
Clang Lint CI / lint-video (push) Successful in 1m55s
2026-05-21 00:43:02 +02:00
klemek 9dbfd34566 docs: update DEVELOPMENT.md 2026-05-21 00:42:42 +02:00
klemek 3dc2a77529 fix: same key multiple uses
Clang Lint CI / lint-no-video (push) Successful in 1m4s
Clang Build CI / run-video (push) Successful in 1m4s
Clang Build CI / run-no-video (push) Successful in 1m4s
Clang Build CI / build-release (push) Has been cancelled
Clang Lint CI / lint-video (push) Successful in 1m27s
2026-05-21 00:41:44 +02:00
klemek 7dbce62182 feat: ignore some values in auto random 2026-05-21 00:32:03 +02:00
klemek bb84350591 feat: default projection mapping with shift + M 2026-05-20 23:20:55 +02:00
klemek 7db7f4b89e Update README.md 2026-05-17 01:01:53 +02:00
klemek e5b2d2306f forge (steel) v1.1.3
Clang Build CI / run-no-video (push) Successful in 1m10s
Clang Lint CI / lint-no-video (push) Successful in 1m18s
Clang Build CI / build-release (push) Successful in 1m53s
Clang Build CI / run-video (push) Successful in 1m20s
Clang Lint CI / lint-video (push) Successful in 2m48s
2026-05-17 00:58:34 +02:00
klemek 54b166d33f fix: clock_gettime instead of clock
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-no-video (push) Successful in 1m14s
Clang Lint CI / lint-video (push) Successful in 1m16s
2026-05-17 00:57:59 +02:00
klemek 344029f195 fix: default video buffers to 1 2026-05-17 00:41:59 +02:00
klemek 4837ab2786 fix: on video disconnect reset all context resolution 2026-05-17 00:41:13 +02:00
klemek e38f57af46 feat: select fourcc and handle hw decoded
Clang Build CI / build-release (push) Failing after 54s
Clang Build CI / run-video (push) Successful in 1m12s
Clang Lint CI / lint-no-video (push) Successful in 1m12s
Clang Build CI / run-no-video (push) Successful in 1m17s
Clang Lint CI / lint-video (push) Successful in 4m33s
2026-05-17 00:40:22 +02:00
klemek e667c6b869 fix: default project src inputs 2026-05-16 21:42:01 +02:00
klemek 0b344eb52a fix: video input on both output and monitoring 2026-05-16 21:41:14 +02:00
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
83 changed files with 3796 additions and 1865 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
+3 -1
View File
@@ -24,6 +24,8 @@ pkg
forge-* forge-*
confdeps.* confdeps.*
conftest.* conftest.*
forge_saved_state.txt *.txt
error.glsl 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 run run project with test args
demo run project with demo mode demo run project with demo mode
valgrind valgrind analysis valgrind valgrind analysis
clean-release remove autoconf/automake files full-clean remove build files and untracked files
test-release try to build release test-release try to build release
release-% make full release of version % release-% make full release of version %
release-arch make arch-linux release package release-arch make arch-linux release package
@@ -20,7 +20,7 @@ release-arch make arch-linux release package
# make full build # make full build
make -f Makefile.dev release-1.0.0 make -f Makefile.dev release-1.0.0
# push release # push release
git push origin master --tags git push origin main --tags
# create release from tag on github # create release from tag on github
# attach .tar.gz to the github release # attach .tar.gz to the github release
make -f Makefile.dev release-arch make -f Makefile.dev release-arch
@@ -117,12 +117,23 @@ make -f Makefile.dev release-arch
- [x] Printable PDF of default scr/fx - [x] Printable PDF of default scr/fx
- [x] Add NanoKontrol setup file - [x] Add NanoKontrol setup file
- [x] Find and fix opengl errors 0500 ? - [x] Find and fix opengl errors 0500 ?
- [ ] Improvements - [ ] Extra features
- [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
- [x] 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 - [ ] Record show as text files
- [ ] Play from record text file - [ ] Play from record text file
- [ ] Key codes as inputs
- [ ] Mouse position and scroll as inputs
- [ ] Fixes - [ ] Fixes
- [ ] Try to write NanoKontrol config - [ ] Try to write NanoKontrol config
- [ ] Investigate video device fps loss (bad unregister ?) - [x] Investigate video device fps loss (bad unregister ?)
- explore libv4l directly [github](https://github.com/philips/libv4l) (with `-lv4l2`)
+6 -6
View File
@@ -1,10 +1,10 @@
AUTOMAKE_OPTIONS = foreign subdir-objects -Wall AUTOMAKE_OPTIONS = foreign subdir-objects -Wall
bin_PROGRAMS = forge bin_PROGRAMS = forge
forge_SOURCES = src/args.c src/arr.c src/config_file.c src/file.c src/forge.c src/main.c src/midi.c src/project.c src/rand.c src/shaders.c src/shared.c src/state.c src/string.c src/tempo.c src/timer.c src/video.c src/window.c $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/hashmap.c/hashmap.c $(top_srcdir)/log.c/src/log.c forge_SOURCES = src/args.c src/arr.c src/config_file.c src/file.c src/forge.c src/main.c src/midi.c src/project.c src/rand.c src/shaders.c src/state.c src/string.c src/tempo.c src/timer.c src/video.c src/window.c $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/hashmap.c/hashmap.c $(top_srcdir)/log.c/src/log.c
forge_CFLAGS = -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays -fno-exceptions -fopenmp -I$(top_srcdir)/include -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE -DLOG_USE_COLOR -DDATADIR=\"$(datadir)/$(PACKAGE)\" forge_CFLAGS = -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays -fno-exceptions -fopenmp -I$(top_srcdir)/include -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE -DLOG_USE_COLOR -DVIDEO_IN -DDATADIR=\"$(datadir)/$(PACKAGE)\"
forge_LDADD = -lm -lGL -lglfw -lasound -lbsd forge_LDADD = -lm -lGL -lglfw -lasound
include_HEADERS = src/args.h src/arr.h src/config.h src/config_file.h src/constants.h src/file.h src/forge.h src/main.h src/midi.h src/project.h src/rand.h src/shaders.h src/shared.h src/state.h src/string.h src/tempo.h src/timer.h src/types.h src/video.h src/window.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/include/linmath.h $(top_srcdir)/include/hashmap.h $(top_srcdir)/include/log.h include_HEADERS = src/args.h src/arr.h src/config.h src/config_file.h src/constants.h src/file.h src/forge.h src/main.h src/midi.h src/project.h src/rand.h src/shaders.h src/state.h src/string.h src/tempo.h src/timer.h src/types.h src/video.h src/window.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/include/linmath.h $(top_srcdir)/include/hashmap.h $(top_srcdir)/include/log.h
EXTRA_DIST = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuv.glsl EXTRA_DIST = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuyv.glsl
confdir = $(prefix)/share/$(PACKAGE) confdir = $(prefix)/share/$(PACKAGE)
conf_DATA = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuv.glsl conf_DATA = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuyv.glsl
+45 -40
View File
@@ -1,72 +1,78 @@
TARGET ?= forge TARGET ?= forge
INSTALL_DIR ?= $(HOME)/.local/bin 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 SHELL := /bin/bash
.PHONY: build .PHONY: build
clean: clean:
@rm -rf build @rm -rf build
build: build/$(TARGET):
@mkdir -p build @mkdir -p build
gcc \ gcc \
src/*.h src/*.c \ src/*.h src/*.c \
-Iinclude \ -Iinclude \
hashmap.c/hashmap.c \ hashmap.c/hashmap.c \
log.c/src/log.c \ log.c/src/log.c \
-lm -lGL -lglfw -lasound -lbsd \ -lm -lGL -lglfw -lasound \
-Wall -Wextra \ -Wall -Wextra \
-Wno-format-truncation \ -Wno-format-truncation \
-DGLFW_INCLUDE_NONE \ -DGLFW_INCLUDE_NONE \
-DGLFW_EXPOSE_NATIVE_EGL \ -DGLFW_EXPOSE_NATIVE_EGL \
-DGLFW_NATIVE_INCLUDE_NONE \ -DGLFW_NATIVE_INCLUDE_NONE \
-DLOG_USE_COLOR \ -DLOG_USE_COLOR \
-DVIDEO_IN \
-o build/$(TARGET) \ -o build/$(TARGET) \
-g -Og -g -Og
.PHONY: run .PHONY: build
run: build build: build/$(TARGET)
./build/$(TARGET) $(TEST_ARGS) --monitor-only --internal-size=480 --video-size=240 --hot-reload
.PHONY: demo .PHONY: build-no-video
demo: build build-no-video:
./build/$(TARGET) $(TEST_ARGS) --demo @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 .PHONY: sample
sample: build sample: build/$(TARGET)
./build/$(TARGET) --project=sample ./build/$(TARGET) --project=sample $(RUN_ARGS)
.PHONY: valgrind .PHONY: valgrind
valgrind: build valgrind: build/$(TARGET)
valgrind \ valgrind \
--show-realloc-size-zero=no \ --show-realloc-size-zero=no \
--undef-value-errors=no \ --undef-value-errors=no \
./build/$(TARGET) $(TEST_ARGS) ./build/$(TARGET) $(RUN_ARGS)
.PHONY: clean-release .PHONY: full-clean
clean-release: full-clean:
@rm -rf \ git clean -f -x
autom4te.cache \ rm -rf */*/.deps
aclocal.m4 \ rm -rf */.deps
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: test-release .PHONY: test-release
test-release: clean clean-release test-release: clean full-clean
aclocal aclocal
autoconf autoconf
automake --add-missing automake --add-missing
@@ -76,8 +82,8 @@ test-release: clean clean-release
cp $(TARGET)-steel-*.tar.gz build/ cp $(TARGET)-steel-*.tar.gz build/
.PHONY: release-% .PHONY: release-%
release-%: clean clean-release release-%: clean full-clean
git pull origin master git pull origin main
sed -i -E "s/[0-9]+\\.[0-9]+\\.[0-9]+/$*/g" configure.ac sed -i -E "s/[0-9]+\\.[0-9]+\\.[0-9]+/$*/g" configure.ac
aclocal aclocal
autoconf 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 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 add configure.ac PKGBUILD
git commit -am "forge (steel) v$*" git commit -am "forge (steel) v$*"
git tag v$* -m "forge (steel) v$*" git tag v$* -m "FORGE steel-$*"
@echo "Push release: git push origin master --tags" @echo "Push release: git push origin main --tags"
@echo "Rollback release: git reset HEAD~1 --hard && git tag -d v$*" @echo "Rollback release: git reset HEAD~1 --hard && git tag -d v$*"
@@ -100,4 +106,3 @@ release-arch: clean
mkdir -p build mkdir -p build
cp PKGBUILD build cp PKGBUILD build
cd build && makepkg cd build && makepkg
+4 -4
View File
@@ -1,12 +1,12 @@
pkgname=forge-steel pkgname=forge-steel
pkgver=1.0.1 pkgver=1.2.1
pkgrel=1 pkgrel=1
pkgdesc="Fusion Of Real Time Generative Effects" pkgdesc="Fusion Of Real Time Generative Effects"
arch=('i686' 'pentium4' 'x86_64' 'arm' 'armv7h' 'armv6h' 'aarch64' 'riscv64') 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') depends=('glfw>=1:3', 'v4l-utils>=1.32', 'alsa-lib>=1.2', 'libglvnd>=1.7')
url="https://github.com/klemek/forge-steel" url="https://git.klemek.fr/klemek/forge-steel"
source=("${pkgname}-steel-${pkgver}.tar.gz::https://github.com/klemek/forge-steel/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz") source=("${pkgname}-steel-${pkgver}.tar.gz::https://git.klemek.fr/klemek/forge-steel/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
sha256sums=('b2345c1a87f6b5b13dcce6a237a3f9a9ddb7fa9c3e982f5e164e7d7fef5725f3') sha256sums=('57559bde7a524e3c9e70de4bc9b675a5a086590a8d85697cebd80c0ebd09f149')
srcdir=build srcdir=build
backup=("usr/share/${pkgname}") backup=("usr/share/${pkgname}")
+93 -32
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) [![](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.6k-blue?style=flat-square)
[![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)
<!-- omit from toc --> <!-- omit from toc -->
# F.O.R.G.E. (Steel) # F.O.R.G.E. (Steel)
@@ -83,6 +82,7 @@ Here are some pointers if you want to customize your FORGE experience:
- [My nanoKontrol2 is acting strange](#my-nanokontrol2-is-acting-strange) - [My nanoKontrol2 is acting strange](#my-nanokontrol2-is-acting-strange)
- [How do I report a bug?](#how-do-i-report-a-bug) - [How do I report a bug?](#how-do-i-report-a-bug)
- [Help I got low FPS on my video device](#help-i-got-low-fps-on-my-video-device) - [Help I got low FPS on my video device](#help-i-got-low-fps-on-my-video-device)
- [My video feed got strange lines](#my-video-feed-got-strange-lines)
- [How do I change the default project built-in sentences?](#how-do-i-change-the-default-project-built-in-sentences) - [How do I change the default project built-in sentences?](#how-do-i-change-the-default-project-built-in-sentences)
## What is FORGE ? ## What is FORGE ?
@@ -116,11 +116,10 @@ Here's a quick rundown of the process:
| libGL | libgl-dev | extra/libglvnd | | libGL | libgl-dev | extra/libglvnd |
| libasound | libasound2-dev | extra/alsa-lib | | libasound | libasound2-dev | extra/alsa-lib |
| libv4l2 | libv4l-dev | extra/v4l-utils | | libv4l2 | libv4l-dev | extra/v4l-utils |
| libbsd | libbsd-dev | extra/libbsd |
### From release ### From release
See [Releases](https://github.com/klemek/forge-steel/releases) See [Releases](https://git.klemek.fr/klemek/forge-steel/releases)
```shell ```shell
tar xvzf forge-steel-x.y.z.tar.gz tar xvzf forge-steel-x.y.z.tar.gz
@@ -133,7 +132,7 @@ make install
### From repository (PKGBUILD) ### From repository (PKGBUILD)
```shell ```shell
git clone --recursive https://github.com/klemek/forge-steel git clone --recursive https://git.klemek.fr/klemek/forge-steel
cd forge cd forge
makepkg -si makepkg -si
``` ```
@@ -142,7 +141,7 @@ makepkg -si
### From repository (dev version) ### From repository (dev version)
```shell ```shell
git clone --recursive https://github.com/klemek/forge-steel git clone --recursive https://git.klemek.fr/klemek/forge-steel
cd forge cd forge
aclocal aclocal
autoconf autoconf
@@ -158,23 +157,33 @@ make install
When running, the following hotkeys are available: When running, the following hotkeys are available:
* <kbd>Esc</kbd>: Exit window | Hotkey | Function |
* <kbd>R</kbd>: Randomize internal values | ------ | -------- |
* <kbd>0</kbd>: Reset internal values to 0 | <kbd>Esc</kbd> | Exit FORGE |
* <kbd>D</kbd>: Demo mode On/Off | <kbd>R</kbd> | Randomize internal values |
* <kbd>A</kbd>: Auto Random mode On/Off | <kbd>Shift</kbd> + <kbd>R</kbd> | Reset internal values to 0 |
| <kbd>D</kbd> | Demo mode On/Off |
| <kbd>A</kbd> | Auto Random mode On/Off |
| <kbd>&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 ### CLI arguments
```txt ```txt
usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-v=FILE] [-vs=SIZE] [-is=SIZE] [-sf=STATE_PATH] [-ls / -nls] [-ss / -nss] [-tm] [-tf] forge steel-dev
usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-arc=CYCLES] [-vi=FILE] [-vs=SIZE] [-vb=COUNT] [-vr / -nvr] [-vf=FOURCC] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-mr / -nmr] [-tm] [-tf]
Fusion Of Real-time Generative Effects. Fusion Of Real-time Generative Effects.
options: options:
-h, --help show this help message and exit -h, --help show this help message and exit
-v, --version print version -v, --version print version
-p, --project forge project directory (default: /usr/share/forge/default) -p, --project forge project directory (default: ./default)
-c, --config config file name (default: forge_project.cfg) -c, --config config file name (default: forge_project.cfg)
-hr, --hot-reload hot reload of shaders scripts -hr, --hot-reload hot reload of shaders scripts
-s, --screen output screen number (default: primary) -s, --screen output screen number (default: primary)
@@ -183,16 +192,22 @@ options:
-w, --windowed not fullscreen -w, --windowed not fullscreen
-t, --tempo base tempo (default: 60) -t, --tempo base tempo (default: 60)
-d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random) -d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random)
-ar, --auto-random randomize state every 4 beats -ar, --auto-random randomize state every cycle (4 beats)
-nar, --no-auto-random do not randomize state (default) -nar, --no-auto-random do not randomize state (default)
-v, --video-in path to video capture device (multiple allowed) -arc, --auto-random-cycle auto random cycle length (default: 4)
-vi, --video-in path to video capture device (multiple allowed)
-vb, --video-buffers number of video buffers to use (default: 1)
-vs, --video-size video capture desired height (default: internal texture height) -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
-vf, --video-fourcc video codec fourcc (default: YUYV)
-is, --internal-size internal texture height (default: 720) -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) -ls, --load-state load saved state (default)
-nls, --no-load-state do not load saved state -nls, --no-load-state do not load saved state
-ss, --save-state save state (default) -ss, --save-state save state (default)
-nss, --no-save-state do not save state -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 -tm, --trace-midi print midi code and values
-tf, --trace-fps print fps status of subsystems -tf, --trace-fps print fps status of subsystems
``` ```
@@ -233,7 +248,7 @@ Working with pages and items, you can use the following predefined sources and e
| **1** | **0** | Feedback + Thru | _Hue_ | _Saturation_ | _Light_ | Thru | _Hue_ | _Saturation_ | _Light_ | | **1** | **0** | Feedback + Thru | _Hue_ | _Saturation_ | _Light_ | Thru | _Hue_ | _Saturation_ | _Light_ |
| | **1** | Lines | _Thick. / Dezoom_ | _Rotation_ | _Distortion_ | Feedback + Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ | | | **1** | Lines | _Thick. / Dezoom_ | _Rotation_ | _Distortion_ | Feedback + Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
| | **2** | Dots | _Zoom_ | _Rotation_ | _Lens_ | Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ | | | **2** | Dots | _Zoom_ | _Rotation_ | _Lens_ | Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
| | **3** | Waves | _Spacing_ | _Thickness_ | _Vert. Scroll (R)_ | Colorize | _Black Color_ | _White Color_ | _Shift_ | | | **3** | Bacteria | _Zoom_ | _Details_ | _Delta details_ | Colorize | _Black Color_ | _White Color_ | _Shift_ |
| | **4** | Noise | _Zoom_ | _Voronoi dist._ | _Details_ | Quantize | _Pixel Size_ | _Bit Depth_ | _Blur_ | | | **4** | Noise | _Zoom_ | _Voronoi dist._ | _Details_ | Quantize | _Pixel Size_ | _Bit Depth_ | _Blur_ |
| **2** | **5** | Video In 1 + Thru | _Hue_ | _Saturation_ | _Light_ | Dithering | _Pixel Size_ | _Bit Depth_ | _Blur_ | | **2** | **5** | Video In 1 + Thru | _Hue_ | _Saturation_ | _Light_ | Dithering | _Pixel Size_ | _Bit Depth_ | _Blur_ |
| | **6** | CP437 | _Zoom_ | _Charset_ | _Char. Delta_ | TV | _Lens_ | _Horz. Noise_ | _Dezoom_ | | | **6** | CP437 | _Zoom_ | _Charset_ | _Char. Delta_ | TV | _Lens_ | _Horz. Noise_ | _Dezoom_ |
@@ -248,6 +263,28 @@ Working with pages and items, you can use the following predefined sources and e
See the [printable version](./docs/forge_default_mapping.pdf). See the [printable version](./docs/forge_default_mapping.pdf).
### Available hotkeys
| Hotkey | Function |
| ------ | -------- |
| <kbd>Shift</kbd> + <kbd>F</kbd> | Switch between shader-decoded or hardware decoded YUYV |
| <kbd>M</kbd> | Projection mapping 1 |
| <kbd>Shift</kbd> + <kbd>M</kbd> | Projection mapping 2 |
| <kbd>Ctrl</kbd> + <kbd>M</kbd> | Projection mapping 3 |
| <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>M</kbd> | Projection mapping 4 |
### Projection Mappings
In any of the projection mapping mode, use the nanoKONTROL2 last 4 columns to control 4 on-screen points:
| Midi Control | Function |
| ------ | -------- |
| Fader N | point N - X position |
| Knob N | point N - Y position |
| Last column top button | activate projection mapping |
| Last column middle button | invert projection mapping |
| Last column bottom button | show projection borders |
## Making your own FORGE project ## Making your own FORGE project
You want to embrace the "user" in "user-defined"? It's time to make your own project. You want to embrace the "user" in "user-defined"? It's time to make your own project.
@@ -269,16 +306,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) * [sample/forge_project.cfg](./sample/forge_project.cfg) (beginner oriented)
* [default/forge_project.cfg](./default/forge_project.cfg) (more complete) * [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: Each group has the following properties:
* A number of layers with `MIDI_X_ACTIVE_COUNT` (default: `1`) * A number of layers with `GROUP_X_ACTIVE_COUNT` (default: `1`)
* Each midi code controlling how to change the active layer with `MIDI_X_ACTIVE_Y` * Each midi/keyboard code controlling how to change the active layer with `GROUP_X_ACTIVE_Y`
* A number of codes with `MIDI_X_COUNT` * A number of codes with `GROUP_X_COUNT`
* Each midi code controlling the active layer with `MIDI_X_Y` (as a `vec3`: `_X` / `_Y` / `_Z`) * Each midi/keyboard code controlling the active layer with `GROUP_X_Y` (as a `vec3`: `_X` / `_Y` / `_Z`)
#### States #### States
@@ -286,9 +335,9 @@ FORGE allows to define a "state" to a fragment shader.
This combines several parameters: This combines several parameters:
* `SELECT_PAGE_COUNT` (default: `1`) + `SELECT_PAGE_X`: define midi codes for pages of item. * `SELECT_PAGE_COUNT` (default: `1`) + `SELECT_PAGE_X`: define midi/keyboard codes for pages of item.
* `SELECT_ITEM_COUNT` + `SELECT_ITEM_X`: define midi codes for items per page. * `SELECT_ITEM_COUNT` + `SELECT_ITEM_X`: define midi/keyboard codes for items per page.
* `SELECT_FRAG_X`: define midi codes to "select" a fragment shader. * `SELECT_FRAG_X`: define midi/keyboard codes to "select" a fragment shader.
The selected fragment shader will have its state updated with either: The selected fragment shader will have its state updated with either:
@@ -329,8 +378,8 @@ uniform float iTime; // the current time
uniform sampler2D iTex0; // texture 1 (0-based) uniform sampler2D iTex0; // texture 1 (0-based)
uniform sampler2D iTex9; // texture 10 uniform sampler2D iTex9; // texture 10
uniform int iSeed1; uniform int iSeed1;
uniform vec3 iMidi2_3[7]; // midi group 2, layer 3, size 7 uniform vec3 iGroup2_3[7]; // midi group 2, layer 3, size 7
uniform vec3 iMidi3_1[2]; uniform vec3 iGroup3_1[2];
``` ```
#### Working with `#include` #### Working with `#include`
@@ -446,11 +495,11 @@ FORGE (steel) describe the linux version.
Verify you have the correct [requirements](#requirements) installed. 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 ### 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. I'll try to answer and update the README.
### My nanoKontrol2 is acting strange ### My nanoKontrol2 is acting strange
@@ -461,16 +510,28 @@ Use the [KORG KONTROL Editor](https://www.korg.com/us/support/download/software/
### How do I report a bug? ### 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.). Don't forget to add all information available to your bug (version, operating system, etc.).
### Help I got low FPS on my video device ### Help I got low FPS on my video device
There's already an [open issue](https://github.com/klemek/forge-steel/issues/1) on this subject. Unfortunately, V4L2 is very slow compared to driver-specific decoding.
You can check your device real FPS on [V4L2 UCP](https://github.com/HedgeHawk/v4l2ucp) or [GTK UVC Viewer](https://github.com/jaswdr/guvcview).
### My video feed got strange lines
You may need to decode the [V4L2 YUYV format](https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-yuyv.html).
The code is available in the default project [default/inc_yuyv.glsl](./default/inc_yuyv.glsl)
### How do I change the default project built-in sentences? ### How do I change the default project built-in sentences?
The sentences are defined in [default/inc_sentences.glsl](./default/inc_sentences.glsl). The sentences are defined in [default/inc_sentences.glsl](./default/inc_sentences.glsl).
The script [scripts/sentences.py](./scripts/sentences.py) can help you update them. The script [scripts/sentences.py](./scripts/sentences.py) can help you update them.
### My video device keeps changing ID each time it's unplugged
You should [bind your device to a fixed interface](https://linuxvox.com/blog/linux-bind-camera-to-fixed-devvideo/).
+3
View File
@@ -2,3 +2,6 @@
-DGLFW_INCLUDE_NONE -DGLFW_INCLUDE_NONE
-DGLFW_EXPOSE_NATIVE_EGL -DGLFW_EXPOSE_NATIVE_EGL
-DGLFW_NATIVE_INCLUDE_NONE -DGLFW_NATIVE_INCLUDE_NONE
-DVIDEO_IN
-DEGL_DEBUG
-DGL_DEBUG
+2 -4
View File
@@ -1,4 +1,4 @@
AC_INIT([forge], [steel-1.0.1], [klemek.dev@proton.me]) AC_INIT([forge], [steel-1.2.1], [klemek.dev@proton.me])
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AC_PROG_CC AC_PROG_CC
@@ -11,7 +11,6 @@ AC_CHECK_HEADERS([stdlib.h])
AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([sys/ioctl.h])
AC_CHECK_HEADERS([sys/mman.h]) AC_CHECK_HEADERS([sys/mman.h])
AC_CHECK_HEADERS([sys/stat.h]) AC_CHECK_HEADERS([sys/stat.h])
AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_HEADERS([sys/types.h]) AC_CHECK_HEADERS([sys/types.h])
AC_CHECK_HEADERS([sys/wait.h]) AC_CHECK_HEADERS([sys/wait.h])
@@ -22,8 +21,7 @@ AC_CHECK_HEADERS([math.h])
AC_CHECK_HEADERS([string.h]) AC_CHECK_HEADERS([string.h])
AC_CHECK_HEADERS([time.h]) AC_CHECK_HEADERS([time.h])
AC_CHECK_HEADERS([unistd.h]) AC_CHECK_HEADERS([unistd.h])
AC_CHECK_HEADERS([pthread.h])
AC_CHECK_HEADERS([bsd/string.h])
AC_CHECK_HEADERS([linux/videodev2.h]) AC_CHECK_HEADERS([linux/videodev2.h])
+203 -67
View File
@@ -6,7 +6,7 @@
# (shaders, video devices, textures, midi inputs, etc.) # (shaders, video devices, textures, midi inputs, etc.)
# Every number based constant will be "one-based" (1,2,3,etc.) # Every number based constant will be "one-based" (1,2,3,etc.)
# To read more, go to # To read more, go to
# https://github.com/klemek/forge-steel # https://git.klemek.fr/klemek/forge-steel
# ================ # ================
@@ -37,6 +37,8 @@ UNIFORM_IN_FPS_PREFIX=iInputFPS
UNIFORM_DEMO=iDemo UNIFORM_DEMO=iDemo
# 0/1 if auto random # 0/1 if auto random
UNIFORM_AUTORAND=iAutoRand UNIFORM_AUTORAND=iAutoRand
# auto random cycle length
UNIFORM_AUTORANDCYCLE=iAutoRandCycle
# Current page # Current page
UNIFORM_PAGE=iPage UNIFORM_PAGE=iPage
# Current selected shader # Current selected shader
@@ -62,8 +64,8 @@ UNIFORM_IN_RESOLUTION_PREFIX=iInputResolution
# --- uniform vec3 --- # --- uniform vec3 ---
# Midi group X layer Y (beware of group size) # Midi group X layer Y (beware of group size)
# Injected as "iMidiX_Y[Z]" # Injected as "iGroupX_Y[Z]"
UNIFORM_MIDI_PREFIX=iMidi UNIFORM_GROUP_PREFIX=iGroup
# --- uniform sampler2D --- # --- uniform sampler2D ---
@@ -91,7 +93,7 @@ SUB_2_PREFIX=fx_
# Total number of internal textures # Total number of internal textures
TEX_COUNT=10 TEX_COUNT=12
# === VIDEO DEVICES # === VIDEO DEVICES
# Video devices will be read from CLI arguments # Video devices will be read from CLI arguments
@@ -105,7 +107,6 @@ IN_2_OUT=2
# === FRAGMENT SHADERS # === FRAGMENT SHADERS
# Fragment shaders will be read from the CLI directory as "fragX.glsl" # Fragment shaders will be read from the CLI directory as "fragX.glsl"
# Special shader "frag0.glsl" will be prepend to each one
# Prefix of fragment shaders to detect # Prefix of fragment shaders to detect
FRAG_FILE_PREFIX=frag FRAG_FILE_PREFIX=frag
@@ -128,10 +129,17 @@ FRAG_OUTPUT=9
FRAG_MONITOR=10 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 # The recognized ALSA name of the midi device
MIDI_HW=hw:CARD=nanoKONTROL2 MIDI_HW=hw:CARD=nanoKONTROL2
@@ -187,8 +195,8 @@ SELECT_ITEM_3=42
SELECT_ITEM_4=41 SELECT_ITEM_4=41
SELECT_ITEM_5=45 SELECT_ITEM_5=45
# === MIDI INPUT STATES # === GROUP INPUT STATES
# Midi inputs will control FORGE's state as follows # Inputs will control FORGE's state as follows
# X groups of Y layers sized Z # X groups of Y layers sized Z
# You can manipulate only 1 layer at a time # You can manipulate only 1 layer at a time
# Every layer of every groups will be send as uniforms # Every layer of every groups will be send as uniforms
@@ -196,69 +204,197 @@ SELECT_ITEM_5=45
# with the same codes for nice display # with the same codes for nice display
# Total number of groups # Total number of groups
MIDI_COUNT=3 GROUP_COUNT=3
# Total number of layers of group 1 # 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 codes to change layer of group 1
MIDI_1_ACTIVE_1=32 GROUP_1_ACTIVE_1=32
MIDI_1_ACTIVE_2=64 GROUP_1_ACTIVE_2=64
# Size of group 1 # Size of group 1
MIDI_1_COUNT=6 GROUP_1_COUNT=6
# Every code of active layer manipulation of group 1 # Every code of active layer manipulation of group 1
MIDI_1_1_X=33 GROUP_1_1_X=33
MIDI_1_1_Y=49 GROUP_1_1_Y=49
MIDI_1_1_Z=65 GROUP_1_1_Z=65
MIDI_1_2_X=1 GROUP_1_2_X=1
MIDI_1_2_Y=17 GROUP_1_2_Y=17
MIDI_1_2_Z= GROUP_1_2_Z=
MIDI_1_3_X=34 GROUP_1_3_X=34
MIDI_1_3_Y=50 GROUP_1_3_Y=50
MIDI_1_3_Z=66 GROUP_1_3_Z=66
MIDI_1_4_X=2 GROUP_1_4_X=2
MIDI_1_4_Y=18 GROUP_1_4_Y=18
MIDI_1_4_Z= GROUP_1_4_Z=
MIDI_1_5_X=35 GROUP_1_5_X=35
MIDI_1_5_Y=51 GROUP_1_5_Y=51
MIDI_1_5_Z=67 GROUP_1_5_Z=67
MIDI_1_6_X=3 GROUP_1_6_X=3
MIDI_1_6_Y=19 GROUP_1_6_Y=19
MIDI_1_6_Z= GROUP_1_6_Z=
# Same for group 2 # Same for group 2
MIDI_2_ACTIVE_COUNT=3 GROUP_2_ACTIVE_COUNT=7
MIDI_2_ACTIVE_1=36 GROUP_2_ACTIVE_1=36
MIDI_2_ACTIVE_2=68 GROUP_2_ACTIVE_2=68
MIDI_2_ACTIVE_3=52 GROUP_2_ACTIVE_3=52
MIDI_2_COUNT=7 GROUP_2_ACTIVE_4=1077
MIDI_2_1_X=37 GROUP_2_ACTIVE_5=11077
MIDI_2_1_Y=53 GROUP_2_ACTIVE_6=101077
MIDI_2_1_Z=69 GROUP_2_ACTIVE_7=111077
MIDI_2_2_X=5 GROUP_2_COUNT=7
MIDI_2_2_Y=21 GROUP_2_1_X=37
MIDI_2_2_Z= GROUP_2_1_Y=53
MIDI_2_3_X=38 GROUP_2_1_Z=69
MIDI_2_3_Y=54 GROUP_2_2_X=5
MIDI_2_3_Z=70 GROUP_2_2_Y=21
MIDI_2_4_X=6 GROUP_2_2_Z=
MIDI_2_4_Y=22 GROUP_2_3_X=38
MIDI_2_4_Z= GROUP_2_3_Y=54
MIDI_2_5_X=39 GROUP_2_3_Z=70
MIDI_2_5_Y=55 GROUP_2_4_X=6
MIDI_2_5_Z=71 GROUP_2_4_Y=22
MIDI_2_6_X=7 GROUP_2_4_Z=
MIDI_2_6_Y=23 GROUP_2_5_X=39
MIDI_2_6_Z= GROUP_2_5_Y=55
MIDI_2_7_X=4 GROUP_2_5_Z=71
MIDI_2_7_Y=20 GROUP_2_6_X=7
MIDI_2_7_Z=59 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 # Same for group 3
MIDI_3_COUNT=2 GROUP_3_COUNT=2
MIDI_3_1_X=48 GROUP_3_1_X=48
MIDI_3_1_Y=58 GROUP_3_1_Y=58
MIDI_3_1_Z= GROUP_3_1_Z=
MIDI_3_2_X=0 GROUP_3_2_X=0
MIDI_3_2_Y=16 GROUP_3_2_Y=16
MIDI_3_2_Z= GROUP_3_2_Z=11089
# Auto-Random Ignore (ARI) prefixes
ARI_COUNT=62
ARI_1=GROUP_3_1_Y
ARI_2=GROUP_3_2_Z
ARI_3=GROUP_2_5_4
ARI_4=GROUP_2_5_4
ARI_5=GROUP_2_5_4
ARI_6=GROUP_2_2_X_4
ARI_7=GROUP_2_2_Y_4
ARI_8=GROUP_2_2_Z_4
ARI_9=GROUP_2_4_X_4
ARI_10=GROUP_2_4_Y_4
ARI_11=GROUP_2_4_Z_4
ARI_12=GROUP_2_6_X_4
ARI_13=GROUP_2_6_Y_4
ARI_14=GROUP_2_6_Z_4
ARI_15=GROUP_2_7_X_4
ARI_16=GROUP_2_7_Y_4
ARI_17=GROUP_2_7_Z_4
ARI_18=GROUP_2_5_5
ARI_19=GROUP_2_5_5
ARI_20=GROUP_2_5_5
ARI_21=GROUP_2_2_X_5
ARI_22=GROUP_2_2_Y_5
ARI_23=GROUP_2_2_Z_5
ARI_24=GROUP_2_4_X_5
ARI_25=GROUP_2_4_Y_5
ARI_26=GROUP_2_4_Z_5
ARI_27=GROUP_2_6_X_5
ARI_28=GROUP_2_6_Y_5
ARI_29=GROUP_2_6_Z_5
ARI_30=GROUP_2_7_X_5
ARI_31=GROUP_2_7_Y_5
ARI_32=GROUP_2_7_Z_5
ARI_33=GROUP_2_5_6
ARI_34=GROUP_2_5_6
ARI_35=GROUP_2_5_6
ARI_36=GROUP_2_2_X_6
ARI_37=GROUP_2_2_Y_6
ARI_38=GROUP_2_2_Z_6
ARI_39=GROUP_2_4_X_6
ARI_40=GROUP_2_4_Y_6
ARI_41=GROUP_2_4_Z_6
ARI_42=GROUP_2_6_X_6
ARI_43=GROUP_2_6_Y_6
ARI_44=GROUP_2_6_Z_6
ARI_45=GROUP_2_7_X_6
ARI_46=GROUP_2_7_Y_6
ARI_47=GROUP_2_7_Z_6
ARI_48=GROUP_2_5_7
ARI_49=GROUP_2_5_7
ARI_50=GROUP_2_5_7
ARI_51=GROUP_2_2_X_7
ARI_52=GROUP_2_2_Y_7
ARI_53=GROUP_2_2_Z_7
ARI_54=GROUP_2_4_X_7
ARI_55=GROUP_2_4_Y_7
ARI_56=GROUP_2_4_Z_7
ARI_57=GROUP_2_6_X_7
ARI_58=GROUP_2_6_Y_7
ARI_59=GROUP_2_6_Z_7
ARI_60=GROUP_2_7_X_7
ARI_61=GROUP_2_7_Y_7
ARI_62=GROUP_2_7_Z_7
# =====
# 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
+6 -2
View File
@@ -8,15 +8,19 @@
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
#include inc_yuv.glsl #include inc_yuyv.glsl
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform sampler2D iTex1; uniform sampler2D iTex1;
uniform sampler2D iTex3;
uniform int iInputFormat1; uniform int iInputFormat1;
uniform vec2 iInputResolution1; uniform vec2 iInputResolution1;
uniform vec3 iGroup3_1[2];
void main() { void main() {
if (iInputFormat1 == YUYV_FOURCC) { if (iGroup3_1[1].z > 0) {
fragColor = texture(iTex1, vUV * vec2(1, -1));
} else if (iInputFormat1 == YUYV_FOURCC) {
fragColor = yuyvTex(iTex1, vUV, int(iInputResolution1.x)); fragColor = yuyvTex(iTex1, vUV, int(iInputResolution1.x));
} else { } else {
fragColor = texture(iTex0, vUV); fragColor = texture(iTex0, vUV);
+154 -48
View File
@@ -9,8 +9,6 @@ out vec4 fragColor;
#include inc_debug.glsl #include inc_debug.glsl
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform sampler2D iTex1;
uniform sampler2D iTex2;
uniform sampler2D iTex3; uniform sampler2D iTex3;
uniform sampler2D iTex4; uniform sampler2D iTex4;
uniform sampler2D iTex5; uniform sampler2D iTex5;
@@ -18,6 +16,7 @@ uniform sampler2D iTex6;
uniform sampler2D iTex7; uniform sampler2D iTex7;
uniform sampler2D iTex8; uniform sampler2D iTex8;
uniform sampler2D iTex9; uniform sampler2D iTex9;
uniform int iFPS;
uniform int iInputFPS1; uniform int iInputFPS1;
uniform int iInputFPS2; uniform int iInputFPS2;
@@ -26,17 +25,91 @@ float s(vec2 uv, float x0, float y0) {
step(-y0 - 1, -uv.y); step(-y0 - 1, -uv.y);
} }
const int texts[10][5] = { const int texts[12][5] = {
{0x49, 0x4E, 0x20, 0x41, 0x00}, // IN A {
{0x49, 0x4E, 0x20, 0x42, 0x00}, // IN B 0x49,
{0x53, 0x52, 0x43, 0x20, 0x41}, // SRC A 0x4E,
{0x53, 0x52, 0x43, 0x20, 0x42}, // SRC B 0x20,
{0x46, 0x58, 0x20, 0x41, 0x00}, // FX A 0x41,
{0x46, 0x58, 0x20, 0x42, 0x00}, // FX B 0x00
{0x41, 0x2B, 0x42, 0x00, 0x00}, // A+B }, // IN A
{0x4D, 0x46, 0x58, 0x00, 0x00}, // MFX {
{0x46, 0x50, 0x53, 0x00, 0x00}, // FPS 0x49,
{0x4F, 0x46, 0x46, 0x00, 0x00}, // OFF 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() { void main() {
@@ -52,53 +125,86 @@ void main() {
c += s(uv2, 1, 2) * texture(iTex5, uv2); c += s(uv2, 1, 2) * texture(iTex5, uv2);
c += s(uv2, 2, 2) * texture(iTex7, uv2); c += s(uv2, 2, 2) * texture(iTex7, uv2);
c += s(uv2,1,1) * texture(iTex6, uv2); c += s(uv2, 1, 0) * texture(iTex6, uv2);
c += s(uv2,2,1) * texture(iTex8, uv2); c += s(uv2, 2, 0) * texture(iTex8, uv2);
c += s(uv2,0,0) * debug(mod(uv2, 1)); c += s(uv2, 0, 1) * debug(mod(uv2, 1));
c += s(uv2,1,0) * texture(iTex9, uv2); c += s(uv2, 1, 1) * texture(iTex9, uv2);
c += s(uv2,2,0) * texture(iTex0, uv2); c += s(uv2, 2, 1) * texture(iTex0, uv2);
float sel = 0;
sel += iSelected == 3 ? h_rect(uv2, vec2(1.5, 2.5), vec2(0.5), 0.01) : 0;
sel += iSelected == 4 ? h_rect(uv2, vec2(1.5, 0.5), vec2(0.5), 0.01) : 0;
sel += iSelected == 5 ? h_rect(uv2, vec2(2.5, 2.5), vec2(0.5), 0.01) : 0;
sel += iSelected == 6 ? h_rect(uv2, vec2(2.5, 0.5), vec2(0.5), 0.01) : 0;
sel += iSelected == 8 ? h_rect(uv2, vec2(2.5, 1.5), vec2(0.5), 0.01) : 0;
c = mix(c, 1 - c, sel);
float f = 0; float f = 0;
float t = 0; float t = 0;
f += rect(uv3, vec2(-51, 28.5), vec2(2.1, 0.7)); f += rect(uv3, vec2(-35, 28.5), vec2(2.1, 0.7));
t += write_5(uv3, vec2(-53,28), texts[0]); t += write_5(uv3, vec2(-37, 28), texts[0]);
if (iInputResolution1.x > 0) { if (iInputFormat1 == YUYV_FOURCC) {
c += s(uv2, 0, 2) * texture(iTex3, uv2); c += s(uv2, 0, 2) * texture(iTex3, uv2);
f += rect(uv3, vec2(-50.4, 26.5), vec2(2.8, 0.7)); f += rect(uv3, vec2(-35, 26.75), vec2(2.8, 0.7));
t += write_int(uv3, vec2(-53,26), iInputFPS1, 2); t += write_int(uv3, vec2(-37.6, 26.1), iInputFPS1, 2);
t += write_5(uv3, vec2(-50.5,26), texts[8]); t += write_5(uv3, vec2(-35.1, 26.1), texts[8]);
} else { } else {
f += rect(uv3, vec2(-51.5, 26.5), vec2(1.6, 0.7)); f += rect(uv3, vec2(-35, 26.75), vec2(1.6, 0.7));
t += write_5(uv3, vec2(-53,26), texts[9]); t += write_5(uv3, vec2(-36.5, 26.1), texts[9]);
} }
f += rect(uv3, vec2(-51, 8.5), vec2(2.1, 0.7)); f += rect(uv3, vec2(-35, -11.5), vec2(2.1, 0.7));
t += write_5(uv3, vec2(-53,8), texts[1]); t += write_5(uv3, vec2(-37, -12), texts[1]);
if (iInputResolution2.x > 0) { if (iInputFormat2 == YUYV_FOURCC) {
c += s(uv2,0,1) * texture(iTex4, uv2); c += s(uv2, 0, 0) * texture(iTex4, uv2);
f += rect(uv3, vec2(-50.4, 6.5), vec2(2.8, 0.7)); f += rect(uv3, vec2(-35, -13.25), vec2(2.8, 0.7));
t += write_int(uv3, vec2(-53,6), iInputFPS2, 2); t += write_int(uv3, vec2(-37.6, -13.9), iInputFPS2, 2);
t += write_5(uv3, vec2(-50.5,6), texts[8]); t += write_5(uv3, vec2(-35.1, -13.9), texts[8]);
} else { } else {
f += rect(uv3, vec2(-51.5, 6.5), vec2(1.6, 0.7)); f += rect(uv3, vec2(-35, -13.25), vec2(1.6, 0.7));
t += write_5(uv3, vec2(-53,6), texts[9]); t += write_5(uv3, vec2(-36.5, -13.9), 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, 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));
} }
+6 -2
View File
@@ -8,15 +8,19 @@
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
#include inc_yuv.glsl #include inc_yuyv.glsl
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform sampler2D iTex2; uniform sampler2D iTex2;
uniform sampler2D iTex4;
uniform int iInputFormat2; uniform int iInputFormat2;
uniform vec2 iInputResolution2; uniform vec2 iInputResolution2;
uniform vec3 iGroup3_1[2];
void main() { void main() {
if (iInputFormat2 == YUYV_FOURCC) { if (iGroup3_1[1].z > 0) {
fragColor = texture(iTex2, vUV * vec2(1, -1));
} else if (iInputFormat2 == YUYV_FOURCC) {
fragColor = yuyvTex(iTex2, vUV, int(iInputResolution2.x)); fragColor = yuyvTex(iTex2, vUV, int(iInputResolution2.x));
} else { } else {
fragColor = texture(iTex0, vUV); fragColor = texture(iTex0, vUV);
+2 -2
View File
@@ -13,8 +13,8 @@ out vec4 fragColor;
subroutine uniform src_stage_sub src_stage; subroutine uniform src_stage_sub src_stage;
uniform int iSeed3; uniform int iSeed3;
uniform vec3 iMidi1_1[6]; uniform vec3 iGroup1_1[6];
void main() { void main() {
fragColor = src_stage(vUV, iSeed3, iMidi1_1[0], iMidi1_1[1].xy, iMidi1_1[2], iMidi1_1[3].xy, iMidi1_1[4], iMidi1_1[5].xy); fragColor = src_stage(vUV, iSeed3, iGroup1_1[0], iGroup1_1[1].xy, iGroup1_1[2], iGroup1_1[3].xy, iGroup1_1[4], iGroup1_1[5].xy);
} }
+2 -2
View File
@@ -12,8 +12,8 @@ out vec4 fragColor;
subroutine uniform src_stage_sub src_stage; subroutine uniform src_stage_sub src_stage;
uniform int iSeed4; uniform int iSeed4;
uniform vec3 iMidi1_2[6]; uniform vec3 iGroup1_2[6];
void main() { void main() {
fragColor = src_stage(vUV, iSeed4, iMidi1_2[0], iMidi1_2[1].xy, iMidi1_2[2], iMidi1_2[3].xy, iMidi1_2[4], iMidi1_2[5].xy); fragColor = src_stage(vUV, iSeed4, iGroup1_2[0], iGroup1_2[1].xy, iGroup1_2[2], iGroup1_2[3].xy, iGroup1_2[4], iGroup1_2[5].xy);
} }
+2 -2
View File
@@ -14,8 +14,8 @@ out vec4 fragColor;
uniform sampler2D iTex5; uniform sampler2D iTex5;
uniform sampler2D iTex7; uniform sampler2D iTex7;
uniform int iSeed5; uniform int iSeed5;
uniform vec3 iMidi2_1[7]; uniform vec3 iGroup2_1[7];
void main() { void main() {
fragColor = fx_stage(vUV, iTex5, iTex7, iSeed5, iMidi2_1[0], iMidi2_1[1].xy, iMidi2_1[2], iMidi2_1[3].xy, iMidi2_1[4], iMidi2_1[5].xy, iMidi2_1[6]); fragColor = fx_stage(vUV, 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]);
} }
+2 -2
View File
@@ -14,8 +14,8 @@ out vec4 fragColor;
uniform sampler2D iTex6; uniform sampler2D iTex6;
uniform sampler2D iTex8; uniform sampler2D iTex8;
uniform int iSeed6; uniform int iSeed6;
uniform vec3 iMidi2_2[7]; uniform vec3 iGroup2_2[7];
void main() { void main() {
fragColor = fx_stage(vUV, iTex6, iTex8, iSeed6, iMidi2_2[0], iMidi2_2[1].xy, iMidi2_2[2], iMidi2_2[3].xy, iMidi2_2[4], iMidi2_2[5].xy, iMidi2_2[6]); fragColor = fx_stage(vUV, 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]);
} }
+8 -4
View File
@@ -16,11 +16,11 @@ uniform int iDemo;
uniform sampler2D iTex7; uniform sampler2D iTex7;
uniform sampler2D iTex8; uniform sampler2D iTex8;
uniform int iSeed7; uniform int iSeed7;
uniform vec3 iMidi3_1[2]; uniform vec3 iGroup3_1[2];
void main() { void main() {
float mix_value = magic(iMidi3_1[1].xy, vec3(1, 0, 0), iSeed7); float mix_value = magic(iGroup3_1[1].xy, vec3(1, 0, 0), iSeed7);
bool mix_type = magic_trigger(vec3(iMidi3_1[0].x, 0, 0), iSeed7 + 10); bool mix_type = magic_trigger(vec3(iGroup3_1[0].x, 0, 0), iSeed7 + 10);
vec4 color_a = texture(iTex7, vUV); vec4 color_a = texture(iTex7, vUV);
vec4 color_b = texture(iTex8, 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); 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);
}
} }
+4 -4
View File
@@ -14,13 +14,13 @@ out vec4 fragColor;
uniform sampler2D iTex9; uniform sampler2D iTex9;
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform int iSeed8; uniform int iSeed8;
uniform vec3 iMidi2_3[7]; uniform vec3 iGroup2_3[7];
uniform vec3 iMidi3_1[2]; uniform vec3 iGroup3_1[2];
void main() { void main() {
vec4 color = fx_stage(vUV, iTex9, iTex0, iSeed8, iMidi2_3[0], iMidi2_3[1].xy, iMidi2_3[2], iMidi2_3[3].xy, iMidi2_3[4], iMidi2_3[5].xy, iMidi2_3[6]); vec4 color = fx_stage(vUV, 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); color = mix(color, vec4(0), iGroup3_1[0].y);
fragColor = color; fragColor = color;
} }
+102 -1
View File
@@ -6,8 +6,109 @@
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
#include inc_map.glsl
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform vec3 iGroup2_4[7];
uniform vec3 iGroup2_5[7];
uniform vec3 iGroup2_6[7];
uniform vec3 iGroup2_7[7];
void main() { void main() {
fragColor = texture(iTex0, vUV); bool visible = (iGroup2_4[4].x + iGroup2_5[4].x + iGroup2_6[4].x + iGroup2_7[4].x) > 0;
bool invert = (iGroup2_4[4].y + iGroup2_5[4].y + iGroup2_6[4].y + iGroup2_7[4].y) > 0;
float rect = clamp(iGroup2_4[4].z + iGroup2_5[4].z + iGroup2_6[4].z + iGroup2_7[4].z, 0, 1);
bool modified = false;
vec2 uv = mix(vec2(0), vUV, base_mask(vUV));
if (iGroup2_4[4].x > 0) {
vec2 p11 = vec2(iGroup2_4[6].xy);
vec2 p12 = vec2(iGroup2_4[1].xy);
vec2 p13 = vec2(iGroup2_4[3].xy);
vec2 p14 = vec2(iGroup2_4[5].xy);
p12.x = 1 - p12.x;
p13.y = 1 - p13.y;
p14.x = 1 - p14.x;
p14.y = 1 - p14.y;
vec2 uv1 = project_4p(vUV, p11, p12, p13, p14);
uv1 = mix(vec2(0), uv1, base_mask(uv1));
uv = uv1;
modified = true;
}
if (iGroup2_5[4].x > 0) {
vec2 p21 = vec2(iGroup2_5[6].xy);
vec2 p22 = vec2(iGroup2_5[1].xy);
vec2 p23 = vec2(iGroup2_5[3].xy);
vec2 p24 = vec2(iGroup2_5[5].xy);
p22.x = 1 - p22.x;
p23.y = 1 - p23.y;
p24.x = 1 - p24.x;
p24.y = 1 - p24.y;
vec2 uv2 = project_4p(vUV, p21, p22, p23, p24);
uv2 = mix(vec2(0), uv2, base_mask(uv2));
if (modified) {
uv = mix(uv, uv2, step(0.0001, length(uv2)));
} else {
uv = uv2;
}
modified = true;
}
if (iGroup2_6[4].x > 0) {
vec2 p31 = vec2(iGroup2_6[6].xy);
vec2 p32 = vec2(iGroup2_6[1].xy);
vec2 p33 = vec2(iGroup2_6[3].xy);
vec2 p34 = vec2(iGroup2_6[5].xy);
p32.x = 1 - p32.x;
p33.y = 1 - p33.y;
p34.x = 1 - p34.x;
p34.y = 1 - p34.y;
vec2 uv3 = project_4p(vUV, p31, p32, p33, p34);
uv3 = mix(vec2(0), uv3, base_mask(uv3));
if (modified) {
uv = mix(uv, uv3, step(0.0001, length(uv3)));
} else {
uv = uv3;
}
modified = true;
}
if (iGroup2_7[4].x > 0) {
vec2 p41 = vec2(iGroup2_7[6].xy);
vec2 p42 = vec2(iGroup2_7[1].xy);
vec2 p43 = vec2(iGroup2_7[3].xy);
vec2 p44 = vec2(iGroup2_7[5].xy);
p42.x = 1 - p42.x;
p43.y = 1 - p43.y;
p44.x = 1 - p44.x;
p44.y = 1 - p44.y;
vec2 uv4 = project_4p(vUV, p41, p42, p43, p44);
uv4 = mix(vec2(0), uv4, base_mask(uv4));
if (modified) {
uv = mix(uv, uv4, step(0.0001, length(uv4)));
} else {
uv = uv4;
}
modified = true;
}
vec4 color = texture(iTex0, invert ? vUV : uv);
if (visible) {
float mask = step(0.0001, length(uv));
color *= mix(mask, 1 - mask, invert ? 1 : 0);
color = mix(color, color + mask * vec4(1), rect * (step(uv.x, 0.01) + step(uv.y, 0.01) + step(1 - uv.y, 0.01) + step(1 - uv.x, 0.01)));
}
fragColor = color;
} }
+14
View File
@@ -372,6 +372,20 @@ float write_int(vec2 uv, vec2 pos, uint value, uint magnitude)
return d; return d;
} }
float write_int_left(vec2 uv, vec2 pos, uint value, uint magnitude)
{
int i;
uint m = 1;
float d = 0;
for (i = 0; i < magnitude; i++) {
if (i == 0 || value >= m) {
pos.x += 1;
m *= 10u;
}
}
return write_int(uv, pos, value, magnitude);
}
int read(sampler2D tex, vec2 uv, float k, int d, float t) int read(sampler2D tex, vec2 uv, float k, int d, float t)
{ {
float inv_k = 1 / k; float inv_k = 1 / k;
+116 -55
View File
@@ -1,13 +1,11 @@
#include inc_magic.glsl #include inc_magic.glsl
#include inc_functions.glsl #include inc_functions.glsl
#include inc_yuv.glsl #include inc_yuyv.glsl
#include inc_cp437.glsl #include inc_cp437.glsl
#ifndef INC_DEBUG #ifndef INC_DEBUG
#define INC_DEBUG #define INC_DEBUG
uniform int iFPS;
uniform vec2 iInputResolution1; uniform vec2 iInputResolution1;
uniform vec2 iInputResolution2; uniform vec2 iInputResolution2;
uniform int iInputFormat1; uniform int iInputFormat1;
@@ -15,6 +13,7 @@ uniform int iInputFormat2;
uniform int iDemo; uniform int iDemo;
uniform int iAutoRand; uniform int iAutoRand;
uniform int iAutoRandCycle;
uniform int iPage; uniform int iPage;
uniform int iSelected; uniform int iSelected;
@@ -36,11 +35,10 @@ uniform int iState8;
uniform int iActive1; uniform int iActive1;
uniform int iActive2; uniform int iActive2;
uniform vec3 iMidi2_1[7]; uniform vec3 iGroup2_1[7];
uniform vec3 iMidi2_2[7]; uniform vec3 iGroup2_2[7];
uniform vec3 iMidi2_3[7]; uniform vec3 iGroup2_3[7];
uniform vec3 iMidi3_1[2]; uniform vec3 iGroup3_1[2];
vec4 debug(vec2 vUV) vec4 debug(vec2 vUV)
{ {
@@ -93,29 +91,89 @@ vec4 debug(vec2 vUV)
if (random_mfx) { if (random_mfx) {
selected_mfx = int(randTime(iSeed8 + 100) * 14); selected_mfx = int(randTime(iSeed8 + 100) * 14);
} }
float fxa_value = magic(iMidi2_1[6].xy, vec3(1, 0, 0), iSeed5); float fxa_value = magic(iGroup2_1[6].xy, vec3(1, 0, 0), iSeed5);
bool fxa_invert = magic_trigger(vec3(iMidi2_1[6].z, 0, 0), iSeed5); bool fxa_invert = magic_trigger(vec3(iGroup2_1[6].z, 0, 0), iSeed5);
float fxb_value = magic(iMidi2_2[6].xy, vec3(1, 0, 0), iSeed6); float fxb_value = magic(iGroup2_2[6].xy, vec3(1, 0, 0), iSeed6);
bool fxb_invert = magic_trigger(vec3(iMidi2_2[6].z, 0, 0), iSeed6); bool fxb_invert = magic_trigger(vec3(iGroup2_2[6].z, 0, 0), iSeed6);
float mfx_value = magic(iMidi2_3[6].xy, vec3(1, 0, 0), iSeed8); float mfx_value = magic(iGroup2_3[6].xy, vec3(1, 0, 0), iSeed8);
bool mfx_invert = magic_trigger(vec3(iMidi2_3[6].z, 0, 0), iSeed8); bool mfx_invert = magic_trigger(vec3(iGroup2_3[6].z, 0, 0), iSeed8);
float mix_value = magic(iMidi3_1[1].xy, vec3(1, 0, 0), iSeed7); 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); 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 // logic
const int texts[10][5] = { const int texts[10][5] = {
{0x46, 0x50, 0x53, 0x00, 0x00}, // FPS {
{0x54, 0x45, 0x4D, 0x50, 0x4F}, // TEMPO 0x46,
{0x54, 0x49, 0x4D, 0x45, 0x00}, // TIME 0x50,
{0x44, 0x45, 0x4D, 0x4F, 0x00}, // DEMO 0x53,
{0x4C, 0x49, 0x56, 0x45, 0x00}, // LIVE 0x00,
{0x2B, 0x52, 0x41, 0x4E, 0x44}, // +RAND 0x00
{0x53, 0x52, 0x43, 0x00, 0x00}, // SRC }, // FPS
{0x46, 0x58, 0x00, 0x00, 0x00}, // FX {
{0x49, 0x4E, 0x00, 0x00, 0x00}, // IN 0x54,
{0x4D, 0x46, 0x58, 0x00, 0x00}, // MFX 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; vec2 uv2 = uv1;
@@ -141,8 +199,16 @@ vec4 debug(vec2 vUV)
rect(uv2, vec2(2, -1.55), vec2(0.1, 0.55)) + rect(uv2, vec2(2, -1.55), vec2(0.1, 0.55)) +
rect(uv2, vec2(0.55, 2), vec2(1.5, 0.1)) + rect(uv2, vec2(0.55, 2), vec2(1.5, 0.1)) +
rect(uv2, vec2(2, 1.55), vec2(0.1, 0.55)) + rect(uv2, vec2(2, 1.55), vec2(0.1, 0.55)) +
rect(uv2, vec2(7.5, 0), vec2(1.5, 0.1)) + rect(uv2, vec2(6.8, 0), vec2(0.75, 0.1)) +
h_rect(uv2, vec2(-9, -3.9), vec2(1), 0.1); h_circle(uv2, vec2(7.8, 0), 0.3, 0.1);
if (iDemo < 1 && iInputFormat1 == YUYV_FOURCC) {
f += circle(uv2, vec2(-9, 2), 0.3);
}
if (iDemo < 1 && iInputFormat2 == YUYV_FOURCC) {
f += circle(uv2, vec2(-9, -2), 0.3);
}
// show selected src/fx // show selected src/fx
f += char_at(uv2, vec2(-5.4, 1.45), hex_chars[selected_srca]); f += char_at(uv2, vec2(-5.4, 1.45), hex_chars[selected_srca]);
@@ -177,17 +243,17 @@ vec4 debug(vec2 vUV)
f += write_5(uv3 * 0.75, vec2(-11.6, -1.8), texts[6]); f += write_5(uv3 * 0.75, vec2(-11.6, -1.8), texts[6]);
f += write_5(uv3 * 0.75, vec2(-4.2, -1.8), texts[7]); f += write_5(uv3 * 0.75, vec2(-4.2, -1.8), texts[7]);
f += char_at(uv3 * 0.5, vec2(0.5, 0.5), 0x41); f += char_at(uv3 * 0.5, vec2(-11.5, 3.5), 0x41);
f += char_at(uv3 * 0.5, vec2(0.5, -3), 0x42); f += char_at(uv3 * 0.5, vec2(-11.5, -6), 0x42);
if (iDemo < 1 && (iInputFormat1 == YUYV_FOURCC || iInputFormat2 == YUYV_FOURCC)) { if (iDemo < 1 && (iInputFormat1 == YUYV_FOURCC || iInputFormat2 == YUYV_FOURCC)) {
f += write_5(uv3 * 0.75, vec2(-19.7, -1.8), texts[8]); f += write_5(uv3 * 0.75, vec2(-19.7, -1.8), texts[8]);
} }
f += write_5(uv3 * 0.75, vec2(10.9, 2), texts[9]); f += write_5(uv3 * 0.75, vec2(10.9, 2), texts[9]);
// show inputs / feedback // show inputs / feedback
float line_a_a = rect(uv2, vec2(-8, 2), vec2(2, 0.1)); float line_a_a = rect(uv2, vec2(-7.5, 2), vec2(1.5, 0.1));
float line_a_b = rect(uv2, vec2(-7, 2), vec2(1, 0.1)) + rect(uv2, vec2(-8, 0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-9, -1), vec2(1, 0.1)); float line_a_b = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(-8.5, -2), vec2(0.5, 0.1)) + line(uv2, vec2(-7, 2.1), vec2(-8, -2.1), 0.2);
float line_a_f = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, 4), vec2(7, 0.1)) + rect(uv2, vec2(-7, 3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, 2), vec2(0.1, 2.1)); float line_a_f = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, 3.6), vec2(7, 0.1)) + rect(uv2, vec2(-7, 2.8), vec2(0.1, 0.9)) + rect(uv2, vec2(7, 1.8), vec2(0.1, 1.9));
if (selected_srca == 5 && iInputFormat1 == YUYV_FOURCC) { if (selected_srca == 5 && iInputFormat1 == YUYV_FOURCC) {
f += line_a_a; f += line_a_a;
} else if (selected_srca == 10 && iInputFormat2 == YUYV_FOURCC) { } else if (selected_srca == 10 && iInputFormat2 == YUYV_FOURCC) {
@@ -195,9 +261,10 @@ vec4 debug(vec2 vUV)
} else if (selected_srca % 5 == 0) { } else if (selected_srca % 5 == 0) {
f += line_a_f; f += line_a_f;
} }
float line_b_a = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(-7, -0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-8.5, 1), vec2(1.5, 0.1));
float line_b_b = rect(uv2, vec2(-8, -2), vec2(2, 0.1)); float line_b_a = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(-8.5, 2), vec2(0.5, 0.1)) + line(uv2, vec2(-7, -2.1), vec2(-8, 2.1), 0.2);
float line_b_f = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, -4), vec2(7, 0.1)) + rect(uv2, vec2(-7, -3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, -2), vec2(0.1, 2.1)); float line_b_b = rect(uv2, vec2(-7.5, -2), vec2(1.5, 0.1));
float line_b_f = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, -3.6), vec2(7, 0.1)) + rect(uv2, vec2(-7, -2.8), vec2(0.1, 0.9)) + rect(uv2, vec2(7, -1.8), vec2(0.1, 1.9));
if (selected_srcb == 5 && iInputFormat1 == YUYV_FOURCC) { if (selected_srcb == 5 && iInputFormat1 == YUYV_FOURCC) {
f += line_b_a; f += line_b_a;
} else if (selected_srcb == 10 && iInputFormat2 == YUYV_FOURCC) { } else if (selected_srcb == 10 && iInputFormat2 == YUYV_FOURCC) {
@@ -207,7 +274,9 @@ vec4 debug(vec2 vUV)
} }
// show page // show page
f += char_at(uv2, vec2(-9.2, -4.3), hex_chars[iPage]); f += iPage == 0 ? circle(uv2, vec2(-0.75, -4.1), 0.3) : h_circle(uv2, vec2(-0.75, -4.1), 0.25, 0.1);
f += iPage == 1 ? circle(uv2, vec2(0, -4.1), 0.3) : h_circle(uv2, vec2(0, -4.1), 0.20, 0.1);
f += iPage == 2 ? circle(uv2, vec2(0.75, -4.1), 0.3) : h_circle(uv2, vec2(0.75, -4.1), 0.20, 0.1);
// show fx values // show fx values
float fx_rect = 0; float fx_rect = 0;
@@ -225,33 +294,25 @@ vec4 debug(vec2 vUV)
float x = 0; float x = 0;
x = -15; x = -15;
f += write_5(uv3, vec2(x,13), texts[0]); f += write_5(uv3, vec2(x - 4.5, 13), texts[1]);
f += write_int(uv3, vec2(x - 3.5,13), iFPS, 3); f += write_int(uv3, vec2(x + 1.5, 13), int(iTempo), 3);
v = min(1, iFPS/60.0);
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
x = 0;
f += write_5(uv3, vec2(x,13), texts[1]);
f += write_int(uv3, vec2(x - 3.5,13), int(iTempo), 3);
v = fract(iBeats); v = fract(iBeats);
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
x = 15; x = 15;
f += write_5(uv3, vec2(x,13), texts[2]); if (iAutoRand > 0) {
f += write_int(uv3, vec2(x - 5.5,13), int(iTime), 5); f += write_5(uv3, vec2(x - 4.5, 13), texts[5]);
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); v = fract(iTime);
f += write_5(uv3, vec2(x - 4.5, 13), texts[2]);
}
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
if (iAutoRand > 0) {
f += write_5(uv3, vec2(-4,-15), iDemo > 0 ? texts[3] : texts[4]);
f += write_5(uv3, vec2(0,-15), texts[5]);
} else {
f += write_5(uv3, vec2(-2,-15), iDemo > 0 ? texts[3] : texts[4]);
}
return vec4(f); return vec4(f);
} }
+28 -16
View File
@@ -2,6 +2,8 @@
#define PI 3.1415927 #define PI 3.1415927
#endif #endif
#include inc_time.glsl
#include inc_rand.glsl
#include inc_res.glsl #include inc_res.glsl
#ifndef INC_FUNCTIONS #ifndef INC_FUNCTIONS
@@ -81,8 +83,7 @@ vec3 shift3(vec3 c, float f) {
vec3 mix3(vec3 c1, vec3 c2, vec3 c3, float x) { vec3 mix3(vec3 c1, vec3 c2, vec3 c3, float x) {
return istep(0.5, x) * mix(c1, c2, x * 2) 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) { 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) 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.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.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) { 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.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.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.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) float mean(vec3 v)
@@ -180,15 +179,15 @@ float v_index(vec2 uv) {
return floor(uv.x) + floor(uv.y) * 45; return floor(uv.x) + floor(uv.y) * 45;
} }
vec2 v_pos(float i) { vec2 v_pos(float i, int seed, float time) {
int iTimeId = int(iBeats); int iTimeId = int(time);
float iTimeV = iBeats - iTimeId; float iTimeV = time - iTimeId;
float x0 = rand(i + 823 + iTimeId); float x0 = rand(i + seed + iTimeId);
float y0 = rand(i + 328 + iTimeId); float y0 = rand(i + seed + 10 + iTimeId);
float x1 = rand(i + 823 + iTimeId + 1); float x1 = rand(i + seed + iTimeId + 1);
float y1 = rand(i + 328 + iTimeId + 1); float y1 = rand(i + seed + 10 + iTimeId + 1);
return vec2( return vec2(
mix(x0, x1, ease(ease(iTimeV))), mix(x0, x1, ease(ease(iTimeV))),
@@ -196,7 +195,7 @@ vec2 v_pos(float i) {
); );
} }
vec4 voronoi(vec2 uv, float dist) { vec4 voronoi(vec2 uv, float dist, int seed, float time) {
vec4 o = vec4(0, 0, 2, 0); vec4 o = vec4(0, 0, 2, 0);
vec4 t = vec4(0, 0, 2, 0); vec4 t = vec4(0, 0, 2, 0);
float d, i; float d, i;
@@ -205,7 +204,7 @@ vec4 voronoi(vec2 uv, float dist) {
for (int dy = -1; dy <= 1; dy++) { for (int dy = -1; dy <= 1; dy++) {
uv2 = vec2(floor(uv.x) + dx, floor(uv.y) + dy); uv2 = vec2(floor(uv.x) + dx, floor(uv.y) + dy);
i = v_index(uv2); i = v_index(uv2);
p = uv2 + v_pos(i) * dist; p = uv2 + v_pos(i, seed, time) * dist;
d = length(p - uv); d = length(p - uv);
if (d < o.z) { if (d < o.z) {
t = o; t = o;
@@ -224,6 +223,10 @@ float circle(vec2 uv, vec2 c, float size) {
return istep(size, length(uv - c)); return istep(size, length(uv - c));
} }
float h_circle(vec2 uv, vec2 c, float size, float k) {
return circle(uv, c, size + k * 0.5) - circle(uv, c, size - k * 0.5);
}
float stripe(float x, float k1, float k2) float stripe(float x, float k1, float k2)
{ {
return k2 > k1 ? (1 - step(x, k1)) * (step(x, k2)) : ((1 - step(x, k2)) * (step(x, k1))); return k2 > k1 ? (1 - step(x, k1)) * (step(x, k2)) : ((1 - step(x, k2)) * (step(x, k1)));
@@ -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) { vec2 iso(vec2 p) {
return p * ISOMETRIC_MATRIX; return p * ISOMETRIC_MATRIX;
+30
View File
@@ -0,0 +1,30 @@
#ifndef INC_MAP
#define INC_MAP
vec2 project_4p(vec2 uv, vec2 p1, vec2 p2, vec2 p3, vec2 p4) {
float k1 = (p4.y - p3.y) / (p2.y - p3.y);
float k2 = (p3.y - p1.y) / (p2.y - p3.y);
float a = (p4.x - p3.x + k1 * p3.x - k1 * p2.x) / (p1.x - p3.x - k2 * p3.x + k2 * p2.x);
float b = k1 + a * k2;
float c = 1 - a - b;
// https://math.stackexchange.com/questions/296794/finding-the-transform-matrix-from-4-projected-points-with-javascript/339033#339033
mat3 projection_a = mat3(
a * p1.x, a * p1.y, a,
b * p2.x, b * p2.y, b,
c * p3.x, c * p3.y, c
);
mat3 projection_a_prime = inverse(projection_a);
mat3 projection_b = mat3(
0, 0, -1,
1, 0, 1,
0, 1, 1
);
vec3 tmp = projection_b * projection_a_prime * vec3(uv, 1);
return tmp.xy / tmp.z;
}
float base_mask(vec2 uv) {
return step(0, uv.x) * step(-1, -uv.x) * step(0, uv.y) * step(-1, -uv.y);
}
#endif
+144 -27
View File
@@ -101,7 +101,139 @@ subroutine(src_stage_sub) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
return vec4(f); return vec4(f);
} }
// SRC 4 : waves // // SRC 4 : circuit
// subroutine ( src_stage_sub ) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
// {
// // 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) subroutine ( src_stage_sub ) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
@@ -112,34 +244,19 @@ subroutine(src_stage_sub) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
// controls // controls
float spacing = magic(f1, b1, seed + 10); float zoom = 2 + magic(f1, b1, seed + 10) * 20;
float thickness = magic(f2, b2, seed + 20); float details = 5 * magic(f2, b2, seed + 20);
float scroll = magic_reverse(f3, b3, seed + 30); float delta = magic(f3, b3, seed + 30);
// logic // logic
vec2 uv2 = uv1; uv1 *= zoom;
uv2.y += 0.5;
uv2 *= 2.25; vec4 data = voronoi(uv1, 1, seed + 40, iBeats * 0.25);
uv2 = vec2((uv2.x + 1) * 0.5, -uv2.y);
float m1 = spacing * 4.5 + 0.5; float f = ease(data.x) + ease(data.y);
float y = log(-uv2.y) * m1;
y = mod(y + scroll * 5.0 - iBeats / 16, 5.); f = saw(f * (1 + data.x * details) - delta * 2.0);
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));
return vec4(f); return vec4(f);
} }
@@ -165,7 +282,7 @@ subroutine(src_stage_sub) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
vec2 uv2 = uv1; vec2 uv2 = uv1;
uv2 *= zoom * 20 + 3; uv2 *= zoom * 20 + 3;
uv2.x += iBeats; 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); float f = data.x / (data.x + data.y);
f = sin(f * PI * (details * 20)) * 0.5 + 1; f = sin(f * PI * (details * 20)) * 0.5 + 1;
int nf = int(noise_factor * 6); int nf = int(noise_factor * 6);
-28
View File
@@ -1,28 +0,0 @@
#ifndef INC_YUV
#define INC_YUV
const int YUYV_FOURCC = 1448695129;
const mat3x3 yuv_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;
int xV = x - x % 2 + 1;
vec4 tU = texture(tex, vec2(xU / w, 1 - vUV.y));
vec4 tV = texture(tex, vec2(xV / w, 1 - vUV.y));
vec3 yuv = vec3(
x % 2 == 0 ? tU.x : tV.x,
tU.y - 0.5,
tV.y - 0.5
);
return vec4(yuv_to_rgb * yuv, 1.0);
}
#endif
+44
View File
@@ -0,0 +1,44 @@
#ifndef INC_YUYV
#define INC_YUYV
const int YUYV_FOURCC = 1448695129;
// https://en.wikipedia.org/wiki/Y%E2%80%B2UV
const mat3x3 yuyv_to_rgb_bt709 = {
{
1,
1,
1
},
{
0,
-0.21482,
2.12798
},
{
1.28033,
-0.38059,
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;
int xV = x - x % 2 + 1;
vec4 tU = texture(tex, vec2(xU / w, 1 - vUV.y));
vec4 tV = texture(tex, vec2(xV / w, 1 - vUV.y));
vec3 yuv = vec3(
x % 2 == 0 ? tU.x : tV.x,
tU.y - 0.5,
tV.y - 0.5
);
return vec4(yuyv_to_rgb_bt709 * yuv, 1.0);
}
#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"> <diagram name="Page-1" id="uAijJZJkDDyZqolEMDYd">
<mxGraphModel dx="1848" dy="672" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <mxGraphModel dx="2022" dy="698" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root> <root>
<mxCell id="0" /> <mxCell id="0" />
<mxCell id="1" parent="0" /> <mxCell id="1" parent="0" />
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-1" value="F.O.R.G.E." style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-1" value="F.O.R.G.E." style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;" parent="1" vertex="1">
<mxGeometry x="154" y="210" width="546" height="350" as="geometry" /> <mxGeometry x="154" y="210" width="546" height="350" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-2" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-2" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="270" y="250" width="120" height="60" as="geometry" /> <mxGeometry x="270" y="250" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-3" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-3" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="274" y="410" width="120" height="60" as="geometry" /> <mxGeometry x="274" y="410" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-4" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-4" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="280" y="260" width="120" height="60" as="geometry" /> <mxGeometry x="280" y="260" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-5" value="TEXTURE&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" /> <mxGeometry x="290" y="270" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-6" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-6" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="284" y="420" width="120" height="60" as="geometry" /> <mxGeometry x="284" y="420" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-7" value="SHADER&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" /> <mxGeometry x="294" y="430" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-9" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-9" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="333.5" y="340" as="sourcePoint" /> <mxPoint x="333.5" y="340" as="sourcePoint" />
<mxPoint x="333.5" y="400.5" as="targetPoint" /> <mxPoint x="333.5" y="400.5" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-11" value="UNIFORM&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"> <mxGeometry x="0.1111" relative="1" as="geometry">
<mxPoint x="-40" y="-13" as="offset" /> <mxPoint x="-40" y="-13" as="offset" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-10" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-10" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="370" y="400" as="sourcePoint" /> <mxPoint x="370" y="400" as="sourcePoint" />
<mxPoint x="370" y="340" as="targetPoint" /> <mxPoint x="370" y="340" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-12" value="RENDERS TO&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"> <mxGeometry x="-0.3556" y="2" relative="1" as="geometry">
<mxPoint x="62" y="-1" as="offset" /> <mxPoint x="62" y="-1" as="offset" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-13" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-13" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="140" y="300" as="sourcePoint" /> <mxPoint x="140" y="300" as="sourcePoint" />
<mxPoint x="260" y="299.5" as="targetPoint" /> <mxPoint x="260" y="299.5" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-14" value="DMA&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"> <mxGeometry x="0.1111" relative="1" as="geometry">
<mxPoint x="-10" y="-19" as="offset" /> <mxPoint x="-10" y="-19" as="offset" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-15" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-19" value="OUTPUT&lt;br&gt;SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="140" y="450.5" as="sourcePoint" />
<mxPoint x="260" y="450" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-16" value="UNIFORMS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3Uv0AfHo8SbA6Qcxonjd-15">
<mxGeometry x="0.1111" relative="1" as="geometry">
<mxPoint x="-10" y="-19" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-19" value="OUTPUT&lt;br&gt;SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="530" y="270" width="120" height="60" as="geometry" /> <mxGeometry x="530" y="270" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-23" value="MONITOR&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" /> <mxGeometry x="530" y="360" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-24" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;dashed=1;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-24" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;dashed=1;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="420" y="320" as="sourcePoint" /> <mxPoint x="420" y="320" as="sourcePoint" />
<mxPoint x="520" y="360" as="targetPoint" /> <mxPoint x="520" y="360" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-25" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-25" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="420" y="290" as="sourcePoint" /> <mxPoint x="420" y="290" as="sourcePoint" />
<mxPoint x="520" y="290" as="targetPoint" /> <mxPoint x="520" y="290" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-26" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-26" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="349.5" y="585" as="sourcePoint" /> <mxPoint x="349.5" y="585" as="sourcePoint" />
<mxPoint x="349.5" y="495" as="targetPoint" /> <mxPoint x="350" y="500" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-27" value="COMPILES&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"> <mxGeometry x="0.1111" relative="1" as="geometry">
<mxPoint x="-55" y="-15" as="offset" /> <mxPoint x="-55" y="-15" as="offset" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-28" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-28" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="274" y="590" width="120" height="60" as="geometry" /> <mxGeometry x="274" y="590" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-29" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-29" value="SHADER" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="284" y="600" width="120" height="60" as="geometry" /> <mxGeometry x="284" y="600" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-30" value="GLSL FILE&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" /> <mxGeometry x="294" y="610" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-31" value="MIDI INPUT" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-31" value="MIDI&lt;br&gt;INPUT" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="10" y="420" width="120" height="60" as="geometry" /> <mxGeometry x="460" y="610" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-36" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-36" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="-10" y="250" width="120" height="60" as="geometry" /> <mxGeometry x="-10" y="250" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-37" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-37" value="TEXTURE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry y="260" width="120" height="60" as="geometry" /> <mxGeometry y="260" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-38" value="VIDEO DEVICE&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" /> <mxGeometry x="10" y="270" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-39" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-39" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="660" y="299.5" as="sourcePoint" /> <mxPoint x="660" y="299.5" as="sourcePoint" />
<mxPoint x="760" y="299.5" as="targetPoint" /> <mxPoint x="760" y="299.5" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-40" value="OUTPUT&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" /> <mxGeometry x="770" y="270" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-41" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;dashed=1;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-41" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;dashed=1;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="660" y="389.5" as="sourcePoint" /> <mxPoint x="660" y="389.5" as="sourcePoint" />
<mxPoint x="760" y="389.5" as="targetPoint" /> <mxPoint x="760" y="389.5" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-42" value="MONITOR&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" /> <mxGeometry x="770" y="360" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-43" value="CONTEXT" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-43" value="STATE" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="530" y="460" width="120" height="60" as="geometry" /> <mxGeometry x="530" y="460" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-46" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-46" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="510" y="490" as="sourcePoint" /> <mxPoint x="510" y="490" as="sourcePoint" />
<mxPoint x="430" y="450" as="targetPoint" /> <mxPoint x="430" y="450" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-47" value="UNIFORMS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3Uv0AfHo8SbA6Qcxonjd-46"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-47" value="UNIFORMS" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="3Uv0AfHo8SbA6Qcxonjd-46" vertex="1" connectable="0">
<mxGeometry x="0.1111" relative="1" as="geometry"> <mxGeometry x="0.1111" relative="1" as="geometry">
<mxPoint x="25" y="-18" as="offset" /> <mxPoint x="25" y="-18" as="offset" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-52" value="MIDI OUTPUT" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-52" value="MIDI OUTPUT" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="770" y="460" width="120" height="60" as="geometry" /> <mxGeometry x="770" y="460" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="3Uv0AfHo8SbA6Qcxonjd-55" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> <mxCell id="3Uv0AfHo8SbA6Qcxonjd-55" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry"> <mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="660" y="490" as="sourcePoint" /> <mxPoint x="660" y="490" as="sourcePoint" />
<mxPoint x="760" y="490" as="targetPoint" /> <mxPoint x="760" y="490" as="targetPoint" />
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="WElHySgPOBnYc4yB3MP0-2" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;entryX=0.744;entryY=0.914;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" target="3Uv0AfHo8SbA6Qcxonjd-1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="520" y="600" as="sourcePoint" />
<mxPoint x="539.58" y="530" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="WElHySgPOBnYc4yB3MP0-4" value="KEYBOARD&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> </root>
</mxGraphModel> </mxGraphModel>
</diagram> </diagram>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.
+39 -5
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 * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
* *
* Generator: C/C++ * Generator: C/C++
* Specification: egl * Specification: egl
* Extensions: 10 * Extensions: 11
* *
* APIs: * APIs:
* - egl=1.5 * - egl=1.5
@@ -19,10 +19,10 @@
* - ON_DEMAND = False * - ON_DEMAND = False
* *
* Commandline: * 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: * 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_RESET_NOTIFICATION_STRATEGY 0x31BD
#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
#define EGL_CORE_NATIVE_ENGINE 0x305B #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_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)
#define EGL_DEPTH_SIZE 0x3025 #define EGL_DEPTH_SIZE 0x3025
#define EGL_DISPLAY_SCALING 10000 #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_SURFACE EGL_CAST(EGLSurface,0)
#define EGL_NO_SYNC EGL_CAST(EGLSync,0) #define EGL_NO_SYNC EGL_CAST(EGLSync,0)
#define EGL_NO_TEXTURE 0x305C #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_API 0x30A2
#define EGL_OPENGL_BIT 0x0008 #define EGL_OPENGL_BIT 0x0008
#define EGL_OPENGL_ES2_BIT 0x0004 #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; GLAD_API_CALL int GLAD_EGL_EXT_image_dma_buf_import;
#define EGL_EXT_image_dma_buf_import_modifiers 1 #define EGL_EXT_image_dma_buf_import_modifiers 1
GLAD_API_CALL int GLAD_EGL_EXT_image_dma_buf_import_modifiers; 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 #define EGL_KHR_gl_texture_2D_image 1
GLAD_API_CALL int GLAD_EGL_KHR_gl_texture_2D_image; GLAD_API_CALL int GLAD_EGL_KHR_gl_texture_2D_image;
#define EGL_KHR_image 1 #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 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 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 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 *PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEPROC)(EGLDisplay dpy, EGLImage image); typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEPROC)(EGLDisplay dpy, EGLImage image);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEKHRPROC)(EGLDisplay dpy, EGLImageKHR 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 __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 *PFNEGLGETSYNCATTRIBPROC)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib * value);
typedef EGLBoolean (GLAD_API_PTR *PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint * major, EGLint * minor); 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 EGLBoolean (GLAD_API_PTR *PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
typedef EGLenum (GLAD_API_PTR *PFNEGLQUERYAPIPROC)(void); 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 *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 *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 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); 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 #define eglCreateSync glad_eglCreateSync
GLAD_API_CALL PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface; GLAD_API_CALL PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface;
#define eglCreateWindowSurface glad_eglCreateWindowSurface #define eglCreateWindowSurface glad_eglCreateWindowSurface
GLAD_API_CALL PFNEGLDEBUGMESSAGECONTROLKHRPROC glad_eglDebugMessageControlKHR;
#define eglDebugMessageControlKHR glad_eglDebugMessageControlKHR
GLAD_API_CALL PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext; GLAD_API_CALL PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext;
#define eglDestroyContext glad_eglDestroyContext #define eglDestroyContext glad_eglDestroyContext
GLAD_API_CALL PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage; GLAD_API_CALL PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage;
@@ -1069,12 +1088,16 @@ GLAD_API_CALL PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib;
#define eglGetSyncAttrib glad_eglGetSyncAttrib #define eglGetSyncAttrib glad_eglGetSyncAttrib
GLAD_API_CALL PFNEGLINITIALIZEPROC glad_eglInitialize; GLAD_API_CALL PFNEGLINITIALIZEPROC glad_eglInitialize;
#define eglInitialize glad_eglInitialize #define eglInitialize glad_eglInitialize
GLAD_API_CALL PFNEGLLABELOBJECTKHRPROC glad_eglLabelObjectKHR;
#define eglLabelObjectKHR glad_eglLabelObjectKHR
GLAD_API_CALL PFNEGLMAKECURRENTPROC glad_eglMakeCurrent; GLAD_API_CALL PFNEGLMAKECURRENTPROC glad_eglMakeCurrent;
#define eglMakeCurrent glad_eglMakeCurrent #define eglMakeCurrent glad_eglMakeCurrent
GLAD_API_CALL PFNEGLQUERYAPIPROC glad_eglQueryAPI; GLAD_API_CALL PFNEGLQUERYAPIPROC glad_eglQueryAPI;
#define eglQueryAPI glad_eglQueryAPI #define eglQueryAPI glad_eglQueryAPI
GLAD_API_CALL PFNEGLQUERYCONTEXTPROC glad_eglQueryContext; GLAD_API_CALL PFNEGLQUERYCONTEXTPROC glad_eglQueryContext;
#define eglQueryContext glad_eglQueryContext #define eglQueryContext glad_eglQueryContext
GLAD_API_CALL PFNEGLQUERYDEBUGKHRPROC glad_eglQueryDebugKHR;
#define eglQueryDebugKHR glad_eglQueryDebugKHR
GLAD_API_CALL PFNEGLQUERYDMABUFFORMATSEXTPROC glad_eglQueryDmaBufFormatsEXT; GLAD_API_CALL PFNEGLQUERYDMABUFFORMATSEXTPROC glad_eglQueryDmaBufFormatsEXT;
#define eglQueryDmaBufFormatsEXT glad_eglQueryDmaBufFormatsEXT #define eglQueryDmaBufFormatsEXT glad_eglQueryDmaBufFormatsEXT
GLAD_API_CALL PFNEGLQUERYDMABUFMODIFIERSEXTPROC glad_eglQueryDmaBufModifiersEXT; 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_VERSION_1_5 = 0;
int GLAD_EGL_EXT_image_dma_buf_import = 0; int GLAD_EGL_EXT_image_dma_buf_import = 0;
int GLAD_EGL_EXT_image_dma_buf_import_modifiers = 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_gl_texture_2D_image = 0;
int GLAD_EGL_KHR_image = 0; int GLAD_EGL_KHR_image = 0;
int GLAD_EGL_KHR_image_base = 0; int GLAD_EGL_KHR_image_base = 0;
@@ -1184,6 +1208,7 @@ PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface = NULL
PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface = NULL; PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface = NULL;
PFNEGLCREATESYNCPROC glad_eglCreateSync = NULL; PFNEGLCREATESYNCPROC glad_eglCreateSync = NULL;
PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface = NULL; PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface = NULL;
PFNEGLDEBUGMESSAGECONTROLKHRPROC glad_eglDebugMessageControlKHR = NULL;
PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext = NULL; PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext = NULL;
PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage = NULL; PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage = NULL;
PFNEGLDESTROYIMAGEKHRPROC glad_eglDestroyImageKHR = NULL; PFNEGLDESTROYIMAGEKHRPROC glad_eglDestroyImageKHR = NULL;
@@ -1201,9 +1226,11 @@ PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay = NULL;
PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress = NULL; PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress = NULL;
PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib = NULL; PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib = NULL;
PFNEGLINITIALIZEPROC glad_eglInitialize = NULL; PFNEGLINITIALIZEPROC glad_eglInitialize = NULL;
PFNEGLLABELOBJECTKHRPROC glad_eglLabelObjectKHR = NULL;
PFNEGLMAKECURRENTPROC glad_eglMakeCurrent = NULL; PFNEGLMAKECURRENTPROC glad_eglMakeCurrent = NULL;
PFNEGLQUERYAPIPROC glad_eglQueryAPI = NULL; PFNEGLQUERYAPIPROC glad_eglQueryAPI = NULL;
PFNEGLQUERYCONTEXTPROC glad_eglQueryContext = NULL; PFNEGLQUERYCONTEXTPROC glad_eglQueryContext = NULL;
PFNEGLQUERYDEBUGKHRPROC glad_eglQueryDebugKHR = NULL;
PFNEGLQUERYDMABUFFORMATSEXTPROC glad_eglQueryDmaBufFormatsEXT = NULL; PFNEGLQUERYDMABUFFORMATSEXTPROC glad_eglQueryDmaBufFormatsEXT = NULL;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC glad_eglQueryDmaBufModifiersEXT = NULL; PFNEGLQUERYDMABUFMODIFIERSEXTPROC glad_eglQueryDmaBufModifiersEXT = NULL;
PFNEGLQUERYSTRINGPROC glad_eglQueryString = 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_eglQueryDmaBufFormatsEXT = (PFNEGLQUERYDMABUFFORMATSEXTPROC) load(userptr, "eglQueryDmaBufFormatsEXT");
glad_eglQueryDmaBufModifiersEXT = (PFNEGLQUERYDMABUFMODIFIERSEXTPROC) load(userptr, "eglQueryDmaBufModifiersEXT"); 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) { static void glad_egl_load_EGL_KHR_image( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_EGL_KHR_image) return; if(!GLAD_EGL_KHR_image) return;
glad_eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) load(userptr, "eglCreateImageKHR"); 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 = 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_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_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 = glad_egl_has_extension(extensions, "EGL_KHR_image");
GLAD_EGL_KHR_image_base = glad_egl_has_extension(extensions, "EGL_KHR_image_base"); 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; 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_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(load, userptr);
glad_egl_load_EGL_KHR_image_base(load, userptr); glad_egl_load_EGL_KHR_image_base(load, userptr);
glad_egl_load_EGL_MESA_drm_image(load, userptr); glad_egl_load_EGL_MESA_drm_image(load, userptr);
@@ -1572,4 +1607,3 @@ void gladLoaderUnloadEGL(void) {
#endif #endif
#endif /* GLAD_EGL_IMPLEMENTATION */ #endif /* GLAD_EGL_IMPLEMENTATION */
+29 -6
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 * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
* *
* Generator: C/C++ * Generator: C/C++
* Specification: gl * Specification: gl
* Extensions: 3 * Extensions: 4
* *
* APIs: * APIs:
* - gl:compatibility=4.6 * - gl:compatibility=4.6
@@ -19,10 +19,10 @@
* - ON_DEMAND = False * - ON_DEMAND = False
* *
* Commandline: * 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: * 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; GLAD_API_CALL int GLAD_GL_EXT_EGL_image_storage;
#define GL_EXT_direct_state_access 1 #define GL_EXT_direct_state_access 1
GLAD_API_CALL int GLAD_GL_EXT_direct_state_access; 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); 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_ARB_direct_state_access = 0;
int GLAD_GL_EXT_EGL_image_storage = 0; int GLAD_GL_EXT_EGL_image_storage = 0;
int GLAD_GL_EXT_direct_state_access = 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_glVertexArrayVertexBindingDivisorEXT = (PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) load(userptr, "glVertexArrayVertexBindingDivisorEXT");
glad_glVertexArrayVertexOffsetEXT = (PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) load(userptr, "glVertexArrayVertexOffsetEXT"); 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_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_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_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); 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_ARB_direct_state_access(load, userptr);
glad_gl_load_GL_EXT_EGL_image_storage(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_EXT_direct_state_access(load, userptr);
glad_gl_load_GL_KHR_debug(load, userptr);
@@ -9482,7 +9501,9 @@ static void* glad_gl_dlopen_handle(void) {
"libGL-1.so", "libGL-1.so",
#endif #endif
"libGL.so.1", "libGL.so.1",
"libGL.so" "libGL.so",
"libEGL.so.1",
"libEGL.so"
}; };
#endif #endif
@@ -9505,6 +9526,9 @@ static struct _glad_gl_userptr glad_gl_build_userptr(void *handle) {
#else #else
userptr.gl_get_proc_address_ptr = userptr.gl_get_proc_address_ptr =
(GLADglprocaddrfunc) glad_dlsym_handle(handle, "glXGetProcAddressARB"); (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 #endif
return userptr; return userptr;
@@ -9547,4 +9571,3 @@ void gladLoaderUnloadGL(void) {
#endif #endif
#endif /* GLAD_GL_IMPLEMENTATION */ #endif /* GLAD_GL_IMPLEMENTATION */
+78 -72
View File
@@ -6,7 +6,7 @@
# (shaders, video devices, textures, midi inputs, etc.) # (shaders, video devices, textures, midi inputs, etc.)
# Every number based constant will be "one-based" (1,2,3,etc.) # Every number based constant will be "one-based" (1,2,3,etc.)
# To read more, go to # To read more, go to
# https://github.com/klemek/forge-steel # https://git.klemek.fr/klemek/forge-steel
# ================ # ================
@@ -33,8 +33,6 @@ UNIFORM_BEATS=iBeats
UNIFORM_FPS=iFPS UNIFORM_FPS=iFPS
# 0/1 if demo # 0/1 if demo
UNIFORM_DEMO=iDemo UNIFORM_DEMO=iDemo
# 0/1 if auto random
UNIFORM_AUTORAND=iAutoRand
# Seed for shader X # Seed for shader X
UNIFORM_SEED_PREFIX=iSeed UNIFORM_SEED_PREFIX=iSeed
@@ -46,8 +44,8 @@ UNIFORM_RESOLUTION=iResolution
# --- uniform vec3 --- # --- uniform vec3 ---
# Midi group X layer Y (beware of group size) # Midi group X layer Y (beware of group size)
# Injected as "iMidiX_Y[Z]" # Injected as "iGroupX_Y[Z]"
UNIFORM_MIDI_PREFIX=iMidi UNIFORM_GROUP_PREFIX=iGroup
# --- uniform sampler2D --- # --- uniform sampler2D ---
@@ -81,9 +79,17 @@ FRAG_OUTPUT=2
FRAG_MONITOR=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 # The recognized ALSA name of the midi device
@@ -116,8 +122,8 @@ FADER_16=23
# Midi code for tap tempo # Midi code for tap tempo
TAP_TEMPO=46 TAP_TEMPO=46
# === MIDI INPUT STATES # === GROUP INPUT STATES
# Midi inputs will control FORGE's state as follows # Inputs will control FORGE's state as follows
# X groups of Y layers sized Z # X groups of Y layers sized Z
# You can manipulate only 1 layer at a time # You can manipulate only 1 layer at a time
# Every layer of every groups will be send as uniforms # Every layer of every groups will be send as uniforms
@@ -125,68 +131,68 @@ TAP_TEMPO=46
# with the same codes for nice display # with the same codes for nice display
# Total number of groups # Total number of groups
MIDI_COUNT=1 GROUP_COUNT=1
# Size of group 1 # Size of group 1
MIDI_1_COUNT=20 GROUP_1_COUNT=20
# Every code of active layer manipulation of group 1 # Every code of active layer manipulation of group 1
MIDI_1_1_X=32 GROUP_1_1_X=32
MIDI_1_1_Y=48 GROUP_1_1_Y=48
MIDI_1_1_Z=64 GROUP_1_1_Z=64
MIDI_1_2_X=0 GROUP_1_2_X=0
MIDI_1_2_Y=16 GROUP_1_2_Y=16
MIDI_1_2_Z= GROUP_1_2_Z=
MIDI_1_3_X=33 GROUP_1_3_X=33
MIDI_1_3_Y=49 GROUP_1_3_Y=49
MIDI_1_3_Z=65 GROUP_1_3_Z=65
MIDI_1_4_X=1 GROUP_1_4_X=1
MIDI_1_4_Y=17 GROUP_1_4_Y=17
MIDI_1_4_Z= GROUP_1_4_Z=
MIDI_1_5_X=34 GROUP_1_5_X=34
MIDI_1_5_Y=50 GROUP_1_5_Y=50
MIDI_1_5_Z=66 GROUP_1_5_Z=66
MIDI_1_6_X=2 GROUP_1_6_X=2
MIDI_1_6_Y=18 GROUP_1_6_Y=18
MIDI_1_6_Z= GROUP_1_6_Z=
MIDI_1_7_X=35 GROUP_1_7_X=35
MIDI_1_7_Y=51 GROUP_1_7_Y=51
MIDI_1_7_Z=67 GROUP_1_7_Z=67
MIDI_1_8_X=3 GROUP_1_8_X=3
MIDI_1_8_Y=19 GROUP_1_8_Y=19
MIDI_1_8_Z= GROUP_1_8_Z=
MIDI_1_9_X=36 GROUP_1_9_X=36
MIDI_1_9_Y=52 GROUP_1_9_Y=52
MIDI_1_9_Z=68 GROUP_1_9_Z=68
MIDI_1_10_X=4 GROUP_1_10_X=4
MIDI_1_10_Y=20 GROUP_1_10_Y=20
MIDI_1_10_Z= GROUP_1_10_Z=
MIDI_1_11_X=37 GROUP_1_11_X=37
MIDI_1_11_Y=53 GROUP_1_11_Y=53
MIDI_1_11_Z=69 GROUP_1_11_Z=69
MIDI_1_12_X=5 GROUP_1_12_X=5
MIDI_1_12_Y=21 GROUP_1_12_Y=21
MIDI_1_12_Z= GROUP_1_12_Z=
MIDI_1_13_X=38 GROUP_1_13_X=38
MIDI_1_13_Y=54 GROUP_1_13_Y=54
MIDI_1_13_Z=70 GROUP_1_13_Z=70
MIDI_1_14_X=6 GROUP_1_14_X=6
MIDI_1_14_Y=22 GROUP_1_14_Y=22
MIDI_1_14_Z= GROUP_1_14_Z=
MIDI_1_15_X=39 GROUP_1_15_X=39
MIDI_1_15_Y=55 GROUP_1_15_Y=55
MIDI_1_15_Z=71 GROUP_1_15_Z=71
MIDI_1_16_X=7 GROUP_1_16_X=7
MIDI_1_16_Y=23 GROUP_1_16_Y=23
MIDI_1_16_Z= GROUP_1_16_Z=
MIDI_1_17_X=58 GROUP_1_17_X=58
MIDI_1_17_Y=59 GROUP_1_17_Y=59
MIDI_1_17_Z= GROUP_1_17_Z=
MIDI_1_18_X=60 GROUP_1_18_X=60
MIDI_1_18_Y=61 GROUP_1_18_Y=61
MIDI_1_18_Z=62 GROUP_1_18_Z=62
MIDI_1_19_X=43 GROUP_1_19_X=43
MIDI_1_19_Y=44 GROUP_1_19_Y=44
MIDI_1_19_Z=42 GROUP_1_19_Z=42
MIDI_1_20_X=41 GROUP_1_20_X=41
MIDI_1_20_Y=45 GROUP_1_20_Y=45
MIDI_1_20_Z= GROUP_1_20_Z=
+21 -22
View File
@@ -10,34 +10,33 @@ uniform float iTempo; // current tempo in bpm
uniform float iBeats; // elapsed beats since last tempo reset uniform float iBeats; // elapsed beats since last tempo reset
uniform int iFPS; // output window frames per seconds uniform int iFPS; // output window frames per seconds
uniform int iDemo; // 0/1 if demo mode uniform int iDemo; // 0/1 if demo mode
uniform int iAutoRand; // 0/1 if auto random mode
uniform int iSeed1; // a random seed assigned at start uniform int iSeed1; // a random seed assigned at start
uniform vec2 iResolution; // output window resolution in pixels uniform vec2 iResolution; // output window resolution in pixels
uniform vec3 iMidi1_1[20]; // all midi inputs defined uniform vec3 iGroup1_1[20]; // all midi inputs defined
uniform sampler2D iTex0; // available texture (this code output, so feedback) uniform sampler2D iTex0; // available texture (this code output, so feedback)
void main() { void main() {
// all available buttons and faders // all available buttons and faders
vec3 b1 = iMidi1_1[0]; vec3 b1 = iGroup1_1[0];
vec2 f1 = iMidi1_1[1].xy; vec2 f1 = iGroup1_1[1].xy;
vec3 b2 = iMidi1_1[2]; vec3 b2 = iGroup1_1[2];
vec2 f2 = iMidi1_1[3].xy; vec2 f2 = iGroup1_1[3].xy;
vec3 b3 = iMidi1_1[4]; vec3 b3 = iGroup1_1[4];
vec2 f3 = iMidi1_1[5].xy; vec2 f3 = iGroup1_1[5].xy;
vec3 b4 = iMidi1_1[6]; vec3 b4 = iGroup1_1[6];
vec2 f4 = iMidi1_1[7].xy; vec2 f4 = iGroup1_1[7].xy;
vec3 b5 = iMidi1_1[8]; vec3 b5 = iGroup1_1[8];
vec2 f5 = iMidi1_1[9].xy; vec2 f5 = iGroup1_1[9].xy;
vec3 b6 = iMidi1_1[10]; vec3 b6 = iGroup1_1[10];
vec2 f6 = iMidi1_1[11].xy; vec2 f6 = iGroup1_1[11].xy;
vec3 b7 = iMidi1_1[12]; vec3 b7 = iGroup1_1[12];
vec2 f7 = iMidi1_1[13].xy; vec2 f7 = iGroup1_1[13].xy;
vec3 b8 = iMidi1_1[14]; vec3 b8 = iGroup1_1[14];
vec2 f8 = iMidi1_1[15].xy; vec2 f8 = iGroup1_1[15].xy;
vec3 b9 = iMidi1_1[16]; vec3 b9 = iGroup1_1[16];
vec3 b10 = iMidi1_1[17]; vec3 b10 = iGroup1_1[17];
vec3 b11 = iMidi1_1[18]; vec3 b11 = iGroup1_1[18];
vec3 b12 = iMidi1_1[19]; vec3 b12 = iGroup1_1[19];
// center UV and scale it to ratio // center UV and scale it to ratio
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
+80 -23
View File
@@ -1,4 +1,3 @@
#include <bsd/string.h>
#include <limits.h> #include <limits.h>
#include <log.h> #include <log.h>
#include <stdbool.h> #include <stdbool.h>
@@ -13,7 +12,8 @@
#include "string.h" #include "string.h"
static void print_help(int status_code) { static void print_help(int status_code) {
puts(PACKAGE puts(
PACKAGE
" " VERSION "\n\n" " " VERSION "\n\n"
"usage: " PACKAGE " " "usage: " PACKAGE " "
"[-h] " "[-h] "
@@ -28,12 +28,18 @@ static void print_help(int status_code) {
"[-t=TEMPO] " "[-t=TEMPO] "
"[-d] " "[-d] "
"[-ar / -nar] " "[-ar / -nar] "
"[-v=FILE] " "[-arc=CYCLES] "
#ifdef VIDEO_IN
"[-vi=FILE] "
"[-vs=SIZE] " "[-vs=SIZE] "
"[-vb=COUNT] "
"[-vr / -nvr] "
"[-vf=FOURCC] "
#endif /* VIDEO_IN */
"[-is=SIZE] " "[-is=SIZE] "
"[-sf=STATE_PATH] "
"[-ls / -nls] " "[-ls / -nls] "
"[-ss / -nss] " "[-ss / -nss] "
"[-mr / -nmr] "
"[-tm] " "[-tm] "
"[-tf] " "[-tf] "
"\n\n" "\n\n"
@@ -53,19 +59,27 @@ static void print_help(int status_code) {
" -t, --tempo base tempo (default: 60)\n" " -t, --tempo base tempo (default: 60)\n"
" -d, --demo demonstration mode (assume " " -d, --demo demonstration mode (assume "
"--no-save-state, --no-load-state, --auto-random)\n" "--no-save-state, --no-load-state, --auto-random)\n"
" -ar, --auto-random randomize state every 4 beats\n" " -ar, --auto-random randomize state every cycle (4 beats)\n"
" -nar, --no-auto-random do not randomize state (default)\n" " -nar, --no-auto-random do not randomize state (default)\n"
" -v, --video-in path to video capture device (multiple " " -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" "allowed)\n"
" -vb, --video-buffers number of video buffers to use (default: "
"1)\n"
" -vs, --video-size video capture desired height (default: " " -vs, --video-size video capture desired height (default: "
"internal texture height)\n" "internal texture height)\n"
" -vr, --video-reconnect auto-reconnect video (default)\n"
" -nvr, --no-video-reconnect do not auto-reconnect video\n"
" -vf, --video-fourcc video codec fourcc (default: YUYV)\n"
#endif /* VIDEO_IN */
" -is, --internal-size internal texture height (default: 720)\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" " -ls, --load-state load saved state (default)\n"
" -nls, --no-load-state do not load saved state\n" " -nls, --no-load-state do not load saved state\n"
" -ss, --save-state save state (default)\n" " -ss, --save-state save state (default)\n"
" -nss, --no-save-state do not save state\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" " -tm, --trace-midi print midi code and values\n"
" -tf, --trace-fps print fps status of subsystems\n"); " -tf, --trace-fps print fps status of subsystems\n");
exit(status_code); exit(status_code);
@@ -102,7 +116,7 @@ static unsigned int parse_uint(const char *arg, const char *value) {
tmp_value = (unsigned long long)atoll(value); tmp_value = (unsigned long long)atoll(value);
if (tmp_value >= UINT_MAX) { if (tmp_value > UINT_MAX) {
invalid_value(arg, value); invalid_value(arg, value);
} }
@@ -124,12 +138,18 @@ void args_parse(Parameters *params, int argc, char **argv) {
params->base_tempo = 60.0f; params->base_tempo = 60.0f;
params->demo = false; params->demo = false;
params->auto_random = false; params->auto_random = false;
params->auto_random_cycle = 4;
#ifdef VIDEO_IN
params->video_in.length = 0; params->video_in.length = 0;
params->video_buffers = 1;
params->video_size = 0; params->video_size = 0;
params->video_reconnect = true;
strlcpy(params->video_fourcc, "YUYV", 5);
#endif /* VIDEO_IN */
params->internal_size = 720; params->internal_size = 720;
strlcpy(params->state_file, "forge_saved_state.txt", STR_LEN);
params->load_state = true; params->load_state = true;
params->save_state = true; params->save_state = true;
params->midi_reconnect = true;
params->trace_midi = false; params->trace_midi = false;
params->trace_fps = false; params->trace_fps = false;
@@ -142,8 +162,14 @@ void args_parse(Parameters *params, int argc, char **argv) {
puts(PACKAGE " " VERSION); puts(PACKAGE " " VERSION);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} else if (is_arg(arg, "-p") || is_arg(arg, "--project")) { } 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); strlcpy(params->project_path, value, STR_LEN);
} else if (is_arg(arg, "-c") || is_arg(arg, "--config")) { } 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); strlcpy(params->config_file, value, STR_LEN);
} else if (is_arg(arg, "-hr") || is_arg(arg, "--hot-reload")) { } else if (is_arg(arg, "-hr") || is_arg(arg, "--hot-reload")) {
params->hot_reload = true; params->hot_reload = true;
@@ -168,16 +194,9 @@ void args_parse(Parameters *params, int argc, char **argv) {
params->auto_random = true; params->auto_random = true;
} else if (is_arg(arg, "-nar") || is_arg(arg, "--no-auto-random")) { } else if (is_arg(arg, "-nar") || is_arg(arg, "--no-auto-random")) {
params->auto_random = false; params->auto_random = false;
} else if (is_arg(arg, "-v") || is_arg(arg, "--video-in")) { } else if (is_arg(arg, "-arc") || is_arg(arg, "--auto-random-cycle")) {
if (params->video_in.length == MAX_VIDEO) { params->auto_random_cycle = parse_uint(arg, value);
log_error("maximum video input reached"); if (params->auto_random_cycle == 0) {
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) {
invalid_value(arg, value); invalid_value(arg, value);
} }
} else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) { } else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) {
@@ -185,8 +204,6 @@ void args_parse(Parameters *params, int argc, char **argv) {
if (params->internal_size == 0) { if (params->internal_size == 0) {
invalid_value(arg, value); invalid_value(arg, value);
} }
} else if (is_arg(arg, "-sf") || is_arg(arg, "--state-file")) {
strlcpy(params->state_file, value, STR_LEN);
} else if (is_arg(arg, "-ls") || is_arg(arg, "--load-state")) { } else if (is_arg(arg, "-ls") || is_arg(arg, "--load-state")) {
params->load_state = true; params->load_state = true;
} else if (is_arg(arg, "-nls") || is_arg(arg, "--no-load-state")) { } else if (is_arg(arg, "-nls") || is_arg(arg, "--no-load-state")) {
@@ -195,13 +212,52 @@ void args_parse(Parameters *params, int argc, char **argv) {
params->save_state = true; params->save_state = true;
} else if (is_arg(arg, "-nss") || is_arg(arg, "--no-save-state")) { } else if (is_arg(arg, "-nss") || is_arg(arg, "--no-save-state")) {
params->save_state = false; 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")) { } else if (is_arg(arg, "-tm") || is_arg(arg, "--trace-midi")) {
params->trace_midi = true; params->trace_midi = true;
} else if (is_arg(arg, "-tf") || is_arg(arg, "--trace-fps")) { } else if (is_arg(arg, "-tf") || is_arg(arg, "--trace-fps")) {
params->trace_fps = true; params->trace_fps = true;
} else { } 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 if (is_arg(arg, "-vf") || is_arg(arg, "--video-fourcc")) {
if (strlen(value) == 0) {
invalid_value(arg, value);
}
strlcpy(params->video_fourcc, value, 5);
} else {
invalid_arg(arg); invalid_arg(arg);
} }
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
}
} }
if (params->monitor && params->output && if (params->monitor && params->output &&
@@ -209,8 +265,9 @@ void args_parse(Parameters *params, int argc, char **argv) {
log_error("monitor screen cannot be the same as output screen"); log_error("monitor screen cannot be the same as output screen");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#ifdef VIDEO_IN
if (params->video_size == 0) { if (params->video_size == 0) {
params->video_size = params->internal_size; params->video_size = params->internal_size;
} }
#endif /* VIDEO_IN */
} }
+14
View File
@@ -12,7 +12,21 @@ unsigned int arr_uint_index_of(UintArray array, unsigned int value) {
return ARRAY_NOT_FOUND; return ARRAY_NOT_FOUND;
} }
bool arr_string_match(StringArray array, const char *needle) {
for (unsigned int i = 0; i < array.length; i++) {
if (strncmp(array.values[i], needle, strlen(array.values[i])) == 0) {
return true;
}
}
return false;
}
unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index) { 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--) { for (unsigned int i = offsets.length - 1; i > 0; i--) {
if (*index >= offsets.values[i]) { if (*index >= offsets.values[i]) {
*index -= offsets.values[i]; *index -= offsets.values[i];
+2
View File
@@ -7,4 +7,6 @@ unsigned int arr_uint_index_of(UintArray array, unsigned int value);
unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index); unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index);
bool arr_string_match(StringArray array, const char *needle);
#endif /* ARR_H */ #endif /* ARR_H */
+23 -4
View File
@@ -1,4 +1,3 @@
#include <bsd/string.h>
#include <hashmap.h> #include <hashmap.h>
#include <log.h> #include <log.h>
#include <stdlib.h> #include <stdlib.h>
@@ -69,15 +68,20 @@ void config_file_read(ConfigFile *config, const char *path) {
char *line; char *line;
char *rest; char *rest;
config->map = hashmap_new(sizeof(ConfigFileItem), 0, 0, 0, item_hash, config->map = NULL;
item_compare, NULL, NULL);
file_read(&file, path); file_read(&file, path);
if (file.error) { if (file.error) {
config->error = true;
return; 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); line = strtok_r(file.content, "\n", &rest);
while (line != NULL) { while (line != NULL) {
@@ -88,6 +92,17 @@ void config_file_read(ConfigFile *config, const char *path) {
file_free(&file); file_free(&file);
} }
bool config_file_has(const ConfigFile *config, const char *key) {
ConfigFileItem c_key;
const ConfigFileItem *item;
strlcpy(c_key.key, key, STR_LEN);
item = (const ConfigFileItem *)hashmap_get(config->map, &c_key);
return item != NULL && strnlen(item->value, STR_LEN) > 0;
}
const char *config_file_get_str(const ConfigFile *config, const char *key, const char *config_file_get_str(const ConfigFile *config, const char *key,
const char *default_value) { const char *default_value) {
ConfigFileItem c_key; ConfigFileItem c_key;
@@ -125,4 +140,8 @@ unsigned int config_file_get_int(const ConfigFile *config, const char *key,
return (unsigned int)atoi(item->value); return (unsigned int)atoi(item->value);
} }
void config_file_free(const ConfigFile *config) { hashmap_free(config->map); } void config_file_free(const ConfigFile *config) {
if (config->map != NULL) {
hashmap_free(config->map);
}
}
+2
View File
@@ -5,6 +5,8 @@
void config_file_read(ConfigFile *config, const char *path); void config_file_read(ConfigFile *config, const char *path);
bool config_file_has(const ConfigFile *config, const char *key);
const char *config_file_get_str(const ConfigFile *config, const char *key, const char *config_file_get_str(const ConfigFile *config, const char *key,
const char *default_value); const char *default_value);
+1 -1
View File
@@ -3,7 +3,7 @@
#ifndef CONSTANTS_H #ifndef CONSTANTS_H
#define CONSTANTS_H #define CONSTANTS_H
static char *vertex_shader_text = static const char *vertex_shader_text =
"#version 460\n" "#version 460\n"
"const mat4 mvp = " "const mat4 mvp = "
"{{2.,0.,0.,0.},{0.,2.,0.,0.},{0.,0.,2.,0.},{-1.,-1.,1.,1.}};\n" "{{2.,0.,0.,0.},{0.,2.,0.,0.},{0.,0.,2.,0.},{-1.,-1.,1.,1.}};\n"
+17 -5
View File
@@ -1,4 +1,3 @@
#include <bsd/string.h>
#include <log.h> #include <log.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
@@ -10,7 +9,6 @@
#include "types.h" #include "types.h"
#include "file.h" #include "file.h"
#include "string.h"
static time_t get_file_time(const File *file) { static time_t get_file_time(const File *file) {
struct stat attr; struct stat attr;
@@ -28,6 +26,7 @@ bool file_should_update(const File *file) {
bool file_update(File *file) { bool file_update(File *file) {
long length; long length;
size_t read_length;
FILE *file_pointer; FILE *file_pointer;
// free remaining data // free remaining data
@@ -49,6 +48,12 @@ bool file_update(File *file) {
// read file length // read file length
fseek(file_pointer, 0, SEEK_END); fseek(file_pointer, 0, SEEK_END);
length = ftell(file_pointer); 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 // init buffer
fseek(file_pointer, 0, SEEK_SET); fseek(file_pointer, 0, SEEK_SET);
file->content = malloc(length + 1); file->content = malloc(length + 1);
@@ -59,7 +64,13 @@ bool file_update(File *file) {
return false; return false;
} }
// read file // 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 // close file
fclose(file_pointer); fclose(file_pointer);
// append null byte // append null byte
@@ -119,8 +130,9 @@ void file_write(const char *path, const StringArray *lines) {
fclose(file_pointer); fclose(file_pointer);
} }
void file_free(const File *file) { void file_free(File *file) {
if (!file->error) { if (!file->error && file->content != NULL) {
free(file->content); free(file->content);
file->content = NULL;
} }
} }
+1 -1
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_dump(const char *path, const char *content);
void file_free(const File *file); void file_free(File *file);
#endif /* FILE_H */ #endif /* FILE_H */
+270 -126
View File
@@ -1,45 +1,47 @@
#include <log.h> #include <log.h>
#include <math.h> #include <math.h>
#include <pthread.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/wait.h> #include <unistd.h>
#include "types.h" #include "types.h"
#include "config.h" #include "config.h"
#include "config_file.h" #include "config_file.h"
#include "file.h"
#include "forge.h" #include "forge.h"
#include "midi.h" #include "midi.h"
#include "project.h" #include "project.h"
#include "shaders.h" #include "shaders.h"
#include "shared.h"
#include "state.h" #include "state.h"
#include "tempo.h" #include "tempo.h"
#include "timer.h" #include "timer.h"
#include "video.h" #include "video.h"
#include "window.h" #include "window.h"
static SharedContext *context; static Parameters init_params;
static Context context;
static ShaderProgram program; static ShaderProgram program;
static Window *window_output; static Window *window_output;
static Window *window_monitor; static Window *window_monitor;
static VideoCaptureArray inputs;
static Timer timer; static Timer timer;
static MidiDevice midi; static MidiDevice midi;
static bool trace_midi;
static Project project; 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; double fps;
char title[STR_LEN]; char title[STR_LEN];
if (timer_inc(&timer)) { if (timer_inc(&timer)) {
fps = timer_reset(&timer); fps = timer_reset(&timer);
if (trace_fps) { if (init_params.trace_fps) {
log_trace("(main) %.2ffps", fps); log_trace("(main) %.2ffps", fps);
} }
@@ -53,178 +55,249 @@ static void compute_fps(bool trace_fps) {
window_update_title(window_monitor, title); 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) { static void init_context() {
state_init(context, &project.state_config, params->demo, params->auto_random, context.stop = false;
params->base_tempo, params->state_file, params->load_state);
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)); #ifdef VIDEO_IN
memset(context->input_formats, 0, sizeof(context->input_formats)); memset(context.input_resolutions, 0, sizeof(context.input_resolutions));
memset(context->input_fps, 0, sizeof(context->input_fps)); 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++) { memset(context.input_index, 0, sizeof(context.input_index));
if (!inputs.values[i].error) { #endif /* VIDEO_IN */
context->input_resolutions[i][0] = inputs.values[i].width;
context->input_resolutions[i][1] = inputs.values[i].height;
context->input_formats[i] = inputs.values[i].pixelformat;
} }
}
}
static void free_context() { shared_close_context(context); }
static void reload_shader(unsigned int i) { static void reload_shader(unsigned int i) {
shaders_update(&program, &project.fragment_shaders[i][0], i, &project); shaders_update(&program, &project.fragment_shaders[i][0], i, &project);
} }
static void init_inputs(const StringArray *video_in, unsigned int video_size) { #ifdef VIDEO_IN
inputs.length = video_in->length;
for (unsigned int i = 0; i < video_in->length; i++) { static void init_inputs() {
video_init(&inputs.values[i], video_in->values[i], video_size); video_captures.length = init_params.video_in.length;
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,
init_params.video_fourcc, 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;
}
} }
} }
static bool start_video_captures(unsigned int video_count, bool trace_fps) { static void start_video_background_read(VideoCapture *video_capture,
for (unsigned int i = 0; i < video_count; i++) { Context *context, int input_index,
if (!inputs.values[i].error && bool trace_fps) {
!video_background_read(&inputs.values[i], context, i, trace_fps)) { pthread_t thread;
return false; 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);
} }
} }
return true; 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,
init_params.video_fourcc, 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 free_video_captures(unsigned int video_count) { static void start_video_captures() {
for (unsigned int i = 0; i < video_count; i++) { pthread_t thread;
shaders_free_input(&program, &inputs.values[i]); 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");
}
}
}
video_free(&inputs.values[i]); 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) { static void error_callback(int error, const char *description) {
log_error("[GLFW] %d: %s", error, description); log_error("[GLFW] %d: %s", error, description);
window_terminate(); window_terminate();
context->stop = true; context.stop = true;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
static void key_callback(Window *window, int key, static void key_callback(Window *window, int key,
__attribute__((unused)) int scancode, int action, __attribute__((unused)) int scancode, int action,
__attribute__((unused)) int mods) { int mods) {
unsigned int event;
event = window_read_key(key, action, mods);
if (window_escape_key(key, action)) { if (window_escape_key(key, action)) {
// close window on escape key // close window on escape key
log_info("[ESC] Closing..."); log_info("[ESC] Closing...");
window_close(window); window_close(window);
} else if (window_char_key(key, action, 82)) { } else if (event > 0) {
// R: randomize state_key_event(&context, project.state_config, event, midi);
log_info("[R] Randomized");
state_randomize(context, &project.state_config);
state_apply(context, &project.state_config, &midi);
} else if (window_char_key(key, action, 48)) {
// 0: reset
log_info("[0] Reset");
state_reset(context);
state_apply(context, &project.state_config, &midi);
} else if (window_char_key(key, action, 68)) {
// D: demo on/off
log_info((context->demo ? "[D] Demo OFF" : "[D] Demo ON"));
context->demo = !context->demo;
} else if (window_char_key(key, action, 65)) {
// A: auto random on/off
log_info(
(context->auto_random ? "[A] Auto Random OFF" : "[A] Auto Random ON"));
context->auto_random = !context->auto_random;
} }
} }
static void midi_callback(unsigned char code, unsigned char value) { static void midi_callback(unsigned char code, unsigned char value) {
state_apply_event(context, &project.state_config, &midi, code, value, state_midi_event(&context, project.state_config, midi, code, value,
trace_midi); init_params.trace_midi);
} }
static void loop(bool hr, bool trace_fps) { static void start_state_background_write() {
if (hr) { pthread_t thread;
project_reload(&project, reload_shader); 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); static void start_midi_background_listen() {
pthread_t thread;
context->time = window_get_time(); MidiBackgroundListenArgs *process_args =
context->tempo_total = (float)tempo_total(&context->tempo); (MidiBackgroundListenArgs *)malloc(sizeof(MidiBackgroundListenArgs));
process_args->device = &midi;
if (window_output != NULL) { process_args->context = &context;
window_use(window_output, context); process_args->event_callback = midi_callback;
if (pthread_create(&thread, NULL, midi_background_listen, process_args) ==
shaders_compute(&program, context, false, false); 0) {
pthread_detach(thread);
window_refresh(window_output); } else {
log_error("background midi acquisition failed to start");
free(process_args);
}
} }
if (window_monitor != NULL) { static void *background_reconnect_midi(__attribute__((unused)) void *args) {
window_use(window_monitor, context); log_info("background midi reconnect started");
while (!context.stop) {
shaders_compute(&program, context, true, window_output != NULL); sleep(1);
if (!midi.connected) {
window_refresh(window_monitor); midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"),
false);
if (midi.connected) {
start_midi_background_listen();
}
}
}
pthread_exit(NULL);
} }
window_events(); 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();
} }
void forge_run(const Parameters *params) { if (init_params.midi_reconnect) {
context = shared_init_context("/" PACKAGE "_context"); if (pthread_create(&thread, NULL, background_reconnect_midi, NULL) == 0) {
pthread_detach(thread);
} else {
log_error("background midi reconnect failed to start");
}
}
}
context->stop = false; static bool init(const Parameters *params) {
init_params = *params;
project_init(&project, params->project_path, params->config_file); project_init(&project, params->project_path, params->config_file);
if (project.error) { 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)) { start_video_captures();
return; #endif /* VIDEO_IN */
}
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw")); init_midi();
if (midi.error) { start_state_background_write();
context->demo = true;
} else {
trace_midi = params->trace_midi;
if (!midi_background_listen(&midi, context, midi_callback)) {
return;
}
}
if (!state_background_write(context, &project.state_config, &midi)) {
return;
}
window_startup(error_callback); 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) { if (params->output) {
window_output = window_init(PACKAGE " " VERSION, params->output_screen, window_output = window_init(PACKAGE " " VERSION, params->output_screen,
params->windowed, NULL, key_callback); 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 { } else {
window_output = NULL; window_output = NULL;
} }
@@ -234,15 +307,24 @@ void forge_run(const Parameters *params) {
window_init(PACKAGE " " VERSION " (monitor)", params->monitor_screen, window_init(PACKAGE " " VERSION " (monitor)", params->monitor_screen,
params->windowed, window_output, key_callback); 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 { } else {
window_monitor = NULL; window_monitor = NULL;
} }
#ifdef VIDEO_IN
if (params->output && params->monitor) {
window_use(window_output, &context);
}
shaders_link_inputs(&program, &project, &video_captures,
init_params.video_buffers);
#endif /* VIDEO_IN */
if (program.error) { if (program.error) {
context->stop = true; context.stop = true;
window_terminate(); window_terminate();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -251,36 +333,98 @@ void forge_run(const Parameters *params) {
log_info("Initialized"); log_info("Initialized");
while ((window_output == NULL || !window_should_close(window_output)) && return true;
(window_monitor == NULL || !window_should_close(window_monitor))) {
loop(params->hot_reload, params->trace_fps);
} }
context->stop = true; static bool should_close() {
return (window_output != NULL && window_should_close(window_output)) ||
if (params->save_state) { (window_monitor != NULL && window_should_close(window_monitor));
state_save(context, &project.state_config, params->state_file);
} }
shaders_free(&program); static bool loop() {
if (init_params.hot_reload) {
project_reload(&project, reload_shader);
}
#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 */
compute_fps();
context.time = window_get_time();
context.tempo_total = (float)tempo_total(&context.tempo);
if (window_output != NULL) { 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); shaders_free_window(&program, false);
} }
if (window_monitor != NULL) { if (window_monitor != NULL) {
window_use(window_monitor, context); window_use(window_monitor, &context);
shaders_free_window(&program, params->output); shaders_free_window(&program, init_params.output);
} }
free_video_captures(params->video_in.length); shaders_free(&program);
free_context(); #ifdef VIDEO_IN
free_video_captures();
#endif /* VIDEO_IN */
midi_close(&midi);
project_free(&project); project_free(&project);
window_terminate(); window_terminate();
} }
void forge_run(const Parameters *params) {
if (!init(params)) {
return;
}
while (!should_close()) {
if (!loop()) {
return;
}
}
shutdown();
}
+1 -1
View File
@@ -17,7 +17,7 @@ int main(int argc, char **argv) {
puts(PACKAGE " " VERSION); puts(PACKAGE " " VERSION);
set_seed((unsigned long)time(NULL)); rand_set_seed((unsigned long)time(NULL));
forge_run(&params); forge_run(&params);
+64 -30
View File
@@ -1,61 +1,95 @@
#include <GLFW/glfw3.h>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include <bsd/string.h> #include <log.h>
#include <pthread.h>
#include "types.h" #include "types.h"
#include "config.h" #include "config.h"
#include "log.h"
void midi_open(MidiDevice *device, const char *name) { void 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); strlcpy(device->name, name, STR_LEN);
device->connected = false;
device->input = NULL; device->input = NULL;
device->output = NULL; device->output = NULL;
snd_rawmidi_open(&device->input, &device->output, name, SND_RAWMIDI_NONBLOCK); device->connected = snd_rawmidi_open(&device->input, &device->output, name,
SND_RAWMIDI_SYNC) == 0 &&
device->error = device->input == NULL || device->output == NULL; device->input != NULL && device->output != NULL;
if (log_error) {
if (device->connected) {
log_info("(%s) MIDI open", name); log_info("(%s) MIDI open", name);
} else {
log_warn("(%s) MIDI open failed", name);
}
}
}
void midi_write(MidiDevice device, unsigned char code, unsigned char value) {
if (!device.connected) {
return;
} }
void midi_write(const MidiDevice *device, unsigned char code,
unsigned char value) {
unsigned char buffer[3]; unsigned char buffer[3];
buffer[0] = 0xB0; buffer[0] = 0xB0;
buffer[1] = code; buffer[1] = code;
buffer[2] = value; buffer[2] = value;
snd_rawmidi_write(device->output, buffer, 3); snd_rawmidi_write(device.output, buffer, 3);
} }
bool midi_background_listen(const MidiDevice *device, void midi_close(MidiDevice *device) {
const SharedContext *context, if (device->connected) {
void (*event_callback)(unsigned char code, snd_rawmidi_close(device->input);
unsigned char value)) { snd_rawmidi_close(device->output);
pid_t pid; 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; int bytes_read;
snd_rawmidi_info_t *info;
unsigned char buffer[3]; unsigned char buffer[3];
pid = fork(); log_info("(%s) background acquisition started", device->name);
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);
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); bytes_read = snd_rawmidi_read(device->input, buffer, 3);
if (bytes_read == 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)", snd_rawmidi_info_free(info);
device->name, pid);
return false; 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);
} }
+4 -7
View File
@@ -3,12 +3,9 @@
#ifndef MIDI_H #ifndef MIDI_H
#define MIDI_H #define MIDI_H
void midi_open(MidiDevice *device, const char *name); void midi_open(MidiDevice *device, const char *name, bool log_error);
void midi_write(const MidiDevice *device, unsigned char code, void midi_write(MidiDevice device, unsigned char code, unsigned char value);
unsigned char value); void *midi_background_listen(void *args);
bool midi_background_listen(const MidiDevice *device, void midi_close(MidiDevice *device);
const SharedContext *context,
void (*event_callback)(unsigned char code,
unsigned char value));
#endif /* MIDI_H */ #endif /* MIDI_H */
+11 -3
View File
@@ -1,4 +1,4 @@
#include <bsd/string.h> #include <log.h>
#include <string.h> #include <string.h>
#include "types.h" #include "types.h"
@@ -6,7 +6,6 @@
#include "config.h" #include "config.h"
#include "config_file.h" #include "config_file.h"
#include "file.h" #include "file.h"
#include "log.h"
#include "project.h" #include "project.h"
#include "state.h" #include "state.h"
#include "string.h" #include "string.h"
@@ -49,6 +48,8 @@ static bool parse_fragment_shader_file(Project *project, unsigned int i) {
include_end - project->fragment_shaders[i][0].content, include_end - project->fragment_shaders[i][0].content,
tmp_file.content); tmp_file.content);
free(project->fragment_shaders[i][0].content);
project->fragment_shaders[i][0].content = new_content; project->fragment_shaders[i][0].content = new_content;
file_free(&tmp_file); file_free(&tmp_file);
@@ -103,6 +104,12 @@ void project_init(Project *project, const char *project_path,
project->sub_counts.length = project->frag_count; 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++) { for (unsigned int i = 0; i < project->frag_count; i++) {
project->sub_counts.values[i] = 0; project->sub_counts.values[i] = 0;
if (!read_fragment_shader_file(project, frag_prefix, i)) { if (!read_fragment_shader_file(project, frag_prefix, i)) {
@@ -135,9 +142,10 @@ 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++) { for (unsigned int i = 0; i < project->frag_count; i++) {
file_free(&project->fragment_shaders[i][0]); file_free(&project->fragment_shaders[i][0]);
// other sub files contents are freed at parse_fragment_shader_file
} }
config_file_free(&project->config); config_file_free(&project->config);
+1 -1
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_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 */
+4 -4
View File
@@ -4,7 +4,7 @@ static unsigned long long mcg_state = 0xcafef00dd15ea5e5u; // Must be odd
static unsigned long long const multiplier = 6364136223846793005u; static unsigned long long const multiplier = 6364136223846793005u;
// https://en.wikipedia.org/wiki/Permuted_congruential_generator // 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 long long x = mcg_state;
unsigned count = (unsigned)(x >> 61); unsigned count = (unsigned)(x >> 61);
@@ -13,11 +13,11 @@ static unsigned long rand(void) {
return (unsigned long)(x >> (22 + count)); return (unsigned long)(x >> (22 + count));
} }
void set_seed(unsigned long long seed) { void rand_set_seed(unsigned long long seed) {
mcg_state = 2 * seed + 1; mcg_state = 2 * seed + 1;
(void)rand(); (void)fast_rand();
} }
unsigned int rand_uint(const unsigned int max) { unsigned int rand_uint(const unsigned int max) {
return max == 0 ? 0 : (unsigned int)(rand() % max); return max == 0 ? 0 : (unsigned int)(fast_rand() % max);
} }
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef RAND_H #ifndef RAND_H
#define RAND_H #define RAND_H
void set_seed(unsigned long long seed); void rand_set_seed(unsigned long long seed);
unsigned int rand_uint(unsigned int max); unsigned int rand_uint(unsigned int max);
#endif #endif
+489 -175
View File
@@ -14,75 +14,202 @@
#define GLAD_GL_IMPLEMENTATION #define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h> #include <glad/gl.h>
#ifdef VIDEO_IN
#define GLAD_EGL_IMPLEMENTATION #define GLAD_EGL_IMPLEMENTATION
#include <glad/egl.h> #include <glad/egl.h>
#endif /* VIDEO_IN */
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#ifdef VIDEO_IN
#include <GLFW/glfw3native.h> #include <GLFW/glfw3native.h>
#endif /* VIDEO_IN */
static const GLuint unused_uniform = (GLuint)-1; static const GLint UNUSED_UNIFORM = -1;
bool check_glerror(ShaderProgram *program) { static bool check_glerror_ro(const char *context) {
unsigned int code; unsigned int code;
code = glGetError(); code = glGetError();
if (code > 0) { if (code > 0) {
log_warn("GL Error: %04x", code); log_warn("GL Error: %04x (%s)", code, context);
return true;
}
return false;
}
static bool check_glerror(ShaderProgram *program, const char *context) {
if (check_glerror_ro(context)) {
program->error = true; program->error = true;
return true;
}
return false;
} }
return code > 0; #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)");
} }
static void init_gl(ShaderProgram *program) { #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); gladLoadGL(glfwGetProcAddress);
#ifdef GL_DEBUG
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(gl_debug_callback, NULL);
#endif /* GL_DEBUG */
#ifdef VIDEO_IN
program->egl_display = glfwGetEGLDisplay(); program->egl_display = glfwGetEGLDisplay();
if (program->egl_display == EGL_NO_DISPLAY) { if (program->egl_display == EGL_NO_DISPLAY) {
log_error("error: glfwGetEGLDisplay no EGLDisplay returned"); log_error("error: glfwGetEGLDisplay no EGLDisplay returned");
program->error = true; program->error = true;
return; return false;
} }
gladLoadEGL(program->egl_display, glfwGetProcAddress); gladLoadEGL(program->egl_display, glfwGetProcAddress);
#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);
}
} }
static void init_textures(ShaderProgram *program, #endif /* EGL_DEBUG */
const SharedContext *context) {
#endif /* VIDEO_IN */
return !check_glerror(program, "init_gl") &&
!check_eglerror(program, "init_gl");
}
static bool init_textures(ShaderProgram *program, const Context *context) {
glGenTextures(program->tex_count, program->textures); glGenTextures(program->tex_count, program->textures);
if (check_glerror(program, "init_textures/glGenTextures")) {
return false;
}
for (unsigned int i = 0; i < program->tex_count; i++) { for (unsigned int i = 0; i < program->tex_count; i++) {
// selects which texture unit subsequent texture state calls will affect // selects which texture unit subsequent texture state calls will affect
glActiveTexture(GL_TEXTURE0 + i); glActiveTexture(GL_TEXTURE0 + i);
if (check_glerror(program, "init_textures/glActiveTexture")) {
return false;
}
glBindTexture(GL_TEXTURE_2D, program->textures[i]); glBindTexture(GL_TEXTURE_2D, program->textures[i]);
if (check_glerror(program, "init_textures/glBindTexture")) {
return false;
}
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND); glDisable(GL_BLEND);
if (check_glerror(program, "init_textures/glDisable")) {
return false;
}
// define texture image as empty // define texture image as empty
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0], glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0); context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
if (check_glerror(program, "init_textures/glTexImage2D")) {
return false;
}
// setup mipmap context // setup mipmap context
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
if (check_glerror(program, "init_textures/glTexParameteri")) {
return false;
}
log_info("Texture %d initialized", i); log_info("Texture %d initialized", i);
} }
return true;
} }
static void rebind_textures(const ShaderProgram *program) { static void rebind_textures(const ShaderProgram *program) {
for (unsigned int i = 0; i < program->tex_count; i++) { for (unsigned int i = 0; i < program->tex_count; i++) {
glActiveTexture(GL_TEXTURE0 + i); glActiveTexture(GL_TEXTURE0 + i);
check_glerror_ro("rebind_textures/glActiveTexture");
glBindTexture(GL_TEXTURE_2D, program->textures[i]); glBindTexture(GL_TEXTURE_2D, program->textures[i]);
check_glerror_ro("rebind_textures/glBindTexture");
} }
} }
static void link_input_to_texture(ShaderProgram *program, VideoCapture *input, #ifdef VIDEO_IN
unsigned int texture_index) { static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input,
input->dma_image = EGL_NO_IMAGE_KHR; unsigned int input_index,
unsigned int 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 // https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
const EGLint attrib_list[] = {EGL_WIDTH, const EGLint attrib_list[] = {EGL_WIDTH,
@@ -92,57 +219,83 @@ static void link_input_to_texture(ShaderProgram *program, VideoCapture *input,
EGL_LINUX_DRM_FOURCC_EXT, EGL_LINUX_DRM_FOURCC_EXT,
input->pixelformat, input->pixelformat,
EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_FD_EXT,
input->exp_fd, input->exp_fd[sub_index],
EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT,
0, 0,
EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE0_PITCH_EXT,
input->bytesperline, input->bytesperline,
EGL_NONE}; EGL_NONE};
input->dma_image = dma_image = eglCreateImageKHR(program->egl_display, EGL_NO_CONTEXT,
eglCreateImageKHR(program->egl_display, EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT, NULL, attrib_list); EGL_LINUX_DMA_BUF_EXT, NULL, attrib_list);
if (check_eglerror(program, "link_input_to_texture/eglCreateImageKHR")) {
if (input->dma_image == EGL_NO_IMAGE_KHR) { return false;
log_error("(%s) eglCreateImageKHR failed %04x", input->name, eglGetError());
return;
} }
program->dma_images[input_index * program->sub_video_count + sub_index] =
dma_image;
glActiveTexture(GL_TEXTURE0 + texture_index); glActiveTexture(GL_TEXTURE0 + texture_index);
if (check_glerror(program, "link_input_to_texture/glActiveTexture")) {
return false;
}
glBindTexture(GL_TEXTURE_2D, program->textures[texture_index]); glBindTexture(GL_TEXTURE_2D, program->textures[texture_index]);
if (check_glerror(program, "link_input_to_texture/glBindTexture")) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, input->width, input->height, 0, GL_RGB, return false;
GL_UNSIGNED_BYTE, 0); }
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt // https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt
glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, input->dma_image, NULL); glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, dma_image, NULL);
if (check_eglerror(program,
log_info("Texture %d linked to %s", texture_index, input->name); "link_input_to_texture/glEGLImageTargetTexStorageEXT")) {
return false;
} }
static void init_input(ShaderProgram *program, const ConfigFile *config, log_info("Texture %d linked to %s[%d]", texture_index, input->name,
VideoCaptureArray *inputs) { sub_index);
return true;
}
static bool init_input(ShaderProgram *program, const ConfigFile *config,
VideoCaptureArray *inputs, unsigned int input_index,
bool reload) {
unsigned int tex_i; unsigned int tex_i;
unsigned int sub_index;
char name[STR_LEN]; char name[STR_LEN];
for (unsigned int i = 0; i < program->in_count; i++) { if (input_index < inputs->length && input_index < program->in_count &&
if (i < inputs->length && !inputs->values[i].error) { !inputs->values[input_index].error) {
snprintf(name, STR_LEN, "IN_%d_OUT", i + 1); snprintf(name, STR_LEN, "IN_%d_OUT", input_index + 1);
tex_i = config_file_get_int(config, name, 0); tex_i = config_file_get_int(config, name, 0);
link_input_to_texture(program, &inputs->values[i], tex_i); 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 { } else {
log_warn("Cannot link input %d", i + 1); 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) { const ConfigFile *config) {
unsigned int tex_i; unsigned int tex_i;
char name[STR_LEN]; char name[STR_LEN];
GLenum framebuffer_status;
glGenFramebuffers(program->frag_count, program->frame_buffers); glGenFramebuffers(program->frag_count, program->frame_buffers);
if (check_glerror(program, "init_framebuffers/glGenFramebuffers")) {
return false;
}
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
if (i == program->frag_output_index || i == program->frag_monitor_index) { if (i == program->frag_output_index || i == program->frag_monitor_index) {
@@ -150,50 +303,89 @@ static void init_framebuffers(ShaderProgram *program,
} }
glBindFramebuffer(GL_FRAMEBUFFER, program->frame_buffers[i]); glBindFramebuffer(GL_FRAMEBUFFER, program->frame_buffers[i]);
if (check_glerror(program, "init_framebuffers/glBindFramebuffer")) {
return false;
}
snprintf(name, STR_LEN, "FRAG_%d_OUT", i + 1); snprintf(name, STR_LEN, "FRAG_%d_OUT", i + 1);
tex_i = config_file_get_int(config, name, 0); tex_i = config_file_get_int(config, name, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
program->textures[tex_i], 0); program->textures[tex_i], 0);
if (check_glerror(program, "init_framebuffers/glFramebufferTexture2D")) {
return false;
}
// check framebuffer status // check framebuffer status
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { framebuffer_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
log_error("Framebuffer %d is KO: %x", i + 1, if (check_glerror(program, "init_framebuffers/glCheckFramebufferStatus")) {
glCheckFramebufferStatus(GL_FRAMEBUFFER)); return false;
}
if (framebuffer_status != GL_FRAMEBUFFER_COMPLETE) {
log_error("Framebuffer %d is KO: %x", i + 1, framebuffer_status);
program->error = true; program->error = true;
return false;
return;
} }
log_info("Framebuffer %d initialized", i); log_info("Framebuffer %d initialized", i);
} }
return; return true;
} }
static void init_vertices(ShaderProgram *program) { static bool init_vertices(ShaderProgram *program) {
glGenBuffers(1, &program->vertex_buffer); glGenBuffers(1, &program->vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer); if (check_glerror(program, "init_vertices/glGenBuffers")) {
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); return false;
} }
static void bind_vertices(ShaderProgram *program, unsigned int index) {
glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer);
if (check_glerror(program, "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 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]); glGenVertexArrays(1, &program->vertex_array[index]);
if (check_glerror(program, "bind_vertices/glGenVertexArrays")) {
return false;
}
glBindVertexArray(program->vertex_array[index]); glBindVertexArray(program->vertex_array[index]);
if (check_glerror(program, "bind_vertices/glBindVertexArray")) {
return false;
}
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
// enable attribute pointer // enable attribute pointer
glEnableVertexAttribArray(program->vpos_locations[i]); glEnableVertexAttribArray(program->vpos_locations[i]);
if (check_glerror(program, "bind_vertices/glEnableVertexAttribArray")) {
return false;
}
// specify the location and data format of the array of generic vertex // specify the location and data format of the array of generic vertex
// attributes to use when rendering // attributes to use when rendering
glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (void *)offsetof(Vertex, pos)); sizeof(Vertex), (void *)offsetof(Vertex, pos));
if (check_glerror(program, "bind_vertices/glVertexAttribPointer")) {
return false;
} }
} }
return true;
}
static bool compile_shader(GLuint shader_id, const char *name, static bool compile_shader(GLuint shader_id, const char *name,
const char *source_code) { const char *source_code) {
GLint status_params; GLint status_params;
@@ -203,13 +395,18 @@ static bool compile_shader(GLuint shader_id, const char *name,
// update shader source code // update shader source code
glShaderSource(shader_id, 1, &source_code, NULL); glShaderSource(shader_id, 1, &source_code, NULL);
check_glerror_ro("compile_shader/glShaderSource");
// compile shader // compile shader
glCompileShader(shader_id); glCompileShader(shader_id);
check_glerror_ro("compile_shader/glCompileShader");
// get compilation status // get compilation status
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params); glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params);
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) { if (status_params == GL_FALSE) {
log_error("Failed to compile\n%s", log); log_error("Failed to compile\n%s", log);
@@ -221,9 +418,13 @@ static bool compile_shader(GLuint shader_id, const char *name,
return status_params == GL_TRUE; return status_params == GL_TRUE;
} }
static void init_shaders(ShaderProgram *program, const Project *project) { static bool init_shaders(ShaderProgram *program, const Project *project) {
// compile vertex shader // compile vertex shader
program->vertex_shader = glCreateShader(GL_VERTEX_SHADER); program->vertex_shader = glCreateShader(GL_VERTEX_SHADER);
if (check_glerror(program, "init_shaders/glCreateShader")) {
return false;
}
program->error = program->error || !compile_shader(program->vertex_shader, program->error = program->error || !compile_shader(program->vertex_shader,
"internal vertex shader", "internal vertex shader",
vertex_shader_text); vertex_shader_text);
@@ -231,30 +432,61 @@ static void init_shaders(ShaderProgram *program, const Project *project) {
// compile fragment shaders // compile fragment shaders
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER); program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER);
if (check_glerror(program, "init_shaders/glCreateShader")) {
return false;
}
program->error = program->error || program->error = program->error ||
!compile_shader(program->fragment_shaders[i], !compile_shader(program->fragment_shaders[i],
project->fragment_shaders[i][0].path, project->fragment_shaders[i][0].path,
project->fragment_shaders[i][0].content); project->fragment_shaders[i][0].content);
if (program->error) { if (program->error) {
return; return false;
}
} }
} }
static void init_single_program(ShaderProgram *program, unsigned int i, return true;
}
static bool init_single_program(ShaderProgram *program, unsigned int i,
const ConfigFile *config, const ConfigFile *config,
const StateConfig *state_config) { const StateConfig *state_config) {
unsigned int index1; unsigned int index1;
unsigned int index2; unsigned int index2;
char name[STR_LEN]; char name[STR_LEN];
const char *prefix; const char *prefix;
GLint link_status;
char link_log[STR_LEN];
program->programs[i] = glCreateProgram(); program->programs[i] = glCreateProgram();
if (check_glerror(program, "init_single_program/glCreateProgram")) {
return false;
}
glAttachShader(program->programs[i], program->vertex_shader); glAttachShader(program->programs[i], program->vertex_shader);
glAttachShader(program->programs[i], program->fragment_shaders[i]); glAttachShader(program->programs[i], program->fragment_shaders[i]);
if (check_glerror(program, "init_single_program/glAttachShader")) {
return false;
}
glLinkProgram(program->programs[i]); glLinkProgram(program->programs[i]);
if (check_glerror(program, "init_single_program/glLinkProgram")) {
return false;
}
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 // create uniforms pointers
program->itime_locations[i] = glGetUniformLocation( program->itime_locations[i] = glGetUniformLocation(
@@ -280,6 +512,9 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
program->iautorand_locations[i] = glGetUniformLocation( program->iautorand_locations[i] = glGetUniformLocation(
program->programs[i], program->programs[i],
config_file_get_str(config, "UNIFORM_AUTORAND", "iAutoRand")); config_file_get_str(config, "UNIFORM_AUTORAND", "iAutoRand"));
program->iautorandcycle_locations[i] = glGetUniformLocation(
program->programs[i],
config_file_get_str(config, "UNIFORM_AUTORANDCYCLE", "iAutoRandCycle"));
program->ipage_locations[i] = glGetUniformLocation( program->ipage_locations[i] = glGetUniformLocation(
program->programs[i], program->programs[i],
config_file_get_str(config, "UNIFORM_PAGE", "iPage")); config_file_get_str(config, "UNIFORM_PAGE", "iPage"));
@@ -324,18 +559,6 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
glGetUniformLocation(program->programs[i], name); glGetUniformLocation(program->programs[i], name);
} }
for (unsigned int j = 0; j < program->sub_type_count; j++) {
snprintf(name, STR_LEN, "SUB_%d_PREFIX", j + 1);
prefix = config_file_get_str(config, name, 0);
for (unsigned int k = 0; k < program->sub_variant_count; k++) {
snprintf(name, STR_LEN, "%s%d", prefix, k + 1);
program->sub_locations[i * program->sub_variant_count *
program->sub_type_count +
j * program->sub_variant_count + k] =
glGetSubroutineIndex(program->programs[i], GL_FRAGMENT_SHADER, name);
}
}
prefix = config_file_get_str(config, "UNIFORM_ACTIVE_PREFIX", "iActive"); prefix = config_file_get_str(config, "UNIFORM_ACTIVE_PREFIX", "iActive");
for (unsigned int j = 0; j < program->active_count; j++) { for (unsigned int j = 0; j < program->active_count; j++) {
snprintf(name, STR_LEN, "%s%d", prefix, j + 1); snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
@@ -345,23 +568,24 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
if (program->midi_lengths.length == 0) { if (program->midi_lengths.length == 0) {
index1 = 0; index1 = 0;
for (unsigned int j = 0; j < state_config->midi_active_counts.length; j++) { for (unsigned int j = 0; j < state_config->group_active_counts.length;
for (unsigned int k = 0; k < state_config->midi_active_counts.values[j]; j++) {
for (unsigned int k = 0; k < state_config->group_active_counts.values[j];
k++) { k++) {
program->midi_lengths.values[index1++] = program->midi_lengths.values[index1++] =
state_config->midi_counts.values[j]; state_config->group_counts.values[j];
} }
} }
program->midi_lengths.length = index1; 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; index2 = 0;
for (unsigned int j = 0; j < state_config->midi_active_counts.length; j++) { for (unsigned int j = 0; j < state_config->group_active_counts.length; j++) {
for (unsigned int k = 0; k < state_config->midi_active_counts.values[j]; for (unsigned int k = 0; k < state_config->group_active_counts.values[j];
k++) { k++) {
snprintf(name, STR_LEN, "%s%d_%d", prefix, j + 1, k + 1); 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); glGetUniformLocation(program->programs[i], name);
} }
} }
@@ -374,147 +598,95 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
glGetUniformLocation(program->programs[i], name); glGetUniformLocation(program->programs[i], name);
} }
if (check_glerror(program, "init_single_program/glGetUniformLocation")) {
return false;
}
for (unsigned int j = 0; j < program->sub_type_count; j++) {
snprintf(name, STR_LEN, "SUB_%d_PREFIX", j + 1);
prefix = config_file_get_str(config, name, 0);
for (unsigned int k = 0; k < program->sub_variant_count; k++) {
snprintf(name, STR_LEN, "%s%d", prefix, k + 1);
program->sub_locations[i * program->sub_variant_count *
program->sub_type_count +
j * program->sub_variant_count + k] =
glGetSubroutineIndex(program->programs[i], GL_FRAGMENT_SHADER, name);
}
}
if (check_glerror(program, "init_single_program/glGetSubroutineIndex")) {
return false;
}
// create attribute pointer // create attribute pointer
program->vpos_locations[i] = program->vpos_locations[i] =
glGetAttribLocation(program->programs[i], "vPos"); glGetAttribLocation(program->programs[i], "vPos");
log_info("Program %d initialized", i + 1); if (check_glerror(program, "init_single_program/glGetAttribLocation")) {
return false;
} }
static void init_programs(ShaderProgram *program, const ConfigFile *config, log_info("Program %d initialized", i + 1);
return true;
}
static bool init_programs(ShaderProgram *program, const ConfigFile *config,
const StateConfig *state_config) { const StateConfig *state_config) {
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
init_single_program(program, i, config, state_config); if (!init_single_program(program, i, config, state_config)) {
return false;
} }
} }
void shaders_init(ShaderProgram *program, const Project *project, return true;
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); static void update_viewport(ShaderProgram *program, const Context *context) {
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) {
// viewport changed // viewport changed
if (context->resolution[0] != program->last_resolution[0] || if (context->resolution[0] != program->last_resolution[0] ||
context->resolution[1] != program->last_resolution[1]) { context->resolution[1] != program->last_resolution[1]) {
// clean and resize all textures // clean and resize all textures
for (unsigned int i = 0; i < program->tex_count; i++) { for (unsigned int i = 0; i < program->tex_count; i++) {
glActiveTexture(GL_TEXTURE0 + i); glActiveTexture(GL_TEXTURE0 + i);
check_glerror_ro("update_viewport/glActiveTexture");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0], glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0); context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
check_glerror_ro("update_viewport/glTexImage2D");
} }
program->last_resolution[0] = context->resolution[0]; program->last_resolution[0] = context->resolution[0];
program->last_resolution[1] = context->resolution[1]; program->last_resolution[1] = context->resolution[1];
} }
} }
static void write_uniform_1f(GLuint location, float value) { static void write_uniform_1f(GLint location, float value) {
if (location != unused_uniform) { if (location != UNUSED_UNIFORM) {
glUniform1f(location, value); glUniform1f(location, value);
} }
} }
static void write_uniform_1i(GLuint location, unsigned int value) { static void write_uniform_1i(GLint location, unsigned int value) {
if (location != unused_uniform) { if (location != UNUSED_UNIFORM) {
glUniform1i(location, (const GLint)value); glUniform1i(location, (const GLint)value);
} }
} }
static void write_uniform_2f(GLuint location, const vec2 *value) { static void write_uniform_2f(GLint location, const vec2 *value) {
if (location != unused_uniform) { if (location != UNUSED_UNIFORM) {
glUniform2fv(location, 1, (const GLfloat *)value); 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) { const vec3 *value) {
if (location != unused_uniform) { if (location != UNUSED_UNIFORM) {
glUniform3fv(location, count, (const GLfloat *)value); glUniform3fv(location, count, (const GLfloat *)value);
} }
} }
static void use_program(const ShaderProgram *program, int i, bool output, static void use_program(const ShaderProgram *program, int i, bool output,
const SharedContext *context) { const Context *context) {
unsigned int k; unsigned int k;
unsigned int offset; unsigned int offset;
unsigned int subcount; unsigned int subcount;
@@ -545,6 +717,8 @@ static void use_program(const ShaderProgram *program, int i, bool output,
write_uniform_1i(program->idemo_locations[i], context->demo ? 1 : 0); write_uniform_1i(program->idemo_locations[i], context->demo ? 1 : 0);
write_uniform_1i(program->iautorand_locations[i], write_uniform_1i(program->iautorand_locations[i],
context->auto_random ? 1 : 0); context->auto_random ? 1 : 0);
write_uniform_1i(program->iautorandcycle_locations[i],
context->auto_random_cycle);
write_uniform_1i(program->ipage_locations[i], context->page); write_uniform_1i(program->ipage_locations[i], context->page);
write_uniform_1i(program->iselected_locations[i], context->selected + 1); write_uniform_1i(program->iselected_locations[i], context->selected + 1);
write_uniform_2f(program->ires_locations[i], &context->resolution); write_uniform_2f(program->ires_locations[i], &context->resolution);
@@ -555,6 +729,8 @@ static void use_program(const ShaderProgram *program, int i, bool output,
context->active[j] + 1); context->active[j] + 1);
} }
#ifdef VIDEO_IN
for (unsigned int j = 0; j < program->in_count; j++) { for (unsigned int j = 0; j < program->in_count; j++) {
write_uniform_2f(program->iinres_locations[i * program->in_count + j], write_uniform_2f(program->iinres_locations[i * program->in_count + j],
&context->input_resolutions[j]); &context->input_resolutions[j]);
@@ -564,6 +740,8 @@ static void use_program(const ShaderProgram *program, int i, bool output,
context->input_fps[j]); context->input_fps[j]);
} }
#endif /* VIDEO_IN */
// set seeds uniforms // set seeds uniforms
for (unsigned int j = 0; j < program->frag_count; j++) { for (unsigned int j = 0; j < program->frag_count; j++) {
write_uniform_1i(program->iseed_locations[i * program->frag_count + j], write_uniform_1i(program->iseed_locations[i * program->frag_count + j],
@@ -578,7 +756,7 @@ static void use_program(const ShaderProgram *program, int i, bool output,
offset = 0; offset = 0;
for (unsigned int j = 0; j < program->midi_lengths.length; j++) { for (unsigned int j = 0; j < program->midi_lengths.length; j++) {
write_uniform_multi_3f( 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); program->midi_lengths.values[j], context->values + offset);
offset += program->midi_lengths.values[j]; offset += program->midi_lengths.values[j];
} }
@@ -590,7 +768,7 @@ static void use_program(const ShaderProgram *program, int i, bool output,
if (program->sub_locations[i * program->sub_variant_count * if (program->sub_locations[i * program->sub_variant_count *
program->sub_type_count + program->sub_type_count +
j * program->sub_variant_count + k] != j * program->sub_variant_count + k] !=
unused_uniform) { UNUSED_UNIFORM) {
subroutines[subcount++] = subroutines[subcount++] =
program->sub_locations[i * program->sub_variant_count * program->sub_locations[i * program->sub_variant_count *
program->sub_type_count + program->sub_type_count +
@@ -605,15 +783,137 @@ static void use_program(const ShaderProgram *program, int i, bool output,
// set GL_TEXTURE(X) to uniform sampler2D texX // set GL_TEXTURE(X) to uniform sampler2D texX
for (unsigned int j = 0; j < program->tex_count; j++) { for (unsigned int j = 0; j < program->tex_count; j++) {
write_uniform_1i(program->textures_locations[i * program->tex_count + j], write_uniform_1i(program->textures_locations[i * program->tex_count + j],
j); program->tex_map[j]);
} }
// draw output // draw output
glDrawArrays(GL_TRIANGLES, 0, 6); 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) { bool monitor, bool output_only) {
#ifdef VIDEO_IN
update_inputs_tex_map(program, context);
#endif /* VIDEO_IN */
if (!output_only) { if (!output_only) {
glBindVertexArray(program->vertex_array[0]); glBindVertexArray(program->vertex_array[0]);
@@ -634,25 +934,39 @@ void shaders_compute(ShaderProgram *program, const SharedContext *context,
monitor ? program->frag_monitor_index monitor ? program->frag_monitor_index
: program->frag_output_index, : program->frag_output_index,
true, context); true, context);
check_glerror(program, "shaders_compute");
} }
void shaders_free(const ShaderProgram *program) { void shaders_free(const ShaderProgram *program) {
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
glDeleteProgram(program->programs[i]); glDeleteProgram(program->programs[i]);
} }
check_glerror_ro("shaders_free/glDeleteProgram");
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); glDeleteFramebuffers(program->frag_count, program->frame_buffers);
check_glerror_ro("shaders_free/glDeleteFramebuffers");
glDeleteTextures(program->tex_count, program->textures); glDeleteTextures(program->tex_count, program->textures);
check_glerror_ro("shaders_free/glDeleteTextures");
#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); glDeleteBuffers(1, &program->vertex_buffer);
check_glerror_ro("shaders_free/glDeleteBuffers");
} }
void shaders_free_window(const ShaderProgram *program, bool secondary) { void shaders_free_window(const ShaderProgram *program, bool secondary) {
glDeleteVertexArrays(1, &program->vertex_array[secondary ? 1 : 0]); glDeleteVertexArrays(1, &program->vertex_array[secondary ? 1 : 0]);
} check_glerror_ro("shaders_free_window/glDeleteVertexArrays");
void shaders_free_input(const ShaderProgram *program,
const VideoCapture *input) {
if (!input->error && input->dma_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(program->egl_display, input->dma_image);
}
} }
+14 -6
View File
@@ -4,20 +4,28 @@
#define SHADERS_H #define SHADERS_H
void shaders_init(ShaderProgram *program, const Project *project, void shaders_init(ShaderProgram *program, const Project *project,
const SharedContext *context, VideoCaptureArray *inputs, const Context *context, bool rebind);
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, void shaders_update(ShaderProgram *program, const File *fragment_shader,
unsigned int i, const Project *project); 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); bool monitor, bool output_only);
void shaders_free(const ShaderProgram *program); void shaders_free(const ShaderProgram *program);
void shaders_free_window(const ShaderProgram *program, bool secondary); void shaders_free_window(const ShaderProgram *program, bool secondary);
void shaders_free_input(const ShaderProgram *program,
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 */
+676 -356
View File
File diff suppressed because it is too large Load Diff
+9 -16
View File
@@ -5,26 +5,19 @@
void state_parse_config(StateConfig *state_config, const ConfigFile *config); void state_parse_config(StateConfig *state_config, const ConfigFile *config);
void state_apply_event(SharedContext *context, const StateConfig *state_config, void state_midi_event(Context *context, StateConfig state_config,
const MidiDevice *midi, unsigned char code, MidiDevice midi, unsigned char code,
unsigned char value, bool trace_midi); unsigned char value, bool trace_midi);
bool state_background_write(SharedContext *context, void state_key_event(Context *context, StateConfig state_config,
const StateConfig *state_config, unsigned int code, MidiDevice midi);
const MidiDevice *midi);
void state_init(SharedContext *context, const StateConfig *state_config, void *state_background_write(void *args);
bool demo, bool auto_random, unsigned int base_tempo,
const char *state_file, bool load_state);
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 */
+13 -5
View File
@@ -1,4 +1,3 @@
#include <bsd/string.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -6,6 +5,8 @@
#include "config.h" #include "config.h"
#include "string.h" #include "string.h"
static bool is_digit(char c) { return c >= '0' && c <= '9'; }
unsigned int string_trim(char *str) { unsigned int string_trim(char *str) {
// https://www.delftstack.com/howto/c/trim-string-in-c/ // https://www.delftstack.com/howto/c/trim-string-in-c/
unsigned int start; unsigned int start;
@@ -14,7 +15,7 @@ unsigned int string_trim(char *str) {
start = 0; start = 0;
end = strnlen(str, STR_LEN) - 1; end = strnlen(str, STR_LEN) - 1;
if (end == 0) { if (end <= 0) {
return 0; return 0;
} }
@@ -37,8 +38,6 @@ unsigned int string_trim(char *str) {
return end - start + 1; return end - start + 1;
} }
static bool is_digit(char c) { return c >= '0' && c <= '9'; }
bool string_is_number(const char *value) { bool string_is_number(const char *value) {
unsigned long value_len; unsigned long value_len;
@@ -59,14 +58,23 @@ bool string_is_number(const char *value) {
char *string_replace_at(const char *src, unsigned int from, unsigned int to, char *string_replace_at(const char *src, unsigned int from, unsigned int to,
const char *rpl) { const char *rpl) {
unsigned long src_len, rpl_len; unsigned long src_len;
unsigned long rpl_len;
char *dst; char *dst;
if (to < from) {
return "";
}
src_len = strnlen(src, STR_LEN * STR_LEN); src_len = strnlen(src, STR_LEN * STR_LEN);
rpl_len = strnlen(rpl, STR_LEN * STR_LEN); rpl_len = strnlen(rpl, STR_LEN * STR_LEN);
dst = malloc(src_len - (to - from) + rpl_len + 1); dst = malloc(src_len - (to - from) + rpl_len + 1);
if (dst == NULL) {
return "";
}
strlcpy(dst, src, from + 1); strlcpy(dst, src, from + 1);
strlcpy(dst + from, rpl, rpl_len + 1); strlcpy(dst + from, rpl, rpl_len + 1);
strlcpy(dst + from + rpl_len, src + to, src_len - to + 1); strlcpy(dst + from + rpl_len, src + to, src_len - to + 1);
+30 -18
View File
@@ -1,18 +1,18 @@
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <sys/time.h> #include <time.h>
#include "types.h" #include "types.h"
#include "config.h" #include "config.h"
#include "tempo.h" #include "tempo.h"
static long now() { static long now_ms() {
struct timeval now; struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
gettimeofday(&now, NULL); return 0;
}
return now.tv_sec * 1000 + now.tv_usec / 1000; return 1000 * ts.tv_sec + ts.tv_nsec / 1e6;
} }
static void reset_tap_chain(Tempo *tempo, long t) { static void reset_tap_chain(Tempo *tempo, long t) {
@@ -25,14 +25,6 @@ static void reset_tap_chain(Tempo *tempo, long t) {
memset(tempo->tap_durations, 0, sizeof(tempo->tap_durations)); memset(tempo->tap_durations, 0, sizeof(tempo->tap_durations));
} }
void tempo_init(Tempo *tempo) {
long t;
t = now();
reset_tap_chain(tempo, t);
}
static bool is_chain_active(const Tempo tempo, long t) { static bool is_chain_active(const Tempo tempo, long t) {
return (tempo.last_tap + MAX_BEAT_LENGTH) > t && return (tempo.last_tap + MAX_BEAT_LENGTH) > t &&
(tempo.last_tap + (tempo.beat_length * BEATS_UNTIL_CHAIN_RESET)) > t; (tempo.last_tap + (tempo.beat_length * BEATS_UNTIL_CHAIN_RESET)) > t;
@@ -98,15 +90,35 @@ static void add_tap_to_chain(Tempo *tempo, long t) {
tempo->tempo = 60000.0 / tempo->beat_length; tempo->tempo = 60000.0 / tempo->beat_length;
} }
void tempo_set(Tempo *tempo, float value) { void tempo_init(Tempo *tempo, float value) {
long t;
t = now_ms();
reset_tap_chain(tempo, t);
tempo->tempo = value; tempo->tempo = value;
tempo->beat_length = 60000.0 / value; tempo->beat_length = 60000.0 / value;
} }
void tempo_set(Tempo *tempo, float value) {
long t;
long progress;
t = now_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) { void tempo_tap(Tempo *tempo) {
long t; long t;
t = now(); t = now_ms();
if (!is_chain_active(*tempo, t)) { if (!is_chain_active(*tempo, t)) {
reset_tap_chain(tempo, t); reset_tap_chain(tempo, t);
@@ -118,7 +130,7 @@ void tempo_tap(Tempo *tempo) {
double tempo_total(const Tempo *tempo) { double tempo_total(const Tempo *tempo) {
long t; long t;
t = now(); t = now_ms();
return (double)(t - tempo->last_reset) / (double)tempo->beat_length; return (double)(t - tempo->last_reset) / (double)tempo->beat_length;
} }
+1 -1
View File
@@ -3,7 +3,7 @@
#ifndef TEMPO_H #ifndef TEMPO_H
#define TEMPO_H #define TEMPO_H
void tempo_init(Tempo *tempo); void tempo_init(Tempo *tempo, float value);
void tempo_tap(Tempo *tempo); void tempo_tap(Tempo *tempo);
+13 -9
View File
@@ -1,4 +1,6 @@
#include <sys/time.h> #include <bits/time.h>
#include <limits.h>
#include <time.h>
#include "types.h" #include "types.h"
@@ -7,23 +9,25 @@
void timer_init(Timer *timer, const unsigned int target) { void timer_init(Timer *timer, const unsigned int target) {
timer->counter = 0; timer->counter = 0;
timer->target = target; timer->target = target;
clock_gettime(CLOCK_REALTIME, &timer->start);
gettimeofday(&timer->start, NULL);
} }
bool timer_inc(Timer *timer) { bool timer_inc(Timer *timer) {
timer->counter += 1; timer->counter += 1;
return timer->counter >= timer->target; return timer->counter == UINT_MAX || timer->counter >= timer->target;
} }
double timer_reset(Timer *timer) { double timer_reset(Timer *timer) {
struct timeval stop; struct timespec stop;
double secs, per_secs; double secs;
double per_secs;
gettimeofday(&stop, NULL); if (clock_gettime(CLOCK_REALTIME, &stop) != 0) {
return 0.0;
}
secs = (double)(stop.tv_usec - timer->start.tv_usec) / 1000000 + secs = (double)(stop.tv_sec - timer->start.tv_sec) +
(double)(stop.tv_sec - timer->start.tv_sec); (double)(stop.tv_nsec - timer->start.tv_nsec) / 1e9;
per_secs = (double)timer->counter / secs; per_secs = (double)timer->counter / secs;
timer->start = stop; timer->start = stop;
+124 -66
View File
@@ -1,12 +1,13 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#ifdef VIDEO_IN
#include <glad/egl.h> #include <glad/egl.h>
#include <linux/videodev2.h>
#endif /* VIDEO_IN */
#include <glad/gl.h> #include <glad/gl.h>
#include <hashmap.h> #include <hashmap.h>
#include <linmath.h> #include <linmath.h>
#include <linux/videodev2.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/time.h>
#include <time.h> #include <time.h>
#include "config.h" #include "config.h"
@@ -43,12 +44,18 @@ typedef struct Parameters {
float base_tempo; float base_tempo;
bool demo; bool demo;
bool auto_random; bool auto_random;
unsigned int auto_random_cycle;
#ifdef VIDEO_IN
StringArray video_in; StringArray video_in;
unsigned int video_buffers;
unsigned int video_size; unsigned int video_size;
bool video_reconnect;
char video_fourcc[5];
#endif /* VIDEO_IN */
unsigned int internal_size; unsigned int internal_size;
char state_file[STR_LEN];
bool load_state; bool load_state;
bool save_state; bool save_state;
bool midi_reconnect;
bool trace_midi; bool trace_midi;
bool trace_fps; bool trace_fps;
} Parameters; } Parameters;
@@ -82,6 +89,7 @@ typedef struct ShaderProgram {
GLuint vertex_array[2]; GLuint vertex_array[2];
unsigned int tex_count; unsigned int tex_count;
unsigned int tex_map[ARRAY_SIZE];
GLuint textures[ARRAY_SIZE]; GLuint textures[ARRAY_SIZE];
unsigned int frag_count; unsigned int frag_count;
@@ -93,58 +101,46 @@ typedef struct ShaderProgram {
GLuint frame_buffers[ARRAY_SIZE]; GLuint frame_buffers[ARRAY_SIZE];
GLuint fragment_shaders[ARRAY_SIZE]; GLuint fragment_shaders[ARRAY_SIZE];
GLuint itime_locations[ARRAY_SIZE]; GLint itime_locations[ARRAY_SIZE];
GLuint itempo_locations[ARRAY_SIZE]; GLint itempo_locations[ARRAY_SIZE];
GLuint ibeats_locations[ARRAY_SIZE]; GLint ibeats_locations[ARRAY_SIZE];
GLuint ifps_locations[ARRAY_SIZE]; GLint ifps_locations[ARRAY_SIZE];
GLuint ires_locations[ARRAY_SIZE]; GLint ires_locations[ARRAY_SIZE];
GLuint itexres_locations[ARRAY_SIZE]; GLint itexres_locations[ARRAY_SIZE];
GLuint iinres_locations[ARRAY_SIZE]; GLint iinres_locations[ARRAY_SIZE];
GLuint iinfmt_locations[ARRAY_SIZE]; GLint iinfmt_locations[ARRAY_SIZE];
GLuint iinfps_locations[ARRAY_SIZE]; GLint iinfps_locations[ARRAY_SIZE];
GLuint idemo_locations[ARRAY_SIZE]; GLint idemo_locations[ARRAY_SIZE];
GLuint iautorand_locations[ARRAY_SIZE]; GLint iautorand_locations[ARRAY_SIZE];
GLuint iseed_locations[ARRAY_SIZE]; GLint iautorandcycle_locations[ARRAY_SIZE];
GLuint istate_locations[ARRAY_SIZE]; GLint iseed_locations[ARRAY_SIZE];
GLuint ipage_locations[ARRAY_SIZE]; GLint istate_locations[ARRAY_SIZE];
GLuint iselected_locations[ARRAY_SIZE]; GLint ipage_locations[ARRAY_SIZE];
GLuint iactive_locations[ARRAY_SIZE]; GLint iselected_locations[ARRAY_SIZE];
GLint iactive_locations[ARRAY_SIZE];
UintArray midi_lengths; 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_type_count;
unsigned int sub_variant_count; unsigned int sub_variant_count;
GLuint sub_locations[ARRAY_SIZE]; GLint sub_locations[ARRAY_SIZE];
unsigned int active_count; unsigned int active_count;
unsigned int in_count; unsigned int in_count;
#ifdef VIDEO_IN
unsigned int sub_video_count;
unsigned int input_tex_map[MAX_VIDEO];
EGLDisplay egl_display; EGLDisplay egl_display;
EGLImageKHR dma_images[MAX_VIDEO];
#endif /* VIDEO_IN */
} ShaderProgram; } 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 // window.c
typedef GLFWwindow Window; typedef GLFWwindow Window;
@@ -164,15 +160,17 @@ typedef struct Tempo {
// context.c // context.c
typedef struct SharedContext { typedef struct Context {
int fd; int fd;
vec2 resolution; vec2 resolution;
vec2 tex_resolution; vec2 tex_resolution;
#ifdef VIDEO_IN
vec2 input_resolutions[MAX_VIDEO]; 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; double time;
unsigned int fps;
Tempo tempo; Tempo tempo;
double tempo_total; double tempo_total;
UintArray state; UintArray state;
@@ -182,13 +180,60 @@ typedef struct SharedContext {
vec3 values[ARRAY_SIZE]; vec3 values[ARRAY_SIZE];
bool demo; bool demo;
bool auto_random; bool auto_random;
unsigned int auto_random_cycle;
unsigned int seeds[MAX_FRAG]; unsigned int seeds[MAX_FRAG];
bool monitor; unsigned int fps;
_Atomic bool stop;
} Context;
unsigned int input_formats[MAX_VIDEO]; // video.c
unsigned int input_fps[MAX_VIDEO];
bool stop; #ifdef VIDEO_IN
} SharedContext;
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 // state.c
@@ -198,24 +243,45 @@ typedef struct StateConfig {
UintArray select_page_codes; UintArray select_page_codes;
UintArray select_item_codes; UintArray select_item_codes;
UintArray select_frag_codes; UintArray select_frag_codes;
UintArray midi_active_counts; UintArray group_active_counts;
UintArray midi_active_offsets; UintArray group_active_offsets;
UintArray midi_active_codes; UintArray group_active_codes;
UintArray midi_counts; UintArray group_counts;
UintArray midi_offsets; UintArray group_offsets;
UintArray midi_codes; UintArray codes;
UintArray fader_codes; UintArray fader_codes;
UintArray values_offsets; UintArray values_offsets;
UintArray random_ignored;
unsigned int value_count; unsigned int value_count;
unsigned int tap_tempo_code; unsigned int tap_tempo_code;
char save_file_prefix[STR_LEN];
unsigned int 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; } StateConfig;
typedef struct StateBackgroundWriteArgs {
Context *context;
StateConfig state_config;
MidiDevice *midi;
} StateBackgroundWriteArgs;
// timer.c // timer.c
typedef struct Timer { typedef struct Timer {
struct timeval start; struct timespec start;
unsigned int counter; unsigned int counter;
unsigned int target; unsigned int target;
} Timer; } Timer;
@@ -224,6 +290,7 @@ typedef struct Timer {
typedef struct ConfigFile { typedef struct ConfigFile {
struct hashmap *map; struct hashmap *map;
bool error;
} ConfigFile; } ConfigFile;
typedef struct ConfigFileItem { typedef struct ConfigFileItem {
@@ -231,15 +298,6 @@ typedef struct ConfigFileItem {
char value[STR_LEN]; char value[STR_LEN];
} ConfigFileItem; } ConfigFileItem;
// midi.c
typedef struct MidiDevice {
bool error;
char name[STR_LEN];
snd_rawmidi_t *input;
snd_rawmidi_t *output;
} MidiDevice;
// project.c // project.c
typedef struct Project { typedef struct Project {
+169 -92
View File
@@ -1,10 +1,11 @@
#include <bsd/string.h> #ifdef VIDEO_IN
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <log.h> #include <log.h>
#include <pthread.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <unistd.h> #include <unistd.h>
@@ -15,6 +16,8 @@
#include "timer.h" #include "timer.h"
#include "video.h" #include "video.h"
static const enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
static void ioctl_error(VideoCapture *video_capture, const char *operation, static void ioctl_error(VideoCapture *video_capture, const char *operation,
const char *default_msg) { const char *default_msg) {
if (errno == EINVAL) { if (errno == EINVAL) {
@@ -66,15 +69,31 @@ static void ioctl_error(VideoCapture *video_capture, const char *operation,
video_capture->error = true; video_capture->error = true;
} }
static void open_device(VideoCapture *video_capture, const char *name) { static void fourcc_to_string(unsigned int fourcc, char *str) {
str[0] = (char)(fourcc & 0xFF);
str[1] = (char)((fourcc >> 8) & 0xFF);
str[2] = (char)((fourcc >> 16) & 0xFF);
str[3] = (char)((fourcc >> 24) & 0xFF);
str[4] = '\0';
}
static int string_to_fourcc(const char *str) {
return (unsigned int)str[0] | ((unsigned int)str[1] << 8) |
((unsigned int)str[2] << 16) | ((unsigned int)str[3] << 24);
}
static void open_device(VideoCapture *video_capture, const char *name,
bool log_error) {
strlcpy(video_capture->name, name, STR_LEN); strlcpy(video_capture->name, name, STR_LEN);
video_capture->error = false; video_capture->error = false;
video_capture->fd = -1; video_capture->fd = -1;
video_capture->exp_fd = -1; video_capture->buf_count = 0;
video_capture->fd = open(name, O_RDWR); video_capture->fd = open(name, O_RDWR | O_NONBLOCK);
if (video_capture->fd == -1) { if (video_capture->fd == -1) {
if (log_error) {
log_warn("(%s) Cannot open device", name); log_warn("(%s) Cannot open device", name);
}
video_capture->error = true; video_capture->error = true;
} }
} }
@@ -105,7 +124,8 @@ static bool check_caps(VideoCapture *video_capture) {
} }
static bool get_available_sizes(VideoCapture *video_capture, static bool get_available_sizes(VideoCapture *video_capture,
unsigned int preferred_height) { unsigned int preferred_height,
unsigned int pixel_format) {
struct v4l2_frmsizeenum fmt_enum; struct v4l2_frmsizeenum fmt_enum;
unsigned int index; unsigned int index;
bool found = false; bool found = false;
@@ -114,7 +134,7 @@ static bool get_available_sizes(VideoCapture *video_capture,
index = 0; index = 0;
fmt_enum.index = index; fmt_enum.index = index;
fmt_enum.pixel_format = V4L2_PIX_FMT_YUYV; fmt_enum.pixel_format = pixel_format;
found = false; found = false;
video_capture->width = 0; video_capture->width = 0;
@@ -146,7 +166,7 @@ static bool get_available_sizes(VideoCapture *video_capture,
memset(&fmt_enum, 0, sizeof(fmt_enum)); memset(&fmt_enum, 0, sizeof(fmt_enum));
fmt_enum.index = ++index; fmt_enum.index = ++index;
fmt_enum.pixel_format = V4L2_PIX_FMT_YUYV; fmt_enum.pixel_format = pixel_format;
} }
if (video_capture->height == 0) { if (video_capture->height == 0) {
@@ -158,54 +178,47 @@ static bool get_available_sizes(VideoCapture *video_capture,
return true; return true;
} }
static bool set_format(VideoCapture *video_capture) { static bool set_format(VideoCapture *video_capture, unsigned int pixel_format) {
struct v4l2_format fmt; struct v4l2_format fmt;
char fourcc[STR_LEN];
video_capture->output = false;
memset(&fmt, 0, sizeof(fmt)); memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.type = buf_type;
fmt.fmt.pix.width = video_capture->width; fmt.fmt.pix.width = video_capture->width;
fmt.fmt.pix.height = video_capture->height; fmt.fmt.pix.height = video_capture->height;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.pixelformat = pixel_format;
fmt.fmt.pix.field = V4L2_FIELD_ANY; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) {
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
video_capture->output = true;
if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) { if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) {
ioctl_error(video_capture, "VIDIOC_S_FMT", ioctl_error(video_capture, "VIDIOC_S_FMT",
"Requested buffer type not supported"); "Requested buffer type not supported");
return false; return false;
} }
}
video_capture->width = fmt.fmt.pix.width; video_capture->width = fmt.fmt.pix.width;
video_capture->height = fmt.fmt.pix.height; video_capture->height = fmt.fmt.pix.height;
video_capture->pixelformat = fmt.fmt.pix.pixelformat; video_capture->pixelformat = fmt.fmt.pix.pixelformat;
video_capture->bytesperline = fmt.fmt.pix.bytesperline; video_capture->bytesperline = fmt.fmt.pix.bytesperline;
log_info("(%s) Format fourcc: %c%c%c%c", video_capture->name, fourcc_to_string(fmt.fmt.pix.pixelformat, fourcc);
fmt.fmt.pix.pixelformat, fmt.fmt.pix.pixelformat >> 8,
fmt.fmt.pix.pixelformat >> 16, fmt.fmt.pix.pixelformat >> 24); log_info("(%s) Format fourcc: %s", video_capture->name, fourcc);
log_info("(%s) Resolution: %dx%d", video_capture->name, fmt.fmt.pix.width, log_info("(%s) Resolution: %dx%d", video_capture->name, fmt.fmt.pix.width,
fmt.fmt.pix.height); fmt.fmt.pix.height);
return true; return true;
} }
static bool request_buffers(VideoCapture *video_capture) { static bool request_buffers(VideoCapture *video_capture,
unsigned int buffer_count) {
struct v4l2_requestbuffers reqbuf; struct v4l2_requestbuffers reqbuf;
memset(&reqbuf, 0, sizeof(reqbuf)); memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT reqbuf.type = buf_type;
: V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP; reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = 1; reqbuf.count = buffer_count;
if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) { if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
ioctl_error(video_capture, "VIDIOC_REQBUFS", ioctl_error(video_capture, "VIDIOC_REQBUFS",
@@ -215,19 +228,24 @@ static bool request_buffers(VideoCapture *video_capture) {
log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count); log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count);
video_capture->buf_count = reqbuf.count;
for (unsigned int i = 0; i < reqbuf.count; i++) {
video_capture->exp_fd[i] = -1;
}
return true; return true;
} }
static bool export_buffer(VideoCapture *video_capture) { static bool export_buffer(VideoCapture *video_capture, int *fd,
unsigned int index) {
struct v4l2_exportbuffer expbuf; struct v4l2_exportbuffer expbuf;
video_capture->exp_fd = -1; *fd = -1;
memset(&expbuf, 0, sizeof(expbuf)); memset(&expbuf, 0, sizeof(expbuf));
expbuf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT expbuf.type = buf_type;
: V4L2_BUF_TYPE_VIDEO_CAPTURE; expbuf.index = index;
expbuf.index = 0;
expbuf.flags = O_RDONLY; expbuf.flags = O_RDONLY;
if (ioctl(video_capture->fd, VIDIOC_EXPBUF, &expbuf) == -1) { if (ioctl(video_capture->fd, VIDIOC_EXPBUF, &expbuf) == -1) {
@@ -237,12 +255,22 @@ static bool export_buffer(VideoCapture *video_capture) {
return false; return false;
} }
video_capture->exp_fd = expbuf.fd; *fd = expbuf.fd;
return true; return true;
} }
static const enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; static bool export_buffers(VideoCapture *video_capture) {
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) { static bool open_stream(VideoCapture *video_capture) {
if (ioctl(video_capture->fd, VIDIOC_STREAMON, &buf_type) == -1) { if (ioctl(video_capture->fd, VIDIOC_STREAMON, &buf_type) == -1) {
@@ -255,95 +283,131 @@ static bool open_stream(VideoCapture *video_capture) {
return true; return true;
} }
static void create_image_buffer(VideoCapture *video_capture) { static bool create_image_buffer(VideoCapture *video_capture,
memset(&video_capture->buf, 0, sizeof(video_capture->buf)); struct v4l2_buffer *buf, unsigned int index) {
memset(buf, 0, sizeof(*buf));
video_capture->buf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT buf->type = buf_type;
: V4L2_BUF_TYPE_VIDEO_CAPTURE; buf->memory = V4L2_MEMORY_MMAP;
video_capture->buf.memory = V4L2_MEMORY_MMAP; buf->index = index;
video_capture->buf.index = 0;
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf); if (ioctl(video_capture->fd, VIDIOC_QBUF, buf) == -1) {
ioctl_error(video_capture, "VIDIOC_QBUF", "Could not enqueue buffer");
return false;
}
return true;
}
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) { static void close_stream(const VideoCapture *video_capture) {
ioctl(video_capture->fd, VIDIOC_STREAMOFF, &buf_type); ioctl(video_capture->fd, VIDIOC_STREAMOFF, &buf_type);
} }
static unsigned int read_video(VideoCapture *video_capture) {
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, void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height) { unsigned int preferred_height, unsigned int buffer_count,
open_device(video_capture, name); const char *video_fourcc, bool log_error) {
open_device(video_capture, name, log_error);
if (video_capture->error) { if (video_capture->error) {
return; return;
} }
if (!check_caps(video_capture)) { if (!check_caps(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!get_available_sizes(video_capture, preferred_height)) { if (!get_available_sizes(video_capture, preferred_height,
string_to_fourcc(video_fourcc))) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!set_format(video_capture)) { if (!set_format(video_capture, string_to_fourcc(video_fourcc))) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!request_buffers(video_capture)) { if (!request_buffers(video_capture, buffer_count)) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!export_buffer(video_capture)) { if (!export_buffers(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!open_stream(video_capture)) { if (!open_stream(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
create_image_buffer(video_capture); if (!create_image_buffers(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
} }
static bool read_video(VideoCapture *video_capture) { void *video_background_read(void *args) {
if (ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf) == -1) { VideoBackgroundReadArgs *process_args = (VideoBackgroundReadArgs *)args;
ioctl_error(video_capture, "VIDIOC_DQBUF", VideoCapture *video_capture = process_args->capture;
"buffer type not supported or no buffer allocated or the index " Context *context = process_args->context;
"is out of bounds"); int input_index = process_args->input_index;
return false; bool trace_fps = process_args->trace_fps;
}
if (ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf) == -1) {
ioctl_error(video_capture, "VIDIOC_QBUF",
"buffer type not supported or no buffer allocated or the index "
"is out of bounds");
return false;
}
return true;
}
bool video_background_read(VideoCapture *video_capture, SharedContext *context,
int input_index, bool trace_fps) {
pid_t pid;
Timer timer; Timer timer;
double fps; double fps;
bool result;
pid = fork(); log_info("(%s) background acquisition started", video_capture->name);
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);
timer_init(&timer, 30); timer_init(&timer, 30);
while (!context->stop && read_video(video_capture)) { while (!context->stop && !video_capture->error) {
// repeat infinitely result = read_video(video_capture);
if (timer_inc(&timer)) {
if (result && timer_inc(&timer)) {
fps = timer_reset(&timer); fps = timer_reset(&timer);
context->input_fps[input_index] = (unsigned int)round(fps); context->input_fps[input_index] = (unsigned int)round(fps);
@@ -351,26 +415,39 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
log_trace("(%s) %.2ffps", video_capture->name, fps); log_trace("(%s) %.2ffps", video_capture->name, fps);
} }
} }
if (result) {
context->input_index[input_index] = video_capture->buf_index;
}
} }
if (context->stop) { if (context->stop) {
log_info("(%s) background acquisition stopped by main thread (pid: %d)", log_info("(%s) background acquisition stopped by main thread",
video_capture->name, pid); video_capture->name);
} else { } else {
log_info("(%s) background acquisition stopped after error (pid: %d)", log_info("(%s) background acquisition stopped after error",
video_capture->name, pid); video_capture->name);
video_capture->disconnected = true;
context->input_formats[input_index] = 0;
context->input_resolutions[input_index][0] = 0;
context->input_resolutions[input_index][1] = 0;
} }
exit(context->stop ? EXIT_SUCCESS : EXIT_FAILURE); free(process_args);
return false; pthread_exit(NULL);
} }
void video_free(const VideoCapture *video_capture) { void video_free(const VideoCapture *video_capture) {
if (!video_capture->error) { unsigned int i;
close_stream(video_capture);
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->exp_fd != -1) {
close(video_capture->exp_fd);
} }
if (video_capture->fd != -1) { if (video_capture->fd != -1) {
close_stream(video_capture);
close(video_capture->fd); close(video_capture->fd);
} }
} }
#endif /* VIDEO_IN */
+8 -4
View File
@@ -3,12 +3,16 @@
#ifndef VIDEO_H #ifndef VIDEO_H
#define VIDEO_H #define VIDEO_H
void video_init(VideoCapture *video_capture, const char *name, #ifdef VIDEO_IN
unsigned int preferred_height);
bool video_background_read(VideoCapture *video_capture, SharedContext *context, void video_init(VideoCapture *video_capture, const char *name,
int input_index, bool trace_fps); unsigned int preferred_height, unsigned int buffer_count,
const char *video_fourcc, bool log_error);
void *video_background_read(void *args);
void video_free(const VideoCapture *video_capture); void video_free(const VideoCapture *video_capture);
#endif /* VIDEO_IN */
#endif /* VIDEO_H */ #endif /* VIDEO_H */
+28 -6
View File
@@ -59,6 +59,9 @@ create_window(GLFWmonitor *monitor, const char *title, Window *shared_context,
// Context related hints // Context related hints
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); 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); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// create fullscreen window in selected monitor // create fullscreen window in selected monitor
@@ -120,16 +123,18 @@ void window_events() { glfwPollEvents(); }
double window_get_time() { return glfwGetTime(); } double window_get_time() { return glfwGetTime(); }
void window_use(Window *window, SharedContext *context) { void window_use(Window *window, Context *context) {
int width, height; int width;
int height;
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
glfwGetFramebufferSize(window, &width, &height); glfwGetFramebufferSize(window, &width, &height);
context->resolution[0] = width; context->resolution[0] = width;
context->resolution[1] = height; context->resolution[1] = height;
if (height > 0) {
context->tex_resolution[0] = context->tex_resolution[0] =
(int)(context->tex_resolution[1] * context->resolution[0] / (int)(context->tex_resolution[1] * width / height);
context->resolution[1]); }
} }
void window_close(Window *window) { 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; return key == GLFW_KEY_ESCAPE && action == GLFW_PRESS;
} }
bool window_char_key(int key, int action, const int char_code) { unsigned int window_read_key(int key, int action, int mods) {
return key == char_code && action == GLFW_PRESS; unsigned int result;
if (action == GLFW_RELEASE || key == GLFW_KEY_LEFT_SHIFT ||
key == GLFW_KEY_RIGHT_SHIFT || key == GLFW_KEY_LEFT_CONTROL ||
key == GLFW_KEY_RIGHT_CONTROL || key == GLFW_KEY_LEFT_ALT ||
key == GLFW_KEY_RIGHT_ALT) {
return 0;
}
result = 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;
} }
+2 -2
View File
@@ -15,7 +15,7 @@ void window_update_title(Window *window, const char *title);
double window_get_time(); double window_get_time();
void window_use(Window *window, SharedContext *context); void window_use(Window *window, Context *context);
void window_refresh(Window *window); 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_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 */