Compare commits
26 Commits
2025-10-21
...
ee8b09aa8f
| Author | SHA1 | Date | |
|---|---|---|---|
| ee8b09aa8f | |||
| 92450cccb8 | |||
| a68d10d38a | |||
| e51ee84167 | |||
| cec347a97c | |||
| 4f844fe17e | |||
| dff5d6fab2 | |||
| ef37a7a2e6 | |||
| 8d42d5741f | |||
| f18d6143d1 | |||
| 0a03509323 | |||
| 8f3d013c8e | |||
| 9110d689a5 | |||
| b290cee689 | |||
| 194726f823 | |||
| 44de2c7013 | |||
| 0a269449a3 | |||
| 4164cc8e88 | |||
| b625916b18 | |||
| 92093e7b3f | |||
| be8be3a48d | |||
| 47787abd73 | |||
| fe256704ac | |||
| 8d17b6c047 | |||
| 98a16148cc | |||
| f86da327ff |
28
.gitignore
vendored
28
.gitignore
vendored
@@ -5,18 +5,24 @@
|
|||||||
/CMakeFiles/
|
/CMakeFiles/
|
||||||
/CMakeCache.txt
|
/CMakeCache.txt
|
||||||
/cmake_install.cmake
|
/cmake_install.cmake
|
||||||
/Makefile
|
|
||||||
/*.cmake
|
/*.cmake
|
||||||
/*.obj
|
/*.obj
|
||||||
/*.o
|
/*.o
|
||||||
/*.lo
|
/*.lo
|
||||||
/*.a
|
/*.a
|
||||||
/*.lib
|
/*.lib
|
||||||
/*.dll
|
*.pdb
|
||||||
/*.so
|
|
||||||
/*.dylib
|
# Binarios compilados
|
||||||
/*.exe
|
*.dll
|
||||||
/*.pdb
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.exe
|
||||||
|
shadertoy
|
||||||
|
Shadertoy
|
||||||
|
|
||||||
|
# Permitir DLLs de distribucion en release/
|
||||||
|
!release/**/*.dll
|
||||||
|
|
||||||
# Generated by CMake/IDE
|
# Generated by CMake/IDE
|
||||||
/compile_commands.json
|
/compile_commands.json
|
||||||
@@ -29,9 +35,16 @@ third_party/**/build/
|
|||||||
third_party/**/CMakeFiles/
|
third_party/**/CMakeFiles/
|
||||||
third_party/**/CMakeCache.txt
|
third_party/**/CMakeCache.txt
|
||||||
|
|
||||||
|
# Release artifacts
|
||||||
|
dist/
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.dmg
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
.vscode/
|
.vscode/
|
||||||
.idea/
|
.idea/
|
||||||
|
.claude/
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
*.userprefs
|
*.userprefs
|
||||||
@@ -62,6 +75,3 @@ coverage.info
|
|||||||
venv/
|
venv/
|
||||||
env/
|
env/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
||||||
# Avoid committing local SDL runtime if you copy it next to the exe
|
|
||||||
SDL3.dll
|
|
||||||
|
|||||||
290
CLAUDE.md
Normal file
290
CLAUDE.md
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This is a cross-platform Shadertoy-like fragment shader viewer built with SDL3. It supports two rendering backends:
|
||||||
|
- **SDL3 GPU** (default): renders via Vulkan on Linux/Windows and Metal on macOS.
|
||||||
|
- **OpenGL 3.3** (fallback): the original backend, used automatically if SDL3 GPU init fails.
|
||||||
|
|
||||||
|
Selection at launch:
|
||||||
|
```bash
|
||||||
|
./shadertoy --backend=gpu # force SDL3 GPU
|
||||||
|
./shadertoy --backend=opengl # force OpenGL
|
||||||
|
./shadertoy --backend=auto # default: GPU first, fall back to OpenGL on failure
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build and Development Commands
|
||||||
|
|
||||||
|
### Building (CMake - Development)
|
||||||
|
```bash
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --build . --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building (Makefile - Release Packages)
|
||||||
|
```bash
|
||||||
|
make windows_release # Creates .zip with DLLs
|
||||||
|
make macos_release # Creates .dmg with app bundle
|
||||||
|
make linux_release # Creates .tar.gz
|
||||||
|
make show_version # Display build version (YYYY-MM-DD format)
|
||||||
|
```
|
||||||
|
|
||||||
|
Platform-specific debug builds:
|
||||||
|
```bash
|
||||||
|
make windows_debug
|
||||||
|
make macos_debug
|
||||||
|
make linux_debug
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiling Shaders to SPIR-V
|
||||||
|
The SDL3 GPU backend reads compiled SPIR-V (`.frag.spv`) at runtime. Run this after touching any `.vk.glsl` file:
|
||||||
|
```bash
|
||||||
|
cmake --build build --target compile_shaders
|
||||||
|
```
|
||||||
|
Requires `glslc` (Debian/Ubuntu: `apt install glslang-tools`; macOS: `brew install glslang`).
|
||||||
|
|
||||||
|
### Running the Application
|
||||||
|
```bash
|
||||||
|
./shadertoy [SHADER_NAME_OR_PATH] [-F|--fullscreen] [--backend=auto|gpu|opengl]
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
./shadertoy test # auto backend, data/shaders/test/
|
||||||
|
./shadertoy --backend=gpu seascape # force SDL3 GPU (Vulkan/Metal)
|
||||||
|
./shadertoy -F data/shaders/fractal_pyramid # explicit folder path, fullscreen
|
||||||
|
```
|
||||||
|
|
||||||
|
**Runtime Controls:**
|
||||||
|
- `ESC` - Exit
|
||||||
|
- `F3` - Toggle fullscreen
|
||||||
|
- `LEFT/RIGHT ARROW` - Cycle through shaders in directory
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Layered design
|
||||||
|
- `source/main.cpp` — SDL3 window, event loop, shader-list scanning, dispatch to a backend.
|
||||||
|
- `source/rendering/shader_backend.hpp` — abstract `IShaderBackend` interface + `ShaderMetadata` / `ShaderUniforms` / `ShaderProgramSpec` shared types. Two factories: `makeOpenGLBackend()`, `makeSdl3GpuBackend()`.
|
||||||
|
- `source/rendering/opengl_shader_backend.{hpp,cpp}` — OpenGL 3.3 implementation. Loads `<folder>/<name>.gl.glsl` at runtime.
|
||||||
|
- `source/rendering/sdl3gpu/sdl3gpu_shader_backend.{hpp,cpp}` — SDL3 GPU implementation. Loads `<folder>/<name>.frag.spv` (Linux/Windows) or `<folder>/<name>.frag.msl` (macOS); shares one passthrough vertex shader from `shaders/_common/passthrough.vert.{spv,msl}`.
|
||||||
|
- `source/rendering/sdl3gpu/shader_factory.hpp` — small helper that loads a shader binary/source from disk and creates an `SDL_GPUShader`.
|
||||||
|
|
||||||
|
### Shader folder layout
|
||||||
|
One folder per shader, under `data/shaders/`:
|
||||||
|
```
|
||||||
|
data/shaders/<name>/
|
||||||
|
<name>.gl.glsl # OpenGL GLSL 3.30 (handwritten)
|
||||||
|
<name>.vk.glsl # Vulkan GLSL 4.50 (handwritten)
|
||||||
|
<name>.frag.msl # Metal Shading Language (handwritten)
|
||||||
|
<name>.frag.spv # generated by `make compile_shaders` from .vk.glsl
|
||||||
|
meta.txt # Name / Author / iChannelN
|
||||||
|
data/shaders/_common/
|
||||||
|
passthrough.vk.glsl # shared fullscreen-triangle vertex (Vulkan)
|
||||||
|
passthrough.vert.spv # generated
|
||||||
|
passthrough.vert.msl # handwritten Metal
|
||||||
|
```
|
||||||
|
Folders starting with `_` or `.` are skipped by the scanner. The `meta.txt` parser is in `Rendering::parseMetaFile`.
|
||||||
|
|
||||||
|
### Backend selection logic (`main.cpp`)
|
||||||
|
1. Parse `--backend=...` flag (default `auto`).
|
||||||
|
2. If not OpenGL: create a window with no flags, instantiate `Sdl3GpuShaderBackend`. If `init()` fails AND choice was `auto`, destroy the window and continue. If choice was `gpu`, exit with error.
|
||||||
|
3. Otherwise: create a window with `SDL_WINDOW_OPENGL` and instantiate `OpenGLShaderBackend`.
|
||||||
|
|
||||||
|
### Global State (main.cpp)
|
||||||
|
```cpp
|
||||||
|
shader_list_ // Vector<ShaderEntry { folder, base_name }>
|
||||||
|
current_shader_index_ // Active shader in rotation
|
||||||
|
shader_start_ticks_ // Base time for iTime uniform calculation
|
||||||
|
window_ // SDL3 window pointer
|
||||||
|
backend_ // unique_ptr<IShaderBackend>
|
||||||
|
shaders_directory_ // Shaders root path (resolved at startup)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
- **SDL3** ≥ 3.2 — windowing, events, GPU API (`SDL_gpu.h`)
|
||||||
|
- **GLAD** — OpenGL 3.3 loader (used only by the OpenGL backend, statically linked via `source/external/glad/`)
|
||||||
|
- **C++17 stdlib** — filesystem, fstream, vector, algorithms
|
||||||
|
- Build-time tool: `glslc` (only required to regenerate `.frag.spv`)
|
||||||
|
|
||||||
|
### Platform-Specific Code
|
||||||
|
Uses preprocessor defines (`WINDOWS_BUILD`, `MACOS_BUILD`, `LINUX_BUILD`) for:
|
||||||
|
- `getExecutableDirectory()` - Windows API, mach-o dyld, or /proc/self/exe
|
||||||
|
- `getResourcesDirectory()` - Special macOS app bundle handling (Contents/Resources)
|
||||||
|
- Linking flags - Windows uses static linking, macOS links OpenGL framework
|
||||||
|
|
||||||
|
## Shader System
|
||||||
|
|
||||||
|
### Authoring a shader (manual steps)
|
||||||
|
For each new shader, three handwritten files live in `data/shaders/<name>/`:
|
||||||
|
1. **`<name>.gl.glsl`** — OpenGL GLSL 3.30 (the original Shadertoy-style format described below).
|
||||||
|
2. **`<name>.vk.glsl`** — Vulkan GLSL 4.50 with explicit `layout(set=3, binding=0) uniform ShadertoyUBO { float iTime; vec2 iResolution; } u;` and `layout(set=2, binding=N) uniform sampler2D` for any texture channel.
|
||||||
|
3. **`<name>.frag.msl`** — Metal Shading Language. Entry point must be named `<name>_fs`. Uniforms come in via `[[buffer(0)]]`; samplers via `[[texture(N)]] [[sampler(N)]]`.
|
||||||
|
|
||||||
|
After editing any `.vk.glsl`, rebuild SPIR-V: `cmake --build build --target compile_shaders`.
|
||||||
|
|
||||||
|
The MSL is **not** auto-generated — write it by hand following the same convention as `aee_2026/source/core/rendering/sdl3gpu/msl/*.msl.h`.
|
||||||
|
|
||||||
|
### Shadertoy → Vulkan/Metal porting cheatsheet
|
||||||
|
- `iResolution` is `vec2` here (no `.xy`). Reconstruct vec3 manually if needed.
|
||||||
|
- Replace `texture(iChannel0, ...)` calls — no texture channels currently wired through the GPU backend (planned).
|
||||||
|
- The shared vertex stage emits `vUV` already in Shadertoy convention `(0,0)` bottom-left → `(1,1)` top-right; multiply by `iResolution` to get `fragCoord`.
|
||||||
|
- The Y axis is flipped in NDC inside the shared vertex shader so Vulkan/Metal render right-side-up like OpenGL.
|
||||||
|
|
||||||
|
### Shader Format (GLSL 3.3 Core)
|
||||||
|
All shaders must follow this structure:
|
||||||
|
|
||||||
|
```glsl
|
||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV; // Normalized [0,1] coordinates from vertex shader
|
||||||
|
uniform vec2 iResolution; // Window resolution in pixels
|
||||||
|
uniform float iTime; // Time since shader loaded (seconds)
|
||||||
|
|
||||||
|
// Shadertoy-style entry point
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
// fragCoord is in pixel coordinates
|
||||||
|
// Your shader code here
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper converts vUV to pixel coordinates
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding New Shaders
|
||||||
|
1. Create `.glsl` file in `data/shaders/<name>/` directory (use `.frag.glsl` convention)
|
||||||
|
2. Follow required format above
|
||||||
|
3. File automatically appears in runtime shader rotation (arrow keys to navigate)
|
||||||
|
4. **No code changes required** - directory is scanned at startup
|
||||||
|
|
||||||
|
### Shader Loading Pipeline
|
||||||
|
1. Directory scan on startup (`scanShaderDirectory()`)
|
||||||
|
2. Sort alphabetically
|
||||||
|
3. Load fragment shader source from disk
|
||||||
|
4. Compile vertex shader (fixed, embedded in main.cpp)
|
||||||
|
5. Compile fragment shader with error logging
|
||||||
|
6. Link program with error handling
|
||||||
|
7. Update uniforms each frame (iResolution, iTime)
|
||||||
|
|
||||||
|
### Supported Shadertoy Features
|
||||||
|
- ✅ `iTime` - Time uniform
|
||||||
|
- ✅ `iResolution` - Window resolution (vec2, not vec3)
|
||||||
|
- ✅ `mainImage()` function signature
|
||||||
|
- ❌ `iMouse` - Not implemented
|
||||||
|
- ❌ `iChannel0-3` - No texture channels (multi-pass not supported)
|
||||||
|
- ❌ `iFrame`, `iTimeDelta`, `iDate` - Not implemented
|
||||||
|
|
||||||
|
### Converting from Shadertoy
|
||||||
|
When porting Shadertoy shaders:
|
||||||
|
1. Copy the `mainImage()` function as-is
|
||||||
|
2. Add standard header (see format above)
|
||||||
|
3. Add wrapper `main()` function
|
||||||
|
4. Remove texture channel references (iChannel0-3)
|
||||||
|
5. Change `iResolution.xy` to `iResolution` (this project uses vec2)
|
||||||
|
|
||||||
|
### Common Conversion Issues and Solutions
|
||||||
|
|
||||||
|
Based on experience converting complex shaders like ddla_light_tunnel:
|
||||||
|
|
||||||
|
#### iResolution vec3 vs vec2
|
||||||
|
- **Shadertoy:** `iResolution` is `vec3(width, height, width/height)`
|
||||||
|
- **This project:** `iResolution` is `vec2(width, height)`
|
||||||
|
- **Solution:** Create vec3 manually: `vec3 r = vec3(iResolution.xy, iResolution.x/iResolution.y);`
|
||||||
|
- **Then use:** `r.xy` for resolution, `r.y` for height (as in original)
|
||||||
|
|
||||||
|
#### Uninitialized Variables
|
||||||
|
- **Problem:** Shadertoy code may have `vec3 rgb;` without initialization
|
||||||
|
- **Shadertoy behavior:** Likely initializes to `vec3(0.0)` (black)
|
||||||
|
- **This project:** Uninitialized variables contain undefined values (often causes black screen or wrong colors)
|
||||||
|
- **Solution:** Always initialize: `vec3 rgb = vec3(0.0);`
|
||||||
|
- **Wrong approach:** Don't use random noise unless shader explicitly uses iChannel texture for noise
|
||||||
|
|
||||||
|
#### Low mix() Factors Are Intentional
|
||||||
|
- **Example:** `rgb = mix(rgb, calculated_color, 0.01);` means 1% new color, 99% existing
|
||||||
|
- **Don't change these factors** - they create subtle effects intentionally
|
||||||
|
- **If output is black:** Problem is likely the base value (rgb), not the mix factor
|
||||||
|
|
||||||
|
#### iChannel Textures
|
||||||
|
- **Shadertoy shows iChannel0-3** in UI, but shader may not use them
|
||||||
|
- **If iChannel3 has RGB noise but code doesn't reference it:** The noise is not actually used
|
||||||
|
- **Check code for `texture(iChannelN, ...)` calls** - if none exist, ignore the iChannel setup
|
||||||
|
- **Procedural noise replacement:** Only if shader explicitly samples the texture
|
||||||
|
|
||||||
|
#### Color Swapping Issues
|
||||||
|
- **If colors are completely wrong:** Don't randomly swap color variables
|
||||||
|
- **First verify:** Code matches original Shadertoy exactly (except required GLSL changes)
|
||||||
|
- **Common mistake:** Changing color applications that were correct in original
|
||||||
|
- **Debug approach:** Revert to exact original code, only modify for GLSL 3.3 compatibility
|
||||||
|
|
||||||
|
#### Division by Small Values - Color Overflow Artifacts
|
||||||
|
- **Problem:** Division by values near zero causes extreme values → color overflow artifacts (green points, strange colors)
|
||||||
|
- **Example:** `.01*vec4(6,2,1,0)/length(u*sin(iTime))` can divide by ~0.0 when near center and sin≈0
|
||||||
|
- **Symptoms:** Bright white center that pulses to green, or random color artifacts in specific areas
|
||||||
|
- **Root cause:** Even with tonemap (tanh/clamp), extreme intermediate values cause precision issues or saturation
|
||||||
|
- **Solution - Double Protection:**
|
||||||
|
1. **Add epsilon to denominator:** `max(denominator, 0.001)` prevents division by exact zero
|
||||||
|
2. **Clamp the result:** `min(result, vec4(50.0))` prevents extreme accumulation
|
||||||
|
3. **Only clamp problematic terms:** Don't clamp everything or scene becomes dim
|
||||||
|
- **Example fix:**
|
||||||
|
```glsl
|
||||||
|
// Original (causes overflow):
|
||||||
|
o += .01*vec4(6,2,1,0)/length(u*sin(t+t+t)) + 1./s * length(u);
|
||||||
|
|
||||||
|
// Fixed (prevents overflow while maintaining brightness):
|
||||||
|
vec4 brightTerm = min(.01*vec4(6,2,1,0)/max(length(u*sin(t+t+t)), 0.001), vec4(50.0));
|
||||||
|
o += brightTerm + 1./s * length(u);
|
||||||
|
```
|
||||||
|
- **Key values:** epsilon ~0.001 (not too small, not too large), clamp ~50.0 (allows brightness without explosion)
|
||||||
|
- **Why this works in Shadertoy:** WebGL/browsers may handle float overflow differently than native OpenGL drivers
|
||||||
|
|
||||||
|
#### Debugging Black/Wrong Output
|
||||||
|
1. **Check compilation errors first** - shader must compile without errors
|
||||||
|
2. **Initialize all variables** - especially vec3 colors
|
||||||
|
3. **Verify vec3 iResolution handling** - create vec3 from vec2 if needed
|
||||||
|
4. **Don't modify mix factors** - keep original values
|
||||||
|
5. **Compare with original code** - ensure logic is identical
|
||||||
|
6. **Test progressive changes** - add header, test; add wrapper, test; etc.
|
||||||
|
7. **Check for division by small values** - if you see color artifacts (especially green), look for divisions that can approach zero
|
||||||
|
|
||||||
|
## Build System Details
|
||||||
|
|
||||||
|
### Version Numbering
|
||||||
|
Releases use build date format: `shadertoy-YYYY-MM-DD-{platform}` (auto-generated by Makefile)
|
||||||
|
|
||||||
|
### Release Artifacts
|
||||||
|
- **Windows:** `.zip` with `shadertoy.exe` + `SDL3.dll` + shaders
|
||||||
|
- **macOS:** `.dmg` with app bundle containing embedded SDL3.framework (arm64 only)
|
||||||
|
- **Linux:** `.tar.gz` with binary + shaders
|
||||||
|
|
||||||
|
### Resource Bundling
|
||||||
|
- Shaders copied to release packages
|
||||||
|
- LICENSE and README.md included
|
||||||
|
- Platform-specific dependencies bundled (DLLs on Windows, frameworks on macOS)
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
### Vertex Shader
|
||||||
|
The vertex shader is hardcoded in `main.cpp` and creates a fullscreen quad. It:
|
||||||
|
- Takes `vec2 aPos` (location 0) in NDC space [-1, 1]
|
||||||
|
- Outputs `vec2 vUV` normalized to [0, 1]
|
||||||
|
- No transformation matrices needed
|
||||||
|
|
||||||
|
### Shader Hot-Reloading
|
||||||
|
Currently **not implemented**. Shader changes require application restart. The architecture would support adding this via file watching.
|
||||||
|
|
||||||
|
### Multi-Pass Rendering
|
||||||
|
Single-pass only. To add multi-pass (BufferA/B/C like Shadertoy):
|
||||||
|
- Create FBOs and textures per buffer
|
||||||
|
- Render buffers in dependency order
|
||||||
|
- Pass textures as `iChannel0-3` uniforms
|
||||||
|
- Use ping-pong for feedback loops
|
||||||
|
|
||||||
|
### OpenGL Context
|
||||||
|
Created via SDL3 with core profile (no deprecated functions). Context version: 3.3 core.
|
||||||
235
CMakeLists.txt
235
CMakeLists.txt
@@ -1,143 +1,120 @@
|
|||||||
cmake_minimum_required(VERSION 3.14)
|
# CMakeLists.txt
|
||||||
project(shadertoy_sdl3 LANGUAGES C CXX)
|
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(shadertoy VERSION 1.00)
|
||||||
|
|
||||||
|
# Estàndard de C++
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
# Default to Release for single-config generators when none specified
|
# Política CMP0072: usar GLVND (libOpenGL/libGLX) en lloc de la libGL clàssica.
|
||||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
cmake_policy(SET CMP0072 NEW)
|
||||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
set(OpenGL_GL_PREFERENCE GLVND)
|
||||||
endif()
|
|
||||||
|
|
||||||
# Paths
|
# Opció per a empaquetat de bundle macOS (.app). El Makefile la passa amb -DMACOS_BUNDLE=ON.
|
||||||
set(GLAD_SRC "${CMAKE_CURRENT_SOURCE_DIR}/third_party/glad/src/glad.c")
|
option(MACOS_BUNDLE "Build for macOS .app bundle (rpath into ../Frameworks)" OFF)
|
||||||
if(NOT EXISTS "${GLAD_SRC}")
|
|
||||||
message(FATAL_ERROR "glad.c no encontrado en: ${GLAD_SRC}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# glad library
|
# --- LISTA EXPLÍCITA DE FUENTES ---
|
||||||
add_library(glad_src STATIC "${GLAD_SRC}")
|
set(APP_SOURCES
|
||||||
target_include_directories(glad_src PUBLIC
|
source/main.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/third_party/glad/include
|
source/rendering/shader_backend.cpp
|
||||||
|
source/rendering/opengl_shader_backend.cpp
|
||||||
|
source/rendering/sdl3gpu/sdl3gpu_shader_backend.cpp
|
||||||
|
source/audio/jail_audio.cpp
|
||||||
)
|
)
|
||||||
set_target_properties(glad_src PROPERTIES LINKER_LANGUAGE C)
|
|
||||||
|
|
||||||
# Executable
|
# Fuentes de librerías de terceros
|
||||||
add_executable(shadertoy_sdl3
|
set(EXTERNAL_SOURCES
|
||||||
src/main.cpp
|
source/external/glad/src/glad.c
|
||||||
|
source/external/stb_vorbis_impl.cpp
|
||||||
)
|
)
|
||||||
target_include_directories(shadertoy_sdl3 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/glad/include)
|
|
||||||
|
|
||||||
# SDL3
|
# Configuració de SDL3
|
||||||
find_package(SDL3 REQUIRED)
|
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
|
||||||
target_link_libraries(shadertoy_sdl3 PRIVATE glad_src SDL3::SDL3)
|
message(STATUS "SDL3 trobat: ${SDL3_INCLUDE_DIRS}")
|
||||||
|
|
||||||
# Platform-specific flags and linkers (try to mimic your Makefile)
|
# --- COMPILACIÓ DE SHADERS (Vulkan SPIR-V) ---
|
||||||
if(WIN32)
|
# Es fa a cada build: compile_shaders.cmake fa check de timestamps, no
|
||||||
target_compile_definitions(shadertoy_sdl3 PRIVATE WINDOWS_BUILD)
|
# recompila el que ja està al dia.
|
||||||
if(MSVC)
|
find_program(GLSLC_EXE NAMES glslc)
|
||||||
# MSVC: reasonable defaults; adjust as needed
|
if(GLSLC_EXE)
|
||||||
target_compile_options(shadertoy_sdl3 PRIVATE /W3 /permissive-)
|
message(STATUS "glslc trobat: ${GLSLC_EXE}")
|
||||||
# Link to system libraries (MSVC uses system libs automatically for system includes)
|
add_custom_target(compile_shaders ALL
|
||||||
target_link_libraries(shadertoy_sdl3 PRIVATE opengl32)
|
COMMAND ${CMAKE_COMMAND}
|
||||||
else()
|
-D GLSLC=${GLSLC_EXE}
|
||||||
# MinGW / GNU on Windows
|
-D SHADERS_DIR=${CMAKE_SOURCE_DIR}/data/shaders
|
||||||
target_compile_options(shadertoy_sdl3 PRIVATE -std=c++17 -Wall -Os -ffunction-sections -fdata-sections)
|
-P ${CMAKE_SOURCE_DIR}/tools/shaders/compile_shaders.cmake
|
||||||
target_link_options(shadertoy_sdl3 PRIVATE "-Wl,--gc-sections" "-Wl,-Bstatic" "-Wl,-Bdynamic")
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
target_link_libraries(shadertoy_sdl3 PRIVATE -lmingw32 -lws2_32 -lSDL3 -lopengl32)
|
COMMENT "Compiling .vk.glsl shaders to SPIR-V")
|
||||||
endif()
|
|
||||||
else()
|
else()
|
||||||
# POSIX platforms
|
message(STATUS "glslc no trobat — el target compile_shaders no estarà disponible")
|
||||||
target_compile_options(shadertoy_sdl3 PRIVATE -std=c++17 -Wall -Os)
|
endif()
|
||||||
if(APPLE)
|
|
||||||
find_library(COCOA_LIBRARY Cocoa REQUIRED)
|
# --- RECURSO DE WINDOWS (icona) ---
|
||||||
find_library(IOKIT_LIBRARY IOKit REQUIRED)
|
# A Windows compilem release/windows/shadertoy.rc amb windres via CMake.
|
||||||
find_library(CORE_VIDEO_LIBRARY CoreVideo REQUIRED)
|
# El .rc fa referència a icon.ico per nom; afegim --include-dir perquè el
|
||||||
target_link_libraries(shadertoy_sdl3 PRIVATE ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${CORE_VIDEO_LIBRARY})
|
# trobi a release/icons/.
|
||||||
target_compile_options(shadertoy_sdl3 PRIVATE -arch arm64)
|
if(WIN32)
|
||||||
else()
|
enable_language(RC)
|
||||||
|
set(WIN_RC_FILE ${CMAKE_SOURCE_DIR}/release/windows/shadertoy.rc)
|
||||||
|
set_source_files_properties(${WIN_RC_FILE} PROPERTIES
|
||||||
|
COMPILE_FLAGS "--include-dir=${CMAKE_SOURCE_DIR}/release/icons")
|
||||||
|
list(APPEND APP_SOURCES ${WIN_RC_FILE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# --- AÑADIR EJECUTABLE ---
|
||||||
|
add_executable(${PROJECT_NAME} ${APP_SOURCES} ${EXTERNAL_SOURCES})
|
||||||
|
|
||||||
|
# --- DIRECTORIOS DE INCLUSIÓN ---
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
|
"${CMAKE_SOURCE_DIR}/source"
|
||||||
|
"${CMAKE_SOURCE_DIR}/source/external/glad/include"
|
||||||
|
"${CMAKE_SOURCE_DIR}/source/external"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Enllaçar la llibreria SDL3
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE SDL3::SDL3)
|
||||||
|
|
||||||
|
|
||||||
|
# --- CONFIGURACIÓ PLATAFORMES I COMPILADOR ---
|
||||||
|
# Flags de compilació
|
||||||
|
target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
|
||||||
|
target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:RELEASE>:-Os -ffunction-sections -fdata-sections>)
|
||||||
|
|
||||||
|
# Definir _DEBUG en mode Debug
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:DEBUG>:_DEBUG>)
|
||||||
|
|
||||||
|
|
||||||
|
# Configuració específica per a cada plataforma
|
||||||
|
if(WIN32)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE WINDOWS_BUILD)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 mingw32 opengl32)
|
||||||
|
elseif(APPLE)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD)
|
||||||
|
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated)
|
||||||
|
if(NOT CMAKE_OSX_ARCHITECTURES)
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
||||||
|
endif()
|
||||||
|
if(MACOS_BUNDLE)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUNDLE)
|
||||||
|
target_link_options(${PROJECT_NAME} PRIVATE
|
||||||
|
-rpath @executable_path/../Frameworks/
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
elseif(UNIX AND NOT APPLE)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Configuració comuna per a OpenGL
|
||||||
|
if(NOT WIN32)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
target_link_libraries(shadertoy_sdl3 PRIVATE OpenGL::GL)
|
if(OPENGL_FOUND)
|
||||||
endif()
|
message(STATUS "OpenGL trobat: ${OPENGL_LIBRARIES}")
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENGL_LIBRARIES})
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "OpenGL no trobat")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Ensure RUNTIME output directory for single-config builds (Release/Debug)
|
# El binari surt a l'arrel del projecte (com fins ara).
|
||||||
set_target_properties(shadertoy_sdl3 PROPERTIES
|
set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin/Release"
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin/Debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
set(RELEASE_DIR "${CMAKE_BINARY_DIR}/release_package")
|
|
||||||
set(WINDOWS_ZIP "${CMAKE_BINARY_DIR}/${PROJECT_NAME}-${CMAKE_SYSTEM_PROCESSOR}-win.zip")
|
|
||||||
set(DLL_SOURCE_DIR "${CMAKE_SOURCE_DIR}/release") # coloca tus SDL3.dll aquí
|
|
||||||
|
|
||||||
# PowerShell script que realizará las copias y el ZIP de forma robusta.
|
|
||||||
set(PS_SCRIPT "${CMAKE_BINARY_DIR}/package_windows.ps1")
|
|
||||||
file(WRITE "${PS_SCRIPT}"
|
|
||||||
"param(\n"
|
|
||||||
" [string]\$srcExe,\n"
|
|
||||||
" [string]\$releaseDir,\n"
|
|
||||||
" [string]\$readme,\n"
|
|
||||||
" [string]\$license,\n"
|
|
||||||
" [string]\$shadersDir,\n"
|
|
||||||
" [string]\$dllDir,\n"
|
|
||||||
" [string]\$outZip\n"
|
|
||||||
")\n"
|
|
||||||
"\n"
|
|
||||||
"# Remove old\n"
|
|
||||||
"if (Test-Path \$releaseDir) { Remove-Item -Recurse -Force \$releaseDir }\n"
|
|
||||||
"New-Item -ItemType Directory -Path \$releaseDir | Out-Null\n"
|
|
||||||
"\n"
|
|
||||||
"# Copy exe\n"
|
|
||||||
"Write-Host 'Copying executable...'\n"
|
|
||||||
"Copy-Item -Path \$srcExe -Destination (Join-Path \$releaseDir (Split-Path \$srcExe -Leaf)) -Force\n"
|
|
||||||
"\n"
|
|
||||||
"# Copy README / LICENSE if exist\n"
|
|
||||||
"if (Test-Path \$readme) { Copy-Item -Path \$readme -Destination (Join-Path \$releaseDir 'README.md') -Force }\n"
|
|
||||||
"if (Test-Path \$license) { Copy-Item -Path \$license -Destination (Join-Path \$releaseDir 'LICENSE') -Force }\n"
|
|
||||||
"\n"
|
|
||||||
"# Copy shaders if present\n"
|
|
||||||
"if (Test-Path \$shadersDir) { Copy-Item -Path (Join-Path \$shadersDir '*') -Destination (Join-Path \$releaseDir 'shaders') -Recurse -Force }\n"
|
|
||||||
"\n"
|
|
||||||
"# Copy DLLs if present\n"
|
|
||||||
"if (Test-Path \$dllDir) { Copy-Item -Path (Join-Path \$dllDir '*') -Destination (Join-Path \$releaseDir 'release') -Recurse -Force }\n"
|
|
||||||
"\n"
|
|
||||||
"# Create ZIP\n"
|
|
||||||
"Write-Host 'Creating zip: ' \$outZip\n"
|
|
||||||
"if (Test-Path \$outZip) { Remove-Item -Force \$outZip }\n"
|
|
||||||
"Compress-Archive -Path (Join-Path \$releaseDir '*') -DestinationPath \$outZip\n"
|
|
||||||
"Write-Host 'Package created: ' \$outZip\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_target(package_windows
|
|
||||||
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config Release
|
|
||||||
COMMAND powershell.exe -NoProfile -ExecutionPolicy Bypass -File "${PS_SCRIPT}"
|
|
||||||
-srcExe "$<TARGET_FILE:shadertoy_sdl3>"
|
|
||||||
-releaseDir "${RELEASE_DIR}"
|
|
||||||
-readme "${CMAKE_SOURCE_DIR}/README.md"
|
|
||||||
-license "${CMAKE_SOURCE_DIR}/LICENSE"
|
|
||||||
-shadersDir "${CMAKE_SOURCE_DIR}/shaders"
|
|
||||||
-dllDir "${DLL_SOURCE_DIR}"
|
|
||||||
-outZip "${WINDOWS_ZIP}"
|
|
||||||
COMMENT "Building Release and creating Windows package"
|
|
||||||
BYPRODUCTS "${WINDOWS_ZIP}"
|
|
||||||
)
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Helpful messages
|
|
||||||
message(STATUS "CMake generator: ${CMAKE_GENERATOR}")
|
|
||||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
|
||||||
message(STATUS "Binary output (runtime): ${CMAKE_BINARY_DIR}/bin")
|
|
||||||
|
|
||||||
# Developer target: build Release and then package on Windows
|
|
||||||
add_custom_target(build_release
|
|
||||||
COMMAND ${CMAKE_COMMAND} --build "${CMAKE_BINARY_DIR}" --config Release
|
|
||||||
COMMENT "Building Release configuration"
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
add_dependencies(package_windows build_release)
|
|
||||||
endif()
|
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
|
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
|
||||||
|
|
||||||
Copyright (c) 2025 Coffee Crisis Arcade Edition
|
Copyright (c) 2025 Shadertoy
|
||||||
|
|
||||||
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
||||||
|
|
||||||
|
|||||||
189
Makefile
Normal file
189
Makefile
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
# ==============================================================================
|
||||||
|
# Makefile per a Shadertoy
|
||||||
|
#
|
||||||
|
# Tres targets:
|
||||||
|
# make → Release (cmake)
|
||||||
|
# make debug → Debug (cmake)
|
||||||
|
# make release → Release + empaquetat per a distribució a dist/
|
||||||
|
#
|
||||||
|
# El SO es detecta automàticament. La compilació sempre passa per CMake.
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
PROJECT := shadertoy
|
||||||
|
APP_NAME := Shadertoy
|
||||||
|
DIR_ROOT := $(dir $(abspath $(MAKEFILE_LIST)))
|
||||||
|
BUILDDIR := build
|
||||||
|
DIST_DIR := dist
|
||||||
|
RELEASE_FOLDER := $(DIST_DIR)/_tmp
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# DETECCIÓ DE PLATAFORMA + GENERADOR CMAKE + JOBS
|
||||||
|
# ==============================================================================
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
# MSYS2/Git Bash usa /dev/null, cmd.exe pur usa NUL.
|
||||||
|
ifneq ($(MSYSTEM),)
|
||||||
|
NULDEV := /dev/null
|
||||||
|
else
|
||||||
|
NULDEV := NUL
|
||||||
|
endif
|
||||||
|
JOBS ?= $(NUMBER_OF_PROCESSORS)
|
||||||
|
HAS_NINJA := $(shell ninja --version 2>$(NULDEV))
|
||||||
|
ifneq ($(HAS_NINJA),)
|
||||||
|
CMAKE_GEN := -G "Ninja"
|
||||||
|
else
|
||||||
|
CMAKE_GEN := -G "MinGW Makefiles"
|
||||||
|
endif
|
||||||
|
UNAME_S := Windows
|
||||||
|
SHELL := cmd.exe
|
||||||
|
else
|
||||||
|
NULDEV := /dev/null
|
||||||
|
JOBS ?= $(shell nproc 2>/dev/null || echo 4)
|
||||||
|
CMAKE_GEN :=
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# VERSIÓ (data, format YYYY.MM.DD)
|
||||||
|
# ==============================================================================
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
VERSION := $(shell powershell -Command "Get-Date -Format 'yyyy.MM.dd'")
|
||||||
|
else
|
||||||
|
VERSION := $(shell date +%Y.%m.%d)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# NOMS DELS ARTEFACTES DE RELEASE
|
||||||
|
# ==============================================================================
|
||||||
|
WINDOWS_RELEASE := $(DIST_DIR)/$(PROJECT)-$(VERSION)-win32-x64.zip
|
||||||
|
MACOS_APPLE_SILICON_RELEASE := $(DIST_DIR)/$(PROJECT)-$(VERSION)-macos-apple-silicon.dmg
|
||||||
|
LINUX_RELEASE := $(DIST_DIR)/$(PROJECT)-$(VERSION)-linux.tar.gz
|
||||||
|
|
||||||
|
.PHONY: all debug release clean help _windows_release _macos_release _linux_release
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# COMPILACIÓ (delegada a CMake)
|
||||||
|
# ==============================================================================
|
||||||
|
all:
|
||||||
|
@cmake $(CMAKE_GEN) -S . -B $(BUILDDIR) -DCMAKE_BUILD_TYPE=Release
|
||||||
|
@cmake --build $(BUILDDIR) -j$(JOBS)
|
||||||
|
|
||||||
|
debug:
|
||||||
|
@cmake $(CMAKE_GEN) -S . -B $(BUILDDIR) -DCMAKE_BUILD_TYPE=Debug
|
||||||
|
@cmake --build $(BUILDDIR) -j$(JOBS)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# RELEASE (auto-dispatch per SO)
|
||||||
|
# ==============================================================================
|
||||||
|
release:
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
@"$(MAKE)" _windows_release
|
||||||
|
else
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
@$(MAKE) _macos_release
|
||||||
|
else
|
||||||
|
@$(MAKE) _linux_release
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -rf $(BUILDDIR) $(DIST_DIR)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# RELEASE LINUX
|
||||||
|
# ==============================================================================
|
||||||
|
_linux_release:
|
||||||
|
@echo "Creant release per a Linux - Versió: $(VERSION)"
|
||||||
|
@cmake $(CMAKE_GEN) -S . -B $(BUILDDIR) -DCMAKE_BUILD_TYPE=Release
|
||||||
|
@cmake --build $(BUILDDIR) -j$(JOBS)
|
||||||
|
@mkdir -p $(DIST_DIR)
|
||||||
|
@rm -rf $(RELEASE_FOLDER)
|
||||||
|
@mkdir -p $(RELEASE_FOLDER)
|
||||||
|
@cp -R data $(RELEASE_FOLDER)/
|
||||||
|
@cp LICENSE $(RELEASE_FOLDER)/
|
||||||
|
@cp README.md $(RELEASE_FOLDER)/
|
||||||
|
@cp $(PROJECT) $(RELEASE_FOLDER)/
|
||||||
|
@strip -s -R .comment -R .gnu.version $(RELEASE_FOLDER)/$(PROJECT) --strip-unneeded
|
||||||
|
@rm -f $(LINUX_RELEASE)
|
||||||
|
@tar -czf $(LINUX_RELEASE) -C $(RELEASE_FOLDER) .
|
||||||
|
@echo "Release creat: $(LINUX_RELEASE)"
|
||||||
|
@rm -rf $(RELEASE_FOLDER)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# RELEASE MACOS (Apple Silicon, .dmg amb .app bundle)
|
||||||
|
# ==============================================================================
|
||||||
|
_macos_release:
|
||||||
|
@echo "Creant release per a macOS - Versió: $(VERSION)"
|
||||||
|
@command -v create-dmg >/dev/null 2>&1 || { \
|
||||||
|
echo "Falta create-dmg. Instal·la amb: brew install create-dmg"; \
|
||||||
|
exit 1; \
|
||||||
|
}
|
||||||
|
@cmake -S . -B $(BUILDDIR) -DCMAKE_BUILD_TYPE=Release -DMACOS_BUNDLE=ON -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0
|
||||||
|
@cmake --build $(BUILDDIR) -j$(JOBS)
|
||||||
|
@mkdir -p $(DIST_DIR)
|
||||||
|
@rm -rf $(RELEASE_FOLDER)
|
||||||
|
@rm -f tmp.dmg "$(MACOS_APPLE_SILICON_RELEASE)" $(DIST_DIR)/rw.*
|
||||||
|
@mkdir -p "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||||
|
@mkdir -p "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS"
|
||||||
|
@mkdir -p "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||||
|
@cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources/"
|
||||||
|
@cp -R release/macos/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/"
|
||||||
|
@cp release/icons/icon.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources/"
|
||||||
|
@cp release/macos/Info.plist "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/"
|
||||||
|
@cp $(PROJECT) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(PROJECT)"
|
||||||
|
@cp LICENSE "$(RELEASE_FOLDER)/"
|
||||||
|
@cp README.md "$(RELEASE_FOLDER)/"
|
||||||
|
@RAW_VERSION=$$(echo "$(VERSION)" | sed 's/^v//'); \
|
||||||
|
sed -i '' '/<key>CFBundleShortVersionString<\/key>/{n;s|<string>.*</string>|<string>'"$$RAW_VERSION"'</string>|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"; \
|
||||||
|
sed -i '' '/<key>CFBundleVersion<\/key>/{n;s|<string>.*</string>|<string>'"$$RAW_VERSION"'</string>|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"
|
||||||
|
@codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app"
|
||||||
|
@create-dmg \
|
||||||
|
--volname "$(APP_NAME)" \
|
||||||
|
--window-pos 200 120 \
|
||||||
|
--window-size 720 300 \
|
||||||
|
--icon-size 96 \
|
||||||
|
--text-size 12 \
|
||||||
|
--icon "$(APP_NAME).app" 278 102 \
|
||||||
|
--icon "LICENSE" 441 102 \
|
||||||
|
--icon "README.md" 604 102 \
|
||||||
|
--app-drop-link 115 102 \
|
||||||
|
--hide-extension "$(APP_NAME).app" \
|
||||||
|
"$(MACOS_APPLE_SILICON_RELEASE)" \
|
||||||
|
"$(RELEASE_FOLDER)" || true
|
||||||
|
@echo "Release creat: $(MACOS_APPLE_SILICON_RELEASE)"
|
||||||
|
@rm -rf $(RELEASE_FOLDER)
|
||||||
|
@rm -f $(DIST_DIR)/rw.*
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# RELEASE WINDOWS (.zip amb DLLs)
|
||||||
|
# ==============================================================================
|
||||||
|
_windows_release:
|
||||||
|
@echo off
|
||||||
|
@echo Creant release per a Windows - Versió: $(VERSION)
|
||||||
|
@cmake $(CMAKE_GEN) -S . -B $(BUILDDIR) -DCMAKE_BUILD_TYPE=Release
|
||||||
|
@cmake --build $(BUILDDIR) -j$(JOBS)
|
||||||
|
@powershell -Command "if (-not (Test-Path '$(DIST_DIR)')) {New-Item '$(DIST_DIR)' -ItemType Directory | Out-Null}"
|
||||||
|
@powershell -Command "if (Test-Path '$(RELEASE_FOLDER)') {Remove-Item '$(RELEASE_FOLDER)' -Recurse -Force}"
|
||||||
|
@powershell -Command "New-Item '$(RELEASE_FOLDER)' -ItemType Directory | Out-Null"
|
||||||
|
@powershell -Command "Copy-Item -Path 'data' -Destination '$(RELEASE_FOLDER)' -Recurse"
|
||||||
|
@powershell -Command "Copy-Item 'LICENSE' -Destination '$(RELEASE_FOLDER)'"
|
||||||
|
@powershell -Command "Copy-Item 'README.md' -Destination '$(RELEASE_FOLDER)'"
|
||||||
|
@powershell -Command "Copy-Item 'release\windows\dll\*.dll' -Destination '$(RELEASE_FOLDER)'"
|
||||||
|
@powershell -Command "Copy-Item -Path '$(PROJECT).exe' -Destination '$(RELEASE_FOLDER)/$(APP_NAME).exe'"
|
||||||
|
@strip -s -R .comment -R .gnu.version "$(RELEASE_FOLDER)/$(APP_NAME).exe" --strip-unneeded
|
||||||
|
@powershell -Command "if (Test-Path '$(WINDOWS_RELEASE)') {Remove-Item '$(WINDOWS_RELEASE)'}"
|
||||||
|
@powershell -Command "Compress-Archive -Path '$(RELEASE_FOLDER)/*' -DestinationPath '$(WINDOWS_RELEASE)'"
|
||||||
|
@echo Release creat: $(WINDOWS_RELEASE)
|
||||||
|
@powershell -Command "Remove-Item '$(RELEASE_FOLDER)' -Recurse -Force"
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# AJUDA
|
||||||
|
# ==============================================================================
|
||||||
|
help:
|
||||||
|
@echo "Makefile per a $(PROJECT)"
|
||||||
|
@echo ""
|
||||||
|
@echo " make Compilar Release (cmake)"
|
||||||
|
@echo " make debug Compilar Debug (cmake)"
|
||||||
|
@echo " make release Compilar + empaquetar per a distribució a $(DIST_DIR)/"
|
||||||
|
@echo " make clean Esborrar $(BUILDDIR)/ i $(DIST_DIR)/"
|
||||||
|
@echo ""
|
||||||
|
@echo " Versió actual: $(VERSION)"
|
||||||
129
README.md
129
README.md
@@ -11,17 +11,27 @@ Proyecto minimal para ejecutar fragment shaders tipo Shadertoy usando SDL3 + GLA
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Características
|
||||||
|
|
||||||
|
- **Visualizador de shaders fragment** compatible con formato Shadertoy
|
||||||
|
- **Contador de FPS** en barra de título
|
||||||
|
- **Toggle VSync** con tecla F4
|
||||||
|
- **Cambio de shaders en runtime** con flechas ←/→
|
||||||
|
- **Sistema de metadata** en shaders (Name/Author automático en título)
|
||||||
|
- **Sistema de feedback** para shaders que requieren frame anterior (opcional)
|
||||||
|
- **Soporte de audio** con jail_audio (música de fondo)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Estructura
|
## Estructura
|
||||||
|
|
||||||
- src/ — código fuente C++ (incluye main.cpp).
|
- src/ — código fuente C++ (incluye main.cpp)
|
||||||
|
- shaders/ — shaders fragment (.frag.glsl) que se cargan en runtime
|
||||||
- shaders/ — shaders fragment (.frag.glsl) que se cargan en runtime.
|
- data/ — recursos (música, texturas, etc.)
|
||||||
|
- third_party/glad/ — glad.c + headers
|
||||||
- third_party/glad/ — glad.c + headers.
|
- third_party/ — jail_audio y otras dependencias
|
||||||
|
- CMakeLists.txt — configuración de build
|
||||||
- CMakeLists.txt — configuración de build.
|
- Makefile — builds de release para Windows/macOS/Linux
|
||||||
|
|
||||||
- .gitignore — recomendado.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -63,55 +73,74 @@ brew install cmake sdl3
|
|||||||
|
|
||||||
## Uso
|
## Uso
|
||||||
|
|
||||||
Por defecto el ejecutable carga shaders/test.frag.glsl.
|
Ejecutar con un shader específico:
|
||||||
|
|
||||||
|
./shadertoy shaders/fractal_pyramid.frag.glsl
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ejecutar en ventana:
|
Ejecutar en fullscreen:
|
||||||
|
|
||||||
./shadertoy_sdl3 ../shaders/test.frag.glsl
|
./shadertoy -F shaders/seascape.frag.glsl
|
||||||
|
# o
|
||||||
|
./shadertoy --fullscreen shaders/seascape.frag.glsl
|
||||||
|
|
||||||
Ejecutar en fullscreen nativo:
|
|
||||||
|
|
||||||
./shadertoy_sdl3 -F ../shaders/test.frag.glsl
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Si ejecutas desde la raíz del repo:
|
Si ejecutas desde la raíz del repo:
|
||||||
|
|
||||||
./build/shadertoy_sdl3 shaders/frag_tile_iter.frag.glsl
|
./build/shadertoy shaders/water.glsl
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Atajos en ejecución
|
### Atajos de teclado
|
||||||
|
|
||||||
- Escape — salir.
|
- **ESC** — Salir de la aplicación
|
||||||
|
- **F3** — Toggle fullscreen
|
||||||
- F11 — alternar fullscreen desktop.
|
- **F4** — Toggle VSync (ON/OFF)
|
||||||
|
- **← / →** — Cambiar al shader anterior/siguiente en la carpeta shaders/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Formato de shader esperado
|
## Formato de shader esperado
|
||||||
|
|
||||||
- #version 330 core
|
### Header obligatorio:
|
||||||
|
```glsl
|
||||||
|
// Name: Nombre del shader
|
||||||
|
// Author: Autor
|
||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
- Debe declarar:
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
```
|
||||||
|
|
||||||
uniform vec2 iResolution;
|
### Función mainImage (estilo Shadertoy):
|
||||||
|
```glsl
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
// Tu código aquí
|
||||||
|
// fragCoord está en píxeles
|
||||||
|
vec2 uv = fragCoord / iResolution.xy;
|
||||||
|
fragColor = vec4(uv, 0.5, 1.0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
uniform float iTime;
|
### Wrapper main():
|
||||||
|
```glsl
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
in vec2 vUV;
|
### Metadata opcional:
|
||||||
|
- `// Name: Nombre` - Aparece en barra de título
|
||||||
out vec4 FragColor;
|
- `// Author: Autor` - Aparece en barra de título
|
||||||
|
- `// iChannel3: self` - Habilita feedback (frame anterior)
|
||||||
- Función de entrada esperada (opcional, el main llama a mainImage):
|
|
||||||
|
|
||||||
void mainImage(out vec4 fragColor, in vec2 fragCoord);
|
|
||||||
|
|
||||||
- main() debe convertir vUV a fragCoord y llamar a mainImage.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -133,15 +162,33 @@ Si obtienes "Failed to load fragment shader file", ejecuta desde la carpeta buil
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Multi-pass / Buffers (nota)
|
## Compatibilidad con Shadertoy
|
||||||
|
|
||||||
Ejemplo actual es single-pass. Para portar Shadertoy con BufferA/B/C necesitas:
|
### Características soportadas:
|
||||||
|
✅ `iTime` - Tiempo en segundos
|
||||||
|
✅ `iResolution` - Resolución de ventana (vec2)
|
||||||
|
✅ `mainImage()` - Función de entrada estándar
|
||||||
|
✅ Self-feedback - Frame anterior con `// iChannel3: self`
|
||||||
|
|
||||||
- crear FBOs y textures por buffer
|
### No soportado actualmente:
|
||||||
|
❌ `iMouse` - Interacción con ratón
|
||||||
|
❌ `iChannel0-2` - Texturas externas
|
||||||
|
❌ Multi-pass completo (BufferA/B/C/D)
|
||||||
|
❌ `iFrame`, `iTimeDelta`, `iDate`
|
||||||
|
|
||||||
- renderizar buffers en orden y pasar las texturas como iChannelN a pases posteriores
|
### Diferencias importantes:
|
||||||
|
- **`iResolution`**: En Shadertoy es `vec3(width, height, width/height)`, aquí es `vec2(width, height)`
|
||||||
|
- Solución: `vec3 r = vec3(iResolution.xy, iResolution.x/iResolution.y);`
|
||||||
|
- **Inicialización de variables**: OpenGL nativo requiere inicializar variables explícitamente
|
||||||
|
- **División por valores pequeños**: Puede causar overflow - usar `max(divisor, epsilon)`
|
||||||
|
|
||||||
- evitar leer y escribir la misma textura (usar ping-pong si hace falta)
|
### Conversión de shaders de Shadertoy:
|
||||||
|
1. Copiar función `mainImage()` tal cual
|
||||||
|
2. Añadir header estándar (ver arriba)
|
||||||
|
3. Añadir wrapper `main()`
|
||||||
|
4. Eliminar referencias a `iChannel0-3` si no se usan
|
||||||
|
5. Adaptar `iResolution` de vec3 a vec2 si es necesario
|
||||||
|
6. Inicializar variables: `vec3 col = vec3(0.0);` en lugar de `vec3 col;`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
data/music/485077__mat397__confused-voices.ogg
Normal file
BIN
data/music/485077__mat397__confused-voices.ogg
Normal file
Binary file not shown.
BIN
data/music/485078__mat397__polyflute-pad.ogg
Normal file
BIN
data/music/485078__mat397__polyflute-pad.ogg
Normal file
Binary file not shown.
BIN
data/music/485079__mat397__melancholic-flutes-pad.ogg
Normal file
BIN
data/music/485079__mat397__melancholic-flutes-pad.ogg
Normal file
Binary file not shown.
BIN
data/music/486083__mat397__world-of-ants-pad.ogg
Normal file
BIN
data/music/486083__mat397__world-of-ants-pad.ogg
Normal file
Binary file not shown.
BIN
data/music/618041__mat397__mangle-dark-pad.ogg
Normal file
BIN
data/music/618041__mat397__mangle-dark-pad.ogg
Normal file
Binary file not shown.
BIN
data/music/618042__mat397__bad-electric-dark-pad.ogg
Normal file
BIN
data/music/618042__mat397__bad-electric-dark-pad.ogg
Normal file
Binary file not shown.
41
data/music/_readme_and_license.txt
Normal file
41
data/music/_readme_and_license.txt
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
Pack downloaded from Freesound
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
"Ambient pads"
|
||||||
|
|
||||||
|
This Pack of sounds contains sounds by the following user:
|
||||||
|
- Mat397 ( https://freesound.org/people/Mat397/ )
|
||||||
|
|
||||||
|
You can find this pack online at: https://freesound.org/people/Mat397/packs/27416/
|
||||||
|
|
||||||
|
|
||||||
|
Licenses in this Pack (see below for individual sound licenses)
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
Creative Commons 0: http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
Attribution 3.0: http://creativecommons.org/licenses/by/3.0/
|
||||||
|
|
||||||
|
|
||||||
|
Sounds in this Pack
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* 618042__mat397__bad-electric-dark-pad.wav.wav
|
||||||
|
* url: https://freesound.org/s/618042/
|
||||||
|
* license: Creative Commons 0
|
||||||
|
* 618041__mat397__mangle-dark-pad.wav.wav
|
||||||
|
* url: https://freesound.org/s/618041/
|
||||||
|
* license: Creative Commons 0
|
||||||
|
* 486083__mat397__world-of-ants-pad.wav.wav
|
||||||
|
* url: https://freesound.org/s/486083/
|
||||||
|
* license: Attribution 3.0
|
||||||
|
* 485079__mat397__melancholic-flutes-pad.wav.wav
|
||||||
|
* url: https://freesound.org/s/485079/
|
||||||
|
* license: Attribution 3.0
|
||||||
|
* 485078__mat397__polyflute-pad.wav.wav
|
||||||
|
* url: https://freesound.org/s/485078/
|
||||||
|
* license: Attribution 3.0
|
||||||
|
* 485077__mat397__confused-voices.wav.wav
|
||||||
|
* url: https://freesound.org/s/485077/
|
||||||
|
* license: Attribution 3.0
|
||||||
|
|
||||||
|
|
||||||
19
data/shaders/_common/passthrough.vert.msl
Normal file
19
data/shaders/_common/passthrough.vert.msl
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Shared fullscreen-triangle vertex shader for the SDL3 GPU backend.
|
||||||
|
// Emits uv in Shadertoy convention: (0,0) bottom-left, (1,1) top-right.
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex PassthroughVOut passthrough_vs(uint vid [[vertex_id]]) {
|
||||||
|
const float2 positions[3] = { {-1.0, -1.0}, {3.0, -1.0}, {-1.0, 3.0} };
|
||||||
|
PassthroughVOut out;
|
||||||
|
float2 pos = positions[vid];
|
||||||
|
out.uv = pos * 0.5 + 0.5;
|
||||||
|
out.pos = float4(pos, 0.0, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
BIN
data/shaders/_common/passthrough.vert.spv
Normal file
BIN
data/shaders/_common/passthrough.vert.spv
Normal file
Binary file not shown.
17
data/shaders/_common/passthrough.vk.glsl
Normal file
17
data/shaders/_common/passthrough.vk.glsl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Shared fullscreen-triangle vertex shader for the SDL3 GPU backend.
|
||||||
|
// Emits vUV in Shadertoy convention: (0,0) bottom-left, (1,1) top-right.
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 vUV;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
const vec2 positions[3] = vec2[3](
|
||||||
|
vec2(-1.0, -1.0),
|
||||||
|
vec2( 3.0, -1.0),
|
||||||
|
vec2(-1.0, 3.0)
|
||||||
|
);
|
||||||
|
vec2 pos = positions[gl_VertexIndex];
|
||||||
|
vUV = pos * 0.5 + 0.5;
|
||||||
|
gl_Position = vec4(pos, 0.0, 1.0);
|
||||||
|
}
|
||||||
75
data/shaders/cineshader_lava/cineshader_lava.frag.msl
Normal file
75
data/shaders/cineshader_lava/cineshader_lava.frag.msl
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Cineshader Lava — edankwan
|
||||||
|
// MSL port of cineshader_lava.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float opSmoothUnion(float d1, float d2, float k) {
|
||||||
|
float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0);
|
||||||
|
return mix(d2, d1, h) - k * h * (1.0 - h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float sdSphere(float3 p, float s) {
|
||||||
|
return length(p) - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float map(float3 p, float iTime) {
|
||||||
|
float d = 2.0;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
float fi = float(i);
|
||||||
|
float time = iTime * (fract(fi * 412.531 + 0.513) - 0.5) * 2.0;
|
||||||
|
d = opSmoothUnion(
|
||||||
|
sdSphere(p + sin(time + fi * float3(52.5126, 64.62744, 632.25)) * float3(2.0, 2.0, 0.8),
|
||||||
|
mix(0.5, 1.0, fract(fi * 412.531 + 0.5124))),
|
||||||
|
d,
|
||||||
|
0.4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 calcNormal(float3 p, float iTime) {
|
||||||
|
const float h = 1e-5;
|
||||||
|
const float2 k = float2(1, -1);
|
||||||
|
return normalize(k.xyy * map(p + k.xyy * h, iTime) +
|
||||||
|
k.yyx * map(p + k.yyx * h, iTime) +
|
||||||
|
k.yxy * map(p + k.yxy * h, iTime) +
|
||||||
|
k.xxx * map(p + k.xxx * h, iTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 cineshader_lava_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 uv = fragCoord / U.iResolution;
|
||||||
|
|
||||||
|
float3 rayOri = float3((uv - 0.5) * float2(U.iResolution.x / U.iResolution.y, 1.0) * 6.0, 3.0);
|
||||||
|
float3 rayDir = float3(0.0, 0.0, -1.0);
|
||||||
|
|
||||||
|
float depth = 0.0;
|
||||||
|
float3 p = float3(0.0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
p = rayOri + rayDir * depth;
|
||||||
|
float dist = map(p, U.iTime);
|
||||||
|
depth += dist;
|
||||||
|
if (dist < 1e-6) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
depth = min(6.0, depth);
|
||||||
|
float3 n = calcNormal(p, U.iTime);
|
||||||
|
float b = max(0.0, dot(n, float3(0.577)));
|
||||||
|
float3 col = (0.5 + 0.5 * cos((b + U.iTime * 3.0) + uv.xyx * 2.0 + float3(0, 2, 4))) * (0.85 + b * 0.35);
|
||||||
|
col *= exp(-depth * 0.15);
|
||||||
|
|
||||||
|
return float4(col, 1.0 - (depth - 0.5) / 2.0);
|
||||||
|
}
|
||||||
BIN
data/shaders/cineshader_lava/cineshader_lava.frag.spv
Normal file
BIN
data/shaders/cineshader_lava/cineshader_lava.frag.spv
Normal file
Binary file not shown.
83
data/shaders/cineshader_lava/cineshader_lava.gl.glsl
Normal file
83
data/shaders/cineshader_lava/cineshader_lava.gl.glsl
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
// Name: Cineshader Lava
|
||||||
|
// Author: edankwan
|
||||||
|
// URL: https://www.shadertoy.com/view/3sySRK
|
||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
float opSmoothUnion( float d1, float d2, float k )
|
||||||
|
{
|
||||||
|
float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
|
||||||
|
return mix( d2, d1, h ) - k*h*(1.0-h);
|
||||||
|
}
|
||||||
|
|
||||||
|
float sdSphere( vec3 p, float s )
|
||||||
|
{
|
||||||
|
return length(p)-s;
|
||||||
|
}
|
||||||
|
|
||||||
|
float map(vec3 p)
|
||||||
|
{
|
||||||
|
float d = 2.0;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
float fi = float(i);
|
||||||
|
float time = iTime * (fract(fi * 412.531 + 0.513) - 0.5) * 2.0;
|
||||||
|
d = opSmoothUnion(
|
||||||
|
sdSphere(p + sin(time + fi * vec3(52.5126, 64.62744, 632.25)) * vec3(2.0, 2.0, 0.8), mix(0.5, 1.0, fract(fi * 412.531 + 0.5124))),
|
||||||
|
d,
|
||||||
|
0.4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 calcNormal( in vec3 p )
|
||||||
|
{
|
||||||
|
const float h = 1e-5; // or some other value
|
||||||
|
const vec2 k = vec2(1,-1);
|
||||||
|
return normalize( k.xyy*map( p + k.xyy*h ) +
|
||||||
|
k.yyx*map( p + k.yyx*h ) +
|
||||||
|
k.yxy*map( p + k.yxy*h ) +
|
||||||
|
k.xxx*map( p + k.xxx*h ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
|
{
|
||||||
|
vec2 uv = fragCoord/iResolution.xy;
|
||||||
|
|
||||||
|
// screen size is 6m x 6m
|
||||||
|
vec3 rayOri = vec3((uv - 0.5) * vec2(iResolution.x/iResolution.y, 1.0) * 6.0, 3.0);
|
||||||
|
vec3 rayDir = vec3(0.0, 0.0, -1.0);
|
||||||
|
|
||||||
|
float depth = 0.0;
|
||||||
|
vec3 p;
|
||||||
|
|
||||||
|
for(int i = 0; i < 64; i++) {
|
||||||
|
p = rayOri + rayDir * depth;
|
||||||
|
float dist = map(p);
|
||||||
|
depth += dist;
|
||||||
|
if (dist < 1e-6) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
depth = min(6.0, depth);
|
||||||
|
vec3 n = calcNormal(p);
|
||||||
|
float b = max(0.0, dot(n, vec3(0.577)));
|
||||||
|
vec3 col = (0.5 + 0.5 * cos((b + iTime * 3.0) + uv.xyx * 2.0 + vec3(0,2,4))) * (0.85 + b * 0.35);
|
||||||
|
col *= exp( -depth * 0.15 );
|
||||||
|
|
||||||
|
// maximum thickness is 2m in alpha channel
|
||||||
|
fragColor = vec4(col, 1.0 - (depth - 0.5) / 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
77
data/shaders/cineshader_lava/cineshader_lava.vk.glsl
Normal file
77
data/shaders/cineshader_lava/cineshader_lava.vk.glsl
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Cineshader Lava
|
||||||
|
// Author: edankwan
|
||||||
|
// URL: https://www.shadertoy.com/view/3sySRK
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
float opSmoothUnion(float d1, float d2, float k) {
|
||||||
|
float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0);
|
||||||
|
return mix(d2, d1, h) - k * h * (1.0 - h);
|
||||||
|
}
|
||||||
|
|
||||||
|
float sdSphere(vec3 p, float s) {
|
||||||
|
return length(p) - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
float map(vec3 p) {
|
||||||
|
float d = 2.0;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
float fi = float(i);
|
||||||
|
float time = iTime * (fract(fi * 412.531 + 0.513) - 0.5) * 2.0;
|
||||||
|
d = opSmoothUnion(
|
||||||
|
sdSphere(p + sin(time + fi * vec3(52.5126, 64.62744, 632.25)) * vec3(2.0, 2.0, 0.8), mix(0.5, 1.0, fract(fi * 412.531 + 0.5124))),
|
||||||
|
d,
|
||||||
|
0.4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 calcNormal(in vec3 p) {
|
||||||
|
const float h = 1e-5;
|
||||||
|
const vec2 k = vec2(1, -1);
|
||||||
|
return normalize(k.xyy * map(p + k.xyy * h) +
|
||||||
|
k.yyx * map(p + k.yyx * h) +
|
||||||
|
k.yxy * map(p + k.yxy * h) +
|
||||||
|
k.xxx * map(p + k.xxx * h));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 uv = fragCoord / iResolution.xy;
|
||||||
|
|
||||||
|
vec3 rayOri = vec3((uv - 0.5) * vec2(iResolution.x / iResolution.y, 1.0) * 6.0, 3.0);
|
||||||
|
vec3 rayDir = vec3(0.0, 0.0, -1.0);
|
||||||
|
|
||||||
|
float depth = 0.0;
|
||||||
|
vec3 p;
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
p = rayOri + rayDir * depth;
|
||||||
|
float dist = map(p);
|
||||||
|
depth += dist;
|
||||||
|
if (dist < 1e-6) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
depth = min(6.0, depth);
|
||||||
|
vec3 n = calcNormal(p);
|
||||||
|
float b = max(0.0, dot(n, vec3(0.577)));
|
||||||
|
vec3 col = (0.5 + 0.5 * cos((b + iTime * 3.0) + uv.xyx * 2.0 + vec3(0, 2, 4))) * (0.85 + b * 0.35);
|
||||||
|
col *= exp(-depth * 0.15);
|
||||||
|
|
||||||
|
fragColor = vec4(col, 1.0 - (depth - 0.5) / 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/cineshader_lava/meta.txt
Normal file
2
data/shaders/cineshader_lava/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Cineshader Lava
|
||||||
|
Author: edankwan
|
||||||
42
data/shaders/creation/creation.frag.msl
Normal file
42
data/shaders/creation/creation.frag.msl
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Creation by Silexars — Danguafer
|
||||||
|
// MSL port of creation.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment float4 creation_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float t = U.iTime;
|
||||||
|
float2 r = U.iResolution;
|
||||||
|
|
||||||
|
float3 c = float3(0.0);
|
||||||
|
float l = 0.0;
|
||||||
|
float z = t;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
float2 p = fragCoord / r;
|
||||||
|
float2 uv = p;
|
||||||
|
p -= 0.5;
|
||||||
|
p.x *= r.x / r.y;
|
||||||
|
z += 0.07;
|
||||||
|
l = length(p);
|
||||||
|
float invl = (l > 0.0) ? (1.0 / l) : 0.0;
|
||||||
|
uv += p * invl * (sin(z) + 1.0) * abs(sin(l * 9.0 - z - z));
|
||||||
|
float2 m = fract(uv) - 0.5;
|
||||||
|
float denom = length(m);
|
||||||
|
if (denom < 1e-6) denom = 1e-6;
|
||||||
|
c[i] = 0.01 / denom;
|
||||||
|
}
|
||||||
|
float L = (l > 0.0) ? l : 1.0;
|
||||||
|
return float4(c / L, t);
|
||||||
|
}
|
||||||
BIN
data/shaders/creation/creation.frag.spv
Normal file
BIN
data/shaders/creation/creation.frag.spv
Normal file
Binary file not shown.
@@ -1,3 +1,6 @@
|
|||||||
|
// Name: Creation by Silexars
|
||||||
|
// Author: Danguafer
|
||||||
|
// URL: https://www.shadertoy.com/view/XsXXDn
|
||||||
#version 330 core
|
#version 330 core
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
45
data/shaders/creation/creation.vk.glsl
Normal file
45
data/shaders/creation/creation.vk.glsl
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Creation by Silexars
|
||||||
|
// Author: Danguafer
|
||||||
|
// URL: https://www.shadertoy.com/view/XsXXDn
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define t iTime
|
||||||
|
#define r iResolution.xy
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec3 c = vec3(0.0);
|
||||||
|
float l;
|
||||||
|
float z = t;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
vec2 uv, p = fragCoord.xy / r;
|
||||||
|
uv = p;
|
||||||
|
p -= 0.5;
|
||||||
|
p.x *= r.x / r.y;
|
||||||
|
z += 0.07;
|
||||||
|
l = length(p);
|
||||||
|
float invl = (l > 0.0) ? (1.0 / l) : 0.0;
|
||||||
|
uv += p * invl * (sin(z) + 1.0) * abs(sin(l * 9.0 - z - z));
|
||||||
|
vec2 m = mod(uv, 1.0) - 0.5;
|
||||||
|
float denom = length(m);
|
||||||
|
if (denom < 1e-6) denom = 1e-6;
|
||||||
|
c[i] = 0.01 / denom;
|
||||||
|
}
|
||||||
|
float L = (l > 0.0) ? l : 1.0;
|
||||||
|
fragColor = vec4(c / L, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/creation/meta.txt
Normal file
2
data/shaders/creation/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Creation by Silexars
|
||||||
|
Author: Danguafer
|
||||||
455
data/shaders/cube_lines/cube_lines.frag.msl
Normal file
455
data/shaders/cube_lines/cube_lines.frag.msl
Normal file
@@ -0,0 +1,455 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Cube lines — Danil
|
||||||
|
// MSL port of cube_lines.vk.glsl. The original Shadertoy is ~780 lines and
|
||||||
|
// uses every GLSL trick (mat3 chains, arrays, fwidth-based AA, swap macros).
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// - fcos() uses fwidth() like the GLSL original to soften high-frequency
|
||||||
|
// terms. The GLSL fallback path that divides by iResolution.y when
|
||||||
|
// fwidth returns 0/NaN/Inf is omitted here; the main fwidth-based
|
||||||
|
// branch covers virtually all fragments and the fallback is rarely
|
||||||
|
// hit in practice.
|
||||||
|
// - Optional Shadertoy defines (ANIM_SHAPE, ANIM_COLOR, ROTATION_SPEED,
|
||||||
|
// CAMERA_*, USE_COLOR, AA_*, ONLY_BOX, etc.) are left at their defaults
|
||||||
|
// just like the .vk.glsl ships them.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
constant float ROTATION_SPEED = 0.8999;
|
||||||
|
constant float tshift = 53.0;
|
||||||
|
constant float FDIST = 0.7;
|
||||||
|
constant float PI = 3.1415926;
|
||||||
|
constant float3 BOXDIMS = float3(0.75, 0.75, 1.25);
|
||||||
|
constant float IOR = 1.33;
|
||||||
|
|
||||||
|
static float3x3 rotx(float a) {
|
||||||
|
float s = sin(a), c = cos(a);
|
||||||
|
return float3x3(float3(1.0, 0.0, 0.0), float3(0.0, c, s), float3(0.0, -s, c));
|
||||||
|
}
|
||||||
|
static float3x3 roty(float a) {
|
||||||
|
float s = sin(a), c = cos(a);
|
||||||
|
return float3x3(float3(c, 0.0, s), float3(0.0, 1.0, 0.0), float3(-s, 0.0, c));
|
||||||
|
}
|
||||||
|
static float3x3 rotz(float a) {
|
||||||
|
float s = sin(a), c = cos(a);
|
||||||
|
return float3x3(float3(c, s, 0.0), float3(-s, c, 0.0), float3(0.0, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 fcos(float3 x) {
|
||||||
|
float3 w = fwidth(x);
|
||||||
|
return cos(x) * smoothstep(float3(3.14 * 2.0), float3(0.0), w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getColor(float3 p) {
|
||||||
|
p = abs(p);
|
||||||
|
p *= 1.25;
|
||||||
|
p = 0.5 * p / dot(p, p);
|
||||||
|
|
||||||
|
float t = 0.13 * length(p);
|
||||||
|
float3 col = float3(0.3, 0.4, 0.5);
|
||||||
|
col += 0.12 * fcos(6.28318 * t * 1.0 + float3(0.0, 0.8, 1.1));
|
||||||
|
col += 0.11 * fcos(6.28318 * t * 3.1 + float3(0.3, 0.4, 0.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 5.1 + float3(0.1, 0.7, 1.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 17.1 + float3(0.2, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 31.1 + float3(0.1, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 65.1 + float3(0.0, 0.5, 0.8));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 115.1 + float3(0.1, 0.4, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 265.1 + float3(1.1, 1.4, 2.7));
|
||||||
|
col = clamp(col, 0.0, 1.0);
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calcColor(float3 ro, float3 rd, float3 nor, float d, float len, int idx,
|
||||||
|
bool si, float td,
|
||||||
|
thread float4& colx, thread float4& colsi) {
|
||||||
|
float3 pos = ro + rd * d;
|
||||||
|
float a = 1.0 - smoothstep(len - 0.15 * 0.5, len + 0.00001, length(pos));
|
||||||
|
float3 col = getColor(pos);
|
||||||
|
colx = float4(col, a);
|
||||||
|
if (si) {
|
||||||
|
pos = ro + rd * td;
|
||||||
|
float ta = 1.0 - smoothstep(len - 0.15 * 0.5, len + 0.00001, length(pos));
|
||||||
|
col = getColor(pos);
|
||||||
|
colsi = float4(col, ta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool iBilinearPatch(float3 ro, float3 rd, float4 ps, float4 ph, float sz,
|
||||||
|
thread float& t, thread float3& norm,
|
||||||
|
thread bool& si, thread float& tsi, thread float3& normsi,
|
||||||
|
thread float& fade, thread float& fadesi) {
|
||||||
|
float3 va = float3(0.0, 0.0, ph.x + ph.w - ph.y - ph.z);
|
||||||
|
float3 vb = float3(0.0, ps.w - ps.y, ph.z - ph.x);
|
||||||
|
float3 vc = float3(ps.z - ps.x, 0.0, ph.y - ph.x);
|
||||||
|
float3 vd = float3(ps.xy, ph.x);
|
||||||
|
t = -1.0;
|
||||||
|
tsi = -1.0;
|
||||||
|
si = false;
|
||||||
|
fade = 1.0;
|
||||||
|
fadesi = 1.0;
|
||||||
|
norm = float3(0.0, 1.0, 0.0);
|
||||||
|
normsi = float3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
float tmp = 1.0 / (vb.y * vc.x);
|
||||||
|
float a = 0.0, b = 0.0, c = 0.0;
|
||||||
|
float d = va.z * tmp;
|
||||||
|
float e = 0.0, f = 0.0;
|
||||||
|
float g = (vc.z * vb.y - vd.y * va.z) * tmp;
|
||||||
|
float h = (vb.z * vc.x - va.z * vd.x) * tmp;
|
||||||
|
float i = -1.0;
|
||||||
|
float j = (vd.x * vd.y * va.z + vd.z * vb.y * vc.x) * tmp - (vd.y * vb.z * vc.x + vd.x * vc.z * vb.y) * tmp;
|
||||||
|
|
||||||
|
float p = dot(float3(a, b, c), rd.xzy * rd.xzy) + dot(float3(d, e, f), rd.xzy * rd.zyx);
|
||||||
|
float q = dot(float3(2.0, 2.0, 2.0) * ro.xzy * rd.xyz, float3(a, b, c)) + dot(ro.xzz * rd.zxy, float3(d, d, e)) +
|
||||||
|
dot(ro.yyx * rd.zxy, float3(e, f, f)) + dot(float3(g, h, i), rd.xzy);
|
||||||
|
float r = dot(float3(a, b, c), ro.xzy * ro.xzy) + dot(float3(d, e, f), ro.xzy * ro.zyx) + dot(float3(g, h, i), ro.xzy) + j;
|
||||||
|
|
||||||
|
if (abs(p) < 0.000001) {
|
||||||
|
float tt = -r / q;
|
||||||
|
if (tt <= 0.0) return false;
|
||||||
|
t = tt;
|
||||||
|
float3 pos = ro + t * rd;
|
||||||
|
if (length(pos) > sz) return false;
|
||||||
|
float3 grad = float3(2.0) * pos.xzy * float3(a, b, c) + pos.zxz * float3(d, d, e) + pos.yyx * float3(f, e, f) + float3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
float sq = q * q - 4.0 * p * r;
|
||||||
|
if (sq < 0.0) return false;
|
||||||
|
float s = sqrt(sq);
|
||||||
|
float t0 = (-q + s) / (2.0 * p);
|
||||||
|
float t1 = (-q - s) / (2.0 * p);
|
||||||
|
float tt1 = min(t0 < 0.0 ? t1 : t0, t1 < 0.0 ? t0 : t1);
|
||||||
|
float tt2 = max(t0 > 0.0 ? t1 : t0, t1 > 0.0 ? t0 : t1);
|
||||||
|
float tt0 = tt1;
|
||||||
|
if (tt0 <= 0.0) return false;
|
||||||
|
float3 pos = ro + tt0 * rd;
|
||||||
|
bool ru = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru) {
|
||||||
|
tt0 = tt2;
|
||||||
|
pos = ro + tt0 * rd;
|
||||||
|
}
|
||||||
|
if (tt0 <= 0.0) return false;
|
||||||
|
bool ru2 = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru2) return false;
|
||||||
|
|
||||||
|
if ((tt2 > 0.0) && (!ru) && !(step(sz, length(ro + tt2 * rd)) > 0.5)) {
|
||||||
|
si = true;
|
||||||
|
fadesi = s;
|
||||||
|
tsi = tt2;
|
||||||
|
float3 tpos = ro + tsi * rd;
|
||||||
|
float3 tgrad = float3(2.0) * tpos.xzy * float3(a, b, c) + tpos.zxz * float3(d, d, e) +
|
||||||
|
tpos.yyx * float3(f, e, f) + float3(g, h, i);
|
||||||
|
normsi = -normalize(tgrad);
|
||||||
|
}
|
||||||
|
|
||||||
|
fade = s;
|
||||||
|
t = tt0;
|
||||||
|
float3 grad = float3(2.0) * pos.xzy * float3(a, b, c) + pos.zxz * float3(d, d, e) + pos.yyx * float3(f, e, f) + float3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static float dot2(float3 v) { return dot(v, v); }
|
||||||
|
|
||||||
|
static float segShadow(float3 ro, float3 rd, float3 pa, float sh) {
|
||||||
|
float dm = dot(rd.yz, rd.yz);
|
||||||
|
float k1 = (ro.x - pa.x) * dm;
|
||||||
|
float k2 = (ro.x + pa.x) * dm;
|
||||||
|
float2 k5 = (ro.yz + pa.yz) * dm;
|
||||||
|
float k3 = dot(ro.yz + pa.yz, rd.yz);
|
||||||
|
float2 k4 = (pa.yz + pa.yz) * rd.yz;
|
||||||
|
float2 k6 = (pa.yz + pa.yz) * dm;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
float2 s = float2(i & 1, i >> 1);
|
||||||
|
float t = dot(s, k4) - k3;
|
||||||
|
if (t > 0.0) {
|
||||||
|
sh = min(sh, dot2(float3(clamp(-rd.x * t, k1, k2), k5 - k6 * s) + rd * t) / (t * t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float boxSoftShadow(float3 ro, float3 rd, float3 rad, float sk) {
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
float3 rdd = rd;
|
||||||
|
float3 roo = ro;
|
||||||
|
|
||||||
|
float3 m = 1.0 / rdd;
|
||||||
|
float3 n = m * roo;
|
||||||
|
float3 k = abs(m) * rad;
|
||||||
|
|
||||||
|
float3 t1 = -n - k;
|
||||||
|
float3 t2 = -n + k;
|
||||||
|
|
||||||
|
float tN = max(max(t1.x, t1.y), t1.z);
|
||||||
|
float tF = min(min(t2.x, t2.y), t2.z);
|
||||||
|
|
||||||
|
if (tN < tF && tF > 0.0) return 0.0;
|
||||||
|
|
||||||
|
float sh = 1.0;
|
||||||
|
sh = segShadow(roo.xyz, rdd.xyz, rad.xyz, sh);
|
||||||
|
sh = segShadow(roo.yzx, rdd.yzx, rad.yzx, sh);
|
||||||
|
sh = segShadow(roo.zxy, rdd.zxy, rad.zxy, sh);
|
||||||
|
sh = clamp(sk * sqrt(sh), 0.0, 1.0);
|
||||||
|
return sh * sh * (3.0 - 2.0 * sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float boxRay(float3 ro, float3 rd, float3 r, thread float3& nn, bool entering) {
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
float3 dr = 1.0 / rd;
|
||||||
|
float3 n = ro * dr;
|
||||||
|
float3 k = r * abs(dr);
|
||||||
|
|
||||||
|
float3 pin = -k - n;
|
||||||
|
float3 pout = k - n;
|
||||||
|
float tin = max(pin.x, max(pin.y, pin.z));
|
||||||
|
float tout = min(pout.x, min(pout.y, pout.z));
|
||||||
|
if (tin > tout) return -1.0;
|
||||||
|
if (entering) {
|
||||||
|
nn = -sign(rd) * step(pin.zxy, pin.xyz) * step(pin.yzx, pin.xyz);
|
||||||
|
} else {
|
||||||
|
nn = sign(rd) * step(pout.xyz, pout.zxy) * step(pout.xyz, pout.yzx);
|
||||||
|
}
|
||||||
|
return entering ? tin : tout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 bgcol(float3 rd) {
|
||||||
|
return mix(float3(0.01), float3(0.336, 0.458, 0.668), 1.0 - pow(abs(rd.z + 0.25), 1.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 background(float3 ro, float3 rd, float3 l_dir, thread float& alpha) {
|
||||||
|
float t = (-BOXDIMS.z - ro.z) / rd.z;
|
||||||
|
alpha = 0.0;
|
||||||
|
float3 bgc = bgcol(rd);
|
||||||
|
if (t < 0.0) return bgc;
|
||||||
|
float2 uv = ro.xy + t * rd.xy;
|
||||||
|
float shad = boxSoftShadow((ro + t * rd), normalize(l_dir + float3(0.0, 0.0, 1.0)) * rotz(PI * 0.65), BOXDIMS, 1.5);
|
||||||
|
float aofac = smoothstep(-0.95, 0.75, length(abs(uv) - min(abs(uv), float2(0.45))));
|
||||||
|
aofac = min(aofac, smoothstep(-0.65, 1.0, shad));
|
||||||
|
float lght = max(dot(normalize(ro + t * rd + float3(0.0, -0.0, -5.0)), normalize(l_dir - float3(0.0, 0.0, 1.0)) * rotz(PI * 0.65)), 0.0);
|
||||||
|
float3 col = mix(float3(0.4), float3(0.71, 0.772, 0.895), lght * lght * aofac + 0.05) * aofac;
|
||||||
|
alpha = 1.0 - smoothstep(7.0, 10.0, length(uv));
|
||||||
|
return mix(col * length(col) * 0.8, bgc, smoothstep(7.0, 10.0, length(uv)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static float4 insides(float3 ro, float3 rd, float3 nor_c, float3 l_dir, thread float& tout) {
|
||||||
|
tout = -1.0;
|
||||||
|
|
||||||
|
float pi = 3.1415926;
|
||||||
|
|
||||||
|
if (abs(nor_c.x) > 0.5) {
|
||||||
|
rd = rd.xzy * nor_c.x;
|
||||||
|
ro = ro.xzy * nor_c.x;
|
||||||
|
} else if (abs(nor_c.z) > 0.5) {
|
||||||
|
l_dir = l_dir * roty(pi);
|
||||||
|
rd = rd.yxz * nor_c.z;
|
||||||
|
ro = ro.yxz * nor_c.z;
|
||||||
|
} else if (abs(nor_c.y) > 0.5) {
|
||||||
|
l_dir = l_dir * rotz(-pi * 0.5);
|
||||||
|
rd = rd * nor_c.y;
|
||||||
|
ro = ro * nor_c.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float curvature = 0.5;
|
||||||
|
float bil_size = 1.0;
|
||||||
|
float4 ps = float4(-bil_size, -bil_size, bil_size, bil_size) * curvature;
|
||||||
|
float4 ph = float4(-bil_size, bil_size, bil_size, -bil_size) * curvature;
|
||||||
|
|
||||||
|
float4 colx[3] = { float4(0.0), float4(0.0), float4(0.0) };
|
||||||
|
float3 dx[3] = { float3(-1.0), float3(-1.0), float3(-1.0) };
|
||||||
|
float4 colxsi[3] = { float4(0.0), float4(0.0), float4(0.0) };
|
||||||
|
int order[3] = { 0, 1, 2 };
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (abs(nor_c.x) > 0.5) {
|
||||||
|
ro = ro * rotz(-pi * (1.0 / 3.0));
|
||||||
|
rd = rd * rotz(-pi * (1.0 / 3.0));
|
||||||
|
} else if (abs(nor_c.z) > 0.5) {
|
||||||
|
ro = ro * rotz(pi * (1.0 / 3.0));
|
||||||
|
rd = rd * rotz(pi * (1.0 / 3.0));
|
||||||
|
} else if (abs(nor_c.y) > 0.5) {
|
||||||
|
ro = ro * rotx(pi * (1.0 / 3.0));
|
||||||
|
rd = rd * rotx(pi * (1.0 / 3.0));
|
||||||
|
}
|
||||||
|
float3 normnew;
|
||||||
|
float tnew;
|
||||||
|
bool si;
|
||||||
|
float tsi;
|
||||||
|
float3 normsi;
|
||||||
|
float fade;
|
||||||
|
float fadesi;
|
||||||
|
|
||||||
|
if (iBilinearPatch(ro, rd, ps, ph, bil_size, tnew, normnew, si, tsi, normsi, fade, fadesi)) {
|
||||||
|
if (tnew > 0.0) {
|
||||||
|
float4 tcol, tcolsi;
|
||||||
|
calcColor(ro, rd, normnew, tnew, bil_size, i, si, tsi, tcol, tcolsi);
|
||||||
|
if (tcol.a > 0.0) {
|
||||||
|
dx[i] = float3(tnew, float(si), tsi);
|
||||||
|
|
||||||
|
float dif = clamp(dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
float amb = clamp(0.5 + 0.5 * dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
|
||||||
|
{
|
||||||
|
float3 shad = float3(0.32, 0.43, 0.54) * amb + float3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const float3 tcr = float3(1.0, 0.21, 0.11);
|
||||||
|
float ta = clamp(length(tcol.rgb), 0.0, 1.0);
|
||||||
|
tcol = clamp(tcol * tcol * 2.0, 0.0, 1.0);
|
||||||
|
float4 tvalx = float4(tcol.rgb * shad * 1.4 + 3.0 * (tcr * tcol.rgb) * clamp(1.0 - (amb + dif), 0.0, 1.0), min(tcol.a, ta));
|
||||||
|
tvalx.rgb = clamp(2.0 * tvalx.rgb * tvalx.rgb, 0.0, 1.0);
|
||||||
|
tvalx *= min(fade * 5.0, 1.0);
|
||||||
|
colx[i] = tvalx;
|
||||||
|
}
|
||||||
|
if (si) {
|
||||||
|
dif = clamp(dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
amb = clamp(0.5 + 0.5 * dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
float3 shad = float3(0.32, 0.43, 0.54) * amb + float3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const float3 tcr = float3(1.0, 0.21, 0.11);
|
||||||
|
float ta = clamp(length(tcolsi.rgb), 0.0, 1.0);
|
||||||
|
tcolsi = clamp(tcolsi * tcolsi * 2.0, 0.0, 1.0);
|
||||||
|
float4 tvalx = float4(tcolsi.rgb * shad + 3.0 * (tcr * tcolsi.rgb) * clamp(1.0 - (amb + dif), 0.0, 1.0), min(tcolsi.a, ta));
|
||||||
|
tvalx.rgb = clamp(2.0 * tvalx.rgb * tvalx.rgb, 0.0, 1.0);
|
||||||
|
tvalx.rgb *= min(fadesi * 5.0, 1.0);
|
||||||
|
colxsi[i] = tvalx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort by dx[*].x descending (3 passes of bubble sort like the GLSL)
|
||||||
|
if (dx[0].x < dx[1].x) { float3 tv = dx[0]; dx[0] = dx[1]; dx[1] = tv; int ti = order[0]; order[0] = order[1]; order[1] = ti; }
|
||||||
|
if (dx[1].x < dx[2].x) { float3 tv = dx[1]; dx[1] = dx[2]; dx[2] = tv; int ti = order[1]; order[1] = order[2]; order[2] = ti; }
|
||||||
|
if (dx[0].x < dx[1].x) { float3 tv = dx[0]; dx[0] = dx[1]; dx[1] = tv; int ti = order[0]; order[0] = order[1]; order[1] = ti; }
|
||||||
|
|
||||||
|
tout = max(max(dx[0].x, dx[1].x), dx[2].x);
|
||||||
|
|
||||||
|
float a = 1.0;
|
||||||
|
if (dx[0].y < 0.5) {
|
||||||
|
a = colx[order[0]].a;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rul[3] = {
|
||||||
|
((dx[0].y > 0.5) && (dx[1].x <= 0.0)),
|
||||||
|
((dx[1].y > 0.5) && (dx[0].x > dx[1].z)),
|
||||||
|
((dx[2].y > 0.5) && (dx[1].x > dx[2].z))
|
||||||
|
};
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
if (rul[k]) {
|
||||||
|
float4 tcolxsi = colxsi[order[k]];
|
||||||
|
float4 tcolx = colx[order[k]];
|
||||||
|
float4 tvalx = mix(tcolxsi, tcolx, tcolx.a);
|
||||||
|
float4 tvalx2 = mix(float4(0.0), tvalx, max(tcolx.a, tcolxsi.a));
|
||||||
|
colx[order[k]] = tvalx2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float a1 = (dx[1].y < 0.5) ? colx[order[1]].a : ((dx[1].z > dx[0].x) ? colx[order[1]].a : 1.0);
|
||||||
|
float a2 = (dx[2].y < 0.5) ? colx[order[2]].a : ((dx[2].z > dx[1].x) ? colx[order[2]].a : 1.0);
|
||||||
|
float3 col = mix(mix(colx[order[0]].rgb, colx[order[1]].rgb, a1), colx[order[2]].rgb, a2);
|
||||||
|
a = max(max(a, a1), a2);
|
||||||
|
return float4(col, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 cube_lines_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float iTime = U.iTime;
|
||||||
|
|
||||||
|
float3 l_dir = normalize(float3(0.0, 1.0, 0.0));
|
||||||
|
l_dir = l_dir * rotz(0.5);
|
||||||
|
float mouseY = PI * 0.49 - smoothstep(0.0, 8.5, fmod((iTime + tshift) * 0.33, 25.0))
|
||||||
|
* (1.0 - smoothstep(14.0, 24.0, fmod((iTime + tshift) * 0.33, 25.0))) * 0.55 * PI;
|
||||||
|
float mouseX = -2.0 * PI - 0.25 * (iTime * ROTATION_SPEED + tshift);
|
||||||
|
|
||||||
|
float3 eye = 4.0 * float3(cos(mouseX) * cos(mouseY), sin(mouseX) * cos(mouseY), sin(mouseY));
|
||||||
|
float3 w = normalize(-eye);
|
||||||
|
float3 up = float3(0.0, 0.0, 1.0);
|
||||||
|
float3 u = normalize(cross(w, up));
|
||||||
|
float3 v = cross(u, w);
|
||||||
|
|
||||||
|
float4 tot = float4(0.0);
|
||||||
|
float2 uv = (fragCoord - 0.5 * U.iResolution) / U.iResolution.x;
|
||||||
|
float3 rd = normalize(w * FDIST + uv.x * u + uv.y * v);
|
||||||
|
|
||||||
|
float3 ni;
|
||||||
|
float t = boxRay(eye, rd, BOXDIMS, ni, true);
|
||||||
|
float3 ro = eye + t * rd;
|
||||||
|
float2 coords = ro.xy * ni.z / BOXDIMS.xy + ro.yz * ni.x / BOXDIMS.yz + ro.zx * ni.y / BOXDIMS.zx;
|
||||||
|
float fadeborders = (1.0 - smoothstep(0.915, 1.05, abs(coords.x))) * (1.0 - smoothstep(0.915, 1.05, abs(coords.y)));
|
||||||
|
|
||||||
|
if (t > 0.0) {
|
||||||
|
float3 col = float3(0.0);
|
||||||
|
float R0 = (IOR - 1.0) / (IOR + 1.0);
|
||||||
|
R0 *= R0;
|
||||||
|
|
||||||
|
float2 theta = float2(0.0);
|
||||||
|
float3 n = float3(cos(theta.x) * sin(theta.y), sin(theta.x) * sin(theta.y), cos(theta.y));
|
||||||
|
|
||||||
|
float3 nr = n.zxy * ni.x + n.yzx * ni.y + n.xyz * ni.z;
|
||||||
|
float3 rdr = reflect(rd, nr);
|
||||||
|
float talpha;
|
||||||
|
float3 reflcol = background(ro, rdr, l_dir, talpha);
|
||||||
|
|
||||||
|
float3 rd2 = refract(rd, nr, 1.0 / IOR);
|
||||||
|
|
||||||
|
float accum = 1.0;
|
||||||
|
float3 no2 = ni;
|
||||||
|
float3 ro_refr = ro;
|
||||||
|
|
||||||
|
float4 colo[2] = { float4(0.0), float4(0.0) };
|
||||||
|
|
||||||
|
for (int j = 0; j < 2; j++) {
|
||||||
|
float tb;
|
||||||
|
float2 coords2 = ro_refr.xy * no2.z + ro_refr.yz * no2.x + ro_refr.zx * no2.y;
|
||||||
|
float3 eye2 = float3(coords2, -1.0);
|
||||||
|
float3 rd2trans = rd2.yzx * no2.x + rd2.zxy * no2.y + rd2.xyz * no2.z;
|
||||||
|
|
||||||
|
rd2trans.z = -rd2trans.z;
|
||||||
|
float4 internalcol = insides(eye2, rd2trans, no2, l_dir, tb);
|
||||||
|
if (tb > 0.0) {
|
||||||
|
internalcol.rgb *= accum;
|
||||||
|
colo[j] = internalcol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tb <= 0.0) || (internalcol.a < 1.0)) {
|
||||||
|
float tout = boxRay(ro_refr, rd2, BOXDIMS, no2, false);
|
||||||
|
no2 = n.zyx * no2.x + n.xzy * no2.y + n.yxz * no2.z;
|
||||||
|
float3 rout = ro_refr + tout * rd2;
|
||||||
|
float3 rdout = refract(rd2, -no2, IOR);
|
||||||
|
float fresnel2 = R0 + (1.0 - R0) * pow(1.0 - dot(rdout, no2), 1.3);
|
||||||
|
rd2 = reflect(rd2, -no2);
|
||||||
|
|
||||||
|
ro_refr = rout;
|
||||||
|
ro_refr.z = max(ro_refr.z, -0.999);
|
||||||
|
|
||||||
|
accum *= fresnel2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float fresnel = R0 + (1.0 - R0) * pow(1.0 - dot(-rd, nr), 5.0);
|
||||||
|
col = mix(mix(colo[1].rgb * colo[1].a, colo[0].rgb, colo[0].a) * fadeborders, reflcol, pow(fresnel, 1.5));
|
||||||
|
col = clamp(col, 0.0, 1.0);
|
||||||
|
|
||||||
|
float cineshader_alpha = clamp(0.15 * dot(eye, ro), 0.0, 1.0);
|
||||||
|
tot += float4(col, cineshader_alpha);
|
||||||
|
} else {
|
||||||
|
float alpha;
|
||||||
|
tot += float4(background(eye, rd, l_dir, alpha), 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 outColor = tot;
|
||||||
|
outColor.rgb = clamp(outColor.rgb, 0.0, 1.0);
|
||||||
|
return outColor;
|
||||||
|
}
|
||||||
BIN
data/shaders/cube_lines/cube_lines.frag.spv
Normal file
BIN
data/shaders/cube_lines/cube_lines.frag.spv
Normal file
Binary file not shown.
778
data/shaders/cube_lines/cube_lines.gl.glsl
Normal file
778
data/shaders/cube_lines/cube_lines.gl.glsl
Normal file
@@ -0,0 +1,778 @@
|
|||||||
|
// Name: Cube lines
|
||||||
|
// Author: Danil
|
||||||
|
// URL: https://www.shadertoy.com/view/NslGRN
|
||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
// Note: Original shader uses iChannel0 for background blending (optional feature)
|
||||||
|
// Since we don't support texture channels, that line is commented out
|
||||||
|
// The shader works perfectly without it in default mode
|
||||||
|
|
||||||
|
// Created by Danil (2021+) https://cohost.org/arugl
|
||||||
|
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||||
|
// self https://www.shadertoy.com/view/NslGRN
|
||||||
|
|
||||||
|
|
||||||
|
// --defines for "DESKTOP WALLPAPERS" that use this shader--
|
||||||
|
// comment or uncomment every define to make it work (add or remove "//" before #define)
|
||||||
|
|
||||||
|
|
||||||
|
// this shadertoy use ALPHA, NO_ALPHA set alpha to 1, BG_ALPHA set background as alpha
|
||||||
|
// iChannel0 used as background if alpha ignored by wallpaper-app
|
||||||
|
//#define NO_ALPHA
|
||||||
|
//#define BG_ALPHA
|
||||||
|
//#define SHADOW_ALPHA
|
||||||
|
//#define ONLY_BOX
|
||||||
|
|
||||||
|
|
||||||
|
// save PERFORMANCE by disabling shadow
|
||||||
|
//#define NO_SHADOW
|
||||||
|
|
||||||
|
|
||||||
|
// static CAMERA position, 0.49 on top, 0.001 horizontal
|
||||||
|
//#define CAMERA_POS 0.049
|
||||||
|
|
||||||
|
|
||||||
|
// speed of ROTATION
|
||||||
|
#define ROTATION_SPEED 0.8999
|
||||||
|
|
||||||
|
|
||||||
|
// static SHAPE form, default 0.5
|
||||||
|
//#define STATIC_SHAPE 0.15
|
||||||
|
|
||||||
|
|
||||||
|
// static SCALE far/close to camera, 2.0 is default, exampe 0.5 or 10.0
|
||||||
|
//#define CAMERA_FAR 0.1
|
||||||
|
|
||||||
|
|
||||||
|
// ANIMATION shape change
|
||||||
|
//#define ANIM_SHAPE
|
||||||
|
|
||||||
|
|
||||||
|
// ANIMATION color change
|
||||||
|
//#define ANIM_COLOR
|
||||||
|
|
||||||
|
|
||||||
|
// custom COLOR, and change those const values
|
||||||
|
//#define USE_COLOR
|
||||||
|
const vec3 color_blue=vec3(0.5,0.65,0.8);
|
||||||
|
const vec3 color_red=vec3(0.99,0.2,0.1);
|
||||||
|
|
||||||
|
|
||||||
|
// use 4xAA for cube only (set 2-4-etc level of AA)
|
||||||
|
//#define AA_CUBE 4
|
||||||
|
|
||||||
|
// use 4xAA for everything - derivative filtering will not be used, look fcos2
|
||||||
|
// this is very slow - DO NOT USE
|
||||||
|
//#define AA_ALL 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --shader code--
|
||||||
|
|
||||||
|
// Layers sorted and support transparency and self-intersection-transparency
|
||||||
|
// Antialiasing is only dFd. (with some dFd fixes around edges)
|
||||||
|
|
||||||
|
// using iq's intersectors: https://iquilezles.org/articles/intersectors
|
||||||
|
// using https://www.shadertoy.com/view/ltKBzG
|
||||||
|
// using https://www.shadertoy.com/view/tsVXzh
|
||||||
|
// using https://www.shadertoy.com/view/WlffDn
|
||||||
|
// using https://www.shadertoy.com/view/WslGz4
|
||||||
|
|
||||||
|
#define tshift 53.
|
||||||
|
|
||||||
|
// reflect back side
|
||||||
|
//#define backside_refl
|
||||||
|
|
||||||
|
// Camera with mouse
|
||||||
|
// #define MOUSE_control (disabled - no iMouse support)
|
||||||
|
|
||||||
|
// min(iFrame,0) does not speedup compilation in ANGLE
|
||||||
|
#define ANGLE_loops 0
|
||||||
|
|
||||||
|
|
||||||
|
// this shader discover Nvidia bug with arrays https://www.shadertoy.com/view/NslGR4
|
||||||
|
// use DEBUG with BUG, BUG trigger that bug and one layer will be white on Nvidia in OpenGL
|
||||||
|
//#define DEBUG
|
||||||
|
//#define BUG
|
||||||
|
|
||||||
|
#define FDIST 0.7
|
||||||
|
#define PI 3.1415926
|
||||||
|
#define GROUNDSPACING 0.5
|
||||||
|
#define GROUNDGRID 0.05
|
||||||
|
#define BOXDIMS vec3(0.75, 0.75, 1.25)
|
||||||
|
|
||||||
|
#define IOR 1.33
|
||||||
|
|
||||||
|
mat3 rotx(float a){float s = sin(a);float c = cos(a);return mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, c, s), vec3(0.0, -s, c)); }
|
||||||
|
mat3 roty(float a){float s = sin(a);float c = cos(a);return mat3(vec3(c, 0.0, s), vec3(0.0, 1.0, 0.0), vec3(-s, 0.0, c));}
|
||||||
|
mat3 rotz(float a){float s = sin(a);float c = cos(a);return mat3(vec3(c, s, 0.0), vec3(-s, c, 0.0), vec3(0.0, 0.0, 1.0 ));}
|
||||||
|
|
||||||
|
vec3 fcos1(vec3 x) {
|
||||||
|
vec3 w = fwidth(x);
|
||||||
|
//if((length(w)==0.))return vec3(0.); // dFd fix2
|
||||||
|
//w*=0.; //test
|
||||||
|
float lw=length(w);
|
||||||
|
if((lw==0.)||isnan(lw)||isinf(lw)){vec3 tc=vec3(0.); for(int i=0;i<8;i++)tc+=cos(x+x*float(i-4)*(0.01*400./iResolution.y));return tc/8.;}
|
||||||
|
|
||||||
|
return cos(x) * smoothstep(3.14 * 2.0, 0.0, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fcos2( vec3 x){return cos(x);}
|
||||||
|
vec3 fcos( vec3 x){
|
||||||
|
#ifdef AA_ALL
|
||||||
|
return fcos2(x);
|
||||||
|
#else
|
||||||
|
return fcos1(x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getColor(vec3 p)
|
||||||
|
{
|
||||||
|
// dFd fix, dFd broken on borders, but it fix only top level dFd, self intersection has border
|
||||||
|
//if (length(p) > 0.99)return vec3(0.);
|
||||||
|
p = abs(p);
|
||||||
|
|
||||||
|
p *= 01.25;
|
||||||
|
p = 0.5 * p / dot(p, p);
|
||||||
|
#ifdef ANIM_COLOR
|
||||||
|
p+=0.072*iTime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float t = (0.13) * length(p);
|
||||||
|
vec3 col = vec3(0.3, 0.4, 0.5);
|
||||||
|
col += 0.12 * fcos(6.28318 * t * 1.0 + vec3(0.0, 0.8, 1.1));
|
||||||
|
col += 0.11 * fcos(6.28318 * t * 3.1 + vec3(0.3, 0.4, 0.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 5.1 + vec3(0.1, 0.7, 1.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 17.1 + vec3(0.2, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 31.1 + vec3(0.1, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 65.1 + vec3(0.0, 0.5, 0.8));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 115.1 + vec3(0.1, 0.4, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 265.1 + vec3(1.1, 1.4, 2.7));
|
||||||
|
col = clamp(col, 0., 1.);
|
||||||
|
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calcColor(vec3 ro, vec3 rd, vec3 nor, float d, float len, int idx, bool si, float td, out vec4 colx,
|
||||||
|
out vec4 colsi)
|
||||||
|
{
|
||||||
|
|
||||||
|
vec3 pos = (ro + rd * d);
|
||||||
|
#ifdef DEBUG
|
||||||
|
float a = 1. - smoothstep(len - 0.15, len + 0.00001, length(pos));
|
||||||
|
if (idx == 0)colx = vec4(1., 0., 0., a);
|
||||||
|
if (idx == 1)colx = vec4(0., 1., 0., a);
|
||||||
|
if (idx == 2)colx = vec4(0., 0., 1., a);
|
||||||
|
if (si)
|
||||||
|
{
|
||||||
|
pos = (ro + rd * td);
|
||||||
|
float ta = 1. - smoothstep(len - 0.15, len + 0.00001, length(pos));
|
||||||
|
if (idx == 0)colsi = vec4(1., 0., 0., ta);
|
||||||
|
if (idx == 1)colsi = vec4(0., 1., 0., ta);
|
||||||
|
if (idx == 2)colsi = vec4(0., 0., 1., ta);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
float a = 1. - smoothstep(len - 0.15*0.5, len + 0.00001, length(pos));
|
||||||
|
//a=1.;
|
||||||
|
vec3 col = getColor(pos);
|
||||||
|
colx = vec4(col, a);
|
||||||
|
if (si)
|
||||||
|
{
|
||||||
|
pos = (ro + rd * td);
|
||||||
|
float ta = 1. - smoothstep(len - 0.15*0.5, len + 0.00001, length(pos));
|
||||||
|
//ta=1.;
|
||||||
|
col = getColor(pos);
|
||||||
|
colsi = vec4(col, ta);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// xSI is self intersect data, fade to fix dFd on edges
|
||||||
|
bool iBilinearPatch(in vec3 ro, in vec3 rd, in vec4 ps, in vec4 ph, in float sz, out float t, out vec3 norm,
|
||||||
|
out bool si, out float tsi, out vec3 normsi, out float fade, out float fadesi)
|
||||||
|
{
|
||||||
|
vec3 va = vec3(0.0, 0.0, ph.x + ph.w - ph.y - ph.z);
|
||||||
|
vec3 vb = vec3(0.0, ps.w - ps.y, ph.z - ph.x);
|
||||||
|
vec3 vc = vec3(ps.z - ps.x, 0.0, ph.y - ph.x);
|
||||||
|
vec3 vd = vec3(ps.xy, ph.x);
|
||||||
|
t = -1.;
|
||||||
|
tsi = -1.;
|
||||||
|
si = false;
|
||||||
|
fade = 1.;
|
||||||
|
fadesi = 1.;
|
||||||
|
norm=vec3(0.,1.,0.);normsi=vec3(0.,1.,0.);
|
||||||
|
|
||||||
|
float tmp = 1.0 / (vb.y * vc.x);
|
||||||
|
float a = 0.0;
|
||||||
|
float b = 0.0;
|
||||||
|
float c = 0.0;
|
||||||
|
float d = va.z * tmp;
|
||||||
|
float e = 0.0;
|
||||||
|
float f = 0.0;
|
||||||
|
float g = (vc.z * vb.y - vd.y * va.z) * tmp;
|
||||||
|
float h = (vb.z * vc.x - va.z * vd.x) * tmp;
|
||||||
|
float i = -1.0;
|
||||||
|
float j = (vd.x * vd.y * va.z + vd.z * vb.y * vc.x) * tmp - (vd.y * vb.z * vc.x + vd.x * vc.z * vb.y) * tmp;
|
||||||
|
|
||||||
|
float p = dot(vec3(a, b, c), rd.xzy * rd.xzy) + dot(vec3(d, e, f), rd.xzy * rd.zyx);
|
||||||
|
float q = dot(vec3(2.0, 2.0, 2.0) * ro.xzy * rd.xyz, vec3(a, b, c)) + dot(ro.xzz * rd.zxy, vec3(d, d, e)) +
|
||||||
|
dot(ro.yyx * rd.zxy, vec3(e, f, f)) + dot(vec3(g, h, i), rd.xzy);
|
||||||
|
float r =
|
||||||
|
dot(vec3(a, b, c), ro.xzy * ro.xzy) + dot(vec3(d, e, f), ro.xzy * ro.zyx) + dot(vec3(g, h, i), ro.xzy) + j;
|
||||||
|
|
||||||
|
if (abs(p) < 0.000001)
|
||||||
|
{
|
||||||
|
float tt = -r / q;
|
||||||
|
if (tt <= 0.)
|
||||||
|
return false;
|
||||||
|
t = tt;
|
||||||
|
// normal
|
||||||
|
|
||||||
|
vec3 pos = ro + t * rd;
|
||||||
|
if(length(pos)>sz)return false;
|
||||||
|
vec3 grad =
|
||||||
|
vec3(2.0) * pos.xzy * vec3(a, b, c) + pos.zxz * vec3(d, d, e) + pos.yyx * vec3(f, e, f) + vec3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float sq = q * q - 4.0 * p * r;
|
||||||
|
if (sq < 0.0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float s = sqrt(sq);
|
||||||
|
float t0 = (-q + s) / (2.0 * p);
|
||||||
|
float t1 = (-q - s) / (2.0 * p);
|
||||||
|
float tt1 = min(t0 < 0.0 ? t1 : t0, t1 < 0.0 ? t0 : t1);
|
||||||
|
float tt2 = max(t0 > 0.0 ? t1 : t0, t1 > 0.0 ? t0 : t1);
|
||||||
|
float tt0 = tt1;
|
||||||
|
if (tt0 <= 0.)
|
||||||
|
return false;
|
||||||
|
vec3 pos = ro + tt0 * rd;
|
||||||
|
// black border on end of circle and self intersection with alpha come because dFd
|
||||||
|
// uncomment this to see or rename fcos2 to fcos
|
||||||
|
//sz+=0.3;
|
||||||
|
bool ru = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru)
|
||||||
|
{
|
||||||
|
tt0 = tt2;
|
||||||
|
pos = ro + tt0 * rd;
|
||||||
|
}
|
||||||
|
if (tt0 <= 0.)
|
||||||
|
return false;
|
||||||
|
bool ru2 = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// self intersect
|
||||||
|
if ((tt2 > 0.) && ((!ru)) && !(step(sz, length(ro + tt2 * rd)) > 0.5))
|
||||||
|
{
|
||||||
|
si = true;
|
||||||
|
fadesi=s;
|
||||||
|
tsi = tt2;
|
||||||
|
vec3 tpos = ro + tsi * rd;
|
||||||
|
// normal
|
||||||
|
vec3 tgrad = vec3(2.0) * tpos.xzy * vec3(a, b, c) + tpos.zxz * vec3(d, d, e) +
|
||||||
|
tpos.yyx * vec3(f, e, f) + vec3(g, h, i);
|
||||||
|
normsi = -normalize(tgrad);
|
||||||
|
}
|
||||||
|
|
||||||
|
fade=s;
|
||||||
|
t = tt0;
|
||||||
|
// normal
|
||||||
|
vec3 grad =
|
||||||
|
vec3(2.0) * pos.xzy * vec3(a, b, c) + pos.zxz * vec3(d, d, e) + pos.yyx * vec3(f, e, f) + vec3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float dot2( in vec3 v ) { return dot(v,v); }
|
||||||
|
|
||||||
|
float segShadow( in vec3 ro, in vec3 rd, in vec3 pa, float sh )
|
||||||
|
{
|
||||||
|
float dm = dot(rd.yz,rd.yz);
|
||||||
|
float k1 = (ro.x-pa.x)*dm;
|
||||||
|
float k2 = (ro.x+pa.x)*dm;
|
||||||
|
vec2 k5 = (ro.yz+pa.yz)*dm;
|
||||||
|
float k3 = dot(ro.yz+pa.yz,rd.yz);
|
||||||
|
vec2 k4 = (pa.yz+pa.yz)*rd.yz;
|
||||||
|
vec2 k6 = (pa.yz+pa.yz)*dm;
|
||||||
|
|
||||||
|
for( int i=0; i<4 + ANGLE_loops; i++ )
|
||||||
|
{
|
||||||
|
vec2 s = vec2(i&1,i>>1);
|
||||||
|
float t = dot(s,k4) - k3;
|
||||||
|
|
||||||
|
if( t>0.0 )
|
||||||
|
sh = min(sh,dot2(vec3(clamp(-rd.x*t,k1,k2),k5-k6*s)+rd*t)/(t*t));
|
||||||
|
}
|
||||||
|
return sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
float boxSoftShadow( in vec3 ro, in vec3 rd, in vec3 rad, in float sk )
|
||||||
|
{
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
vec3 rdd = rd;
|
||||||
|
vec3 roo = ro;
|
||||||
|
|
||||||
|
vec3 m = 1.0/rdd;
|
||||||
|
vec3 n = m*roo;
|
||||||
|
vec3 k = abs(m)*rad;
|
||||||
|
|
||||||
|
vec3 t1 = -n - k;
|
||||||
|
vec3 t2 = -n + k;
|
||||||
|
|
||||||
|
float tN = max( max( t1.x, t1.y ), t1.z );
|
||||||
|
float tF = min( min( t2.x, t2.y ), t2.z );
|
||||||
|
|
||||||
|
if( tN<tF && tF>0.0) return 0.0;
|
||||||
|
|
||||||
|
float sh = 1.0;
|
||||||
|
sh = segShadow( roo.xyz, rdd.xyz, rad.xyz, sh );
|
||||||
|
sh = segShadow( roo.yzx, rdd.yzx, rad.yzx, sh );
|
||||||
|
sh = segShadow( roo.zxy, rdd.zxy, rad.zxy, sh );
|
||||||
|
sh = clamp(sk*sqrt(sh),0.0,1.0);
|
||||||
|
return sh*sh*(3.0-2.0*sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
float box(in vec3 ro, in vec3 rd, in vec3 r, out vec3 nn, bool entering)
|
||||||
|
{
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
vec3 dr = 1.0 / rd;
|
||||||
|
vec3 n = ro * dr;
|
||||||
|
vec3 k = r * abs(dr);
|
||||||
|
|
||||||
|
vec3 pin = -k - n;
|
||||||
|
vec3 pout = k - n;
|
||||||
|
float tin = max(pin.x, max(pin.y, pin.z));
|
||||||
|
float tout = min(pout.x, min(pout.y, pout.z));
|
||||||
|
if (tin > tout)
|
||||||
|
return -1.;
|
||||||
|
if (entering)
|
||||||
|
{
|
||||||
|
nn = -sign(rd) * step(pin.zxy, pin.xyz) * step(pin.yzx, pin.xyz);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nn = sign(rd) * step(pout.xyz, pout.zxy) * step(pout.xyz, pout.yzx);
|
||||||
|
}
|
||||||
|
return entering ? tin : tout;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bgcol(in vec3 rd)
|
||||||
|
{
|
||||||
|
return mix(vec3(0.01), vec3(0.336, 0.458, .668), 1. - pow(abs(rd.z+0.25), 1.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 background(in vec3 ro, in vec3 rd , vec3 l_dir, out float alpha)
|
||||||
|
{
|
||||||
|
#ifdef ONLY_BOX
|
||||||
|
alpha=0.;
|
||||||
|
return vec3(0.01);
|
||||||
|
#endif
|
||||||
|
float t = (-BOXDIMS.z - ro.z) / rd.z;
|
||||||
|
alpha=0.;
|
||||||
|
vec3 bgc = bgcol(rd);
|
||||||
|
if (t < 0.)
|
||||||
|
return bgc;
|
||||||
|
vec2 uv = ro.xy + t * rd.xy;
|
||||||
|
#ifdef NO_SHADOW
|
||||||
|
float shad=1.;
|
||||||
|
#else
|
||||||
|
float shad = boxSoftShadow((ro + t * rd), normalize(l_dir+vec3(0.,0.,1.))*rotz(PI*0.65) , BOXDIMS, 1.5);
|
||||||
|
#endif
|
||||||
|
float aofac = smoothstep(-0.95, .75, length(abs(uv) - min(abs(uv), vec2(0.45))));
|
||||||
|
aofac = min(aofac,smoothstep(-0.65, 1., shad));
|
||||||
|
float lght=max(dot(normalize(ro + t * rd+vec3(0.,-0.,-5.)), normalize(l_dir-vec3(0.,0.,1.))*rotz(PI*0.65)), 0.0);
|
||||||
|
vec3 col = mix(vec3(0.4), vec3(.71,.772,0.895), lght*lght* aofac+ 0.05) * aofac;
|
||||||
|
alpha=1.-smoothstep(7.,10.,length(uv));
|
||||||
|
#ifdef SHADOW_ALPHA
|
||||||
|
//alpha=clamp(alpha*max(lght*lght*0.95,(1.-aofac)*1.25),0.,1.);
|
||||||
|
alpha=clamp(alpha*(1.-aofac)*1.25,0.,1.);
|
||||||
|
#endif
|
||||||
|
return mix(col*length(col)*0.8,bgc,smoothstep(7.,10.,length(uv)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define swap(a,b) tv=a;a=b;b=tv
|
||||||
|
|
||||||
|
vec4 insides(vec3 ro, vec3 rd, vec3 nor_c, vec3 l_dir, out float tout)
|
||||||
|
{
|
||||||
|
tout = -1.;
|
||||||
|
vec3 trd=rd;
|
||||||
|
|
||||||
|
vec3 col = vec3(0.);
|
||||||
|
|
||||||
|
float pi = 3.1415926;
|
||||||
|
|
||||||
|
if (abs(nor_c.x) > 0.5)
|
||||||
|
{
|
||||||
|
rd = rd.xzy * nor_c.x;
|
||||||
|
ro = ro.xzy * nor_c.x;
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.z) > 0.5)
|
||||||
|
{
|
||||||
|
l_dir *= roty(pi);
|
||||||
|
rd = rd.yxz * nor_c.z;
|
||||||
|
ro = ro.yxz * nor_c.z;
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.y) > 0.5)
|
||||||
|
{
|
||||||
|
l_dir *= rotz(-pi * 0.5);
|
||||||
|
rd = rd * nor_c.y;
|
||||||
|
ro = ro * nor_c.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ANIM_SHAPE
|
||||||
|
float curvature = (0.001+1.5-1.5*smoothstep(0.,8.5,mod((iTime+tshift)*0.44,20.))*(1.-smoothstep(10.,18.5,mod((iTime+tshift)*0.44,20.))));
|
||||||
|
// curvature(to not const above) make compilation on Angle 15+ sec
|
||||||
|
#else
|
||||||
|
#ifdef STATIC_SHAPE
|
||||||
|
const float curvature = STATIC_SHAPE;
|
||||||
|
#else
|
||||||
|
const float curvature = .5;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
float bil_size = 1.;
|
||||||
|
vec4 ps = vec4(-bil_size, -bil_size, bil_size, bil_size) * curvature;
|
||||||
|
vec4 ph = vec4(-bil_size, bil_size, bil_size, -bil_size) * curvature;
|
||||||
|
|
||||||
|
vec4 [3]colx=vec4[3](vec4(0.),vec4(0.),vec4(0.));
|
||||||
|
vec3 [3]dx=vec3[3](vec3(-1.),vec3(-1.),vec3(-1.));
|
||||||
|
vec4 [3]colxsi=vec4[3](vec4(0.),vec4(0.),vec4(0.));
|
||||||
|
int [3]order=int[3](0,1,2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3 + ANGLE_loops; i++)
|
||||||
|
{
|
||||||
|
if (abs(nor_c.x) > 0.5)
|
||||||
|
{
|
||||||
|
ro *= rotz(-pi * (1. / float(3)));
|
||||||
|
rd *= rotz(-pi * (1. / float(3)));
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.z) > 0.5)
|
||||||
|
{
|
||||||
|
ro *= rotz(pi * (1. / float(3)));
|
||||||
|
rd *= rotz(pi * (1. / float(3)));
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.y) > 0.5)
|
||||||
|
{
|
||||||
|
ro *= rotx(pi * (1. / float(3)));
|
||||||
|
rd *= rotx(pi * (1. / float(3)));
|
||||||
|
}
|
||||||
|
vec3 normnew;
|
||||||
|
float tnew;
|
||||||
|
bool si;
|
||||||
|
float tsi;
|
||||||
|
vec3 normsi;
|
||||||
|
float fade;
|
||||||
|
float fadesi;
|
||||||
|
|
||||||
|
if (iBilinearPatch(ro, rd, ps, ph, bil_size, tnew, normnew, si, tsi, normsi, fade, fadesi))
|
||||||
|
{
|
||||||
|
if (tnew > 0.)
|
||||||
|
{
|
||||||
|
vec4 tcol, tcolsi;
|
||||||
|
calcColor(ro, rd, normnew, tnew, bil_size, i, si, tsi, tcol, tcolsi);
|
||||||
|
if (tcol.a > 0.0)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
vec3 tvalx = vec3(tnew, float(si), tsi);
|
||||||
|
dx[i]=tvalx;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
colx[i]=tcol;
|
||||||
|
if (si)colxsi[i]=tcolsi;
|
||||||
|
#else
|
||||||
|
|
||||||
|
float dif = clamp(dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
float amb = clamp(0.5 + 0.5 * dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
|
||||||
|
{
|
||||||
|
#ifdef USE_COLOR
|
||||||
|
vec3 shad = 0.57 * color_blue * amb + 1.5*color_blue.bgr * dif;
|
||||||
|
const vec3 tcr = color_red;
|
||||||
|
#else
|
||||||
|
vec3 shad = vec3(0.32, 0.43, 0.54) * amb + vec3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const vec3 tcr = vec3(1.,0.21,0.11);
|
||||||
|
#endif
|
||||||
|
float ta = clamp(length(tcol.rgb),0.,1.);
|
||||||
|
tcol=clamp(tcol*tcol*2.,0.,1.);
|
||||||
|
vec4 tvalx =
|
||||||
|
vec4((tcol.rgb*shad*1.4 + 3.*(tcr*tcol.rgb)*clamp(1.-(amb+dif),0.,1.)), min(tcol.a,ta));
|
||||||
|
tvalx.rgb=clamp(2.*tvalx.rgb*tvalx.rgb,0.,1.);
|
||||||
|
tvalx*=(min(fade*5.,1.));
|
||||||
|
colx[i]=tvalx;
|
||||||
|
}
|
||||||
|
if (si)
|
||||||
|
{
|
||||||
|
dif = clamp(dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
amb = clamp(0.5 + 0.5 * dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
{
|
||||||
|
#ifdef USE_COLOR
|
||||||
|
vec3 shad = 0.57 * color_blue * amb + 1.5*color_blue.bgr * dif;
|
||||||
|
const vec3 tcr = color_red;
|
||||||
|
#else
|
||||||
|
vec3 shad = vec3(0.32, 0.43, 0.54) * amb + vec3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const vec3 tcr = vec3(1.,0.21,0.11);
|
||||||
|
#endif
|
||||||
|
float ta = clamp(length(tcolsi.rgb),0.,1.);
|
||||||
|
tcolsi=clamp(tcolsi*tcolsi*2.,0.,1.);
|
||||||
|
vec4 tvalx =
|
||||||
|
vec4(tcolsi.rgb * shad + 3.*(tcr*tcolsi.rgb)*clamp(1.-(amb+dif),0.,1.), min(tcolsi.a,ta));
|
||||||
|
tvalx.rgb=clamp(2.*tvalx.rgb*tvalx.rgb,0.,1.);
|
||||||
|
tvalx.rgb*=(min(fadesi*5.,1.));
|
||||||
|
colxsi[i]=tvalx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// transparency logic and layers sorting
|
||||||
|
float a = 1.;
|
||||||
|
if (dx[0].x < dx[1].x){{vec3 swap(dx[0], dx[1]);}{int swap(order[0], order[1]);}}
|
||||||
|
if (dx[1].x < dx[2].x){{vec3 swap(dx[1], dx[2]);}{int swap(order[1], order[2]);}}
|
||||||
|
if (dx[0].x < dx[1].x){{vec3 swap(dx[0], dx[1]);}{int swap(order[0], order[1]);}}
|
||||||
|
|
||||||
|
tout = max(max(dx[0].x, dx[1].x), dx[2].x);
|
||||||
|
|
||||||
|
if (dx[0].y < 0.5)
|
||||||
|
{
|
||||||
|
a=colx[order[0]].a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(defined(DEBUG)&&defined(BUG))
|
||||||
|
|
||||||
|
// self intersection
|
||||||
|
bool [3] rul= bool[3](
|
||||||
|
((dx[0].y > 0.5) && (dx[1].x <= 0.)),
|
||||||
|
((dx[1].y > 0.5) && (dx[0].x > dx[1].z)),
|
||||||
|
((dx[2].y > 0.5) && (dx[1].x > dx[2].z))
|
||||||
|
);
|
||||||
|
for(int k=0;k<3;k++){
|
||||||
|
if(rul[k]){
|
||||||
|
vec4 tcolxsi = vec4(0.);
|
||||||
|
tcolxsi=colxsi[order[k]];
|
||||||
|
vec4 tcolx = vec4(0.);
|
||||||
|
tcolx=colx[order[k]];
|
||||||
|
|
||||||
|
vec4 tvalx = mix(tcolxsi, tcolx, tcolx.a);
|
||||||
|
colx[order[k]]=tvalx;
|
||||||
|
|
||||||
|
vec4 tvalx2 = mix(vec4(0.), tvalx, max(tcolx.a, tcolxsi.a));
|
||||||
|
colx[order[k]]=tvalx2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float a1 = (dx[1].y < 0.5) ? colx[order[1]].a : ((dx[1].z > dx[0].x) ? colx[order[1]].a : 1.);
|
||||||
|
float a2 = (dx[2].y < 0.5) ? colx[order[2]].a : ((dx[2].z > dx[1].x) ? colx[order[2]].a : 1.);
|
||||||
|
col = mix(mix(colx[order[0]].rgb, colx[order[1]].rgb, a1), colx[order[2]].rgb, a2);
|
||||||
|
a = max(max(a, a1), a2);
|
||||||
|
return vec4(col, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord)
|
||||||
|
{
|
||||||
|
float osc = 0.5;
|
||||||
|
vec3 l_dir = normalize(vec3(0., 1., 0.));
|
||||||
|
l_dir *= rotz(0.5);
|
||||||
|
float mouseY = 1.0 * 0.5 * PI;
|
||||||
|
// Note: MOUSE_control disabled (no iMouse support)
|
||||||
|
// #ifdef MOUSE_control
|
||||||
|
// mouseY = (1.0 - 1.15 * iMouse.y / iResolution.y) * 0.5 * PI;
|
||||||
|
// if(iMouse.y < 1.)
|
||||||
|
// #endif
|
||||||
|
#ifdef CAMERA_POS
|
||||||
|
mouseY = PI*CAMERA_POS;
|
||||||
|
#else
|
||||||
|
mouseY = PI*0.49 - smoothstep(0.,8.5,mod((iTime+tshift)*0.33,25.))*(1.-smoothstep(14.,24.0,mod((iTime+tshift)*0.33,25.))) * 0.55 * PI;
|
||||||
|
#endif
|
||||||
|
#ifdef ROTATION_SPEED
|
||||||
|
float mouseX = -2.*PI-0.25*(iTime*ROTATION_SPEED+tshift);
|
||||||
|
#else
|
||||||
|
float mouseX = -2.*PI-0.25*(iTime+tshift);
|
||||||
|
#endif
|
||||||
|
// Note: MOUSE_control disabled (no iMouse support)
|
||||||
|
// #ifdef MOUSE_control
|
||||||
|
// mouseX+=-(iMouse.x / iResolution.x) * 2. * PI;
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
#ifdef CAMERA_FAR
|
||||||
|
vec3 eye = (2. + CAMERA_FAR) * vec3(cos(mouseX) * cos(mouseY), sin(mouseX) * cos(mouseY), sin(mouseY));
|
||||||
|
#else
|
||||||
|
vec3 eye = 4. * vec3(cos(mouseX) * cos(mouseY), sin(mouseX) * cos(mouseY), sin(mouseY));
|
||||||
|
#endif
|
||||||
|
vec3 w = normalize(-eye);
|
||||||
|
vec3 up = vec3(0., 0., 1.);
|
||||||
|
vec3 u = normalize(cross(w, up));
|
||||||
|
vec3 v = cross(u, w);
|
||||||
|
|
||||||
|
vec4 tot=vec4(0.);
|
||||||
|
#if defined(AA_CUBE)||defined(AA_ALL)
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
const int AA = AA_CUBE;
|
||||||
|
#else
|
||||||
|
const int AA = AA_ALL;
|
||||||
|
#endif
|
||||||
|
vec3 incol_once=vec3(0.);
|
||||||
|
bool in_once=false;
|
||||||
|
vec4 incolbg_once=vec4(0.);
|
||||||
|
bool bg_in_once=false;
|
||||||
|
vec4 outcolbg_once=vec4(0.);
|
||||||
|
bool bg_out_once=false;
|
||||||
|
for( int mx=0; mx<AA; mx++ )
|
||||||
|
for( int nx=0; nx<AA; nx++ )
|
||||||
|
{
|
||||||
|
vec2 o = vec2(mod(float(mx+AA/2),float(AA)),mod(float(nx+AA/2),float(AA))) / float(AA) - 0.5;
|
||||||
|
vec2 uv = (fragCoord + o - 0.5 * iResolution.xy) / iResolution.x;
|
||||||
|
#else
|
||||||
|
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.x;
|
||||||
|
#endif
|
||||||
|
vec3 rd = normalize(w * FDIST + uv.x * u + uv.y * v);
|
||||||
|
|
||||||
|
vec3 ni;
|
||||||
|
float t = box(eye, rd, BOXDIMS, ni, true);
|
||||||
|
vec3 ro = eye + t * rd;
|
||||||
|
vec2 coords = ro.xy * ni.z/BOXDIMS.xy + ro.yz * ni.x/BOXDIMS.yz + ro.zx * ni.y/BOXDIMS.zx;
|
||||||
|
float fadeborders = (1.-smoothstep(0.915,1.05,abs(coords.x)))*(1.-smoothstep(0.915,1.05,abs(coords.y)));
|
||||||
|
|
||||||
|
if (t > 0.)
|
||||||
|
{
|
||||||
|
float ang = -iTime * 0.33;
|
||||||
|
vec3 col = vec3(0.);
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
if(in_once)col=incol_once;
|
||||||
|
else{
|
||||||
|
in_once=true;
|
||||||
|
#endif
|
||||||
|
float R0 = (IOR - 1.) / (IOR + 1.);
|
||||||
|
R0 *= R0;
|
||||||
|
|
||||||
|
vec2 theta = vec2(0.);
|
||||||
|
vec3 n = vec3(cos(theta.x) * sin(theta.y), sin(theta.x) * sin(theta.y), cos(theta.y));
|
||||||
|
|
||||||
|
vec3 nr = n.zxy * ni.x + n.yzx * ni.y + n.xyz * ni.z;
|
||||||
|
vec3 rdr = reflect(rd, nr);
|
||||||
|
float talpha;
|
||||||
|
vec3 reflcol = background(ro, rdr, l_dir,talpha);
|
||||||
|
|
||||||
|
vec3 rd2 = refract(rd, nr, 1. / IOR);
|
||||||
|
|
||||||
|
float accum = 1.;
|
||||||
|
vec3 no2 = ni;
|
||||||
|
vec3 ro_refr = ro;
|
||||||
|
|
||||||
|
vec4 [2] colo = vec4[2](vec4(0.),vec4(0.));
|
||||||
|
|
||||||
|
for (int j = 0; j < 2 + ANGLE_loops; j++)
|
||||||
|
{
|
||||||
|
float tb;
|
||||||
|
vec2 coords2 = ro_refr.xy * no2.z + ro_refr.yz * no2.x + ro_refr.zx * no2.y;
|
||||||
|
vec3 eye2 = vec3(coords2, -1.);
|
||||||
|
vec3 rd2trans = rd2.yzx * no2.x + rd2.zxy * no2.y + rd2.xyz * no2.z;
|
||||||
|
|
||||||
|
rd2trans.z = -rd2trans.z;
|
||||||
|
vec4 internalcol = insides(eye2, rd2trans, no2, l_dir, tb);
|
||||||
|
if (tb > 0.)
|
||||||
|
{
|
||||||
|
internalcol.rgb *= accum;
|
||||||
|
colo[j]=internalcol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tb <= 0.) || (internalcol.a < 1.))
|
||||||
|
{
|
||||||
|
float tout = box(ro_refr, rd2, BOXDIMS, no2, false);
|
||||||
|
no2 = n.zyx * no2.x + n.xzy * no2.y + n.yxz * no2.z;
|
||||||
|
vec3 rout = ro_refr + tout * rd2;
|
||||||
|
vec3 rdout = refract(rd2, -no2, IOR);
|
||||||
|
float fresnel2 = R0 + (1. - R0) * pow(1. - dot(rdout, no2), 1.3);
|
||||||
|
rd2 = reflect(rd2, -no2);
|
||||||
|
|
||||||
|
#ifdef backside_refl
|
||||||
|
if((dot(rdout, no2))>0.5){fresnel2=1.;}
|
||||||
|
#endif
|
||||||
|
ro_refr = rout;
|
||||||
|
ro_refr.z = max(ro_refr.z, -0.999);
|
||||||
|
|
||||||
|
accum *= fresnel2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float fresnel = R0 + (1. - R0) * pow(1. - dot(-rd, nr), 5.);
|
||||||
|
col = mix(mix(colo[1].rgb * colo[1].a, colo[0].rgb, colo[0].a)*fadeborders, reflcol, pow(fresnel, 1.5));
|
||||||
|
col=clamp(col,0.,1.);
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
}
|
||||||
|
incol_once=col;
|
||||||
|
if(!bg_in_once){
|
||||||
|
bg_in_once=true;
|
||||||
|
float alpha;
|
||||||
|
incolbg_once = vec4(background(eye, rd, l_dir, alpha), 0.15);
|
||||||
|
#if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
incolbg_once.w = alpha;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float cineshader_alpha = 0.;
|
||||||
|
cineshader_alpha = clamp(0.15*dot(eye,ro),0.,1.);
|
||||||
|
vec4 tcolx = vec4(col, cineshader_alpha);
|
||||||
|
#if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
tcolx.w = 1.;
|
||||||
|
#endif
|
||||||
|
tot += tcolx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vec4 tcolx = vec4(0.);
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
if(!bg_out_once){
|
||||||
|
bg_out_once=true;
|
||||||
|
#endif
|
||||||
|
float alpha;
|
||||||
|
tcolx = vec4(background(eye, rd, l_dir, alpha), 0.15);
|
||||||
|
#if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
tcolx.w = alpha;
|
||||||
|
#endif
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
outcolbg_once=tcolx;
|
||||||
|
}else tcolx=max(outcolbg_once,incolbg_once);
|
||||||
|
#endif
|
||||||
|
tot += tcolx;
|
||||||
|
}
|
||||||
|
#if defined(AA_CUBE)||defined(AA_ALL)
|
||||||
|
}
|
||||||
|
tot /= float(AA*AA);
|
||||||
|
#endif
|
||||||
|
fragColor = tot;
|
||||||
|
#ifdef NO_ALPHA
|
||||||
|
fragColor.w = 1.;
|
||||||
|
#endif
|
||||||
|
fragColor.rgb=clamp(fragColor.rgb,0.,1.);
|
||||||
|
// Note: iChannel0 line removed (texture channel not supported)
|
||||||
|
// Original line was for optional background blending when BG_ALPHA/ONLY_BOX/SHADOW_ALPHA defined
|
||||||
|
// #if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
// fragColor.rgb=fragColor.rgb*fragColor.w+texture(iChannel0, fragCoord/iResolution.xy).rgb*(1.-fragColor.w);
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
782
data/shaders/cube_lines/cube_lines.vk.glsl
Normal file
782
data/shaders/cube_lines/cube_lines.vk.glsl
Normal file
@@ -0,0 +1,782 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Cube lines
|
||||||
|
// Author: Danil
|
||||||
|
// URL: https://www.shadertoy.com/view/NslGRN
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Note: Original shader uses iChannel0 for background blending (optional feature)
|
||||||
|
// Since we don't support texture channels, that line is commented out
|
||||||
|
// The shader works perfectly without it in default mode
|
||||||
|
|
||||||
|
// Created by Danil (2021+) https://cohost.org/arugl
|
||||||
|
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||||
|
// self https://www.shadertoy.com/view/NslGRN
|
||||||
|
|
||||||
|
|
||||||
|
// --defines for "DESKTOP WALLPAPERS" that use this shader--
|
||||||
|
// comment or uncomment every define to make it work (add or remove "//" before #define)
|
||||||
|
|
||||||
|
|
||||||
|
// this shadertoy use ALPHA, NO_ALPHA set alpha to 1, BG_ALPHA set background as alpha
|
||||||
|
// iChannel0 used as background if alpha ignored by wallpaper-app
|
||||||
|
//#define NO_ALPHA
|
||||||
|
//#define BG_ALPHA
|
||||||
|
//#define SHADOW_ALPHA
|
||||||
|
//#define ONLY_BOX
|
||||||
|
|
||||||
|
|
||||||
|
// save PERFORMANCE by disabling shadow
|
||||||
|
//#define NO_SHADOW
|
||||||
|
|
||||||
|
|
||||||
|
// static CAMERA position, 0.49 on top, 0.001 horizontal
|
||||||
|
//#define CAMERA_POS 0.049
|
||||||
|
|
||||||
|
|
||||||
|
// speed of ROTATION
|
||||||
|
#define ROTATION_SPEED 0.8999
|
||||||
|
|
||||||
|
|
||||||
|
// static SHAPE form, default 0.5
|
||||||
|
//#define STATIC_SHAPE 0.15
|
||||||
|
|
||||||
|
|
||||||
|
// static SCALE far/close to camera, 2.0 is default, exampe 0.5 or 10.0
|
||||||
|
//#define CAMERA_FAR 0.1
|
||||||
|
|
||||||
|
|
||||||
|
// ANIMATION shape change
|
||||||
|
//#define ANIM_SHAPE
|
||||||
|
|
||||||
|
|
||||||
|
// ANIMATION color change
|
||||||
|
//#define ANIM_COLOR
|
||||||
|
|
||||||
|
|
||||||
|
// custom COLOR, and change those const values
|
||||||
|
//#define USE_COLOR
|
||||||
|
const vec3 color_blue=vec3(0.5,0.65,0.8);
|
||||||
|
const vec3 color_red=vec3(0.99,0.2,0.1);
|
||||||
|
|
||||||
|
|
||||||
|
// use 4xAA for cube only (set 2-4-etc level of AA)
|
||||||
|
//#define AA_CUBE 4
|
||||||
|
|
||||||
|
// use 4xAA for everything - derivative filtering will not be used, look fcos2
|
||||||
|
// this is very slow - DO NOT USE
|
||||||
|
//#define AA_ALL 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --shader code--
|
||||||
|
|
||||||
|
// Layers sorted and support transparency and self-intersection-transparency
|
||||||
|
// Antialiasing is only dFd. (with some dFd fixes around edges)
|
||||||
|
|
||||||
|
// using iq's intersectors: https://iquilezles.org/articles/intersectors
|
||||||
|
// using https://www.shadertoy.com/view/ltKBzG
|
||||||
|
// using https://www.shadertoy.com/view/tsVXzh
|
||||||
|
// using https://www.shadertoy.com/view/WlffDn
|
||||||
|
// using https://www.shadertoy.com/view/WslGz4
|
||||||
|
|
||||||
|
#define tshift 53.
|
||||||
|
|
||||||
|
// reflect back side
|
||||||
|
//#define backside_refl
|
||||||
|
|
||||||
|
// Camera with mouse
|
||||||
|
// #define MOUSE_control (disabled - no iMouse support)
|
||||||
|
|
||||||
|
// min(iFrame,0) does not speedup compilation in ANGLE
|
||||||
|
#define ANGLE_loops 0
|
||||||
|
|
||||||
|
|
||||||
|
// this shader discover Nvidia bug with arrays https://www.shadertoy.com/view/NslGR4
|
||||||
|
// use DEBUG with BUG, BUG trigger that bug and one layer will be white on Nvidia in OpenGL
|
||||||
|
//#define DEBUG
|
||||||
|
//#define BUG
|
||||||
|
|
||||||
|
#define FDIST 0.7
|
||||||
|
#define PI 3.1415926
|
||||||
|
#define GROUNDSPACING 0.5
|
||||||
|
#define GROUNDGRID 0.05
|
||||||
|
#define BOXDIMS vec3(0.75, 0.75, 1.25)
|
||||||
|
|
||||||
|
#define IOR 1.33
|
||||||
|
|
||||||
|
mat3 rotx(float a){float s = sin(a);float c = cos(a);return mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, c, s), vec3(0.0, -s, c)); }
|
||||||
|
mat3 roty(float a){float s = sin(a);float c = cos(a);return mat3(vec3(c, 0.0, s), vec3(0.0, 1.0, 0.0), vec3(-s, 0.0, c));}
|
||||||
|
mat3 rotz(float a){float s = sin(a);float c = cos(a);return mat3(vec3(c, s, 0.0), vec3(-s, c, 0.0), vec3(0.0, 0.0, 1.0 ));}
|
||||||
|
|
||||||
|
vec3 fcos1(vec3 x) {
|
||||||
|
vec3 w = fwidth(x);
|
||||||
|
//if((length(w)==0.))return vec3(0.); // dFd fix2
|
||||||
|
//w*=0.; //test
|
||||||
|
float lw=length(w);
|
||||||
|
if((lw==0.)||isnan(lw)||isinf(lw)){vec3 tc=vec3(0.); for(int i=0;i<8;i++)tc+=cos(x+x*float(i-4)*(0.01*400./iResolution.y));return tc/8.;}
|
||||||
|
|
||||||
|
return cos(x) * smoothstep(3.14 * 2.0, 0.0, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fcos2( vec3 x){return cos(x);}
|
||||||
|
vec3 fcos( vec3 x){
|
||||||
|
#ifdef AA_ALL
|
||||||
|
return fcos2(x);
|
||||||
|
#else
|
||||||
|
return fcos1(x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getColor(vec3 p)
|
||||||
|
{
|
||||||
|
// dFd fix, dFd broken on borders, but it fix only top level dFd, self intersection has border
|
||||||
|
//if (length(p) > 0.99)return vec3(0.);
|
||||||
|
p = abs(p);
|
||||||
|
|
||||||
|
p *= 01.25;
|
||||||
|
p = 0.5 * p / dot(p, p);
|
||||||
|
#ifdef ANIM_COLOR
|
||||||
|
p+=0.072*iTime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float t = (0.13) * length(p);
|
||||||
|
vec3 col = vec3(0.3, 0.4, 0.5);
|
||||||
|
col += 0.12 * fcos(6.28318 * t * 1.0 + vec3(0.0, 0.8, 1.1));
|
||||||
|
col += 0.11 * fcos(6.28318 * t * 3.1 + vec3(0.3, 0.4, 0.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 5.1 + vec3(0.1, 0.7, 1.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 17.1 + vec3(0.2, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 31.1 + vec3(0.1, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 65.1 + vec3(0.0, 0.5, 0.8));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 115.1 + vec3(0.1, 0.4, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 265.1 + vec3(1.1, 1.4, 2.7));
|
||||||
|
col = clamp(col, 0., 1.);
|
||||||
|
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calcColor(vec3 ro, vec3 rd, vec3 nor, float d, float len, int idx, bool si, float td, out vec4 colx,
|
||||||
|
out vec4 colsi)
|
||||||
|
{
|
||||||
|
|
||||||
|
vec3 pos = (ro + rd * d);
|
||||||
|
#ifdef DEBUG
|
||||||
|
float a = 1. - smoothstep(len - 0.15, len + 0.00001, length(pos));
|
||||||
|
if (idx == 0)colx = vec4(1., 0., 0., a);
|
||||||
|
if (idx == 1)colx = vec4(0., 1., 0., a);
|
||||||
|
if (idx == 2)colx = vec4(0., 0., 1., a);
|
||||||
|
if (si)
|
||||||
|
{
|
||||||
|
pos = (ro + rd * td);
|
||||||
|
float ta = 1. - smoothstep(len - 0.15, len + 0.00001, length(pos));
|
||||||
|
if (idx == 0)colsi = vec4(1., 0., 0., ta);
|
||||||
|
if (idx == 1)colsi = vec4(0., 1., 0., ta);
|
||||||
|
if (idx == 2)colsi = vec4(0., 0., 1., ta);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
float a = 1. - smoothstep(len - 0.15*0.5, len + 0.00001, length(pos));
|
||||||
|
//a=1.;
|
||||||
|
vec3 col = getColor(pos);
|
||||||
|
colx = vec4(col, a);
|
||||||
|
if (si)
|
||||||
|
{
|
||||||
|
pos = (ro + rd * td);
|
||||||
|
float ta = 1. - smoothstep(len - 0.15*0.5, len + 0.00001, length(pos));
|
||||||
|
//ta=1.;
|
||||||
|
col = getColor(pos);
|
||||||
|
colsi = vec4(col, ta);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// xSI is self intersect data, fade to fix dFd on edges
|
||||||
|
bool iBilinearPatch(in vec3 ro, in vec3 rd, in vec4 ps, in vec4 ph, in float sz, out float t, out vec3 norm,
|
||||||
|
out bool si, out float tsi, out vec3 normsi, out float fade, out float fadesi)
|
||||||
|
{
|
||||||
|
vec3 va = vec3(0.0, 0.0, ph.x + ph.w - ph.y - ph.z);
|
||||||
|
vec3 vb = vec3(0.0, ps.w - ps.y, ph.z - ph.x);
|
||||||
|
vec3 vc = vec3(ps.z - ps.x, 0.0, ph.y - ph.x);
|
||||||
|
vec3 vd = vec3(ps.xy, ph.x);
|
||||||
|
t = -1.;
|
||||||
|
tsi = -1.;
|
||||||
|
si = false;
|
||||||
|
fade = 1.;
|
||||||
|
fadesi = 1.;
|
||||||
|
norm=vec3(0.,1.,0.);normsi=vec3(0.,1.,0.);
|
||||||
|
|
||||||
|
float tmp = 1.0 / (vb.y * vc.x);
|
||||||
|
float a = 0.0;
|
||||||
|
float b = 0.0;
|
||||||
|
float c = 0.0;
|
||||||
|
float d = va.z * tmp;
|
||||||
|
float e = 0.0;
|
||||||
|
float f = 0.0;
|
||||||
|
float g = (vc.z * vb.y - vd.y * va.z) * tmp;
|
||||||
|
float h = (vb.z * vc.x - va.z * vd.x) * tmp;
|
||||||
|
float i = -1.0;
|
||||||
|
float j = (vd.x * vd.y * va.z + vd.z * vb.y * vc.x) * tmp - (vd.y * vb.z * vc.x + vd.x * vc.z * vb.y) * tmp;
|
||||||
|
|
||||||
|
float p = dot(vec3(a, b, c), rd.xzy * rd.xzy) + dot(vec3(d, e, f), rd.xzy * rd.zyx);
|
||||||
|
float q = dot(vec3(2.0, 2.0, 2.0) * ro.xzy * rd.xyz, vec3(a, b, c)) + dot(ro.xzz * rd.zxy, vec3(d, d, e)) +
|
||||||
|
dot(ro.yyx * rd.zxy, vec3(e, f, f)) + dot(vec3(g, h, i), rd.xzy);
|
||||||
|
float r =
|
||||||
|
dot(vec3(a, b, c), ro.xzy * ro.xzy) + dot(vec3(d, e, f), ro.xzy * ro.zyx) + dot(vec3(g, h, i), ro.xzy) + j;
|
||||||
|
|
||||||
|
if (abs(p) < 0.000001)
|
||||||
|
{
|
||||||
|
float tt = -r / q;
|
||||||
|
if (tt <= 0.)
|
||||||
|
return false;
|
||||||
|
t = tt;
|
||||||
|
// normal
|
||||||
|
|
||||||
|
vec3 pos = ro + t * rd;
|
||||||
|
if(length(pos)>sz)return false;
|
||||||
|
vec3 grad =
|
||||||
|
vec3(2.0) * pos.xzy * vec3(a, b, c) + pos.zxz * vec3(d, d, e) + pos.yyx * vec3(f, e, f) + vec3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float sq = q * q - 4.0 * p * r;
|
||||||
|
if (sq < 0.0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float s = sqrt(sq);
|
||||||
|
float t0 = (-q + s) / (2.0 * p);
|
||||||
|
float t1 = (-q - s) / (2.0 * p);
|
||||||
|
float tt1 = min(t0 < 0.0 ? t1 : t0, t1 < 0.0 ? t0 : t1);
|
||||||
|
float tt2 = max(t0 > 0.0 ? t1 : t0, t1 > 0.0 ? t0 : t1);
|
||||||
|
float tt0 = tt1;
|
||||||
|
if (tt0 <= 0.)
|
||||||
|
return false;
|
||||||
|
vec3 pos = ro + tt0 * rd;
|
||||||
|
// black border on end of circle and self intersection with alpha come because dFd
|
||||||
|
// uncomment this to see or rename fcos2 to fcos
|
||||||
|
//sz+=0.3;
|
||||||
|
bool ru = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru)
|
||||||
|
{
|
||||||
|
tt0 = tt2;
|
||||||
|
pos = ro + tt0 * rd;
|
||||||
|
}
|
||||||
|
if (tt0 <= 0.)
|
||||||
|
return false;
|
||||||
|
bool ru2 = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// self intersect
|
||||||
|
if ((tt2 > 0.) && ((!ru)) && !(step(sz, length(ro + tt2 * rd)) > 0.5))
|
||||||
|
{
|
||||||
|
si = true;
|
||||||
|
fadesi=s;
|
||||||
|
tsi = tt2;
|
||||||
|
vec3 tpos = ro + tsi * rd;
|
||||||
|
// normal
|
||||||
|
vec3 tgrad = vec3(2.0) * tpos.xzy * vec3(a, b, c) + tpos.zxz * vec3(d, d, e) +
|
||||||
|
tpos.yyx * vec3(f, e, f) + vec3(g, h, i);
|
||||||
|
normsi = -normalize(tgrad);
|
||||||
|
}
|
||||||
|
|
||||||
|
fade=s;
|
||||||
|
t = tt0;
|
||||||
|
// normal
|
||||||
|
vec3 grad =
|
||||||
|
vec3(2.0) * pos.xzy * vec3(a, b, c) + pos.zxz * vec3(d, d, e) + pos.yyx * vec3(f, e, f) + vec3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float dot2( in vec3 v ) { return dot(v,v); }
|
||||||
|
|
||||||
|
float segShadow( in vec3 ro, in vec3 rd, in vec3 pa, float sh )
|
||||||
|
{
|
||||||
|
float dm = dot(rd.yz,rd.yz);
|
||||||
|
float k1 = (ro.x-pa.x)*dm;
|
||||||
|
float k2 = (ro.x+pa.x)*dm;
|
||||||
|
vec2 k5 = (ro.yz+pa.yz)*dm;
|
||||||
|
float k3 = dot(ro.yz+pa.yz,rd.yz);
|
||||||
|
vec2 k4 = (pa.yz+pa.yz)*rd.yz;
|
||||||
|
vec2 k6 = (pa.yz+pa.yz)*dm;
|
||||||
|
|
||||||
|
for( int i=0; i<4 + ANGLE_loops; i++ )
|
||||||
|
{
|
||||||
|
vec2 s = vec2(i&1,i>>1);
|
||||||
|
float t = dot(s,k4) - k3;
|
||||||
|
|
||||||
|
if( t>0.0 )
|
||||||
|
sh = min(sh,dot2(vec3(clamp(-rd.x*t,k1,k2),k5-k6*s)+rd*t)/(t*t));
|
||||||
|
}
|
||||||
|
return sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
float boxSoftShadow( in vec3 ro, in vec3 rd, in vec3 rad, in float sk )
|
||||||
|
{
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
vec3 rdd = rd;
|
||||||
|
vec3 roo = ro;
|
||||||
|
|
||||||
|
vec3 m = 1.0/rdd;
|
||||||
|
vec3 n = m*roo;
|
||||||
|
vec3 k = abs(m)*rad;
|
||||||
|
|
||||||
|
vec3 t1 = -n - k;
|
||||||
|
vec3 t2 = -n + k;
|
||||||
|
|
||||||
|
float tN = max( max( t1.x, t1.y ), t1.z );
|
||||||
|
float tF = min( min( t2.x, t2.y ), t2.z );
|
||||||
|
|
||||||
|
if( tN<tF && tF>0.0) return 0.0;
|
||||||
|
|
||||||
|
float sh = 1.0;
|
||||||
|
sh = segShadow( roo.xyz, rdd.xyz, rad.xyz, sh );
|
||||||
|
sh = segShadow( roo.yzx, rdd.yzx, rad.yzx, sh );
|
||||||
|
sh = segShadow( roo.zxy, rdd.zxy, rad.zxy, sh );
|
||||||
|
sh = clamp(sk*sqrt(sh),0.0,1.0);
|
||||||
|
return sh*sh*(3.0-2.0*sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
float box(in vec3 ro, in vec3 rd, in vec3 r, out vec3 nn, bool entering)
|
||||||
|
{
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
vec3 dr = 1.0 / rd;
|
||||||
|
vec3 n = ro * dr;
|
||||||
|
vec3 k = r * abs(dr);
|
||||||
|
|
||||||
|
vec3 pin = -k - n;
|
||||||
|
vec3 pout = k - n;
|
||||||
|
float tin = max(pin.x, max(pin.y, pin.z));
|
||||||
|
float tout = min(pout.x, min(pout.y, pout.z));
|
||||||
|
if (tin > tout)
|
||||||
|
return -1.;
|
||||||
|
if (entering)
|
||||||
|
{
|
||||||
|
nn = -sign(rd) * step(pin.zxy, pin.xyz) * step(pin.yzx, pin.xyz);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nn = sign(rd) * step(pout.xyz, pout.zxy) * step(pout.xyz, pout.yzx);
|
||||||
|
}
|
||||||
|
return entering ? tin : tout;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bgcol(in vec3 rd)
|
||||||
|
{
|
||||||
|
return mix(vec3(0.01), vec3(0.336, 0.458, .668), 1. - pow(abs(rd.z+0.25), 1.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 background(in vec3 ro, in vec3 rd , vec3 l_dir, out float alpha)
|
||||||
|
{
|
||||||
|
#ifdef ONLY_BOX
|
||||||
|
alpha=0.;
|
||||||
|
return vec3(0.01);
|
||||||
|
#endif
|
||||||
|
float t = (-BOXDIMS.z - ro.z) / rd.z;
|
||||||
|
alpha=0.;
|
||||||
|
vec3 bgc = bgcol(rd);
|
||||||
|
if (t < 0.)
|
||||||
|
return bgc;
|
||||||
|
vec2 uv = ro.xy + t * rd.xy;
|
||||||
|
#ifdef NO_SHADOW
|
||||||
|
float shad=1.;
|
||||||
|
#else
|
||||||
|
float shad = boxSoftShadow((ro + t * rd), normalize(l_dir+vec3(0.,0.,1.))*rotz(PI*0.65) , BOXDIMS, 1.5);
|
||||||
|
#endif
|
||||||
|
float aofac = smoothstep(-0.95, .75, length(abs(uv) - min(abs(uv), vec2(0.45))));
|
||||||
|
aofac = min(aofac,smoothstep(-0.65, 1., shad));
|
||||||
|
float lght=max(dot(normalize(ro + t * rd+vec3(0.,-0.,-5.)), normalize(l_dir-vec3(0.,0.,1.))*rotz(PI*0.65)), 0.0);
|
||||||
|
vec3 col = mix(vec3(0.4), vec3(.71,.772,0.895), lght*lght* aofac+ 0.05) * aofac;
|
||||||
|
alpha=1.-smoothstep(7.,10.,length(uv));
|
||||||
|
#ifdef SHADOW_ALPHA
|
||||||
|
//alpha=clamp(alpha*max(lght*lght*0.95,(1.-aofac)*1.25),0.,1.);
|
||||||
|
alpha=clamp(alpha*(1.-aofac)*1.25,0.,1.);
|
||||||
|
#endif
|
||||||
|
return mix(col*length(col)*0.8,bgc,smoothstep(7.,10.,length(uv)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define swap(a,b) tv=a;a=b;b=tv
|
||||||
|
|
||||||
|
vec4 insides(vec3 ro, vec3 rd, vec3 nor_c, vec3 l_dir, out float tout)
|
||||||
|
{
|
||||||
|
tout = -1.;
|
||||||
|
vec3 trd=rd;
|
||||||
|
|
||||||
|
vec3 col = vec3(0.);
|
||||||
|
|
||||||
|
float pi = 3.1415926;
|
||||||
|
|
||||||
|
if (abs(nor_c.x) > 0.5)
|
||||||
|
{
|
||||||
|
rd = rd.xzy * nor_c.x;
|
||||||
|
ro = ro.xzy * nor_c.x;
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.z) > 0.5)
|
||||||
|
{
|
||||||
|
l_dir *= roty(pi);
|
||||||
|
rd = rd.yxz * nor_c.z;
|
||||||
|
ro = ro.yxz * nor_c.z;
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.y) > 0.5)
|
||||||
|
{
|
||||||
|
l_dir *= rotz(-pi * 0.5);
|
||||||
|
rd = rd * nor_c.y;
|
||||||
|
ro = ro * nor_c.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ANIM_SHAPE
|
||||||
|
float curvature = (0.001+1.5-1.5*smoothstep(0.,8.5,mod((iTime+tshift)*0.44,20.))*(1.-smoothstep(10.,18.5,mod((iTime+tshift)*0.44,20.))));
|
||||||
|
// curvature(to not const above) make compilation on Angle 15+ sec
|
||||||
|
#else
|
||||||
|
#ifdef STATIC_SHAPE
|
||||||
|
const float curvature = STATIC_SHAPE;
|
||||||
|
#else
|
||||||
|
const float curvature = .5;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
float bil_size = 1.;
|
||||||
|
vec4 ps = vec4(-bil_size, -bil_size, bil_size, bil_size) * curvature;
|
||||||
|
vec4 ph = vec4(-bil_size, bil_size, bil_size, -bil_size) * curvature;
|
||||||
|
|
||||||
|
vec4 [3]colx=vec4[3](vec4(0.),vec4(0.),vec4(0.));
|
||||||
|
vec3 [3]dx=vec3[3](vec3(-1.),vec3(-1.),vec3(-1.));
|
||||||
|
vec4 [3]colxsi=vec4[3](vec4(0.),vec4(0.),vec4(0.));
|
||||||
|
int [3]order=int[3](0,1,2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3 + ANGLE_loops; i++)
|
||||||
|
{
|
||||||
|
if (abs(nor_c.x) > 0.5)
|
||||||
|
{
|
||||||
|
ro *= rotz(-pi * (1. / float(3)));
|
||||||
|
rd *= rotz(-pi * (1. / float(3)));
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.z) > 0.5)
|
||||||
|
{
|
||||||
|
ro *= rotz(pi * (1. / float(3)));
|
||||||
|
rd *= rotz(pi * (1. / float(3)));
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.y) > 0.5)
|
||||||
|
{
|
||||||
|
ro *= rotx(pi * (1. / float(3)));
|
||||||
|
rd *= rotx(pi * (1. / float(3)));
|
||||||
|
}
|
||||||
|
vec3 normnew;
|
||||||
|
float tnew;
|
||||||
|
bool si;
|
||||||
|
float tsi;
|
||||||
|
vec3 normsi;
|
||||||
|
float fade;
|
||||||
|
float fadesi;
|
||||||
|
|
||||||
|
if (iBilinearPatch(ro, rd, ps, ph, bil_size, tnew, normnew, si, tsi, normsi, fade, fadesi))
|
||||||
|
{
|
||||||
|
if (tnew > 0.)
|
||||||
|
{
|
||||||
|
vec4 tcol, tcolsi;
|
||||||
|
calcColor(ro, rd, normnew, tnew, bil_size, i, si, tsi, tcol, tcolsi);
|
||||||
|
if (tcol.a > 0.0)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
vec3 tvalx = vec3(tnew, float(si), tsi);
|
||||||
|
dx[i]=tvalx;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
colx[i]=tcol;
|
||||||
|
if (si)colxsi[i]=tcolsi;
|
||||||
|
#else
|
||||||
|
|
||||||
|
float dif = clamp(dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
float amb = clamp(0.5 + 0.5 * dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
|
||||||
|
{
|
||||||
|
#ifdef USE_COLOR
|
||||||
|
vec3 shad = 0.57 * color_blue * amb + 1.5*color_blue.bgr * dif;
|
||||||
|
const vec3 tcr = color_red;
|
||||||
|
#else
|
||||||
|
vec3 shad = vec3(0.32, 0.43, 0.54) * amb + vec3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const vec3 tcr = vec3(1.,0.21,0.11);
|
||||||
|
#endif
|
||||||
|
float ta = clamp(length(tcol.rgb),0.,1.);
|
||||||
|
tcol=clamp(tcol*tcol*2.,0.,1.);
|
||||||
|
vec4 tvalx =
|
||||||
|
vec4((tcol.rgb*shad*1.4 + 3.*(tcr*tcol.rgb)*clamp(1.-(amb+dif),0.,1.)), min(tcol.a,ta));
|
||||||
|
tvalx.rgb=clamp(2.*tvalx.rgb*tvalx.rgb,0.,1.);
|
||||||
|
tvalx*=(min(fade*5.,1.));
|
||||||
|
colx[i]=tvalx;
|
||||||
|
}
|
||||||
|
if (si)
|
||||||
|
{
|
||||||
|
dif = clamp(dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
amb = clamp(0.5 + 0.5 * dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
{
|
||||||
|
#ifdef USE_COLOR
|
||||||
|
vec3 shad = 0.57 * color_blue * amb + 1.5*color_blue.bgr * dif;
|
||||||
|
const vec3 tcr = color_red;
|
||||||
|
#else
|
||||||
|
vec3 shad = vec3(0.32, 0.43, 0.54) * amb + vec3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const vec3 tcr = vec3(1.,0.21,0.11);
|
||||||
|
#endif
|
||||||
|
float ta = clamp(length(tcolsi.rgb),0.,1.);
|
||||||
|
tcolsi=clamp(tcolsi*tcolsi*2.,0.,1.);
|
||||||
|
vec4 tvalx =
|
||||||
|
vec4(tcolsi.rgb * shad + 3.*(tcr*tcolsi.rgb)*clamp(1.-(amb+dif),0.,1.), min(tcolsi.a,ta));
|
||||||
|
tvalx.rgb=clamp(2.*tvalx.rgb*tvalx.rgb,0.,1.);
|
||||||
|
tvalx.rgb*=(min(fadesi*5.,1.));
|
||||||
|
colxsi[i]=tvalx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// transparency logic and layers sorting
|
||||||
|
float a = 1.;
|
||||||
|
if (dx[0].x < dx[1].x){{vec3 swap(dx[0], dx[1]);}{int swap(order[0], order[1]);}}
|
||||||
|
if (dx[1].x < dx[2].x){{vec3 swap(dx[1], dx[2]);}{int swap(order[1], order[2]);}}
|
||||||
|
if (dx[0].x < dx[1].x){{vec3 swap(dx[0], dx[1]);}{int swap(order[0], order[1]);}}
|
||||||
|
|
||||||
|
tout = max(max(dx[0].x, dx[1].x), dx[2].x);
|
||||||
|
|
||||||
|
if (dx[0].y < 0.5)
|
||||||
|
{
|
||||||
|
a=colx[order[0]].a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(defined(DEBUG)&&defined(BUG))
|
||||||
|
|
||||||
|
// self intersection
|
||||||
|
bool [3] rul= bool[3](
|
||||||
|
((dx[0].y > 0.5) && (dx[1].x <= 0.)),
|
||||||
|
((dx[1].y > 0.5) && (dx[0].x > dx[1].z)),
|
||||||
|
((dx[2].y > 0.5) && (dx[1].x > dx[2].z))
|
||||||
|
);
|
||||||
|
for(int k=0;k<3;k++){
|
||||||
|
if(rul[k]){
|
||||||
|
vec4 tcolxsi = vec4(0.);
|
||||||
|
tcolxsi=colxsi[order[k]];
|
||||||
|
vec4 tcolx = vec4(0.);
|
||||||
|
tcolx=colx[order[k]];
|
||||||
|
|
||||||
|
vec4 tvalx = mix(tcolxsi, tcolx, tcolx.a);
|
||||||
|
colx[order[k]]=tvalx;
|
||||||
|
|
||||||
|
vec4 tvalx2 = mix(vec4(0.), tvalx, max(tcolx.a, tcolxsi.a));
|
||||||
|
colx[order[k]]=tvalx2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float a1 = (dx[1].y < 0.5) ? colx[order[1]].a : ((dx[1].z > dx[0].x) ? colx[order[1]].a : 1.);
|
||||||
|
float a2 = (dx[2].y < 0.5) ? colx[order[2]].a : ((dx[2].z > dx[1].x) ? colx[order[2]].a : 1.);
|
||||||
|
col = mix(mix(colx[order[0]].rgb, colx[order[1]].rgb, a1), colx[order[2]].rgb, a2);
|
||||||
|
a = max(max(a, a1), a2);
|
||||||
|
return vec4(col, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord)
|
||||||
|
{
|
||||||
|
float osc = 0.5;
|
||||||
|
vec3 l_dir = normalize(vec3(0., 1., 0.));
|
||||||
|
l_dir *= rotz(0.5);
|
||||||
|
float mouseY = 1.0 * 0.5 * PI;
|
||||||
|
// Note: MOUSE_control disabled (no iMouse support)
|
||||||
|
// #ifdef MOUSE_control
|
||||||
|
// mouseY = (1.0 - 1.15 * iMouse.y / iResolution.y) * 0.5 * PI;
|
||||||
|
// if(iMouse.y < 1.)
|
||||||
|
// #endif
|
||||||
|
#ifdef CAMERA_POS
|
||||||
|
mouseY = PI*CAMERA_POS;
|
||||||
|
#else
|
||||||
|
mouseY = PI*0.49 - smoothstep(0.,8.5,mod((iTime+tshift)*0.33,25.))*(1.-smoothstep(14.,24.0,mod((iTime+tshift)*0.33,25.))) * 0.55 * PI;
|
||||||
|
#endif
|
||||||
|
#ifdef ROTATION_SPEED
|
||||||
|
float mouseX = -2.*PI-0.25*(iTime*ROTATION_SPEED+tshift);
|
||||||
|
#else
|
||||||
|
float mouseX = -2.*PI-0.25*(iTime+tshift);
|
||||||
|
#endif
|
||||||
|
// Note: MOUSE_control disabled (no iMouse support)
|
||||||
|
// #ifdef MOUSE_control
|
||||||
|
// mouseX+=-(iMouse.x / iResolution.x) * 2. * PI;
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
#ifdef CAMERA_FAR
|
||||||
|
vec3 eye = (2. + CAMERA_FAR) * vec3(cos(mouseX) * cos(mouseY), sin(mouseX) * cos(mouseY), sin(mouseY));
|
||||||
|
#else
|
||||||
|
vec3 eye = 4. * vec3(cos(mouseX) * cos(mouseY), sin(mouseX) * cos(mouseY), sin(mouseY));
|
||||||
|
#endif
|
||||||
|
vec3 w = normalize(-eye);
|
||||||
|
vec3 up = vec3(0., 0., 1.);
|
||||||
|
vec3 u = normalize(cross(w, up));
|
||||||
|
vec3 v = cross(u, w);
|
||||||
|
|
||||||
|
vec4 tot=vec4(0.);
|
||||||
|
#if defined(AA_CUBE)||defined(AA_ALL)
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
const int AA = AA_CUBE;
|
||||||
|
#else
|
||||||
|
const int AA = AA_ALL;
|
||||||
|
#endif
|
||||||
|
vec3 incol_once=vec3(0.);
|
||||||
|
bool in_once=false;
|
||||||
|
vec4 incolbg_once=vec4(0.);
|
||||||
|
bool bg_in_once=false;
|
||||||
|
vec4 outcolbg_once=vec4(0.);
|
||||||
|
bool bg_out_once=false;
|
||||||
|
for( int mx=0; mx<AA; mx++ )
|
||||||
|
for( int nx=0; nx<AA; nx++ )
|
||||||
|
{
|
||||||
|
vec2 o = vec2(mod(float(mx+AA/2),float(AA)),mod(float(nx+AA/2),float(AA))) / float(AA) - 0.5;
|
||||||
|
vec2 uv = (fragCoord + o - 0.5 * iResolution.xy) / iResolution.x;
|
||||||
|
#else
|
||||||
|
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.x;
|
||||||
|
#endif
|
||||||
|
vec3 rd = normalize(w * FDIST + uv.x * u + uv.y * v);
|
||||||
|
|
||||||
|
vec3 ni;
|
||||||
|
float t = box(eye, rd, BOXDIMS, ni, true);
|
||||||
|
vec3 ro = eye + t * rd;
|
||||||
|
vec2 coords = ro.xy * ni.z/BOXDIMS.xy + ro.yz * ni.x/BOXDIMS.yz + ro.zx * ni.y/BOXDIMS.zx;
|
||||||
|
float fadeborders = (1.-smoothstep(0.915,1.05,abs(coords.x)))*(1.-smoothstep(0.915,1.05,abs(coords.y)));
|
||||||
|
|
||||||
|
if (t > 0.)
|
||||||
|
{
|
||||||
|
float ang = -iTime * 0.33;
|
||||||
|
vec3 col = vec3(0.);
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
if(in_once)col=incol_once;
|
||||||
|
else{
|
||||||
|
in_once=true;
|
||||||
|
#endif
|
||||||
|
float R0 = (IOR - 1.) / (IOR + 1.);
|
||||||
|
R0 *= R0;
|
||||||
|
|
||||||
|
vec2 theta = vec2(0.);
|
||||||
|
vec3 n = vec3(cos(theta.x) * sin(theta.y), sin(theta.x) * sin(theta.y), cos(theta.y));
|
||||||
|
|
||||||
|
vec3 nr = n.zxy * ni.x + n.yzx * ni.y + n.xyz * ni.z;
|
||||||
|
vec3 rdr = reflect(rd, nr);
|
||||||
|
float talpha;
|
||||||
|
vec3 reflcol = background(ro, rdr, l_dir,talpha);
|
||||||
|
|
||||||
|
vec3 rd2 = refract(rd, nr, 1. / IOR);
|
||||||
|
|
||||||
|
float accum = 1.;
|
||||||
|
vec3 no2 = ni;
|
||||||
|
vec3 ro_refr = ro;
|
||||||
|
|
||||||
|
vec4 [2] colo = vec4[2](vec4(0.),vec4(0.));
|
||||||
|
|
||||||
|
for (int j = 0; j < 2 + ANGLE_loops; j++)
|
||||||
|
{
|
||||||
|
float tb;
|
||||||
|
vec2 coords2 = ro_refr.xy * no2.z + ro_refr.yz * no2.x + ro_refr.zx * no2.y;
|
||||||
|
vec3 eye2 = vec3(coords2, -1.);
|
||||||
|
vec3 rd2trans = rd2.yzx * no2.x + rd2.zxy * no2.y + rd2.xyz * no2.z;
|
||||||
|
|
||||||
|
rd2trans.z = -rd2trans.z;
|
||||||
|
vec4 internalcol = insides(eye2, rd2trans, no2, l_dir, tb);
|
||||||
|
if (tb > 0.)
|
||||||
|
{
|
||||||
|
internalcol.rgb *= accum;
|
||||||
|
colo[j]=internalcol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tb <= 0.) || (internalcol.a < 1.))
|
||||||
|
{
|
||||||
|
float tout = box(ro_refr, rd2, BOXDIMS, no2, false);
|
||||||
|
no2 = n.zyx * no2.x + n.xzy * no2.y + n.yxz * no2.z;
|
||||||
|
vec3 rout = ro_refr + tout * rd2;
|
||||||
|
vec3 rdout = refract(rd2, -no2, IOR);
|
||||||
|
float fresnel2 = R0 + (1. - R0) * pow(1. - dot(rdout, no2), 1.3);
|
||||||
|
rd2 = reflect(rd2, -no2);
|
||||||
|
|
||||||
|
#ifdef backside_refl
|
||||||
|
if((dot(rdout, no2))>0.5){fresnel2=1.;}
|
||||||
|
#endif
|
||||||
|
ro_refr = rout;
|
||||||
|
ro_refr.z = max(ro_refr.z, -0.999);
|
||||||
|
|
||||||
|
accum *= fresnel2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float fresnel = R0 + (1. - R0) * pow(1. - dot(-rd, nr), 5.);
|
||||||
|
col = mix(mix(colo[1].rgb * colo[1].a, colo[0].rgb, colo[0].a)*fadeborders, reflcol, pow(fresnel, 1.5));
|
||||||
|
col=clamp(col,0.,1.);
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
}
|
||||||
|
incol_once=col;
|
||||||
|
if(!bg_in_once){
|
||||||
|
bg_in_once=true;
|
||||||
|
float alpha;
|
||||||
|
incolbg_once = vec4(background(eye, rd, l_dir, alpha), 0.15);
|
||||||
|
#if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
incolbg_once.w = alpha;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float cineshader_alpha = 0.;
|
||||||
|
cineshader_alpha = clamp(0.15*dot(eye,ro),0.,1.);
|
||||||
|
vec4 tcolx = vec4(col, cineshader_alpha);
|
||||||
|
#if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
tcolx.w = 1.;
|
||||||
|
#endif
|
||||||
|
tot += tcolx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vec4 tcolx = vec4(0.);
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
if(!bg_out_once){
|
||||||
|
bg_out_once=true;
|
||||||
|
#endif
|
||||||
|
float alpha;
|
||||||
|
tcolx = vec4(background(eye, rd, l_dir, alpha), 0.15);
|
||||||
|
#if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
tcolx.w = alpha;
|
||||||
|
#endif
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
outcolbg_once=tcolx;
|
||||||
|
}else tcolx=max(outcolbg_once,incolbg_once);
|
||||||
|
#endif
|
||||||
|
tot += tcolx;
|
||||||
|
}
|
||||||
|
#if defined(AA_CUBE)||defined(AA_ALL)
|
||||||
|
}
|
||||||
|
tot /= float(AA*AA);
|
||||||
|
#endif
|
||||||
|
fragColor = tot;
|
||||||
|
#ifdef NO_ALPHA
|
||||||
|
fragColor.w = 1.;
|
||||||
|
#endif
|
||||||
|
fragColor.rgb=clamp(fragColor.rgb,0.,1.);
|
||||||
|
// Note: iChannel0 line removed (texture channel not supported)
|
||||||
|
// Original line was for optional background blending when BG_ALPHA/ONLY_BOX/SHADOW_ALPHA defined
|
||||||
|
// #if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
// fragColor.rgb=fragColor.rgb*fragColor.w+texture(iChannel0, fragCoord/iResolution.xy).rgb*(1.-fragColor.w);
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/cube_lines/meta.txt
Normal file
2
data/shaders/cube_lines/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Cube lines
|
||||||
|
Author: Danil
|
||||||
127
data/shaders/dbz/dbz.frag.msl
Normal file
127
data/shaders/dbz/dbz.frag.msl
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// New Leaked 3I/Atlas NASA Footage — msm01
|
||||||
|
// MSL port of dbz.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
constant float NBCaps = 3.0;
|
||||||
|
|
||||||
|
static float2x2 r2d(float a) {
|
||||||
|
float c = cos(a), s = sin(a);
|
||||||
|
return float2x2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float hash12(float2 p) {
|
||||||
|
float3 p3 = fract(float3(p.xyx) * 0.1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float fbm(float2 v_p) {
|
||||||
|
float pvpx = v_p.x;
|
||||||
|
float2 V1 = float2(floor(pvpx));
|
||||||
|
float2 V2 = float2(floor(pvpx + 1.0));
|
||||||
|
return mix(hash12(V1), hash12(V2), smoothstep(0.0, 1.0, fract(pvpx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define S(a,b,c) smoothstep(a,b,c)
|
||||||
|
|
||||||
|
fragment float4 dbz_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 p = float2((1.0 / U.iResolution.y) * (fragCoord.x - U.iResolution.x / 2.0),
|
||||||
|
fragCoord.y / U.iResolution.y - 0.5);
|
||||||
|
|
||||||
|
p.x = -p.x;
|
||||||
|
p *= 150.0;
|
||||||
|
|
||||||
|
float4 col = float4(0.05, 0.05, 0.15, 1.0);
|
||||||
|
|
||||||
|
float2 save1 = p;
|
||||||
|
|
||||||
|
p = p * r2d(-0.05);
|
||||||
|
col = mix(col, float4(0.2, 0.3, 0.5, 1.0),
|
||||||
|
smoothstep(75.0, 0.0, abs(p.y - 5.0 * fbm(float2(0.01 * (p.x - 33.333 * U.iTime))) + 3.5)));
|
||||||
|
p = p * r2d(0.05);
|
||||||
|
|
||||||
|
p = p * r2d(-0.05);
|
||||||
|
p *= 0.35;
|
||||||
|
p += float2(-5.0 * U.iTime, 0.0);
|
||||||
|
|
||||||
|
float2 b = fract(5.0 * p);
|
||||||
|
p = floor(5.0 * p);
|
||||||
|
if (fbm(float2(p.x * p.y)) > 0.996) {
|
||||||
|
col += clamp(1.0 - pow(3.0 * length(b + float2(-0.5)), 0.5), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = save1;
|
||||||
|
float2 save3;
|
||||||
|
|
||||||
|
float Nb_Capsules = clamp(NBCaps, 0.0, 4.0);
|
||||||
|
for (float i = 0.0; i < Nb_Capsules; i++) {
|
||||||
|
p = save1;
|
||||||
|
p = p * r2d(-0.05);
|
||||||
|
p *= 2.5;
|
||||||
|
p *= 1.0 - 0.25 * i;
|
||||||
|
p += float2(150.0 * fbm(float2(0.15 * U.iTime + i * 54.321)) - 75.0,
|
||||||
|
50.0 * sin(0.25 * U.iTime + i * 54.321) - 25.0);
|
||||||
|
save3 = p;
|
||||||
|
|
||||||
|
p *= 0.04;
|
||||||
|
p.y = abs(p.y);
|
||||||
|
|
||||||
|
if (p.x > 0.0) {
|
||||||
|
col += float4(0.0, 1.0, 0.5, 1.0) * smoothstep(0.2, 0.0, abs(p.y - 0.05 * fbm(float2(1.5 * p.x - 40.0 * U.iTime))) - 0.05) * smoothstep(29.0, 0.0, abs(p.x));
|
||||||
|
col += float4(1.0, 1.0, 1.0, 1.0) * smoothstep(0.1, 0.0, abs(p.y - 0.05 * fbm(float2(1.5 * p.x - 40.0 * U.iTime))) - 0.05) * smoothstep(29.0, 0.0, abs(p.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
p = save3;
|
||||||
|
p.y = abs(p.y);
|
||||||
|
p += float2(-10.0, 0.0);
|
||||||
|
p *= float2(0.75, 1.0);
|
||||||
|
|
||||||
|
col += 0.8 * float4(0.0, 1.0, 0.5, 1.0) * S(20.0, 0.0, length(p) - 25.0 + 7.0 * sin(0.30 * length(p) * atan2(p.y, p.x) + 55.0 * U.iTime));
|
||||||
|
col += 0.8 * float4(1.0, 1.0, 1.0, 1.0) * S(20.0, 0.0, length(p) - 20.0 + 7.0 * sin(0.30 * length(p) * atan2(p.y, p.x) + 55.0 * U.iTime));
|
||||||
|
|
||||||
|
p = save3;
|
||||||
|
|
||||||
|
col = mix(col, float4(1.0), 0.5 * S(10.0, 0.0, length(p + float2(5.0, 0.0)) - 20.0) * abs(sin(50.0 * U.iTime)));
|
||||||
|
col = mix(col, float4(1.0), 0.5 * S(20.0, 0.0, length(p + float2(5.0, 0.0)) - 20.0));
|
||||||
|
col = mix(col, float4(1.0), S(0.01, 0.0, length(p) - 20.0));
|
||||||
|
|
||||||
|
if (length(p) - 20.0 < 0.0) {
|
||||||
|
col = mix(col, float4(0.65, 0.68, 0.68 + 0.1 * (3.0 - i), 1.0), S(0.5, 0.0, length(p - float2(2.0, 0.0)) - 17.0));
|
||||||
|
if (S(0.0, 1.0, length(float2(3.0, 2.0) * p + float2(33.5, 0.0)) - 23.0) > 0.0) {
|
||||||
|
col = mix(col, float4(0.45, 0.55, 0.55 + 0.1 * (3.0 - i), 1.0),
|
||||||
|
0.75 * S(0.5, 0.0, length(p - float2(2.0, 0.0) + 0.5 * fbm(float2(4.5 * atan2(p.y, p.x)))) - 9.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
col = mix(col, float4(0.0), S(0.2, 0.0, abs(length(p) - 19.9) - 0.20));
|
||||||
|
col = mix(col, float4(0.5, 0.2, 0.3, 1.0)
|
||||||
|
- S(5.0, 0.0, length(p + float2(-6.0, 15.0)) - 20.0)
|
||||||
|
- S(0.25, 0.0, abs(length(p + float2(0.0, 3.0)) - 15.0) - 0.4)
|
||||||
|
- S(0.0, 1.5, p.y - 8.5)
|
||||||
|
+ 0.25 * float4(1.0, 0.5, 0.0, 1.0) * S(10.0, 0.0, abs(p.y))
|
||||||
|
,
|
||||||
|
S(0.5, 0.0, length(float2(3.0, 2.0) * p + float2(35.0, 0.0)) - 19.9));
|
||||||
|
|
||||||
|
col = mix(col, float4(0.0, 0.0, 0.0, 1.0), S(1.0, 0.0, abs(length(float2(3.0, 2.0) * p + float2(35.0, 0.0)) - 19.9) - 0.1));
|
||||||
|
col = mix(col, float4(0.0, 0.0, 0.0, 1.0), S(1.0, 0.0, abs(length(float2(3.0, 2.0) * p + float2(33.5, 0.0)) - 23.0) - 0.1));
|
||||||
|
|
||||||
|
if (p.y > 0.0) col = mix(col, float4(0.0, 0.0, 0.0, 1.0), S(1.0, 0.0, abs(length(float2(3.0, 2.0) * p + float2(29.0, 0.0)) - 30.0) - 0.1));
|
||||||
|
if (p.y < 0.0) col = mix(col, float4(0.0, 0.0, 0.0, 1.0), S(1.0, 0.0, abs(length(float2(3.0, 2.0) * p + float2(-31.0, 0.0)) - 30.0) - 0.1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clamp(col, 0.0, 1.0);
|
||||||
|
}
|
||||||
BIN
data/shaders/dbz/dbz.frag.spv
Normal file
BIN
data/shaders/dbz/dbz.frag.spv
Normal file
Binary file not shown.
190
data/shaders/dbz/dbz.gl.glsl
Normal file
190
data/shaders/dbz/dbz.gl.glsl
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
// Name: New Leaked 3I/Atlas NASA Footage
|
||||||
|
// Author: msm01
|
||||||
|
// URL: https://www.shadertoy.com/view/3ftcRr
|
||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
// A small improv/fanart from yesterday.
|
||||||
|
|
||||||
|
#define s(a,b,c) smoothstep(a,b,c)
|
||||||
|
#define PI 3.14159
|
||||||
|
#define NBCaps 3.
|
||||||
|
|
||||||
|
mat2 r2d( float a ){ float c = cos(a), s = sin(a); return mat2( c, s, -s, c ); }
|
||||||
|
float metaDiamond(vec2 p, vec2 pixel, float r){ vec2 d = abs(p-pixel); return r / (d.x + d.y); }
|
||||||
|
|
||||||
|
// Dave Hoskins's hash ! Noone can hash hashes like he hashes !
|
||||||
|
float hash12(vec2 p)
|
||||||
|
{
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * .1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
// Smoothed 1D-noise. Just like Zoltraak : stupid simple. Powerful.
|
||||||
|
float fbm(in vec2 v_p)
|
||||||
|
{
|
||||||
|
float pvpx = v_p.x;
|
||||||
|
vec2 V1 = vec2(floor(pvpx ));
|
||||||
|
vec2 V2 = vec2(floor(pvpx + 1.0));
|
||||||
|
return mix(hash12(V1),hash12(V2),smoothstep(0.0,1.0,fract(pvpx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
|
{
|
||||||
|
// Get Base Coordinates
|
||||||
|
vec2 p = vec2( (1.0/iResolution.y)*(fragCoord.x - iResolution.x/2.0),fragCoord.y / iResolution.y - 0.5);
|
||||||
|
|
||||||
|
// reversed, for accurate Martian perspective... :)
|
||||||
|
p.x=-p.x;
|
||||||
|
|
||||||
|
// Zoom out
|
||||||
|
p*=150.0;
|
||||||
|
|
||||||
|
// Init the Accumulator
|
||||||
|
vec4 col = vec4(0.05,0.05,0.15,1.0);
|
||||||
|
|
||||||
|
// Make up other boxes and save base in them.
|
||||||
|
vec2 save1 = p;
|
||||||
|
vec2 save2 = p;
|
||||||
|
|
||||||
|
// Faint Nebula Background
|
||||||
|
|
||||||
|
// Tilt the camera
|
||||||
|
p*= r2d(-0.05);
|
||||||
|
// Space Background Gradient
|
||||||
|
col = mix(col,vec4(0.2,0.3,0.5,1.0),smoothstep(75.0,0.0,abs(p.y - 5.0*fbm(vec2(0.01*(p.x - 33.333*iTime))) + 3.5)));
|
||||||
|
// Untilt the camera
|
||||||
|
p*= r2d( 0.05);
|
||||||
|
|
||||||
|
// BG Starfield
|
||||||
|
|
||||||
|
// Rotate
|
||||||
|
p*= r2d(-0.05);
|
||||||
|
// Zoom In
|
||||||
|
p*= 0.35;
|
||||||
|
// Scroll Left
|
||||||
|
p+= vec2(-5.0*iTime,0.0);
|
||||||
|
|
||||||
|
// Hack the coords...
|
||||||
|
vec2 b = fract(5.0*p);
|
||||||
|
p = floor(5.0*p);
|
||||||
|
// Draw the stars
|
||||||
|
if( fbm(vec2(p.x*p.y)) > 0.996)col += clamp(1.0-pow(3.0*length(b+vec2(-0.5)),0.5),0.0,1.0);
|
||||||
|
|
||||||
|
// Reload because the coords are all f.. up now !
|
||||||
|
p = save1;
|
||||||
|
// Another Box...
|
||||||
|
vec2 save3;
|
||||||
|
|
||||||
|
// We're going to draw max 4 capsules max.
|
||||||
|
// Yes we could draw more but Earth must survive, man. Have mercy !
|
||||||
|
float Nb_Capsules = clamp(NBCaps,0.0,4.0);
|
||||||
|
for( float i = 0.0;i<Nb_Capsules; i++ )
|
||||||
|
{
|
||||||
|
// Reloooooaaaaad !
|
||||||
|
p = save1;
|
||||||
|
// Tilt as much as we tilted the stars...
|
||||||
|
p*= r2d(-0.05);
|
||||||
|
// Zoom out a bit
|
||||||
|
p*=2.5;
|
||||||
|
// Then zoom in a bit closer every loop.
|
||||||
|
p*=1.0-0.25*i;
|
||||||
|
// Compute Random Coordinates For Each Capsule Position
|
||||||
|
// Move To That Position.
|
||||||
|
p += vec2(150.0*fbm(vec2(0.15*iTime + i*54.321)) - 75.0, // X varies randomly
|
||||||
|
50.0*sin( 0.25*iTime + i*54.321) - 25.0); // Y varies periodically
|
||||||
|
// Save Position
|
||||||
|
save3 = p;
|
||||||
|
|
||||||
|
// Mega Zoom
|
||||||
|
p*=0.04;
|
||||||
|
// (Ox)-axis Symetry for jets
|
||||||
|
p.y = abs(p.y);
|
||||||
|
|
||||||
|
if( p.x > 0.0 )
|
||||||
|
{
|
||||||
|
// Green Jet
|
||||||
|
col += vec4(0.0,1.0,0.5,1.0)*smoothstep(0.2,0.0,abs(p.y - 0.05*fbm(vec2(1.5*p.x - 40.0*iTime)))-0.05)*smoothstep(29.0,0.0,abs(p.x));
|
||||||
|
// White Jet
|
||||||
|
col += vec4(1.0,1.0,1.0,1.0)*smoothstep(0.1,0.0,abs(p.y - 0.05*fbm(vec2(1.5*p.x - 40.0*iTime)))-0.05)*smoothstep(29.0,0.0,abs(p.x));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reload !
|
||||||
|
p = save3;
|
||||||
|
// (Ox)-axis Symetry for the flames
|
||||||
|
p.y = abs(p.y);
|
||||||
|
// Fine-tuning Flames position
|
||||||
|
p+= vec2(-10.0,0.0);
|
||||||
|
// Fine-tuning Flames Shape
|
||||||
|
p *= vec2(0.75,1.0);
|
||||||
|
|
||||||
|
// Green Flames
|
||||||
|
col += 0.8*vec4(0.0,1.0,0.5,1.0)*s(20.0,0.0,length(p)-25.0+7.0*sin(0.30*length(p)*atan(p.y,p.x) + 55.0*iTime));
|
||||||
|
// White flames
|
||||||
|
col += 0.8*vec4(1.0,1.0,1.0,1.0)*s(20.0,0.0,length(p)-20.0+7.0*sin(0.30*length(p)*atan(p.y,p.x) + 55.0*iTime));
|
||||||
|
|
||||||
|
p = save3;
|
||||||
|
|
||||||
|
// Fat Aura
|
||||||
|
col = mix(col,vec4(1.0),0.5*s(10.0,0.0,length(p + vec2(5.0,0.0))-20.0)*abs(sin(50.0*iTime)));
|
||||||
|
// Less-Fat Aura
|
||||||
|
col = mix(col,vec4(1.0),0.5*s(20.0,0.0,length(p + vec2(5.0,0.0))-20.0));
|
||||||
|
// Frieren : "Aura ? Shader yourself !"
|
||||||
|
|
||||||
|
// The Pod
|
||||||
|
|
||||||
|
// White Disk
|
||||||
|
col = mix(col,vec4(1.0),s(0.01,0.0,length(p)-20.0));
|
||||||
|
|
||||||
|
if( length(p) - 20.0 < 0.0 ) // Basic Masking
|
||||||
|
{
|
||||||
|
// 2D Shading : bluish large shadow
|
||||||
|
col = mix(col,vec4(0.65,0.68,0.68 + 0.1*(3.0-i),1.0),s(0.5,0.0,length(p - vec2(2.0,0.0))-17.0));
|
||||||
|
// 2D Shading : dark small shadow
|
||||||
|
// If Outside Porthole Zone
|
||||||
|
if(s(0.0,1.0,length(vec2(3.0,2.0)*p + vec2(33.5,0.0))-23.0)>0.0)
|
||||||
|
col = mix(col,vec4(0.45,0.55,0.55 + 0.1*(3.0-i),1.0),0.75*s(0.5,0.0,length(p - vec2(2.0,0.0)+ 0.5*fbm(vec2(4.5*atan(p.y,p.x))))-9.0));
|
||||||
|
|
||||||
|
// Small 2D Indentation Details On The Spheres Using A Procedural Texture
|
||||||
|
// NOTE: Original used texture(iChannel0, ...) which is not supported
|
||||||
|
// Texture detail removed - not essential for the effect
|
||||||
|
// vec4 colorCapsule = vec4(hash12(0.0003*p*dot(p,p) + 0.789*i));
|
||||||
|
// if(colorCapsule.x>0.75)if(s(0.0,1.0,length(vec2(3.0,2.0)*p + vec2(33.5,0.0))-23.0)>0.0)col *= vec4(0.25,0.25,0.25,1.0);
|
||||||
|
|
||||||
|
// Bigger Dark Line All Around The Pod
|
||||||
|
col = mix(col,vec4(0.0),s(0.2,0.0,abs(length(p)-19.9)-0.20));
|
||||||
|
// Draw The Porthole :
|
||||||
|
col = mix(col,vec4(0.5,0.2,0.3,1.0) // Base Color
|
||||||
|
-s(5.0,0.0,length(p + vec2(-6.0,15.0))-20.0) // Main Shadow
|
||||||
|
-s(0.25,0.0,abs(length(p + vec2(0.0,3.0))-15.0)-0.4)// Vertical Shadow
|
||||||
|
-s(0.0,1.5,p.y-8.5) // top Shadow
|
||||||
|
+0.25*vec4(1.0,0.5,0.0,1.0)*s(10.0,0.0,abs(p.y)) // Fake Glass Gradient
|
||||||
|
,
|
||||||
|
s(0.5,0.0,length(vec2(3.0,2.0)*p + vec2(35.0,0.0))-19.9));
|
||||||
|
|
||||||
|
// Porthole Black Rings
|
||||||
|
// Internal
|
||||||
|
col = mix(col,vec4(0.0,0.0,0.0,1.0),s(1.0,0.0,abs(length(vec2(3.0,2.0)*p + vec2(35.0,0.0))-19.9)-0.1));
|
||||||
|
// External
|
||||||
|
col = mix(col,vec4(0.0,0.0,0.0,1.0),s(1.0,0.0,abs(length(vec2(3.0,2.0)*p + vec2(33.5,0.0))-23.0)-0.1));
|
||||||
|
|
||||||
|
// Pod Tennis-Ball Door Line...
|
||||||
|
if(p.y>0.0)col = mix(col,vec4(0.0,0.0,0.0,1.0),s(1.0,0.0,abs(length(vec2(3.0,2.0)*p + vec2( 29.0,0.0))-30.0)-0.1));
|
||||||
|
if(p.y<0.0)col = mix(col,vec4(0.0,0.0,0.0,1.0),s(1.0,0.0,abs(length(vec2(3.0,2.0)*p + vec2(-31.0,0.0))-30.0)-0.1));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// WAKE UP SHEEPLE !
|
||||||
|
fragColor = clamp(col,0.0,1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
127
data/shaders/dbz/dbz.vk.glsl
Normal file
127
data/shaders/dbz/dbz.vk.glsl
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: New Leaked 3I/Atlas NASA Footage
|
||||||
|
// Author: msm01
|
||||||
|
// URL: https://www.shadertoy.com/view/3ftcRr
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define s(a,b,c) smoothstep(a,b,c)
|
||||||
|
#define PI 3.14159
|
||||||
|
#define NBCaps 3.
|
||||||
|
|
||||||
|
mat2 r2d(float a) { float c = cos(a), s = sin(a); return mat2(c, s, -s, c); }
|
||||||
|
float metaDiamond(vec2 p, vec2 pixel, float r) { vec2 d = abs(p - pixel); return r / (d.x + d.y); }
|
||||||
|
|
||||||
|
float hash12(vec2 p) {
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * .1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
float fbm(in vec2 v_p) {
|
||||||
|
float pvpx = v_p.x;
|
||||||
|
vec2 V1 = vec2(floor(pvpx));
|
||||||
|
vec2 V2 = vec2(floor(pvpx + 1.0));
|
||||||
|
return mix(hash12(V1), hash12(V2), smoothstep(0.0, 1.0, fract(pvpx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 p = vec2((1.0 / iResolution.y) * (fragCoord.x - iResolution.x / 2.0),
|
||||||
|
fragCoord.y / iResolution.y - 0.5);
|
||||||
|
|
||||||
|
p.x = -p.x;
|
||||||
|
p *= 150.0;
|
||||||
|
|
||||||
|
vec4 col = vec4(0.05, 0.05, 0.15, 1.0);
|
||||||
|
|
||||||
|
vec2 save1 = p;
|
||||||
|
vec2 save2 = p;
|
||||||
|
|
||||||
|
p *= r2d(-0.05);
|
||||||
|
col = mix(col, vec4(0.2, 0.3, 0.5, 1.0),
|
||||||
|
smoothstep(75.0, 0.0, abs(p.y - 5.0 * fbm(vec2(0.01 * (p.x - 33.333 * iTime))) + 3.5)));
|
||||||
|
p *= r2d(0.05);
|
||||||
|
|
||||||
|
p *= r2d(-0.05);
|
||||||
|
p *= 0.35;
|
||||||
|
p += vec2(-5.0 * iTime, 0.0);
|
||||||
|
|
||||||
|
vec2 b = fract(5.0 * p);
|
||||||
|
p = floor(5.0 * p);
|
||||||
|
if (fbm(vec2(p.x * p.y)) > 0.996) col += clamp(1.0 - pow(3.0 * length(b + vec2(-0.5)), 0.5), 0.0, 1.0);
|
||||||
|
|
||||||
|
p = save1;
|
||||||
|
vec2 save3;
|
||||||
|
|
||||||
|
float Nb_Capsules = clamp(NBCaps, 0.0, 4.0);
|
||||||
|
for (float i = 0.0; i < Nb_Capsules; i++) {
|
||||||
|
p = save1;
|
||||||
|
p *= r2d(-0.05);
|
||||||
|
p *= 2.5;
|
||||||
|
p *= 1.0 - 0.25 * i;
|
||||||
|
p += vec2(150.0 * fbm(vec2(0.15 * iTime + i * 54.321)) - 75.0,
|
||||||
|
50.0 * sin(0.25 * iTime + i * 54.321) - 25.0);
|
||||||
|
save3 = p;
|
||||||
|
|
||||||
|
p *= 0.04;
|
||||||
|
p.y = abs(p.y);
|
||||||
|
|
||||||
|
if (p.x > 0.0) {
|
||||||
|
col += vec4(0.0, 1.0, 0.5, 1.0) * smoothstep(0.2, 0.0, abs(p.y - 0.05 * fbm(vec2(1.5 * p.x - 40.0 * iTime))) - 0.05) * smoothstep(29.0, 0.0, abs(p.x));
|
||||||
|
col += vec4(1.0, 1.0, 1.0, 1.0) * smoothstep(0.1, 0.0, abs(p.y - 0.05 * fbm(vec2(1.5 * p.x - 40.0 * iTime))) - 0.05) * smoothstep(29.0, 0.0, abs(p.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
p = save3;
|
||||||
|
p.y = abs(p.y);
|
||||||
|
p += vec2(-10.0, 0.0);
|
||||||
|
p *= vec2(0.75, 1.0);
|
||||||
|
|
||||||
|
col += 0.8 * vec4(0.0, 1.0, 0.5, 1.0) * s(20.0, 0.0, length(p) - 25.0 + 7.0 * sin(0.30 * length(p) * atan(p.y, p.x) + 55.0 * iTime));
|
||||||
|
col += 0.8 * vec4(1.0, 1.0, 1.0, 1.0) * s(20.0, 0.0, length(p) - 20.0 + 7.0 * sin(0.30 * length(p) * atan(p.y, p.x) + 55.0 * iTime));
|
||||||
|
|
||||||
|
p = save3;
|
||||||
|
|
||||||
|
col = mix(col, vec4(1.0), 0.5 * s(10.0, 0.0, length(p + vec2(5.0, 0.0)) - 20.0) * abs(sin(50.0 * iTime)));
|
||||||
|
col = mix(col, vec4(1.0), 0.5 * s(20.0, 0.0, length(p + vec2(5.0, 0.0)) - 20.0));
|
||||||
|
|
||||||
|
col = mix(col, vec4(1.0), s(0.01, 0.0, length(p) - 20.0));
|
||||||
|
|
||||||
|
if (length(p) - 20.0 < 0.0) {
|
||||||
|
col = mix(col, vec4(0.65, 0.68, 0.68 + 0.1 * (3.0 - i), 1.0), s(0.5, 0.0, length(p - vec2(2.0, 0.0)) - 17.0));
|
||||||
|
if (s(0.0, 1.0, length(vec2(3.0, 2.0) * p + vec2(33.5, 0.0)) - 23.0) > 0.0)
|
||||||
|
col = mix(col, vec4(0.45, 0.55, 0.55 + 0.1 * (3.0 - i), 1.0),
|
||||||
|
0.75 * s(0.5, 0.0, length(p - vec2(2.0, 0.0) + 0.5 * fbm(vec2(4.5 * atan(p.y, p.x)))) - 9.0));
|
||||||
|
|
||||||
|
col = mix(col, vec4(0.0), s(0.2, 0.0, abs(length(p) - 19.9) - 0.20));
|
||||||
|
col = mix(col, vec4(0.5, 0.2, 0.3, 1.0)
|
||||||
|
- s(5.0, 0.0, length(p + vec2(-6.0, 15.0)) - 20.0)
|
||||||
|
- s(0.25, 0.0, abs(length(p + vec2(0.0, 3.0)) - 15.0) - 0.4)
|
||||||
|
- s(0.0, 1.5, p.y - 8.5)
|
||||||
|
+ 0.25 * vec4(1.0, 0.5, 0.0, 1.0) * s(10.0, 0.0, abs(p.y))
|
||||||
|
,
|
||||||
|
s(0.5, 0.0, length(vec2(3.0, 2.0) * p + vec2(35.0, 0.0)) - 19.9));
|
||||||
|
|
||||||
|
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), s(1.0, 0.0, abs(length(vec2(3.0, 2.0) * p + vec2(35.0, 0.0)) - 19.9) - 0.1));
|
||||||
|
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), s(1.0, 0.0, abs(length(vec2(3.0, 2.0) * p + vec2(33.5, 0.0)) - 23.0) - 0.1));
|
||||||
|
|
||||||
|
if (p.y > 0.0) col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), s(1.0, 0.0, abs(length(vec2(3.0, 2.0) * p + vec2(29.0, 0.0)) - 30.0) - 0.1));
|
||||||
|
if (p.y < 0.0) col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), s(1.0, 0.0, abs(length(vec2(3.0, 2.0) * p + vec2(-31.0, 0.0)) - 30.0) - 0.1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragColor = clamp(col, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/dbz/meta.txt
Normal file
2
data/shaders/dbz/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: New Leaked 3I/Atlas NASA Footage
|
||||||
|
Author: msm01
|
||||||
67
data/shaders/fractal_pyramid/fractal_pyramid.frag.msl
Normal file
67
data/shaders/fractal_pyramid/fractal_pyramid.frag.msl
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Fractal Pyramid — bradjamesgrant
|
||||||
|
// MSL port of fractal_pyramid.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float3 palette(float d) {
|
||||||
|
return mix(float3(0.2, 0.7, 0.9), float3(1.0, 0.0, 1.0), d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float2 rotate(float2 p, float a) {
|
||||||
|
float c = cos(a);
|
||||||
|
float s = sin(a);
|
||||||
|
return p * float2x2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float mapScene(float3 p, float iTime) {
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
float t = iTime * 0.2;
|
||||||
|
p.xz = rotate(p.xz, t);
|
||||||
|
p.xy = rotate(p.xy, t * 1.89);
|
||||||
|
p.xz = abs(p.xz);
|
||||||
|
p.xz -= 0.5;
|
||||||
|
}
|
||||||
|
return dot(sign(p), p) / 5.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float4 rm(float3 ro, float3 rd, float iTime) {
|
||||||
|
float t = 0.0;
|
||||||
|
float3 col = float3(0.0);
|
||||||
|
float d = 1.0;
|
||||||
|
for (int i = 0; i < 64; ++i) {
|
||||||
|
float3 p = ro + rd * t;
|
||||||
|
d = mapScene(p, iTime) * 0.5;
|
||||||
|
if (d < 0.02) break;
|
||||||
|
if (d > 100.0) break;
|
||||||
|
col += palette(length(p) * 0.1) / (400.0 * d);
|
||||||
|
t += d;
|
||||||
|
}
|
||||||
|
return float4(col, 1.0 / (d * 100.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 fractal_pyramid_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 uv = (fragCoord - (U.iResolution * 0.5)) / U.iResolution.x;
|
||||||
|
float3 ro = float3(0.0, 0.0, -50.0);
|
||||||
|
ro.xz = rotate(ro.xz, U.iTime);
|
||||||
|
float3 cf = normalize(-ro);
|
||||||
|
float3 cs = normalize(cross(cf, float3(0.0, 1.0, 0.0)));
|
||||||
|
float3 cu = normalize(cross(cf, cs));
|
||||||
|
|
||||||
|
float3 uuv = ro + cf * 3.0 + uv.x * cs + uv.y * cu;
|
||||||
|
float3 rd = normalize(uuv - ro);
|
||||||
|
|
||||||
|
return rm(ro, rd, U.iTime);
|
||||||
|
}
|
||||||
BIN
data/shaders/fractal_pyramid/fractal_pyramid.frag.spv
Normal file
BIN
data/shaders/fractal_pyramid/fractal_pyramid.frag.spv
Normal file
Binary file not shown.
@@ -1,3 +1,6 @@
|
|||||||
|
// Name: Fractal Pyramid
|
||||||
|
// Author: bradjamesgrant
|
||||||
|
// URL: https://www.shadertoy.com/view/tsXBzS
|
||||||
#version 330 core
|
#version 330 core
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
71
data/shaders/fractal_pyramid/fractal_pyramid.vk.glsl
Normal file
71
data/shaders/fractal_pyramid/fractal_pyramid.vk.glsl
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Fractal Pyramid
|
||||||
|
// Author: bradjamesgrant
|
||||||
|
// URL: https://www.shadertoy.com/view/tsXBzS
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec3 palette(float d) {
|
||||||
|
return mix(vec3(0.2, 0.7, 0.9), vec3(1.0, 0.0, 1.0), d);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 rotate(vec2 p, float a) {
|
||||||
|
float c = cos(a);
|
||||||
|
float s = sin(a);
|
||||||
|
return p * mat2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
float mapScene(vec3 p) {
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
float t = iTime * 0.2;
|
||||||
|
p.xz = rotate(p.xz, t);
|
||||||
|
p.xy = rotate(p.xy, t * 1.89);
|
||||||
|
p.xz = abs(p.xz);
|
||||||
|
p.xz -= 0.5;
|
||||||
|
}
|
||||||
|
return dot(sign(p), p) / 5.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 rm(vec3 ro, vec3 rd) {
|
||||||
|
float t = 0.0;
|
||||||
|
vec3 col = vec3(0.0);
|
||||||
|
float d = 1.0;
|
||||||
|
for (int i = 0; i < 64; ++i) {
|
||||||
|
vec3 p = ro + rd * t;
|
||||||
|
d = mapScene(p) * 0.5;
|
||||||
|
if (d < 0.02) break;
|
||||||
|
if (d > 100.0) break;
|
||||||
|
col += palette(length(p) * 0.1) / (400.0 * d);
|
||||||
|
t += d;
|
||||||
|
}
|
||||||
|
return vec4(col, 1.0 / (d * 100.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 uv = (fragCoord - (iResolution.xy * 0.5)) / iResolution.x;
|
||||||
|
vec3 ro = vec3(0.0, 0.0, -50.0);
|
||||||
|
ro.xz = rotate(ro.xz, iTime);
|
||||||
|
vec3 cf = normalize(-ro);
|
||||||
|
vec3 cs = normalize(cross(cf, vec3(0.0, 1.0, 0.0)));
|
||||||
|
vec3 cu = normalize(cross(cf, cs));
|
||||||
|
|
||||||
|
vec3 uuv = ro + cf * 3.0 + uv.x * cs + uv.y * cu;
|
||||||
|
vec3 rd = normalize(uuv - ro);
|
||||||
|
|
||||||
|
vec4 col = rm(ro, rd);
|
||||||
|
fragColor = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/fractal_pyramid/meta.txt
Normal file
2
data/shaders/fractal_pyramid/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Fractal Pyramid
|
||||||
|
Author: bradjamesgrant
|
||||||
89
data/shaders/just_another_cube/just_another_cube.frag.msl
Normal file
89
data/shaders/just_another_cube/just_another_cube.frag.msl
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Just Another Cube — mrange
|
||||||
|
// MSL port of just_another_cube.vk.glsl. The Shadertoy original uses
|
||||||
|
// mutable file-scope globals; in MSL we pass them by reference.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
constant float M = 1e-3;
|
||||||
|
|
||||||
|
static float D(float3 p,
|
||||||
|
thread float2x2& R,
|
||||||
|
thread float& d,
|
||||||
|
thread float& G) {
|
||||||
|
p.xy = p.xy * R;
|
||||||
|
p.xz = p.xz * R;
|
||||||
|
|
||||||
|
float3 S = sin(123.0 * p);
|
||||||
|
|
||||||
|
float shell = abs(length(p) - 0.6);
|
||||||
|
p *= p * p * p;
|
||||||
|
d = pow(dot(p, p), 0.125) - 0.5
|
||||||
|
- pow(1.0 + S.x * S.y * S.z, 8.0) / 1e5;
|
||||||
|
|
||||||
|
G = min(G, max(shell, d));
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 just_another_cube_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 C = in.uv * U.iResolution;
|
||||||
|
|
||||||
|
float2x2 R;
|
||||||
|
float d = 1.0, z = 0.0, G = 9.0;
|
||||||
|
|
||||||
|
float3 r = float3(U.iResolution, U.iResolution.y);
|
||||||
|
float3 I = normalize(float3(C - 0.5 * r.xy, r.y));
|
||||||
|
float3 B = float3(1, 2, 9) * M;
|
||||||
|
float3 p = float3(0.0);
|
||||||
|
float3 O = float3(0.0);
|
||||||
|
|
||||||
|
{
|
||||||
|
float4 cs = cos(0.3 * U.iTime + float4(0, 11, 33, 0));
|
||||||
|
R = float2x2(cs.x, cs.y, cs.z, cs.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; z < 9.0 && d > M; z += D(p, R, d, G)) {
|
||||||
|
p = z * I;
|
||||||
|
p.z -= 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z < 9.0) {
|
||||||
|
for (int i = 0; i < 3; ) {
|
||||||
|
r = float3(0.0);
|
||||||
|
r[i] = M;
|
||||||
|
O[i++] = D(p + r, R, d, G) - D(p - r, R, d, G);
|
||||||
|
}
|
||||||
|
|
||||||
|
O = normalize(O);
|
||||||
|
z = 1.0 + dot(O, I);
|
||||||
|
|
||||||
|
r = reflect(I, O);
|
||||||
|
|
||||||
|
C = (p + r * (5.0 - p.y) / abs(r.y)).xz;
|
||||||
|
|
||||||
|
float3 colorTerm;
|
||||||
|
if (r.y > 0.0) {
|
||||||
|
d = sqrt(length(C * C)) + 1.0;
|
||||||
|
colorTerm = 5e2 * smoothstep(5.0, 4.0, d) * d * B;
|
||||||
|
} else {
|
||||||
|
colorTerm = exp(-2.0 * length(C)) * (B / M - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
O = z * z * colorTerm + pow(1.0 + O.y, 5.0) * B;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 result = sqrt(float4(O + B / G, O.x + B.x / G));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
BIN
data/shaders/just_another_cube/just_another_cube.frag.spv
Normal file
BIN
data/shaders/just_another_cube/just_another_cube.frag.spv
Normal file
Binary file not shown.
159
data/shaders/just_another_cube/just_another_cube.gl.glsl
Normal file
159
data/shaders/just_another_cube/just_another_cube.gl.glsl
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
// Name: Just Another Cube
|
||||||
|
// Author: mrange
|
||||||
|
// URL: https://www.shadertoy.com/view/3XdXRr
|
||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
// CC0: Just another cube
|
||||||
|
// Glowtracers are great for compact coding, but I wanted to see how much
|
||||||
|
// I could squeeze a more normal raymarcher in terms of characters used.
|
||||||
|
|
||||||
|
// Twigl: https://twigl.app?ol=true&ss=-OW-y9xgRgWubwKcn0Nd
|
||||||
|
|
||||||
|
// == Globals ==
|
||||||
|
// Single-letter variable names are used to save characters (code golfing).
|
||||||
|
mat2 R; // A 2D rotation matrix, calculated once per frame in mainImage and used by D.
|
||||||
|
float d=1. // Stores the most recent distance to the scene from the ray's position.
|
||||||
|
, z=0. // Stores the total distance traveled along the ray (initialized to avoid undefined behavior)
|
||||||
|
, G=9. // "Glow" variable. Tracks the closest the ray comes to the object (for volumetric glow effect).
|
||||||
|
, M=1e-3
|
||||||
|
;
|
||||||
|
// == Distance Function (SDF - Signed Distance Field) ==
|
||||||
|
// This function calculates the shortest distance from a given point 'p' to the scene geometry.
|
||||||
|
// A positive result means the point is outside an object, negative is inside, and zero is on the surface.
|
||||||
|
// This is the core of "raymarching", as it tells us the largest safe step we can take along a ray.
|
||||||
|
float D(vec3 p) {
|
||||||
|
// Apply two rotations to the point's coordinates. This twists the space the object
|
||||||
|
// exists in, making the simple cube shape appear more complex and animated.
|
||||||
|
p.xy *= R;
|
||||||
|
p.xz *= R;
|
||||||
|
|
||||||
|
// Create a higher-frequency version of the coordinate for detailed surface patterns.
|
||||||
|
vec3 S = sin(123.*p);
|
||||||
|
|
||||||
|
// This creates a volumetric glow effect by tracking the minimum distance
|
||||||
|
// to either the existing glow value or a glowing shell around the object.
|
||||||
|
G = min(
|
||||||
|
G
|
||||||
|
// The glowing shell
|
||||||
|
, max(
|
||||||
|
abs(length(p)-.6)
|
||||||
|
// The main object distance calculation:
|
||||||
|
// 1. A superquadric (rounded cube shape) is created using an L8-norm.
|
||||||
|
// The expression `pow(dot(p=p*p*p*p,p),.125)` is a golfed version of
|
||||||
|
// `pow(pow(p.x,8)+pow(p.y,8)+pow(p.z,8), 1./8.)`.
|
||||||
|
// The `- .5` defines the object's size.
|
||||||
|
, d = pow(dot(p*=p*p*p,p),.125) - .5
|
||||||
|
// 2. Surface detail subtraction. This creates small surface variations
|
||||||
|
// using high-frequency sine waves for more appealing reflections.
|
||||||
|
- pow(1.+S.x*S.y*S.z,8.)/1e5
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// == Main Render Function ==
|
||||||
|
// This function is called for every pixel on the screen to determine its color.
|
||||||
|
// 'o' is the final output color (rgba). 'C' is the input pixel coordinate (xy).
|
||||||
|
void mainImage(out vec4 o, vec2 C) {
|
||||||
|
// Single-letter variable names are used to save characters (code golfing).
|
||||||
|
vec3 p // The current point in 3D space along the ray.
|
||||||
|
, O // Multi-purpose vector: color accumulator, then normal vector, then final color.
|
||||||
|
, r=vec3(iResolution.xy, iResolution.y) // 'r' holds screen resolution, later re-used for the epsilon vector and reflection.
|
||||||
|
// 'I' is the Ray Direction vector. It's calculated once per pixel.
|
||||||
|
// This converts the 2D screen coordinate 'C' into a 3D direction, creating the camera perspective.
|
||||||
|
, I=normalize(vec3(C-.5*r.xy, r.y))
|
||||||
|
// Base glow color (dark bluish tint).
|
||||||
|
, B=vec3(1,2,9)*M
|
||||||
|
;
|
||||||
|
|
||||||
|
// == Raymarching Loop ==
|
||||||
|
// This loop "marches" a ray from the camera out into the scene to find what it hits.
|
||||||
|
// It uses a golfed structure where the body of the loop updates the ray position 'p',
|
||||||
|
// and the "advancement" step moves the ray forward.
|
||||||
|
for(
|
||||||
|
// -- Initializer (runs once before the loop) --
|
||||||
|
// Calculate the rotation matrix for this frame based on time.
|
||||||
|
R = mat2(cos(.3*iTime+vec4(0,11,33,0)))
|
||||||
|
// -- Condition --
|
||||||
|
// Loop while total distance 'z' is less than 9 and we are not yet touching a surface (d > 1e-3).
|
||||||
|
; z<9. && d > M
|
||||||
|
// -- Advancement --
|
||||||
|
// The ray advances by the safe distance 'd' returned by D(p).
|
||||||
|
// The result of D(p) is also assigned to the global 'd' inside the function.
|
||||||
|
; z += D(p)
|
||||||
|
)
|
||||||
|
// -- Loop Body --
|
||||||
|
// Calculate the current position 'p' in world space.
|
||||||
|
// The camera starts at (0,0,-2) and points forward.
|
||||||
|
p = z*I
|
||||||
|
, p.z -= 2.
|
||||||
|
;
|
||||||
|
|
||||||
|
// -- Hit Condition --
|
||||||
|
// If the loop finished because z exceeded the max distance, we hit nothing. Otherwise, we hit the surface.
|
||||||
|
if (z < 9.) {
|
||||||
|
// -- Calculate Surface Normal --
|
||||||
|
// Estimate the gradient ∇D at the hit point 'p' via central differences on the SDF D.
|
||||||
|
// We use ε = 1e-3 and loop over each axis (x, y, z):
|
||||||
|
// • Zero r, then set r[i] = ε.
|
||||||
|
// • Compute O[i] = D(p + r) – D(p – r).
|
||||||
|
// After the loop, O holds the unnormalized normal vector.
|
||||||
|
for (
|
||||||
|
int i=0 // axis index: 0→x, 1→y, 2→z (initialized to avoid warnings)
|
||||||
|
; i < 3
|
||||||
|
; O[i++] = D(p+r) - D(p-r)
|
||||||
|
)
|
||||||
|
r -= r // clear r to vec3(0)
|
||||||
|
, r[i] = M // set only the i-th component
|
||||||
|
;
|
||||||
|
|
||||||
|
// -- Lighting and Shading --
|
||||||
|
// 'z' is re-purposed to store a fresnel factor (1 - cos(angle)) for edge brightness.
|
||||||
|
// `dot(O, I)` calculates how much the surface faces away from the camera.
|
||||||
|
// O is also normalized here to become a proper normal vector.
|
||||||
|
z = 1.+dot(O = normalize(O),I);
|
||||||
|
|
||||||
|
// 'r' is re-purposed to store the reflection vector.
|
||||||
|
r = reflect(I,O);
|
||||||
|
|
||||||
|
// Calculate a point 'C' along the reflection vector 'r' to sample a background color.
|
||||||
|
// For upward reflections (r.y > 0), this finds the intersection with the plane y=5.
|
||||||
|
C = (p+r*(5.-p.y)/abs(r.y)).xz;
|
||||||
|
|
||||||
|
// Calculate the final color 'O' of the hit point.
|
||||||
|
O =
|
||||||
|
// Multiply by the fresnel factor squared for stronger edge reflections.
|
||||||
|
z*z *
|
||||||
|
// Use a ternary operator to decide the color based on where the reflection ray goes.
|
||||||
|
(
|
||||||
|
// If the reflection vector points upward...
|
||||||
|
r.y>0.
|
||||||
|
// ...sample a procedural "sky" with a radial gradient and blue tint.
|
||||||
|
? 5e2*smoothstep(5., 4., d = sqrt(length(C*C))+1.)*d*B
|
||||||
|
// ...otherwise, sample a "floor" with a deep blue exponential falloff.
|
||||||
|
: exp(-2.*length(C))*(B/M-1.)
|
||||||
|
)
|
||||||
|
// Add rim lighting (brighter on upward-facing surfaces).
|
||||||
|
+ pow(1.+O.y,5.)*B
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
// == Tonemapping & Output ==
|
||||||
|
// Apply final effects and map the High Dynamic Range (HDR) color to a displayable range.
|
||||||
|
// Add glow contribution: smaller G values (closer ray passes) create a brighter blue glow.
|
||||||
|
o = sqrt(O+B/G).xyzx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
88
data/shaders/just_another_cube/just_another_cube.vk.glsl
Normal file
88
data/shaders/just_another_cube/just_another_cube.vk.glsl
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Just Another Cube
|
||||||
|
// Author: mrange
|
||||||
|
// URL: https://www.shadertoy.com/view/3XdXRr
|
||||||
|
// CC0: Just another cube
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
mat2 R;
|
||||||
|
float d = 1.;
|
||||||
|
float z = 0.;
|
||||||
|
float G = 9.;
|
||||||
|
float M = 1e-3;
|
||||||
|
|
||||||
|
float D(vec3 p) {
|
||||||
|
p.xy *= R;
|
||||||
|
p.xz *= R;
|
||||||
|
|
||||||
|
vec3 S = sin(123. * p);
|
||||||
|
|
||||||
|
G = min(
|
||||||
|
G,
|
||||||
|
max(
|
||||||
|
abs(length(p) - .6),
|
||||||
|
d = pow(dot(p *= p * p * p, p), .125) - .5
|
||||||
|
- pow(1. + S.x * S.y * S.z, 8.) / 1e5
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 o, vec2 C) {
|
||||||
|
vec3 p,
|
||||||
|
O,
|
||||||
|
r = vec3(iResolution.xy, iResolution.y),
|
||||||
|
I = normalize(vec3(C - .5 * r.xy, r.y)),
|
||||||
|
B = vec3(1, 2, 9) * M;
|
||||||
|
|
||||||
|
for (
|
||||||
|
R = mat2(cos(.3 * iTime + vec4(0, 11, 33, 0)));
|
||||||
|
z < 9. && d > M;
|
||||||
|
z += D(p)
|
||||||
|
)
|
||||||
|
p = z * I,
|
||||||
|
p.z -= 2.;
|
||||||
|
|
||||||
|
O = vec3(0.0);
|
||||||
|
|
||||||
|
if (z < 9.) {
|
||||||
|
for (int i = 0; i < 3; ) {
|
||||||
|
r -= r;
|
||||||
|
r[i] = M;
|
||||||
|
O[i++] = D(p + r) - D(p - r);
|
||||||
|
}
|
||||||
|
|
||||||
|
z = 1. + dot(O = normalize(O), I);
|
||||||
|
|
||||||
|
r = reflect(I, O);
|
||||||
|
|
||||||
|
C = (p + r * (5. - p.y) / abs(r.y)).xz;
|
||||||
|
|
||||||
|
O =
|
||||||
|
z * z *
|
||||||
|
(
|
||||||
|
r.y > 0.
|
||||||
|
? 5e2 * smoothstep(5., 4., d = sqrt(length(C * C)) + 1.) * d * B
|
||||||
|
: exp(-2. * length(C)) * (B / M - 1.)
|
||||||
|
)
|
||||||
|
+ pow(1. + O.y, 5.) * B;
|
||||||
|
}
|
||||||
|
|
||||||
|
o = sqrt(O + B / G).xyzx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/just_another_cube/meta.txt
Normal file
2
data/shaders/just_another_cube/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Just Another Cube
|
||||||
|
Author: mrange
|
||||||
2
data/shaders/octograms/meta.txt
Normal file
2
data/shaders/octograms/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Octograms
|
||||||
|
Author: whisky_shusuky
|
||||||
95
data/shaders/octograms/octograms.frag.msl
Normal file
95
data/shaders/octograms/octograms.frag.msl
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Octograms — whisky_shusuky
|
||||||
|
// MSL port of octograms.vk.glsl. The Shadertoy original uses a mutable
|
||||||
|
// file-scope `gTime`; in MSL we pass it as a parameter through the chain.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float2x2 rot(float a) {
|
||||||
|
float c = cos(a), s = sin(a);
|
||||||
|
return float2x2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float sdBox(float3 p, float3 b) {
|
||||||
|
float3 q = abs(p) - b;
|
||||||
|
return length(max(q, float3(0.0))) + min(max(q.x, max(q.y, q.z)), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float boxGeom(float3 pos, float scale) {
|
||||||
|
pos *= scale;
|
||||||
|
float base = sdBox(pos, float3(0.4, 0.4, 0.1)) / 1.5;
|
||||||
|
pos.xy = (pos.xy * 5.0 - float2(0.0, 3.5)) * rot(0.75);
|
||||||
|
return -base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float box_set(float3 pos, float gTime) {
|
||||||
|
float3 pos_origin = pos;
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box1 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box2 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box3 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box4 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box5 = boxGeom(pos, 0.5) * 6.0;
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
float box6 = boxGeom(pos, 0.5) * 6.0;
|
||||||
|
|
||||||
|
return max(max(max(max(max(box1, box2), box3), box4), box5), box6);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 octograms_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 p = (fragCoord * 2.0 - U.iResolution) / min(U.iResolution.x, U.iResolution.y);
|
||||||
|
|
||||||
|
float3 ro = float3(0.0, -0.2, U.iTime * 4.0);
|
||||||
|
float3 ray = normalize(float3(p, 1.5));
|
||||||
|
ray.xy = ray.xy * rot(sin(U.iTime * 0.03) * 5.0);
|
||||||
|
ray.yz = ray.yz * rot(sin(U.iTime * 0.05) * 0.2);
|
||||||
|
float t = 0.1;
|
||||||
|
float ac = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 99; i++) {
|
||||||
|
float3 pos = ro + ray * t;
|
||||||
|
pos = fract((pos - 2.0) / 4.0) * 4.0 - 2.0;
|
||||||
|
float gTime = U.iTime - float(i) * 0.01;
|
||||||
|
|
||||||
|
float d = box_set(pos, gTime);
|
||||||
|
d = max(abs(d), 0.01);
|
||||||
|
ac += exp(-d * 23.0);
|
||||||
|
t += d * 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 col = float3(ac * 0.02);
|
||||||
|
col += float3(0.0, 0.2 * abs(sin(U.iTime)), 0.5 + sin(U.iTime) * 0.2);
|
||||||
|
|
||||||
|
return float4(col, 1.0 - t * (0.02 + 0.02 * sin(U.iTime)));
|
||||||
|
}
|
||||||
BIN
data/shaders/octograms/octograms.frag.spv
Normal file
BIN
data/shaders/octograms/octograms.frag.spv
Normal file
Binary file not shown.
@@ -1,3 +1,6 @@
|
|||||||
|
// Name: Octograms
|
||||||
|
// Author: whisky_shusuky
|
||||||
|
// URL: https://www.shadertoy.com/view/tlVGDt
|
||||||
#version 330 core
|
#version 330 core
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
109
data/shaders/octograms/octograms.vk.glsl
Normal file
109
data/shaders/octograms/octograms.vk.glsl
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Octograms
|
||||||
|
// Author: whisky_shusuky
|
||||||
|
// URL: https://www.shadertoy.com/view/tlVGDt
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
float gTime = 0.0;
|
||||||
|
const float REPEAT = 5.0;
|
||||||
|
|
||||||
|
mat2 rot(float a) {
|
||||||
|
float c = cos(a), s = sin(a);
|
||||||
|
return mat2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
float sdBox(vec3 p, vec3 b) {
|
||||||
|
vec3 q = abs(p) - b;
|
||||||
|
return length(max(q, vec3(0.0))) + min(max(q.x, max(q.y, q.z)), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float boxGeom(vec3 pos, float scale) {
|
||||||
|
pos *= scale;
|
||||||
|
float base = sdBox(pos, vec3(.4, .4, .1)) / 1.5;
|
||||||
|
pos.xy *= 5.0;
|
||||||
|
pos.y -= 3.5;
|
||||||
|
pos.xy *= rot(.75);
|
||||||
|
float result = -base;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float box_set(vec3 pos, float iTimeLocal) {
|
||||||
|
vec3 pos_origin = pos;
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box1 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box2 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box3 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box4 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box5 = boxGeom(pos, .5) * 6.0;
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
float box6 = boxGeom(pos, .5) * 6.0;
|
||||||
|
|
||||||
|
float result = max(max(max(max(max(box1, box2), box3), box4), box5), box6);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float mapScene(vec3 pos, float iTimeLocal) {
|
||||||
|
return box_set(pos, iTimeLocal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 p = (fragCoord.xy * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
|
||||||
|
vec3 ro = vec3(0.0, -0.2, iTime * 4.0);
|
||||||
|
vec3 ray = normalize(vec3(p, 1.5));
|
||||||
|
ray.xy = ray.xy * rot(sin(iTime * .03) * 5.0);
|
||||||
|
ray.yz = ray.yz * rot(sin(iTime * .05) * .2);
|
||||||
|
float t = 0.1;
|
||||||
|
vec3 col = vec3(0.0);
|
||||||
|
float ac = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 99; i++) {
|
||||||
|
vec3 pos = ro + ray * t;
|
||||||
|
pos = mod(pos - 2.0, 4.0) - 2.0;
|
||||||
|
gTime = iTime - float(i) * 0.01;
|
||||||
|
|
||||||
|
float d = mapScene(pos, iTime);
|
||||||
|
|
||||||
|
d = max(abs(d), 0.01);
|
||||||
|
ac += exp(-d * 23.0);
|
||||||
|
|
||||||
|
t += d * 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
col = vec3(ac * 0.02);
|
||||||
|
col += vec3(0.0, 0.2 * abs(sin(iTime)), 0.5 + sin(iTime) * 0.2);
|
||||||
|
|
||||||
|
fragColor = vec4(col, 1.0 - t * (0.02 + 0.02 * sin(iTime)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/remember/meta.txt
Normal file
2
data/shaders/remember/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Remember
|
||||||
|
Author: diatribes
|
||||||
64
data/shaders/remember/remember.frag.msl
Normal file
64
data/shaders/remember/remember.frag.msl
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Remember — diatribes
|
||||||
|
// MSL port of remember.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float hash12(float2 p) {
|
||||||
|
float3 p3 = fract(float3(p.xyx) * 0.1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 remember_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 u = fragCoord;
|
||||||
|
|
||||||
|
float3 q, p = float3(U.iResolution, U.iResolution.x / U.iResolution.y);
|
||||||
|
|
||||||
|
float i = 0.0, s = 0.0;
|
||||||
|
float d = 0.125 * hash12(u);
|
||||||
|
float t = U.iTime * 0.1;
|
||||||
|
|
||||||
|
u = (u + u - p.xy) / p.y;
|
||||||
|
if (abs(u.y) > 0.8) { return float4(0); }
|
||||||
|
|
||||||
|
float4 o = float4(0.0);
|
||||||
|
|
||||||
|
for (; i < 64.0; i++) {
|
||||||
|
|
||||||
|
q = p = float3(u * d, d + t * 5.0);
|
||||||
|
// mat2(cos(.1*p.z+.1*t+vec4(0,33,11,0))) — column-major: (m00,m10,m01,m11)
|
||||||
|
float4 cs = cos(0.1 * p.z + 0.1 * t + float4(0, 33, 11, 0));
|
||||||
|
float2x2 m = float2x2(cs.x, cs.y, cs.z, cs.w);
|
||||||
|
p.xy = p.xy * m;
|
||||||
|
|
||||||
|
q.xz = cos(q.xz);
|
||||||
|
p.z = cos(p.z);
|
||||||
|
|
||||||
|
for (s = 1.0; s++ < 6.0;) {
|
||||||
|
q += sin(0.6 * t + p.zxy * 0.6);
|
||||||
|
p += sin(t + t + p.yzx * s) * 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = 0.02 + abs(min(length(p + 3.0 * sin(p.z * 0.5)) - 4.0, length(q - 2.0 * sin(p.z * 0.4)) - 6.0)) * 0.2;
|
||||||
|
d += s;
|
||||||
|
|
||||||
|
float4 brightTerm = min(0.01 * float4(6, 2, 1, 0) / max(length(u * sin(t + t + t)), 0.001), float4(50.0));
|
||||||
|
o += brightTerm + 1.0 / s * length(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
o = tanh(max(o / 6e2 + dot(u, u) * 0.35, 0.0));
|
||||||
|
return o;
|
||||||
|
}
|
||||||
BIN
data/shaders/remember/remember.frag.spv
Normal file
BIN
data/shaders/remember/remember.frag.spv
Normal file
Binary file not shown.
73
data/shaders/remember/remember.gl.glsl
Normal file
73
data/shaders/remember/remember.gl.glsl
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// Name: Remember
|
||||||
|
// Author: diatribes
|
||||||
|
// URL: https://www.shadertoy.com/view/tXSBDK
|
||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
// fuzzy brain
|
||||||
|
|
||||||
|
// Hash function to replace iChannel0 texture noise
|
||||||
|
float hash12(vec2 p) {
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * .1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 o, vec2 u) {
|
||||||
|
|
||||||
|
vec3 q,p = vec3(iResolution.xy, iResolution.x / iResolution.y);
|
||||||
|
|
||||||
|
float i = 0.0, s,
|
||||||
|
// start the ray at a small random distance,
|
||||||
|
// this will reduce banding
|
||||||
|
// Replaced texelFetch(iChannel0, ...) with hash function
|
||||||
|
d = .125 * hash12(u),
|
||||||
|
t = iTime * .1;
|
||||||
|
|
||||||
|
// scale coords
|
||||||
|
u = (u+u-p.xy)/p.y;
|
||||||
|
if (abs(u.y) > .8) { o = vec4(0); return; }
|
||||||
|
|
||||||
|
// Initialize output color (out parameter must be initialized before use)
|
||||||
|
o = vec4(0.0);
|
||||||
|
|
||||||
|
for(; i<64.; i++) {
|
||||||
|
|
||||||
|
// shorthand for standard raymarch sample, then move forward:
|
||||||
|
// p = ro + rd * d, p.z + t
|
||||||
|
q = p = vec3(u * d, d + t*5.);
|
||||||
|
p.xy *= mat2(cos(.1*p.z+.1*t+vec4(0,33,11,0)));
|
||||||
|
|
||||||
|
q.xz = cos(q.xz);
|
||||||
|
p.z = cos(p.z) ;
|
||||||
|
// turbulence
|
||||||
|
for (s = 1.; s++ <6.;
|
||||||
|
q += sin(.6*t+p.zxy*.6),
|
||||||
|
p += sin(t+t+p.yzx*s)*.6);
|
||||||
|
|
||||||
|
// distance to spheres
|
||||||
|
d += s = .02 + abs(min(length(p+3.*sin(p.z*.5))-4., length(q-2.*sin(p.z*.4))-6.))*.2;
|
||||||
|
|
||||||
|
// color: 1.+cos so we don't go negative, cos(d+vec4(6,4,2,0)) samples from the palette
|
||||||
|
// divide by s for form and distance
|
||||||
|
// Clamp only the first term to prevent extreme overflow, leave second term free
|
||||||
|
vec4 brightTerm = min(.01*vec4(6,2,1,0)/max(length(u*sin(t+t+t)), 0.001), vec4(50.0));
|
||||||
|
o += brightTerm + 1. / s * length(u);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// tonemap and divide brightness
|
||||||
|
o = tanh(max(o /6e2 + dot(u,u)*.35, 0.));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
61
data/shaders/remember/remember.vk.glsl
Normal file
61
data/shaders/remember/remember.vk.glsl
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Remember
|
||||||
|
// Author: diatribes
|
||||||
|
// URL: https://www.shadertoy.com/view/tXSBDK
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
// fuzzy brain — Hash function to replace iChannel0 texture noise
|
||||||
|
float hash12(vec2 p) {
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * .1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 o, vec2 u) {
|
||||||
|
|
||||||
|
vec3 q, p = vec3(iResolution.xy, iResolution.x / iResolution.y);
|
||||||
|
|
||||||
|
float i = 0.0, s,
|
||||||
|
d = .125 * hash12(u),
|
||||||
|
t = iTime * .1;
|
||||||
|
|
||||||
|
u = (u + u - p.xy) / p.y;
|
||||||
|
if (abs(u.y) > .8) { o = vec4(0); return; }
|
||||||
|
|
||||||
|
o = vec4(0.0);
|
||||||
|
|
||||||
|
for (; i < 64.; i++) {
|
||||||
|
|
||||||
|
q = p = vec3(u * d, d + t * 5.);
|
||||||
|
p.xy *= mat2(cos(.1 * p.z + .1 * t + vec4(0, 33, 11, 0)));
|
||||||
|
|
||||||
|
q.xz = cos(q.xz);
|
||||||
|
p.z = cos(p.z);
|
||||||
|
for (s = 1.; s++ < 6.;
|
||||||
|
q += sin(.6 * t + p.zxy * .6),
|
||||||
|
p += sin(t + t + p.yzx * s) * .6);
|
||||||
|
|
||||||
|
d += s = .02 + abs(min(length(p + 3. * sin(p.z * .5)) - 4., length(q - 2. * sin(p.z * .4)) - 6.)) * .2;
|
||||||
|
|
||||||
|
vec4 brightTerm = min(.01 * vec4(6, 2, 1, 0) / max(length(u * sin(t + t + t)), 0.001), vec4(50.0));
|
||||||
|
o += brightTerm + 1. / s * length(u);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
o = tanh(max(o / 6e2 + dot(u, u) * .35, 0.));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/seascape/meta.txt
Normal file
2
data/shaders/seascape/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Seascape
|
||||||
|
Author: Alexander Alekseev
|
||||||
181
data/shaders/seascape/seascape.frag.msl
Normal file
181
data/shaders/seascape/seascape.frag.msl
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Seascape — Alexander Alekseev (TDM, 2014)
|
||||||
|
// MSL port of seascape.vk.glsl. iTime threaded through helpers because
|
||||||
|
// MSL does not allow file-scope mutable globals.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
constant int NUM_STEPS = 32;
|
||||||
|
constant float PI = 3.141592;
|
||||||
|
constant float EPSILON = 1e-3;
|
||||||
|
|
||||||
|
constant int ITER_GEOMETRY = 3;
|
||||||
|
constant int ITER_FRAGMENT = 5;
|
||||||
|
constant float SEA_HEIGHT = 0.6;
|
||||||
|
constant float SEA_CHOPPY = 4.0;
|
||||||
|
constant float SEA_SPEED = 0.8;
|
||||||
|
constant float SEA_FREQ = 0.16;
|
||||||
|
constant float3 SEA_BASE = float3(0.0, 0.09, 0.18);
|
||||||
|
constant float3 SEA_WATER_COLOR = float3(0.8, 0.9, 0.6) * 0.6;
|
||||||
|
constant float2x2 octave_m = float2x2(1.6, 1.2, -1.2, 1.6);
|
||||||
|
|
||||||
|
static float3x3 fromEuler(float3 ang) {
|
||||||
|
float2 a1 = float2(sin(ang.x), cos(ang.x));
|
||||||
|
float2 a2 = float2(sin(ang.y), cos(ang.y));
|
||||||
|
float2 a3 = float2(sin(ang.z), cos(ang.z));
|
||||||
|
float3x3 m;
|
||||||
|
m[0] = float3(a1.y * a3.y + a1.x * a2.x * a3.x, a1.y * a2.x * a3.x + a3.y * a1.x, -a2.y * a3.x);
|
||||||
|
m[1] = float3(-a2.y * a1.x, a1.y * a2.y, a2.x);
|
||||||
|
m[2] = float3(a3.y * a1.x * a2.x + a1.y * a3.x, a1.x * a3.x - a1.y * a3.y * a2.x, a2.y * a3.y);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float hash(float2 p) {
|
||||||
|
float h = dot(p, float2(127.1, 311.7));
|
||||||
|
return fract(sin(h) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float noise(float2 p) {
|
||||||
|
float2 i = floor(p);
|
||||||
|
float2 f = fract(p);
|
||||||
|
float2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
return -1.0 + 2.0 * mix(mix(hash(i + float2(0.0, 0.0)),
|
||||||
|
hash(i + float2(1.0, 0.0)), u.x),
|
||||||
|
mix(hash(i + float2(0.0, 1.0)),
|
||||||
|
hash(i + float2(1.0, 1.0)), u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float diffuseLight(float3 n, float3 l, float p) {
|
||||||
|
return pow(dot(n, l) * 0.4 + 0.6, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float specularLight(float3 n, float3 l, float3 e, float s) {
|
||||||
|
float nrm = (s + 8.0) / (PI * 8.0);
|
||||||
|
return pow(max(dot(reflect(e, n), l), 0.0), s) * nrm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getSkyColor(float3 e) {
|
||||||
|
e.y = (max(e.y, 0.0) * 0.8 + 0.2) * 0.8;
|
||||||
|
return float3(pow(1.0 - e.y, 2.0), 1.0 - e.y, 0.6 + (1.0 - e.y) * 0.4) * 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float sea_octave(float2 uv, float choppy) {
|
||||||
|
uv += noise(uv);
|
||||||
|
float2 wv = 1.0 - abs(sin(uv));
|
||||||
|
float2 swv = abs(cos(uv));
|
||||||
|
wv = mix(wv, swv, wv);
|
||||||
|
return pow(1.0 - pow(wv.x * wv.y, 0.65), choppy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float seaMap(float3 p, float iTime, int iter) {
|
||||||
|
float SEA_TIME = 1.0 + iTime * SEA_SPEED;
|
||||||
|
float freq = SEA_FREQ;
|
||||||
|
float amp = SEA_HEIGHT;
|
||||||
|
float choppy = SEA_CHOPPY;
|
||||||
|
float2 uv = p.xz; uv.x *= 0.75;
|
||||||
|
|
||||||
|
float d, h = 0.0;
|
||||||
|
for (int i = 0; i < iter; i++) {
|
||||||
|
d = sea_octave((uv + SEA_TIME) * freq, choppy);
|
||||||
|
d += sea_octave((uv - SEA_TIME) * freq, choppy);
|
||||||
|
h += d * amp;
|
||||||
|
uv = uv * octave_m;
|
||||||
|
freq *= 1.9;
|
||||||
|
amp *= 0.22;
|
||||||
|
choppy = mix(choppy, 1.0, 0.2);
|
||||||
|
}
|
||||||
|
return p.y - h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getSeaColor(float3 p, float3 n, float3 l, float3 eye, float3 dist) {
|
||||||
|
float fresnel = clamp(1.0 - dot(n, -eye), 0.0, 1.0);
|
||||||
|
fresnel = min(fresnel * fresnel * fresnel, 0.5);
|
||||||
|
|
||||||
|
float3 reflected = getSkyColor(reflect(eye, n));
|
||||||
|
float3 refracted = SEA_BASE + diffuseLight(n, l, 80.0) * SEA_WATER_COLOR * 0.12;
|
||||||
|
|
||||||
|
float3 color = mix(refracted, reflected, fresnel);
|
||||||
|
|
||||||
|
float atten = max(1.0 - dot(dist, dist) * 0.001, 0.0);
|
||||||
|
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
|
||||||
|
|
||||||
|
color += specularLight(n, l, eye, 600.0 * rsqrt(dot(dist, dist)));
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getNormal(float3 p, float eps, float iTime) {
|
||||||
|
float3 n;
|
||||||
|
n.y = seaMap(p, iTime, ITER_FRAGMENT);
|
||||||
|
n.x = seaMap(float3(p.x + eps, p.y, p.z), iTime, ITER_FRAGMENT) - n.y;
|
||||||
|
n.z = seaMap(float3(p.x, p.y, p.z + eps), iTime, ITER_FRAGMENT) - n.y;
|
||||||
|
n.y = eps;
|
||||||
|
return normalize(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float heightMapTracing(float3 ori, float3 dir, thread float3& p, float iTime) {
|
||||||
|
float tm = 0.0;
|
||||||
|
float tx = 1000.0;
|
||||||
|
float hx = seaMap(ori + dir * tx, iTime, ITER_GEOMETRY);
|
||||||
|
if (hx > 0.0) {
|
||||||
|
p = ori + dir * tx;
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
float hm = seaMap(ori, iTime, ITER_GEOMETRY);
|
||||||
|
for (int i = 0; i < NUM_STEPS; i++) {
|
||||||
|
float tmid = mix(tm, tx, hm / (hm - hx));
|
||||||
|
p = ori + dir * tmid;
|
||||||
|
float hmid = seaMap(p, iTime, ITER_GEOMETRY);
|
||||||
|
if (hmid < 0.0) {
|
||||||
|
tx = tmid;
|
||||||
|
hx = hmid;
|
||||||
|
} else {
|
||||||
|
tm = tmid;
|
||||||
|
hm = hmid;
|
||||||
|
}
|
||||||
|
if (abs(hmid) < EPSILON) break;
|
||||||
|
}
|
||||||
|
return mix(tm, tx, hm / (hm - hx));
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getPixel(float2 coord, float time, float2 iResolution, float iTime) {
|
||||||
|
float2 uv = coord / iResolution;
|
||||||
|
uv = uv * 2.0 - 1.0;
|
||||||
|
uv.x *= iResolution.x / iResolution.y;
|
||||||
|
|
||||||
|
float3 ang = float3(sin(time * 3.0) * 0.1, sin(time) * 0.2 + 0.3, time);
|
||||||
|
float3 ori = float3(0.0, 3.5, time * 5.0);
|
||||||
|
float3 dir = normalize(float3(uv.xy, -2.0));
|
||||||
|
dir.z += length(uv) * 0.14;
|
||||||
|
dir = normalize(dir) * fromEuler(ang);
|
||||||
|
|
||||||
|
float3 p;
|
||||||
|
heightMapTracing(ori, dir, p, iTime);
|
||||||
|
float3 dist = p - ori;
|
||||||
|
float EPSILON_NRM = 0.1 / iResolution.x;
|
||||||
|
float3 n = getNormal(p, dot(dist, dist) * EPSILON_NRM, iTime);
|
||||||
|
float3 light = normalize(float3(0.0, 1.0, 0.8));
|
||||||
|
|
||||||
|
return mix(
|
||||||
|
getSkyColor(dir),
|
||||||
|
getSeaColor(p, n, light, dir, dist),
|
||||||
|
pow(smoothstep(0.0, -0.02, dir.y), 0.2));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 seascape_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float time = U.iTime * 0.3;
|
||||||
|
float3 color = getPixel(fragCoord, time, U.iResolution, U.iTime);
|
||||||
|
return float4(pow(color, float3(0.65)), 1.0);
|
||||||
|
}
|
||||||
BIN
data/shaders/seascape/seascape.frag.spv
Normal file
BIN
data/shaders/seascape/seascape.frag.spv
Normal file
Binary file not shown.
223
data/shaders/seascape/seascape.gl.glsl
Normal file
223
data/shaders/seascape/seascape.gl.glsl
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
// Name: Seascape
|
||||||
|
// Author: Alexander Alekseev
|
||||||
|
// URL: https://www.shadertoy.com/view/Ms2SD1
|
||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Seascape" by Alexander Alekseev aka TDM - 2014
|
||||||
|
* License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||||
|
* Contact: tdmaav@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
const int NUM_STEPS = 32;
|
||||||
|
const float PI = 3.141592;
|
||||||
|
const float EPSILON = 1e-3;
|
||||||
|
#define EPSILON_NRM (0.1 / iResolution.x)
|
||||||
|
//#define AA
|
||||||
|
|
||||||
|
// sea
|
||||||
|
const int ITER_GEOMETRY = 3;
|
||||||
|
const int ITER_FRAGMENT = 5;
|
||||||
|
const float SEA_HEIGHT = 0.6;
|
||||||
|
const float SEA_CHOPPY = 4.0;
|
||||||
|
const float SEA_SPEED = 0.8;
|
||||||
|
const float SEA_FREQ = 0.16;
|
||||||
|
const vec3 SEA_BASE = vec3(0.0,0.09,0.18);
|
||||||
|
const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6)*0.6;
|
||||||
|
#define SEA_TIME (1.0 + iTime * SEA_SPEED)
|
||||||
|
const mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);
|
||||||
|
|
||||||
|
// math
|
||||||
|
mat3 fromEuler(vec3 ang) {
|
||||||
|
vec2 a1 = vec2(sin(ang.x),cos(ang.x));
|
||||||
|
vec2 a2 = vec2(sin(ang.y),cos(ang.y));
|
||||||
|
vec2 a3 = vec2(sin(ang.z),cos(ang.z));
|
||||||
|
mat3 m;
|
||||||
|
m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);
|
||||||
|
m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
|
||||||
|
m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
float hash( vec2 p ) {
|
||||||
|
float h = dot(p,vec2(127.1,311.7));
|
||||||
|
return fract(sin(h)*43758.5453123);
|
||||||
|
}
|
||||||
|
float noise( in vec2 p ) {
|
||||||
|
vec2 i = floor( p );
|
||||||
|
vec2 f = fract( p );
|
||||||
|
vec2 u = f*f*(3.0-2.0*f);
|
||||||
|
return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ),
|
||||||
|
hash( i + vec2(1.0,0.0) ), u.x),
|
||||||
|
mix( hash( i + vec2(0.0,1.0) ),
|
||||||
|
hash( i + vec2(1.0,1.0) ), u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lighting
|
||||||
|
float diffuse(vec3 n,vec3 l,float p) {
|
||||||
|
return pow(dot(n,l) * 0.4 + 0.6,p);
|
||||||
|
}
|
||||||
|
float specular(vec3 n,vec3 l,vec3 e,float s) {
|
||||||
|
float nrm = (s + 8.0) / (PI * 8.0);
|
||||||
|
return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sky
|
||||||
|
vec3 getSkyColor(vec3 e) {
|
||||||
|
e.y = (max(e.y,0.0)*0.8+0.2)*0.8;
|
||||||
|
return vec3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4) * 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sea
|
||||||
|
float sea_octave(vec2 uv, float choppy) {
|
||||||
|
uv += noise(uv);
|
||||||
|
vec2 wv = 1.0-abs(sin(uv));
|
||||||
|
vec2 swv = abs(cos(uv));
|
||||||
|
wv = mix(wv,swv,wv);
|
||||||
|
return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
|
||||||
|
}
|
||||||
|
|
||||||
|
float map(vec3 p) {
|
||||||
|
float freq = SEA_FREQ;
|
||||||
|
float amp = SEA_HEIGHT;
|
||||||
|
float choppy = SEA_CHOPPY;
|
||||||
|
vec2 uv = p.xz; uv.x *= 0.75;
|
||||||
|
|
||||||
|
float d, h = 0.0;
|
||||||
|
for(int i = 0; i < ITER_GEOMETRY; i++) {
|
||||||
|
d = sea_octave((uv+SEA_TIME)*freq,choppy);
|
||||||
|
d += sea_octave((uv-SEA_TIME)*freq,choppy);
|
||||||
|
h += d * amp;
|
||||||
|
uv *= octave_m; freq *= 1.9; amp *= 0.22;
|
||||||
|
choppy = mix(choppy,1.0,0.2);
|
||||||
|
}
|
||||||
|
return p.y - h;
|
||||||
|
}
|
||||||
|
|
||||||
|
float map_detailed(vec3 p) {
|
||||||
|
float freq = SEA_FREQ;
|
||||||
|
float amp = SEA_HEIGHT;
|
||||||
|
float choppy = SEA_CHOPPY;
|
||||||
|
vec2 uv = p.xz; uv.x *= 0.75;
|
||||||
|
|
||||||
|
float d, h = 0.0;
|
||||||
|
for(int i = 0; i < ITER_FRAGMENT; i++) {
|
||||||
|
d = sea_octave((uv+SEA_TIME)*freq,choppy);
|
||||||
|
d += sea_octave((uv-SEA_TIME)*freq,choppy);
|
||||||
|
h += d * amp;
|
||||||
|
uv *= octave_m; freq *= 1.9; amp *= 0.22;
|
||||||
|
choppy = mix(choppy,1.0,0.2);
|
||||||
|
}
|
||||||
|
return p.y - h;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
|
||||||
|
float fresnel = clamp(1.0 - dot(n, -eye), 0.0, 1.0);
|
||||||
|
fresnel = min(fresnel * fresnel * fresnel, 0.5);
|
||||||
|
|
||||||
|
vec3 reflected = getSkyColor(reflect(eye, n));
|
||||||
|
vec3 refracted = SEA_BASE + diffuse(n, l, 80.0) * SEA_WATER_COLOR * 0.12;
|
||||||
|
|
||||||
|
vec3 color = mix(refracted, reflected, fresnel);
|
||||||
|
|
||||||
|
float atten = max(1.0 - dot(dist, dist) * 0.001, 0.0);
|
||||||
|
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
|
||||||
|
|
||||||
|
color += specular(n, l, eye, 600.0 * inversesqrt(dot(dist,dist)));
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tracing
|
||||||
|
vec3 getNormal(vec3 p, float eps) {
|
||||||
|
vec3 n;
|
||||||
|
n.y = map_detailed(p);
|
||||||
|
n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;
|
||||||
|
n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;
|
||||||
|
n.y = eps;
|
||||||
|
return normalize(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
|
||||||
|
float tm = 0.0;
|
||||||
|
float tx = 1000.0;
|
||||||
|
float hx = map(ori + dir * tx);
|
||||||
|
if(hx > 0.0) {
|
||||||
|
p = ori + dir * tx;
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
float hm = map(ori);
|
||||||
|
for(int i = 0; i < NUM_STEPS; i++) {
|
||||||
|
float tmid = mix(tm, tx, hm / (hm - hx));
|
||||||
|
p = ori + dir * tmid;
|
||||||
|
float hmid = map(p);
|
||||||
|
if(hmid < 0.0) {
|
||||||
|
tx = tmid;
|
||||||
|
hx = hmid;
|
||||||
|
} else {
|
||||||
|
tm = tmid;
|
||||||
|
hm = hmid;
|
||||||
|
}
|
||||||
|
if(abs(hmid) < EPSILON) break;
|
||||||
|
}
|
||||||
|
return mix(tm, tx, hm / (hm - hx));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getPixel(in vec2 coord, float time) {
|
||||||
|
vec2 uv = coord / iResolution.xy;
|
||||||
|
uv = uv * 2.0 - 1.0;
|
||||||
|
uv.x *= iResolution.x / iResolution.y;
|
||||||
|
|
||||||
|
// ray
|
||||||
|
vec3 ang = vec3(sin(time*3.0)*0.1,sin(time)*0.2+0.3,time);
|
||||||
|
vec3 ori = vec3(0.0,3.5,time*5.0);
|
||||||
|
vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.14;
|
||||||
|
dir = normalize(dir) * fromEuler(ang);
|
||||||
|
|
||||||
|
// tracing
|
||||||
|
vec3 p;
|
||||||
|
heightMapTracing(ori,dir,p);
|
||||||
|
vec3 dist = p - ori;
|
||||||
|
vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);
|
||||||
|
vec3 light = normalize(vec3(0.0,1.0,0.8));
|
||||||
|
|
||||||
|
// color
|
||||||
|
return mix(
|
||||||
|
getSkyColor(dir),
|
||||||
|
getSeaColor(p,n,light,dir,dist),
|
||||||
|
pow(smoothstep(0.0,-0.02,dir.y),0.2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// main
|
||||||
|
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||||
|
// Removed mouse interaction (iMouse not available)
|
||||||
|
float time = iTime * 0.3;
|
||||||
|
|
||||||
|
#ifdef AA
|
||||||
|
vec3 color = vec3(0.0);
|
||||||
|
for(int i = -1; i <= 1; i++) {
|
||||||
|
for(int j = -1; j <= 1; j++) {
|
||||||
|
vec2 uv = fragCoord+vec2(i,j)/3.0;
|
||||||
|
color += getPixel(uv, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color /= 9.0;
|
||||||
|
#else
|
||||||
|
vec3 color = getPixel(fragCoord, time);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// post
|
||||||
|
fragColor = vec4(pow(color,vec3(0.65)), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
200
data/shaders/seascape/seascape.vk.glsl
Normal file
200
data/shaders/seascape/seascape.vk.glsl
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Seascape
|
||||||
|
// Author: Alexander Alekseev
|
||||||
|
// URL: https://www.shadertoy.com/view/Ms2SD1
|
||||||
|
//
|
||||||
|
// "Seascape" by Alexander Alekseev aka TDM - 2014
|
||||||
|
// CC BY-NC-SA 3.0 Unported License.
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
const int NUM_STEPS = 32;
|
||||||
|
const float PI = 3.141592;
|
||||||
|
const float EPSILON = 1e-3;
|
||||||
|
#define EPSILON_NRM (0.1 / iResolution.x)
|
||||||
|
|
||||||
|
const int ITER_GEOMETRY = 3;
|
||||||
|
const int ITER_FRAGMENT = 5;
|
||||||
|
const float SEA_HEIGHT = 0.6;
|
||||||
|
const float SEA_CHOPPY = 4.0;
|
||||||
|
const float SEA_SPEED = 0.8;
|
||||||
|
const float SEA_FREQ = 0.16;
|
||||||
|
const vec3 SEA_BASE = vec3(0.0, 0.09, 0.18);
|
||||||
|
const vec3 SEA_WATER_COLOR = vec3(0.8, 0.9, 0.6) * 0.6;
|
||||||
|
#define SEA_TIME (1.0 + iTime * SEA_SPEED)
|
||||||
|
const mat2 octave_m = mat2(1.6, 1.2, -1.2, 1.6);
|
||||||
|
|
||||||
|
mat3 fromEuler(vec3 ang) {
|
||||||
|
vec2 a1 = vec2(sin(ang.x), cos(ang.x));
|
||||||
|
vec2 a2 = vec2(sin(ang.y), cos(ang.y));
|
||||||
|
vec2 a3 = vec2(sin(ang.z), cos(ang.z));
|
||||||
|
mat3 m;
|
||||||
|
m[0] = vec3(a1.y * a3.y + a1.x * a2.x * a3.x, a1.y * a2.x * a3.x + a3.y * a1.x, -a2.y * a3.x);
|
||||||
|
m[1] = vec3(-a2.y * a1.x, a1.y * a2.y, a2.x);
|
||||||
|
m[2] = vec3(a3.y * a1.x * a2.x + a1.y * a3.x, a1.x * a3.x - a1.y * a3.y * a2.x, a2.y * a3.y);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
float hash(vec2 p) {
|
||||||
|
float h = dot(p, vec2(127.1, 311.7));
|
||||||
|
return fract(sin(h) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
float noise(in vec2 p) {
|
||||||
|
vec2 i = floor(p);
|
||||||
|
vec2 f = fract(p);
|
||||||
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
return -1.0 + 2.0 * mix(mix(hash(i + vec2(0.0, 0.0)),
|
||||||
|
hash(i + vec2(1.0, 0.0)), u.x),
|
||||||
|
mix(hash(i + vec2(0.0, 1.0)),
|
||||||
|
hash(i + vec2(1.0, 1.0)), u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float diffuse(vec3 n, vec3 l, float p) {
|
||||||
|
return pow(dot(n, l) * 0.4 + 0.6, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
float specular(vec3 n, vec3 l, vec3 e, float s) {
|
||||||
|
float nrm = (s + 8.0) / (PI * 8.0);
|
||||||
|
return pow(max(dot(reflect(e, n), l), 0.0), s) * nrm;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getSkyColor(vec3 e) {
|
||||||
|
e.y = (max(e.y, 0.0) * 0.8 + 0.2) * 0.8;
|
||||||
|
return vec3(pow(1.0 - e.y, 2.0), 1.0 - e.y, 0.6 + (1.0 - e.y) * 0.4) * 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sea_octave(vec2 uv, float choppy) {
|
||||||
|
uv += noise(uv);
|
||||||
|
vec2 wv = 1.0 - abs(sin(uv));
|
||||||
|
vec2 swv = abs(cos(uv));
|
||||||
|
wv = mix(wv, swv, wv);
|
||||||
|
return pow(1.0 - pow(wv.x * wv.y, 0.65), choppy);
|
||||||
|
}
|
||||||
|
|
||||||
|
float map(vec3 p) {
|
||||||
|
float freq = SEA_FREQ;
|
||||||
|
float amp = SEA_HEIGHT;
|
||||||
|
float choppy = SEA_CHOPPY;
|
||||||
|
vec2 uv = p.xz; uv.x *= 0.75;
|
||||||
|
|
||||||
|
float d, h = 0.0;
|
||||||
|
for (int i = 0; i < ITER_GEOMETRY; i++) {
|
||||||
|
d = sea_octave((uv + SEA_TIME) * freq, choppy);
|
||||||
|
d += sea_octave((uv - SEA_TIME) * freq, choppy);
|
||||||
|
h += d * amp;
|
||||||
|
uv *= octave_m; freq *= 1.9; amp *= 0.22;
|
||||||
|
choppy = mix(choppy, 1.0, 0.2);
|
||||||
|
}
|
||||||
|
return p.y - h;
|
||||||
|
}
|
||||||
|
|
||||||
|
float map_detailed(vec3 p) {
|
||||||
|
float freq = SEA_FREQ;
|
||||||
|
float amp = SEA_HEIGHT;
|
||||||
|
float choppy = SEA_CHOPPY;
|
||||||
|
vec2 uv = p.xz; uv.x *= 0.75;
|
||||||
|
|
||||||
|
float d, h = 0.0;
|
||||||
|
for (int i = 0; i < ITER_FRAGMENT; i++) {
|
||||||
|
d = sea_octave((uv + SEA_TIME) * freq, choppy);
|
||||||
|
d += sea_octave((uv - SEA_TIME) * freq, choppy);
|
||||||
|
h += d * amp;
|
||||||
|
uv *= octave_m; freq *= 1.9; amp *= 0.22;
|
||||||
|
choppy = mix(choppy, 1.0, 0.2);
|
||||||
|
}
|
||||||
|
return p.y - h;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
|
||||||
|
float fresnel = clamp(1.0 - dot(n, -eye), 0.0, 1.0);
|
||||||
|
fresnel = min(fresnel * fresnel * fresnel, 0.5);
|
||||||
|
|
||||||
|
vec3 reflected = getSkyColor(reflect(eye, n));
|
||||||
|
vec3 refracted = SEA_BASE + diffuse(n, l, 80.0) * SEA_WATER_COLOR * 0.12;
|
||||||
|
|
||||||
|
vec3 color = mix(refracted, reflected, fresnel);
|
||||||
|
|
||||||
|
float atten = max(1.0 - dot(dist, dist) * 0.001, 0.0);
|
||||||
|
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
|
||||||
|
|
||||||
|
color += specular(n, l, eye, 600.0 * inversesqrt(dot(dist, dist)));
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getNormal(vec3 p, float eps) {
|
||||||
|
vec3 n;
|
||||||
|
n.y = map_detailed(p);
|
||||||
|
n.x = map_detailed(vec3(p.x + eps, p.y, p.z)) - n.y;
|
||||||
|
n.z = map_detailed(vec3(p.x, p.y, p.z + eps)) - n.y;
|
||||||
|
n.y = eps;
|
||||||
|
return normalize(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
|
||||||
|
float tm = 0.0;
|
||||||
|
float tx = 1000.0;
|
||||||
|
float hx = map(ori + dir * tx);
|
||||||
|
if (hx > 0.0) {
|
||||||
|
p = ori + dir * tx;
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
float hm = map(ori);
|
||||||
|
for (int i = 0; i < NUM_STEPS; i++) {
|
||||||
|
float tmid = mix(tm, tx, hm / (hm - hx));
|
||||||
|
p = ori + dir * tmid;
|
||||||
|
float hmid = map(p);
|
||||||
|
if (hmid < 0.0) {
|
||||||
|
tx = tmid;
|
||||||
|
hx = hmid;
|
||||||
|
} else {
|
||||||
|
tm = tmid;
|
||||||
|
hm = hmid;
|
||||||
|
}
|
||||||
|
if (abs(hmid) < EPSILON) break;
|
||||||
|
}
|
||||||
|
return mix(tm, tx, hm / (hm - hx));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getPixel(in vec2 coord, float time) {
|
||||||
|
vec2 uv = coord / iResolution.xy;
|
||||||
|
uv = uv * 2.0 - 1.0;
|
||||||
|
uv.x *= iResolution.x / iResolution.y;
|
||||||
|
|
||||||
|
vec3 ang = vec3(sin(time * 3.0) * 0.1, sin(time) * 0.2 + 0.3, time);
|
||||||
|
vec3 ori = vec3(0.0, 3.5, time * 5.0);
|
||||||
|
vec3 dir = normalize(vec3(uv.xy, -2.0)); dir.z += length(uv) * 0.14;
|
||||||
|
dir = normalize(dir) * fromEuler(ang);
|
||||||
|
|
||||||
|
vec3 p;
|
||||||
|
heightMapTracing(ori, dir, p);
|
||||||
|
vec3 dist = p - ori;
|
||||||
|
vec3 n = getNormal(p, dot(dist, dist) * EPSILON_NRM);
|
||||||
|
vec3 light = normalize(vec3(0.0, 1.0, 0.8));
|
||||||
|
|
||||||
|
return mix(
|
||||||
|
getSkyColor(dir),
|
||||||
|
getSeaColor(p, n, light, dir, dist),
|
||||||
|
pow(smoothstep(0.0, -0.02, dir.y), 0.2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
float time = iTime * 0.3;
|
||||||
|
vec3 color = getPixel(fragCoord, time);
|
||||||
|
fragColor = vec4(pow(color, vec3(0.65)), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/shader_art_coding_introduction/meta.txt
Normal file
2
data/shaders/shader_art_coding_introduction/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Shader Art Coding Introduction
|
||||||
|
Author: kishimisu
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Shader Art Coding Introduction — kishimisu
|
||||||
|
// MSL port of shader_art_coding_introduction.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float3 palette(float t) {
|
||||||
|
float3 a = float3(0.5, 0.5, 0.5);
|
||||||
|
float3 b = float3(0.5, 0.5, 0.5);
|
||||||
|
float3 c = float3(1.0, 1.0, 1.0);
|
||||||
|
float3 d = float3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos(6.28318 * (c * t * d));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 shader_art_coding_introduction_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 uv = (fragCoord * 2.0 - U.iResolution) / U.iResolution.y;
|
||||||
|
float2 uv0 = uv;
|
||||||
|
float3 finalColor = float3(0.0);
|
||||||
|
|
||||||
|
for (float i = 0.0; i < 4.0; i++) {
|
||||||
|
uv = fract(uv * 1.5) - 0.5;
|
||||||
|
|
||||||
|
float d = length(uv) * exp(-length(uv0));
|
||||||
|
|
||||||
|
float3 col = palette(length(uv0) + i * 0.4 + U.iTime * 0.4);
|
||||||
|
|
||||||
|
d = sin(d * 8.0 + U.iTime) / 8.0;
|
||||||
|
d = abs(d);
|
||||||
|
d = pow(0.01 / d, 1.2);
|
||||||
|
|
||||||
|
finalColor += col * d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return float4(finalColor, 1.0);
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -1,3 +1,6 @@
|
|||||||
|
// Name: Shader Art Coding Introduction
|
||||||
|
// Author: kishimisu
|
||||||
|
// URL: https://www.shadertoy.com/view/mtyGWy
|
||||||
#version 330 core
|
#version 330 core
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Shader Art Coding Introduction
|
||||||
|
// Author: kishimisu
|
||||||
|
// URL: https://www.shadertoy.com/view/mtyGWy
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec3 palette(float t) {
|
||||||
|
vec3 a = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos(6.28318 * (c * t * d));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
|
||||||
|
vec2 uv0 = uv;
|
||||||
|
vec3 finalColor = vec3(0.0);
|
||||||
|
|
||||||
|
for (float i = 0.0; i < 4.0; i++) {
|
||||||
|
uv = fract(uv * 1.5) - 0.5;
|
||||||
|
|
||||||
|
float d = length(uv) * exp(-length(uv0));
|
||||||
|
|
||||||
|
vec3 col = palette(length(uv0) + i * 0.4 + iTime * 0.4);
|
||||||
|
|
||||||
|
d = sin(d * 8.0 + iTime) / 8.0;
|
||||||
|
d = abs(d);
|
||||||
|
d = pow(0.01 / d, 1.2);
|
||||||
|
|
||||||
|
finalColor += col * d;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragColor = vec4(finalColor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/test/meta.txt
Normal file
2
data/shaders/test/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Test
|
||||||
|
Author: JailDesigner
|
||||||
36
data/shaders/test/test.frag.msl
Normal file
36
data/shaders/test/test.frag.msl
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Test shader (Metal Shading Language port of test.vk.glsl).
|
||||||
|
// Author: JailDesigner
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float3 palette(float t) {
|
||||||
|
float3 a = float3(1.0, 0.5, 0.5);
|
||||||
|
float3 b = float3(1.0, 0.5, 0.5);
|
||||||
|
float3 c = float3(1.0, 1.0, 1.0);
|
||||||
|
float3 d = float3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos(6.28318 * (c * t * d));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 test_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& u [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * u.iResolution;
|
||||||
|
float2 uv = (fragCoord * 2.0 - u.iResolution) / u.iResolution.y;
|
||||||
|
float d = length(uv);
|
||||||
|
float3 col = palette(d);
|
||||||
|
d = sin(d * 8.0 + u.iTime) / 8.0;
|
||||||
|
d = abs(d);
|
||||||
|
d = 0.02 / d;
|
||||||
|
col *= d;
|
||||||
|
return float4(col, 1.0);
|
||||||
|
}
|
||||||
BIN
data/shaders/test/test.frag.spv
Normal file
BIN
data/shaders/test/test.frag.spv
Normal file
Binary file not shown.
@@ -1,3 +1,5 @@
|
|||||||
|
// Name: Test
|
||||||
|
// Author: JailDesigner
|
||||||
#version 330 core
|
#version 330 core
|
||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
in vec2 vUV;
|
in vec2 vUV;
|
||||||
42
data/shaders/test/test.vk.glsl
Normal file
42
data/shaders/test/test.vk.glsl
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Test
|
||||||
|
// Author: JailDesigner
|
||||||
|
//
|
||||||
|
// Vulkan port of test.gl.glsl. Bindings follow the SDL3 GPU convention:
|
||||||
|
// set=3, binding=0 — fragment uniform buffer (anonymous block: members
|
||||||
|
// are accessible directly as iTime / iResolution, like Shadertoy).
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec3 palette(float t) {
|
||||||
|
vec3 a = vec3(1.0, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(1.0, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos(6.28318 * (c * t * d));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 uv = (fragCoord * 2.0 - iResolution) / iResolution.y;
|
||||||
|
float d = length(uv);
|
||||||
|
vec3 col = palette(d);
|
||||||
|
d = sin(d * 8.0 + iTime) / 8.0;
|
||||||
|
d = abs(d);
|
||||||
|
d = 0.02 / d;
|
||||||
|
col *= d;
|
||||||
|
fragColor = vec4(col, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
data/shaders/water/meta.txt
Normal file
2
data/shaders/water/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Water
|
||||||
|
Author: diatribes
|
||||||
40
data/shaders/water/water.frag.msl
Normal file
40
data/shaders/water/water.frag.msl
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Water — diatribes
|
||||||
|
// MSL port of water.vk.glsl. Entry point is named after the shader (water_fs).
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment float4 water_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 u = fragCoord;
|
||||||
|
|
||||||
|
float s = 0.002, i = 0.0, n;
|
||||||
|
float3 r = float3(U.iResolution, U.iResolution.x / U.iResolution.y);
|
||||||
|
float3 p = float3(0);
|
||||||
|
u = (u - r.xy / 2.0) / r.y - 0.3;
|
||||||
|
|
||||||
|
float4 o = float4(0);
|
||||||
|
|
||||||
|
for (; i < 32.0 && s > 0.001; i++) {
|
||||||
|
float4 term = float4(5, 2, 1, 0) / max(length(u - 0.1), 0.001);
|
||||||
|
o += min(term, float4(100.0));
|
||||||
|
p += float3(u * s, s);
|
||||||
|
s = 1.0 + p.y;
|
||||||
|
for (n = 0.01; n < 1.0; n += n) {
|
||||||
|
s += abs(dot(sin(p.z + U.iTime + p / n), float3(1))) * n * 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = tanh(o / 5e2);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
BIN
data/shaders/water/water.frag.spv
Normal file
BIN
data/shaders/water/water.frag.spv
Normal file
Binary file not shown.
44
data/shaders/water/water.gl.glsl
Normal file
44
data/shaders/water/water.gl.glsl
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Name: Water
|
||||||
|
// Author: diatribes
|
||||||
|
// URL: https://www.shadertoy.com/view/tXjXDy
|
||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
/*
|
||||||
|
-2 by @FabriceNeyret2
|
||||||
|
|
||||||
|
thanks!! :D
|
||||||
|
|
||||||
|
If it doesn't display correctly, change line 17 "r/r" to "vec3(1)"
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mainImage( out vec4 o, vec2 u ) {
|
||||||
|
float s=.002, i=0., n; // FIXED: Initialize i=0
|
||||||
|
vec3 r = vec3(iResolution.xy, iResolution.x/iResolution.y);
|
||||||
|
vec3 p = vec3(0);
|
||||||
|
u = (u-r.xy/2.)/r.y-.3;
|
||||||
|
|
||||||
|
o = vec4(0); // FIXED: Initialize output to black
|
||||||
|
|
||||||
|
for(; i < 32. && s > .001; i++) {
|
||||||
|
// Clamp only extreme overflow values, let normal brightness through
|
||||||
|
vec4 term = vec4(5,2,1,0)/max(length(u-.1), 0.001);
|
||||||
|
o += min(term, vec4(100.0));
|
||||||
|
for (p += vec3(u*s,s), s = 1. + p.y, n =.01; n < 1.; n+=n) {
|
||||||
|
s += abs(dot(sin(p.z+iTime+p / n), vec3(1))) * n*.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = tanh(o/5e2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
45
data/shaders/water/water.vk.glsl
Normal file
45
data/shaders/water/water.vk.glsl
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Water
|
||||||
|
// Author: diatribes
|
||||||
|
// URL: https://www.shadertoy.com/view/tXjXDy
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
-2 by @FabriceNeyret2
|
||||||
|
thanks!! :D
|
||||||
|
|
||||||
|
If it doesn't display correctly, change line "r/r" to "vec3(1)"
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mainImage( out vec4 o, vec2 u ) {
|
||||||
|
float s=.002, i=0., n;
|
||||||
|
vec3 r = vec3(iResolution.xy, iResolution.x/iResolution.y);
|
||||||
|
vec3 p = vec3(0);
|
||||||
|
u = (u-r.xy/2.)/r.y-.3;
|
||||||
|
|
||||||
|
o = vec4(0);
|
||||||
|
|
||||||
|
for(; i < 32. && s > .001; i++) {
|
||||||
|
vec4 term = vec4(5,2,1,0)/max(length(u-.1), 0.001);
|
||||||
|
o += min(term, vec4(100.0));
|
||||||
|
for (p += vec3(u*s,s), s = 1. + p.y, n =.01; n < 1.; n+=n) {
|
||||||
|
s += abs(dot(sin(p.z+iTime+p / n), vec3(1))) * n*.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = tanh(o/5e2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
150
release/icons/create_icons.py
Normal file
150
release/icons/create_icons.py
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def check_dependencies():
|
||||||
|
"""Verifica que ImageMagick esté instalado"""
|
||||||
|
try:
|
||||||
|
subprocess.run(['magick', '--version'], capture_output=True, check=True)
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||||
|
print("Error: ImageMagick no está instalado o no se encuentra en el PATH")
|
||||||
|
print("Instala ImageMagick desde: https://imagemagick.org/script/download.php")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Verificar iconutil solo en macOS
|
||||||
|
if sys.platform == 'darwin':
|
||||||
|
try:
|
||||||
|
# iconutil no tiene --version, mejor usar which o probar con -h
|
||||||
|
result = subprocess.run(['which', 'iconutil'], capture_output=True, check=True)
|
||||||
|
if result.returncode == 0:
|
||||||
|
print("✓ iconutil disponible - se crearán archivos .ico e .icns")
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||||
|
print("Error: iconutil no está disponible (solo funciona en macOS)")
|
||||||
|
print("Solo se creará el archivo .ico")
|
||||||
|
else:
|
||||||
|
print("ℹ️ Sistema no-macOS detectado - solo se creará archivo .ico")
|
||||||
|
|
||||||
|
|
||||||
|
def create_icons(input_file):
|
||||||
|
"""Crea archivos .icns e .ico a partir de un PNG"""
|
||||||
|
|
||||||
|
# Verificar que el archivo existe
|
||||||
|
if not os.path.isfile(input_file):
|
||||||
|
print(f"Error: El archivo {input_file} no existe.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Obtener información del archivo
|
||||||
|
file_path = Path(input_file)
|
||||||
|
file_dir = file_path.parent
|
||||||
|
file_name = file_path.stem # Nombre sin extensión
|
||||||
|
file_extension = file_path.suffix
|
||||||
|
|
||||||
|
if file_extension.lower() not in ['.png', '.jpg', '.jpeg', '.bmp', '.tiff']:
|
||||||
|
print(f"Advertencia: {file_extension} puede no ser compatible. Se recomienda usar PNG.")
|
||||||
|
|
||||||
|
# Crear archivo .ico usando el método simplificado
|
||||||
|
ico_output = file_dir / f"{file_name}.ico"
|
||||||
|
try:
|
||||||
|
print(f"Creando {ico_output}...")
|
||||||
|
subprocess.run([
|
||||||
|
'magick', str(input_file),
|
||||||
|
'-define', 'icon:auto-resize=256,128,64,48,32,16',
|
||||||
|
str(ico_output)
|
||||||
|
], check=True)
|
||||||
|
print(f"✓ Archivo .ico creado: {ico_output}")
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error creando archivo .ico: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Crear archivo .icns (solo en macOS)
|
||||||
|
if sys.platform == 'darwin':
|
||||||
|
try:
|
||||||
|
# Crear carpeta temporal para iconset
|
||||||
|
temp_folder = file_dir / "icon.iconset"
|
||||||
|
|
||||||
|
# Eliminar carpeta temporal si existe
|
||||||
|
if temp_folder.exists():
|
||||||
|
shutil.rmtree(temp_folder)
|
||||||
|
|
||||||
|
# Crear carpeta temporal
|
||||||
|
temp_folder.mkdir(parents=True)
|
||||||
|
|
||||||
|
# Definir los tamaños y nombres de archivo para .icns
|
||||||
|
icon_sizes = [
|
||||||
|
(16, "icon_16x16.png"),
|
||||||
|
(32, "icon_16x16@2x.png"),
|
||||||
|
(32, "icon_32x32.png"),
|
||||||
|
(64, "icon_32x32@2x.png"),
|
||||||
|
(128, "icon_128x128.png"),
|
||||||
|
(256, "icon_128x128@2x.png"),
|
||||||
|
(256, "icon_256x256.png"),
|
||||||
|
(512, "icon_256x256@2x.png"),
|
||||||
|
(512, "icon_512x512.png"),
|
||||||
|
(1024, "icon_512x512@2x.png")
|
||||||
|
]
|
||||||
|
|
||||||
|
print("Generando imágenes para .icns...")
|
||||||
|
# Crear cada tamaño de imagen
|
||||||
|
for size, output_name in icon_sizes:
|
||||||
|
output_path = temp_folder / output_name
|
||||||
|
subprocess.run([
|
||||||
|
'magick', str(input_file),
|
||||||
|
'-resize', f'{size}x{size}',
|
||||||
|
str(output_path)
|
||||||
|
], check=True)
|
||||||
|
|
||||||
|
# Crear archivo .icns usando iconutil
|
||||||
|
icns_output = file_dir / f"{file_name}.icns"
|
||||||
|
print(f"Creando {icns_output}...")
|
||||||
|
subprocess.run([
|
||||||
|
'iconutil', '-c', 'icns',
|
||||||
|
str(temp_folder),
|
||||||
|
'-o', str(icns_output)
|
||||||
|
], check=True)
|
||||||
|
|
||||||
|
# Limpiar carpeta temporal
|
||||||
|
if temp_folder.exists():
|
||||||
|
shutil.rmtree(temp_folder)
|
||||||
|
|
||||||
|
print(f"✓ Archivo .icns creado: {icns_output}")
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error creando archivo .icns: {e}")
|
||||||
|
# Limpiar carpeta temporal en caso de error
|
||||||
|
if temp_folder.exists():
|
||||||
|
shutil.rmtree(temp_folder)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("ℹ️ Archivo .icns no creado (solo disponible en macOS)")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Función principal"""
|
||||||
|
# Verificar argumentos
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print(f"Uso: {sys.argv[0]} ARCHIVO")
|
||||||
|
print("Ejemplo: python3 create_icons.py imagen.png")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
input_file = sys.argv[1]
|
||||||
|
|
||||||
|
# Verificar dependencias
|
||||||
|
check_dependencies()
|
||||||
|
|
||||||
|
# Crear iconos
|
||||||
|
if create_icons(input_file):
|
||||||
|
print("\n✅ Proceso completado exitosamente")
|
||||||
|
else:
|
||||||
|
print("\n❌ El proceso falló")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
BIN
release/icons/icon.afdesign
Normal file
BIN
release/icons/icon.afdesign
Normal file
Binary file not shown.
BIN
release/icons/icon.icns
Normal file
BIN
release/icons/icon.icns
Normal file
Binary file not shown.
BIN
release/icons/icon.ico
Normal file
BIN
release/icons/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 137 KiB |
BIN
release/icons/icon.png
Normal file
BIN
release/icons/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 364 KiB |
BIN
release/icons/icon.pxd
Normal file
BIN
release/icons/icon.pxd
Normal file
Binary file not shown.
42
release/macos/Info.plist
Normal file
42
release/macos/Info.plist
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>es</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Shadertoy</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>shadertoy</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>icon</string>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>icon</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>net.jailgames.shadertoy</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>shadertoy</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.00</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.00</string>
|
||||||
|
<key>CSResourcesFileMapped</key>
|
||||||
|
<true/>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>12.0</string>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright 2025 JailDesigner</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
<key>SUPublicDSAKeyFile</key>
|
||||||
|
<string>dsa_pub.pem</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
90
release/macos/frameworks/SDL3.xcframework/Info.plist
Normal file
90
release/macos/frameworks/SDL3.xcframework/Info.plist
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>AvailableLibraries</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/Versions/A/SDL3</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>macos-arm64_x86_64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>macos</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/SDL3</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>tvos-arm64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>tvos</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/SDL3</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/SDL3</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64_x86_64-simulator</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
<key>SupportedPlatformVariant</key>
|
||||||
|
<string>simulator</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/SDL3</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>tvos-arm64_x86_64-simulator</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>tvos</string>
|
||||||
|
<key>SupportedPlatformVariant</key>
|
||||||
|
<string>simulator</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>XFWK</string>
|
||||||
|
<key>XCFrameworkFormatVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Versions/Current/Headers
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Versions/Current/Resources
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Versions/Current/SDL3
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main include header for the SDL library, version 3.2.20
|
||||||
|
*
|
||||||
|
* It is almost always best to include just this one header instead of
|
||||||
|
* picking out individual headers included here. There are exceptions to
|
||||||
|
* this rule--SDL_main.h is special and not included here--but usually
|
||||||
|
* letting SDL.h include the kitchen sink for you is the correct approach.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_h_
|
||||||
|
#define SDL_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
#include <SDL3/SDL_assert.h>
|
||||||
|
#include <SDL3/SDL_asyncio.h>
|
||||||
|
#include <SDL3/SDL_atomic.h>
|
||||||
|
#include <SDL3/SDL_audio.h>
|
||||||
|
#include <SDL3/SDL_bits.h>
|
||||||
|
#include <SDL3/SDL_blendmode.h>
|
||||||
|
#include <SDL3/SDL_camera.h>
|
||||||
|
#include <SDL3/SDL_clipboard.h>
|
||||||
|
#include <SDL3/SDL_cpuinfo.h>
|
||||||
|
#include <SDL3/SDL_dialog.h>
|
||||||
|
#include <SDL3/SDL_endian.h>
|
||||||
|
#include <SDL3/SDL_error.h>
|
||||||
|
#include <SDL3/SDL_events.h>
|
||||||
|
#include <SDL3/SDL_filesystem.h>
|
||||||
|
#include <SDL3/SDL_gamepad.h>
|
||||||
|
#include <SDL3/SDL_gpu.h>
|
||||||
|
#include <SDL3/SDL_guid.h>
|
||||||
|
#include <SDL3/SDL_haptic.h>
|
||||||
|
#include <SDL3/SDL_hidapi.h>
|
||||||
|
#include <SDL3/SDL_hints.h>
|
||||||
|
#include <SDL3/SDL_init.h>
|
||||||
|
#include <SDL3/SDL_iostream.h>
|
||||||
|
#include <SDL3/SDL_joystick.h>
|
||||||
|
#include <SDL3/SDL_keyboard.h>
|
||||||
|
#include <SDL3/SDL_keycode.h>
|
||||||
|
#include <SDL3/SDL_loadso.h>
|
||||||
|
#include <SDL3/SDL_locale.h>
|
||||||
|
#include <SDL3/SDL_log.h>
|
||||||
|
#include <SDL3/SDL_messagebox.h>
|
||||||
|
#include <SDL3/SDL_metal.h>
|
||||||
|
#include <SDL3/SDL_misc.h>
|
||||||
|
#include <SDL3/SDL_mouse.h>
|
||||||
|
#include <SDL3/SDL_mutex.h>
|
||||||
|
#include <SDL3/SDL_pen.h>
|
||||||
|
#include <SDL3/SDL_pixels.h>
|
||||||
|
#include <SDL3/SDL_platform.h>
|
||||||
|
#include <SDL3/SDL_power.h>
|
||||||
|
#include <SDL3/SDL_process.h>
|
||||||
|
#include <SDL3/SDL_properties.h>
|
||||||
|
#include <SDL3/SDL_rect.h>
|
||||||
|
#include <SDL3/SDL_render.h>
|
||||||
|
#include <SDL3/SDL_scancode.h>
|
||||||
|
#include <SDL3/SDL_sensor.h>
|
||||||
|
#include <SDL3/SDL_storage.h>
|
||||||
|
#include <SDL3/SDL_surface.h>
|
||||||
|
#include <SDL3/SDL_system.h>
|
||||||
|
#include <SDL3/SDL_thread.h>
|
||||||
|
#include <SDL3/SDL_time.h>
|
||||||
|
#include <SDL3/SDL_timer.h>
|
||||||
|
#include <SDL3/SDL_tray.h>
|
||||||
|
#include <SDL3/SDL_touch.h>
|
||||||
|
#include <SDL3/SDL_version.h>
|
||||||
|
#include <SDL3/SDL_video.h>
|
||||||
|
#include <SDL3/SDL_oldnames.h>
|
||||||
|
|
||||||
|
#endif /* SDL_h_ */
|
||||||
@@ -0,0 +1,662 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryAssert
|
||||||
|
*
|
||||||
|
* A helpful assertion macro!
|
||||||
|
*
|
||||||
|
* SDL assertions operate like your usual `assert` macro, but with some added
|
||||||
|
* features:
|
||||||
|
*
|
||||||
|
* - It uses a trick with the `sizeof` operator, so disabled assertions
|
||||||
|
* vaporize out of the compiled code, but variables only referenced in the
|
||||||
|
* assertion won't trigger compiler warnings about being unused.
|
||||||
|
* - It is safe to use with a dangling-else: `if (x) SDL_assert(y); else
|
||||||
|
* do_something();`
|
||||||
|
* - It works the same everywhere, instead of counting on various platforms'
|
||||||
|
* compiler and C runtime to behave.
|
||||||
|
* - It provides multiple levels of assertion (SDL_assert, SDL_assert_release,
|
||||||
|
* SDL_assert_paranoid) instead of a single all-or-nothing option.
|
||||||
|
* - It offers a variety of responses when an assertion fails (retry, trigger
|
||||||
|
* the debugger, abort the program, ignore the failure once, ignore it for
|
||||||
|
* the rest of the program's run).
|
||||||
|
* - It tries to show the user a dialog by default, if possible, but the app
|
||||||
|
* can provide a callback to handle assertion failures however they like.
|
||||||
|
* - It lets failed assertions be retried. Perhaps you had a network failure
|
||||||
|
* and just want to retry the test after plugging your network cable back
|
||||||
|
* in? You can.
|
||||||
|
* - It lets the user ignore an assertion failure, if there's a harmless
|
||||||
|
* problem that one can continue past.
|
||||||
|
* - It lets the user mark an assertion as ignored for the rest of the
|
||||||
|
* program's run; if there's a harmless problem that keeps popping up.
|
||||||
|
* - It provides statistics and data on all failed assertions to the app.
|
||||||
|
* - It allows the default assertion handler to be controlled with environment
|
||||||
|
* variables, in case an automated script needs to control it.
|
||||||
|
* - It can be used as an aid to Clang's static analysis; it will treat SDL
|
||||||
|
* assertions as universally true (under the assumption that you are serious
|
||||||
|
* about the asserted claims and that your debug builds will detect when
|
||||||
|
* these claims were wrong). This can help the analyzer avoid false
|
||||||
|
* positives.
|
||||||
|
*
|
||||||
|
* To use it: compile a debug build and just sprinkle around tests to check
|
||||||
|
* your code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_assert_h_
|
||||||
|
#define SDL_assert_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The level of assertion aggressiveness.
|
||||||
|
*
|
||||||
|
* This value changes depending on compiler options and other preprocessor
|
||||||
|
* defines.
|
||||||
|
*
|
||||||
|
* It is currently one of the following values, but future SDL releases might
|
||||||
|
* add more:
|
||||||
|
*
|
||||||
|
* - 0: All SDL assertion macros are disabled.
|
||||||
|
* - 1: Release settings: SDL_assert disabled, SDL_assert_release enabled.
|
||||||
|
* - 2: Debug settings: SDL_assert and SDL_assert_release enabled.
|
||||||
|
* - 3: Paranoid settings: All SDL assertion macros enabled, including
|
||||||
|
* SDL_assert_paranoid.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_ASSERT_LEVEL SomeNumberBasedOnVariousFactors
|
||||||
|
|
||||||
|
#elif !defined(SDL_ASSERT_LEVEL)
|
||||||
|
#ifdef SDL_DEFAULT_ASSERT_LEVEL
|
||||||
|
#define SDL_ASSERT_LEVEL SDL_DEFAULT_ASSERT_LEVEL
|
||||||
|
#elif defined(_DEBUG) || defined(DEBUG) || \
|
||||||
|
(defined(__GNUC__) && !defined(__OPTIMIZE__))
|
||||||
|
#define SDL_ASSERT_LEVEL 2
|
||||||
|
#else
|
||||||
|
#define SDL_ASSERT_LEVEL 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to tell an attached debugger to pause.
|
||||||
|
*
|
||||||
|
* This allows an app to programmatically halt ("break") the debugger as if it
|
||||||
|
* had hit a breakpoint, allowing the developer to examine program state, etc.
|
||||||
|
*
|
||||||
|
* This is a macro--not a function--so that the debugger breaks on the source
|
||||||
|
* code line that used SDL_TriggerBreakpoint and not in some random guts of
|
||||||
|
* SDL. SDL_assert uses this macro for the same reason.
|
||||||
|
*
|
||||||
|
* If the program is not running under a debugger, SDL_TriggerBreakpoint will
|
||||||
|
* likely terminate the app, possibly without warning. If the current platform
|
||||||
|
* isn't supported, this macro is left undefined.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_TriggerBreakpoint() TriggerABreakpointInAPlatformSpecificManner
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) && _MSC_VER >= 1310
|
||||||
|
/* Don't include intrin.h here because it contains C++ code */
|
||||||
|
extern void __cdecl __debugbreak(void);
|
||||||
|
#define SDL_TriggerBreakpoint() __debugbreak()
|
||||||
|
#elif defined(_MSC_VER) && defined(_M_IX86)
|
||||||
|
#define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
|
||||||
|
#elif defined(ANDROID)
|
||||||
|
#include <assert.h>
|
||||||
|
#define SDL_TriggerBreakpoint() assert(0)
|
||||||
|
#elif SDL_HAS_BUILTIN(__builtin_debugtrap)
|
||||||
|
#define SDL_TriggerBreakpoint() __builtin_debugtrap()
|
||||||
|
#elif SDL_HAS_BUILTIN(__builtin_trap)
|
||||||
|
#define SDL_TriggerBreakpoint() __builtin_trap()
|
||||||
|
#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
|
||||||
|
#elif (defined(__GNUC__) || defined(__clang__)) && defined(__riscv)
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "ebreak\n\t" )
|
||||||
|
#elif ( defined(SDL_PLATFORM_APPLE) && (defined(__arm64__) || defined(__aarch64__)) ) /* this might work on other ARM targets, but this is a known quantity... */
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #22\n\t" )
|
||||||
|
#elif defined(SDL_PLATFORM_APPLE) && defined(__arm__)
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "bkpt #22\n\t" )
|
||||||
|
#elif defined(_WIN32) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__arm64__) || defined(__aarch64__)) )
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #0xF000\n\t" )
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define SDL_TriggerBreakpoint() __builtin_trap() /* older gcc may not support SDL_HAS_BUILTIN(__builtin_trap) above */
|
||||||
|
#elif defined(__386__) && defined(__WATCOMC__)
|
||||||
|
#define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
|
||||||
|
#elif defined(HAVE_SIGNAL_H) && !defined(__WATCOMC__)
|
||||||
|
#include <signal.h>
|
||||||
|
#define SDL_TriggerBreakpoint() raise(SIGTRAP)
|
||||||
|
#else
|
||||||
|
/* SDL_TriggerBreakpoint is intentionally left undefined on unknown platforms. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro that reports the current function being compiled.
|
||||||
|
*
|
||||||
|
* If SDL can't figure how the compiler reports this, it will use "???".
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_FUNCTION __FUNCTION__
|
||||||
|
|
||||||
|
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
|
||||||
|
# define SDL_FUNCTION __func__
|
||||||
|
#elif ((defined(__GNUC__) && (__GNUC__ >= 2)) || defined(_MSC_VER) || defined (__WATCOMC__))
|
||||||
|
# define SDL_FUNCTION __FUNCTION__
|
||||||
|
#else
|
||||||
|
# define SDL_FUNCTION "???"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro that reports the current file being compiled.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_FILE __FILE__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro that reports the current line number of the file being compiled.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_LINE __LINE__
|
||||||
|
|
||||||
|
/*
|
||||||
|
sizeof (x) makes the compiler still parse the expression even without
|
||||||
|
assertions enabled, so the code is always checked at compile time, but
|
||||||
|
doesn't actually generate code for it, so there are no side effects or
|
||||||
|
expensive checks at run time, just the constant size of what x WOULD be,
|
||||||
|
which presumably gets optimized out as unused.
|
||||||
|
This also solves the problem of...
|
||||||
|
|
||||||
|
int somevalue = blah();
|
||||||
|
SDL_assert(somevalue == 1);
|
||||||
|
|
||||||
|
...which would cause compiles to complain that somevalue is unused if we
|
||||||
|
disable assertions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro for wrapping code in `do {} while (0);` without compiler warnings.
|
||||||
|
*
|
||||||
|
* Visual Studio with really aggressive warnings enabled needs this to avoid
|
||||||
|
* compiler complaints.
|
||||||
|
*
|
||||||
|
* the `do {} while (0);` trick is useful for wrapping code in a macro that
|
||||||
|
* may or may not be a single statement, to avoid various C language
|
||||||
|
* accidents.
|
||||||
|
*
|
||||||
|
* To use:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* do { SomethingOnce(); } while (SDL_NULL_WHILE_LOOP_CONDITION (0));
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_NULL_WHILE_LOOP_CONDITION (0)
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) /* Avoid /W4 warnings. */
|
||||||
|
/* "while (0,0)" fools Microsoft's compiler's /W4 warning level into thinking
|
||||||
|
this condition isn't constant. And looks like an owl's face! */
|
||||||
|
#define SDL_NULL_WHILE_LOOP_CONDITION (0,0)
|
||||||
|
#else
|
||||||
|
#define SDL_NULL_WHILE_LOOP_CONDITION (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The macro used when an assertion is disabled.
|
||||||
|
*
|
||||||
|
* This isn't for direct use by apps, but this is the code that is inserted
|
||||||
|
* when an SDL_assert is disabled (perhaps in a release build).
|
||||||
|
*
|
||||||
|
* The code does nothing, but wraps `condition` in a sizeof operator, which
|
||||||
|
* generates no code and has no side effects, but avoid compiler warnings
|
||||||
|
* about unused variables.
|
||||||
|
*
|
||||||
|
* \param condition the condition to assert (but not actually run here).
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_disabled_assert(condition) \
|
||||||
|
do { (void) sizeof ((condition)); } while (SDL_NULL_WHILE_LOOP_CONDITION)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible outcomes from a triggered assertion.
|
||||||
|
*
|
||||||
|
* When an enabled assertion triggers, it may call the assertion handler
|
||||||
|
* (possibly one provided by the app via SDL_SetAssertionHandler), which will
|
||||||
|
* return one of these values, possibly after asking the user.
|
||||||
|
*
|
||||||
|
* Then SDL will respond based on this outcome (loop around to retry the
|
||||||
|
* condition, try to break in a debugger, kill the program, or ignore the
|
||||||
|
* problem).
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_AssertState
|
||||||
|
{
|
||||||
|
SDL_ASSERTION_RETRY, /**< Retry the assert immediately. */
|
||||||
|
SDL_ASSERTION_BREAK, /**< Make the debugger trigger a breakpoint. */
|
||||||
|
SDL_ASSERTION_ABORT, /**< Terminate the program. */
|
||||||
|
SDL_ASSERTION_IGNORE, /**< Ignore the assert. */
|
||||||
|
SDL_ASSERTION_ALWAYS_IGNORE /**< Ignore the assert from now on. */
|
||||||
|
} SDL_AssertState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about an assertion failure.
|
||||||
|
*
|
||||||
|
* This structure is filled in with information about a triggered assertion,
|
||||||
|
* used by the assertion handler, then added to the assertion report. This is
|
||||||
|
* returned as a linked list from SDL_GetAssertionReport().
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AssertData
|
||||||
|
{
|
||||||
|
bool always_ignore; /**< true if app should always continue when assertion is triggered. */
|
||||||
|
unsigned int trigger_count; /**< Number of times this assertion has been triggered. */
|
||||||
|
const char *condition; /**< A string of this assert's test code. */
|
||||||
|
const char *filename; /**< The source file where this assert lives. */
|
||||||
|
int linenum; /**< The line in `filename` where this assert lives. */
|
||||||
|
const char *function; /**< The name of the function where this assert lives. */
|
||||||
|
const struct SDL_AssertData *next; /**< next item in the linked list. */
|
||||||
|
} SDL_AssertData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Never call this directly.
|
||||||
|
*
|
||||||
|
* Use the SDL_assert macros instead.
|
||||||
|
*
|
||||||
|
* \param data assert data structure.
|
||||||
|
* \param func function name.
|
||||||
|
* \param file file name.
|
||||||
|
* \param line line number.
|
||||||
|
* \returns assert state.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *data,
|
||||||
|
const char *func,
|
||||||
|
const char *file, int line) SDL_ANALYZER_NORETURN;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The macro used when an assertion triggers a breakpoint.
|
||||||
|
*
|
||||||
|
* This isn't for direct use by apps; use SDL_assert or SDL_TriggerBreakpoint
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_AssertBreakpoint() SDL_TriggerBreakpoint()
|
||||||
|
|
||||||
|
#elif !defined(SDL_AssertBreakpoint)
|
||||||
|
# if defined(ANDROID) && defined(assert)
|
||||||
|
/* Define this as empty in case assert() is defined as SDL_assert */
|
||||||
|
# define SDL_AssertBreakpoint()
|
||||||
|
# else
|
||||||
|
# define SDL_AssertBreakpoint() SDL_TriggerBreakpoint()
|
||||||
|
# endif
|
||||||
|
#endif /* !SDL_AssertBreakpoint */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The macro used when an assertion is enabled.
|
||||||
|
*
|
||||||
|
* This isn't for direct use by apps, but this is the code that is inserted
|
||||||
|
* when an SDL_assert is enabled.
|
||||||
|
*
|
||||||
|
* The `do {} while(0)` avoids dangling else problems:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* if (x) SDL_assert(y); else blah();
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ... without the do/while, the "else" could attach to this macro's "if". We
|
||||||
|
* try to handle just the minimum we need here in a macro...the loop, the
|
||||||
|
* static vars, and break points. The heavy lifting is handled in
|
||||||
|
* SDL_ReportAssertion().
|
||||||
|
*
|
||||||
|
* \param condition the condition to assert.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_enabled_assert(condition) \
|
||||||
|
do { \
|
||||||
|
while ( !(condition) ) { \
|
||||||
|
static struct SDL_AssertData sdl_assert_data = { false, 0, #condition, NULL, 0, NULL, NULL }; \
|
||||||
|
const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \
|
||||||
|
if (sdl_assert_state == SDL_ASSERTION_RETRY) { \
|
||||||
|
continue; /* go again. */ \
|
||||||
|
} else if (sdl_assert_state == SDL_ASSERTION_BREAK) { \
|
||||||
|
SDL_AssertBreakpoint(); \
|
||||||
|
} \
|
||||||
|
break; /* not retrying. */ \
|
||||||
|
} \
|
||||||
|
} while (SDL_NULL_WHILE_LOOP_CONDITION)
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An assertion test that is normally performed only in debug builds.
|
||||||
|
*
|
||||||
|
* This macro is enabled when the SDL_ASSERT_LEVEL is >= 2, otherwise it is
|
||||||
|
* disabled. This is meant to only do these tests in debug builds, so they can
|
||||||
|
* tend to be more expensive, and they are meant to bring everything to a halt
|
||||||
|
* when they fail, with the programmer there to assess the problem.
|
||||||
|
*
|
||||||
|
* In short: you can sprinkle these around liberally and assume they will
|
||||||
|
* evaporate out of the build when building for end-users.
|
||||||
|
*
|
||||||
|
* When assertions are disabled, this wraps `condition` in a `sizeof`
|
||||||
|
* operator, which means any function calls and side effects will not run, but
|
||||||
|
* the compiler will not complain about any otherwise-unused variables that
|
||||||
|
* are only referenced in the assertion.
|
||||||
|
*
|
||||||
|
* One can set the environment variable "SDL_ASSERT" to one of several strings
|
||||||
|
* ("abort", "break", "retry", "ignore", "always_ignore") to force a default
|
||||||
|
* behavior, which may be desirable for automation purposes. If your platform
|
||||||
|
* requires GUI interfaces to happen on the main thread but you're debugging
|
||||||
|
* an assertion in a background thread, it might be desirable to set this to
|
||||||
|
* "break" so that your debugger takes control as soon as assert is triggered,
|
||||||
|
* instead of risking a bad UI interaction (deadlock, etc) in the application.
|
||||||
|
*
|
||||||
|
* \param condition boolean value to test.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_assert(condition) if (assertion_enabled && (condition)) { trigger_assertion; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An assertion test that is performed even in release builds.
|
||||||
|
*
|
||||||
|
* This macro is enabled when the SDL_ASSERT_LEVEL is >= 1, otherwise it is
|
||||||
|
* disabled. This is meant to be for tests that are cheap to make and
|
||||||
|
* extremely unlikely to fail; generally it is frowned upon to have an
|
||||||
|
* assertion failure in a release build, so these assertions generally need to
|
||||||
|
* be of more than life-and-death importance if there's a chance they might
|
||||||
|
* trigger. You should almost always consider handling these cases more
|
||||||
|
* gracefully than an assert allows.
|
||||||
|
*
|
||||||
|
* When assertions are disabled, this wraps `condition` in a `sizeof`
|
||||||
|
* operator, which means any function calls and side effects will not run, but
|
||||||
|
* the compiler will not complain about any otherwise-unused variables that
|
||||||
|
* are only referenced in the assertion.
|
||||||
|
*
|
||||||
|
* One can set the environment variable "SDL_ASSERT" to one of several strings
|
||||||
|
* ("abort", "break", "retry", "ignore", "always_ignore") to force a default
|
||||||
|
* behavior, which may be desirable for automation purposes. If your platform
|
||||||
|
* requires GUI interfaces to happen on the main thread but you're debugging
|
||||||
|
* an assertion in a background thread, it might be desirable to set this to
|
||||||
|
* "break" so that your debugger takes control as soon as assert is triggered,
|
||||||
|
* instead of risking a bad UI interaction (deadlock, etc) in the application.
|
||||||
|
* *
|
||||||
|
*
|
||||||
|
* \param condition boolean value to test.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_assert_release(condition) SDL_disabled_assert(condition)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An assertion test that is performed only when built with paranoid settings.
|
||||||
|
*
|
||||||
|
* This macro is enabled when the SDL_ASSERT_LEVEL is >= 3, otherwise it is
|
||||||
|
* disabled. This is a higher level than both release and debug, so these
|
||||||
|
* tests are meant to be expensive and only run when specifically looking for
|
||||||
|
* extremely unexpected failure cases in a special build.
|
||||||
|
*
|
||||||
|
* When assertions are disabled, this wraps `condition` in a `sizeof`
|
||||||
|
* operator, which means any function calls and side effects will not run, but
|
||||||
|
* the compiler will not complain about any otherwise-unused variables that
|
||||||
|
* are only referenced in the assertion.
|
||||||
|
*
|
||||||
|
* One can set the environment variable "SDL_ASSERT" to one of several strings
|
||||||
|
* ("abort", "break", "retry", "ignore", "always_ignore") to force a default
|
||||||
|
* behavior, which may be desirable for automation purposes. If your platform
|
||||||
|
* requires GUI interfaces to happen on the main thread but you're debugging
|
||||||
|
* an assertion in a background thread, it might be desirable to set this to
|
||||||
|
* "break" so that your debugger takes control as soon as assert is triggered,
|
||||||
|
* instead of risking a bad UI interaction (deadlock, etc) in the application.
|
||||||
|
*
|
||||||
|
* \param condition boolean value to test.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||||
|
|
||||||
|
/* Enable various levels of assertions. */
|
||||||
|
#elif SDL_ASSERT_LEVEL == 0 /* assertions disabled */
|
||||||
|
# define SDL_assert(condition) SDL_disabled_assert(condition)
|
||||||
|
# define SDL_assert_release(condition) SDL_disabled_assert(condition)
|
||||||
|
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||||
|
#elif SDL_ASSERT_LEVEL == 1 /* release settings. */
|
||||||
|
# define SDL_assert(condition) SDL_disabled_assert(condition)
|
||||||
|
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||||
|
#elif SDL_ASSERT_LEVEL == 2 /* debug settings. */
|
||||||
|
# define SDL_assert(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||||
|
#elif SDL_ASSERT_LEVEL == 3 /* paranoid settings. */
|
||||||
|
# define SDL_assert(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_paranoid(condition) SDL_enabled_assert(condition)
|
||||||
|
#else
|
||||||
|
# error Unknown assertion level.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An assertion test that is always performed.
|
||||||
|
*
|
||||||
|
* This macro is always enabled no matter what SDL_ASSERT_LEVEL is set to. You
|
||||||
|
* almost never want to use this, as it could trigger on an end-user's system,
|
||||||
|
* crashing your program.
|
||||||
|
*
|
||||||
|
* One can set the environment variable "SDL_ASSERT" to one of several strings
|
||||||
|
* ("abort", "break", "retry", "ignore", "always_ignore") to force a default
|
||||||
|
* behavior, which may be desirable for automation purposes. If your platform
|
||||||
|
* requires GUI interfaces to happen on the main thread but you're debugging
|
||||||
|
* an assertion in a background thread, it might be desirable to set this to
|
||||||
|
* "break" so that your debugger takes control as soon as assert is triggered,
|
||||||
|
* instead of risking a bad UI interaction (deadlock, etc) in the application.
|
||||||
|
*
|
||||||
|
* \param condition boolean value to test.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_assert_always(condition) SDL_enabled_assert(condition)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback that fires when an SDL assertion fails.
|
||||||
|
*
|
||||||
|
* \param data a pointer to the SDL_AssertData structure corresponding to the
|
||||||
|
* current assertion.
|
||||||
|
* \param userdata what was passed as `userdata` to SDL_SetAssertionHandler().
|
||||||
|
* \returns an SDL_AssertState value indicating how to handle the failure.
|
||||||
|
*
|
||||||
|
* \threadsafety This callback may be called from any thread that triggers an
|
||||||
|
* assert at any time.
|
||||||
|
*
|
||||||
|
* \since This datatype is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef SDL_AssertState (SDLCALL *SDL_AssertionHandler)(
|
||||||
|
const SDL_AssertData *data, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an application-defined assertion handler.
|
||||||
|
*
|
||||||
|
* This function allows an application to show its own assertion UI and/or
|
||||||
|
* force the response to an assertion failure. If the application doesn't
|
||||||
|
* provide this, SDL will try to do the right thing, popping up a
|
||||||
|
* system-specific GUI dialog, and probably minimizing any fullscreen windows.
|
||||||
|
*
|
||||||
|
* This callback may fire from any thread, but it runs wrapped in a mutex, so
|
||||||
|
* it will only fire from one thread at a time.
|
||||||
|
*
|
||||||
|
* This callback is NOT reset to SDL's internal handler upon SDL_Quit()!
|
||||||
|
*
|
||||||
|
* \param handler the SDL_AssertionHandler function to call when an assertion
|
||||||
|
* fails or NULL for the default handler.
|
||||||
|
* \param userdata a pointer that is passed to `handler`.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAssertionHandler
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_SetAssertionHandler(
|
||||||
|
SDL_AssertionHandler handler,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default assertion handler.
|
||||||
|
*
|
||||||
|
* This returns the function pointer that is called by default when an
|
||||||
|
* assertion is triggered. This is an internal function provided by SDL, that
|
||||||
|
* is used for assertions when SDL_SetAssertionHandler() hasn't been used to
|
||||||
|
* provide a different function.
|
||||||
|
*
|
||||||
|
* \returns the default SDL_AssertionHandler that is called when an assert
|
||||||
|
* triggers.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAssertionHandler
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetDefaultAssertionHandler(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current assertion handler.
|
||||||
|
*
|
||||||
|
* This returns the function pointer that is called when an assertion is
|
||||||
|
* triggered. This is either the value last passed to
|
||||||
|
* SDL_SetAssertionHandler(), or if no application-specified function is set,
|
||||||
|
* is equivalent to calling SDL_GetDefaultAssertionHandler().
|
||||||
|
*
|
||||||
|
* The parameter `puserdata` is a pointer to a void*, which will store the
|
||||||
|
* "userdata" pointer that was passed to SDL_SetAssertionHandler(). This value
|
||||||
|
* will always be NULL for the default handler. If you don't care about this
|
||||||
|
* data, it is safe to pass a NULL pointer to this function to ignore it.
|
||||||
|
*
|
||||||
|
* \param puserdata pointer which is filled with the "userdata" pointer that
|
||||||
|
* was passed to SDL_SetAssertionHandler().
|
||||||
|
* \returns the SDL_AssertionHandler that is called when an assert triggers.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetAssertionHandler
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler(void **puserdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of all assertion failures.
|
||||||
|
*
|
||||||
|
* This function gets all assertions triggered since the last call to
|
||||||
|
* SDL_ResetAssertionReport(), or the start of the program.
|
||||||
|
*
|
||||||
|
* The proper way to examine this data looks something like this:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* const SDL_AssertData *item = SDL_GetAssertionReport();
|
||||||
|
* while (item) {
|
||||||
|
* printf("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\\n",
|
||||||
|
* item->condition, item->function, item->filename,
|
||||||
|
* item->linenum, item->trigger_count,
|
||||||
|
* item->always_ignore ? "yes" : "no");
|
||||||
|
* item = item->next;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* \returns a list of all failed assertions or NULL if the list is empty. This
|
||||||
|
* memory should not be modified or freed by the application. This
|
||||||
|
* pointer remains valid until the next call to SDL_Quit() or
|
||||||
|
* SDL_ResetAssertionReport().
|
||||||
|
*
|
||||||
|
* \threadsafety This function is not thread safe. Other threads calling
|
||||||
|
* SDL_ResetAssertionReport() simultaneously, may render the
|
||||||
|
* returned pointer invalid.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ResetAssertionReport
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC const SDL_AssertData * SDLCALL SDL_GetAssertionReport(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the list of all assertion failures.
|
||||||
|
*
|
||||||
|
* This function will clear the list of all assertions triggered up to that
|
||||||
|
* point. Immediately following this call, SDL_GetAssertionReport will return
|
||||||
|
* no items. In addition, any previously-triggered assertions will be reset to
|
||||||
|
* a trigger_count of zero, and their always_ignore state will be false.
|
||||||
|
*
|
||||||
|
* \threadsafety This function is not thread safe. Other threads triggering an
|
||||||
|
* assertion, or simultaneously calling this function may cause
|
||||||
|
* memory leaks or crashes.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAssertionReport
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_ResetAssertionReport(void);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_assert_h_ */
|
||||||
@@ -0,0 +1,546 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* WIKI CATEGORY: AsyncIO */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryAsyncIO
|
||||||
|
*
|
||||||
|
* SDL offers a way to perform I/O asynchronously. This allows an app to read
|
||||||
|
* or write files without waiting for data to actually transfer; the functions
|
||||||
|
* that request I/O never block while the request is fulfilled.
|
||||||
|
*
|
||||||
|
* Instead, the data moves in the background and the app can check for results
|
||||||
|
* at their leisure.
|
||||||
|
*
|
||||||
|
* This is more complicated than just reading and writing files in a
|
||||||
|
* synchronous way, but it can allow for more efficiency, and never having
|
||||||
|
* framerate drops as the hard drive catches up, etc.
|
||||||
|
*
|
||||||
|
* The general usage pattern for async I/O is:
|
||||||
|
*
|
||||||
|
* - Create one or more SDL_AsyncIOQueue objects.
|
||||||
|
* - Open files with SDL_AsyncIOFromFile.
|
||||||
|
* - Start I/O tasks to the files with SDL_ReadAsyncIO or SDL_WriteAsyncIO,
|
||||||
|
* putting those tasks into one of the queues.
|
||||||
|
* - Later on, use SDL_GetAsyncIOResult on a queue to see if any task is
|
||||||
|
* finished without blocking. Tasks might finish in any order with success
|
||||||
|
* or failure.
|
||||||
|
* - When all your tasks are done, close the file with SDL_CloseAsyncIO. This
|
||||||
|
* also generates a task, since it might flush data to disk!
|
||||||
|
*
|
||||||
|
* This all works, without blocking, in a single thread, but one can also wait
|
||||||
|
* on a queue in a background thread, sleeping until new results have arrived:
|
||||||
|
*
|
||||||
|
* - Call SDL_WaitAsyncIOResult from one or more threads to efficiently block
|
||||||
|
* until new tasks complete.
|
||||||
|
* - When shutting down, call SDL_SignalAsyncIOQueue to unblock any sleeping
|
||||||
|
* threads despite there being no new tasks completed.
|
||||||
|
*
|
||||||
|
* And, of course, to match the synchronous SDL_LoadFile, we offer
|
||||||
|
* SDL_LoadFileAsync as a convenience function. This will handle allocating a
|
||||||
|
* buffer, slurping in the file data, and null-terminating it; you still check
|
||||||
|
* for results later.
|
||||||
|
*
|
||||||
|
* Behind the scenes, SDL will use newer, efficient APIs on platforms that
|
||||||
|
* support them: Linux's io_uring and Windows 11's IoRing, for example. If
|
||||||
|
* those technologies aren't available, SDL will offload the work to a thread
|
||||||
|
* pool that will manage otherwise-synchronous loads without blocking the app.
|
||||||
|
*
|
||||||
|
* ## Best Practices
|
||||||
|
*
|
||||||
|
* Simple non-blocking I/O--for an app that just wants to pick up data
|
||||||
|
* whenever it's ready without losing framerate waiting on disks to spin--can
|
||||||
|
* use whatever pattern works well for the program. In this case, simply call
|
||||||
|
* SDL_ReadAsyncIO, or maybe SDL_LoadFileAsync, as needed. Once a frame, call
|
||||||
|
* SDL_GetAsyncIOResult to check for any completed tasks and deal with the
|
||||||
|
* data as it arrives.
|
||||||
|
*
|
||||||
|
* If two separate pieces of the same program need their own I/O, it is legal
|
||||||
|
* for each to create their own queue. This will prevent either piece from
|
||||||
|
* accidentally consuming the other's completed tasks. Each queue does require
|
||||||
|
* some amount of resources, but it is not an overwhelming cost. Do not make a
|
||||||
|
* queue for each task, however. It is better to put many tasks into a single
|
||||||
|
* queue. They will be reported in order of completion, not in the order they
|
||||||
|
* were submitted, so it doesn't generally matter what order tasks are
|
||||||
|
* started.
|
||||||
|
*
|
||||||
|
* One async I/O queue can be shared by multiple threads, or one thread can
|
||||||
|
* have more than one queue, but the most efficient way--if ruthless
|
||||||
|
* efficiency is the goal--is to have one queue per thread, with multiple
|
||||||
|
* threads working in parallel, and attempt to keep each queue loaded with
|
||||||
|
* tasks that are both started by and consumed by the same thread. On modern
|
||||||
|
* platforms that can use newer interfaces, this can keep data flowing as
|
||||||
|
* efficiently as possible all the way from storage hardware to the app, with
|
||||||
|
* no contention between threads for access to the same queue.
|
||||||
|
*
|
||||||
|
* Written data is not guaranteed to make it to physical media by the time a
|
||||||
|
* closing task is completed, unless SDL_CloseAsyncIO is called with its
|
||||||
|
* `flush` parameter set to true, which is to say that a successful result
|
||||||
|
* here can still result in lost data during an unfortunately-timed power
|
||||||
|
* outage if not flushed. However, flushing will take longer and may be
|
||||||
|
* unnecessary, depending on the app's needs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_asyncio_h_
|
||||||
|
#define SDL_asyncio_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The asynchronous I/O operation structure.
|
||||||
|
*
|
||||||
|
* This operates as an opaque handle. One can then request read or write
|
||||||
|
* operations on it.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AsyncIOFromFile
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AsyncIO SDL_AsyncIO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of asynchronous I/O tasks.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_AsyncIOTaskType
|
||||||
|
{
|
||||||
|
SDL_ASYNCIO_TASK_READ, /**< A read operation. */
|
||||||
|
SDL_ASYNCIO_TASK_WRITE, /**< A write operation. */
|
||||||
|
SDL_ASYNCIO_TASK_CLOSE /**< A close operation. */
|
||||||
|
} SDL_AsyncIOTaskType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible outcomes of an asynchronous I/O task.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_AsyncIOResult
|
||||||
|
{
|
||||||
|
SDL_ASYNCIO_COMPLETE, /**< request was completed without error */
|
||||||
|
SDL_ASYNCIO_FAILURE, /**< request failed for some reason; check SDL_GetError()! */
|
||||||
|
SDL_ASYNCIO_CANCELED /**< request was canceled before completing. */
|
||||||
|
} SDL_AsyncIOResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a completed asynchronous I/O request.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AsyncIOOutcome
|
||||||
|
{
|
||||||
|
SDL_AsyncIO *asyncio; /**< what generated this task. This pointer will be invalid if it was closed! */
|
||||||
|
SDL_AsyncIOTaskType type; /**< What sort of task was this? Read, write, etc? */
|
||||||
|
SDL_AsyncIOResult result; /**< the result of the work (success, failure, cancellation). */
|
||||||
|
void *buffer; /**< buffer where data was read/written. */
|
||||||
|
Uint64 offset; /**< offset in the SDL_AsyncIO where data was read/written. */
|
||||||
|
Uint64 bytes_requested; /**< number of bytes the task was to read/write. */
|
||||||
|
Uint64 bytes_transferred; /**< actual number of bytes that were read/written. */
|
||||||
|
void *userdata; /**< pointer provided by the app when starting the task */
|
||||||
|
} SDL_AsyncIOOutcome;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A queue of completed asynchronous I/O tasks.
|
||||||
|
*
|
||||||
|
* When starting an asynchronous operation, you specify a queue for the new
|
||||||
|
* task. A queue can be asked later if any tasks in it have completed,
|
||||||
|
* allowing an app to manage multiple pending tasks in one place, in whatever
|
||||||
|
* order they complete.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CreateAsyncIOQueue
|
||||||
|
* \sa SDL_ReadAsyncIO
|
||||||
|
* \sa SDL_WriteAsyncIO
|
||||||
|
* \sa SDL_GetAsyncIOResult
|
||||||
|
* \sa SDL_WaitAsyncIOResult
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AsyncIOQueue SDL_AsyncIOQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to create a new SDL_AsyncIO object for reading from
|
||||||
|
* and/or writing to a named file.
|
||||||
|
*
|
||||||
|
* The `mode` string understands the following values:
|
||||||
|
*
|
||||||
|
* - "r": Open a file for reading only. It must exist.
|
||||||
|
* - "w": Open a file for writing only. It will create missing files or
|
||||||
|
* truncate existing ones.
|
||||||
|
* - "r+": Open a file for update both reading and writing. The file must
|
||||||
|
* exist.
|
||||||
|
* - "w+": Create an empty file for both reading and writing. If a file with
|
||||||
|
* the same name already exists its content is erased and the file is
|
||||||
|
* treated as a new empty file.
|
||||||
|
*
|
||||||
|
* There is no "b" mode, as there is only "binary" style I/O, and no "a" mode
|
||||||
|
* for appending, since you specify the position when starting a task.
|
||||||
|
*
|
||||||
|
* This function supports Unicode filenames, but they must be encoded in UTF-8
|
||||||
|
* format, regardless of the underlying operating system.
|
||||||
|
*
|
||||||
|
* This call is _not_ asynchronous; it will open the file before returning,
|
||||||
|
* under the assumption that doing so is generally a fast operation. Future
|
||||||
|
* reads and writes to the opened file will be async, however.
|
||||||
|
*
|
||||||
|
* \param file a UTF-8 string representing the filename to open.
|
||||||
|
* \param mode an ASCII string representing the mode to be used for opening
|
||||||
|
* the file.
|
||||||
|
* \returns a pointer to the SDL_AsyncIO structure that is created or NULL on
|
||||||
|
* failure; call SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CloseAsyncIO
|
||||||
|
* \sa SDL_ReadAsyncIO
|
||||||
|
* \sa SDL_WriteAsyncIO
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AsyncIO * SDLCALL SDL_AsyncIOFromFile(const char *file, const char *mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to get the size of the data stream in an SDL_AsyncIO.
|
||||||
|
*
|
||||||
|
* This call is _not_ asynchronous; it assumes that obtaining this info is a
|
||||||
|
* non-blocking operation in most reasonable cases.
|
||||||
|
*
|
||||||
|
* \param asyncio the SDL_AsyncIO to get the size of the data stream from.
|
||||||
|
* \returns the size of the data stream in the SDL_IOStream on success or a
|
||||||
|
* negative error code on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetAsyncIOSize(SDL_AsyncIO *asyncio);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start an async read.
|
||||||
|
*
|
||||||
|
* This function reads up to `size` bytes from `offset` position in the data
|
||||||
|
* source to the area pointed at by `ptr`. This function may read less bytes
|
||||||
|
* than requested.
|
||||||
|
*
|
||||||
|
* This function returns as quickly as possible; it does not wait for the read
|
||||||
|
* to complete. On a successful return, this work will continue in the
|
||||||
|
* background. If the work begins, even failure is asynchronous: a failing
|
||||||
|
* return value from this function only means the work couldn't start at all.
|
||||||
|
*
|
||||||
|
* `ptr` must remain available until the work is done, and may be accessed by
|
||||||
|
* the system at any time until then. Do not allocate it on the stack, as this
|
||||||
|
* might take longer than the life of the calling function to complete!
|
||||||
|
*
|
||||||
|
* An SDL_AsyncIOQueue must be specified. The newly-created task will be added
|
||||||
|
* to it when it completes its work.
|
||||||
|
*
|
||||||
|
* \param asyncio a pointer to an SDL_AsyncIO structure.
|
||||||
|
* \param ptr a pointer to a buffer to read data into.
|
||||||
|
* \param offset the position to start reading in the data source.
|
||||||
|
* \param size the number of bytes to read from the data source.
|
||||||
|
* \param queue a queue to add the new SDL_AsyncIO to.
|
||||||
|
* \param userdata an app-defined pointer that will be provided with the task
|
||||||
|
* results.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_WriteAsyncIO
|
||||||
|
* \sa SDL_CreateAsyncIOQueue
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_ReadAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start an async write.
|
||||||
|
*
|
||||||
|
* This function writes `size` bytes from `offset` position in the data source
|
||||||
|
* to the area pointed at by `ptr`.
|
||||||
|
*
|
||||||
|
* This function returns as quickly as possible; it does not wait for the
|
||||||
|
* write to complete. On a successful return, this work will continue in the
|
||||||
|
* background. If the work begins, even failure is asynchronous: a failing
|
||||||
|
* return value from this function only means the work couldn't start at all.
|
||||||
|
*
|
||||||
|
* `ptr` must remain available until the work is done, and may be accessed by
|
||||||
|
* the system at any time until then. Do not allocate it on the stack, as this
|
||||||
|
* might take longer than the life of the calling function to complete!
|
||||||
|
*
|
||||||
|
* An SDL_AsyncIOQueue must be specified. The newly-created task will be added
|
||||||
|
* to it when it completes its work.
|
||||||
|
*
|
||||||
|
* \param asyncio a pointer to an SDL_AsyncIO structure.
|
||||||
|
* \param ptr a pointer to a buffer to write data from.
|
||||||
|
* \param offset the position to start writing to the data source.
|
||||||
|
* \param size the number of bytes to write to the data source.
|
||||||
|
* \param queue a queue to add the new SDL_AsyncIO to.
|
||||||
|
* \param userdata an app-defined pointer that will be provided with the task
|
||||||
|
* results.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ReadAsyncIO
|
||||||
|
* \sa SDL_CreateAsyncIOQueue
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_WriteAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close and free any allocated resources for an async I/O object.
|
||||||
|
*
|
||||||
|
* Closing a file is _also_ an asynchronous task! If a write failure were to
|
||||||
|
* happen during the closing process, for example, the task results will
|
||||||
|
* report it as usual.
|
||||||
|
*
|
||||||
|
* Closing a file that has been written to does not guarantee the data has
|
||||||
|
* made it to physical media; it may remain in the operating system's file
|
||||||
|
* cache, for later writing to disk. This means that a successfully-closed
|
||||||
|
* file can be lost if the system crashes or loses power in this small window.
|
||||||
|
* To prevent this, call this function with the `flush` parameter set to true.
|
||||||
|
* This will make the operation take longer, and perhaps increase system load
|
||||||
|
* in general, but a successful result guarantees that the data has made it to
|
||||||
|
* physical storage. Don't use this for temporary files, caches, and
|
||||||
|
* unimportant data, and definitely use it for crucial irreplaceable files,
|
||||||
|
* like game saves.
|
||||||
|
*
|
||||||
|
* This function guarantees that the close will happen after any other pending
|
||||||
|
* tasks to `asyncio`, so it's safe to open a file, start several operations,
|
||||||
|
* close the file immediately, then check for all results later. This function
|
||||||
|
* will not block until the tasks have completed.
|
||||||
|
*
|
||||||
|
* Once this function returns true, `asyncio` is no longer valid, regardless
|
||||||
|
* of any future outcomes. Any completed tasks might still contain this
|
||||||
|
* pointer in their SDL_AsyncIOOutcome data, in case the app was using this
|
||||||
|
* value to track information, but it should not be used again.
|
||||||
|
*
|
||||||
|
* If this function returns false, the close wasn't started at all, and it's
|
||||||
|
* safe to attempt to close again later.
|
||||||
|
*
|
||||||
|
* An SDL_AsyncIOQueue must be specified. The newly-created task will be added
|
||||||
|
* to it when it completes its work.
|
||||||
|
*
|
||||||
|
* \param asyncio a pointer to an SDL_AsyncIO structure to close.
|
||||||
|
* \param flush true if data should sync to disk before the task completes.
|
||||||
|
* \param queue a queue to add the new SDL_AsyncIO to.
|
||||||
|
* \param userdata an app-defined pointer that will be provided with the task
|
||||||
|
* results.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, but two
|
||||||
|
* threads should not attempt to close the same object.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_CloseAsyncIO(SDL_AsyncIO *asyncio, bool flush, SDL_AsyncIOQueue *queue, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a task queue for tracking multiple I/O operations.
|
||||||
|
*
|
||||||
|
* Async I/O operations are assigned to a queue when started. The queue can be
|
||||||
|
* checked for completed tasks thereafter.
|
||||||
|
*
|
||||||
|
* \returns a new task queue object or NULL if there was an error; call
|
||||||
|
* SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_DestroyAsyncIOQueue
|
||||||
|
* \sa SDL_GetAsyncIOResult
|
||||||
|
* \sa SDL_WaitAsyncIOResult
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AsyncIOQueue * SDLCALL SDL_CreateAsyncIOQueue(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a previously-created async I/O task queue.
|
||||||
|
*
|
||||||
|
* If there are still tasks pending for this queue, this call will block until
|
||||||
|
* those tasks are finished. All those tasks will be deallocated. Their
|
||||||
|
* results will be lost to the app.
|
||||||
|
*
|
||||||
|
* Any pending reads from SDL_LoadFileAsync() that are still in this queue
|
||||||
|
* will have their buffers deallocated by this function, to prevent a memory
|
||||||
|
* leak.
|
||||||
|
*
|
||||||
|
* Once this function is called, the queue is no longer valid and should not
|
||||||
|
* be used, including by other threads that might access it while destruction
|
||||||
|
* is blocking on pending tasks.
|
||||||
|
*
|
||||||
|
* Do not destroy a queue that still has threads waiting on it through
|
||||||
|
* SDL_WaitAsyncIOResult(). You can call SDL_SignalAsyncIOQueue() first to
|
||||||
|
* unblock those threads, and take measures (such as SDL_WaitThread()) to make
|
||||||
|
* sure they have finished their wait and won't wait on the queue again.
|
||||||
|
*
|
||||||
|
* \param queue the task queue to destroy.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, so long as
|
||||||
|
* no other thread is waiting on the queue with
|
||||||
|
* SDL_WaitAsyncIOResult.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_DestroyAsyncIOQueue(SDL_AsyncIOQueue *queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query an async I/O task queue for completed tasks.
|
||||||
|
*
|
||||||
|
* If a task assigned to this queue has finished, this will return true and
|
||||||
|
* fill in `outcome` with the details of the task. If no task in the queue has
|
||||||
|
* finished, this function will return false. This function does not block.
|
||||||
|
*
|
||||||
|
* If a task has completed, this function will free its resources and the task
|
||||||
|
* pointer will no longer be valid. The task will be removed from the queue.
|
||||||
|
*
|
||||||
|
* It is safe for multiple threads to call this function on the same queue at
|
||||||
|
* once; a completed task will only go to one of the threads.
|
||||||
|
*
|
||||||
|
* \param queue the async I/O task queue to query.
|
||||||
|
* \param outcome details of a finished task will be written here. May not be
|
||||||
|
* NULL.
|
||||||
|
* \returns true if a task has completed, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_WaitAsyncIOResult
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_GetAsyncIOResult(SDL_AsyncIOQueue *queue, SDL_AsyncIOOutcome *outcome);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block until an async I/O task queue has a completed task.
|
||||||
|
*
|
||||||
|
* This function puts the calling thread to sleep until there a task assigned
|
||||||
|
* to the queue that has finished.
|
||||||
|
*
|
||||||
|
* If a task assigned to the queue has finished, this will return true and
|
||||||
|
* fill in `outcome` with the details of the task. If no task in the queue has
|
||||||
|
* finished, this function will return false.
|
||||||
|
*
|
||||||
|
* If a task has completed, this function will free its resources and the task
|
||||||
|
* pointer will no longer be valid. The task will be removed from the queue.
|
||||||
|
*
|
||||||
|
* It is safe for multiple threads to call this function on the same queue at
|
||||||
|
* once; a completed task will only go to one of the threads.
|
||||||
|
*
|
||||||
|
* Note that by the nature of various platforms, more than one waiting thread
|
||||||
|
* may wake to handle a single task, but only one will obtain it, so
|
||||||
|
* `timeoutMS` is a _maximum_ wait time, and this function may return false
|
||||||
|
* sooner.
|
||||||
|
*
|
||||||
|
* This function may return false if there was a system error, the OS
|
||||||
|
* inadvertently awoke multiple threads, or if SDL_SignalAsyncIOQueue() was
|
||||||
|
* called to wake up all waiting threads without a finished task.
|
||||||
|
*
|
||||||
|
* A timeout can be used to specify a maximum wait time, but rather than
|
||||||
|
* polling, it is possible to have a timeout of -1 to wait forever, and use
|
||||||
|
* SDL_SignalAsyncIOQueue() to wake up the waiting threads later.
|
||||||
|
*
|
||||||
|
* \param queue the async I/O task queue to wait on.
|
||||||
|
* \param outcome details of a finished task will be written here. May not be
|
||||||
|
* NULL.
|
||||||
|
* \param timeoutMS the maximum time to wait, in milliseconds, or -1 to wait
|
||||||
|
* indefinitely.
|
||||||
|
* \returns true if task has completed, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SignalAsyncIOQueue
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_WaitAsyncIOResult(SDL_AsyncIOQueue *queue, SDL_AsyncIOOutcome *outcome, Sint32 timeoutMS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wake up any threads that are blocking in SDL_WaitAsyncIOResult().
|
||||||
|
*
|
||||||
|
* This will unblock any threads that are sleeping in a call to
|
||||||
|
* SDL_WaitAsyncIOResult for the specified queue, and cause them to return
|
||||||
|
* from that function.
|
||||||
|
*
|
||||||
|
* This can be useful when destroying a queue to make sure nothing is touching
|
||||||
|
* it indefinitely. In this case, once this call completes, the caller should
|
||||||
|
* take measures to make sure any previously-blocked threads have returned
|
||||||
|
* from their wait and will not touch the queue again (perhaps by setting a
|
||||||
|
* flag to tell the threads to terminate and then using SDL_WaitThread() to
|
||||||
|
* make sure they've done so).
|
||||||
|
*
|
||||||
|
* \param queue the async I/O task queue to signal.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_WaitAsyncIOResult
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_SignalAsyncIOQueue(SDL_AsyncIOQueue *queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all the data from a file path, asynchronously.
|
||||||
|
*
|
||||||
|
* This function returns as quickly as possible; it does not wait for the read
|
||||||
|
* to complete. On a successful return, this work will continue in the
|
||||||
|
* background. If the work begins, even failure is asynchronous: a failing
|
||||||
|
* return value from this function only means the work couldn't start at all.
|
||||||
|
*
|
||||||
|
* The data is allocated with a zero byte at the end (null terminated) for
|
||||||
|
* convenience. This extra byte is not included in SDL_AsyncIOOutcome's
|
||||||
|
* bytes_transferred value.
|
||||||
|
*
|
||||||
|
* This function will allocate the buffer to contain the file. It must be
|
||||||
|
* deallocated by calling SDL_free() on SDL_AsyncIOOutcome's buffer field
|
||||||
|
* after completion.
|
||||||
|
*
|
||||||
|
* An SDL_AsyncIOQueue must be specified. The newly-created task will be added
|
||||||
|
* to it when it completes its work.
|
||||||
|
*
|
||||||
|
* \param file the path to read all available data from.
|
||||||
|
* \param queue a queue to add the new SDL_AsyncIO to.
|
||||||
|
* \param userdata an app-defined pointer that will be provided with the task
|
||||||
|
* results.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_LoadFile_IO
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, void *userdata);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_asyncio_h_ */
|
||||||
@@ -0,0 +1,664 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryAtomic
|
||||||
|
*
|
||||||
|
* Atomic operations.
|
||||||
|
*
|
||||||
|
* IMPORTANT: If you are not an expert in concurrent lockless programming, you
|
||||||
|
* should not be using any functions in this file. You should be protecting
|
||||||
|
* your data structures with full mutexes instead.
|
||||||
|
*
|
||||||
|
* ***Seriously, here be dragons!***
|
||||||
|
*
|
||||||
|
* You can find out a little more about lockless programming and the subtle
|
||||||
|
* issues that can arise here:
|
||||||
|
* https://learn.microsoft.com/en-us/windows/win32/dxtecharts/lockless-programming
|
||||||
|
*
|
||||||
|
* There's also lots of good information here:
|
||||||
|
*
|
||||||
|
* - https://www.1024cores.net/home/lock-free-algorithms
|
||||||
|
* - https://preshing.com/
|
||||||
|
*
|
||||||
|
* These operations may or may not actually be implemented using processor
|
||||||
|
* specific atomic operations. When possible they are implemented as true
|
||||||
|
* processor specific atomic operations. When that is not possible the are
|
||||||
|
* implemented using locks that *do* use the available atomic operations.
|
||||||
|
*
|
||||||
|
* All of the atomic operations that modify memory are full memory barriers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_atomic_h_
|
||||||
|
#define SDL_atomic_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
#include <SDL3/SDL_platform_defines.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An atomic spinlock.
|
||||||
|
*
|
||||||
|
* The atomic locks are efficient spinlocks using CPU instructions, but are
|
||||||
|
* vulnerable to starvation and can spin forever if a thread holding a lock
|
||||||
|
* has been terminated. For this reason you should minimize the code executed
|
||||||
|
* inside an atomic lock and never do expensive things like API or system
|
||||||
|
* calls while holding them.
|
||||||
|
*
|
||||||
|
* They are also vulnerable to starvation if the thread holding the lock is
|
||||||
|
* lower priority than other threads and doesn't get scheduled. In general you
|
||||||
|
* should use mutexes instead, since they have better performance and
|
||||||
|
* contention behavior.
|
||||||
|
*
|
||||||
|
* The atomic locks are not safe to lock recursively.
|
||||||
|
*
|
||||||
|
* Porting Note: The spin lock functions and type are required and can not be
|
||||||
|
* emulated because they are used in the atomic emulation code.
|
||||||
|
*/
|
||||||
|
typedef int SDL_SpinLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to lock a spin lock by setting it to a non-zero value.
|
||||||
|
*
|
||||||
|
* ***Please note that spinlocks are dangerous if you don't know what you're
|
||||||
|
* doing. Please be careful using any sort of spinlock!***
|
||||||
|
*
|
||||||
|
* \param lock a pointer to a lock variable.
|
||||||
|
* \returns true if the lock succeeded, false if the lock is already held.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_LockSpinlock
|
||||||
|
* \sa SDL_UnlockSpinlock
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_TryLockSpinlock(SDL_SpinLock *lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock a spin lock by setting it to a non-zero value.
|
||||||
|
*
|
||||||
|
* ***Please note that spinlocks are dangerous if you don't know what you're
|
||||||
|
* doing. Please be careful using any sort of spinlock!***
|
||||||
|
*
|
||||||
|
* \param lock a pointer to a lock variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_TryLockSpinlock
|
||||||
|
* \sa SDL_UnlockSpinlock
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_LockSpinlock(SDL_SpinLock *lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlock a spin lock by setting it to 0.
|
||||||
|
*
|
||||||
|
* Always returns immediately.
|
||||||
|
*
|
||||||
|
* ***Please note that spinlocks are dangerous if you don't know what you're
|
||||||
|
* doing. Please be careful using any sort of spinlock!***
|
||||||
|
*
|
||||||
|
* \param lock a pointer to a lock variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_LockSpinlock
|
||||||
|
* \sa SDL_TryLockSpinlock
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_UnlockSpinlock(SDL_SpinLock *lock);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a compiler barrier.
|
||||||
|
*
|
||||||
|
* A compiler barrier prevents the compiler from reordering reads and writes
|
||||||
|
* to globally visible variables across the call.
|
||||||
|
*
|
||||||
|
* This macro only prevents the compiler from reordering reads and writes, it
|
||||||
|
* does not prevent the CPU from reordering reads and writes. However, all of
|
||||||
|
* the atomic operations that modify memory are full memory barriers.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this macro is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_CompilerBarrier() DoCompilerSpecificReadWriteBarrier()
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) && (_MSC_VER > 1200) && !defined(__clang__)
|
||||||
|
void _ReadWriteBarrier(void);
|
||||||
|
#pragma intrinsic(_ReadWriteBarrier)
|
||||||
|
#define SDL_CompilerBarrier() _ReadWriteBarrier()
|
||||||
|
#elif (defined(__GNUC__) && !defined(SDL_PLATFORM_EMSCRIPTEN)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
|
||||||
|
/* This is correct for all CPUs when using GCC or Solaris Studio 12.1+. */
|
||||||
|
#define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory")
|
||||||
|
#elif defined(__WATCOMC__)
|
||||||
|
extern __inline void SDL_CompilerBarrier(void);
|
||||||
|
#pragma aux SDL_CompilerBarrier = "" parm [] modify exact [];
|
||||||
|
#else
|
||||||
|
#define SDL_CompilerBarrier() \
|
||||||
|
{ SDL_SpinLock _tmp = 0; SDL_LockSpinlock(&_tmp); SDL_UnlockSpinlock(&_tmp); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a memory release barrier (function version).
|
||||||
|
*
|
||||||
|
* Please refer to SDL_MemoryBarrierRelease for details. This is a function
|
||||||
|
* version, which might be useful if you need to use this functionality from a
|
||||||
|
* scripting language, etc. Also, some of the macro versions call this
|
||||||
|
* function behind the scenes, where more heavy lifting can happen inside of
|
||||||
|
* SDL. Generally, though, an app written in C/C++/etc should use the macro
|
||||||
|
* version, as it will be more efficient.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this function is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_MemoryBarrierRelease
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_MemoryBarrierReleaseFunction(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a memory acquire barrier (function version).
|
||||||
|
*
|
||||||
|
* Please refer to SDL_MemoryBarrierRelease for details. This is a function
|
||||||
|
* version, which might be useful if you need to use this functionality from a
|
||||||
|
* scripting language, etc. Also, some of the macro versions call this
|
||||||
|
* function behind the scenes, where more heavy lifting can happen inside of
|
||||||
|
* SDL. Generally, though, an app written in C/C++/etc should use the macro
|
||||||
|
* version, as it will be more efficient.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this function is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_MemoryBarrierAcquire
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a memory release barrier (macro version).
|
||||||
|
*
|
||||||
|
* Memory barriers are designed to prevent reads and writes from being
|
||||||
|
* reordered by the compiler and being seen out of order on multi-core CPUs.
|
||||||
|
*
|
||||||
|
* A typical pattern would be for thread A to write some data and a flag, and
|
||||||
|
* for thread B to read the flag and get the data. In this case you would
|
||||||
|
* insert a release barrier between writing the data and the flag,
|
||||||
|
* guaranteeing that the data write completes no later than the flag is
|
||||||
|
* written, and you would insert an acquire barrier between reading the flag
|
||||||
|
* and reading the data, to ensure that all the reads associated with the flag
|
||||||
|
* have completed.
|
||||||
|
*
|
||||||
|
* In this pattern you should always see a release barrier paired with an
|
||||||
|
* acquire barrier and you should gate the data reads/writes with a single
|
||||||
|
* flag variable.
|
||||||
|
*
|
||||||
|
* For more information on these semantics, take a look at the blog post:
|
||||||
|
* http://preshing.com/20120913/acquire-and-release-semantics
|
||||||
|
*
|
||||||
|
* This is the macro version of this functionality; if possible, SDL will use
|
||||||
|
* compiler intrinsics or inline assembly, but some platforms might need to
|
||||||
|
* call the function version of this, SDL_MemoryBarrierReleaseFunction to do
|
||||||
|
* the heavy lifting. Apps that can use the macro should favor it over the
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this macro is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_MemoryBarrierAcquire
|
||||||
|
* \sa SDL_MemoryBarrierReleaseFunction
|
||||||
|
*/
|
||||||
|
#define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a memory acquire barrier (macro version).
|
||||||
|
*
|
||||||
|
* Please see SDL_MemoryBarrierRelease for the details on what memory barriers
|
||||||
|
* are and when to use them.
|
||||||
|
*
|
||||||
|
* This is the macro version of this functionality; if possible, SDL will use
|
||||||
|
* compiler intrinsics or inline assembly, but some platforms might need to
|
||||||
|
* call the function version of this, SDL_MemoryBarrierAcquireFunction, to do
|
||||||
|
* the heavy lifting. Apps that can use the macro should favor it over the
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this macro is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_MemoryBarrierRelease
|
||||||
|
* \sa SDL_MemoryBarrierAcquireFunction
|
||||||
|
*/
|
||||||
|
#define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
|
||||||
|
|
||||||
|
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("lwsync" : : : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("lwsync" : : : "memory")
|
||||||
|
#elif defined(__GNUC__) && defined(__aarch64__)
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||||
|
#elif defined(__GNUC__) && defined(__arm__)
|
||||||
|
#if 0 /* defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID) */
|
||||||
|
/* Information from:
|
||||||
|
https://chromium.googlesource.com/chromium/chromium/+/trunk/base/atomicops_internals_arm_gcc.h#19
|
||||||
|
|
||||||
|
The Linux kernel provides a helper function which provides the right code for a memory barrier,
|
||||||
|
hard-coded at address 0xffff0fa0
|
||||||
|
*/
|
||||||
|
typedef void (*SDL_KernelMemoryBarrierFunc)();
|
||||||
|
#define SDL_MemoryBarrierRelease() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
|
||||||
|
#define SDL_MemoryBarrierAcquire() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
|
||||||
|
#else
|
||||||
|
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||||
|
#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
|
||||||
|
#ifdef __thumb__
|
||||||
|
/* The mcr instruction isn't available in thumb mode, use real functions */
|
||||||
|
#define SDL_MEMORY_BARRIER_USES_FUNCTION
|
||||||
|
#define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
|
||||||
|
#define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
|
||||||
|
#else
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
|
||||||
|
#endif /* __thumb__ */
|
||||||
|
#else
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory")
|
||||||
|
#endif /* SDL_PLATFORM_LINUX || SDL_PLATFORM_ANDROID */
|
||||||
|
#endif /* __GNUC__ && __arm__ */
|
||||||
|
#else
|
||||||
|
#if (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
|
||||||
|
/* This is correct for all CPUs on Solaris when using Solaris Studio 12.1+. */
|
||||||
|
#include <mbarrier.h>
|
||||||
|
#define SDL_MemoryBarrierRelease() __machine_rel_barrier()
|
||||||
|
#define SDL_MemoryBarrierAcquire() __machine_acq_barrier()
|
||||||
|
#else
|
||||||
|
/* This is correct for the x86 and x64 CPUs, and we'll expand this over time. */
|
||||||
|
#define SDL_MemoryBarrierRelease() SDL_CompilerBarrier()
|
||||||
|
#define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier()
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to insert a CPU-specific "pause" instruction into the program.
|
||||||
|
*
|
||||||
|
* This can be useful in busy-wait loops, as it serves as a hint to the CPU as
|
||||||
|
* to the program's intent; some CPUs can use this to do more efficient
|
||||||
|
* processing. On some platforms, this doesn't do anything, so using this
|
||||||
|
* macro might just be a harmless no-op.
|
||||||
|
*
|
||||||
|
* Note that if you are busy-waiting, there are often more-efficient
|
||||||
|
* approaches with other synchronization primitives: mutexes, semaphores,
|
||||||
|
* condition variables, etc.
|
||||||
|
*
|
||||||
|
* \threadsafety This macro is safe to use from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_CPUPauseInstruction() DoACPUPauseInACompilerAndArchitectureSpecificWay
|
||||||
|
|
||||||
|
#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
|
||||||
|
#define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */
|
||||||
|
#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(__aarch64__)
|
||||||
|
#define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory")
|
||||||
|
#elif (defined(__powerpc__) || defined(__powerpc64__))
|
||||||
|
#define SDL_CPUPauseInstruction() __asm__ __volatile__("or 27,27,27");
|
||||||
|
#elif (defined(__riscv) && __riscv_xlen == 64)
|
||||||
|
#define SDL_CPUPauseInstruction() __asm__ __volatile__(".insn i 0x0F, 0, x0, x0, 0x010");
|
||||||
|
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
||||||
|
#define SDL_CPUPauseInstruction() _mm_pause() /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */
|
||||||
|
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
|
||||||
|
#define SDL_CPUPauseInstruction() __yield()
|
||||||
|
#elif defined(__WATCOMC__) && defined(__386__)
|
||||||
|
extern __inline void SDL_CPUPauseInstruction(void);
|
||||||
|
#pragma aux SDL_CPUPauseInstruction = ".686p" ".xmm2" "pause"
|
||||||
|
#else
|
||||||
|
#define SDL_CPUPauseInstruction()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type representing an atomic integer value.
|
||||||
|
*
|
||||||
|
* This can be used to manage a value that is synchronized across multiple
|
||||||
|
* CPUs without a race condition; when an app sets a value with
|
||||||
|
* SDL_SetAtomicInt all other threads, regardless of the CPU it is running on,
|
||||||
|
* will see that value when retrieved with SDL_GetAtomicInt, regardless of CPU
|
||||||
|
* caches, etc.
|
||||||
|
*
|
||||||
|
* This is also useful for atomic compare-and-swap operations: a thread can
|
||||||
|
* change the value as long as its current value matches expectations. When
|
||||||
|
* done in a loop, one can guarantee data consistency across threads without a
|
||||||
|
* lock (but the usual warnings apply: if you don't know what you're doing, or
|
||||||
|
* you don't do it carefully, you can confidently cause any number of
|
||||||
|
* disasters with this, so in most cases, you _should_ use a mutex instead of
|
||||||
|
* this!).
|
||||||
|
*
|
||||||
|
* This is a struct so people don't accidentally use numeric operations on it
|
||||||
|
* directly. You have to use SDL atomic functions.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicInt
|
||||||
|
* \sa SDL_GetAtomicInt
|
||||||
|
* \sa SDL_SetAtomicInt
|
||||||
|
* \sa SDL_AddAtomicInt
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AtomicInt { int value; } SDL_AtomicInt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an atomic variable to a new value if it is currently an old value.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt variable to be modified.
|
||||||
|
* \param oldval the old value.
|
||||||
|
* \param newval the new value.
|
||||||
|
* \returns true if the atomic variable was set, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAtomicInt
|
||||||
|
* \sa SDL_SetAtomicInt
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicInt(SDL_AtomicInt *a, int oldval, int newval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an atomic variable to a value.
|
||||||
|
*
|
||||||
|
* This function also acts as a full memory barrier.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt variable to be modified.
|
||||||
|
* \param v the desired value.
|
||||||
|
* \returns the previous value of the atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAtomicInt
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_SetAtomicInt(SDL_AtomicInt *a, int v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of an atomic variable.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt variable.
|
||||||
|
* \returns the current value of an atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetAtomicInt
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_GetAtomicInt(SDL_AtomicInt *a);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add to an atomic variable.
|
||||||
|
*
|
||||||
|
* This function also acts as a full memory barrier.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt variable to be modified.
|
||||||
|
* \param v the desired value to add.
|
||||||
|
* \returns the previous value of the atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AtomicDecRef
|
||||||
|
* \sa SDL_AtomicIncRef
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_AddAtomicInt(SDL_AtomicInt *a, int v);
|
||||||
|
|
||||||
|
#ifndef SDL_AtomicIncRef
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment an atomic variable used as a reference count.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this macro is for, you shouldn't use it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt to increment.
|
||||||
|
* \returns the previous value of the atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AtomicDecRef
|
||||||
|
*/
|
||||||
|
#define SDL_AtomicIncRef(a) SDL_AddAtomicInt(a, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_AtomicDecRef
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement an atomic variable used as a reference count.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this macro is for, you shouldn't use it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt to decrement.
|
||||||
|
* \returns true if the variable reached zero after decrementing, false
|
||||||
|
* otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AtomicIncRef
|
||||||
|
*/
|
||||||
|
#define SDL_AtomicDecRef(a) (SDL_AddAtomicInt(a, -1) == 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type representing an atomic unsigned 32-bit value.
|
||||||
|
*
|
||||||
|
* This can be used to manage a value that is synchronized across multiple
|
||||||
|
* CPUs without a race condition; when an app sets a value with
|
||||||
|
* SDL_SetAtomicU32 all other threads, regardless of the CPU it is running on,
|
||||||
|
* will see that value when retrieved with SDL_GetAtomicU32, regardless of CPU
|
||||||
|
* caches, etc.
|
||||||
|
*
|
||||||
|
* This is also useful for atomic compare-and-swap operations: a thread can
|
||||||
|
* change the value as long as its current value matches expectations. When
|
||||||
|
* done in a loop, one can guarantee data consistency across threads without a
|
||||||
|
* lock (but the usual warnings apply: if you don't know what you're doing, or
|
||||||
|
* you don't do it carefully, you can confidently cause any number of
|
||||||
|
* disasters with this, so in most cases, you _should_ use a mutex instead of
|
||||||
|
* this!).
|
||||||
|
*
|
||||||
|
* This is a struct so people don't accidentally use numeric operations on it
|
||||||
|
* directly. You have to use SDL atomic functions.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicU32
|
||||||
|
* \sa SDL_GetAtomicU32
|
||||||
|
* \sa SDL_SetAtomicU32
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AtomicU32 { Uint32 value; } SDL_AtomicU32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an atomic variable to a new value if it is currently an old value.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
||||||
|
* \param oldval the old value.
|
||||||
|
* \param newval the new value.
|
||||||
|
* \returns true if the atomic variable was set, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAtomicU32
|
||||||
|
* \sa SDL_SetAtomicU32
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicU32(SDL_AtomicU32 *a, Uint32 oldval, Uint32 newval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an atomic variable to a value.
|
||||||
|
*
|
||||||
|
* This function also acts as a full memory barrier.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
||||||
|
* \param v the desired value.
|
||||||
|
* \returns the previous value of the atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAtomicU32
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC Uint32 SDLCALL SDL_SetAtomicU32(SDL_AtomicU32 *a, Uint32 v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of an atomic variable.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicU32 variable.
|
||||||
|
* \returns the current value of an atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetAtomicU32
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC Uint32 SDLCALL SDL_GetAtomicU32(SDL_AtomicU32 *a);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a pointer to a new value if it is currently an old value.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to a pointer.
|
||||||
|
* \param oldval the old pointer value.
|
||||||
|
* \param newval the new pointer value.
|
||||||
|
* \returns true if the pointer was set, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicInt
|
||||||
|
* \sa SDL_GetAtomicPointer
|
||||||
|
* \sa SDL_SetAtomicPointer
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicPointer(void **a, void *oldval, void *newval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a pointer to a value atomically.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to a pointer.
|
||||||
|
* \param v the desired pointer value.
|
||||||
|
* \returns the previous value of the pointer.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicPointer
|
||||||
|
* \sa SDL_GetAtomicPointer
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void * SDLCALL SDL_SetAtomicPointer(void **a, void *v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of a pointer atomically.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to a pointer.
|
||||||
|
* \returns the current value of a pointer.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicPointer
|
||||||
|
* \sa SDL_SetAtomicPointer
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void * SDLCALL SDL_GetAtomicPointer(void **a);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_atomic_h_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,486 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* WIKI CATEGORY: BeginCode */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryBeginCode
|
||||||
|
*
|
||||||
|
* `SDL_begin_code.h` sets things up for C dynamic library function
|
||||||
|
* definitions, static inlined functions, and structures aligned at 4-byte
|
||||||
|
* alignment. If you don't like ugly C preprocessor code, don't look at this
|
||||||
|
* file. :)
|
||||||
|
*
|
||||||
|
* SDL's headers use this; applications generally should not include this
|
||||||
|
* header directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This shouldn't be nested -- included it around code only. */
|
||||||
|
#ifdef SDL_begin_code_h
|
||||||
|
#error Nested inclusion of SDL_begin_code.h
|
||||||
|
#endif
|
||||||
|
#define SDL_begin_code_h
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a symbol as deprecated.
|
||||||
|
*
|
||||||
|
* A function is marked deprecated by adding this macro to its declaration:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* extern SDL_DEPRECATED int ThisFunctionWasABadIdea(void);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Compilers with deprecation support can give a warning when a deprecated
|
||||||
|
* function is used. This symbol may be used in SDL's headers, but apps are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* SDL, on occasion, might deprecate a function for various reasons. However,
|
||||||
|
* SDL never removes symbols before major versions, so deprecated interfaces
|
||||||
|
* in SDL3 will remain available until SDL4, where it would be expected an app
|
||||||
|
* would have to take steps to migrate anyhow.
|
||||||
|
*
|
||||||
|
* On compilers without a deprecation mechanism, this is defined to nothing,
|
||||||
|
* and using a deprecated function will not generate a warning.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_DEPRECATED __attribute__((deprecated))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a symbol as a public API.
|
||||||
|
*
|
||||||
|
* SDL uses this macro for all its public functions. On some targets, it is
|
||||||
|
* used to signal to the compiler that this function needs to be exported from
|
||||||
|
* a shared library, but it might have other side effects.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_DECLSPEC __attribute__ ((visibility("default")))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to set a function's calling conventions.
|
||||||
|
*
|
||||||
|
* SDL uses this macro for all its public functions, and any callbacks it
|
||||||
|
* defines. This macro guarantees that calling conventions match between SDL
|
||||||
|
* and the app, even if the two were built with different compilers or
|
||||||
|
* optimization settings.
|
||||||
|
*
|
||||||
|
* When writing a callback function, it is very important for it to be
|
||||||
|
* correctly tagged with SDLCALL, as mismatched calling conventions can cause
|
||||||
|
* strange behaviors and can be difficult to diagnose. Plus, on many
|
||||||
|
* platforms, SDLCALL is defined to nothing, so compilers won't be able to
|
||||||
|
* warn that the tag is missing.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDLCALL __cdecl
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to request a function be inlined.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler to inline a function. The compiler is free
|
||||||
|
* to ignore this request. On compilers without inline support, this is
|
||||||
|
* defined to nothing.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_INLINE __inline
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to demand a function be inlined.
|
||||||
|
*
|
||||||
|
* This is a command to the compiler to inline a function. SDL uses this macro
|
||||||
|
* in its public headers for a handful of simple functions. On compilers
|
||||||
|
* without forceinline support, this is defined to `static SDL_INLINE`, which
|
||||||
|
* is often good enough.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_FORCE_INLINE __forceinline
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function as never-returning.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler that a function does not return. An example
|
||||||
|
* of a function like this is the C runtime's exit() function.
|
||||||
|
*
|
||||||
|
* This hint can lead to code optimizations, and help analyzers understand
|
||||||
|
* code flow better. On compilers without noreturn support, this is defined to
|
||||||
|
* nothing.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_NORETURN __attribute__((noreturn))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function as never-returning (for analysis purposes).
|
||||||
|
*
|
||||||
|
* This is almost identical to SDL_NORETURN, except functions marked with this
|
||||||
|
* _can_ actually return. The difference is that this isn't used for code
|
||||||
|
* generation, but rather static analyzers use this information to assume
|
||||||
|
* truths about program state and available code paths. Specifically, this tag
|
||||||
|
* is useful for writing an assertion mechanism. Indeed, SDL_assert uses this
|
||||||
|
* tag behind the scenes. Generally, apps that don't understand the specific
|
||||||
|
* use-case for this tag should avoid using it directly.
|
||||||
|
*
|
||||||
|
* On compilers without analyzer_noreturn support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to signal that a case statement without a `break` is intentional.
|
||||||
|
*
|
||||||
|
* C compilers have gotten more aggressive about warning when a switch's
|
||||||
|
* `case` block does not end with a `break` or other flow control statement,
|
||||||
|
* flowing into the next case's code, as this is a common accident that leads
|
||||||
|
* to strange bugs. But sometimes falling through to the next case is the
|
||||||
|
* correct and desired behavior. This symbol lets an app communicate this
|
||||||
|
* intention to the compiler, so it doesn't generate a warning.
|
||||||
|
*
|
||||||
|
* It is used like this:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* switch (x) {
|
||||||
|
* case 1:
|
||||||
|
* DoSomethingOnlyForOne();
|
||||||
|
* SDL_FALLTHROUGH; // tell the compiler this was intentional.
|
||||||
|
* case 2:
|
||||||
|
* DoSomethingForOneAndTwo();
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_FALLTHROUGH [[fallthrough]]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function's return value as critical.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler that a function's return value should not be
|
||||||
|
* ignored.
|
||||||
|
*
|
||||||
|
* If an NODISCARD function's return value is thrown away (the function is
|
||||||
|
* called as if it returns `void`), the compiler will issue a warning.
|
||||||
|
*
|
||||||
|
* While it's generally good practice to check return values for errors, often
|
||||||
|
* times legitimate programs do not for good reasons. Be careful about what
|
||||||
|
* functions are tagged as NODISCARD. It operates best when used on a function
|
||||||
|
* that's failure is surprising and catastrophic; a good example would be a
|
||||||
|
* program that checks the return values of all its file write function calls
|
||||||
|
* but not the call to close the file, which it assumes incorrectly never
|
||||||
|
* fails.
|
||||||
|
*
|
||||||
|
* Function callers that want to throw away a NODISCARD return value can call
|
||||||
|
* the function with a `(void)` cast, which informs the compiler the act is
|
||||||
|
* intentional.
|
||||||
|
*
|
||||||
|
* On compilers without nodiscard support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_NODISCARD [[nodiscard]]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function as an allocator.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler that a function is an allocator, like
|
||||||
|
* malloc(), with certain rules. A description of how GCC treats this hint is
|
||||||
|
* here:
|
||||||
|
*
|
||||||
|
* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-malloc-function-attribute
|
||||||
|
*
|
||||||
|
* On compilers without allocator tag support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* Most apps don't need to, and should not, use this directly.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_MALLOC __declspec(allocator) __desclspec(restrict)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function as returning a certain allocation.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler that a function allocates and returns a
|
||||||
|
* specific amount of memory based on one of its arguments. For example, the C
|
||||||
|
* runtime's malloc() function could use this macro with an argument of 1
|
||||||
|
* (first argument to malloc is the size of the allocation).
|
||||||
|
*
|
||||||
|
* On compilers without alloc_size support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* Most apps don't need to, and should not, use this directly.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_ALLOC_SIZE(p) __attribute__((alloc_size(p)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a pointer variable, to help with pointer aliasing.
|
||||||
|
*
|
||||||
|
* A good explanation of the restrict keyword is here:
|
||||||
|
*
|
||||||
|
* https://en.wikipedia.org/wiki/Restrict
|
||||||
|
*
|
||||||
|
* On compilers without restrict support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_RESTRICT __restrict__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the compiler supports a given builtin functionality.
|
||||||
|
*
|
||||||
|
* This allows preprocessor checks for things that otherwise might fail to
|
||||||
|
* compile.
|
||||||
|
*
|
||||||
|
* Supported by virtually all clang versions and more-recent GCCs. Use this
|
||||||
|
* instead of checking the clang version if possible.
|
||||||
|
*
|
||||||
|
* On compilers without has_builtin support, this is defined to 0 (always
|
||||||
|
* false).
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_HAS_BUILTIN(x) __has_builtin(x)
|
||||||
|
|
||||||
|
/* end of wiki documentation section. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_HAS_BUILTIN
|
||||||
|
#ifdef __has_builtin
|
||||||
|
#define SDL_HAS_BUILTIN(x) __has_builtin(x)
|
||||||
|
#else
|
||||||
|
#define SDL_HAS_BUILTIN(x) 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_DEPRECATED
|
||||||
|
# if defined(__GNUC__) && (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */
|
||||||
|
# define SDL_DEPRECATED __attribute__((deprecated))
|
||||||
|
# elif defined(_MSC_VER)
|
||||||
|
# define SDL_DEPRECATED __declspec(deprecated)
|
||||||
|
# else
|
||||||
|
# define SDL_DEPRECATED
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_UNUSED
|
||||||
|
# ifdef __GNUC__
|
||||||
|
# define SDL_UNUSED __attribute__((unused))
|
||||||
|
# else
|
||||||
|
# define SDL_UNUSED
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Some compilers use a special export keyword */
|
||||||
|
#ifndef SDL_DECLSPEC
|
||||||
|
# if defined(SDL_PLATFORM_WINDOWS)
|
||||||
|
# ifdef DLL_EXPORT
|
||||||
|
# define SDL_DECLSPEC __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define SDL_DECLSPEC
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# if defined(__GNUC__) && __GNUC__ >= 4
|
||||||
|
# define SDL_DECLSPEC __attribute__ ((visibility("default")))
|
||||||
|
# else
|
||||||
|
# define SDL_DECLSPEC
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* By default SDL uses the C calling convention */
|
||||||
|
#ifndef SDLCALL
|
||||||
|
#if defined(SDL_PLATFORM_WINDOWS) && !defined(__GNUC__)
|
||||||
|
#define SDLCALL __cdecl
|
||||||
|
#else
|
||||||
|
#define SDLCALL
|
||||||
|
#endif
|
||||||
|
#endif /* SDLCALL */
|
||||||
|
|
||||||
|
/* Force structure packing at 4 byte alignment.
|
||||||
|
This is necessary if the header is included in code which has structure
|
||||||
|
packing set to an alternate value, say for loading structures from disk.
|
||||||
|
The packing is reset to the previous value in SDL_close_code.h
|
||||||
|
*/
|
||||||
|
#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__)
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(disable: 4103)
|
||||||
|
#endif
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic ignored "-Wpragma-pack"
|
||||||
|
#endif
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#pragma nopackwarning
|
||||||
|
#endif
|
||||||
|
#ifdef _WIN64
|
||||||
|
/* Use 8-byte alignment on 64-bit architectures, so pointers are aligned */
|
||||||
|
#pragma pack(push,8)
|
||||||
|
#else
|
||||||
|
#pragma pack(push,4)
|
||||||
|
#endif
|
||||||
|
#endif /* Compiler needs structure packing set */
|
||||||
|
|
||||||
|
#ifndef SDL_INLINE
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define SDL_INLINE __inline__
|
||||||
|
#elif defined(_MSC_VER) || defined(__BORLANDC__) || \
|
||||||
|
defined(__DMC__) || defined(__SC__) || \
|
||||||
|
defined(__WATCOMC__) || defined(__LCC__) || \
|
||||||
|
defined(__DECC) || defined(__CC_ARM)
|
||||||
|
#define SDL_INLINE __inline
|
||||||
|
#ifndef __inline__
|
||||||
|
#define __inline__ __inline
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define SDL_INLINE inline
|
||||||
|
#ifndef __inline__
|
||||||
|
#define __inline__ inline
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_INLINE not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_FORCE_INLINE
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define SDL_FORCE_INLINE __forceinline
|
||||||
|
#elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) )
|
||||||
|
#define SDL_FORCE_INLINE __attribute__((always_inline)) static __inline__
|
||||||
|
#else
|
||||||
|
#define SDL_FORCE_INLINE static SDL_INLINE
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_FORCE_INLINE not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_NORETURN
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define SDL_NORETURN __attribute__((noreturn))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SDL_NORETURN __declspec(noreturn)
|
||||||
|
#else
|
||||||
|
#define SDL_NORETURN
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_NORETURN not defined */
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#if __has_feature(attribute_analyzer_noreturn)
|
||||||
|
#define SDL_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_ANALYZER_NORETURN
|
||||||
|
#define SDL_ANALYZER_NORETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Apparently this is needed by several Windows compilers */
|
||||||
|
#ifndef __MACH__
|
||||||
|
#ifndef NULL
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define NULL 0
|
||||||
|
#else
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
#endif /* NULL */
|
||||||
|
#endif /* ! macOS - breaks precompiled headers */
|
||||||
|
|
||||||
|
#ifndef SDL_FALLTHROUGH
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 201703L) || \
|
||||||
|
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L)
|
||||||
|
#define SDL_FALLTHROUGH [[fallthrough]]
|
||||||
|
#else
|
||||||
|
#if defined(__has_attribute) && !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
|
||||||
|
#define SDL_HAS_FALLTHROUGH __has_attribute(__fallthrough__)
|
||||||
|
#else
|
||||||
|
#define SDL_HAS_FALLTHROUGH 0
|
||||||
|
#endif /* __has_attribute */
|
||||||
|
#if SDL_HAS_FALLTHROUGH && \
|
||||||
|
((defined(__GNUC__) && __GNUC__ >= 7) || \
|
||||||
|
(defined(__clang_major__) && __clang_major__ >= 10))
|
||||||
|
#define SDL_FALLTHROUGH __attribute__((__fallthrough__))
|
||||||
|
#else
|
||||||
|
#define SDL_FALLTHROUGH do {} while (0) /* fallthrough */
|
||||||
|
#endif /* SDL_HAS_FALLTHROUGH */
|
||||||
|
#undef SDL_HAS_FALLTHROUGH
|
||||||
|
#endif /* C++17 or C2x */
|
||||||
|
#endif /* SDL_FALLTHROUGH not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_NODISCARD
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 201703L) || \
|
||||||
|
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
|
||||||
|
#define SDL_NODISCARD [[nodiscard]]
|
||||||
|
#elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) )
|
||||||
|
#define SDL_NODISCARD __attribute__((warn_unused_result))
|
||||||
|
#elif defined(_MSC_VER) && (_MSC_VER >= 1700)
|
||||||
|
#define SDL_NODISCARD _Check_return_
|
||||||
|
#else
|
||||||
|
#define SDL_NODISCARD
|
||||||
|
#endif /* C++17 or C23 */
|
||||||
|
#endif /* SDL_NODISCARD not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_MALLOC
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
||||||
|
#define SDL_MALLOC __attribute__((malloc))
|
||||||
|
/** FIXME
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SDL_MALLOC __declspec(allocator) __desclspec(restrict)
|
||||||
|
**/
|
||||||
|
#else
|
||||||
|
#define SDL_MALLOC
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_MALLOC not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_ALLOC_SIZE
|
||||||
|
#if (defined(__clang__) && __clang_major__ >= 4) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||||
|
#define SDL_ALLOC_SIZE(p) __attribute__((alloc_size(p)))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SDL_ALLOC_SIZE(p)
|
||||||
|
#else
|
||||||
|
#define SDL_ALLOC_SIZE(p)
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_ALLOC_SIZE not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_ALLOC_SIZE2
|
||||||
|
#if (defined(__clang__) && __clang_major__ >= 4) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||||
|
#define SDL_ALLOC_SIZE2(p1, p2) __attribute__((alloc_size(p1, p2)))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SDL_ALLOC_SIZE2(p1, p2)
|
||||||
|
#else
|
||||||
|
#define SDL_ALLOC_SIZE2(p1, p2)
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_ALLOC_SIZE2 not defined */
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryBits
|
||||||
|
*
|
||||||
|
* Functions for fiddling with bits and bitmasks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_bits_h_
|
||||||
|
#define SDL_bits_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__WATCOMC__) && defined(__386__)
|
||||||
|
extern __inline int _SDL_bsr_watcom(Uint32);
|
||||||
|
#pragma aux _SDL_bsr_watcom = \
|
||||||
|
"bsr eax, eax" \
|
||||||
|
parm [eax] nomemory \
|
||||||
|
value [eax] \
|
||||||
|
modify exact [eax] nomemory;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of the most significant (set) bit in a 32-bit number.
|
||||||
|
*
|
||||||
|
* Result is undefined when called with 0. This operation can also be stated
|
||||||
|
* as "count leading zeroes" and "log base 2".
|
||||||
|
*
|
||||||
|
* Note that this is a forced-inline function in a header, and not a public
|
||||||
|
* API function available in the SDL library (which is to say, the code is
|
||||||
|
* embedded in the calling program and the linker and dynamic loader will not
|
||||||
|
* be able to find this function inside SDL itself).
|
||||||
|
*
|
||||||
|
* \param x the 32-bit value to examine.
|
||||||
|
* \returns the index of the most significant bit, or -1 if the value is 0.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
SDL_FORCE_INLINE int SDL_MostSignificantBitIndex32(Uint32 x)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
|
||||||
|
/* Count Leading Zeroes builtin in GCC.
|
||||||
|
* http://gcc.gnu.org/onlinedocs/gcc-4.3.4/gcc/Other-Builtins.html
|
||||||
|
*/
|
||||||
|
if (x == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 31 - __builtin_clz(x);
|
||||||
|
#elif defined(__WATCOMC__) && defined(__386__)
|
||||||
|
if (x == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _SDL_bsr_watcom(x);
|
||||||
|
#elif defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
|
unsigned long index;
|
||||||
|
if (_BitScanReverse(&index, x)) {
|
||||||
|
return (int)index;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
/* Based off of Bit Twiddling Hacks by Sean Eron Anderson
|
||||||
|
* <seander@cs.stanford.edu>, released in the public domain.
|
||||||
|
* http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
|
||||||
|
*/
|
||||||
|
const Uint32 b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
|
||||||
|
const int S[] = {1, 2, 4, 8, 16};
|
||||||
|
|
||||||
|
int msbIndex = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (x == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 4; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (x & b[i])
|
||||||
|
{
|
||||||
|
x >>= S[i];
|
||||||
|
msbIndex |= S[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return msbIndex;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a unsigned 32-bit value has exactly one bit set.
|
||||||
|
*
|
||||||
|
* If there are no bits set (`x` is zero), or more than one bit set, this
|
||||||
|
* returns false. If any one bit is exclusively set, this returns true.
|
||||||
|
*
|
||||||
|
* Note that this is a forced-inline function in a header, and not a public
|
||||||
|
* API function available in the SDL library (which is to say, the code is
|
||||||
|
* embedded in the calling program and the linker and dynamic loader will not
|
||||||
|
* be able to find this function inside SDL itself).
|
||||||
|
*
|
||||||
|
* \param x the 32-bit value to examine.
|
||||||
|
* \returns true if exactly one bit is set in `x`, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
SDL_FORCE_INLINE bool SDL_HasExactlyOneBitSet32(Uint32 x)
|
||||||
|
{
|
||||||
|
if (x && !(x & (x - 1))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_bits_h_ */
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryBlendmode
|
||||||
|
*
|
||||||
|
* Blend modes decide how two colors will mix together. There are both
|
||||||
|
* standard modes for basic needs and a means to create custom modes,
|
||||||
|
* dictating what sort of math to do on what color components.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_blendmode_h_
|
||||||
|
#define SDL_blendmode_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of blend modes used in drawing operations.
|
||||||
|
*
|
||||||
|
* These predefined blend modes are supported everywhere.
|
||||||
|
*
|
||||||
|
* Additional values may be obtained from SDL_ComposeCustomBlendMode.
|
||||||
|
*
|
||||||
|
* \since This datatype is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ComposeCustomBlendMode
|
||||||
|
*/
|
||||||
|
typedef Uint32 SDL_BlendMode;
|
||||||
|
|
||||||
|
#define SDL_BLENDMODE_NONE 0x00000000u /**< no blending: dstRGBA = srcRGBA */
|
||||||
|
#define SDL_BLENDMODE_BLEND 0x00000001u /**< alpha blending: dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA)), dstA = srcA + (dstA * (1-srcA)) */
|
||||||
|
#define SDL_BLENDMODE_BLEND_PREMULTIPLIED 0x00000010u /**< pre-multiplied alpha blending: dstRGBA = srcRGBA + (dstRGBA * (1-srcA)) */
|
||||||
|
#define SDL_BLENDMODE_ADD 0x00000002u /**< additive blending: dstRGB = (srcRGB * srcA) + dstRGB, dstA = dstA */
|
||||||
|
#define SDL_BLENDMODE_ADD_PREMULTIPLIED 0x00000020u /**< pre-multiplied additive blending: dstRGB = srcRGB + dstRGB, dstA = dstA */
|
||||||
|
#define SDL_BLENDMODE_MOD 0x00000004u /**< color modulate: dstRGB = srcRGB * dstRGB, dstA = dstA */
|
||||||
|
#define SDL_BLENDMODE_MUL 0x00000008u /**< color multiply: dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA)), dstA = dstA */
|
||||||
|
#define SDL_BLENDMODE_INVALID 0x7FFFFFFFu
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The blend operation used when combining source and destination pixel
|
||||||
|
* components.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_BlendOperation
|
||||||
|
{
|
||||||
|
SDL_BLENDOPERATION_ADD = 0x1, /**< dst + src: supported by all renderers */
|
||||||
|
SDL_BLENDOPERATION_SUBTRACT = 0x2, /**< src - dst : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||||
|
SDL_BLENDOPERATION_REV_SUBTRACT = 0x3, /**< dst - src : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||||
|
SDL_BLENDOPERATION_MINIMUM = 0x4, /**< min(dst, src) : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||||
|
SDL_BLENDOPERATION_MAXIMUM = 0x5 /**< max(dst, src) : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||||
|
} SDL_BlendOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The normalized factor used to multiply pixel components.
|
||||||
|
*
|
||||||
|
* The blend factors are multiplied with the pixels from a drawing operation
|
||||||
|
* (src) and the pixels from the render target (dst) before the blend
|
||||||
|
* operation. The comma-separated factors listed above are always applied in
|
||||||
|
* the component order red, green, blue, and alpha.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_BlendFactor
|
||||||
|
{
|
||||||
|
SDL_BLENDFACTOR_ZERO = 0x1, /**< 0, 0, 0, 0 */
|
||||||
|
SDL_BLENDFACTOR_ONE = 0x2, /**< 1, 1, 1, 1 */
|
||||||
|
SDL_BLENDFACTOR_SRC_COLOR = 0x3, /**< srcR, srcG, srcB, srcA */
|
||||||
|
SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR = 0x4, /**< 1-srcR, 1-srcG, 1-srcB, 1-srcA */
|
||||||
|
SDL_BLENDFACTOR_SRC_ALPHA = 0x5, /**< srcA, srcA, srcA, srcA */
|
||||||
|
SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA = 0x6, /**< 1-srcA, 1-srcA, 1-srcA, 1-srcA */
|
||||||
|
SDL_BLENDFACTOR_DST_COLOR = 0x7, /**< dstR, dstG, dstB, dstA */
|
||||||
|
SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR = 0x8, /**< 1-dstR, 1-dstG, 1-dstB, 1-dstA */
|
||||||
|
SDL_BLENDFACTOR_DST_ALPHA = 0x9, /**< dstA, dstA, dstA, dstA */
|
||||||
|
SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA /**< 1-dstA, 1-dstA, 1-dstA, 1-dstA */
|
||||||
|
} SDL_BlendFactor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose a custom blend mode for renderers.
|
||||||
|
*
|
||||||
|
* The functions SDL_SetRenderDrawBlendMode and SDL_SetTextureBlendMode accept
|
||||||
|
* the SDL_BlendMode returned by this function if the renderer supports it.
|
||||||
|
*
|
||||||
|
* A blend mode controls how the pixels from a drawing operation (source) get
|
||||||
|
* combined with the pixels from the render target (destination). First, the
|
||||||
|
* components of the source and destination pixels get multiplied with their
|
||||||
|
* blend factors. Then, the blend operation takes the two products and
|
||||||
|
* calculates the result that will get stored in the render target.
|
||||||
|
*
|
||||||
|
* Expressed in pseudocode, it would look like this:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* dstRGB = colorOperation(srcRGB * srcColorFactor, dstRGB * dstColorFactor);
|
||||||
|
* dstA = alphaOperation(srcA * srcAlphaFactor, dstA * dstAlphaFactor);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Where the functions `colorOperation(src, dst)` and `alphaOperation(src,
|
||||||
|
* dst)` can return one of the following:
|
||||||
|
*
|
||||||
|
* - `src + dst`
|
||||||
|
* - `src - dst`
|
||||||
|
* - `dst - src`
|
||||||
|
* - `min(src, dst)`
|
||||||
|
* - `max(src, dst)`
|
||||||
|
*
|
||||||
|
* The red, green, and blue components are always multiplied with the first,
|
||||||
|
* second, and third components of the SDL_BlendFactor, respectively. The
|
||||||
|
* fourth component is not used.
|
||||||
|
*
|
||||||
|
* The alpha component is always multiplied with the fourth component of the
|
||||||
|
* SDL_BlendFactor. The other components are not used in the alpha
|
||||||
|
* calculation.
|
||||||
|
*
|
||||||
|
* Support for these blend modes varies for each renderer. To check if a
|
||||||
|
* specific SDL_BlendMode is supported, create a renderer and pass it to
|
||||||
|
* either SDL_SetRenderDrawBlendMode or SDL_SetTextureBlendMode. They will
|
||||||
|
* return with an error if the blend mode is not supported.
|
||||||
|
*
|
||||||
|
* This list describes the support of custom blend modes for each renderer.
|
||||||
|
* All renderers support the four blend modes listed in the SDL_BlendMode
|
||||||
|
* enumeration.
|
||||||
|
*
|
||||||
|
* - **direct3d**: Supports all operations with all factors. However, some
|
||||||
|
* factors produce unexpected results with `SDL_BLENDOPERATION_MINIMUM` and
|
||||||
|
* `SDL_BLENDOPERATION_MAXIMUM`.
|
||||||
|
* - **direct3d11**: Same as Direct3D 9.
|
||||||
|
* - **opengl**: Supports the `SDL_BLENDOPERATION_ADD` operation with all
|
||||||
|
* factors. OpenGL versions 1.1, 1.2, and 1.3 do not work correctly here.
|
||||||
|
* - **opengles2**: Supports the `SDL_BLENDOPERATION_ADD`,
|
||||||
|
* `SDL_BLENDOPERATION_SUBTRACT`, `SDL_BLENDOPERATION_REV_SUBTRACT`
|
||||||
|
* operations with all factors.
|
||||||
|
* - **psp**: No custom blend mode support.
|
||||||
|
* - **software**: No custom blend mode support.
|
||||||
|
*
|
||||||
|
* Some renderers do not provide an alpha component for the default render
|
||||||
|
* target. The `SDL_BLENDFACTOR_DST_ALPHA` and
|
||||||
|
* `SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA` factors do not have an effect in this
|
||||||
|
* case.
|
||||||
|
*
|
||||||
|
* \param srcColorFactor the SDL_BlendFactor applied to the red, green, and
|
||||||
|
* blue components of the source pixels.
|
||||||
|
* \param dstColorFactor the SDL_BlendFactor applied to the red, green, and
|
||||||
|
* blue components of the destination pixels.
|
||||||
|
* \param colorOperation the SDL_BlendOperation used to combine the red,
|
||||||
|
* green, and blue components of the source and
|
||||||
|
* destination pixels.
|
||||||
|
* \param srcAlphaFactor the SDL_BlendFactor applied to the alpha component of
|
||||||
|
* the source pixels.
|
||||||
|
* \param dstAlphaFactor the SDL_BlendFactor applied to the alpha component of
|
||||||
|
* the destination pixels.
|
||||||
|
* \param alphaOperation the SDL_BlendOperation used to combine the alpha
|
||||||
|
* component of the source and destination pixels.
|
||||||
|
* \returns an SDL_BlendMode that represents the chosen factors and
|
||||||
|
* operations.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetRenderDrawBlendMode
|
||||||
|
* \sa SDL_GetRenderDrawBlendMode
|
||||||
|
* \sa SDL_SetTextureBlendMode
|
||||||
|
* \sa SDL_GetTextureBlendMode
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_BlendMode SDLCALL SDL_ComposeCustomBlendMode(SDL_BlendFactor srcColorFactor,
|
||||||
|
SDL_BlendFactor dstColorFactor,
|
||||||
|
SDL_BlendOperation colorOperation,
|
||||||
|
SDL_BlendFactor srcAlphaFactor,
|
||||||
|
SDL_BlendFactor dstAlphaFactor,
|
||||||
|
SDL_BlendOperation alphaOperation);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_blendmode_h_ */
|
||||||
@@ -0,0 +1,519 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryCamera
|
||||||
|
*
|
||||||
|
* Video capture for the SDL library.
|
||||||
|
*
|
||||||
|
* This API lets apps read input from video sources, like webcams. Camera
|
||||||
|
* devices can be enumerated, queried, and opened. Once opened, it will
|
||||||
|
* provide SDL_Surface objects as new frames of video come in. These surfaces
|
||||||
|
* can be uploaded to an SDL_Texture or processed as pixels in memory.
|
||||||
|
*
|
||||||
|
* Several platforms will alert the user if an app tries to access a camera,
|
||||||
|
* and some will present a UI asking the user if your application should be
|
||||||
|
* allowed to obtain images at all, which they can deny. A successfully opened
|
||||||
|
* camera will not provide images until permission is granted. Applications,
|
||||||
|
* after opening a camera device, can see if they were granted access by
|
||||||
|
* either polling with the SDL_GetCameraPermissionState() function, or waiting
|
||||||
|
* for an SDL_EVENT_CAMERA_DEVICE_APPROVED or SDL_EVENT_CAMERA_DEVICE_DENIED
|
||||||
|
* event. Platforms that don't have any user approval process will report
|
||||||
|
* approval immediately.
|
||||||
|
*
|
||||||
|
* Note that SDL cameras only provide video as individual frames; they will
|
||||||
|
* not provide full-motion video encoded in a movie file format, although an
|
||||||
|
* app is free to encode the acquired frames into any format it likes. It also
|
||||||
|
* does not provide audio from the camera hardware through this API; not only
|
||||||
|
* do many webcams not have microphones at all, many people--from streamers to
|
||||||
|
* people on Zoom calls--will want to use a separate microphone regardless of
|
||||||
|
* the camera. In any case, recorded audio will be available through SDL's
|
||||||
|
* audio API no matter what hardware provides the microphone.
|
||||||
|
*
|
||||||
|
* ## Camera gotchas
|
||||||
|
*
|
||||||
|
* Consumer-level camera hardware tends to take a little while to warm up,
|
||||||
|
* once the device has been opened. Generally most camera apps have some sort
|
||||||
|
* of UI to take a picture (a button to snap a pic while a preview is showing,
|
||||||
|
* some sort of multi-second countdown for the user to pose, like a photo
|
||||||
|
* booth), which puts control in the users' hands, or they are intended to
|
||||||
|
* stay on for long times (Pokemon Go, etc).
|
||||||
|
*
|
||||||
|
* It's not uncommon that a newly-opened camera will provide a couple of
|
||||||
|
* completely black frames, maybe followed by some under-exposed images. If
|
||||||
|
* taking a single frame automatically, or recording video from a camera's
|
||||||
|
* input without the user initiating it from a preview, it could be wise to
|
||||||
|
* drop the first several frames (if not the first several _seconds_ worth of
|
||||||
|
* frames!) before using images from a camera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_camera_h_
|
||||||
|
#define SDL_camera_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
#include <SDL3/SDL_error.h>
|
||||||
|
#include <SDL3/SDL_pixels.h>
|
||||||
|
#include <SDL3/SDL_properties.h>
|
||||||
|
#include <SDL3/SDL_surface.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a unique ID for a camera device for the time it is connected to the
|
||||||
|
* system, and is never reused for the lifetime of the application.
|
||||||
|
*
|
||||||
|
* If the device is disconnected and reconnected, it will get a new ID.
|
||||||
|
*
|
||||||
|
* The value 0 is an invalid ID.
|
||||||
|
*
|
||||||
|
* \since This datatype is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
*/
|
||||||
|
typedef Uint32 SDL_CameraID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The opaque structure used to identify an opened SDL camera.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef struct SDL_Camera SDL_Camera;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The details of an output format for a camera device.
|
||||||
|
*
|
||||||
|
* Cameras often support multiple formats; each one will be encapsulated in
|
||||||
|
* this struct.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameraSupportedFormats
|
||||||
|
* \sa SDL_GetCameraFormat
|
||||||
|
*/
|
||||||
|
typedef struct SDL_CameraSpec
|
||||||
|
{
|
||||||
|
SDL_PixelFormat format; /**< Frame format */
|
||||||
|
SDL_Colorspace colorspace; /**< Frame colorspace */
|
||||||
|
int width; /**< Frame width */
|
||||||
|
int height; /**< Frame height */
|
||||||
|
int framerate_numerator; /**< Frame rate numerator ((num / denom) == FPS, (denom / num) == duration in seconds) */
|
||||||
|
int framerate_denominator; /**< Frame rate demoninator ((num / denom) == FPS, (denom / num) == duration in seconds) */
|
||||||
|
} SDL_CameraSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position of camera in relation to system device.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameraPosition
|
||||||
|
*/
|
||||||
|
typedef enum SDL_CameraPosition
|
||||||
|
{
|
||||||
|
SDL_CAMERA_POSITION_UNKNOWN,
|
||||||
|
SDL_CAMERA_POSITION_FRONT_FACING,
|
||||||
|
SDL_CAMERA_POSITION_BACK_FACING
|
||||||
|
} SDL_CameraPosition;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to get the number of built-in camera drivers.
|
||||||
|
*
|
||||||
|
* This function returns a hardcoded number. This never returns a negative
|
||||||
|
* value; if there are no drivers compiled into this build of SDL, this
|
||||||
|
* function returns zero. The presence of a driver in this list does not mean
|
||||||
|
* it will function, it just means SDL is capable of interacting with that
|
||||||
|
* interface. For example, a build of SDL might have v4l2 support, but if
|
||||||
|
* there's no kernel support available, SDL's v4l2 driver would fail if used.
|
||||||
|
*
|
||||||
|
* By default, SDL tries all drivers, in its preferred order, until one is
|
||||||
|
* found to be usable.
|
||||||
|
*
|
||||||
|
* \returns the number of built-in camera drivers.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameraDriver
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_GetNumCameraDrivers(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to get the name of a built in camera driver.
|
||||||
|
*
|
||||||
|
* The list of camera drivers is given in the order that they are normally
|
||||||
|
* initialized by default; the drivers that seem more reasonable to choose
|
||||||
|
* first (as far as the SDL developers believe) are earlier in the list.
|
||||||
|
*
|
||||||
|
* The names of drivers are all simple, low-ASCII identifiers, like "v4l2",
|
||||||
|
* "coremedia" or "android". These never have Unicode characters, and are not
|
||||||
|
* meant to be proper names.
|
||||||
|
*
|
||||||
|
* \param index the index of the camera driver; the value ranges from 0 to
|
||||||
|
* SDL_GetNumCameraDrivers() - 1.
|
||||||
|
* \returns the name of the camera driver at the requested index, or NULL if
|
||||||
|
* an invalid index was specified.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetNumCameraDrivers
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCameraDriver(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the current camera driver.
|
||||||
|
*
|
||||||
|
* The names of drivers are all simple, low-ASCII identifiers, like "v4l2",
|
||||||
|
* "coremedia" or "android". These never have Unicode characters, and are not
|
||||||
|
* meant to be proper names.
|
||||||
|
*
|
||||||
|
* \returns the name of the current camera driver or NULL if no driver has
|
||||||
|
* been initialized.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCurrentCameraDriver(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of currently connected camera devices.
|
||||||
|
*
|
||||||
|
* \param count a pointer filled in with the number of cameras returned, may
|
||||||
|
* be NULL.
|
||||||
|
* \returns a 0 terminated array of camera instance IDs or NULL on failure;
|
||||||
|
* call SDL_GetError() for more information. This should be freed
|
||||||
|
* with SDL_free() when it is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_CameraID * SDLCALL SDL_GetCameras(int *count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of native formats/sizes a camera supports.
|
||||||
|
*
|
||||||
|
* This returns a list of all formats and frame sizes that a specific camera
|
||||||
|
* can offer. This is useful if your app can accept a variety of image formats
|
||||||
|
* and sizes and so want to find the optimal spec that doesn't require
|
||||||
|
* conversion.
|
||||||
|
*
|
||||||
|
* This function isn't strictly required; if you call SDL_OpenCamera with a
|
||||||
|
* NULL spec, SDL will choose a native format for you, and if you instead
|
||||||
|
* specify a desired format, it will transparently convert to the requested
|
||||||
|
* format on your behalf.
|
||||||
|
*
|
||||||
|
* If `count` is not NULL, it will be filled with the number of elements in
|
||||||
|
* the returned array.
|
||||||
|
*
|
||||||
|
* Note that it's legal for a camera to supply an empty list. This is what
|
||||||
|
* will happen on Emscripten builds, since that platform won't tell _anything_
|
||||||
|
* about available cameras until you've opened one, and won't even tell if
|
||||||
|
* there _is_ a camera until the user has given you permission to check
|
||||||
|
* through a scary warning popup.
|
||||||
|
*
|
||||||
|
* \param instance_id the camera device instance ID.
|
||||||
|
* \param count a pointer filled in with the number of elements in the list,
|
||||||
|
* may be NULL.
|
||||||
|
* \returns a NULL terminated array of pointers to SDL_CameraSpec or NULL on
|
||||||
|
* failure; call SDL_GetError() for more information. This is a
|
||||||
|
* single allocation that should be freed with SDL_free() when it is
|
||||||
|
* no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_CameraSpec ** SDLCALL SDL_GetCameraSupportedFormats(SDL_CameraID instance_id, int *count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the human-readable device name for a camera.
|
||||||
|
*
|
||||||
|
* \param instance_id the camera device instance ID.
|
||||||
|
* \returns a human-readable device name or NULL on failure; call
|
||||||
|
* SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCameraName(SDL_CameraID instance_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the camera in relation to the system.
|
||||||
|
*
|
||||||
|
* Most platforms will report UNKNOWN, but mobile devices, like phones, can
|
||||||
|
* often make a distinction between cameras on the front of the device (that
|
||||||
|
* points towards the user, for taking "selfies") and cameras on the back (for
|
||||||
|
* filming in the direction the user is facing).
|
||||||
|
*
|
||||||
|
* \param instance_id the camera device instance ID.
|
||||||
|
* \returns the position of the camera on the system hardware.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_CameraPosition SDLCALL SDL_GetCameraPosition(SDL_CameraID instance_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a video recording device (a "camera").
|
||||||
|
*
|
||||||
|
* You can open the device with any reasonable spec, and if the hardware can't
|
||||||
|
* directly support it, it will convert data seamlessly to the requested
|
||||||
|
* format. This might incur overhead, including scaling of image data.
|
||||||
|
*
|
||||||
|
* If you would rather accept whatever format the device offers, you can pass
|
||||||
|
* a NULL spec here and it will choose one for you (and you can use
|
||||||
|
* SDL_Surface's conversion/scaling functions directly if necessary).
|
||||||
|
*
|
||||||
|
* You can call SDL_GetCameraFormat() to get the actual data format if passing
|
||||||
|
* a NULL spec here. You can see the exact specs a device can support without
|
||||||
|
* conversion with SDL_GetCameraSupportedFormats().
|
||||||
|
*
|
||||||
|
* SDL will not attempt to emulate framerate; it will try to set the hardware
|
||||||
|
* to the rate closest to the requested speed, but it won't attempt to limit
|
||||||
|
* or duplicate frames artificially; call SDL_GetCameraFormat() to see the
|
||||||
|
* actual framerate of the opened the device, and check your timestamps if
|
||||||
|
* this is crucial to your app!
|
||||||
|
*
|
||||||
|
* Note that the camera is not usable until the user approves its use! On some
|
||||||
|
* platforms, the operating system will prompt the user to permit access to
|
||||||
|
* the camera, and they can choose Yes or No at that point. Until they do, the
|
||||||
|
* camera will not be usable. The app should either wait for an
|
||||||
|
* SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event,
|
||||||
|
* or poll SDL_GetCameraPermissionState() occasionally until it returns
|
||||||
|
* non-zero. On platforms that don't require explicit user approval (and
|
||||||
|
* perhaps in places where the user previously permitted access), the approval
|
||||||
|
* event might come immediately, but it might come seconds, minutes, or hours
|
||||||
|
* later!
|
||||||
|
*
|
||||||
|
* \param instance_id the camera device instance ID.
|
||||||
|
* \param spec the desired format for data the device will provide. Can be
|
||||||
|
* NULL.
|
||||||
|
* \returns an SDL_Camera object or NULL on failure; call SDL_GetError() for
|
||||||
|
* more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
* \sa SDL_GetCameraFormat
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_Camera * SDLCALL SDL_OpenCamera(SDL_CameraID instance_id, const SDL_CameraSpec *spec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query if camera access has been approved by the user.
|
||||||
|
*
|
||||||
|
* Cameras will not function between when the device is opened by the app and
|
||||||
|
* when the user permits access to the hardware. On some platforms, this
|
||||||
|
* presents as a popup dialog where the user has to explicitly approve access;
|
||||||
|
* on others the approval might be implicit and not alert the user at all.
|
||||||
|
*
|
||||||
|
* This function can be used to check the status of that approval. It will
|
||||||
|
* return 0 if still waiting for user response, 1 if the camera is approved
|
||||||
|
* for use, and -1 if the user denied access.
|
||||||
|
*
|
||||||
|
* Instead of polling with this function, you can wait for a
|
||||||
|
* SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event
|
||||||
|
* in the standard SDL event loop, which is guaranteed to be sent once when
|
||||||
|
* permission to use the camera is decided.
|
||||||
|
*
|
||||||
|
* If a camera is declined, there's nothing to be done but call
|
||||||
|
* SDL_CloseCamera() to dispose of it.
|
||||||
|
*
|
||||||
|
* \param camera the opened camera device to query.
|
||||||
|
* \returns -1 if user denied access to the camera, 1 if user approved access,
|
||||||
|
* 0 if no decision has been made yet.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
* \sa SDL_CloseCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_GetCameraPermissionState(SDL_Camera *camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the instance ID of an opened camera.
|
||||||
|
*
|
||||||
|
* \param camera an SDL_Camera to query.
|
||||||
|
* \returns the instance ID of the specified camera on success or 0 on
|
||||||
|
* failure; call SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_CameraID SDLCALL SDL_GetCameraID(SDL_Camera *camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the properties associated with an opened camera.
|
||||||
|
*
|
||||||
|
* \param camera the SDL_Camera obtained from SDL_OpenCamera().
|
||||||
|
* \returns a valid property ID on success or 0 on failure; call
|
||||||
|
* SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetCameraProperties(SDL_Camera *camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the spec that a camera is using when generating images.
|
||||||
|
*
|
||||||
|
* Note that this might not be the native format of the hardware, as SDL might
|
||||||
|
* be converting to this format behind the scenes.
|
||||||
|
*
|
||||||
|
* If the system is waiting for the user to approve access to the camera, as
|
||||||
|
* some platforms require, this will return false, but this isn't necessarily
|
||||||
|
* a fatal error; you should either wait for an
|
||||||
|
* SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event,
|
||||||
|
* or poll SDL_GetCameraPermissionState() occasionally until it returns
|
||||||
|
* non-zero.
|
||||||
|
*
|
||||||
|
* \param camera opened camera device.
|
||||||
|
* \param spec the SDL_CameraSpec to be initialized by this function.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_GetCameraFormat(SDL_Camera *camera, SDL_CameraSpec *spec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a frame.
|
||||||
|
*
|
||||||
|
* The frame is a memory pointer to the image data, whose size and format are
|
||||||
|
* given by the spec requested when opening the device.
|
||||||
|
*
|
||||||
|
* This is a non blocking API. If there is a frame available, a non-NULL
|
||||||
|
* surface is returned, and timestampNS will be filled with a non-zero value.
|
||||||
|
*
|
||||||
|
* Note that an error case can also return NULL, but a NULL by itself is
|
||||||
|
* normal and just signifies that a new frame is not yet available. Note that
|
||||||
|
* even if a camera device fails outright (a USB camera is unplugged while in
|
||||||
|
* use, etc), SDL will send an event separately to notify the app, but
|
||||||
|
* continue to provide blank frames at ongoing intervals until
|
||||||
|
* SDL_CloseCamera() is called, so real failure here is almost always an out
|
||||||
|
* of memory condition.
|
||||||
|
*
|
||||||
|
* After use, the frame should be released with SDL_ReleaseCameraFrame(). If
|
||||||
|
* you don't do this, the system may stop providing more video!
|
||||||
|
*
|
||||||
|
* Do not call SDL_DestroySurface() on the returned surface! It must be given
|
||||||
|
* back to the camera subsystem with SDL_ReleaseCameraFrame!
|
||||||
|
*
|
||||||
|
* If the system is waiting for the user to approve access to the camera, as
|
||||||
|
* some platforms require, this will return NULL (no frames available); you
|
||||||
|
* should either wait for an SDL_EVENT_CAMERA_DEVICE_APPROVED (or
|
||||||
|
* SDL_EVENT_CAMERA_DEVICE_DENIED) event, or poll
|
||||||
|
* SDL_GetCameraPermissionState() occasionally until it returns non-zero.
|
||||||
|
*
|
||||||
|
* \param camera opened camera device.
|
||||||
|
* \param timestampNS a pointer filled in with the frame's timestamp, or 0 on
|
||||||
|
* error. Can be NULL.
|
||||||
|
* \returns a new frame of video on success, NULL if none is currently
|
||||||
|
* available.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ReleaseCameraFrame
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_AcquireCameraFrame(SDL_Camera *camera, Uint64 *timestampNS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release a frame of video acquired from a camera.
|
||||||
|
*
|
||||||
|
* Let the back-end re-use the internal buffer for camera.
|
||||||
|
*
|
||||||
|
* This function _must_ be called only on surface objects returned by
|
||||||
|
* SDL_AcquireCameraFrame(). This function should be called as quickly as
|
||||||
|
* possible after acquisition, as SDL keeps a small FIFO queue of surfaces for
|
||||||
|
* video frames; if surfaces aren't released in a timely manner, SDL may drop
|
||||||
|
* upcoming video frames from the camera.
|
||||||
|
*
|
||||||
|
* If the app needs to keep the surface for a significant time, they should
|
||||||
|
* make a copy of it and release the original.
|
||||||
|
*
|
||||||
|
* The app should not use the surface again after calling this function;
|
||||||
|
* assume the surface is freed and the pointer is invalid.
|
||||||
|
*
|
||||||
|
* \param camera opened camera device.
|
||||||
|
* \param frame the video frame surface to release.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AcquireCameraFrame
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_ReleaseCameraFrame(SDL_Camera *camera, SDL_Surface *frame);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to shut down camera processing and close the camera
|
||||||
|
* device.
|
||||||
|
*
|
||||||
|
* \param camera opened camera device.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, but no
|
||||||
|
* thread may reference `device` once this function is called.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_CloseCamera(SDL_Camera *camera);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_camera_h_ */
|
||||||
@@ -0,0 +1,331 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryClipboard
|
||||||
|
*
|
||||||
|
* SDL provides access to the system clipboard, both for reading information
|
||||||
|
* from other processes and publishing information of its own.
|
||||||
|
*
|
||||||
|
* This is not just text! SDL apps can access and publish data by mimetype.
|
||||||
|
*
|
||||||
|
* ## Basic use (text)
|
||||||
|
*
|
||||||
|
* Obtaining and publishing simple text to the system clipboard is as easy as
|
||||||
|
* calling SDL_GetClipboardText() and SDL_SetClipboardText(), respectively.
|
||||||
|
* These deal with C strings in UTF-8 encoding. Data transmission and encoding
|
||||||
|
* conversion is completely managed by SDL.
|
||||||
|
*
|
||||||
|
* ## Clipboard callbacks (data other than text)
|
||||||
|
*
|
||||||
|
* Things get more complicated when the clipboard contains something other
|
||||||
|
* than text. Not only can the system clipboard contain data of any type, in
|
||||||
|
* some cases it can contain the same data in different formats! For example,
|
||||||
|
* an image painting app might let the user copy a graphic to the clipboard,
|
||||||
|
* and offers it in .BMP, .JPG, or .PNG format for other apps to consume.
|
||||||
|
*
|
||||||
|
* Obtaining clipboard data ("pasting") like this is a matter of calling
|
||||||
|
* SDL_GetClipboardData() and telling it the mimetype of the data you want.
|
||||||
|
* But how does one know if that format is available? SDL_HasClipboardData()
|
||||||
|
* can report if a specific mimetype is offered, and
|
||||||
|
* SDL_GetClipboardMimeTypes() can provide the entire list of mimetypes
|
||||||
|
* available, so the app can decide what to do with the data and what formats
|
||||||
|
* it can support.
|
||||||
|
*
|
||||||
|
* Setting the clipboard ("copying") to arbitrary data is done with
|
||||||
|
* SDL_SetClipboardData. The app does not provide the data in this call, but
|
||||||
|
* rather the mimetypes it is willing to provide and a callback function.
|
||||||
|
* During the callback, the app will generate the data. This allows massive
|
||||||
|
* data sets to be provided to the clipboard, without any data being copied
|
||||||
|
* before it is explicitly requested. More specifically, it allows an app to
|
||||||
|
* offer data in multiple formats without providing a copy of all of them
|
||||||
|
* upfront. If the app has an image that it could provide in PNG or JPG
|
||||||
|
* format, it doesn't have to encode it to either of those unless and until
|
||||||
|
* something tries to paste it.
|
||||||
|
*
|
||||||
|
* ## Primary Selection
|
||||||
|
*
|
||||||
|
* The X11 and Wayland video targets have a concept of the "primary selection"
|
||||||
|
* in addition to the usual clipboard. This is generally highlighted (but not
|
||||||
|
* explicitly copied) text from various apps. SDL offers APIs for this through
|
||||||
|
* SDL_GetPrimarySelectionText() and SDL_SetPrimarySelectionText(). SDL offers
|
||||||
|
* these APIs on platforms without this concept, too, but only so far that it
|
||||||
|
* will keep a copy of a string that the app sets for later retrieval; the
|
||||||
|
* operating system will not ever attempt to change the string externally if
|
||||||
|
* it doesn't support a primary selection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_clipboard_h_
|
||||||
|
#define SDL_clipboard_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
#include <SDL3/SDL_error.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Function prototypes */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put UTF-8 text into the clipboard.
|
||||||
|
*
|
||||||
|
* \param text the text to store in the clipboard.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetClipboardText
|
||||||
|
* \sa SDL_HasClipboardText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardText(const char *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get UTF-8 text from the clipboard.
|
||||||
|
*
|
||||||
|
* This function returns an empty string if there is not enough memory left
|
||||||
|
* for a copy of the clipboard's content.
|
||||||
|
*
|
||||||
|
* \returns the clipboard text on success or an empty string on failure; call
|
||||||
|
* SDL_GetError() for more information. This should be freed with
|
||||||
|
* SDL_free() when it is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasClipboardText
|
||||||
|
* \sa SDL_SetClipboardText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC char * SDLCALL SDL_GetClipboardText(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query whether the clipboard exists and contains a non-empty text string.
|
||||||
|
*
|
||||||
|
* \returns true if the clipboard has text, or false if it does not.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetClipboardText
|
||||||
|
* \sa SDL_SetClipboardText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasClipboardText(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put UTF-8 text into the primary selection.
|
||||||
|
*
|
||||||
|
* \param text the text to store in the primary selection.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetPrimarySelectionText
|
||||||
|
* \sa SDL_HasPrimarySelectionText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_SetPrimarySelectionText(const char *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get UTF-8 text from the primary selection.
|
||||||
|
*
|
||||||
|
* This function returns an empty string if there is not enough memory left
|
||||||
|
* for a copy of the primary selection's content.
|
||||||
|
*
|
||||||
|
* \returns the primary selection text on success or an empty string on
|
||||||
|
* failure; call SDL_GetError() for more information. This should be
|
||||||
|
* freed with SDL_free() when it is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasPrimarySelectionText
|
||||||
|
* \sa SDL_SetPrimarySelectionText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC char * SDLCALL SDL_GetPrimarySelectionText(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query whether the primary selection exists and contains a non-empty text
|
||||||
|
* string.
|
||||||
|
*
|
||||||
|
* \returns true if the primary selection has text, or false if it does not.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetPrimarySelectionText
|
||||||
|
* \sa SDL_SetPrimarySelectionText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasPrimarySelectionText(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function that will be called when data for the specified mime-type
|
||||||
|
* is requested by the OS.
|
||||||
|
*
|
||||||
|
* The callback function is called with NULL as the mime_type when the
|
||||||
|
* clipboard is cleared or new data is set. The clipboard is automatically
|
||||||
|
* cleared in SDL_Quit().
|
||||||
|
*
|
||||||
|
* \param userdata a pointer to the provided user data.
|
||||||
|
* \param mime_type the requested mime-type.
|
||||||
|
* \param size a pointer filled in with the length of the returned data.
|
||||||
|
* \returns a pointer to the data for the provided mime-type. Returning NULL
|
||||||
|
* or setting the length to 0 will cause no data to be sent to the
|
||||||
|
* "receiver". It is up to the receiver to handle this. Essentially
|
||||||
|
* returning no data is more or less undefined behavior and may cause
|
||||||
|
* breakage in receiving applications. The returned data will not be
|
||||||
|
* freed, so it needs to be retained and dealt with internally.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
typedef const void *(SDLCALL *SDL_ClipboardDataCallback)(void *userdata, const char *mime_type, size_t *size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function that will be called when the clipboard is cleared, or when new
|
||||||
|
* data is set.
|
||||||
|
*
|
||||||
|
* \param userdata a pointer to the provided user data.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offer clipboard data to the OS.
|
||||||
|
*
|
||||||
|
* Tell the operating system that the application is offering clipboard data
|
||||||
|
* for each of the provided mime-types. Once another application requests the
|
||||||
|
* data the callback function will be called, allowing it to generate and
|
||||||
|
* respond with the data for the requested mime-type.
|
||||||
|
*
|
||||||
|
* The size of text data does not include any terminator, and the text does
|
||||||
|
* not need to be null-terminated (e.g., you can directly copy a portion of a
|
||||||
|
* document).
|
||||||
|
*
|
||||||
|
* \param callback a function pointer to the function that provides the
|
||||||
|
* clipboard data.
|
||||||
|
* \param cleanup a function pointer to the function that cleans up the
|
||||||
|
* clipboard data.
|
||||||
|
* \param userdata an opaque pointer that will be forwarded to the callbacks.
|
||||||
|
* \param mime_types a list of mime-types that are being offered. SDL copies the given list.
|
||||||
|
* \param num_mime_types the number of mime-types in the mime_types list.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ClearClipboardData
|
||||||
|
* \sa SDL_GetClipboardData
|
||||||
|
* \sa SDL_HasClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanupCallback cleanup, void *userdata, const char **mime_types, size_t num_mime_types);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the clipboard data.
|
||||||
|
*
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_ClearClipboardData(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data from the clipboard for a given mime type.
|
||||||
|
*
|
||||||
|
* The size of text data does not include the terminator, but the text is
|
||||||
|
* guaranteed to be null-terminated.
|
||||||
|
*
|
||||||
|
* \param mime_type the mime type to read from the clipboard.
|
||||||
|
* \param size a pointer filled in with the length of the returned data.
|
||||||
|
* \returns the retrieved data buffer or NULL on failure; call SDL_GetError()
|
||||||
|
* for more information. This should be freed with SDL_free() when it
|
||||||
|
* is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasClipboardData
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void * SDLCALL SDL_GetClipboardData(const char *mime_type, size_t *size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query whether there is data in the clipboard for the provided mime type.
|
||||||
|
*
|
||||||
|
* \param mime_type the mime type to check for data.
|
||||||
|
* \returns true if data exists in the clipboard for the provided mime type,
|
||||||
|
* false if it does not.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
* \sa SDL_GetClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasClipboardData(const char *mime_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the list of mime types available in the clipboard.
|
||||||
|
*
|
||||||
|
* \param num_mime_types a pointer filled with the number of mime types, may
|
||||||
|
* be NULL.
|
||||||
|
* \returns a null-terminated array of strings with mime types, or NULL on
|
||||||
|
* failure; call SDL_GetError() for more information. This should be
|
||||||
|
* freed with SDL_free() when it is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC char ** SDLCALL SDL_GetClipboardMimeTypes(size_t *num_mime_types);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_clipboard_h_ */
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file reverses the effects of SDL_begin_code.h and should be included
|
||||||
|
* after you finish any function and structure declarations in your headers.
|
||||||
|
*
|
||||||
|
* SDL's headers use this; applications generally should not include this
|
||||||
|
* header directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_begin_code_h
|
||||||
|
#error SDL_close_code.h included without matching SDL_begin_code.h
|
||||||
|
#endif
|
||||||
|
#undef SDL_begin_code_h
|
||||||
|
|
||||||
|
/* Reset structure packing at previous byte alignment */
|
||||||
|
#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__)
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#pragma nopackwarning
|
||||||
|
#endif
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif /* Compiler needs structure packing set */
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Header file containing SDL's license. */
|
||||||
@@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* WIKI CATEGORY: CPUInfo */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryCPUInfo
|
||||||
|
*
|
||||||
|
* CPU feature detection for SDL.
|
||||||
|
*
|
||||||
|
* These functions are largely concerned with reporting if the system has
|
||||||
|
* access to various SIMD instruction sets, but also has other important info
|
||||||
|
* to share, such as system RAM size and number of logical CPU cores.
|
||||||
|
*
|
||||||
|
* CPU instruction set checks, like SDL_HasSSE() and SDL_HasNEON(), are
|
||||||
|
* available on all platforms, even if they don't make sense (an ARM processor
|
||||||
|
* will never have SSE and an x86 processor will never have NEON, for example,
|
||||||
|
* but these functions still exist and will simply return false in these
|
||||||
|
* cases).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_cpuinfo_h_
|
||||||
|
#define SDL_cpuinfo_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A guess for the cacheline size used for padding.
|
||||||
|
*
|
||||||
|
* Most x86 processors have a 64 byte cache line. The 64-bit PowerPC
|
||||||
|
* processors have a 128 byte cache line. We use the larger value to be
|
||||||
|
* generally safe.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_CACHELINE_SIZE 128
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of logical CPU cores available.
|
||||||
|
*
|
||||||
|
* \returns the total number of logical CPU cores. On CPUs that include
|
||||||
|
* technologies such as hyperthreading, the number of logical cores
|
||||||
|
* may be more than the number of physical cores.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_GetNumLogicalCPUCores(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the L1 cache line size of the CPU.
|
||||||
|
*
|
||||||
|
* This is useful for determining multi-threaded structure padding or SIMD
|
||||||
|
* prefetch sizes.
|
||||||
|
*
|
||||||
|
* \returns the L1 cache line size of the CPU, in bytes.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_GetCPUCacheLineSize(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has AltiVec features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using PowerPC instruction
|
||||||
|
* sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has AltiVec features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasAltiVec(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has MMX features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using Intel instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has MMX features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasMMX(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has SSE features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using Intel instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has SSE features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasSSE2
|
||||||
|
* \sa SDL_HasSSE3
|
||||||
|
* \sa SDL_HasSSE41
|
||||||
|
* \sa SDL_HasSSE42
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasSSE(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has SSE2 features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using Intel instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has SSE2 features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasSSE
|
||||||
|
* \sa SDL_HasSSE3
|
||||||
|
* \sa SDL_HasSSE41
|
||||||
|
* \sa SDL_HasSSE42
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasSSE2(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has SSE3 features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using Intel instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has SSE3 features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasSSE
|
||||||
|
* \sa SDL_HasSSE2
|
||||||
|
* \sa SDL_HasSSE41
|
||||||
|
* \sa SDL_HasSSE42
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasSSE3(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has SSE4.1 features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using Intel instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has SSE4.1 features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasSSE
|
||||||
|
* \sa SDL_HasSSE2
|
||||||
|
* \sa SDL_HasSSE3
|
||||||
|
* \sa SDL_HasSSE42
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasSSE41(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has SSE4.2 features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using Intel instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has SSE4.2 features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasSSE
|
||||||
|
* \sa SDL_HasSSE2
|
||||||
|
* \sa SDL_HasSSE3
|
||||||
|
* \sa SDL_HasSSE41
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasSSE42(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has AVX features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using Intel instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has AVX features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasAVX2
|
||||||
|
* \sa SDL_HasAVX512F
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasAVX(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has AVX2 features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using Intel instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has AVX2 features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasAVX
|
||||||
|
* \sa SDL_HasAVX512F
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasAVX2(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has AVX-512F (foundation) features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using Intel instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has AVX-512F features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasAVX
|
||||||
|
* \sa SDL_HasAVX2
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasAVX512F(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has ARM SIMD (ARMv6) features.
|
||||||
|
*
|
||||||
|
* This is different from ARM NEON, which is a different instruction set.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using ARM instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has ARM SIMD features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasNEON
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasARMSIMD(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has NEON (ARM SIMD) features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using ARM instruction sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has ARM NEON features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasNEON(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has LSX (LOONGARCH SIMD) features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using LOONGARCH instruction
|
||||||
|
* sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has LOONGARCH LSX features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasLSX(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the CPU has LASX (LOONGARCH SIMD) features.
|
||||||
|
*
|
||||||
|
* This always returns false on CPUs that aren't using LOONGARCH instruction
|
||||||
|
* sets.
|
||||||
|
*
|
||||||
|
* \returns true if the CPU has LOONGARCH LASX features or false if not.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasLASX(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the amount of RAM configured in the system.
|
||||||
|
*
|
||||||
|
* \returns the amount of RAM configured in the system in MiB.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report the alignment this system needs for SIMD allocations.
|
||||||
|
*
|
||||||
|
* This will return the minimum number of bytes to which a pointer must be
|
||||||
|
* aligned to be compatible with SIMD instructions on the current machine. For
|
||||||
|
* example, if the machine supports SSE only, it will return 16, but if it
|
||||||
|
* supports AVX-512F, it'll return 64 (etc). This only reports values for
|
||||||
|
* instruction sets SDL knows about, so if your SDL build doesn't have
|
||||||
|
* SDL_HasAVX512F(), then it might return 16 for the SSE support it sees and
|
||||||
|
* not 64 for the AVX-512 instructions that exist but SDL doesn't know about.
|
||||||
|
* Plan accordingly.
|
||||||
|
*
|
||||||
|
* \returns the alignment in bytes needed for available, known SIMD
|
||||||
|
* instructions.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_aligned_alloc
|
||||||
|
* \sa SDL_aligned_free
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC size_t SDLCALL SDL_GetSIMDAlignment(void);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_cpuinfo_h_ */
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user