From ae810e1a9c68d05bee254ef570fbb0e783e25931 Mon Sep 17 00:00:00 2001 From: skal Date: Tue, 10 Feb 2026 17:47:15 +0100 Subject: feat: Add ShaderToy conversion tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add automated conversion pipeline for ShaderToy shaders to demo effects: - convert_shadertoy.py: Automated code generation script - Manual templates: Header, implementation, and WGSL boilerplate - Example shader: Test case for conversion workflow - README: Complete conversion guide with examples Handles basic GLSL→WGSL conversion (types, uniforms, mainImage extraction). Manual fixes needed for fragColor returns and complex type inference. Organized under tools/shadertoy/ for maintainability. Co-Authored-By: Claude Sonnet 4.5 --- tools/shadertoy/README.md | 191 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 tools/shadertoy/README.md (limited to 'tools/shadertoy/README.md') diff --git a/tools/shadertoy/README.md b/tools/shadertoy/README.md new file mode 100644 index 0000000..e734684 --- /dev/null +++ b/tools/shadertoy/README.md @@ -0,0 +1,191 @@ +# ShaderToy Conversion Guide + +Quick guide to convert ShaderToy shaders to demo effects. + +## Quick Start (Automated) + +```bash +# Save ShaderToy code to a file +cat > tunnel.txt << 'EOF' +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord / iResolution.xy; + vec3 col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0,2,4)); + fragColor = vec4(col, 1.0); +} +EOF + +# Generate effect files +./tools/shadertoy/convert_shadertoy.py tunnel.txt Tunnel + +# Follow printed instructions to integrate +``` + +## Files + +**Automated Script:** +- `convert_shadertoy.py` - Generates all files from ShaderToy code +- `example.txt` - Example ShaderToy shader for testing + +**Manual Templates:** +- `template.h` - Header boilerplate +- `template.cc` - Implementation boilerplate +- `template.wgsl` - Shader boilerplate with conversion notes + +## Manual Steps + +### 1. Copy Templates + +```bash +# Choose effect name (e.g., "tunnel", "plasma", "warp") +EFFECT_NAME="myeffect" + +cp tools/shadertoy/template.h src/gpu/effects/${EFFECT_NAME}_effect.h +cp tools/shadertoy/template.cc src/gpu/effects/${EFFECT_NAME}_effect.cc +cp tools/shadertoy/template.wgsl workspaces/main/shaders/${EFFECT_NAME}.wgsl +``` + +### 2. Rename Class + +In both `.h` and `.cc`: +- `ShaderToyEffect` → `MyEffectEffect` +- `SHADERTOY_EFFECT_H_` → `MYEFFECT_EFFECT_H_` +- `shadertoy_effect.h` → `myeffect_effect.h` + +### 3. Convert Shader + +In `.wgsl`, paste ShaderToy `mainImage()` into `fs_main()`: + +**ShaderToy:** +```glsl +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord / iResolution.xy; + fragColor = vec4(uv, 0.5, 1.0); +} +``` + +**WGSL:** +```wgsl +@fragment fn fs_main(@builtin(position) p: vec4) -> @location(0) vec4 { + let uv = p.xy / uniforms.resolution; + return vec4(uv, 0.5, 1.0); +} +``` + +### 4. Update Asset Name + +In `.cc`, update `AssetId::ASSET_SHADERTOY_SHADER` to match your shader filename: +```cpp +AssetId::ASSET_MYEFFECT_SHADER +``` + +### 5. Add to Assets + +In `workspaces/main/assets.txt`: +``` +shaders/myeffect.wgsl +``` + +### 6. Register Effect + +In `src/gpu/demo_effects.h`: +```cpp +#include "gpu/effects/myeffect_effect.h" +``` + +In `workspaces/main/timeline.seq`: +``` +SEQUENCE 0.0 0 + EFFECT MyEffectEffect 0.0 10.0 0 +``` + +### 7. Update Tests + +In `tests/test_demo_effects.cc`: +- Add `"MyEffectEffect"` to test list +- Increment `EXPECTED_*_COUNT` + +### 8. Build & Test + +```bash +cmake --build build -j4 +./build/demo64k + +# Run tests +cmake -S . -B build -DDEMO_BUILD_TESTS=ON +cmake --build build -j4 +cd build && ctest +``` + +## Example Conversion + +**Input ShaderToy:** +```glsl +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord / iResolution.xy; + vec3 col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0,2,4)); + fragColor = vec4(col, 1.0); +} +``` + +**Generated WGSL (after script + manual fixes):** +```wgsl +@fragment fn fs_main(@builtin(position) p: vec4) -> @location(0) vec4 { + let uv = p.xy / uniforms.resolution; + let col = vec3(0.5) + 0.5 * cos(uniforms.time + uv.xyx + vec3(0.0, 2.0, 4.0)); + return vec4(col, 1.0); +} +``` + +## Common Conversions + +| ShaderToy | WGSL | +|-----------|------| +| `iResolution.xy` | `uniforms.resolution` | +| `iTime` | `uniforms.time` | +| `fragCoord` | `p.xy` | +| `float` | `f32` | +| `vec2` | `vec2` | +| `mod(x, y)` | `x % y` | +| `texture(iChannel0, uv)` | `textureSample(txt, smplr, uv)` | +| `fragColor = ...` | `return ...` | +| `vec2 p = ...` | `let p = vec2(...)` or `var p: vec2 = ...` | + +## Custom Parameters + +For tunable values: + +**C++ (`.h`):** +```cpp +struct MyEffectParams { + float speed; + float scale; + float _pad[2]; +}; +static_assert(sizeof(MyEffectParams) == 16, "..."); +``` + +**WGSL:** +```wgsl +struct MyEffectParams { + speed: f32, + scale: f32, + _pad0: f32, + _pad1: f32, +} +@group(0) @binding(3) var params: MyEffectParams; +``` + +## Available Uniforms + +Always available in `uniforms: CommonUniforms`: +- `resolution: vec2` - Screen resolution +- `aspect_ratio: f32` - Width/height +- `time: f32` - Demo time (seconds) +- `beat: f32` - Music beat sync (0-1) +- `audio_intensity: f32` - Audio reactivity + +## Next Steps + +- See `doc/CONTRIBUTING.md` for commit policy +- See `doc/SEQUENCE.md` for timeline syntax +- See existing effects in `src/gpu/effects/` for examples -- cgit v1.2.3