44 Commits

Author SHA1 Message Date
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
klemek fcd829e79f forge (steel) v1.0.1 2025-11-12 23:41:47 +01:00
klemek a3d9baf18c fix: iDemo redundant with autorandom 2025-11-12 23:41:09 +01:00
klemek 3903149549 build: fix clean-release 2025-11-12 23:40:41 +01:00
klemek 4d984d1e28 docs: update README and DEVELOPMENT 2025-11-12 23:31:55 +01:00
74 changed files with 1974 additions and 1039 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
+12 -1
View File
@@ -16,7 +16,18 @@ jobs:
- name: install libs - name: install libs
run: sudo apt install -y libglfw3-dev libgl-dev libv4l-dev libasound2-dev libbsd-dev run: sudo apt install -y libglfw3-dev libgl-dev libv4l-dev libasound2-dev libbsd-dev
- name: gcc - name: gcc
run: mkdir -p build && gcc -v -Wall -Wextra -Werror -Wno-format-truncation src/*.c src/*.h -lglfw -lGL -lm -lasound -lbsd -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE run: mkdir -p build && gcc -v -Wall -Wextra -Werror -Wno-format-truncation src/*.c src/*.h -lglfw -lGL -lm -lasound -lbsd -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE -DVIDEO_IN
build-no-video:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: 'true'
- name: install libs
run: sudo apt install -y libglfw3-dev libgl-dev libasound2-dev libbsd-dev
- name: gcc
run: mkdir -p build && gcc -v -Werror src/*.c src/*.h -lglfw -lGL -lm -lasound -lbsd -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE
build-release: build-release:
needs: lint needs: lint
+1 -1
View File
@@ -24,6 +24,6 @@ pkg
forge-* forge-*
confdeps.* confdeps.*
conftest.* conftest.*
forge_saved_state.txt *.txt
error.glsl error.glsl
draft/ draft/
+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 -3
View File
@@ -117,9 +117,24 @@ make -f Makefile.dev release-arch
- [x] Printable PDF of default scr/fx - [x] Printable PDF of default scr/fx
- [x] Add NanoKontrol setup file - [x] Add NanoKontrol setup file
- [x] Find and fix opengl errors 0500 ? - [x] Find and fix opengl errors 0500 ?
- [ ] Bonus - [ ] Extra features
- [x] `--auto-random-cycle=4`
- [x] Arrows (up-down: bpm / left-right: cycle)
- [x] Save states (numkey: load / shift + numkey: save)
- [x] (clean) static functions at top of files
- [x] Configurable key codes
- [x] Monitor improvements
- [ ] Ignore some values in auto random
- [x] build without video in
- [ ] Auto discover video devices
- [ ] Update README monitor/keymap
- [ ] Auto reconnect midi input
- [ ] Auto reconnect video device
- [ ] 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
- [ ] Fixes
- [ ] Try to write NanoKontrol config - [ ] Try to write NanoKontrol config
- [ ] Investigate video device fps loss (bad unregister ?) - [x] Investigate video device fps loss (bad unregister ?)
- explore libv4l directly [github](https://github.com/philips/libv4l) (with `-lv4l2`)
+3 -3
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/shared.c src/state.c src/string.c src/tempo.c src/timer.c src/video.c src/window.c $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/hashmap.c/hashmap.c $(top_srcdir)/log.c/src/log.c
forge_CFLAGS = -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays -fno-exceptions -fopenmp -I$(top_srcdir)/include -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE -DLOG_USE_COLOR -DDATADIR=\"$(datadir)/$(PACKAGE)\" forge_CFLAGS = -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays -fno-exceptions -fopenmp -I$(top_srcdir)/include -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE -DLOG_USE_COLOR -DVIDEO_IN -DDATADIR=\"$(datadir)/$(PACKAGE)\"
forge_LDADD = -lm -lGL -lglfw -lasound -lbsd forge_LDADD = -lm -lGL -lglfw -lasound -lbsd
include_HEADERS = src/args.h src/arr.h src/config.h src/config_file.h src/constants.h src/file.h src/forge.h src/main.h src/midi.h src/project.h src/rand.h src/shaders.h src/shared.h src/state.h src/string.h src/tempo.h src/timer.h src/types.h src/video.h src/window.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/include/linmath.h $(top_srcdir)/include/hashmap.h $(top_srcdir)/include/log.h include_HEADERS = src/args.h src/arr.h src/config.h src/config_file.h src/constants.h src/file.h src/forge.h src/main.h src/midi.h src/project.h src/rand.h src/shaders.h src/shared.h src/state.h src/string.h src/tempo.h src/timer.h src/types.h src/video.h src/window.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/include/linmath.h $(top_srcdir)/include/hashmap.h $(top_srcdir)/include/log.h
EXTRA_DIST = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuv.glsl EXTRA_DIST = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuyv.glsl
confdir = $(prefix)/share/$(PACKAGE) confdir = $(prefix)/share/$(PACKAGE)
conf_DATA = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuv.glsl conf_DATA = default/forge_project.cfg default/frag1.glsl default/frag10.glsl default/frag2.glsl default/frag3.glsl default/frag4.glsl default/frag5.glsl default/frag6.glsl default/frag7.glsl default/frag8.glsl default/frag9.glsl default/inc_cp437.glsl default/inc_debug.glsl default/inc_functions.glsl default/inc_fx.glsl default/inc_magic.glsl default/inc_rand.glsl default/inc_res.glsl default/inc_sentences.glsl default/inc_src.glsl default/inc_template.glsl default/inc_time.glsl default/inc_yuyv.glsl
+6 -1
View File
@@ -21,9 +21,14 @@ build:
-DGLFW_EXPOSE_NATIVE_EGL \ -DGLFW_EXPOSE_NATIVE_EGL \
-DGLFW_NATIVE_INCLUDE_NONE \ -DGLFW_NATIVE_INCLUDE_NONE \
-DLOG_USE_COLOR \ -DLOG_USE_COLOR \
-DVIDEO_IN \
-o build/$(TARGET) \ -o build/$(TARGET) \
-g -Og -g -Og
.PHONY: format
format:
clang-format -i src/*
.PHONY: run .PHONY: run
run: build run: build
./build/$(TARGET) $(TEST_ARGS) --monitor-only --internal-size=480 --video-size=240 --hot-reload ./build/$(TARGET) $(TEST_ARGS) --monitor-only --internal-size=480 --video-size=240 --hot-reload
@@ -54,6 +59,7 @@ clean-release:
configure~ \ configure~ \
depcomp \ depcomp \
**/.deps \ **/.deps \
**/**/.deps \
$(TARGET) \ $(TARGET) \
$(TARGET)-*.tar.gz \ $(TARGET)-*.tar.gz \
$(TARGET)-*.pkg.tar.zst \ $(TARGET)-*.pkg.tar.zst \
@@ -99,4 +105,3 @@ release-arch: clean
mkdir -p build mkdir -p build
cp PKGBUILD build cp PKGBUILD build
cd build && makepkg cd build && makepkg
+2 -2
View File
@@ -1,12 +1,12 @@
pkgname=forge-steel pkgname=forge-steel
pkgver=1.0.0 pkgver=1.0.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://github.com/klemek/forge-steel"
source=("${pkgname}-steel-${pkgver}.tar.gz::https://github.com/klemek/forge-steel/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz") source=("${pkgname}-steel-${pkgver}.tar.gz::https://github.com/klemek/forge-steel/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
sha256sums=('da61207bc8af1b71544f5e35e99e7ea8dbbb72b77c0c7dc21f05ba694c28cdfa') sha256sums=('b2345c1a87f6b5b13dcce6a237a3f9a9ddb7fa9c3e982f5e164e7d7fef5725f3')
srcdir=build srcdir=build
backup=("usr/share/${pkgname}") backup=("usr/share/${pkgname}")
+58 -34
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) [![GitHub Release](https://img.shields.io/github/v/release/klemek/forge-steel?style=flat-square)](https://github.com/klemek/forge-steel/releases) [![GitHub Release Date](https://img.shields.io/github/release-date/klemek/forge-steel?style=flat-square)](https://github.com/klemek/forge-steel/releases) [![GitHub last commit](https://img.shields.io/github/last-commit/klemek/forge?style=flat-square)](https://github.com/klemek/forge-steel/commits/master/) [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/klemek/forge-steel/ci.yml?style=flat-square)](https://github.com/klemek/forge-steel/actions/workflows/ci.yml) [![Sonar Quality Gate](https://img.shields.io/sonar/quality_gate/klemek_forge-steel?server=https%3A%2F%2Fsonarcloud.io&style=flat-square)](https://sonarcloud.io/summary/new_code?id=klemek_forge-steel) ![LOC](https://img.shields.io/badge/LOC-3.8k-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,13 +82,14 @@ 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 ?
![FORGE concept schema](./docs/forge.drawio.png) ![FORGE concept schema](./docs/forge.drawio.png)
FORGE is an engine rendering a project into visuals. FORGE is an graphical engine rendering a project into visuals.
Using OpenGL GLSL language, it talks to your graphic card to generate layers of textures defined by the fragment shaders and outputs it to your screen. Using OpenGL GLSL language, it talks to your graphic card to generate layers of textures defined by the fragment shaders and outputs it to your screen.
@@ -158,43 +158,55 @@ make install
When running, the following hotkeys are available: When running, the following hotkeys are available:
* <kbd>Esc</kbd>: Exit window | Hotkey | Function |
* <kbd>R</kbd>: Randomize internal values | ------ | -------- |
* <kbd>0</kbd>: Reset internal values to 0 | <kbd>Esc</kbd> | Exit FORGE |
* <kbd>D</kbd>: Demo mode On/Off | <kbd>R</kbd> | Randomize internal values |
* <kbd>A</kbd>: Auto Random mode On/Off | <kbd>Shift</kbd> + <kbd>R</kbd> | Reset internal values to 0 |
| <kbd>D</kbd> | Demo mode On/Off |
| <kbd>A</kbd> | Auto Random mode On/Off |
| <kbd>&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] [-vr / -nvr] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-tm] [-tf]
Fusion Of Real-time Generative Effects. Fusion Of Real-time Generative Effects.
options: options:
-h, --help show this help message and exit -h, --help show this help message and exit
-v, --version print version -v, --version print version
-p, --project forge project directory (default: /usr/share/forge/default) -p, --project forge project directory (default: ./default)
-c, --config config file name (default: forge_project.cfg) -c, --config config file name (default: forge_project.cfg)
-hr, --hot-reload hot reload of shaders scripts -hr, --hot-reload hot reload of shaders scripts
-s, --screen output screen number (default: primary) -s, --screen output screen number (default: primary)
-m, --monitor monitor screen number (default: none) -m, --monitor monitor screen number (default: none)
-mo, --monitor-only no output screen -mo, --monitor-only no output screen
-w, --windowed not fullscreen -w, --windowed not fullscreen
-t, --tempo base tempo (default: 60) -t, --tempo base tempo (default: 60)
-d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random) -d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random)
-ar, --auto-random randomize state every 4 beats -ar, --auto-random randomize state every cycle (4 beats)
-nar, --no-auto-random do not randomize state (default) -nar, --no-auto-random do not randomize state (default)
-v, --video-in path to video capture device (multiple allowed) -arc, --auto-random-cycle auto random cycle length (default: 4)
-vs, --video-size video capture desired height (default: internal texture height) -vi, --video-in path to video capture device (multiple allowed)
-is, --internal-size internal texture height (default: 720) -vs, --video-size video capture desired height (default: internal texture height)
-sf, --state-file saved state file (default: forge_saved_state.txt) -vr, --video-reconnect auto-reconnect video (default)
-ls, --load-state load saved state (default) -nvr, --no-video-reconnect do not auto-reconnect video
-nls, --no-load-state do not load saved state -is, --internal-size internal texture height (default: 720)
-ss, --save-state save state (default) -ls, --load-state load saved state (default)
-nss, --no-save-state do not save state -nls, --no-load-state do not load saved state
-tm, --trace-midi print midi code and values -ss, --save-state save state (default)
-tf, --trace-fps print fps status of subsystems -nss, --no-save-state do not save state
-tm, --trace-midi print midi code and values
-tf, --trace-fps print fps status of subsystems
``` ```
## Default Project ## Default Project
@@ -233,7 +245,7 @@ Working with pages and items, you can use the following predefined sources and e
| **1** | **0** | Feedback + Thru | _Hue_ | _Saturation_ | _Light_ | Thru | _Hue_ | _Saturation_ | _Light_ | | **1** | **0** | Feedback + Thru | _Hue_ | _Saturation_ | _Light_ | Thru | _Hue_ | _Saturation_ | _Light_ |
| | **1** | Lines | _Thick. / Dezoom_ | _Rotation_ | _Distortion_ | Feedback + Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ | | | **1** | Lines | _Thick. / Dezoom_ | _Rotation_ | _Distortion_ | Feedback + Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
| | **2** | Dots | _Zoom_ | _Rotation_ | _Lens_ | Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ | | | **2** | Dots | _Zoom_ | _Rotation_ | _Lens_ | Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
| | **3** | Waves | _Spacing_ | _Thickness_ | _Vert. Scroll (R)_ | Colorize | _Black Color_ | _White Color_ | _Shift_ | | | **3** | Circuit | _Zoom_ | _H. connect_ | _V. connect_ | Colorize | _Black Color_ | _White Color_ | _Shift_ |
| | **4** | Noise | _Zoom_ | _Voronoi dist._ | _Details_ | Quantize | _Pixel Size_ | _Bit Depth_ | _Blur_ | | | **4** | Noise | _Zoom_ | _Voronoi dist._ | _Details_ | Quantize | _Pixel Size_ | _Bit Depth_ | _Blur_ |
| **2** | **5** | Video In 1 + Thru | _Hue_ | _Saturation_ | _Light_ | Dithering | _Pixel Size_ | _Bit Depth_ | _Blur_ | | **2** | **5** | Video In 1 + Thru | _Hue_ | _Saturation_ | _Light_ | Dithering | _Pixel Size_ | _Bit Depth_ | _Blur_ |
| | **6** | CP437 | _Zoom_ | _Charset_ | _Char. Delta_ | TV | _Lens_ | _Horz. Noise_ | _Dezoom_ | | | **6** | CP437 | _Zoom_ | _Charset_ | _Char. Delta_ | TV | _Lens_ | _Horz. Noise_ | _Dezoom_ |
@@ -467,10 +479,22 @@ Don't forget to add all information available to your bug (version, operating sy
### Help I got low FPS on my video device ### Help I got low FPS on my video device
There's already an [open issue](https://github.com/klemek/forge-steel/issues/1) on this subject. Unfortunately, V4L2 is very slow compared to driver-specific decoding.
You can check your device real FPS on [V4L2 UCP](https://github.com/HedgeHawk/v4l2ucp) or [GTK UVC Viewer](https://github.com/jaswdr/guvcview).
### My video feed got strange lines
You need to decode the [V4L2 YUYV format](https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-yuyv.html).
The code is available in the default project [default/inc_yuyv.glsl](./default/inc_yuyv.glsl)
### How do I change the default project built-in sentences? ### How do I change the default project built-in sentences?
The sentences are defined in [default/inc_sentences.glsl](./default/inc_sentences.glsl). The sentences are defined in [default/inc_sentences.glsl](./default/inc_sentences.glsl).
The script [scripts/sentences.py](./scripts/sentences.py) can help you update them. The script [scripts/sentences.py](./scripts/sentences.py) can help you update them.
### My video device keeps changing ID each time it's unplugged
You should [bind your device to a fixed interface](https://linuxvox.com/blog/linux-bind-camera-to-fixed-devvideo/).
+2 -1
View File
@@ -1,4 +1,5 @@
-Iinclude -Iinclude
-DGLFW_INCLUDE_NONE -DGLFW_INCLUDE_NONE
-DGLFW_EXPOSE_NATIVE_EGL -DGLFW_EXPOSE_NATIVE_EGL
-DGLFW_NATIVE_INCLUDE_NONE -DGLFW_NATIVE_INCLUDE_NONE
-DVIDEO_IN
+1 -1
View File
@@ -1,4 +1,4 @@
AC_INIT([forge], [steel-1.0.0], [klemek.dev@proton.me]) AC_INIT([forge], [steel-1.0.1], [klemek.dev@proton.me])
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AC_PROG_CC AC_PROG_CC
+78 -9
View File
@@ -37,6 +37,8 @@ UNIFORM_IN_FPS_PREFIX=iInputFPS
UNIFORM_DEMO=iDemo UNIFORM_DEMO=iDemo
# 0/1 if auto random # 0/1 if auto random
UNIFORM_AUTORAND=iAutoRand UNIFORM_AUTORAND=iAutoRand
# auto random cycle length
UNIFORM_AUTORANDCYCLE=iAutoRandCycle
# Current page # Current page
UNIFORM_PAGE=iPage UNIFORM_PAGE=iPage
# Current selected shader # Current selected shader
@@ -49,6 +51,8 @@ UNIFORM_STATE_PREFIX=iState
UNIFORM_ACTIVE_PREFIX=iActive UNIFORM_ACTIVE_PREFIX=iActive
# Input X format raw integer value # Input X format raw integer value
UNIFORM_IN_FORMAT_PREFIX=iInputFormat UNIFORM_IN_FORMAT_PREFIX=iInputFormat
# Input X should use swap texture or not (0/1)
UNIFORM_IN_SWAP_PREFIX=iInputSwap
# --- uniform vec2 --- # --- uniform vec2 ---
@@ -91,7 +95,7 @@ SUB_2_PREFIX=fx_
# Total number of internal textures # Total number of internal textures
TEX_COUNT=10 TEX_COUNT=12
# === VIDEO DEVICES # === VIDEO DEVICES
# Video devices will be read from CLI arguments # Video devices will be read from CLI arguments
@@ -102,10 +106,12 @@ IN_COUNT=2
# To which texture will be bound video device X # To which texture will be bound video device X
IN_1_OUT=1 IN_1_OUT=1
IN_2_OUT=2 IN_2_OUT=2
# To which texture will be bound swap buffers (for double-buffering)
IN_1_SWAP_OUT=3
IN_2_SWAP_OUT=4
# === FRAGMENT SHADERS # === FRAGMENT SHADERS
# Fragment shaders will be read from the CLI directory as "fragX.glsl" # Fragment shaders will be read from the CLI directory as "fragX.glsl"
# Special shader "frag0.glsl" will be prepend to each one
# Prefix of fragment shaders to detect # Prefix of fragment shaders to detect
FRAG_FILE_PREFIX=frag FRAG_FILE_PREFIX=frag
@@ -114,13 +120,13 @@ FRAG_FILE_PREFIX=frag
FRAG_COUNT=10 FRAG_COUNT=10
# To which texture will the shader fragX.glsl will render to # To which texture will the shader fragX.glsl will render to
FRAG_1_OUT=3 FRAG_1_OUT=5
FRAG_2_OUT=4 FRAG_2_OUT=6
FRAG_3_OUT=5 FRAG_3_OUT=7
FRAG_4_OUT=6 FRAG_4_OUT=8
FRAG_5_OUT=7 FRAG_5_OUT=9
FRAG_6_OUT=8 FRAG_6_OUT=10
FRAG_7_OUT=9 FRAG_7_OUT=11
FRAG_8_OUT=0 FRAG_8_OUT=0
# Which fragment shader renders to output window # Which fragment shader renders to output window
FRAG_OUTPUT=9 FRAG_OUTPUT=9
@@ -262,3 +268,66 @@ MIDI_3_1_Z=
MIDI_3_2_X=0 MIDI_3_2_X=0
MIDI_3_2_Y=16 MIDI_3_2_Y=16
MIDI_3_2_Z= MIDI_3_2_Z=
# =====
# OTHER
# =====
# === SAVE FILES
# When loading/saving from last run or using save states
SAVE_FILE_PREFIX=forge_default_save
# === HOTKEYS
# You can change the default keycodes used on runtime
# Modifiers are encoded like this:
# 1000 -> shift
# 10000 -> control
# 100000 -> alt
# This means 110082 is control+alt+R
# R on (qwerty)
HOTKEY_RANDOMIZE=82
# SHIFT+R (qwerty)
HOTKEY_RESET=1082
# D (qwerty)
HOTKEY_DEMO=68
# A (qwerty)
HOTKEY_AUTORAND=65
# Left arrow
HOTKEY_AUTORAND_DOWN=263
# Right arrow
HOTKEY_AUTORAND_UP=262
# Down arrow
HOTKEY_TEMPO_DOWN=264
# Up arrow
HOTKEY_TEMPO_UP=265
# Number of load states keys
HOTKEY_LOAD_COUNT=10
# 1 to 9 then 0 keys
HOTKEY_LOAD_1=49
HOTKEY_LOAD_2=50
HOTKEY_LOAD_3=51
HOTKEY_LOAD_4=52
HOTKEY_LOAD_5=53
HOTKEY_LOAD_6=54
HOTKEY_LOAD_7=55
HOTKEY_LOAD_8=56
HOTKEY_LOAD_9=57
HOTKEY_LOAD_10=48
# Number of save states keys
HOTKEY_SAVE_COUNT=10
# 1 to 9 then 0 keys with shift
HOTKEY_SAVE_1=1049
HOTKEY_SAVE_2=1050
HOTKEY_SAVE_3=1051
HOTKEY_SAVE_4=1052
HOTKEY_SAVE_5=1053
HOTKEY_SAVE_6=1054
HOTKEY_SAVE_7=1055
HOTKEY_SAVE_8=1056
HOTKEY_SAVE_9=1057
HOTKEY_SAVE_10=1048
+11 -5
View File
@@ -2,23 +2,29 @@
// VIDEO 1 // VIDEO 1
// ----------- // -----------
// IN: 1 (RAW IN A) // IN: 1+3 (RAW IN A)
// OUT: 3 (IN A) // OUT: 5 (IN A)
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
#include inc_yuv.glsl #include inc_yuyv.glsl
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform sampler2D iTex1; uniform sampler2D iTex1;
uniform sampler2D iTex3;
uniform int iInputFormat1; uniform int iInputFormat1;
uniform int iInputSwap1;
uniform vec2 iInputResolution1; uniform vec2 iInputResolution1;
void main() { void main() {
if (iInputFormat1 == YUYV_FOURCC) { if (iInputFormat1 == YUYV_FOURCC) {
fragColor = yuyvTex(iTex1, vUV, int(iInputResolution1.x)); if (iInputSwap1 > 0) {
fragColor = yuyvTex(iTex3, vUV, int(iInputResolution1.x));
} else {
fragColor = yuyvTex(iTex1, vUV, int(iInputResolution1.x));
}
} else { } else {
fragColor = texture(iTex0, vUV); fragColor = texture(iTex0, vUV);
} }
} }
+84 -50
View File
@@ -9,24 +9,23 @@ out vec4 fragColor;
#include inc_debug.glsl #include inc_debug.glsl
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform sampler2D iTex1;
uniform sampler2D iTex2;
uniform sampler2D iTex3;
uniform sampler2D iTex4;
uniform sampler2D iTex5; uniform sampler2D iTex5;
uniform sampler2D iTex6; uniform sampler2D iTex6;
uniform sampler2D iTex7; uniform sampler2D iTex7;
uniform sampler2D iTex8; uniform sampler2D iTex8;
uniform sampler2D iTex9; uniform sampler2D iTex9;
uniform sampler2D iTex10;
uniform sampler2D iTex11;
uniform int iFPS;
uniform int iInputFPS1; uniform int iInputFPS1;
uniform int iInputFPS2; uniform int iInputFPS2;
float s(vec2 uv, float x0, float y0) { float s(vec2 uv, float x0, float y0) {
return step(x0, uv.x) * step(-x0 - 1, -uv.x) * step(y0, uv.y) * return step(x0, uv.x) * step(-x0 - 1, -uv.x) * step(y0, uv.y) *
step(-y0 - 1, -uv.y); step(-y0 - 1, -uv.y);
} }
const int texts[10][5] = { const int texts[12][5] = {
{0x49, 0x4E, 0x20, 0x41, 0x00}, // IN A {0x49, 0x4E, 0x20, 0x41, 0x00}, // IN A
{0x49, 0x4E, 0x20, 0x42, 0x00}, // IN B {0x49, 0x4E, 0x20, 0x42, 0x00}, // IN B
{0x53, 0x52, 0x43, 0x20, 0x41}, // SRC A {0x53, 0x52, 0x43, 0x20, 0x41}, // SRC A
@@ -37,6 +36,8 @@ const int texts[10][5] = {
{0x4D, 0x46, 0x58, 0x00, 0x00}, // MFX {0x4D, 0x46, 0x58, 0x00, 0x00}, // MFX
{0x46, 0x50, 0x53, 0x00, 0x00}, // FPS {0x46, 0x50, 0x53, 0x00, 0x00}, // FPS
{0x4F, 0x46, 0x46, 0x00, 0x00}, // OFF {0x4F, 0x46, 0x46, 0x00, 0x00}, // OFF
{0x44, 0x45, 0x4D, 0x4F, 0x00}, // DEMO
{0x4C, 0x49, 0x56, 0x45, 0x00}, // LIVE
}; };
void main() { void main() {
@@ -48,57 +49,90 @@ void main() {
vec2 uv3 = uv1 * 60; vec2 uv3 = uv1 * 60;
vec4 c = vec4(0); vec4 c = vec4(0);
c += s(uv2,1,2) * texture(iTex5, uv2);
c += s(uv2,2,2) * texture(iTex7, uv2);
c += s(uv2,1,1) * texture(iTex6, uv2); c += s(uv2, 1, 2) * texture(iTex7, uv2);
c += s(uv2,2,1) * texture(iTex8, uv2); c += s(uv2, 2, 2) * texture(iTex9, uv2);
c += s(uv2,0,0) * debug(mod(uv2, 1)); c += s(uv2, 1, 0) * texture(iTex8, uv2);
c += s(uv2,1,0) * texture(iTex9, uv2); c += s(uv2, 2, 0) * texture(iTex10, uv2);
c += s(uv2,2,0) * texture(iTex0, uv2);
c += s(uv2, 0, 1) * debug(mod(uv2, 1));
c += s(uv2, 1, 1) * texture(iTex11, uv2);
c += s(uv2, 2, 1) * texture(iTex0, uv2);
float sel = 0;
sel += iSelected == 3 ? h_rect(uv2, vec2(1.5, 2.5), vec2(0.5), 0.01) : 0;
sel += iSelected == 4 ? h_rect(uv2, vec2(1.5, 0.5), vec2(0.5), 0.01) : 0;
sel += iSelected == 5 ? h_rect(uv2, vec2(2.5, 2.5), vec2(0.5), 0.01) : 0;
sel += iSelected == 6 ? h_rect(uv2, vec2(2.5, 0.5), vec2(0.5), 0.01) : 0;
sel += iSelected == 8 ? h_rect(uv2, vec2(2.5, 1.5), vec2(0.5), 0.01) : 0;
c = mix(c, 1 - c, sel);
float f = 0; float f = 0;
float t = 0; float t = 0;
f += rect(uv3, vec2(-51, 28.5), vec2(2.1, 0.7)); f += rect(uv3, vec2(-35, 28.5), vec2(2.1, 0.7));
t += write_5(uv3, vec2(-53,28), texts[0]); t += write_5(uv3, vec2(-37, 28), texts[0]);
if (iInputResolution1.x > 0) {
c += s(uv2,0,2) * texture(iTex3, uv2);
f += rect(uv3, vec2(-50.4, 26.5), vec2(2.8, 0.7));
t += write_int(uv3, vec2(-53,26), iInputFPS1, 2);
t += write_5(uv3, vec2(-50.5,26), texts[8]);
} else {
f += rect(uv3, vec2(-51.5, 26.5), vec2(1.6, 0.7));
t += write_5(uv3, vec2(-53,26), texts[9]);
}
f += rect(uv3, vec2(-51, 8.5), vec2(2.1, 0.7));
t += write_5(uv3, vec2(-53,8), texts[1]);
if (iInputResolution2.x > 0) { if (iInputFormat1 == YUYV_FOURCC) {
c += s(uv2,0,1) * texture(iTex4, uv2); c += s(uv2, 0, 2) * texture(iTex5, uv2);
f += rect(uv3, vec2(-50.4, 6.5), vec2(2.8, 0.7)); f += rect(uv3, vec2(-35, 26.75), vec2(2.8, 0.7));
t += write_int(uv3, vec2(-53,6), iInputFPS2, 2); t += write_int(uv3, vec2(-37.6, 26.1), iInputFPS1, 2);
t += write_5(uv3, vec2(-50.5,6), texts[8]); t += write_5(uv3, vec2(-35.1, 26.1), texts[8]);
} else { } else {
f += rect(uv3, vec2(-51.5, 6.5), vec2(1.6, 0.7)); f += rect(uv3, vec2(-35, 26.75), vec2(1.6, 0.7));
t += write_5(uv3, vec2(-53,6), texts[9]); t += write_5(uv3, vec2(-36.5, 26.1), texts[9]);
} }
f += rect(uv3, vec2(-14.5, 28.5), vec2(2.6, 0.7));
t += write_5(uv3, vec2(-17,28), texts[2]);
f += rect(uv3, vec2(-14.5, 8.5), vec2(2.6, 0.7));
t += write_5(uv3, vec2(-17,8), texts[3]);
f += rect(uv3, vec2(21, 28.5), vec2(2.1, 0.7));
t += write_5(uv3, vec2(19,28), texts[4]);
f += rect(uv3, vec2(21, 8.5), vec2(2.1, 0.7));
t += write_5(uv3, vec2(19,8), texts[5]);
f += rect(uv3, vec2(-15.5, -11.5), vec2(1.6, 0.7));
t += write_5(uv3, vec2(-17,-12), texts[6]);
f += rect(uv3, vec2(20.5, -11.5), vec2(1.6, 0.7));
t += write_5(uv3, vec2(19,-12), texts[7]);
fragColor = mix(c, vec4(f - t), f); f += rect(uv3, vec2(-35, -11.5), vec2(2.1, 0.7));
} t += write_5(uv3, vec2(-37, -12), texts[1]);
if (iInputFormat2 == YUYV_FOURCC) {
c += s(uv2, 0, 0) * texture(iTex6, uv2);
f += rect(uv3, vec2(-35, -13.25), vec2(2.8, 0.7));
t += write_int(uv3, vec2(-37.6, -13.9), iInputFPS2, 2);
t += write_5(uv3, vec2(-35.1, -13.9), texts[8]);
} else {
f += rect(uv3, vec2(-35, -13.25), vec2(1.6, 0.7));
t += write_5(uv3, vec2(-36.5, -13.9), texts[9]);
}
f += rect(uv3, vec2(-35, 8.5), vec2(2.1, 0.7));
if (iDemo > 0) {
t += write_5(uv3, vec2(-37, 8), texts[10]);
} else {
t += write_5(uv3, vec2(-37, 8), texts[11]);
}
f += rect(uv3, vec2(0, 28.5), vec2(2.6, 0.7));
f += iActive1 == 1 ? h_rect(uv3, vec2(0, 28.5), vec2(3, 1), 0.2) : 0;
t += write_5(uv3, vec2(-2.5, 28), texts[2]);
f += rect(uv3, vec2(0, -11.5), vec2(2.6, 0.7));
f += iActive1 == 2 ? h_rect(uv3, vec2(0, -11.5), vec2(3, 1), 0.2) : 0;
t += write_5(uv3, vec2(-2.5, -12), texts[3]);
f += rect(uv3, vec2(35, 28.5), vec2(2.1, 0.7));
f += iActive2 == 1 ? h_rect(uv3, vec2(35, 28.5), vec2(2.5, 1), 0.2) : 0;
t += write_5(uv3, vec2(33, 28), texts[4]);
f += rect(uv3, vec2(35, -11.5), vec2(2.1, 0.7));
f += iActive2 == 2 ? h_rect(uv3, vec2(35, -11.5), vec2(2.5, 1), 0.2) : 0;
t += write_5(uv3, vec2(33, -12), texts[5]);
f += rect(uv3, vec2(0, 8.5), vec2(1.6, 0.7));
t += write_5(uv3, vec2(-1.5, 8), texts[6]);
f += rect(uv3, vec2(35, 8.5), vec2(1.6, 0.7));
f += iActive2 == 3 ? h_rect(uv3, vec2(35, 8.5), vec2(2, 1), 0.2) : 0;
t += write_5(uv3, vec2(33.5, 8), texts[7]);
f += rect(uv3, vec2(35, 6.75), vec2(2.8, 0.7));
t += write_int(uv3, vec2(32.4, 6.1), iFPS, 2);
t += write_5(uv3, vec2(34.9, 6.1), texts[8]);
fragColor = mix(c, vec4(min(1, f) - t), min(1, f));
}
+11 -5
View File
@@ -2,23 +2,29 @@
// VIDEO 2 // VIDEO 2
// ----------- // -----------
// IN: 2 (RAW IN B) // IN: 2+4 (RAW IN B)
// OUT: 4 (IN B) // OUT: 6 (IN B)
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
#include inc_yuv.glsl #include inc_yuyv.glsl
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform sampler2D iTex2; uniform sampler2D iTex2;
uniform sampler2D iTex4;
uniform int iInputFormat2; uniform int iInputFormat2;
uniform int iInputSwap2;
uniform vec2 iInputResolution2; uniform vec2 iInputResolution2;
void main() { void main() {
if (iInputFormat2 == YUYV_FOURCC) { if (iInputFormat2 == YUYV_FOURCC) {
fragColor = yuyvTex(iTex2, vUV, int(iInputResolution2.x)); if (iInputSwap2 > 0) {
fragColor = yuyvTex(iTex4, vUV, int(iInputResolution2.x));
} else {
fragColor = yuyvTex(iTex2, vUV, int(iInputResolution2.x));
}
} else { } else {
fragColor = texture(iTex0, vUV); fragColor = texture(iTex0, vUV);
} }
} }
+2 -2
View File
@@ -3,7 +3,7 @@
// SRC A // SRC A
// ----------- // -----------
// OUT: 5 (FX A) // OUT: 7 (FX A)
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
@@ -17,4 +17,4 @@ uniform vec3 iMidi1_1[6];
void main() { void main() {
fragColor = src_stage(vUV, iSeed3, iMidi1_1[0], iMidi1_1[1].xy, iMidi1_1[2], iMidi1_1[3].xy, iMidi1_1[4], iMidi1_1[5].xy); fragColor = src_stage(vUV, iSeed3, iMidi1_1[0], iMidi1_1[1].xy, iMidi1_1[2], iMidi1_1[3].xy, iMidi1_1[4], iMidi1_1[5].xy);
} }
+2 -2
View File
@@ -2,7 +2,7 @@
// SRC B // SRC B
// ----------- // -----------
// OUT: 6 (FX B) // OUT: 8 (FX B)
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
@@ -16,4 +16,4 @@ uniform vec3 iMidi1_2[6];
void main() { void main() {
fragColor = src_stage(vUV, iSeed4, iMidi1_2[0], iMidi1_2[1].xy, iMidi1_2[2], iMidi1_2[3].xy, iMidi1_2[4], iMidi1_2[5].xy); fragColor = src_stage(vUV, iSeed4, iMidi1_2[0], iMidi1_2[1].xy, iMidi1_2[2], iMidi1_2[3].xy, iMidi1_2[4], iMidi1_2[5].xy);
} }
+6 -6
View File
@@ -2,20 +2,20 @@
// FX A // FX A
// ------------- // -------------
// IN: 5 (SRC A) // IN: 7 (SRC A)
// IN: 7 (FX A) // IN: 9 (FX A)
// OUT: 7 (A+B) // OUT: 9 (A+B)
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
#include inc_fx.glsl #include inc_fx.glsl
uniform sampler2D iTex5;
uniform sampler2D iTex7; uniform sampler2D iTex7;
uniform sampler2D iTex9;
uniform int iSeed5; uniform int iSeed5;
uniform vec3 iMidi2_1[7]; uniform vec3 iMidi2_1[7];
void main() { void main() {
fragColor = fx_stage(vUV, iTex5, iTex7, iSeed5, iMidi2_1[0], iMidi2_1[1].xy, iMidi2_1[2], iMidi2_1[3].xy, iMidi2_1[4], iMidi2_1[5].xy, iMidi2_1[6]); fragColor = fx_stage(vUV, iTex7, iTex9, iSeed5, iMidi2_1[0], iMidi2_1[1].xy, iMidi2_1[2], iMidi2_1[3].xy, iMidi2_1[4], iMidi2_1[5].xy, iMidi2_1[6]);
} }
+6 -6
View File
@@ -2,20 +2,20 @@
// FX B // FX B
// ------------- // -------------
// IN: 6 (SRC B) // IN: 8 (SRC B)
// IN: 8 (FX B) // IN: 10 (FX B)
// OUT: 8 (A+B) // OUT: 10 (A+B)
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
#include inc_fx.glsl #include inc_fx.glsl
uniform sampler2D iTex6;
uniform sampler2D iTex8; uniform sampler2D iTex8;
uniform sampler2D iTex10;
uniform int iSeed6; uniform int iSeed6;
uniform vec3 iMidi2_2[7]; uniform vec3 iMidi2_2[7];
void main() { void main() {
fragColor = fx_stage(vUV, iTex6, iTex8, iSeed6, iMidi2_2[0], iMidi2_2[1].xy, iMidi2_2[2], iMidi2_2[3].xy, iMidi2_2[4], iMidi2_2[5].xy, iMidi2_2[6]); fragColor = fx_stage(vUV, iTex8, iTex10, iSeed6, iMidi2_2[0], iMidi2_2[1].xy, iMidi2_2[2], iMidi2_2[3].xy, iMidi2_2[4], iMidi2_2[5].xy, iMidi2_2[6]);
} }
+15 -10
View File
@@ -2,9 +2,9 @@
// A+B // A+B
// ------------ // ------------
// IN: 7 (FX A) // IN: 9 (FX A)
// IN: 8 (FX B) // IN: 10 (FX B)
// OUT: 9 (MFX) // OUT: 11 (MFX)
in vec2 vUV; in vec2 vUV;
out vec4 fragColor; out vec4 fragColor;
@@ -12,8 +12,9 @@ out vec4 fragColor;
#include inc_magic.glsl #include inc_magic.glsl
#include inc_functions.glsl #include inc_functions.glsl
uniform sampler2D iTex7; uniform int iDemo;
uniform sampler2D iTex8; uniform sampler2D iTex9;
uniform sampler2D iTex10;
uniform int iSeed7; uniform int iSeed7;
uniform vec3 iMidi3_1[2]; uniform vec3 iMidi3_1[2];
@@ -21,12 +22,16 @@ void main() {
float mix_value = magic(iMidi3_1[1].xy, vec3(1, 0, 0), iSeed7); float mix_value = magic(iMidi3_1[1].xy, vec3(1, 0, 0), iSeed7);
bool mix_type = magic_trigger(vec3(iMidi3_1[0].x, 0, 0), iSeed7 + 10); bool mix_type = magic_trigger(vec3(iMidi3_1[0].x, 0, 0), iSeed7 + 10);
vec4 color_a = texture(iTex7, vUV); vec4 color_a = texture(iTex9, vUV);
vec4 color_b = texture(iTex8, vUV); vec4 color_b = texture(iTex10, vUV);
float k = mean(color_a); float k = mean(color_a);
mix_value = mix(mix_value * 0.9 + 0.05, mix_value, 1 - iDemo); mix_value = mix(mix_value, mix_value * 0.9 + 0.05, iDemo);
fragColor = mix(color_b, color_a, mix_type ? step(mix_value, k) : mix_value); if (mix_type) {
} fragColor = mix(color_a, color_b, step(mix_value, k));
} else {
fragColor = mix(color_b, color_a, mix_value);
}
}
+9 -5
View File
@@ -2,7 +2,7 @@
// MFX // MFX
// ------------ // ------------
// IN: 9 (A+B) // IN: 11 (A+B)
// IN: 0 (OUT) // IN: 0 (OUT)
// OUT: 0 (OUT) // OUT: 0 (OUT)
@@ -11,16 +11,20 @@ out vec4 fragColor;
#include inc_fx.glsl #include inc_fx.glsl
uniform sampler2D iTex9; uniform sampler2D iTex11;
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform int iSeed8; uniform int iSeed8;
uniform vec3 iMidi2_3[7]; uniform vec3 iMidi2_3[7];
uniform vec3 iMidi3_1[2]; uniform vec3 iMidi3_1[2];
uniform int iDemo;
uniform int iAutoRand;
void main() { void main() {
vec4 color = fx_stage(vUV, iTex9, iTex0, iSeed8, iMidi2_3[0], iMidi2_3[1].xy, iMidi2_3[2], iMidi2_3[3].xy, iMidi2_3[4], iMidi2_3[5].xy, iMidi2_3[6]); vec4 color = fx_stage(vUV, iTex11, iTex0, iSeed8, iMidi2_3[0], iMidi2_3[1].xy, iMidi2_3[2], iMidi2_3[3].xy, iMidi2_3[4], iMidi2_3[5].xy, iMidi2_3[6]);
color = mix(color, vec4(0), iMidi3_1[0].y); if (iDemo < 1 && iAutoRand < 1) {
color = mix(color, vec4(0), iMidi3_1[0].y);
}
fragColor = color; fragColor = color;
} }
+1 -1
View File
@@ -10,4 +10,4 @@ uniform sampler2D iTex0;
void main() { void main() {
fragColor = texture(iTex0, vUV); fragColor = texture(iTex0, vUV);
} }
+19 -5
View File
@@ -94,7 +94,7 @@ const int cp437[] = {
0xE333, 0x1333, 0x0ECC, 0x0100, // 0x59, Y 0xE333, 0x1333, 0x0ECC, 0x0100, // 0x59, Y
0x813F, 0x1367, 0x0F6C, 0x0764, // 0x5A, Z 0x813F, 0x1367, 0x0F6C, 0x0764, // 0x5A, Z
0x666E, 0x0001, 0x0E66, 0x0100, // 0x5B, [ 0x666E, 0x0001, 0x0E66, 0x0100, // 0x5B, [
0x8C63, 0x1000, 0x0000, 0x0463, // 0x5C, 0x8C63, 0x1000, 0x0000, 0x0463, // 0x5C,
0x888E, 0x1111, 0x0E88, 0x0111, // 0x5D, ] 0x888E, 0x1111, 0x0E88, 0x0111, // 0x5D, ]
0x36C8, 0x6310, 0x0000, 0x0000, // 0x5E, ^ 0x36C8, 0x6310, 0x0000, 0x0000, // 0x5E, ^
0x0000, 0x0000, 0xF000, 0xF000, // 0x5F, _ 0x0000, 0x0000, 0xF000, 0xF000, // 0x5F, _
@@ -372,13 +372,27 @@ float write_int(vec2 uv, vec2 pos, uint value, uint magnitude)
return d; return d;
} }
float write_int_left(vec2 uv, vec2 pos, uint value, uint magnitude)
{
int i;
uint m = 1;
float d = 0;
for (i = 0; i < magnitude; i++) {
if (i == 0 || value >= m) {
pos.x += 1;
m *= 10u;
}
}
return write_int(uv, pos, value, magnitude);
}
int read(sampler2D tex, vec2 uv, float k, int d, float t) int read(sampler2D tex, vec2 uv, float k, int d, float t)
{ {
float inv_k = 1 / k; float inv_k = 1 / k;
vec2 tex_uv = floor(uv * k) * inv_k; vec2 tex_uv = floor(uv * k) * inv_k;
tex_uv += vec2(d % 2, floor(d * 0.5)) * 0.5 * inv_k; tex_uv += vec2(d % 2, floor(d * 0.5)) * 0.5 * inv_k;
return return
((mean(reframe(tex, tex_uv + vec2(0, 3) * inv_k * 0.125)) > t) ? 1 : 0) + ((mean(reframe(tex, tex_uv + vec2(0, 3) * inv_k * 0.125)) > t) ? 1 : 0) +
((mean(reframe(tex, tex_uv + vec2(0, 2) * inv_k * 0.125)) > t) ? 2 : 0) + ((mean(reframe(tex, tex_uv + vec2(0, 2) * inv_k * 0.125)) > t) ? 2 : 0) +
((mean(reframe(tex, tex_uv + vec2(0, 1) * inv_k * 0.125)) > t) ? 4 : 0) + ((mean(reframe(tex, tex_uv + vec2(0, 1) * inv_k * 0.125)) > t) ? 4 : 0) +
((mean(reframe(tex, tex_uv + vec2(0, 0) * inv_k * 0.125)) > t) ? 8 : 0) + ((mean(reframe(tex, tex_uv + vec2(0, 0) * inv_k * 0.125)) > t) ? 8 : 0) +
@@ -397,7 +411,7 @@ int read(sampler2D tex, vec2 uv, float k, int d, float t)
} }
// https://web.archive.org/web/20151229003112/http://blogs.msdn.com/b/jeuge/archive/2005/06/08/hakmem-bit-count.aspx // https://web.archive.org/web/20151229003112/http://blogs.msdn.com/b/jeuge/archive/2005/06/08/hakmem-bit-count.aspx
int bit_count(int u) int bit_count(int u)
{ {
int c; int c;
c = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); c = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
@@ -410,7 +424,7 @@ int guess_char(sampler2D tex, vec2 uv, float k, float t)
int b1 = read(tex, uv, k, 1, t); int b1 = read(tex, uv, k, 1, t);
int b2 = read(tex, uv, k, 2, t); int b2 = read(tex, uv, k, 2, t);
int b3 = read(tex, uv, k, 3, t); int b3 = read(tex, uv, k, 3, t);
int mc = 0; int mc = 0;
int mb = 100; int mb = 100;
int i; int i;
@@ -430,4 +444,4 @@ int guess_char(sampler2D tex, vec2 uv, float k, float t)
return mc; return mc;
} }
#endif #endif
+41 -36
View File
@@ -1,19 +1,19 @@
#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;
uniform int iInputFormat2; uniform int iInputFormat2;
uniform int iDemo;
uniform int iAutoRand; uniform int iAutoRand;
uniform int iAutoRandCycle;
uniform int iPage; uniform int iPage;
uniform int iSelected; uniform int iSelected;
@@ -99,6 +99,7 @@ vec4 debug(vec2 vUV)
float mfx_value = magic(iMidi2_3[6].xy, vec3(1, 0, 0), iSeed8); float mfx_value = magic(iMidi2_3[6].xy, vec3(1, 0, 0), iSeed8);
bool mfx_invert = magic_trigger(vec3(iMidi2_3[6].z, 0, 0), iSeed8); bool mfx_invert = magic_trigger(vec3(iMidi2_3[6].z, 0, 0), iSeed8);
float mix_value = magic(iMidi3_1[1].xy, vec3(1, 0, 0), iSeed7); float mix_value = magic(iMidi3_1[1].xy, vec3(1, 0, 0), iSeed7);
mix_value = mix(mix_value, mix_value * 0.9 + 0.05, iDemo);
bool mix_type = magic_trigger(vec3(iMidi3_1[0].x, 0, 0), iSeed7 + 10); bool mix_type = magic_trigger(vec3(iMidi3_1[0].x, 0, 0), iSeed7 + 10);
// logic // logic
@@ -109,7 +110,7 @@ vec4 debug(vec2 vUV)
{0x54, 0x49, 0x4D, 0x45, 0x00}, // TIME {0x54, 0x49, 0x4D, 0x45, 0x00}, // TIME
{0x44, 0x45, 0x4D, 0x4F, 0x00}, // DEMO {0x44, 0x45, 0x4D, 0x4F, 0x00}, // DEMO
{0x4C, 0x49, 0x56, 0x45, 0x00}, // LIVE {0x4C, 0x49, 0x56, 0x45, 0x00}, // LIVE
{0x2B, 0x52, 0x41, 0x4E, 0x44}, // +RAND {0x52, 0x41, 0x4E, 0x44, 0x00}, // RAND
{0x53, 0x52, 0x43, 0x00, 0x00}, // SRC {0x53, 0x52, 0x43, 0x00, 0x00}, // SRC
{0x46, 0x58, 0x00, 0x00, 0x00}, // FX {0x46, 0x58, 0x00, 0x00, 0x00}, // FX
{0x49, 0x4E, 0x00, 0x00, 0x00}, // IN {0x49, 0x4E, 0x00, 0x00, 0x00}, // IN
@@ -125,7 +126,7 @@ vec4 debug(vec2 vUV)
vec2 uv3 = uv1 * 30; vec2 uv3 = uv1 * 30;
// base frame // base frame
float f = float f =
h_rect(uv2, vec2(-5, -2), vec2(1), 0.1) + h_rect(uv2, vec2(-5, -2), vec2(1), 0.1) +
h_rect(uv2, vec2(-2, -2), vec2(1), 0.1) + h_rect(uv2, vec2(-2, -2), vec2(1), 0.1) +
rect(uv2, vec2(-3.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(-3.5, -2), vec2(0.5, 0.1)) +
@@ -139,8 +140,17 @@ vec4 debug(vec2 vUV)
rect(uv2, vec2(2, -1.55), vec2(0.1, 0.55)) + rect(uv2, vec2(2, -1.55), vec2(0.1, 0.55)) +
rect(uv2, vec2(0.55, 2), vec2(1.5, 0.1)) + rect(uv2, vec2(0.55, 2), vec2(1.5, 0.1)) +
rect(uv2, vec2(2, 1.55), vec2(0.1, 0.55)) + rect(uv2, vec2(2, 1.55), vec2(0.1, 0.55)) +
rect(uv2, vec2(7.5, 0), vec2(1.5, 0.1)) + rect(uv2, vec2(6.8, 0), vec2(0.75, 0.1)) +
h_rect(uv2, vec2(-9, -3.9), vec2(1), 0.1); h_circle(uv2, vec2(7.8, 0), 0.3, 0.1)
;
if (iDemo < 1 && iInputFormat1 == YUYV_FOURCC) {
f += circle(uv2, vec2(-9, 2), 0.3);
}
if (iDemo < 1 && iInputFormat2 == YUYV_FOURCC) {
f += circle(uv2, vec2(-9, -2), 0.3);
}
// show selected src/fx // show selected src/fx
f += char_at(uv2, vec2(-5.4, 1.45), hex_chars[selected_srca]); f += char_at(uv2, vec2(-5.4, 1.45), hex_chars[selected_srca]);
@@ -175,17 +185,17 @@ vec4 debug(vec2 vUV)
f += write_5(uv3 * 0.75, vec2(-11.6,-1.8), texts[6]); f += write_5(uv3 * 0.75, vec2(-11.6,-1.8), texts[6]);
f += write_5(uv3 * 0.75, vec2(-4.2,-1.8), texts[7]); f += write_5(uv3 * 0.75, vec2(-4.2,-1.8), texts[7]);
f += char_at(uv3 * 0.5, vec2(0.5, 0.5), 0x41); f += char_at(uv3 * 0.5, vec2(-11.5, 3.5), 0x41);
f += char_at(uv3 * 0.5, vec2(0.5, -3), 0x42); f += char_at(uv3 * 0.5, vec2(-11.5, -6), 0x42);
if (iDemo < 1 && (iInputFormat1 == YUYV_FOURCC || iInputFormat2 == YUYV_FOURCC)) { if (iDemo < 1 && (iInputFormat1 == YUYV_FOURCC || iInputFormat2 == YUYV_FOURCC)) {
f += write_5(uv3 * 0.75, vec2(-19.7,-1.8), texts[8]); f += write_5(uv3 * 0.75, vec2(-19.7,-1.8), texts[8]);
} }
f += write_5(uv3 * 0.75, vec2(10.9,2), texts[9]); f += write_5(uv3 * 0.75, vec2(10.9,2), texts[9]);
// show inputs / feedback // show inputs / feedback
float line_a_a = rect(uv2, vec2(-8, 2), vec2(2, 0.1)); float line_a_a = rect(uv2, vec2(-7.5, 2), vec2(1.5, 0.1));
float line_a_b = rect(uv2, vec2(-7, 2), vec2(1, 0.1)) + rect(uv2, vec2(-8, 0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-9, -1), vec2(1, 0.1)); float line_a_b = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(-8.5, -2), vec2(0.5, 0.1)) + line(uv2, vec2(-7, 2.1), vec2(-8, -2.1), 0.2);
float line_a_f = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, 4), vec2(7, 0.1)) + rect(uv2, vec2(-7, 3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, 2), vec2(0.1, 2.1)); float line_a_f = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, 3.6), vec2(7, 0.1)) + rect(uv2, vec2(-7, 2.8), vec2(0.1, 0.9)) + rect(uv2, vec2(7, 1.8), vec2(0.1, 1.9));
if (selected_srca == 5 && iInputFormat1 == YUYV_FOURCC) { if (selected_srca == 5 && iInputFormat1 == YUYV_FOURCC) {
f += line_a_a; f += line_a_a;
} else if (selected_srca == 10 && iInputFormat2 == YUYV_FOURCC) { } else if (selected_srca == 10 && iInputFormat2 == YUYV_FOURCC) {
@@ -193,9 +203,10 @@ vec4 debug(vec2 vUV)
} else if (selected_srca % 5 == 0) { } else if (selected_srca % 5 == 0) {
f += line_a_f; f += line_a_f;
} }
float line_b_a = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(-7, -0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-8.5, 1), vec2(1.5, 0.1));
float line_b_b = rect(uv2, vec2(-8, -2), vec2(2, 0.1)); float line_b_a = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(-8.5, 2), vec2(0.5, 0.1)) + line(uv2, vec2(-7, -2.1), vec2(-8, 2.1), 0.2);
float line_b_f = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, -4), vec2(7, 0.1)) + rect(uv2, vec2(-7, -3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, -2), vec2(0.1, 2.1)); float line_b_b = rect(uv2, vec2(-7.5, -2), vec2(1.5, 0.1));
float line_b_f = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, -3.6), vec2(7, 0.1)) + rect(uv2, vec2(-7, -2.8), vec2(0.1, 0.9)) + rect(uv2, vec2(7, -1.8), vec2(0.1, 1.9));
if (selected_srcb == 5 && iInputFormat1 == YUYV_FOURCC) { if (selected_srcb == 5 && iInputFormat1 == YUYV_FOURCC) {
f += line_b_a; f += line_b_a;
} else if (selected_srcb == 10 && iInputFormat2 == YUYV_FOURCC) { } else if (selected_srcb == 10 && iInputFormat2 == YUYV_FOURCC) {
@@ -205,7 +216,9 @@ vec4 debug(vec2 vUV)
} }
// show page // show page
f += char_at(uv2, vec2(-9.2, -4.3), hex_chars[iPage]); f += iPage == 0 ? circle(uv2, vec2(-0.75, -4.1), 0.3) : h_circle(uv2, vec2(-0.75, -4.1), 0.25, 0.1);
f += iPage == 1 ? circle(uv2, vec2(0, -4.1), 0.3) : h_circle(uv2, vec2(0, -4.1), 0.20, 0.1);
f += iPage == 2 ? circle(uv2, vec2(0.75, -4.1), 0.3) : h_circle(uv2, vec2(0.75, -4.1), 0.20, 0.1);
// show fx values // show fx values
float fx_rect = 0; float fx_rect = 0;
@@ -223,34 +236,26 @@ vec4 debug(vec2 vUV)
float x = 0; float x = 0;
x = -15; x = -15;
f += write_5(uv3, vec2(x,13), texts[0]); f += write_5(uv3, vec2(x - 4.5,13), texts[1]);
f += write_int(uv3, vec2(x - 3.5,13), iFPS, 3); f += write_int(uv3, vec2(x + 1.5,13), int(iTempo), 3);
v = min(1, iFPS/60.0);
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
x = 0;
f += write_5(uv3, vec2(x,13), texts[1]);
f += write_int(uv3, vec2(x - 3.5,13), int(iTempo), 3);
v = fract(iBeats); v = fract(iBeats);
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
x = 15; x = 15;
f += write_5(uv3, vec2(x,13), texts[2]); if (iAutoRand > 0) {
f += write_int(uv3, vec2(x - 5.5,13), int(iTime), 5); f += write_5(uv3, vec2(x - 4.5,13), texts[5]);
v = fract(iTime); f += write_int(uv3, vec2(x - 0.5,13), int(iAutoRandCycle), 5);
v = fract(iBeats / iAutoRandCycle);
} else {
f += write_int(uv3, vec2(x - 0.5,13), int(iTime), 5);
v = fract(iTime);
f += write_5(uv3, vec2(x - 4.5,13), texts[2]);
}
f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2);
f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4));
if (iAutoRand > 0) {
f += write_5(uv3, vec2(-4,-15), iDemo > 0 ? texts[3] : texts[4]);
f += write_5(uv3, vec2(0,-15), texts[5]);
} else {
f += write_5(uv3, vec2(-2,-15), iDemo > 0 ? texts[3] : texts[4]);
}
return vec4(f); return vec4(f);
} }
#endif #endif
+11 -5
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
@@ -186,10 +188,10 @@ vec2 v_pos(float i) {
float x0 = rand(i + 823 + iTimeId); float x0 = rand(i + 823 + iTimeId);
float y0 = rand(i + 328 + iTimeId); float y0 = rand(i + 328 + iTimeId);
float x1 = rand(i + 823 + iTimeId + 1); float x1 = rand(i + 823 + iTimeId + 1);
float y1 = rand(i + 328 + iTimeId + 1); float y1 = rand(i + 328 + iTimeId + 1);
return vec2( return vec2(
mix(x0, x1, ease(ease(iTimeV))), mix(x0, x1, ease(ease(iTimeV))),
mix(y0, y1, ease(ease(iTimeV))) mix(y0, y1, ease(ease(iTimeV)))
@@ -224,6 +226,10 @@ float circle(vec2 uv, vec2 c, float size) {
return istep(size, length(uv - c)); return istep(size, length(uv - c));
} }
float h_circle(vec2 uv, vec2 c, float size, float k) {
return circle(uv, c, size + k * 0.5) - circle(uv, c, size - k * 0.5);
}
float stripe(float x, float k1, float k2) float stripe(float x, float k1, float k2)
{ {
return k2 > k1 ? (1 - step(x, k1)) * (step(x, k2)) : ((1 - step(x, k2)) * (step(x, k1))); return k2 > k1 ? (1 - step(x, k1)) * (step(x, k2)) : ((1 - step(x, k2)) * (step(x, k1)));
@@ -251,13 +257,13 @@ float line(vec2 uv, vec2 p1, vec2 p2, float thick) {
vec2 p = p2 - p1; vec2 p = p2 - p1;
uv -= p1; uv -= p1;
vec2 k; vec2 k;
if (abs(p.y) > abs(p.x)) { if (abs(p.y) > abs(p.x)) {
k = vec2( k = vec2(
uv.x - p.x * uv.y / p.y, uv.x - p.x * uv.y / p.y,
uv.y / p.y uv.y / p.y
); );
return step(k.x, thick * 0.5) return step(k.x, thick * 0.5)
* step(-k.x, thick * 0.5) * step(-k.x, thick * 0.5)
* step(k.y, 1) * step(k.y, 1)
@@ -267,7 +273,7 @@ float line(vec2 uv, vec2 p1, vec2 p2, float thick) {
uv.x / p.x, uv.x / p.x,
uv.y - p.y * uv.x / p.x uv.y - p.y * uv.x / p.x
); );
return step(k.y, thick * 0.5) return step(k.y, thick * 0.5)
* step(-k.y, thick * 0.5) * step(-k.y, thick * 0.5)
* step(k.x, 1) * step(k.x, 1)
+14 -14
View File
@@ -60,9 +60,9 @@ vec4 fx_shift(vec2 vUV, sampler2D src0, sampler2D src1, int seed, vec3 b1, vec2
float y_shift = magic(f3, b3, seed + 30); float y_shift = magic(f3, b3, seed + 30);
// logic // logic
vec3 c0 = texture(src0, uv0).xyz; vec3 c0 = texture(src0, uv0).xyz;
vec2 uv2 = uv1; vec2 uv2 = uv1;
uv2 = mix(uv2 * (1 + zoom * 2), uv2 * (zoom), step(0.5, zoom)); uv2 = mix(uv2 * (1 + zoom * 2), uv2 * (zoom), step(0.5, zoom));
uv2 += vec2(x_shift * ratio, y_shift) * 2; uv2 += vec2(x_shift * ratio, y_shift) * 2;
@@ -127,7 +127,7 @@ subroutine(fx_stage_sub) vec4 fx_5(vec2 vUV, sampler2D previous, sampler2D feedb
// logic // logic
vec3 c0 = texture(previous, uv0).xyz; vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1; vec2 uv2 = uv1;
float pixel = (1 - pixel_size) * 250 + 25; float pixel = (1 - pixel_size) * 250 + 25;
uv2 = round(uv2 * pixel) / pixel; uv2 = round(uv2 * pixel) / pixel;
@@ -199,9 +199,9 @@ subroutine(fx_stage_sub) vec4 fx_7(vec2 vUV, sampler2D previous, sampler2D feedb
float zoom = magic(f3, b3, seed + 30); float zoom = magic(f3, b3, seed + 30);
// logic // logic
vec3 c0 = texture(previous, uv0).xyz; vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1; vec2 uv2 = uv1;
float k1 = lens_v * 0.5; float k1 = lens_v * 0.5;
uv2 *= 1 + zoom * 2; uv2 *= 1 + zoom * 2;
@@ -235,9 +235,9 @@ subroutine(fx_stage_sub) vec4 fx_8(vec2 vUV, sampler2D previous, sampler2D feedb
// logic // logic
vec3 c0 = texture(previous, uv0).xyz; vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1; vec2 uv2 = uv1;
uv2 = mix(uv2, kal2(uv2 * rot(0.25), floor(axes * 9 + 1)) * vec2(1, -2) + vec2(0, -0.5), axes_trigger); uv2 = mix(uv2, kal2(uv2 * rot(0.25), floor(axes * 9 + 1)) * vec2(1, -2) + vec2(0, -0.5), axes_trigger);
uv2 *= rot(rotation); uv2 *= rot(rotation);
uv2.x = (saw(uv2.x / ratio + 0.5 + h_scroll * 2) - 0.5) * ratio; uv2.x = (saw(uv2.x / ratio + 0.5 + h_scroll * 2) - 0.5) * ratio;
vec3 c = reframe(previous, uv2).xyz; vec3 c = reframe(previous, uv2).xyz;
@@ -262,12 +262,12 @@ subroutine(fx_stage_sub) vec4 fx_9(vec2 vUV, sampler2D previous, sampler2D feedb
vec2 charset = magic_f(f2, b2, seed + 20); vec2 charset = magic_f(f2, b2, seed + 20);
vec3 charset_ctrl = magic_b(b2, seed + 20); vec3 charset_ctrl = magic_b(b2, seed + 20);
float char_delta = magic(f3, b3, seed + 30); float char_delta = magic(f3, b3, seed + 30);
float t = magic(seed + 40); float t = magic(seed + 40);
// logic // logic
vec3 c0 = texture(previous, uv0).xyz; vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1; vec2 uv2 = uv1;
float k1 = 100 * (1 - zoom) + 10; float k1 = 100 * (1 - zoom) + 10;
float inv_k = 1 / k1; float inv_k = 1 / k1;
@@ -306,7 +306,7 @@ subroutine(fx_stage_sub) vec4 fx_10(vec2 vUV, sampler2D previous, sampler2D feed
// logic // logic
vec3 c0 = texture(previous, uv0).xyz; vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1; vec2 uv2 = uv1;
uv2 *= 1 + zoom * 2; uv2 *= 1 + zoom * 2;
uv2 = lens(uv2, -lens_v2 * 10, lens_v1 * 10); uv2 = lens(uv2, -lens_v2 * 10, lens_v1 * 10);
@@ -331,7 +331,7 @@ subroutine(fx_stage_sub) vec4 fx_11(vec2 vUV, sampler2D previous, sampler2D feed
float angle = magic(f3, b3, seed + 30); float angle = magic(f3, b3, seed + 30);
// logic // logic
vec3 c0 = texture(previous, uv0).xyz; vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1; vec2 uv2 = uv1;
@@ -363,7 +363,7 @@ subroutine(fx_stage_sub) vec4 fx_12(vec2 vUV, sampler2D previous, sampler2D feed
float fb = magic(f3, b3, seed + 30); float fb = magic(f3, b3, seed + 30);
// logic // logic
vec3 c0 = texture(previous, uv0).xyz; vec3 c0 = texture(previous, uv0).xyz;
vec2 uv2 = uv1; vec2 uv2 = uv1;
@@ -452,7 +452,7 @@ subroutine(fx_stage_sub) vec4 fx_12(vec2 vUV, sampler2D previous, sampler2D feed
} else if (rule == 11) { // B4678/S35678 (Anneal) } else if (rule == 11) { // B4678/S35678 (Anneal)
alive = n >= 6 || !alive && n == 4 || alive && (n == 3 || n == 5); alive = n >= 6 || !alive && n == 4 || alive && (n == 3 || n == 5);
} }
vec3 cout = vec3(alive ? 1 : 0); vec3 cout = vec3(alive ? 1 : 0);
return fx_master(c0, cout, seed, m0); return fx_master(c0, cout, seed, m0);
@@ -559,4 +559,4 @@ subroutine(fx_stage_sub) vec4 fx_15(vec2 vUV, sampler2D previous, sampler2D feed
} }
} }
#endif #endif
+6 -8
View File
@@ -3,13 +3,11 @@
#ifndef INC_MAGIC #ifndef INC_MAGIC
#define INC_MAGIC #define INC_MAGIC
uniform int iDemo;
vec2 magic_f(vec2 F, vec3 B, float i) vec2 magic_f(vec2 F, vec3 B, float i)
{ {
return vec2( return vec2(
mix(F.x, randTime(i + 1), min(1, B.z + iDemo)), mix(F.x, randTime(i + 1), min(1, B.z)),
mix(F.y, randTime(i + 2), min(1, B.z + iDemo)) mix(F.y, randTime(i + 2), min(1, B.z))
); );
} }
@@ -21,9 +19,9 @@ vec2 magic_f(float i)
vec3 magic_b(vec3 B, float i) vec3 magic_b(vec3 B, float i)
{ {
return vec3( return vec3(
mix(B.x, step(0.2, randTime(i + 3)), min(1, B.z + iDemo)), mix(B.x, step(0.2, randTime(i + 3)), min(1, B.z)),
mix(B.y, step(0.5, randTime(i + 4)), min(1, B.z + iDemo)), mix(B.y, step(0.5, randTime(i + 4)), min(1, B.z)),
min(1, B.z + iDemo) min(1, B.z)
); );
} }
@@ -76,4 +74,4 @@ float magic_reverse(float i)
return magic_reverse(vec2(0), vec3(0, 0, 1), i); return magic_reverse(vec2(0), vec3(0, 0, 1), i);
} }
#endif #endif
+1 -1
View File
@@ -11,4 +11,4 @@ float rand(vec2 n){
return rand(n.x * 1234 + n.y * 9876); return rand(n.x * 1234 + n.y * 9876);
} }
#endif #endif
+1 -1
View File
@@ -4,4 +4,4 @@
uniform vec2 iResolution; uniform vec2 iResolution;
uniform vec2 iTexResolution; uniform vec2 iTexResolution;
#endif #endif
+1 -1
View File
@@ -26,4 +26,4 @@ const int sentences[SENTENCE_COUNT][20] = {
const int lengths[SENTENCE_COUNT] = { const int lengths[SENTENCE_COUNT] = {
5, 5, 10, 6, 2, 9, 10, 7, 18, 14, 4, 9, 10, 1, 6, 11, 11 5, 5, 10, 6, 2, 9, 10, 7, 18, 14, 4, 9, 10, 1, 6, 11, 11
}; };
#endif #endif
+166 -75
View File
@@ -5,9 +5,11 @@
#ifndef INC_SRC #ifndef INC_SRC
#define INC_SRC #define INC_SRC
uniform int iDemo;
uniform sampler2D iTex0; uniform sampler2D iTex0;
uniform sampler2D iTex3; uniform sampler2D iTex5;
uniform sampler2D iTex4; uniform sampler2D iTex6;
subroutine vec4 src_stage_sub(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3); subroutine vec4 src_stage_sub(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3);
@@ -15,7 +17,7 @@ vec4 src_thru(vec2 vUV, sampler2D tex, int seed, vec3 b1, vec2 f1, vec3 b2, vec2
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
// controls // controls
@@ -34,21 +36,21 @@ vec4 src_thru(vec2 vUV, sampler2D tex, int seed, vec3 b1, vec2 f1, vec3 b2, vec2
// output // output
return vec4(c, 1.); return vec4(c, 1.);
} }
// SRC 1: feedback + thru // SRC 1: feedback + thru
subroutine(src_stage_sub) vec4 src_1(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_1(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
return src_thru(vUV, iTex0, seed, b1, f1, b2, f2, b3, f3); return src_thru(vUV, iTex0, seed, b1, f1, b2, f2, b3, f3);
} }
// SRC 2 : lines // SRC 2 : lines
subroutine(src_stage_sub) vec4 src_2(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_2(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -66,16 +68,16 @@ subroutine(src_stage_sub) vec4 src_2(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
float k = thickness * 2; float k = thickness * 2;
uv2.y = cmod(uv2.y, k * 2 + 0.1); uv2.y = cmod(uv2.y, k * 2 + 0.1);
float f = istep(k * 0.125 + 0.05, uv2.y) * istep(k * 0.125 + 0.01, -uv2.y); float f = istep(k * 0.125 + 0.05, uv2.y) * istep(k * 0.125 + 0.01, -uv2.y);
return vec4(f); return vec4(f);
} }
// SRC 3 : dots // SRC 3 : dots
subroutine(src_stage_sub) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -95,59 +97,148 @@ subroutine(src_stage_sub) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
float k = zoom * 0.1 + 0.05; float k = zoom * 0.1 + 0.05;
uv2 = cmod(uv2, k * 2); uv2 = cmod(uv2, k * 2);
float f = istep(k / (1 + length(uv1) * 2), length(uv2)); float f = istep(k / (1 + length(uv1) * 2), length(uv2));
return vec4(f); return vec4(f);
} }
// SRC 4 : waves // SRC 4 : circuit
subroutine(src_stage_sub) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
// controls // controls
float spacing = magic(f1, b1, seed + 10); float z = 10 + magic(f1, b1, 123) * 20;
float thickness = magic(f2, b2, seed + 20); float h = magic(f2, b2, seed + 20) * 0.8 + 0.1;
float scroll = magic_reverse(f3, b3, seed + 30); float v = magic_reverse(f3, b3, seed + 30) * 0.8 + 0.1;
// logic // logic
vec2 uv2 = uv1; uv1 *= z;
uv2.y += 0.5; uv1 += iBeats;
uv2 *= 2.25;
uv2 = vec2((uv2.x + 1) * 0.5, -uv2.y); float s0 = rand(floor(mod(uv1, 1000))) * 1000;
float m1 = spacing * 4.5 + 0.5; float s1 = rand(floor(mod(uv1 + vec2(0, 1), 1000))) * 1000;
float y = log(-uv2.y) * m1; float s2 = rand(floor(mod(uv1 - vec2(1, 0), 1000))) * 1000;
y = mod(y + scroll * 5.0 - iBeats / 16, 5.);
float id = floor(y) * 32; bool up = rand(s1 + 1) < h;
float s = cos(uv2.x * rand(id + 837) * 100 + rand(id + 281) * PI) bool left = rand(s2 + 2) < v;
+ cos(uv2.x * rand(id + 231) * 100 + rand(id + 526) * PI) bool down = rand(s0 + 1) < h;
+ cos(uv2.x * rand(id + 746) * 100 + rand(id + 621) * PI) bool right = rand(s0 + 2) < v;
+ cos(uv2.x * rand(id + 235) * 100 + rand(id + 315) * PI) bool up_down = up && down;
+ cos(uv2.x * rand(id + 782) * 100 + rand(id + 314) * PI) bool left_right = left && right;
+ cos(uv2.x * rand(id + 241) * 100 + rand(id + 734) * PI)
+ cos(uv2.x * rand(id + 416) * 100 + rand(id + 425) * PI) uv1 = mod(uv1, 1.0) - 0.5;
+ cos(uv2.x * rand(id + 315) * 100 + rand(id + 525) * PI)
+ cos(uv2.x * rand(id + 423) * 100 + rand(id + 743) * PI) const float t = 0.1;
+ cos(uv2.x * rand(id + 637) * 100 + rand(id + 245) * PI);
s *= 0.1; float f = 0;
float cut = 0.025 + thickness * 0.475; int c = 0;
float y2 = min(1.0, -(uv2.y));
float f = (0.1 + 0.9 * (cos((y2 + 1.0) * PI) * 0.5 + 0.5)) * istep(0, uv2.y) * istep(cut, fract(y + (s - 1) * (1 - cut) * 0.5)); if (up) {
f += stripe(uv1.x, -t * 0.5, t * 0.5) * step(-t * 0.5, uv1.y);
c += 1;
}
if (down) {
f += stripe(uv1.x, -t * 0.5, t * 0.5) * istep(t * 0.5, uv1.y);
c += 1;
}
if (left) {
f += stripe(uv1.y, -t * 0.5, t * 0.5) * istep(t * 0.5, uv1.x);
c += 1;
}
if (right) {
f += stripe(uv1.y, -t * 0.5, t * 0.5) * step(-t * 0.5, uv1.x);
c += 1;
}
if (c == 1) {
f += istep(t, length(uv1));
}
f = min(f, 1);
if ((up_down ^^ left_right) && c == 2) {
if (up_down) {
uv1.xy = uv1.yx;
}
if (rand(s0 + 3) < 0.5) {
uv1.x = -uv1.x;
}
float k = rand(s0 + 4) * 60;
f -= rect(uv1, vec2(0), vec2(t * 3, t));
f = max(0, f);
if (k < 10) { // resistor
f += line(uv1, vec2(-t * 3.25, -t * 0.5), vec2(-t * 2.5, t * 2), t * 0.75);
f += line(uv1, vec2(-t * 2.5, t * 2), vec2(-t * 1.5, -t * 2), t * 0.75);
f += line(uv1, vec2(-t * 1.5, -t * 2), vec2(-t * 0.5, t * 2), t * 0.75);
f += line(uv1, vec2(-t * 0.5, t * 2), vec2(t * 0.5, -t * 2), t * 0.75);
f += line(uv1, vec2(t * 0.5, -t * 2), vec2(t * 1.5, t * 2), t * 0.75);
f += line(uv1, vec2(t * 1.5, t * 2), vec2(t * 2.5, -t * 2), t * 0.75);
f += line(uv1, vec2(t * 2.5, -t * 2), vec2(t * 3.25, t * 0.5), t * 0.75);
} else if (k < 20) { // capacitor
f += rect(uv1, vec2(-t * 2, 0), vec2(t, t * 0.5));
f += rect(uv1, vec2(t * 2, 0), vec2(t, t * 0.5));
f += rect(uv1, vec2(t, 0), vec2(t * 0.5, t * 3.5));
f += rect(uv1, vec2(-t, 0), vec2(t * 0.5, t * 3.5));
} else if (k < 30) { // diode
f += line(uv1, vec2(-t * 2, t * 2.5), vec2(t * 2, 0), t);
f += line(uv1, vec2(-t * 2, -t * 2.5), vec2(t * 2, 0), t);
f += rect(uv1, vec2(t * 2.5, 0), vec2(t * 0.5, t * 3));
f += rect(uv1, vec2(-t * 2.5, 0), vec2(t * 0.5, t * 3));
} else if (k < 40) { // lamp
f += istep(t * 3.5, length(uv1));
f -= istep(t * 2.5, length(uv1));
f += line(uv1, vec2(-t * 2), vec2(t * 2), t);
f += line(uv1, vec2(-t * 2, t * 2), vec2(t * 2, -t * 2), t);
} else if (k < 50) { // inductor
f += istep(t * 2, length(uv1 - vec2(t * 2.5, 0)));
f += istep(t * 2, length(uv1 - vec2(0, 0)));
f += istep(t * 2, length(uv1 - vec2(-t * 2.5, 0)));
f -= 2 * istep(t, length(uv1 - vec2(t * 2.5, 0)));
f -= 2 * istep(t, length(uv1 - vec2(0, 0)));
f -= 2 * istep(t, length(uv1 - vec2(-t * 2.5, 0)));
f *= step(-t * 0.5, uv1.y);
} else if (k < 60) { // switch
f += istep(t, length(uv1 - vec2(t * 2.5, 0)));
f += istep(t, length(uv1 + vec2(t * 2.5, 0)));
f += line(uv1, vec2(t * 2, 0), vec2(-t * 2.5, t * (k < 55 ? 3 : 1)), t);
}
} else if (c == 3) {
if (left_right) {
uv1.xy = uv1.yx;
if (up) {
uv1.x = -uv1.x;
}
} else if (right) {
uv1.x = -uv1.x;
}
float k = rand(s0 + 4) * 20;
if (k < 10) {
f -= rect(uv1, vec2(0), vec2(t * 3));
f = max(0, f);
f += rect(uv1, vec2(-t * 3, 0), vec2(t * 0.5, t * 3));
f += line(uv1, vec2(t * 0.25, t * 3.25), vec2(-t * 3, t), t);
f += line(uv1, vec2(t * 0.25, -t * 3.25), vec2(-t * 3, -t), t);
}
}
return vec4(f); return vec4(f);
} }
// SRC 5 : noise // SRC 5 : noise
subroutine(src_stage_sub) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -168,28 +259,28 @@ subroutine(src_stage_sub) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
f = sin(f * PI * (details * 20)) * 0.5 + 1; f = sin(f * PI * (details * 20)) * 0.5 + 1;
int nf = int(noise_factor * 6); int nf = int(noise_factor * 6);
f *= mix(1, noise_f(uv2, nf - 1), step(0.0, float(nf))); f *= mix(1, noise_f(uv2, nf - 1), step(0.0, float(nf)));
return vec4(f); return vec4(f);
} }
// SRC 6 : video in 1 + thru // SRC 6 : video in 1 + thru
subroutine(src_stage_sub) vec4 src_6(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_6(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
if (iDemo > 0) { if (iDemo > 0) {
return src_2(vUV, seed, b1, f1, b2, f2, b3, f3); return src_2(vUV, seed, b1, f1, b2, f2, b3, f3);
} }
return src_thru(vUV, iTex3, seed, b1, f1, b2, f2, b3, f3); return src_thru(vUV, iTex5, seed, b1, f1, b2, f2, b3, f3);
} }
#include inc_cp437.glsl #include inc_cp437.glsl
// SRC 7 : cp437 // SRC 7 : cp437
subroutine(src_stage_sub) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -213,7 +304,7 @@ subroutine(src_stage_sub) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
int code = ((charset_ctrl.y < 1 || (uv2i.x % 2 ^ uv2i.y % 2) > 0) ? 1 : 0) * (start_char + int((rand(uv2i) + char_delta) * char_span) % char_span); int code = ((charset_ctrl.y < 1 || (uv2i.x % 2 ^ uv2i.y % 2) > 0) ? 1 : 0) * (start_char + int((rand(uv2i) + char_delta) * char_span) % char_span);
uv2 = mod(uv2, 1); uv2 = mod(uv2, 1);
float f = char(uv2, code) ? 1 : 0; float f = char(uv2, code) ? 1 : 0;
return vec4(f); return vec4(f);
} }
@@ -221,11 +312,11 @@ subroutine(src_stage_sub) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
#include inc_sentences.glsl #include inc_sentences.glsl
subroutine(src_stage_sub) vec4 src_8(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_8(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -245,16 +336,16 @@ subroutine(src_stage_sub) vec4 src_8(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
uv2.x += floor(uv2.y) * (h_delta - 0.5) * 2; uv2.x += floor(uv2.y) * (h_delta - 0.5) * 2;
uv2.y = mix(uv2.y, mod(uv2.y, 1), h_delta_b.x); uv2.y = mix(uv2.y, mod(uv2.y, 1), h_delta_b.x);
float f = write_20(uv2, vec2(-float(lengths[s]) * 0.5, 0), sentences[s]); float f = write_20(uv2, vec2(-float(lengths[s]) * 0.5, 0), sentences[s]);
return vec4(f); return vec4(f);
} }
// SRC 9 : sentences repeat // SRC 9 : sentences repeat
subroutine(src_stage_sub) vec4 src_9(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_9(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -285,11 +376,11 @@ subroutine(src_stage_sub) vec4 src_9(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
} }
// SRC 10 : isometric grid // SRC 10 : isometric grid
subroutine(src_stage_sub) vec4 src_10(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_10(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -317,7 +408,7 @@ subroutine(src_stage_sub) vec4 src_10(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
vec2 u2 = mod(floor(uv3 + vec2(0, 1)), umax); vec2 u2 = mod(floor(uv3 + vec2(0, 1)), umax);
vec2 u3 = mod(floor(uv3 + vec2(-1, 0)), umax); vec2 u3 = mod(floor(uv3 + vec2(-1, 0)), umax);
vec2 u4 = mod(floor(uv3 + vec2(0, -1)), umax); vec2 u4 = mod(floor(uv3 + vec2(0, -1)), umax);
float e0 = (rand(floor(u0)) * 2 - 1) * max_elevation; float e0 = (rand(floor(u0)) * 2 - 1) * max_elevation;
float e1 = (rand(floor(u1)) * 2 - 1) * max_elevation; float e1 = (rand(floor(u1)) * 2 - 1) * max_elevation;
float e2 = (rand(floor(u2)) * 2 - 1) * max_elevation; float e2 = (rand(floor(u2)) * 2 - 1) * max_elevation;
@@ -329,29 +420,29 @@ subroutine(src_stage_sub) vec4 src_10(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
float f = 0; float f = 0;
f = line(uv3, vec2(0, 0) - iso_z(e0), vec2(1, 0) - iso_z(e1), thick) f = line(uv3, vec2(0, 0) - iso_z(e0), vec2(1, 0) - iso_z(e1), thick)
+ line(uv3, vec2(0, 0) - iso_z(e0), vec2(0, 1) - iso_z(e2), thick) + line(uv3, vec2(0, 0) - iso_z(e0), vec2(0, 1) - iso_z(e2), thick)
+ line(uv3, vec2(0, 0) - iso_z(e0), vec2(-1, 0) - iso_z(e3), thick) + line(uv3, vec2(0, 0) - iso_z(e0), vec2(-1, 0) - iso_z(e3), thick)
+ line(uv3, vec2(0, 0) - iso_z(e0), vec2(0, -1) - iso_z(e4), thick); + line(uv3, vec2(0, 0) - iso_z(e0), vec2(0, -1) - iso_z(e4), thick);
return vec4(f); return vec4(f);
} }
// SRC 11 : video in 2 + thru // SRC 11 : video in 2 + thru
subroutine(src_stage_sub) vec4 src_11(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_11(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
if (iDemo > 0) { if (iDemo > 0) {
return src_3(vUV, seed, b1, f1, b2, f2, b3, f3); return src_3(vUV, seed, b1, f1, b2, f2, b3, f3);
} }
return src_thru(vUV, iTex4, seed, b1, f1, b2, f2, b3, f3); return src_thru(vUV, iTex6, seed, b1, f1, b2, f2, b3, f3);
} }
// SRC 12 : Scales // SRC 12 : Scales
subroutine(src_stage_sub) vec4 src_12(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_12(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -390,11 +481,11 @@ subroutine(src_stage_sub) vec4 src_12(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
} }
// SRC 13 : Credenza // SRC 13 : Credenza
subroutine(src_stage_sub) vec4 src_13(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_13(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -409,7 +500,7 @@ subroutine(src_stage_sub) vec4 src_13(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
vec2 uv2 = uv1; vec2 uv2 = uv1;
uv2 *= zoom; uv2 *= zoom;
uv2 = mod(uv2, 2); uv2 = mod(uv2, 2);
uv2 = abs(uv2 - 1); uv2 = abs(uv2 - 1);
@@ -417,16 +508,16 @@ subroutine(src_stage_sub) vec4 src_13(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
float f = istep(1, length(uv2)) * istep(1, length(1 - uv2)); float f = istep(1, length(uv2)) * istep(1, length(1 - uv2));
f *= istep(0.5, saw((length(uv2) + shape + 0.5) * repeat)) * istep(0.5, saw((length(1 - uv2) + shape + 0.5) * repeat)); f *= istep(0.5, saw((length(uv2) + shape + 0.5) * repeat)) * istep(0.5, saw((length(1 - uv2) + shape + 0.5) * repeat));
return vec4(f); return vec4(f);
} }
// SRC 14 : Cursor // SRC 14 : Cursor
subroutine(src_stage_sub) vec4 src_14(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_14(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
// start // start
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
@@ -460,15 +551,15 @@ subroutine(src_stage_sub) vec4 src_14(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
uv2.y += 0.1; uv2.y += 0.1;
f -= istep(0, (uv2.x + uv2.y * 3) * (uv2.x - uv2.y * 3)) * istep(0, uv2.y); f -= istep(0, (uv2.x + uv2.y * 3) * (uv2.x - uv2.y * 3)) * istep(0, uv2.y);
f += rect(uv2, vec2(0, -0.04), vec2(0.01, 0.04)); f += rect(uv2, vec2(0, -0.04), vec2(0.01, 0.04));
return vec4(f); return vec4(f);
} }
// SRC 15 : Random // SRC 15 : Random
subroutine(src_stage_sub) vec4 src_15(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3) subroutine ( src_stage_sub ) vec4 src_15(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{ {
int src = int(randTime(seed + 100) * 14); int src = int(randTime(seed + 100) * 14);
@@ -503,4 +594,4 @@ subroutine(src_stage_sub) vec4 src_15(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3
} }
} }
#endif #endif
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef INC_TEMPLATE #ifndef INC_TEMPLATE
#define INC_TEMPLATE #define INC_TEMPLATE
#endif #endif
+1 -1
View File
@@ -50,4 +50,4 @@ float cosTime(float k)
return cos(modTime(k, 0.5) * 2 * PI); return cos(modTime(k, 0.5) * 2 * PI);
} }
#endif #endif
@@ -1,13 +1,13 @@
#ifndef INC_YUV #ifndef INC_YUYV
#define INC_YUV #define INC_YUYV
const int YUYV_FOURCC = 1448695129; const int YUYV_FOURCC = 1448695129;
const mat3x3 yuv_to_rgb = {{1,1,1},{0,-0.39465,2.03211},{1.13983,-0.5806,0}}; const mat3x3 yuyv_to_rgb = {{1,1,1},{0,-0.39465,2.03211},{1.13983,-0.5806,0}};
vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) { vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) {
float w = base_width - 1; float w = base_width - 1;
int x = int(vUV.x * w); int x = int(vUV.x * w);
int xU = x - x % 2; int xU = x - x % 2;
@@ -22,7 +22,7 @@ vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) {
tV.y - 0.5 tV.y - 0.5
); );
return vec4(yuv_to_rgb * yuv, 1.0); return vec4(yuyv_to_rgb * yuv, 1.0);
} }
#endif #endif
+54 -50
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

-2
View File
@@ -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
-1
View File
@@ -10,7 +10,6 @@ uniform float iTempo; // current tempo in bpm
uniform float iBeats; // elapsed beats since last tempo reset uniform float iBeats; // elapsed beats since last tempo reset
uniform int iFPS; // output window frames per seconds uniform int iFPS; // output window frames per seconds
uniform int iDemo; // 0/1 if demo mode uniform int iDemo; // 0/1 if demo mode
uniform int iAutoRand; // 0/1 if auto random mode
uniform int iSeed1; // a random seed assigned at start uniform int iSeed1; // a random seed assigned at start
uniform vec2 iResolution; // output window resolution in pixels uniform vec2 iResolution; // output window resolution in pixels
uniform vec3 iMidi1_1[20]; // all midi inputs defined uniform vec3 iMidi1_1[20]; // all midi inputs defined
+91 -61
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,61 +12,68 @@
#include "string.h" #include "string.h"
static void print_help(int status_code) { static void print_help(int status_code) {
puts(PACKAGE puts(
" " VERSION "\n\n" PACKAGE
"usage: " PACKAGE " " " " VERSION "\n\n"
"[-h] " "usage: " PACKAGE " "
"[-v] " "[-h] "
"[-p=PROJECT_PATH] " "[-v] "
"[-c=CFG_FILE] " "[-p=PROJECT_PATH] "
"[-hr] " "[-c=CFG_FILE] "
"[-s=SCREEN] " "[-hr] "
"[-m=SCREEN] " "[-s=SCREEN] "
"[-mo] " "[-m=SCREEN] "
"[-w] " "[-mo] "
"[-t=TEMPO] " "[-w] "
"[-d] " "[-t=TEMPO] "
"[-ar / -nar] " "[-d] "
"[-v=FILE] " "[-ar / -nar] "
"[-vs=SIZE] " "[-arc=CYCLES] "
"[-is=SIZE] " #ifdef VIDEO_IN
"[-sf=STATE_PATH] " "[-vi=FILE] "
"[-ls / -nls] " "[-vs=SIZE] "
"[-ss / -nss] " "[-vr / -nvr] "
"[-tm] " #endif /* VIDEO_IN */
"[-tf] " "[-is=SIZE] "
"\n\n" "[-ls / -nls] "
"Fusion Of Real-time Generative Effects.\n\n" "[-ss / -nss] "
"options:\n" "[-tm] "
" -h, --help show this help message and exit\n" "[-tf] "
" -v, --version print version\n" "\n\n"
" -p, --project forge project directory (default: " DATADIR "Fusion Of Real-time Generative Effects.\n\n"
"/default)\n" "options:\n"
" -c, --config config file name (default: " " -h, --help show this help message and exit\n"
"forge_project.cfg)\n" " -v, --version print version\n"
" -hr, --hot-reload hot reload of shaders scripts\n" " -p, --project forge project directory (default: " DATADIR
" -s, --screen output screen number (default: primary)\n" "/default)\n"
" -m, --monitor monitor screen number (default: none)\n" " -c, --config config file name (default: "
" -mo, --monitor-only no output screen\n" "forge_project.cfg)\n"
" -w, --windowed not fullscreen\n" " -hr, --hot-reload hot reload of shaders scripts\n"
" -t, --tempo base tempo (default: 60)\n" " -s, --screen output screen number (default: primary)\n"
" -d, --demo demonstration mode (assume " " -m, --monitor monitor screen number (default: none)\n"
"--no-save-state, --no-load-state, --auto-random)\n" " -mo, --monitor-only no output screen\n"
" -ar, --auto-random randomize state every 4 beats\n" " -w, --windowed not fullscreen\n"
" -nar, --no-auto-random do not randomize state (default)\n" " -t, --tempo base tempo (default: 60)\n"
" -v, --video-in path to video capture device (multiple " " -d, --demo demonstration mode (assume "
"allowed)\n" "--no-save-state, --no-load-state, --auto-random)\n"
" -vs, --video-size video capture desired height (default: " " -ar, --auto-random randomize state every cycle (4 beats)\n"
"internal texture height)\n" " -nar, --no-auto-random do not randomize state (default)\n"
" -is, --internal-size internal texture height (default: 720)\n" " -arc, --auto-random-cycle auto random cycle length (default: 4)\n"
" -sf, --state-file saved state file (default: " #ifdef VIDEO_IN
"forge_saved_state.txt)\n" " -vi, --video-in path to video capture device (multiple "
" -ls, --load-state load saved state (default)\n" "allowed)\n"
" -nls, --no-load-state do not load saved state\n" " -vs, --video-size video capture desired height (default: "
" -ss, --save-state save state (default)\n" "internal texture height)\n"
" -nss, --no-save-state do not save state\n" " -vr, --video-reconnect auto-reconnect video (default)\n"
" -tm, --trace-midi print midi code and values\n" " -nvr, --no-video-reconnect do not auto-reconnect video\n"
" -tf, --trace-fps print fps status of subsystems\n"); #endif /* VIDEO_IN */
" -is, --internal-size internal texture height (default: 720)\n"
" -ls, --load-state load saved state (default)\n"
" -nls, --no-load-state do not load saved state\n"
" -ss, --save-state save state (default)\n"
" -nss, --no-save-state do not save state\n"
" -tm, --trace-midi print midi code and values\n"
" -tf, --trace-fps print fps status of subsystems\n");
exit(status_code); exit(status_code);
} }
@@ -124,10 +130,11 @@ void args_parse(Parameters *params, int argc, char **argv) {
params->base_tempo = 60.0f; params->base_tempo = 60.0f;
params->demo = false; params->demo = false;
params->auto_random = false; params->auto_random = false;
params->auto_random_cycle = 4;
params->video_in.length = 0; params->video_in.length = 0;
params->video_size = 0; params->video_size = 0;
params->video_reconnect = true;
params->internal_size = 720; params->internal_size = 720;
strlcpy(params->state_file, "forge_saved_state.txt", STR_LEN);
params->load_state = true; params->load_state = true;
params->save_state = true; params->save_state = true;
params->trace_midi = false; params->trace_midi = false;
@@ -168,25 +175,48 @@ void args_parse(Parameters *params, int argc, char **argv) {
params->auto_random = true; params->auto_random = true;
} else if (is_arg(arg, "-nar") || is_arg(arg, "--no-auto-random")) { } else if (is_arg(arg, "-nar") || is_arg(arg, "--no-auto-random")) {
params->auto_random = false; params->auto_random = false;
} else if (is_arg(arg, "-v") || is_arg(arg, "--video-in")) { } else if (is_arg(arg, "-arc") || is_arg(arg, "--auto-random-cycle")) {
params->auto_random_cycle = parse_uint(arg, value);
if (params->auto_random_cycle == 0) {
invalid_value(arg, value);
}
} else if (is_arg(arg, "-vi") || is_arg(arg, "--video-in")) {
#ifdef VIDEO_IN
if (params->video_in.length == MAX_VIDEO) { if (params->video_in.length == MAX_VIDEO) {
log_error("maximum video input reached"); log_error("maximum video input reached");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
strlcpy(params->video_in.values[params->video_in.length++], value, strlcpy(params->video_in.values[params->video_in.length++], value,
STR_LEN); STR_LEN);
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
} else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) { } else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) {
#ifdef VIDEO_IN
params->video_size = parse_uint(arg, value); params->video_size = parse_uint(arg, value);
if (params->video_size == 0) { if (params->video_size == 0) {
invalid_value(arg, value); invalid_value(arg, value);
} }
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
} else if (is_arg(arg, "-vr") || is_arg(arg, "--video-reconnect")) {
#ifdef VIDEO_IN
params->video_reconnect = true;
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
} else if (is_arg(arg, "-nvr") || is_arg(arg, "--no-video-reconnect")) {
#ifdef VIDEO_IN
params->video_reconnect = false;
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
} else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) { } else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) {
params->internal_size = parse_uint(arg, value); params->internal_size = parse_uint(arg, value);
if (params->internal_size == 0) { if (params->internal_size == 0) {
invalid_value(arg, value); invalid_value(arg, value);
} }
} else if (is_arg(arg, "-sf") || is_arg(arg, "--state-file")) {
strlcpy(params->state_file, value, STR_LEN);
} else if (is_arg(arg, "-ls") || is_arg(arg, "--load-state")) { } else if (is_arg(arg, "-ls") || is_arg(arg, "--load-state")) {
params->load_state = true; params->load_state = true;
} else if (is_arg(arg, "-nls") || is_arg(arg, "--no-load-state")) { } else if (is_arg(arg, "-nls") || is_arg(arg, "--no-load-state")) {
@@ -213,4 +243,4 @@ void args_parse(Parameters *params, int argc, char **argv) {
if (params->video_size == 0) { if (params->video_size == 0) {
params->video_size = params->internal_size; params->video_size = params->internal_size;
} }
} }
+1 -1
View File
@@ -5,4 +5,4 @@
void args_parse(Parameters *params, int argc, char **argv); void args_parse(Parameters *params, int argc, char **argv);
#endif /* ARGS_H */ #endif /* ARGS_H */
+1 -1
View File
@@ -7,4 +7,4 @@ unsigned int arr_uint_index_of(UintArray array, unsigned int value);
unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index); unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index);
#endif /* ARR_H */ #endif /* ARR_H */
+1 -1
View File
@@ -87,4 +87,4 @@
#define MAX_TAP_VALUES 10 #define MAX_TAP_VALUES 10
#endif #endif
#endif /* CONFIG_H */ #endif /* CONFIG_H */
+15 -2
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>
@@ -75,9 +74,12 @@ void config_file_read(ConfigFile *config, const char *path) {
file_read(&file, path); file_read(&file, path);
if (file.error) { if (file.error) {
config->error = true;
return; return;
} }
config->error = false;
line = strtok_r(file.content, "\n", &rest); line = strtok_r(file.content, "\n", &rest);
while (line != NULL) { while (line != NULL) {
@@ -88,6 +90,17 @@ void config_file_read(ConfigFile *config, const char *path) {
file_free(&file); file_free(&file);
} }
bool config_file_has(const ConfigFile *config, const char *key) {
ConfigFileItem c_key;
const ConfigFileItem *item;
strlcpy(c_key.key, key, STR_LEN);
item = (const ConfigFileItem *)hashmap_get(config->map, &c_key);
return item != NULL && strnlen(item->value, STR_LEN) > 0;
}
const char *config_file_get_str(const ConfigFile *config, const char *key, const char *config_file_get_str(const ConfigFile *config, const char *key,
const char *default_value) { const char *default_value) {
ConfigFileItem c_key; ConfigFileItem c_key;
@@ -125,4 +138,4 @@ unsigned int config_file_get_int(const ConfigFile *config, const char *key,
return (unsigned int)atoi(item->value); return (unsigned int)atoi(item->value);
} }
void config_file_free(const ConfigFile *config) { hashmap_free(config->map); } void config_file_free(const ConfigFile *config) { hashmap_free(config->map); }
+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);
-2
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;
+1 -1
View File
@@ -15,4 +15,4 @@ void file_dump(const char *path, const char *content);
void file_free(const File *file); void file_free(const File *file);
#endif /* FILE_H */ #endif /* FILE_H */
+209 -140
View File
@@ -4,13 +4,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/wait.h> #include <unistd.h>
#include "types.h" #include "types.h"
#include "config.h" #include "config.h"
#include "config_file.h" #include "config_file.h"
#include "file.h"
#include "forge.h" #include "forge.h"
#include "midi.h" #include "midi.h"
#include "project.h" #include "project.h"
@@ -22,24 +21,24 @@
#include "video.h" #include "video.h"
#include "window.h" #include "window.h"
static Parameters init_params;
static SharedContext *context; static SharedContext *context;
static ShaderProgram program; static ShaderProgram program;
static Window *window_output; static Window *window_output;
static Window *window_monitor; static Window *window_monitor;
static VideoCaptureArray inputs;
static Timer timer; static Timer timer;
static MidiDevice midi; static MidiDevice midi;
static bool trace_midi; static bool trace_midi;
static Project project; static Project project;
static void compute_fps(bool trace_fps) { static void compute_fps() {
double fps; double fps;
char title[STR_LEN]; char title[STR_LEN];
if (timer_inc(&timer)) { if (timer_inc(&timer)) {
fps = timer_reset(&timer); fps = timer_reset(&timer);
if (trace_fps) { if (init_params.trace_fps) {
log_trace("(main) %.2ffps", fps); log_trace("(main) %.2ffps", fps);
} }
@@ -57,23 +56,16 @@ static void compute_fps(bool trace_fps) {
} }
} }
static void init_context(const Parameters *params, unsigned int in_count) { static void init_context() {
state_init(context, &project.state_config, params->demo, params->auto_random, context = shared_init_context("/" PACKAGE "_context");
params->base_tempo, params->state_file, params->load_state);
context->monitor = params->monitor; context->stop = false;
state_init(context, &project.state_config, init_params.demo,
init_params.auto_random, init_params.auto_random_cycle,
init_params.base_tempo, init_params.load_state);
memset(context->input_resolutions, 0, sizeof(context->input_resolutions)); memset(context->input_resolutions, 0, sizeof(context->input_resolutions));
memset(context->input_formats, 0, sizeof(context->input_formats));
memset(context->input_fps, 0, sizeof(context->input_fps));
for (unsigned int i = 0; i < in_count; i++) {
if (!inputs.values[i].error) {
context->input_resolutions[i][0] = inputs.values[i].width;
context->input_resolutions[i][1] = inputs.values[i].height;
context->input_formats[i] = inputs.values[i].pixelformat;
}
}
} }
static void free_context() { shared_close_context(context); } static void free_context() { shared_close_context(context); }
@@ -82,33 +74,86 @@ static void reload_shader(unsigned int i) {
shaders_update(&program, &project.fragment_shaders[i][0], i, &project); shaders_update(&program, &project.fragment_shaders[i][0], i, &project);
} }
static void init_inputs(const StringArray *video_in, unsigned int video_size) { #ifdef VIDEO_IN
inputs.length = video_in->length; static void init_inputs() {
context->inputs.length = init_params.video_in.length;
for (unsigned int i = 0; i < video_in->length; i++) { for (unsigned int i = 0; i < init_params.video_in.length; i++) {
video_init(&inputs.values[i], video_in->values[i], video_size); video_init(&context->inputs.values[i], init_params.video_in.values[i],
init_params.video_size);
if (!context->inputs.values[i].error) {
context->input_resolutions[i][0] = context->inputs.values[i].width;
context->input_resolutions[i][1] = context->inputs.values[i].height;
context->inputs.values[i].needs_reload = false;
context->inputs.values[i].disconnected = false;
}
} }
} }
static bool start_video_captures(unsigned int video_count, bool trace_fps) { static bool reconnect_video_captures() {
for (unsigned int i = 0; i < video_count; i++) { for (unsigned int i = 0; i < init_params.video_in.length; i++) {
if (!inputs.values[i].error && if (context->inputs.values[i].disconnected) {
!video_background_read(&inputs.values[i], context, i, trace_fps)) { video_init(&context->inputs.values[i], init_params.video_in.values[i],
return false; init_params.video_size);
if (!context->inputs.values[i].error) {
context->input_resolutions[i][0] = context->inputs.values[i].width;
context->input_resolutions[i][1] = context->inputs.values[i].height;
if (!video_background_read(&context->inputs.values[i], context, i,
init_params.trace_fps)) {
return false;
}
context->inputs.values[i].needs_reload = true;
context->inputs.values[i].disconnected = false;
}
} }
} }
return true; return true;
} }
static void free_video_captures(unsigned int video_count) { static bool start_video_captures() {
for (unsigned int i = 0; i < video_count; i++) { pid_t pid;
shaders_free_input(&program, &inputs.values[i]); for (unsigned int i = 0; i < context->inputs.length; i++) {
if (!context->inputs.values[i].error &&
!video_background_read(&context->inputs.values[i], context, i,
init_params.trace_fps)) {
return false;
}
}
if (!init_params.video_reconnect) {
return true;
}
pid = fork();
if (pid < 0) {
log_error("Could not create subprocess");
return false;
}
if (pid == 0) {
return true;
}
log_info("background reconnect acquisition started (pid: %d)", pid);
while (!context->stop) {
sleep(1);
if (!reconnect_video_captures()) {
return false;
}
}
exit(EXIT_SUCCESS);
}
video_free(&inputs.values[i]); static void free_video_captures() {
for (unsigned int i = 0; i < context->inputs.length; i++) {
shaders_free_input(&program, i);
video_free(&context->inputs.values[i]);
} }
} }
#endif /* VIDEO_IN */
static void error_callback(int error, const char *description) { static void error_callback(int error, const char *description) {
log_error("[GLFW] %d: %s", error, description); log_error("[GLFW] %d: %s", error, description);
window_terminate(); window_terminate();
@@ -118,44 +163,126 @@ static void error_callback(int error, const char *description) {
static void key_callback(Window *window, int key, static void key_callback(Window *window, int key,
__attribute__((unused)) int scancode, int action, __attribute__((unused)) int scancode, int action,
__attribute__((unused)) int mods) { int mods) {
unsigned int event;
event = window_read_key(key, action, mods);
if (window_escape_key(key, action)) { if (window_escape_key(key, action)) {
// close window on escape key // close window on escape key
log_info("[ESC] Closing..."); log_info("[ESC] Closing...");
window_close(window); window_close(window);
} else if (window_char_key(key, action, 82)) { } else if (event > 0) {
// R: randomize state_key_event(context, &project.state_config, event, &midi);
log_info("[R] Randomized");
state_randomize(context, &project.state_config);
state_apply(context, &project.state_config, &midi);
} else if (window_char_key(key, action, 48)) {
// 0: reset
log_info("[0] Reset");
state_reset(context);
state_apply(context, &project.state_config, &midi);
} else if (window_char_key(key, action, 68)) {
// D: demo on/off
log_info((context->demo ? "[D] Demo OFF" : "[D] Demo ON"));
context->demo = !context->demo;
} else if (window_char_key(key, action, 65)) {
// A: auto random on/off
log_info(
(context->auto_random ? "[A] Auto Random OFF" : "[A] Auto Random ON"));
context->auto_random = !context->auto_random;
} }
} }
static void midi_callback(unsigned char code, unsigned char value) { static void midi_callback(unsigned char code, unsigned char value) {
state_apply_event(context, &project.state_config, &midi, code, value, state_midi_event(context, &project.state_config, &midi, code, value,
trace_midi); trace_midi);
} }
static void loop(bool hr, bool trace_fps) { static bool init(const Parameters *params) {
if (hr) { init_params = *params;
project_init(&project, params->project_path, params->config_file);
if (project.error) {
return false;
}
init_context();
#ifdef VIDEO_IN
init_inputs();
if (!start_video_captures()) {
return false;
}
#endif /* VIDEO_IN */
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"));
if (midi.error) {
context->demo = true;
} else {
trace_midi = params->trace_midi;
if (!midi_background_listen(&midi, context, midi_callback)) {
return false;
}
}
if (!state_background_write(context, &project.state_config, &midi)) {
return false;
}
window_startup(error_callback);
context->tex_resolution[1] = params->internal_size;
if (params->output) {
window_output = window_init(PACKAGE " " VERSION, params->output_screen,
params->windowed, NULL, key_callback);
window_use(window_output, context);
shaders_init(&program, &project, context, false);
} else {
window_output = NULL;
}
if (params->monitor) {
window_monitor =
window_init(PACKAGE " " VERSION " (monitor)", params->monitor_screen,
params->windowed, window_output, key_callback);
window_use(window_monitor, context);
shaders_init(&program, &project, context, window_output != NULL);
} else {
window_monitor = NULL;
}
#ifdef VIDEO_IN
shaders_link_inputs(&program, &project, &context->inputs);
#endif /* VIDEO_IN */
if (program.error) {
context->stop = true;
window_terminate();
exit(EXIT_FAILURE);
}
timer_init(&timer, 30);
log_info("Initialized");
return true;
}
static bool should_close() {
return (window_output != NULL && window_should_close(window_output)) ||
(window_monitor != NULL && window_should_close(window_monitor));
}
static bool loop() {
if (init_params.hot_reload) {
project_reload(&project, reload_shader); project_reload(&project, reload_shader);
} }
compute_fps(trace_fps); #ifdef VIDEO_IN
if (init_params.video_reconnect) {
for (unsigned int i = 0; i < context->inputs.length; i++) {
if (context->inputs.values[i].needs_reload) {
shaders_relink_input(&program, &project, &context->inputs, i);
context->inputs.values[i].needs_reload = false;
}
}
}
#endif /* VIDEO_IN */
compute_fps();
context->time = window_get_time(); context->time = window_get_time();
context->tempo_total = (float)tempo_total(&context->tempo); context->tempo_total = (float)tempo_total(&context->tempo);
@@ -177,89 +304,15 @@ static void loop(bool hr, bool trace_fps) {
} }
window_events(); window_events();
return true;
} }
void forge_run(const Parameters *params) { static void shutdown() {
context = shared_init_context("/" PACKAGE "_context");
context->stop = false;
project_init(&project, params->project_path, params->config_file);
if (project.error) {
return;
}
init_inputs(&params->video_in, params->video_size);
init_context(params, project.in_count);
if (!start_video_captures(params->video_in.length, params->trace_fps)) {
return;
}
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"));
if (midi.error) {
context->demo = true;
} else {
trace_midi = params->trace_midi;
if (!midi_background_listen(&midi, context, midi_callback)) {
return;
}
}
if (!state_background_write(context, &project.state_config, &midi)) {
return;
}
window_startup(error_callback);
context->tex_resolution[1] = params->internal_size;
if (params->output) {
window_output = window_init(PACKAGE " " VERSION, params->output_screen,
params->windowed, NULL, key_callback);
window_use(window_output, context);
shaders_init(&program, &project, context, &inputs, false);
} else {
window_output = NULL;
}
if (params->monitor) {
window_monitor =
window_init(PACKAGE " " VERSION " (monitor)", params->monitor_screen,
params->windowed, window_output, key_callback);
window_use(window_monitor, context);
shaders_init(&program, &project, context, &inputs, window_output != NULL);
} else {
window_monitor = NULL;
}
if (program.error) {
context->stop = true;
window_terminate();
exit(EXIT_FAILURE);
}
timer_init(&timer, 30);
log_info("Initialized");
while ((window_output == NULL || !window_should_close(window_output)) &&
(window_monitor == NULL || !window_should_close(window_monitor))) {
loop(params->hot_reload, params->trace_fps);
}
context->stop = true; context->stop = true;
if (params->save_state) { if (init_params.save_state) {
state_save(context, &project.state_config, params->state_file); state_save(context, &project.state_config);
} }
shaders_free(&program); shaders_free(&program);
@@ -273,14 +326,30 @@ void forge_run(const Parameters *params) {
if (window_monitor != NULL) { if (window_monitor != NULL) {
window_use(window_monitor, context); window_use(window_monitor, context);
shaders_free_window(&program, params->output); shaders_free_window(&program, init_params.output);
} }
free_video_captures(params->video_in.length); #ifdef VIDEO_IN
free_video_captures();
#endif /* VIDEO_IN */
free_context(); free_context();
project_free(&project); project_free(&project);
window_terminate(); window_terminate();
} }
void forge_run(const Parameters *params) {
if (!init(params)) {
return;
}
while (!should_close()) {
if (!loop()) {
return;
}
}
shutdown();
}
+1 -1
View File
@@ -5,4 +5,4 @@
void forge_run(const Parameters *params); void forge_run(const Parameters *params);
#endif /* FORGE_H */ #endif /* FORGE_H */
+1 -1
View File
@@ -17,7 +17,7 @@ int main(int argc, char **argv) {
puts(PACKAGE " " VERSION); puts(PACKAGE " " VERSION);
set_seed((unsigned long)time(NULL)); rand_set_seed((unsigned long)time(NULL));
forge_run(&params); forge_run(&params);
+1 -1
View File
@@ -3,4 +3,4 @@
int main(int argc, char **argv); int main(int argc, char **argv);
#endif /* MAIN_H */ #endif /* MAIN_H */
+7 -4
View File
@@ -1,11 +1,10 @@
#include <GLFW/glfw3.h>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include <bsd/string.h> #include <log.h>
#include <stdlib.h>
#include "types.h" #include "types.h"
#include "config.h" #include "config.h"
#include "log.h"
void midi_open(MidiDevice *device, const char *name) { void midi_open(MidiDevice *device, const char *name) {
strlcpy(device->name, name, STR_LEN); strlcpy(device->name, name, STR_LEN);
@@ -21,6 +20,10 @@ void midi_open(MidiDevice *device, const char *name) {
void midi_write(const MidiDevice *device, unsigned char code, void midi_write(const MidiDevice *device, unsigned char code,
unsigned char value) { unsigned char value) {
if (device->error) {
return;
}
unsigned char buffer[3]; unsigned char buffer[3];
buffer[0] = 0xB0; buffer[0] = 0xB0;
@@ -57,5 +60,5 @@ bool midi_background_listen(const MidiDevice *device,
log_info("(%s) background acquisition stopped by main thread (pid: %d)", log_info("(%s) background acquisition stopped by main thread (pid: %d)",
device->name, pid); device->name, pid);
return false; exit(EXIT_SUCCESS);
} }
+1 -1
View File
@@ -11,4 +11,4 @@ bool midi_background_listen(const MidiDevice *device,
void (*event_callback)(unsigned char code, void (*event_callback)(unsigned char code,
unsigned char value)); unsigned char value));
#endif /* MIDI_H */ #endif /* MIDI_H */
+2 -3
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"
@@ -141,4 +140,4 @@ void project_free(const Project *project) {
} }
config_file_free(&project->config); config_file_free(&project->config);
} }
+1 -1
View File
@@ -10,4 +10,4 @@ void project_reload(Project *project, void (*reload_callback)(unsigned int));
void project_free(const Project *project); void project_free(const Project *project);
#endif /* PROJECT_H */ #endif /* PROJECT_H */
+2 -2
View File
@@ -13,11 +13,11 @@ static unsigned long rand(void) {
return (unsigned long)(x >> (22 + count)); return (unsigned long)(x >> (22 + count));
} }
void set_seed(unsigned long long seed) { void rand_set_seed(unsigned long long seed) {
mcg_state = 2 * seed + 1; mcg_state = 2 * seed + 1;
(void)rand(); (void)rand();
} }
unsigned int rand_uint(const unsigned int max) { unsigned int rand_uint(const unsigned int max) {
return max == 0 ? 0 : (unsigned int)(rand() % max); return max == 0 ? 0 : (unsigned int)(rand() % max);
} }
+2 -2
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
+368 -143
View File
@@ -14,75 +14,153 @@
#define GLAD_GL_IMPLEMENTATION #define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h> #include <glad/gl.h>
#ifdef VIDEO_IN
#define GLAD_EGL_IMPLEMENTATION #define GLAD_EGL_IMPLEMENTATION
#include <glad/egl.h> #include <glad/egl.h>
#endif /* VIDEO_IN */
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#ifdef VIDEO_IN
#include <GLFW/glfw3native.h> #include <GLFW/glfw3native.h>
#endif /* VIDEO_IN */
static const GLuint unused_uniform = (GLuint)-1; static const GLuint unused_uniform = (GLuint)-1;
bool check_glerror(ShaderProgram *program) { bool check_glerror_ro(const char *context) {
unsigned int code; unsigned int code;
code = glGetError(); code = glGetError();
if (code > 0) { if (code > 0) {
log_warn("GL Error: %04x", code); log_warn("GL Error: %04x (%s)", code, context);
program->error = true; return true;
} }
return code > 0; return false;
} }
static void init_gl(ShaderProgram *program) { bool check_glerror(ShaderProgram *program, const char *context) {
if (check_glerror_ro(context)) {
program->error = true;
return true;
}
return false;
}
bool check_eglerror_ro(const char *context) {
unsigned int code;
code = eglGetError();
if (code > 0 && code != EGL_SUCCESS) {
log_warn("EGL Error: %04x (%s)", code, context);
return true;
}
return false;
}
bool check_eglerror(ShaderProgram *program, const char *context) {
if (check_eglerror_ro(context)) {
program->error = true;
return true;
}
return false;
}
static bool init_gl(ShaderProgram *program) {
gladLoadGL(glfwGetProcAddress); gladLoadGL(glfwGetProcAddress);
#ifdef VIDEO_IN
program->egl_display = glfwGetEGLDisplay(); program->egl_display = glfwGetEGLDisplay();
if (program->egl_display == EGL_NO_DISPLAY) { if (program->egl_display == EGL_NO_DISPLAY) {
log_error("error: glfwGetEGLDisplay no EGLDisplay returned"); log_error("error: glfwGetEGLDisplay no EGLDisplay returned");
program->error = true; program->error = true;
return; return false;
} }
gladLoadEGL(program->egl_display, glfwGetProcAddress); gladLoadEGL(program->egl_display, glfwGetProcAddress);
#endif /* VIDEO_IN */
return !check_glerror(program, "init_gl") &&
!check_eglerror(program, "init_gl");
} }
static void init_textures(ShaderProgram *program, static bool init_textures(ShaderProgram *program,
const SharedContext *context) { const SharedContext *context) {
glGenTextures(program->tex_count, program->textures); glGenTextures(program->tex_count, program->textures);
if (check_glerror(program, "init_textures/glGenTextures")) {
return false;
}
for (unsigned int i = 0; i < program->tex_count; i++) { for (unsigned int i = 0; i < program->tex_count; i++) {
// selects which texture unit subsequent texture state calls will affect // selects which texture unit subsequent texture state calls will affect
glActiveTexture(GL_TEXTURE0 + i); glActiveTexture(GL_TEXTURE0 + i);
if (check_glerror(program, "init_textures/glActiveTexture")) {
return false;
}
glBindTexture(GL_TEXTURE_2D, program->textures[i]); glBindTexture(GL_TEXTURE_2D, program->textures[i]);
if (check_glerror(program, "init_textures/glBindTexture")) {
return false;
}
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND); glDisable(GL_BLEND);
if (check_glerror(program, "init_textures/glDisable")) {
return false;
}
// define texture image as empty // define texture image as empty
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0], glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0); context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
if (check_glerror(program, "init_textures/glTexImage2D")) {
return false;
}
// setup mipmap context // setup mipmap context
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
if (check_glerror(program, "init_textures/glTexParameteri")) {
return false;
}
log_info("Texture %d initialized", i); log_info("Texture %d initialized", i);
} }
return true;
} }
static void rebind_textures(const ShaderProgram *program) { static void rebind_textures(const ShaderProgram *program) {
for (unsigned int i = 0; i < program->tex_count; i++) { for (unsigned int i = 0; i < program->tex_count; i++) {
glActiveTexture(GL_TEXTURE0 + i); glActiveTexture(GL_TEXTURE0 + i);
check_glerror_ro("rebind_textures/glActiveTexture");
glBindTexture(GL_TEXTURE_2D, program->textures[i]); glBindTexture(GL_TEXTURE_2D, program->textures[i]);
check_glerror_ro("rebind_textures/glBindTexture");
} }
} }
static void link_input_to_texture(ShaderProgram *program, VideoCapture *input, #ifdef VIDEO_IN
unsigned int texture_index) { static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input,
input->dma_image = EGL_NO_IMAGE_KHR; unsigned int input_index,
unsigned int texture_index, bool swap,
bool reload) {
if (reload) {
glDeleteTextures(1, program->textures + texture_index);
if (check_glerror(program, "link_input_to_texture/glDeleteTextures")) {
return false;
}
glGenTextures(1, program->textures + texture_index);
if (check_glerror(program, "link_input_to_texture/glGenTextures")) {
return false;
}
}
EGLImageKHR dma_image;
dma_image = EGL_NO_IMAGE_KHR;
// https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt // https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
const EGLint attrib_list[] = {EGL_WIDTH, const EGLint attrib_list[] = {EGL_WIDTH,
@@ -92,57 +170,90 @@ static void link_input_to_texture(ShaderProgram *program, VideoCapture *input,
EGL_LINUX_DRM_FOURCC_EXT, EGL_LINUX_DRM_FOURCC_EXT,
input->pixelformat, input->pixelformat,
EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_FD_EXT,
input->exp_fd, swap ? input->exp_fd_swap : input->exp_fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT,
0, 0,
EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE0_PITCH_EXT,
input->bytesperline, input->bytesperline,
EGL_NONE}; EGL_NONE};
input->dma_image = dma_image = eglCreateImageKHR(program->egl_display, EGL_NO_CONTEXT,
eglCreateImageKHR(program->egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrib_list);
EGL_LINUX_DMA_BUF_EXT, NULL, attrib_list); if (check_eglerror(program, "link_input_to_texture/eglCreateImageKHR")) {
return false;
}
if (input->dma_image == EGL_NO_IMAGE_KHR) { if (swap) {
log_error("(%s) eglCreateImageKHR failed %04x", input->name, eglGetError()); program->dma_images_swap[input_index] = dma_image;
return; } else {
program->dma_images[input_index] = dma_image;
} }
glActiveTexture(GL_TEXTURE0 + texture_index); glActiveTexture(GL_TEXTURE0 + texture_index);
if (check_glerror(program, "link_input_to_texture/glActiveTexture")) {
return false;
}
glBindTexture(GL_TEXTURE_2D, program->textures[texture_index]); glBindTexture(GL_TEXTURE_2D, program->textures[texture_index]);
if (check_glerror(program, "link_input_to_texture/glBindTexture")) {
return false;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, input->width, input->height, 0, GL_RGB, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, input->width, input->height, 0, GL_RGB,
GL_UNSIGNED_BYTE, 0); GL_UNSIGNED_BYTE, 0);
if (check_glerror(program, "link_input_to_texture/glTexImage2D")) {
return false;
}
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt // https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt
glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, input->dma_image, NULL); glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, dma_image, NULL);
if (check_eglerror(program,
"link_input_to_texture/glEGLImageTargetTexStorageEXT")) {
return false;
}
log_info("Texture %d linked to %s", texture_index, input->name); log_info("Texture %d linked to %s", texture_index, input->name);
return true;
} }
static void init_input(ShaderProgram *program, const ConfigFile *config, static bool init_input(ShaderProgram *program, const ConfigFile *config,
VideoCaptureArray *inputs) { VideoCaptureArray *inputs, unsigned int i, bool reload) {
unsigned int tex_i; unsigned int tex_i;
char name[STR_LEN]; char name[STR_LEN];
for (unsigned int i = 0; i < program->in_count; i++) { if (i < inputs->length && !inputs->values[i].error) {
if (i < inputs->length && !inputs->values[i].error) { snprintf(name, STR_LEN, "IN_%d_OUT", i + 1);
snprintf(name, STR_LEN, "IN_%d_OUT", i + 1); tex_i = config_file_get_int(config, name, 0);
tex_i = config_file_get_int(config, name, 0); if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, false,
link_input_to_texture(program, &inputs->values[i], tex_i); reload)) {
} else { return false;
log_warn("Cannot link input %d", i + 1);
} }
if (inputs->values[i].with_swap) {
snprintf(name, STR_LEN, "IN_%d_SWAP_OUT", i + 1);
tex_i = config_file_get_int(config, name, 0);
if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, true,
reload)) {
return false;
}
}
} else {
log_warn("Cannot link input %d", i + 1);
} }
return true;
} }
#endif /* VIDEO_IN */
static void init_framebuffers(ShaderProgram *program, static bool init_framebuffers(ShaderProgram *program,
const ConfigFile *config) { const ConfigFile *config) {
unsigned int tex_i; unsigned int tex_i;
char name[STR_LEN]; char name[STR_LEN];
GLenum framebuffer_status;
glGenFramebuffers(program->frag_count, program->frame_buffers); glGenFramebuffers(program->frag_count, program->frame_buffers);
if (check_glerror(program, "init_framebuffers/glGenFramebuffers")) {
return false;
}
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
if (i == program->frag_output_index || i == program->frag_monitor_index) { if (i == program->frag_output_index || i == program->frag_monitor_index) {
@@ -150,48 +261,87 @@ static void init_framebuffers(ShaderProgram *program,
} }
glBindFramebuffer(GL_FRAMEBUFFER, program->frame_buffers[i]); glBindFramebuffer(GL_FRAMEBUFFER, program->frame_buffers[i]);
if (check_glerror(program, "init_framebuffers/glBindFramebuffer")) {
return false;
}
snprintf(name, STR_LEN, "FRAG_%d_OUT", i + 1); snprintf(name, STR_LEN, "FRAG_%d_OUT", i + 1);
tex_i = config_file_get_int(config, name, 0); tex_i = config_file_get_int(config, name, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
program->textures[tex_i], 0); program->textures[tex_i], 0);
if (check_glerror(program, "init_framebuffers/glFramebufferTexture2D")) {
return false;
}
// check framebuffer status // check framebuffer status
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { framebuffer_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
log_error("Framebuffer %d is KO: %x", i + 1, if (check_glerror(program, "init_framebuffers/glCheckFramebufferStatus")) {
glCheckFramebufferStatus(GL_FRAMEBUFFER)); return false;
}
if (framebuffer_status != GL_FRAMEBUFFER_COMPLETE) {
log_error("Framebuffer %d is KO: %x", i + 1, framebuffer_status);
program->error = true; program->error = true;
return false;
return;
} }
log_info("Framebuffer %d initialized", i); log_info("Framebuffer %d initialized", i);
} }
return; return true;
} }
static void init_vertices(ShaderProgram *program) { static bool init_vertices(ShaderProgram *program) {
glGenBuffers(1, &program->vertex_buffer); glGenBuffers(1, &program->vertex_buffer);
if (check_glerror(program, "init_vertices/glGenBuffers")) {
return false;
}
glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer);
if (check_glerror(program, "init_vertices/glBindBuffer")) {
return false;
}
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
if (check_glerror(program, "init_vertices/glBufferData")) {
return false;
}
return true;
} }
static void bind_vertices(ShaderProgram *program, unsigned int index) { static bool bind_vertices(ShaderProgram *program, unsigned int index) {
glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer);
if (check_glerror(program, "bind_vertices/glBindBuffer")) {
return false;
}
glGenVertexArrays(1, &program->vertex_array[index]); glGenVertexArrays(1, &program->vertex_array[index]);
if (check_glerror(program, "bind_vertices/glGenVertexArrays")) {
return false;
}
glBindVertexArray(program->vertex_array[index]); glBindVertexArray(program->vertex_array[index]);
if (check_glerror(program, "bind_vertices/glBindVertexArray")) {
return false;
}
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
// enable attribute pointer // enable attribute pointer
glEnableVertexAttribArray(program->vpos_locations[i]); glEnableVertexAttribArray(program->vpos_locations[i]);
if (check_glerror(program, "bind_vertices/glEnableVertexAttribArray")) {
return false;
}
// specify the location and data format of the array of generic vertex // specify the location and data format of the array of generic vertex
// attributes to use when rendering // attributes to use when rendering
glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (void *)offsetof(Vertex, pos)); sizeof(Vertex), (void *)offsetof(Vertex, pos));
if (check_glerror(program, "bind_vertices/glVertexAttribPointer")) {
return false;
}
} }
return true;
} }
static bool compile_shader(GLuint shader_id, const char *name, static bool compile_shader(GLuint shader_id, const char *name,
@@ -203,13 +353,18 @@ static bool compile_shader(GLuint shader_id, const char *name,
// update shader source code // update shader source code
glShaderSource(shader_id, 1, &source_code, NULL); glShaderSource(shader_id, 1, &source_code, NULL);
check_glerror_ro("compile_shader/glShaderSource");
// compile shader // compile shader
glCompileShader(shader_id); glCompileShader(shader_id);
check_glerror_ro("compile_shader/glCompileShader");
// get compilation status // get compilation status
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params); glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params);
check_glerror_ro("compile_shader/glGetShaderiv");
glGetShaderInfoLog(shader_id, 1024, NULL, (GLchar *)&log); glGetShaderInfoLog(shader_id, 1024, NULL, (GLchar *)&log);
check_glerror_ro("compile_shader/glGetShaderInfoLog");
if (status_params == GL_FALSE) { if (status_params == GL_FALSE) {
log_error("Failed to compile\n%s", log); log_error("Failed to compile\n%s", log);
@@ -221,9 +376,13 @@ static bool compile_shader(GLuint shader_id, const char *name,
return status_params == GL_TRUE; return status_params == GL_TRUE;
} }
static void init_shaders(ShaderProgram *program, const Project *project) { static bool init_shaders(ShaderProgram *program, const Project *project) {
// compile vertex shader // compile vertex shader
program->vertex_shader = glCreateShader(GL_VERTEX_SHADER); program->vertex_shader = glCreateShader(GL_VERTEX_SHADER);
if (check_glerror(program, "init_shaders/glCreateShader")) {
return false;
}
program->error = program->error || !compile_shader(program->vertex_shader, program->error = program->error || !compile_shader(program->vertex_shader,
"internal vertex shader", "internal vertex shader",
vertex_shader_text); vertex_shader_text);
@@ -231,18 +390,24 @@ static void init_shaders(ShaderProgram *program, const Project *project) {
// compile fragment shaders // compile fragment shaders
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER); program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER);
if (check_glerror(program, "init_shaders/glCreateShader")) {
return false;
}
program->error = program->error || program->error = program->error ||
!compile_shader(program->fragment_shaders[i], !compile_shader(program->fragment_shaders[i],
project->fragment_shaders[i][0].path, project->fragment_shaders[i][0].path,
project->fragment_shaders[i][0].content); project->fragment_shaders[i][0].content);
if (program->error) { if (program->error) {
return; return false;
} }
} }
return true;
} }
static void init_single_program(ShaderProgram *program, unsigned int i, static bool init_single_program(ShaderProgram *program, unsigned int i,
const ConfigFile *config, const ConfigFile *config,
const StateConfig *state_config) { const StateConfig *state_config) {
unsigned int index1; unsigned int index1;
@@ -251,10 +416,20 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
const char *prefix; const char *prefix;
program->programs[i] = glCreateProgram(); program->programs[i] = glCreateProgram();
if (check_glerror(program, "init_single_program/glCreateProgram")) {
return false;
}
glAttachShader(program->programs[i], program->vertex_shader); glAttachShader(program->programs[i], program->vertex_shader);
glAttachShader(program->programs[i], program->fragment_shaders[i]); glAttachShader(program->programs[i], program->fragment_shaders[i]);
if (check_glerror(program, "init_single_program/glAttachShader")) {
return false;
}
glLinkProgram(program->programs[i]); glLinkProgram(program->programs[i]);
if (check_glerror(program, "init_single_program/glLinkProgram")) {
return false;
}
// create uniforms pointers // create uniforms pointers
program->itime_locations[i] = glGetUniformLocation( program->itime_locations[i] = glGetUniformLocation(
@@ -280,6 +455,9 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
program->iautorand_locations[i] = glGetUniformLocation( program->iautorand_locations[i] = glGetUniformLocation(
program->programs[i], program->programs[i],
config_file_get_str(config, "UNIFORM_AUTORAND", "iAutoRand")); config_file_get_str(config, "UNIFORM_AUTORAND", "iAutoRand"));
program->iautorandcycle_locations[i] = glGetUniformLocation(
program->programs[i],
config_file_get_str(config, "UNIFORM_AUTORANDCYCLE", "iAutoRandCycle"));
program->ipage_locations[i] = glGetUniformLocation( program->ipage_locations[i] = glGetUniformLocation(
program->programs[i], program->programs[i],
config_file_get_str(config, "UNIFORM_PAGE", "iPage")); config_file_get_str(config, "UNIFORM_PAGE", "iPage"));
@@ -310,6 +488,13 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
glGetUniformLocation(program->programs[i], name); glGetUniformLocation(program->programs[i], name);
} }
prefix = config_file_get_str(config, "UNIFORM_IN_SWAP_PREFIX", "iInputSwap");
for (unsigned int j = 0; j < program->in_count; j++) {
snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
program->iinswap_locations[i * program->in_count + j] =
glGetUniformLocation(program->programs[i], name);
}
prefix = config_file_get_str(config, "UNIFORM_SEED_PREFIX", "iSeed"); prefix = config_file_get_str(config, "UNIFORM_SEED_PREFIX", "iSeed");
for (unsigned int j = 0; j < program->frag_count; j++) { for (unsigned int j = 0; j < program->frag_count; j++) {
snprintf(name, STR_LEN, "%s%d", prefix, j + 1); snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
@@ -324,18 +509,6 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
glGetUniformLocation(program->programs[i], name); glGetUniformLocation(program->programs[i], name);
} }
for (unsigned int j = 0; j < program->sub_type_count; j++) {
snprintf(name, STR_LEN, "SUB_%d_PREFIX", j + 1);
prefix = config_file_get_str(config, name, 0);
for (unsigned int k = 0; k < program->sub_variant_count; k++) {
snprintf(name, STR_LEN, "%s%d", prefix, k + 1);
program->sub_locations[i * program->sub_variant_count *
program->sub_type_count +
j * program->sub_variant_count + k] =
glGetSubroutineIndex(program->programs[i], GL_FRAGMENT_SHADER, name);
}
}
prefix = config_file_get_str(config, "UNIFORM_ACTIVE_PREFIX", "iActive"); prefix = config_file_get_str(config, "UNIFORM_ACTIVE_PREFIX", "iActive");
for (unsigned int j = 0; j < program->active_count; j++) { for (unsigned int j = 0; j < program->active_count; j++) {
snprintf(name, STR_LEN, "%s%d", prefix, j + 1); snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
@@ -374,102 +547,48 @@ static void init_single_program(ShaderProgram *program, unsigned int i,
glGetUniformLocation(program->programs[i], name); glGetUniformLocation(program->programs[i], name);
} }
if (check_glerror(program, "init_single_program/glGetUniformLocation")) {
return false;
}
for (unsigned int j = 0; j < program->sub_type_count; j++) {
snprintf(name, STR_LEN, "SUB_%d_PREFIX", j + 1);
prefix = config_file_get_str(config, name, 0);
for (unsigned int k = 0; k < program->sub_variant_count; k++) {
snprintf(name, STR_LEN, "%s%d", prefix, k + 1);
program->sub_locations[i * program->sub_variant_count *
program->sub_type_count +
j * program->sub_variant_count + k] =
glGetSubroutineIndex(program->programs[i], GL_FRAGMENT_SHADER, name);
}
}
if (check_glerror(program, "init_single_program/glGetSubroutineIndex")) {
return false;
}
// create attribute pointer // create attribute pointer
program->vpos_locations[i] = program->vpos_locations[i] =
glGetAttribLocation(program->programs[i], "vPos"); glGetAttribLocation(program->programs[i], "vPos");
if (check_glerror(program, "init_single_program/glGetAttribLocation")) {
return false;
}
log_info("Program %d initialized", i + 1); log_info("Program %d initialized", i + 1);
return true;
} }
static void init_programs(ShaderProgram *program, const ConfigFile *config, static bool init_programs(ShaderProgram *program, const ConfigFile *config,
const StateConfig *state_config) { const StateConfig *state_config) {
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
init_single_program(program, i, config, state_config); if (!init_single_program(program, i, config, state_config)) {
} return false;
}
void shaders_init(ShaderProgram *program, const Project *project,
const SharedContext *context, VideoCaptureArray *inputs,
bool rebind) {
if (!rebind) {
program->error = false;
program->last_resolution[0] = context->resolution[0];
program->last_resolution[1] = context->resolution[1];
program->tex_count = config_file_get_int(&project->config, "TEX_COUNT", 9);
program->frag_count = project->frag_count;
program->frag_output_index =
config_file_get_int(&project->config, "FRAG_OUTPUT", 1) - 1;
program->frag_monitor_index =
config_file_get_int(&project->config, "FRAG_MONITOR", 1) - 1;
program->sub_type_count =
config_file_get_int(&project->config, "SUB_TYPE_COUNT", 0);
program->in_count = config_file_get_int(&project->config, "IN_COUNT", 0);
program->sub_variant_count = project->state_config.state_max;
program->active_count = project->state_config.midi_active_counts.length;
program->midi_lengths.length = 0;
init_gl(program);
if (check_glerror(program)) {
return;
}
init_shaders(program, project);
if (program->error || check_glerror(program)) {
return;
}
init_textures(program, context);
if (check_glerror(program)) {
return;
}
init_input(program, &project->config, inputs);
if (check_glerror(program)) {
return;
}
init_framebuffers(program, &project->config);
if (check_glerror(program)) {
return;
}
init_programs(program, &project->config, &project->state_config);
if (check_glerror(program)) {
return;
}
init_vertices(program);
if (check_glerror(program)) {
return;
} }
} }
bind_vertices(program, rebind ? 1 : 0); return true;
if (check_glerror(program)) {
return;
}
}
void shaders_update(ShaderProgram *program, const File *fragment_shader,
unsigned int i, const Project *project) {
bool result;
result = compile_shader(program->fragment_shaders[i], fragment_shader->path,
fragment_shader->content);
if (result) {
init_single_program(program, i, &project->config, &project->state_config);
log_info("Program %d updated", i + 1);
}
} }
static void update_viewport(ShaderProgram *program, static void update_viewport(ShaderProgram *program,
@@ -480,8 +599,12 @@ static void update_viewport(ShaderProgram *program,
// clean and resize all textures // clean and resize all textures
for (unsigned int i = 0; i < program->tex_count; i++) { for (unsigned int i = 0; i < program->tex_count; i++) {
glActiveTexture(GL_TEXTURE0 + i); glActiveTexture(GL_TEXTURE0 + i);
check_glerror_ro("update_viewport/glActiveTexture");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0], glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0); context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
check_glerror_ro(
"update_viewport/glTexImage2D"); // TODO dont remap input textures
} }
program->last_resolution[0] = context->resolution[0]; program->last_resolution[0] = context->resolution[0];
program->last_resolution[1] = context->resolution[1]; program->last_resolution[1] = context->resolution[1];
@@ -545,6 +668,8 @@ static void use_program(const ShaderProgram *program, int i, bool output,
write_uniform_1i(program->idemo_locations[i], context->demo ? 1 : 0); write_uniform_1i(program->idemo_locations[i], context->demo ? 1 : 0);
write_uniform_1i(program->iautorand_locations[i], write_uniform_1i(program->iautorand_locations[i],
context->auto_random ? 1 : 0); context->auto_random ? 1 : 0);
write_uniform_1i(program->iautorandcycle_locations[i],
context->auto_random_cycle);
write_uniform_1i(program->ipage_locations[i], context->page); write_uniform_1i(program->ipage_locations[i], context->page);
write_uniform_1i(program->iselected_locations[i], context->selected + 1); write_uniform_1i(program->iselected_locations[i], context->selected + 1);
write_uniform_2f(program->ires_locations[i], &context->resolution); write_uniform_2f(program->ires_locations[i], &context->resolution);
@@ -559,9 +684,11 @@ static void use_program(const ShaderProgram *program, int i, bool output,
write_uniform_2f(program->iinres_locations[i * program->in_count + j], write_uniform_2f(program->iinres_locations[i * program->in_count + j],
&context->input_resolutions[j]); &context->input_resolutions[j]);
write_uniform_1i(program->iinfmt_locations[i * program->in_count + j], write_uniform_1i(program->iinfmt_locations[i * program->in_count + j],
context->input_formats[j]); context->inputs.values[j].pixelformat);
write_uniform_1i(program->iinfps_locations[i * program->in_count + j], write_uniform_1i(program->iinfps_locations[i * program->in_count + j],
context->input_fps[j]); context->inputs.values[j].fps);
write_uniform_1i(program->iinswap_locations[i * program->in_count + j],
context->inputs.values[j].swap ? 1 : 0);
} }
// set seeds uniforms // set seeds uniforms
@@ -612,6 +739,87 @@ static void use_program(const ShaderProgram *program, int i, bool output,
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
} }
void shaders_init(ShaderProgram *program, const Project *project,
const SharedContext *context, bool rebind) {
if (!rebind) {
program->error = false;
program->last_resolution[0] = context->resolution[0];
program->last_resolution[1] = context->resolution[1];
program->tex_count = config_file_get_int(&project->config, "TEX_COUNT", 9);
program->frag_count = project->frag_count;
program->frag_output_index =
config_file_get_int(&project->config, "FRAG_OUTPUT", 1) - 1;
program->frag_monitor_index =
config_file_get_int(&project->config, "FRAG_MONITOR", 1) - 1;
program->sub_type_count =
config_file_get_int(&project->config, "SUB_TYPE_COUNT", 0);
program->in_count = config_file_get_int(&project->config, "IN_COUNT", 0);
program->sub_variant_count = project->state_config.state_max;
program->active_count = project->state_config.midi_active_counts.length;
program->midi_lengths.length = 0;
#ifdef VIDEO_IN
memset(program->dma_images, 0, sizeof(program->dma_images));
memset(program->dma_images_swap, 0, sizeof(program->dma_images_swap));
#endif /* VIDEO_IN */
if (!init_gl(program)) {
return;
}
if (!init_shaders(program, project)) {
return;
}
if (!init_textures(program, context)) {
return;
}
if (!init_framebuffers(program, &project->config)) {
return;
}
if (!init_programs(program, &project->config, &project->state_config)) {
return;
}
if (!init_vertices(program)) {
return;
}
}
if (!bind_vertices(program, rebind ? 1 : 0)) {
return;
}
}
void shaders_relink_input(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs, unsigned int i) {
#ifdef VIDEO_IN
// shaders_free_input(program, i);
init_input(program, &project->config, inputs, i, true);
#endif /* VIDEO_IN */
}
void shaders_link_inputs(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs) {
#ifdef VIDEO_IN
for (unsigned int i = 0; i < program->in_count; i++) {
init_input(program, &project->config, inputs, i, false);
}
#endif /* VIDEO_IN */
}
void shaders_update(ShaderProgram *program, const File *fragment_shader,
unsigned int i, const Project *project) {
if (compile_shader(program->fragment_shaders[i], fragment_shader->path,
fragment_shader->content) &&
init_single_program(program, i, &project->config,
&project->state_config)) {
log_info("Program %d updated", i + 1);
}
}
void shaders_compute(ShaderProgram *program, const SharedContext *context, void shaders_compute(ShaderProgram *program, const SharedContext *context,
bool monitor, bool output_only) { bool monitor, bool output_only) {
if (!output_only) { if (!output_only) {
@@ -634,25 +842,42 @@ void shaders_compute(ShaderProgram *program, const SharedContext *context,
monitor ? program->frag_monitor_index monitor ? program->frag_monitor_index
: program->frag_output_index, : program->frag_output_index,
true, context); true, context);
check_glerror(program, "shaders_compute");
} }
void shaders_free(const ShaderProgram *program) { void shaders_free(const ShaderProgram *program) {
for (unsigned int i = 0; i < program->frag_count; i++) { for (unsigned int i = 0; i < program->frag_count; i++) {
glDeleteProgram(program->programs[i]); glDeleteProgram(program->programs[i]);
} }
check_glerror_ro("shaders_free/glDeleteProgram");
glDeleteFramebuffers(program->frag_count, program->frame_buffers); glDeleteFramebuffers(program->frag_count, program->frame_buffers);
check_glerror_ro("shaders_free/glDeleteFramebuffers");
glDeleteTextures(program->tex_count, program->textures); glDeleteTextures(program->tex_count, program->textures);
check_glerror_ro("shaders_free/glDeleteTextures");
glDeleteBuffers(1, &program->vertex_buffer); glDeleteBuffers(1, &program->vertex_buffer);
check_glerror_ro("shaders_free/glDeleteBuffers");
} }
void shaders_free_window(const ShaderProgram *program, bool secondary) { void shaders_free_window(const ShaderProgram *program, bool secondary) {
glDeleteVertexArrays(1, &program->vertex_array[secondary ? 1 : 0]); glDeleteVertexArrays(1, &program->vertex_array[secondary ? 1 : 0]);
check_glerror_ro("shaders_free_window/glDeleteVertexArrays");
} }
void shaders_free_input(const ShaderProgram *program, void shaders_free_input(ShaderProgram *program, unsigned int input_index) {
const VideoCapture *input) { #ifdef VIDEO_IN
if (!input->error && input->dma_image != EGL_NO_IMAGE_KHR) { if (program->dma_images[input_index] != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(program->egl_display, input->dma_image); eglDestroyImageKHR(program->egl_display, program->dma_images[input_index]);
program->dma_images[input_index] = EGL_NO_IMAGE_KHR;
} }
} if (program->dma_images_swap[input_index] != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(program->egl_display,
program->dma_images_swap[input_index]);
program->dma_images_swap[input_index] = EGL_NO_IMAGE_KHR;
}
check_eglerror_ro("shaders_free_input/eglDestroyImageKHR");
#endif /* VIDEO_IN */
}
+9 -5
View File
@@ -4,8 +4,13 @@
#define SHADERS_H #define SHADERS_H
void shaders_init(ShaderProgram *program, const Project *project, void shaders_init(ShaderProgram *program, const Project *project,
const SharedContext *context, VideoCaptureArray *inputs, const SharedContext *context, bool rebind);
bool rebind);
void shaders_relink_input(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs, unsigned int i);
void shaders_link_inputs(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs);
void shaders_update(ShaderProgram *program, const File *fragment_shader, void shaders_update(ShaderProgram *program, const File *fragment_shader,
unsigned int i, const Project *project); unsigned int i, const Project *project);
@@ -17,7 +22,6 @@ void shaders_free(const ShaderProgram *program);
void shaders_free_window(const ShaderProgram *program, bool secondary); void shaders_free_window(const ShaderProgram *program, bool secondary);
void shaders_free_input(const ShaderProgram *program, void shaders_free_input(ShaderProgram *program, unsigned int input_index);
const VideoCapture *input);
#endif /* SHADERS_H */ #endif /* SHADERS_H */
+1 -1
View File
@@ -32,4 +32,4 @@ SharedContext *shared_init_context(const char *key) {
void shared_close_context(SharedContext *shared) { void shared_close_context(SharedContext *shared) {
close_shared(shared, sizeof(SharedContext), shared->fd); close_shared(shared, sizeof(SharedContext), shared->fd);
} }
+1 -1
View File
@@ -6,4 +6,4 @@
SharedContext *shared_init_context(const char *key); SharedContext *shared_init_context(const char *key);
void shared_close_context(SharedContext *shared); void shared_close_context(SharedContext *shared);
#endif /* SHARED_H */ #endif /* SHARED_H */
+361 -187
View File
@@ -1,5 +1,6 @@
#include <log.h> #include <log.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include "types.h" #include "types.h"
@@ -12,6 +13,233 @@
#include "state.h" #include "state.h"
#include "tempo.h" #include "tempo.h"
static void safe_midi_write(const MidiDevice *midi, unsigned int code,
unsigned char value) {
if (code != UNSET_MIDI_CODE) {
midi_write(midi, code, value);
}
}
static void update_page(const SharedContext *context,
const StateConfig *state_config,
const MidiDevice *midi) {
unsigned int page_item_min;
unsigned int page_item_max;
// SHOW PAGE
for (unsigned int i = 0; i < state_config->select_page_codes.length; i++) {
safe_midi_write(midi, state_config->select_page_codes.values[i],
i == context->page ? MIDI_MAX : 0);
}
// SHOW PAGE ITEM
page_item_min = state_config->select_item_codes.length * context->page;
page_item_max = page_item_min + state_config->select_item_codes.length;
if (context->state.values[context->selected] >= page_item_min &&
context->state.values[context->selected] < page_item_max) {
for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) {
safe_midi_write(midi, state_config->select_item_codes.values[i],
i == context->state.values[context->selected] -
page_item_min
? MIDI_MAX
: 0);
}
} else {
for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) {
safe_midi_write(midi, state_config->select_item_codes.values[i], 0);
}
}
}
static void update_active(const SharedContext *context,
const StateConfig *state_config,
const MidiDevice *midi) {
unsigned int k;
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
for (unsigned int j = 0; j < state_config->midi_active_counts.values[i];
j++) {
k = state_config->midi_active_offsets.values[i] + j;
safe_midi_write(midi, state_config->midi_active_codes.values[k],
context->active[i] == j ? MIDI_MAX : 0);
}
}
}
static void update_values(const SharedContext *context,
const StateConfig *state_config,
const MidiDevice *midi) {
unsigned int j;
unsigned int k;
unsigned int part;
for (unsigned int i = 0; i < state_config->midi_codes.length; i++) {
j = i / 3;
part = arr_uint_remap_index(state_config->midi_offsets, &j);
k = state_config->values_offsets.values[part] +
context->active[part] * state_config->midi_counts.values[part] + j;
safe_midi_write(midi, state_config->midi_codes.values[i],
context->values[k][i % 3] * MIDI_MAX);
}
}
static void reset(SharedContext *context) {
memset(context->values, 0, sizeof(context->values));
memset(context->state.values, 0, sizeof(context->state.values));
}
static void randomize(SharedContext *context, const StateConfig *state_config) {
unsigned int j;
unsigned int l;
unsigned int part;
for (unsigned int i = 0; i < state_config->midi_codes.length; i++) {
j = i / 3;
part = arr_uint_remap_index(state_config->midi_offsets, &j);
for (unsigned int k = 0; k < state_config->midi_active_counts.values[part];
k++) {
l = state_config->values_offsets.values[part] +
k * state_config->midi_counts.values[part] + j;
if (arr_uint_index_of(state_config->fader_codes,
state_config->midi_codes.values[i]) !=
ARRAY_NOT_FOUND) {
context->values[l][i % 3] = (float)rand_uint(MIDI_MAX + 1) / MIDI_MAX;
} else {
context->values[l][i % 3] = rand_uint(2) == 1 ? 1 : 0;
}
}
}
for (unsigned int i = 0; i < context->state.length; i++) {
context->state.values[i] = rand_uint(state_config->state_max);
}
}
static void load_from_file(SharedContext *context,
const StateConfig *state_config,
const char *state_file) {
ConfigFile saved_state;
char key[STR_LEN];
config_file_read(&saved_state, state_file);
if (saved_state.error) {
return;
}
tempo_set(&context->tempo,
config_file_get_int(&saved_state, "tempo", context->tempo.tempo));
context->page = config_file_get_int(&saved_state, "page", 0);
context->selected = config_file_get_int(&saved_state, "selected", 0);
for (unsigned int i = 0; i < context->state.length; i++) {
snprintf(key, STR_LEN, "seed_%d", i);
context->seeds[i] =
config_file_get_int(&saved_state, key, context->seeds[i]);
snprintf(key, STR_LEN, "state_%d", i);
context->state.values[i] = config_file_get_int(&saved_state, key, 0);
}
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
snprintf(key, STR_LEN, "active_%d", i);
context->active[i] = config_file_get_int(&saved_state, key, 0);
}
for (unsigned int i = 0; i < state_config->value_count; i++) {
snprintf(key, STR_LEN, "value_%d_x", i);
context->values[i][0] =
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
snprintf(key, STR_LEN, "value_%d_y", i);
context->values[i][1] =
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
snprintf(key, STR_LEN, "value_%d_z", i);
context->values[i][2] =
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
}
config_file_free(&saved_state);
}
static void load_from_default_file(SharedContext *context,
const StateConfig *state_config) {
char state_file[STR_LEN];
snprintf(state_file, STR_LEN, "%s.txt", state_config->save_file_prefix);
load_from_file(context, state_config, state_file);
}
static void load_from_index_file(SharedContext *context,
const StateConfig *state_config,
unsigned int index) {
char state_file[STR_LEN];
snprintf(state_file, STR_LEN, "%s.%d.txt", state_config->save_file_prefix,
index);
load_from_file(context, state_config, state_file);
}
static void save_to_file(const SharedContext *context,
const StateConfig *state_config,
const char *state_file) {
StringArray lines;
log_info("Saving state to '%s'...", state_file);
lines.length = 0;
snprintf(lines.values[lines.length++], STR_LEN, "tempo=%d",
(unsigned int)context->tempo.tempo);
snprintf(lines.values[lines.length++], STR_LEN, "page=%d", context->page);
snprintf(lines.values[lines.length++], STR_LEN, "selected=%d",
context->selected);
for (unsigned int i = 0; i < context->state.length; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "seed_%d=%d", i,
context->seeds[i]);
snprintf(lines.values[lines.length++], STR_LEN, "state_%d=%d", i,
context->state.values[i]);
}
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "active_%d=%d", i,
context->active[i]);
}
for (unsigned int i = 0; i < state_config->value_count; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_x=%d", i,
(unsigned int)(context->values[i][0] * MIDI_MAX));
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_y=%d", i,
(unsigned int)(context->values[i][1] * MIDI_MAX));
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_z=%d", i,
(unsigned int)(context->values[i][2] * MIDI_MAX));
}
file_write(state_file, &lines);
}
static void save_to_default_file(const SharedContext *context,
const StateConfig *state_config) {
char state_file[STR_LEN];
snprintf(state_file, STR_LEN, "%s.txt", state_config->save_file_prefix);
save_to_file(context, state_config, state_file);
}
static void save_to_index_file(const SharedContext *context,
const StateConfig *state_config,
unsigned int index) {
char state_file[STR_LEN];
snprintf(state_file, STR_LEN, "%s.%d.txt", state_config->save_file_prefix,
index);
save_to_file(context, state_config, state_file);
}
void state_parse_config(StateConfig *state_config, const ConfigFile *config) { void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
unsigned int offset; unsigned int offset;
unsigned int count; unsigned int count;
@@ -118,82 +346,81 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
state_config->tap_tempo_code = state_config->tap_tempo_code =
config_file_get_int(config, "TAP_TEMPO", UNSET_MIDI_CODE); config_file_get_int(config, "TAP_TEMPO", UNSET_MIDI_CODE);
}
static void safe_midi_write(const MidiDevice *midi, unsigned int code, strlcpy(state_config->save_file_prefix,
unsigned char value) { config_file_get_str(config, "SAVE_FILE_PREFIX", "forge_save"),
if (code != UNSET_MIDI_CODE) { STR_LEN);
midi_write(midi, code, value);
}
}
static void update_page(const SharedContext *context, state_config->hotkey_randomize =
const StateConfig *state_config, config_file_get_int(config, "HOTKEY_RANDOMIZE", 82);
const MidiDevice *midi) { state_config->hotkey_reset =
unsigned int page_item_min; config_file_get_int(config, "HOTKEY_RESET", 1082);
unsigned int page_item_max; state_config->hotkey_demo = config_file_get_int(config, "HOTKEY_DEMO", 68);
// SHOW PAGE state_config->hotkey_autorand =
for (unsigned int i = 0; i < state_config->select_page_codes.length; i++) { config_file_get_int(config, "HOTKEY_AUTORAND", 65);
safe_midi_write(midi, state_config->select_page_codes.values[i], state_config->hotkey_autorand_down =
i == context->page ? MIDI_MAX : 0); config_file_get_int(config, "HOTKEY_AUTORAND_DOWN", 263);
} state_config->hotkey_autorand_up =
config_file_get_int(config, "HOTKEY_AUTORAND_UP", 262);
state_config->hotkey_tempo_down =
config_file_get_int(config, "HOTKEY_TEMPO_DOWN", 264);
state_config->hotkey_tempo_up =
config_file_get_int(config, "HOTKEY_TEMPO_UP", 265);
// SHOW PAGE ITEM if (config_file_has(config, "HOTKEY_LOAD_COUNT")) {
page_item_min = state_config->select_item_codes.length * context->page; state_config->hotkey_load.length =
page_item_max = page_item_min + state_config->select_item_codes.length; config_file_get_int(config, "HOTKEY_LOAD_COUNT", 0);
if (context->state.values[context->selected] >= page_item_min && for (unsigned int i = 0; i < state_config->hotkey_load.length; i++) {
context->state.values[context->selected] < page_item_max) { snprintf(name, STR_LEN, "HOTKEY_LOAD_%d", i + 1);
for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) { state_config->hotkey_load.values[i] =
safe_midi_write(midi, state_config->select_item_codes.values[i], config_file_get_int(config, name, 0);
i == context->state.values[context->selected] -
page_item_min
? MIDI_MAX
: 0);
} }
} else { } else {
for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) { state_config->hotkey_load.length = 10;
safe_midi_write(midi, state_config->select_item_codes.values[i], 0); state_config->hotkey_load.values[0] = 49;
state_config->hotkey_load.values[1] = 50;
state_config->hotkey_load.values[2] = 51;
state_config->hotkey_load.values[3] = 52;
state_config->hotkey_load.values[4] = 53;
state_config->hotkey_load.values[5] = 54;
state_config->hotkey_load.values[6] = 55;
state_config->hotkey_load.values[7] = 56;
state_config->hotkey_load.values[8] = 57;
state_config->hotkey_load.values[9] = 48;
}
if (config_file_has(config, "HOTKEY_SAVE_COUNT")) {
state_config->hotkey_save.length =
config_file_get_int(config, "HOTKEY_SAVE_COUNT", 0);
for (unsigned int i = 0; i < state_config->hotkey_save.length; i++) {
snprintf(name, STR_LEN, "HOTKEY_SAVE_%d", i + 1);
state_config->hotkey_save.values[i] =
config_file_get_int(config, name, 0);
} }
} else {
state_config->hotkey_save.length = 10;
state_config->hotkey_save.values[0] = 1049;
state_config->hotkey_save.values[1] = 1050;
state_config->hotkey_save.values[2] = 1051;
state_config->hotkey_save.values[3] = 1052;
state_config->hotkey_save.values[4] = 1053;
state_config->hotkey_save.values[5] = 1054;
state_config->hotkey_save.values[6] = 1055;
state_config->hotkey_save.values[7] = 1056;
state_config->hotkey_save.values[8] = 1057;
state_config->hotkey_save.values[9] = 1048;
} }
} }
static void update_active(const SharedContext *context, void state_midi_event(SharedContext *context, const StateConfig *state_config,
const StateConfig *state_config, const MidiDevice *midi, unsigned char code,
const MidiDevice *midi) { unsigned char value, bool trace_midi) {
unsigned int k; unsigned int i;
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
for (unsigned int j = 0; j < state_config->midi_active_counts.values[i];
j++) {
k = state_config->midi_active_offsets.values[i] + j;
safe_midi_write(midi, state_config->midi_active_codes.values[k],
context->active[i] == j ? MIDI_MAX : 0);
}
}
}
static void update_values(const SharedContext *context,
const StateConfig *state_config,
const MidiDevice *midi) {
unsigned int j; unsigned int j;
unsigned int k; unsigned int k;
unsigned int part; unsigned int part;
for (unsigned int i = 0; i < state_config->midi_codes.length; i++) {
j = i / 3;
part = arr_uint_remap_index(state_config->midi_offsets, &j);
k = state_config->values_offsets.values[part] +
context->active[part] * state_config->midi_counts.values[part] + j;
safe_midi_write(midi, state_config->midi_codes.values[i],
context->values[k][i % 3] * MIDI_MAX);
}
}
void state_apply_event(SharedContext *context, const StateConfig *state_config,
const MidiDevice *midi, unsigned char code,
unsigned char value, bool trace_midi) {
unsigned int i, j, k, part;
bool found; bool found;
found = false; found = false;
@@ -281,10 +508,60 @@ void state_apply_event(SharedContext *context, const StateConfig *state_config,
} }
} }
void state_apply(const SharedContext *context, const StateConfig *state_config, void state_key_event(SharedContext *context, const StateConfig *state_config,
const MidiDevice *midi) { unsigned int code, const MidiDevice *midi) {
if (!midi->error) { unsigned int index;
if (code == state_config->hotkey_randomize) {
log_info("[%d] Randomized", code);
randomize(context, state_config);
update_values(context, state_config, midi); update_values(context, state_config, midi);
} else if (code == state_config->hotkey_reset) {
log_info("[%d] Reset", code);
reset(context);
update_values(context, state_config, midi);
} else if (code == state_config->hotkey_demo) {
log_info((context->demo ? "[%d] Demo OFF" : "[%d] Demo ON"), code);
context->demo = !context->demo;
} else if (code == state_config->hotkey_autorand) {
log_info(
(context->auto_random ? "[%d] Auto Random OFF" : "[%d] Auto Random ON"),
code);
context->auto_random = !context->auto_random;
} else if (code == state_config->hotkey_autorand_down) {
if (context->auto_random_cycle > 1) {
context->auto_random_cycle -= 1;
}
log_info("[%d] Auto Random Cycle: %d", code, context->auto_random_cycle);
} else if (code == state_config->hotkey_autorand_up) {
context->auto_random_cycle += 1;
log_info("[%d] Auto Random Cycle: %d", code, context->auto_random_cycle);
} else if (code == state_config->hotkey_tempo_up) {
tempo_set(&context->tempo, context->tempo.tempo + 1);
log_info("[%d] Tempo: %f", code, context->tempo);
} else if (code == state_config->hotkey_tempo_down) {
if (context->tempo.tempo > 0) {
tempo_set(&context->tempo, context->tempo.tempo - 1);
}
log_info("[%d] Tempo: %f", code, context->tempo);
} else {
index = arr_uint_index_of(state_config->hotkey_load, code);
if (index != ARRAY_NOT_FOUND) {
log_info("[%d] Loading state %d", code, index + 1);
load_from_index_file(context, state_config, index + 1);
return;
}
index = arr_uint_index_of(state_config->hotkey_save, code);
if (index != ARRAY_NOT_FOUND) {
log_info("[%d] Saving state %d", code, index + 1);
save_to_index_file(context, state_config, index + 1);
return;
}
log_info("[%d] No hotkey defined", code);
} }
} }
@@ -292,7 +569,10 @@ bool state_background_write(SharedContext *context,
const StateConfig *state_config, const StateConfig *state_config,
const MidiDevice *midi) { const MidiDevice *midi) {
pid_t pid; pid_t pid;
bool beat_active, last_active, change, last_change; bool beat_active;
bool last_active;
bool change;
bool last_change;
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
@@ -314,7 +594,7 @@ bool state_background_write(SharedContext *context,
last_change = false; last_change = false;
while (!context->stop) { while (!context->stop) {
beat_active = tempo_progress(&context->tempo, 1.0) < 0.25; beat_active = tempo_progress(&context->tempo, 1.0) < 0.5;
if (!midi->error && beat_active != last_active) { if (!midi->error && beat_active != last_active) {
safe_midi_write(midi, state_config->tap_tempo_code, safe_midi_write(midi, state_config->tap_tempo_code,
@@ -327,74 +607,35 @@ bool state_background_write(SharedContext *context,
last_active = beat_active; last_active = beat_active;
change = tempo_progress(&context->tempo, 4.0) < 0.25; change = tempo_progress(&context->tempo,
(double)context->auto_random_cycle) < 0.5;
if (context->auto_random && change && !last_change) { if (context->auto_random && change && !last_change) {
state_randomize(context, state_config); randomize(context, state_config);
state_apply(context, state_config, midi); update_values(context, state_config, midi);
} }
last_change = change; last_change = change;
} }
log_info("(state) background writing stopped by main thread (pid: %d)", pid); log_info("(state) background writing stopped by main thread (pid: %d)", pid);
return false; exit(EXIT_SUCCESS);
}
static void state_load(SharedContext *context, const StateConfig *state_config,
const char *state_file) {
ConfigFile saved_state;
char key[STR_LEN];
config_file_read(&saved_state, state_file);
tempo_set(&context->tempo,
config_file_get_int(&saved_state, "tempo", context->tempo.tempo));
context->page = config_file_get_int(&saved_state, "page", 0);
context->selected = config_file_get_int(&saved_state, "selected", 0);
for (unsigned int i = 0; i < context->state.length; i++) {
snprintf(key, STR_LEN, "seed_%d", i);
context->seeds[i] =
config_file_get_int(&saved_state, key, context->seeds[i]);
snprintf(key, STR_LEN, "state_%d", i);
context->state.values[i] = config_file_get_int(&saved_state, key, 0);
}
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
snprintf(key, STR_LEN, "active_%d", i);
context->active[i] = config_file_get_int(&saved_state, key, 0);
}
for (unsigned int i = 0; i < state_config->value_count; i++) {
snprintf(key, STR_LEN, "value_%d_x", i);
context->values[i][0] =
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
snprintf(key, STR_LEN, "value_%d_y", i);
context->values[i][1] =
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
snprintf(key, STR_LEN, "value_%d_z", i);
context->values[i][2] =
(float)config_file_get_int(&saved_state, key, 0) / MIDI_MAX;
}
config_file_free(&saved_state);
} }
void state_init(SharedContext *context, const StateConfig *state_config, void state_init(SharedContext *context, const StateConfig *state_config,
bool demo, bool auto_random, unsigned int base_tempo, bool demo, bool auto_random, unsigned int auto_random_cycles,
const char *state_file, bool load_state) { unsigned int base_tempo, bool load_state) {
tempo_init(&context->tempo); tempo_init(&context->tempo, base_tempo);
tempo_set(&context->tempo, base_tempo);
context->demo = demo; context->demo = demo;
context->auto_random = auto_random; context->auto_random = auto_random;
context->auto_random_cycle = auto_random_cycles;
context->state.length = state_config->select_frag_codes.length; context->state.length = state_config->select_frag_codes.length;
memset(context->state.values, 0, sizeof(context->state.values)); memset(context->state.values, 0, sizeof(context->state.values));
if (auto_random) { if (auto_random) {
state_randomize(context, state_config); randomize(context, state_config);
} }
memset(context->active, 0, sizeof(context->active)); memset(context->active, 0, sizeof(context->active));
@@ -410,77 +651,10 @@ void state_init(SharedContext *context, const StateConfig *state_config,
} }
if (load_state) { if (load_state) {
state_load(context, state_config, state_file); load_from_default_file(context, state_config);
} }
} }
void state_reset(SharedContext *context) { void state_save(const SharedContext *context, const StateConfig *state_config) {
memset(context->values, 0, sizeof(context->values)); save_to_default_file(context, state_config);
memset(context->state.values, 0, sizeof(context->state.values));
}
void state_randomize(SharedContext *context, const StateConfig *state_config) {
unsigned int j;
unsigned int l;
unsigned int part;
for (unsigned int i = 0; i < state_config->midi_codes.length; i++) {
j = i / 3;
part = arr_uint_remap_index(state_config->midi_offsets, &j);
for (unsigned int k = 0; k < state_config->midi_active_counts.values[part];
k++) {
l = state_config->values_offsets.values[part] +
k * state_config->midi_counts.values[part] + j;
if (arr_uint_index_of(state_config->fader_codes,
state_config->midi_codes.values[i]) !=
ARRAY_NOT_FOUND) {
context->values[l][i % 3] = (float)rand_uint(MIDI_MAX + 1) / MIDI_MAX;
} else {
context->values[l][i % 3] = rand_uint(2) == 1 ? 1 : 0;
}
}
}
for (unsigned int i = 0; i < context->state.length; i++) {
context->state.values[i] = rand_uint(state_config->state_max);
}
}
void state_save(const SharedContext *context, const StateConfig *state_config,
const char *state_file) {
StringArray lines;
log_info("Saving state to '%s'...", state_file);
lines.length = 0;
snprintf(lines.values[lines.length++], STR_LEN, "tempo=%d",
(unsigned int)context->tempo.tempo);
snprintf(lines.values[lines.length++], STR_LEN, "page=%d", context->page);
snprintf(lines.values[lines.length++], STR_LEN, "selected=%d",
context->selected);
for (unsigned int i = 0; i < context->state.length; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "seed_%d=%d", i,
context->seeds[i]);
snprintf(lines.values[lines.length++], STR_LEN, "state_%d=%d", i,
context->state.values[i]);
}
for (unsigned int i = 0; i < state_config->midi_active_counts.length; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "active_%d=%d", i,
context->active[i]);
}
for (unsigned int i = 0; i < state_config->value_count; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_x=%d", i,
(unsigned int)(context->values[i][0] * MIDI_MAX));
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_y=%d", i,
(unsigned int)(context->values[i][1] * MIDI_MAX));
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_z=%d", i,
(unsigned int)(context->values[i][2] * MIDI_MAX));
}
file_write(state_file, &lines);
} }
+10 -15
View File
@@ -5,26 +5,21 @@
void state_parse_config(StateConfig *state_config, const ConfigFile *config); void state_parse_config(StateConfig *state_config, const ConfigFile *config);
void state_apply_event(SharedContext *context, const StateConfig *state_config, void state_midi_event(SharedContext *context, const StateConfig *state_config,
const MidiDevice *midi, unsigned char code, const MidiDevice *midi, unsigned char code,
unsigned char value, bool trace_midi); unsigned char value, bool trace_midi);
void state_key_event(SharedContext *context, const StateConfig *state_config,
unsigned int code, const MidiDevice *midi);
bool state_background_write(SharedContext *context, bool state_background_write(SharedContext *context,
const StateConfig *state_config, const StateConfig *state_config,
const MidiDevice *midi); const MidiDevice *midi);
void state_init(SharedContext *context, const StateConfig *state_config, void state_init(SharedContext *context, const StateConfig *state_config,
bool demo, bool auto_random, unsigned int base_tempo, bool demo, bool auto_random, unsigned int auto_random_cycles,
const char *state_file, bool load_state); unsigned int base_tempo, bool load_state);
void state_reset(SharedContext *context); void state_save(const SharedContext *context, const StateConfig *state_config);
void state_randomize(SharedContext *context, const StateConfig *state_config); #endif /* STATE_H */
void state_apply(const SharedContext *context, const StateConfig *state_config,
const MidiDevice *midi);
void state_save(const SharedContext *context, const StateConfig *state_config,
const char *state_file);
#endif /* STATE_H */
+5 -5
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;
@@ -37,8 +38,6 @@ unsigned int string_trim(char *str) {
return end - start + 1; return end - start + 1;
} }
static bool is_digit(char c) { return c >= '0' && c <= '9'; }
bool string_is_number(const char *value) { bool string_is_number(const char *value) {
unsigned long value_len; unsigned long value_len;
@@ -59,7 +58,8 @@ bool string_is_number(const char *value) {
char *string_replace_at(const char *src, unsigned int from, unsigned int to, char *string_replace_at(const char *src, unsigned int from, unsigned int to,
const char *rpl) { const char *rpl) {
unsigned long src_len, rpl_len; unsigned long src_len;
unsigned long rpl_len;
char *dst; char *dst;
src_len = strnlen(src, STR_LEN * STR_LEN); src_len = strnlen(src, STR_LEN * STR_LEN);
@@ -72,4 +72,4 @@ char *string_replace_at(const char *src, unsigned int from, unsigned int to,
strlcpy(dst + from + rpl_len, src + to, src_len - to + 1); strlcpy(dst + from + rpl_len, src + to, src_len - to + 1);
return dst; return dst;
} }
+1 -1
View File
@@ -10,4 +10,4 @@ bool string_is_number(const char *value);
char *string_replace_at(const char *src, unsigned int from, unsigned int to, char *string_replace_at(const char *src, unsigned int from, unsigned int to,
const char *rpl); const char *rpl);
#endif /* STRINGS_H */ #endif /* STRINGS_H */
+22 -10
View File
@@ -25,14 +25,6 @@ static void reset_tap_chain(Tempo *tempo, long t) {
memset(tempo->tap_durations, 0, sizeof(tempo->tap_durations)); memset(tempo->tap_durations, 0, sizeof(tempo->tap_durations));
} }
void tempo_init(Tempo *tempo) {
long t;
t = now();
reset_tap_chain(tempo, t);
}
static bool is_chain_active(const Tempo tempo, long t) { static bool is_chain_active(const Tempo tempo, long t) {
return (tempo.last_tap + MAX_BEAT_LENGTH) > t && return (tempo.last_tap + MAX_BEAT_LENGTH) > t &&
(tempo.last_tap + (tempo.beat_length * BEATS_UNTIL_CHAIN_RESET)) > t; (tempo.last_tap + (tempo.beat_length * BEATS_UNTIL_CHAIN_RESET)) > t;
@@ -98,11 +90,31 @@ static void add_tap_to_chain(Tempo *tempo, long t) {
tempo->tempo = 60000.0 / tempo->beat_length; tempo->tempo = 60000.0 / tempo->beat_length;
} }
void tempo_set(Tempo *tempo, float value) { void tempo_init(Tempo *tempo, float value) {
long t;
t = now();
reset_tap_chain(tempo, t);
tempo->tempo = value; tempo->tempo = value;
tempo->beat_length = 60000.0 / value; tempo->beat_length = 60000.0 / value;
} }
void tempo_set(Tempo *tempo, float value) {
long t;
long progress;
t = now();
progress = (t - tempo->last_reset) % tempo->beat_length;
tempo->tempo = value;
tempo->beat_length = 60000.0 / value;
reset_tap_chain(tempo, t - progress);
}
void tempo_tap(Tempo *tempo) { void tempo_tap(Tempo *tempo) {
long t; long t;
@@ -125,4 +137,4 @@ double tempo_total(const Tempo *tempo) {
double tempo_progress(const Tempo *tempo, double modulo) { double tempo_progress(const Tempo *tempo, double modulo) {
return fmod(tempo_total(tempo), modulo); return fmod(tempo_total(tempo), modulo);
} }
+2 -2
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,4 +13,4 @@ double tempo_total(const Tempo *tempo);
double tempo_progress(const Tempo *tempo, double modulo); double tempo_progress(const Tempo *tempo, double modulo);
#endif /* TEMPO_H */ #endif /* TEMPO_H */
+3 -2
View File
@@ -18,7 +18,8 @@ bool timer_inc(Timer *timer) {
double timer_reset(Timer *timer) { double timer_reset(Timer *timer) {
struct timeval stop; struct timeval stop;
double secs, per_secs; double secs;
double per_secs;
gettimeofday(&stop, NULL); gettimeofday(&stop, NULL);
@@ -30,4 +31,4 @@ double timer_reset(Timer *timer) {
timer->counter = 0; timer->counter = 0;
return per_secs; return per_secs;
} }
+1 -1
View File
@@ -9,4 +9,4 @@ bool timer_inc(Timer *timer);
double timer_reset(Timer *timer); double timer_reset(Timer *timer);
#endif /* TIMER_H */ #endif /* TIMER_H */
+43 -14
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,10 +44,11 @@ typedef struct Parameters {
float base_tempo; float base_tempo;
bool demo; bool demo;
bool auto_random; bool auto_random;
unsigned int auto_random_cycle;
StringArray video_in; StringArray video_in;
unsigned int video_size; unsigned int video_size;
unsigned int internal_size; unsigned int internal_size;
char state_file[STR_LEN]; bool video_reconnect;
bool load_state; bool load_state;
bool save_state; bool save_state;
bool trace_midi; bool trace_midi;
@@ -102,8 +104,10 @@ typedef struct ShaderProgram {
GLuint iinres_locations[ARRAY_SIZE]; GLuint iinres_locations[ARRAY_SIZE];
GLuint iinfmt_locations[ARRAY_SIZE]; GLuint iinfmt_locations[ARRAY_SIZE];
GLuint iinfps_locations[ARRAY_SIZE]; GLuint iinfps_locations[ARRAY_SIZE];
GLuint iinswap_locations[ARRAY_SIZE];
GLuint idemo_locations[ARRAY_SIZE]; GLuint idemo_locations[ARRAY_SIZE];
GLuint iautorand_locations[ARRAY_SIZE]; GLuint iautorand_locations[ARRAY_SIZE];
GLuint iautorandcycle_locations[ARRAY_SIZE];
GLuint iseed_locations[ARRAY_SIZE]; GLuint iseed_locations[ARRAY_SIZE];
GLuint istate_locations[ARRAY_SIZE]; GLuint istate_locations[ARRAY_SIZE];
GLuint ipage_locations[ARRAY_SIZE]; GLuint ipage_locations[ARRAY_SIZE];
@@ -124,7 +128,11 @@ typedef struct ShaderProgram {
unsigned int active_count; unsigned int active_count;
unsigned int in_count; unsigned int in_count;
#ifdef VIDEO_IN
EGLDisplay egl_display; EGLDisplay egl_display;
EGLImageKHR dma_images[MAX_VIDEO];
EGLImageKHR dma_images_swap[MAX_VIDEO];
#endif /* VIDEO_IN */
} ShaderProgram; } ShaderProgram;
// video.c // video.c
@@ -132,18 +140,28 @@ typedef struct ShaderProgram {
typedef struct VideoCapture { typedef struct VideoCapture {
char name[STR_LEN]; char name[STR_LEN];
bool error; bool error;
bool disconnected;
bool needs_reload;
bool with_swap;
bool swap;
unsigned int fps;
int fd; int fd;
int exp_fd; int exp_fd;
int exp_fd_swap;
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
unsigned int pixelformat; unsigned int pixelformat;
unsigned int bytesperline; unsigned int bytesperline;
bool output; #ifdef VIDEO_IN
struct v4l2_buffer buf; struct v4l2_buffer buf;
EGLImageKHR dma_image; struct v4l2_buffer buf_swap;
#endif /* VIDEO_IN */
} VideoCapture; } VideoCapture;
typedef ARRAY(VideoCaptureArray, VideoCapture); typedef struct VideoCaptureArray {
VideoCapture values[MAX_VIDEO];
unsigned int length;
} VideoCaptureArray;
// window.c // window.c
@@ -166,13 +184,10 @@ typedef struct Tempo {
typedef struct SharedContext { typedef struct SharedContext {
int fd; int fd;
vec2 resolution; vec2 resolution;
vec2 tex_resolution; vec2 tex_resolution;
vec2 input_resolutions[MAX_VIDEO]; vec2 input_resolutions[MAX_VIDEO];
double time; double time;
unsigned int fps;
Tempo tempo; Tempo tempo;
double tempo_total; double tempo_total;
UintArray state; UintArray state;
@@ -182,11 +197,10 @@ typedef struct SharedContext {
vec3 values[ARRAY_SIZE]; vec3 values[ARRAY_SIZE];
bool demo; bool demo;
bool auto_random; bool auto_random;
unsigned int auto_random_cycle;
unsigned int seeds[MAX_FRAG]; unsigned int seeds[MAX_FRAG];
bool monitor; unsigned int fps;
VideoCaptureArray inputs;
unsigned int input_formats[MAX_VIDEO];
unsigned int input_fps[MAX_VIDEO];
bool stop; bool stop;
} SharedContext; } SharedContext;
@@ -210,6 +224,20 @@ typedef struct StateConfig {
unsigned int value_count; unsigned int value_count;
unsigned int tap_tempo_code; unsigned int tap_tempo_code;
char save_file_prefix[STR_LEN];
unsigned int hotkey_randomize;
unsigned int hotkey_reset;
unsigned int hotkey_demo;
unsigned int hotkey_autorand;
unsigned int hotkey_autorand_up;
unsigned int hotkey_autorand_down;
unsigned int hotkey_tempo_up;
unsigned int hotkey_tempo_down;
UintArray hotkey_load;
UintArray hotkey_save;
} StateConfig; } StateConfig;
// timer.c // timer.c
@@ -224,6 +252,7 @@ typedef struct Timer {
typedef struct ConfigFile { typedef struct ConfigFile {
struct hashmap *map; struct hashmap *map;
bool error;
} ConfigFile; } ConfigFile;
typedef struct ConfigFileItem { typedef struct ConfigFileItem {
@@ -253,4 +282,4 @@ typedef struct Project {
File fragment_shaders[MAX_FRAG][MAX_SUB_FILE + 1]; File fragment_shaders[MAX_FRAG][MAX_SUB_FILE + 1];
} Project; } Project;
#endif /* TYPES_H */ #endif /* TYPES_H */
+95 -65
View File
@@ -1,4 +1,5 @@
#include <bsd/string.h> #ifdef VIDEO_IN
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
@@ -15,6 +16,9 @@
#include "timer.h" #include "timer.h"
#include "video.h" #include "video.h"
static const unsigned int pixel_format = V4L2_PIX_FMT_YUYV;
static const enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
static void ioctl_error(VideoCapture *video_capture, const char *operation, static void ioctl_error(VideoCapture *video_capture, const char *operation,
const char *default_msg) { const char *default_msg) {
if (errno == EINVAL) { if (errno == EINVAL) {
@@ -70,9 +74,8 @@ static void open_device(VideoCapture *video_capture, const char *name) {
strlcpy(video_capture->name, name, STR_LEN); strlcpy(video_capture->name, name, STR_LEN);
video_capture->error = false; video_capture->error = false;
video_capture->fd = -1; video_capture->fd = -1;
video_capture->exp_fd = -1;
video_capture->fd = open(name, O_RDWR); video_capture->fd = open(name, O_RDWR | O_NONBLOCK);
if (video_capture->fd == -1) { if (video_capture->fd == -1) {
log_warn("(%s) Cannot open device", name); log_warn("(%s) Cannot open device", name);
video_capture->error = true; video_capture->error = true;
@@ -114,7 +117,7 @@ static bool get_available_sizes(VideoCapture *video_capture,
index = 0; index = 0;
fmt_enum.index = index; fmt_enum.index = index;
fmt_enum.pixel_format = V4L2_PIX_FMT_YUYV; fmt_enum.pixel_format = pixel_format;
found = false; found = false;
video_capture->width = 0; video_capture->width = 0;
@@ -146,7 +149,7 @@ static bool get_available_sizes(VideoCapture *video_capture,
memset(&fmt_enum, 0, sizeof(fmt_enum)); memset(&fmt_enum, 0, sizeof(fmt_enum));
fmt_enum.index = ++index; fmt_enum.index = ++index;
fmt_enum.pixel_format = V4L2_PIX_FMT_YUYV; fmt_enum.pixel_format = pixel_format;
} }
if (video_capture->height == 0) { if (video_capture->height == 0) {
@@ -161,26 +164,18 @@ static bool get_available_sizes(VideoCapture *video_capture,
static bool set_format(VideoCapture *video_capture) { static bool set_format(VideoCapture *video_capture) {
struct v4l2_format fmt; struct v4l2_format fmt;
video_capture->output = false;
memset(&fmt, 0, sizeof(fmt)); memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.type = buf_type;
fmt.fmt.pix.width = video_capture->width; fmt.fmt.pix.width = video_capture->width;
fmt.fmt.pix.height = video_capture->height; fmt.fmt.pix.height = video_capture->height;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.pixelformat = pixel_format;
fmt.fmt.pix.field = V4L2_FIELD_ANY; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) { if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) {
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ioctl_error(video_capture, "VIDIOC_S_FMT",
"Requested buffer type not supported");
video_capture->output = true; return false;
if (ioctl(video_capture->fd, VIDIOC_S_FMT, &fmt) == -1) {
ioctl_error(video_capture, "VIDIOC_S_FMT",
"Requested buffer type not supported");
return false;
}
} }
video_capture->width = fmt.fmt.pix.width; video_capture->width = fmt.fmt.pix.width;
@@ -202,10 +197,9 @@ static bool request_buffers(VideoCapture *video_capture) {
memset(&reqbuf, 0, sizeof(reqbuf)); memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT reqbuf.type = buf_type;
: V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP; reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = 1; reqbuf.count = 2;
if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) { if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
ioctl_error(video_capture, "VIDIOC_REQBUFS", ioctl_error(video_capture, "VIDIOC_REQBUFS",
@@ -215,19 +209,21 @@ static bool request_buffers(VideoCapture *video_capture) {
log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count); log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count);
video_capture->with_swap = reqbuf.count > 1;
return true; return true;
} }
static bool export_buffer(VideoCapture *video_capture) { static bool export_buffer(VideoCapture *video_capture, int *fd,
unsigned int index) {
struct v4l2_exportbuffer expbuf; struct v4l2_exportbuffer expbuf;
video_capture->exp_fd = -1; *fd = -1;
memset(&expbuf, 0, sizeof(expbuf)); memset(&expbuf, 0, sizeof(expbuf));
expbuf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT expbuf.type = buf_type;
: V4L2_BUF_TYPE_VIDEO_CAPTURE; expbuf.index = index;
expbuf.index = 0;
expbuf.flags = O_RDONLY; expbuf.flags = O_RDONLY;
if (ioctl(video_capture->fd, VIDIOC_EXPBUF, &expbuf) == -1) { if (ioctl(video_capture->fd, VIDIOC_EXPBUF, &expbuf) == -1) {
@@ -237,12 +233,23 @@ static bool export_buffer(VideoCapture *video_capture) {
return false; return false;
} }
video_capture->exp_fd = expbuf.fd; *fd = expbuf.fd;
return true; return true;
} }
static const enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; static bool export_buffers(VideoCapture *video_capture) {
bool result;
result = export_buffer(video_capture, &video_capture->exp_fd, 0);
if (result && video_capture->with_swap) {
result =
result && export_buffer(video_capture, &video_capture->exp_fd_swap, 1);
}
return result;
}
static bool open_stream(VideoCapture *video_capture) { static bool open_stream(VideoCapture *video_capture) {
if (ioctl(video_capture->fd, VIDIOC_STREAMON, &buf_type) == -1) { if (ioctl(video_capture->fd, VIDIOC_STREAMON, &buf_type) == -1) {
@@ -255,21 +262,53 @@ static bool open_stream(VideoCapture *video_capture) {
return true; return true;
} }
static void create_image_buffer(VideoCapture *video_capture) { static void create_image_buffer(const VideoCapture *video_capture,
memset(&video_capture->buf, 0, sizeof(video_capture->buf)); struct v4l2_buffer *buf, unsigned int index) {
memset(buf, 0, sizeof(*buf));
video_capture->buf.type = video_capture->output ? V4L2_BUF_TYPE_VIDEO_OUTPUT buf->type = buf_type;
: V4L2_BUF_TYPE_VIDEO_CAPTURE; buf->memory = V4L2_MEMORY_MMAP;
video_capture->buf.memory = V4L2_MEMORY_MMAP; buf->index = index;
video_capture->buf.index = 0;
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf); ioctl(video_capture->fd, VIDIOC_QBUF, buf);
}
static void create_image_buffers(VideoCapture *video_capture) {
create_image_buffer(video_capture, &video_capture->buf, 0);
if (video_capture->with_swap) {
create_image_buffer(video_capture, &video_capture->buf_swap, 1);
}
} }
static void close_stream(const VideoCapture *video_capture) { static void close_stream(const VideoCapture *video_capture) {
ioctl(video_capture->fd, VIDIOC_STREAMOFF, &buf_type); ioctl(video_capture->fd, VIDIOC_STREAMOFF, &buf_type);
} }
static unsigned int read_video(VideoCapture *video_capture) {
unsigned int result;
struct v4l2_capability cap;
result = 0;
if ((video_capture->swap || !video_capture->with_swap) &&
ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf) != -1) {
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf);
result = 1;
} else if (!video_capture->swap && video_capture->with_swap &&
ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf_swap) !=
-1) {
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf_swap);
result = 2;
} else if (ioctl(video_capture->fd, VIDIOC_QUERYCAP, &cap) == -1) {
video_capture->error = true;
}
return result;
}
void video_init(VideoCapture *video_capture, const char *name, void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height) { unsigned int preferred_height) {
open_device(video_capture, name); open_device(video_capture, name);
@@ -294,7 +333,7 @@ void video_init(VideoCapture *video_capture, const char *name,
return; return;
} }
if (!export_buffer(video_capture)) { if (!export_buffers(video_capture)) {
return; return;
} }
@@ -302,25 +341,7 @@ void video_init(VideoCapture *video_capture, const char *name,
return; return;
} }
create_image_buffer(video_capture); create_image_buffers(video_capture);
}
static bool read_video(VideoCapture *video_capture) {
if (ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf) == -1) {
ioctl_error(video_capture, "VIDIOC_DQBUF",
"buffer type not supported or no buffer allocated or the index "
"is out of bounds");
return false;
}
if (ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf) == -1) {
ioctl_error(video_capture, "VIDIOC_QBUF",
"buffer type not supported or no buffer allocated or the index "
"is out of bounds");
return false;
}
return true;
} }
bool video_background_read(VideoCapture *video_capture, SharedContext *context, bool video_background_read(VideoCapture *video_capture, SharedContext *context,
@@ -328,6 +349,7 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
pid_t pid; pid_t pid;
Timer timer; Timer timer;
double fps; double fps;
unsigned int video_result;
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
@@ -341,16 +363,19 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
pid); pid);
timer_init(&timer, 30); timer_init(&timer, 30);
while (!context->stop && read_video(video_capture)) { while (!context->stop && !video_capture->error) {
// repeat infinitely video_result = read_video(video_capture);
if (timer_inc(&timer)) { if (video_result > 0 && timer_inc(&timer)) {
fps = timer_reset(&timer); fps = timer_reset(&timer);
context->input_fps[input_index] = (unsigned int)round(fps); context->inputs.values[input_index].fps = (unsigned int)round(fps);
if (trace_fps) { if (trace_fps) {
log_trace("(%s) %.2ffps", video_capture->name, fps); log_trace("(%s) %.2ffps", video_capture->name, fps);
} }
} }
if (video_result > 0) {
video_capture->swap = video_result == 2;
}
} }
if (context->stop) { if (context->stop) {
log_info("(%s) background acquisition stopped by main thread (pid: %d)", log_info("(%s) background acquisition stopped by main thread (pid: %d)",
@@ -358,19 +383,24 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
} else { } else {
log_info("(%s) background acquisition stopped after error (pid: %d)", log_info("(%s) background acquisition stopped after error (pid: %d)",
video_capture->name, pid); video_capture->name, pid);
video_capture->disconnected = true;
video_capture->pixelformat = 0;
video_free(video_capture);
} }
exit(context->stop ? EXIT_SUCCESS : EXIT_FAILURE); exit(context->stop ? EXIT_SUCCESS : EXIT_FAILURE);
return false;
} }
void video_free(const VideoCapture *video_capture) { void video_free(const VideoCapture *video_capture) {
if (!video_capture->error) { close_stream(video_capture);
close_stream(video_capture);
}
if (video_capture->exp_fd != -1) { if (video_capture->exp_fd != -1) {
close(video_capture->exp_fd); close(video_capture->exp_fd);
} }
if (video_capture->exp_fd_swap != -1) {
close(video_capture->exp_fd);
}
if (video_capture->fd != -1) { if (video_capture->fd != -1) {
close(video_capture->fd); close(video_capture->fd);
} }
} }
#endif /* VIDEO_IN */
+1 -1
View File
@@ -11,4 +11,4 @@ bool video_background_read(VideoCapture *video_capture, SharedContext *context,
void video_free(const VideoCapture *video_capture); void video_free(const VideoCapture *video_capture);
#endif /* VIDEO_H */ #endif /* VIDEO_H */
+22 -4
View File
@@ -121,7 +121,8 @@ void window_events() { glfwPollEvents(); }
double window_get_time() { return glfwGetTime(); } double window_get_time() { return glfwGetTime(); }
void window_use(Window *window, SharedContext *context) { void window_use(Window *window, SharedContext *context) {
int width, height; int width;
int height;
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
glfwGetFramebufferSize(window, &width, &height); glfwGetFramebufferSize(window, &width, &height);
@@ -145,6 +146,23 @@ bool window_escape_key(int key, int action) {
return key == GLFW_KEY_ESCAPE && action == GLFW_PRESS; return key == GLFW_KEY_ESCAPE && action == GLFW_PRESS;
} }
bool window_char_key(int key, int action, const int char_code) { unsigned int window_read_key(int key, int action, int mods) {
return key == char_code && action == GLFW_PRESS; unsigned int result;
} if (action == GLFW_RELEASE || key == GLFW_KEY_LEFT_SHIFT ||
key == GLFW_KEY_RIGHT_SHIFT || key == GLFW_KEY_LEFT_CONTROL ||
key == GLFW_KEY_RIGHT_CONTROL || key == GLFW_KEY_LEFT_ALT ||
key == GLFW_KEY_RIGHT_ALT) {
return 0;
}
result = key;
if ((mods & GLFW_MOD_SHIFT) > 0) {
result += 1000;
}
if ((mods & GLFW_MOD_CONTROL) > 0) {
result += 10000;
}
if ((mods & GLFW_MOD_ALT) > 0) {
result += 100000;
}
return result;
}
+2 -2
View File
@@ -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 */