Awesome
CxxSwizzle
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 useCxxSwizzle
in 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
).vcpkg
is 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.
Setup
- 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
Downloading shadertoys
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_IDS
is either a single shadertoy ID (e.g.WtVfRc
) or a list of shadertoy IDs (semicolon-separated)SHADERTOY_DOWNLOAD_QUERY_TYPE
specifies 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 (./shadertoys
by default)SHADERTOY_TEXTURES_ROOT
- a directory where textures are downloaded to (./textures
by default)SHADERTOY_APPLY_TRIVIAL_FIXES
can 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 outsimd
variants.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.
Use case: download specific shadertoys
- Set
SHADERTOY_DOWNLOAD_IDS
to an id of any shadertoy withpublic+api
visiblity (e.g. WtVfRc). If you want to download a batch, separate ids with a semicolon. - Click
Configure
incmake-gui
or runcmake
Use case: query and download shadertoys
- Set
SHADERTOY_DOWNLOAD_QUERY_TYPE
totop_love
,top_popular
,top_newest
ortop_hot
. - Leave
SHADERTOY_DOWNLOAD_QUERY_ARG
empty or set it to a search term. - Set
SHADERTOY_DOWNLOAD_QUERY_MAX_COUNT
to limit how many shaders you want to download. - Click
Configure
incmake-gui
or runcmake
Automatic trivial fixes
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 astruct
scope) - 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) foo
int 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) foo
int foo[]
->CXX_ARRAY(int) foo
int[](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[]
Adding non public+api shadertoys
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
Network
tab 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.frag
Buffer A
->buffer_a.frag
Buffer B
->buffer_b.frag
Buffer C
->buffer_c.frag
Buffer D
->buffer_d.frag
- Create
shadertoy_config.hpp
file. 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
.
Other notable CMake options
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_vc
sandbox 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. UsesVc
lib to make that happen. When configuring on Windows, you might expect something like this in the log (harmless, a result ofVc
scripts 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
GLSL support status
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
length
method - Scalar
x
compoment
- 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
-
Shadertoy integration status
- 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