Skip to content

gwiazdorrr/CxxSwizzle

Repository files navigation

CxxSwizzle

vs2019 vs2022 clang-latest gcc-latest no-parallelism-apple-clang

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. "Doom Shadertoy"

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

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 use CxxSwizzle in your project, this directory is all you need.
  • sandbox_template: a cross-platform shadertoy sandbox project template, using SDL2, Dear ImGui, imgui-sdl and optionally Vc (not to be confused with VC++/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 to
  • textures: placeholder directory where textures are downloaded to
  • test: test project
  • cmake : some very painfully concieved CMake macros that download shaders using Shadertoy API and apply tivial code fixes, if enabled. Uses json-cmake.

Setup

  1. Clone the repository
git clone https://github.com/gwiazdorrr/CxxSwizzle.git
  1. Init vcpkg and imgui_sdl submodules
git submodule update --init
  1. Install vcpkg dependencies (non-Windows platforms), e.g. Debian:
sudo apt-get install curl zip unzip tar
  1. 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 out simd 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

  1. Set SHADERTOY_DOWNLOAD_IDS to an id of any shadertoy with public+api visiblity (e.g. WtVfRc). If you want to download a batch, separate ids with a semicolon.
  2. Click Configure in cmake-gui or run cmake

Use case: query and download shadertoys

  1. Set SHADERTOY_DOWNLOAD_QUERY_TYPE to top_love, top_popular, top_newest or top_hot.
  2. Leave SHADERTOY_DOWNLOAD_QUERY_ARG empty or set it to a search term.
  3. Set SHADERTOY_DOWNLOAD_QUERY_MAX_COUNT to limit how many shaders you want to download.
  4. Click Configure in cmake-gui or run cmake

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 as static 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 a struct 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.

  1. 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 in SHADERTOY_TEXTURES_ROOT.
  2. Create a directory in SHADERTOY_ROOT, say SHADERTOY_ROOT/foo. That's where passes and config need to be saved to.
  3. 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
  4. 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 of simd_vc sandbox modes
  • ENABLE_PARALLELISM: if there are any problems related to <execution> header or std::execution::par_unseq, unchecking this option should help - at a cost of single-threaded rendering.
  • BUILD_SAMPLES_SIMD: builds SIMD samples. Uses Vc lib to make that happen. When configuring on Windows, you might expect something like this in the log (harmless, a result of Vc 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
  • 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
  • Sampler options
    • Filter
      • mipmap Note: there's generally no support for mipmaps at the moment
      • linear
      • nearest
    • Wrap
    • VFlip

About

Modern C++ swizzling header-only library

Resources

License

Stars

Watchers

Forks

Packages

No packages published