This project lets you download and run GLSL shadertoys as C++17 code. Out of 1000 top shadertoys (on 26.11.2021), 840 compile without any code alterations and 953 compile if code patching is enabled. Code after patching is still GLSL-compatible and can be pasted back to the Shadertoy.
Here is the brilliant "DooM" shadertoy port by P_Malin, run as C++ code.

Another example, "Creation" by Danilo Guanabara, being debugged in Visual Studio:

The repository is structured in the following way:
include: header-only, dependency free headers that replicate GLSL syntax, types and built-in functions in C++, as completely as humanely possible. If you wish to useCxxSwizzlein your project, this directory is all you need.sandbox_template: a cross-platform shadertoy sandbox project template, usingSDL2,Dear ImGui, imgui-sdl and optionally Vc (not to be confused withVC++/MSVC).vcpkgis used to resolve the dependencies. Shared by the samples and downloaded shadertoys.samples: a set of some of the best shadertoys, with a license permissive enough to have them included here.shadertoys: placeholder directory where shadertoys are downloaded totextures: placeholder directory where textures are downloaded totest: test projectcmake: some very painfully concieved CMake macros that download shaders using Shadertoy API and apply tivial code fixes, if enabled. Uses json-cmake.
- Clone the repository
git clone https://github.com/gwiazdorrr/CxxSwizzle.git
- Init vcpkg and imgui_sdl submodules
git submodule update --init
- Install vcpkg dependencies (non-Windows platforms), e.g. Debian:
sudo apt-get install curl zip unzip tar
- Configure with CMake toolchain file and a generator of your choice. For example, using
ninja:
cmake -G Ninja -B build -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake
cd build
ninja
If you are using CMake GUI, after clicking Configure select Specify toolchain file for cross-compiling and make sure the path in the next window points to vcpkg/scripts/buildsystems/vcpkg.cmake.
If you are on MacOS and using homebrew > 3.0, vcpkg (as of 11.2022) will have hard time finding pkg-config, so make sure to define following environment variables:
export PKG_CONFIG=/opt/homebrew/bin/pkg-config
TL;DR: set SHADERTOY_DOWNLOAD to any of top_* options and run cmake.
Downloading shadertoys takes place in CMake's configure step (not great, not terrible). Note that only shadertoys with public+api visibility can be downloaded this way. The process in controlled with following properties:
SHADERTOY_DOWNLOAD_IDSis either a single shadertoy ID (e.g.WtVfRc) or a list of shadertoy IDs (semicolon-separated)SHADERTOY_DOWNLOAD_QUERY_TYPEspecifies the type of query (most loved, newest etc.) to run using Shadertoy API to obtain a list of shadertoys to download.
Setting any of the above will trigger the download process. To avoid redownloading same shaders during next CMake's configure phase, both properties are forcefully set to an empty string and "none", respectively. After CMake's generate step is complete, each shadertoy should now be ready to build as a standalone C++ project.
Another properties relevant to downloading Shadertoys:
SHADERTOY_DOWNLOAD_QUERY_ARG- an optional search term for the query.SHADERTOY_DOWNLOAD_QUERY_MAX_COUNT- the upper limit of how many shadertoys to download.SHADERTOY_ROOT- a directory where shadertoys are downloaded to (./shadertoysby default)SHADERTOY_TEXTURES_ROOT- a directory where textures are downloaded to (./texturesby default)SHADERTOY_APPLY_TRIVIAL_FIXEScan be cheched to avoid headaches with most common GLSL to C++ problems (enabled by default).SHADERTOY_API_KEY(advanced) is the API key used to access Shadertoy API. If the default key gets rate-limited, you will need to create your own key and set the parameter.SHADERTOY_SETUP(advanced) specifies which sandbox setup to use. The default one (scalar) has no support for partial derivatives, but branches/loop work out of the box. If you are feeling adventurous check outsimdvariants.SHADERTOY_HTTP_USERAGENT(advanced) specifies custom User-Agent string used in HTTP requests. This is useful in case the default ("curl/x.xx.x") results in 403 response codes.
- Set
SHADERTOY_DOWNLOAD_IDSto an id of any shadertoy withpublic+apivisiblity (e.g. WtVfRc). If you want to download a batch, separate ids with a semicolon. - Click
Configureincmake-guior runcmake
- Set
SHADERTOY_DOWNLOAD_QUERY_TYPEtotop_love,top_popular,top_newestortop_hot. - Leave
SHADERTOY_DOWNLOAD_QUERY_ARGempty or set it to a search term. - Set
SHADERTOY_DOWNLOAD_QUERY_MAX_COUNTto limit how many shaders you want to download. - Click
Configureincmake-guior runcmake
If SHADERTOY_APPLY_TRIVIAL_FIXES is enabled, shaders of a shadertoy are patched according to these rules:
- Replaces
^^operator with!=. Could be replaced with C++'s^, but that's not compatible with GLSL. - Any global const is replaced with
CXX_CONST(defined asstatic inline constexpr). - Function forward declaration are wrapped with
CXX_IGNORE. This is not a C++ issue, but rather a consequence of how shaders get included (in astructscope) - Arrays: the biggest headache. There are two alternative ways of declaring an array in GLSL. On top of that initialization syntax is not compatible with C++. Arrays have
length()method, which is used surprisingly often. Sadly, seems there's no silver bullet here, if you want the replacement macros to be compatible with the limited preprocessor GLSL uses.int [size] foo->CXX_ARRAY_N(int, size) fooint foo[size]->CXX_ARRAY_N(int, size) foo- global
int [] foo = int[](0, 1, 2, 3)->CXX_ARRAY_FIELD(int, foo)(0, 1, 2, 3) - global
int foo [] = int[](0, 1, 2, 3)->CXX_ARRAY_FIELD(int, foo)(0, 1, 2, 3) int [] foo->CXX_ARRAY(int) fooint foo[]->CXX_ARRAY(int) fooint[](0, 1, 2, 3)->CXX_MAKE_ARRAY(int)(0, 1, 2, 3)
Note that all these macros are easily GLSL compatible:
#define CXX_CONST const
#define CXX_IGNORE(x) x
#define CXX_ARRAY_FIELD(type, name) type[] name
#define CXX_ARRAY(type) type[]
#define CXX_ARRAY_N(type, size) type[size]
#define CXX_MAKE_ARRAY(type) type[]If a shadertoy can't be downloaded there's always an option of downloading it manually.
- If the shadertoy uses textures, they will need to be downloaded somehow. The easiest way is to use browser's DevTools (F12), switch to
Networktab and refresh the shadertoy webpage. Textures should be easily found in the list of requests. Save them inSHADERTOY_TEXTURES_ROOT. - Create a directory in
SHADERTOY_ROOT, saySHADERTOY_ROOT/foo. That's where passes and config need to be saved to. - Copy passes and save them in following files:
Image->image.fragBuffer A->buffer_a.fragBuffer B->buffer_b.fragBuffer C->buffer_c.fragBuffer D->buffer_d.frag
- Create
shadertoy_config.hppfile. This is where passes are configured. The most barebones contents are:
shadertoy_config shadertoy_config::make_default()
{
shadertoy_config config;
return config;
}If the shadertoy uses textures / buffers, iChannels settings need to be replicated.
- Input: Pass
config.get_pass(pass_type::image).get_sampler(0) = sampler_config::make_buffer(pass_type::buffer_a)
.init(texture_wrap_modes::clamp, texture_filter_modes::nearest, true);- Input: Texture
config.get_pass(pass_type::buffer_a).get_sampler(1) = sampler_config::make_texture(
"foo.jpg")
.init(texture_wrap_modes::repeat, texture_filter_modes::mipmap, false);- Input: Cubemap
config.get_pass(pass_type::image).get_sampler(3) = sampler_config::make_cubemap({
"face_0.png",
"face_1.png",
"face_2.png",
"face_3.png",
"face_4.png",
"face_5.png"})
.init(texture_wrap_modes::clamp, texture_filter_modes::linear, false);- Input: Keyboard
config.get_pass(pass_type::buffer_c).get_sampler(3) = sampler_config::make_keyboard()
.init(texture_wrap_modes::clamp, texture_filter_modes::nearest, true);After that's done, run cmake.
TRACY_PROFILER_ROOT: setting to Tracy Profiler path will enable the profiler integration.Vc_IMPL: enforces specific SIMD instruction set (AVX2, SSE3 etc.) if using one ofsimd_vcsandbox modesENABLE_PARALLELISM: if there are any problems related to<execution>header orstd::execution::par_unseq, unchecking this option should help - at a cost of single-threaded rendering.BUILD_SAMPLES_SIMD: builds SIMD samples. UsesVclib to make that happen. When configuring on Windows, you might expect something like this in the log (harmless, a result ofVcscripts being a tad outdated):
c
1: fatal error C1083: Cannot open source file: 'C:/SRC/CxxSwizzle/build/vcpkg_installed/x64-windows/share/vc/msvc_version.c': No such file or directory
Parts of GLSL Lang Spec 4.60 CxxSwizzle attempted at replicating:
- Baisc Types [4.1]
- scalar types
-
vec2..4 -
ivec2..4 -
uvec2..4 -
bvec2..4 -
dvec2..4 -
mat2..4 -
mat2..4x2..4 -
dmat2..4 -
dmat2..4x2..4 -
sampler1D(as sampler_generic) -
sampler2D(as sampler_generic) -
samplerCube(as sampler_generic) -
sampler3D - other sampler types
- Implicit Conversions [4.1.10]
- Parameter Qualifiers [4.6]
-
const -
in -
out -
inout
-
- Precision Qualifiers [4.7]
-
highp(no effect) -
mediump(no effect) -
lowp(no effect)
-
- Operators [5.1]
- Constructors [5.4]
- Conversion and Scalar Constructors [5.4.1]
- Vector and Matrix Constructors [5.4.2] needs tests
- Structure Constructors [5.4.3] (see Workarounds)
- Array Constructors [5.4.4]
- One-dimensional (see Workarounds)
- Multi-dimensional
- Vector and Scalar Components and Length [5.5]
- Swizzling
- Vector
lengthmethod - Scalar
xcompoment
- Matrix Components [5.6]
- Structure and Array Operations [5.7]
- Array length method (see Workarounds)
- Equality operator
- Other operators
- Vector and Matrix Operations [5.10] needs more tests
- Function Definitions [6.1]
- Prototypes (see Workarounds)
- Definitions
- Jumps [6.4]
-
discard
-
- Built-in Variables [7]
-
gl_FragCoord -
gl_FragColor - Other variables
-
- Built-in Functions
- Angle and Trigonometry Functions [8.1]
- Exponential Functions [8.2]
- Common Functions [8.3]
-
fma -
frexp,ldexp - Other functions
-
- Floating-Point Pack and Unpack Functions [8.4]
- Geometric Functions [8.5]
-
ftransform - Other functions
-
- Matrix Functions [8.6]
-
matrixCompMult -
outerProduct -
transpose -
determinant -
inverse
-
- Vector Relational Functions [8.7]
- Integer Functions [8.8]
- Texture Functions [8.9] (sampler ignores lod and partial derivatives)
-
textureSize -
texture -
texelFetch(robust buffer access needs implementing) -
textureLod -
textureGrad - Other functions
-
- Fragment Processing Functions [8.13] (SIMD only)
-
dfDx -
dfDy -
fwidth - Coarse and Fine derivatives
- Interpolation Functions
-
- Downloading Shaders with "public+api" visibility
- By id
- Single
- Batch
- Query
- Name
- Sort (Popular, Newest, Love, Hot)
- From-To
- Filters
- By id
- Shader Inputs
- iResolution
- iTime
- iTimeDelta
- iFrame
- iChannelTime Note: always 0
- iChannelResolution
- iMouse
- iChannel0...3
- iDate
- iSampleRate Note: always 0
- iFrameRate
- Sources
- Common
- Buffer A
- Buffer B
- Buffer C
- Buffer D
- Sound
- Cubemap A
- Channels
- Misc
- Keyboard
- Webcam
- Microphone
- Soundcloud
- Buffer A
- Buffer B
- Buffer C
- Buffer D
- Cubemap A
- Textures
- Cubemaps
- Volumes
- Videos
- Music
- Misc
- Sampler options
- Filter
- mipmap Note: there's generally no support for mipmaps at the moment
- linear
- nearest
- Wrap
- VFlip
- Filter