├── .github ├── INTEGRATION.md ├── generate-binding-status.sh ├── template.html ├── update-readme.sh ├── validate.sh └── workflows │ └── deploy-readme.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── cbits ├── helpers.c └── stb_image_wrapper.c ├── check-sdl-bindings ├── examples ├── AudioExample.hs ├── CPUInfoExample.hs ├── CameraExample.hs ├── ClipboardExample.hs ├── Content │ ├── Audio │ │ └── sound.wav │ ├── Images │ │ ├── armadillo.png │ │ ├── astc │ │ │ ├── 10x10.astc │ │ │ ├── 10x5.astc │ │ │ ├── 10x6.astc │ │ │ ├── 10x8.astc │ │ │ ├── 12x10.astc │ │ │ ├── 12x12.astc │ │ │ ├── 4x4.astc │ │ │ ├── 5x4.astc │ │ │ ├── 5x5.astc │ │ │ ├── 6x5.astc │ │ │ ├── 6x6.astc │ │ │ ├── 8x5.astc │ │ │ ├── 8x6.astc │ │ │ └── 8x8.astc │ │ ├── bcn │ │ │ ├── BC1.dds │ │ │ ├── BC1_SRGB.dds │ │ │ ├── BC2.dds │ │ │ ├── BC2_SRGB.dds │ │ │ ├── BC3.dds │ │ │ ├── BC3_SRGB.dds │ │ │ ├── BC4.dds │ │ │ ├── BC5.dds │ │ │ ├── BC6H_S.dds │ │ │ ├── BC6H_U.dds │ │ │ ├── BC7.dds │ │ │ └── BC7_SRGB.dds │ │ ├── cube0.bmp │ │ ├── cube0mip1.bmp │ │ ├── cube1.bmp │ │ ├── cube1mip1.bmp │ │ ├── cube2.bmp │ │ ├── cube2mip1.bmp │ │ ├── cube3.bmp │ │ ├── cube3mip1.bmp │ │ ├── cube4.bmp │ │ ├── cube5.bmp │ │ ├── latency.bmp │ │ ├── memorial.hdr │ │ ├── ravioli.bmp │ │ ├── ravioli_atlas.bmp │ │ └── ravioli_inverted.bmp │ └── Shaders │ │ ├── Compiled │ │ ├── DXIL │ │ │ ├── CustomSampling.frag.dxil │ │ │ ├── DepthOutline.frag.dxil │ │ │ ├── FillTexture.comp.dxil │ │ │ ├── Fullscreen.vert.dxil │ │ │ ├── GradientTexture.comp.dxil │ │ │ ├── LinearToSRGB.comp.dxil │ │ │ ├── LinearToST2084.comp.dxil │ │ │ ├── PositionColor.vert.dxil │ │ │ ├── PositionColorInstanced.vert.dxil │ │ │ ├── PositionColorTransform.vert.dxil │ │ │ ├── PullSpriteBatch.vert.dxil │ │ │ ├── RawTriangle.vert.dxil │ │ │ ├── Skybox.frag.dxil │ │ │ ├── Skybox.vert.dxil │ │ │ ├── SolidColor.frag.dxil │ │ │ ├── SolidColorDepth.frag.dxil │ │ │ ├── SpriteBatch.comp.dxil │ │ │ ├── TexturedQuad.comp.dxil │ │ │ ├── TexturedQuad.frag.dxil │ │ │ ├── TexturedQuad.vert.dxil │ │ │ ├── TexturedQuadArray.frag.dxil │ │ │ ├── TexturedQuadColor.frag.dxil │ │ │ ├── TexturedQuadColorWithMatrix.vert.dxil │ │ │ ├── TexturedQuadWithMatrix.vert.dxil │ │ │ ├── TexturedQuadWithMultiplyColor.frag.dxil │ │ │ ├── ToneMapACES.comp.dxil │ │ │ ├── ToneMapExtendedReinhardLuminance.comp.dxil │ │ │ ├── ToneMapHable.comp.dxil │ │ │ └── ToneMapReinhard.comp.dxil │ │ ├── MSL │ │ │ ├── CustomSampling.frag.msl │ │ │ ├── DepthOutline.frag.msl │ │ │ ├── FillTexture.comp.msl │ │ │ ├── Fullscreen.vert.msl │ │ │ ├── GradientTexture.comp.msl │ │ │ ├── LinearToSRGB.comp.msl │ │ │ ├── LinearToST2084.comp.msl │ │ │ ├── PositionColor.vert.msl │ │ │ ├── PositionColorInstanced.vert.msl │ │ │ ├── PositionColorTransform.vert.msl │ │ │ ├── PullSpriteBatch.vert.msl │ │ │ ├── RawTriangle.vert.msl │ │ │ ├── Skybox.frag.msl │ │ │ ├── Skybox.vert.msl │ │ │ ├── SolidColor.frag.msl │ │ │ ├── SolidColorDepth.frag.msl │ │ │ ├── SpriteBatch.comp.msl │ │ │ ├── TexturedQuad.comp.msl │ │ │ ├── TexturedQuad.frag.msl │ │ │ ├── TexturedQuad.vert.msl │ │ │ ├── TexturedQuadArray.frag.msl │ │ │ ├── TexturedQuadColor.frag.msl │ │ │ ├── TexturedQuadColorWithMatrix.vert.msl │ │ │ ├── TexturedQuadWithMatrix.vert.msl │ │ │ ├── TexturedQuadWithMultiplyColor.frag.msl │ │ │ ├── ToneMapACES.comp.msl │ │ │ ├── ToneMapExtendedReinhardLuminance.comp.msl │ │ │ ├── ToneMapHable.comp.msl │ │ │ └── ToneMapReinhard.comp.msl │ │ └── SPIRV │ │ │ ├── CustomSampling.frag.spv │ │ │ ├── DepthOutline.frag.spv │ │ │ ├── FillTexture.comp.spv │ │ │ ├── Fullscreen.vert.spv │ │ │ ├── GradientTexture.comp.spv │ │ │ ├── LinearToSRGB.comp.spv │ │ │ ├── LinearToST2084.comp.spv │ │ │ ├── PositionColor.vert.spv │ │ │ ├── PositionColorInstanced.vert.spv │ │ │ ├── PositionColorTransform.vert.spv │ │ │ ├── PullSpriteBatch.vert.spv │ │ │ ├── RawTriangle.vert.spv │ │ │ ├── Skybox.frag.spv │ │ │ ├── Skybox.vert.spv │ │ │ ├── SolidColor.frag.spv │ │ │ ├── SolidColorDepth.frag.spv │ │ │ ├── SpriteBatch.comp.spv │ │ │ ├── TexturedQuad.comp.spv │ │ │ ├── TexturedQuad.frag.spv │ │ │ ├── TexturedQuad.vert.spv │ │ │ ├── TexturedQuadArray.frag.spv │ │ │ ├── TexturedQuadColor.frag.spv │ │ │ ├── TexturedQuadColorWithMatrix.vert.spv │ │ │ ├── TexturedQuadWithMatrix.vert.spv │ │ │ ├── TexturedQuadWithMultiplyColor.frag.spv │ │ │ ├── ToneMapACES.comp.spv │ │ │ ├── ToneMapExtendedReinhardLuminance.comp.spv │ │ │ ├── ToneMapHable.comp.spv │ │ │ └── ToneMapReinhard.comp.spv │ │ └── Source │ │ ├── CustomSampling.frag.hlsl │ │ ├── DepthOutline.frag.hlsl │ │ ├── FillTexture.comp.hlsl │ │ ├── Fullscreen.vert.hlsl │ │ ├── GradientTexture.comp.hlsl │ │ ├── LinearToSRGB.comp.hlsl │ │ ├── LinearToST2084.comp.hlsl │ │ ├── PositionColor.vert.hlsl │ │ ├── PositionColorInstanced.vert.hlsl │ │ ├── PositionColorTransform.vert.hlsl │ │ ├── PullSpriteBatch.vert.hlsl │ │ ├── RawTriangle.vert.hlsl │ │ ├── Skybox.frag.hlsl │ │ ├── Skybox.vert.hlsl │ │ ├── SolidColor.frag.hlsl │ │ ├── SolidColorDepth.frag.hlsl │ │ ├── SpriteBatch.comp.hlsl │ │ ├── TexturedQuad.comp.hlsl │ │ ├── TexturedQuad.frag.hlsl │ │ ├── TexturedQuad.vert.hlsl │ │ ├── TexturedQuadArray.frag.hlsl │ │ ├── TexturedQuadColor.frag.hlsl │ │ ├── TexturedQuadColorWithMatrix.vert.hlsl │ │ ├── TexturedQuadWithMatrix.vert.hlsl │ │ ├── TexturedQuadWithMultiplyColor.frag.hlsl │ │ ├── ToneMapACES.comp.hlsl │ │ ├── ToneMapExtendedReinhardLuminance.comp.hlsl │ │ ├── ToneMapHable.comp.hlsl │ │ ├── ToneMapReinhard.comp.hlsl │ │ └── compile.sh ├── DialogExample.hs ├── EventsExample.hs ├── FilesystemExample.hs ├── GPUAnimatedQuadExample.hs ├── GPUBasicComputeExample.hs ├── GPUClear3DSliceExample.hs ├── GPUClearExample.hs ├── GPUComputeSamplerExample.hs ├── GPUComputeUniformsExample.hs ├── GPUCopyAndReadbackExample.hs ├── GPUCopyConsistencyExample.hs ├── GPUCullExample.hs ├── GPUCustomSamplingExample.hs ├── GPUDrawIndirectExample.hs ├── GPUInstancedExample.hs ├── GPUMultiWindowExample.hs ├── GPURawTriangleExample.hs ├── GPUStencilExample.hs ├── GPUTexturedQuadExample.hs ├── GPUTonemappingExample.hs ├── GPUVertexBufferExample.hs ├── GUIDExample.hs ├── GamepadExample.hs ├── HapticExample.hs ├── HintsExample.hs ├── InitExample.hs ├── LocaleExample.hs ├── MessageBoxExample.hs ├── PlatformExample.hs ├── PowerExample.hs ├── ProcessExample.hs ├── RectExample.hs ├── RenderExample.hs ├── SensorExample.hs ├── StorageExample.hs ├── SystemExample.hsc ├── TimeExample.hs ├── TimerExample.hs ├── TouchDeviceExample.hs ├── TrayExample.hs └── WAVExample.hs ├── hie.yaml ├── include ├── helpers.h └── stb_image.h ├── sdl3.cabal ├── src ├── GPUCommon.hs ├── SDL.hs └── SDL │ ├── Assert.hsc │ ├── AsyncIO.hsc │ ├── Atomic.hs │ ├── Audio.hsc │ ├── Bits.hs │ ├── BlendMode.hsc │ ├── CPUInfo.hsc │ ├── Camera.hsc │ ├── Clipboard.hs │ ├── Dialog.hsc │ ├── Endian.hsc │ ├── Error.hs │ ├── Events.hsc │ ├── Filesystem.hsc │ ├── GPU.hsc │ ├── GUID.hsc │ ├── Gamepad.hsc │ ├── Haptic.hsc │ ├── Hidapi.hsc │ ├── Hints.hsc │ ├── IOStream.hs │ ├── Init.hsc │ ├── Joystick.hsc │ ├── Keyboard.hsc │ ├── Keycode.hsc │ ├── LoadSO.hsc │ ├── Locale.hsc │ ├── Log.hsc │ ├── MessageBox.hsc │ ├── Metal.hsc │ ├── Misc.hsc │ ├── Mouse.hsc │ ├── Mutex.hs │ ├── Pen.hsc │ ├── Pixels.hsc │ ├── Platform.hsc │ ├── Power.hsc │ ├── Process.hsc │ ├── Properties.hs │ ├── Rect.hsc │ ├── Render.hsc │ ├── Scancode.hsc │ ├── Sensor.hsc │ ├── Stdinc.hs │ ├── Storage.hsc │ ├── Surface.hsc │ ├── System.hsc │ ├── Thread.hsc │ ├── Time.hsc │ ├── Timer.hsc │ ├── Touch.hsc │ ├── Tray.hsc │ ├── Version.hsc │ └── Video.hsc └── test ├── binding-checker.hs └── validator.md /.github/generate-binding-status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Generate SDL3 Binding Status for README 4 | # ======================================= 5 | # This script runs the binding checker and generates a status table 6 | # to be included in the README.md file. 7 | 8 | set -e 9 | 10 | echo "Generating SDL3 binding status..." >&2 11 | 12 | # Check if cabal and binding-checker are available 13 | if ! command -v cabal >/dev/null 2>&1; then 14 | echo "Error: cabal not found. Cannot generate binding status." >&2 15 | exit 1 16 | fi 17 | 18 | # Build the binding checker 19 | echo "Building binding checker..." >&2 20 | cabal build exe:binding-checker -f-pkgconfig >/dev/null 2>&1 21 | 22 | # Find SDL3 headers 23 | SDL_PATHS="/usr/local/include/SDL3:/usr/include/SDL3:/opt/homebrew/include/SDL3" 24 | sdl_dir="" 25 | 26 | IFS=':' read -ra PATHS <<< "$SDL_PATHS" 27 | for path in "${PATHS[@]}"; do 28 | if [[ -d "$path" ]]; then 29 | sdl_dir="$path" 30 | break 31 | fi 32 | done 33 | 34 | if [[ -z "$sdl_dir" ]]; then 35 | echo "Error: No SDL3 headers found in standard locations" >&2 36 | echo "Please install SDL3 development files first." >&2 37 | echo "Searched paths: $SDL_PATHS" >&2 38 | exit 1 39 | fi 40 | 41 | # Create temporary directory for results 42 | TEMP_DIR=$(mktemp -d) 43 | trap "rm -rf $TEMP_DIR" EXIT 44 | 45 | # Get list of modules from source directory 46 | modules=() 47 | for file in src/SDL/*.hsc src/SDL/*.hs; do 48 | if [[ -f "$file" ]]; then 49 | basename=$(basename "$file" .hsc) 50 | basename=$(basename "$basename" .hs) 51 | modules+=("$basename") 52 | fi 53 | done 54 | 55 | # Check if we found any modules 56 | if [[ ${#modules[@]} -eq 0 ]]; then 57 | echo "Error: No Haskell binding modules found in src/SDL/" >&2 58 | exit 1 59 | fi 60 | 61 | # Check each module and collect results 62 | echo "Checking bindings for ${#modules[@]} modules..." >&2 63 | 64 | results_file="$TEMP_DIR/results.txt" 65 | total_headers=0 66 | total_broken=0 67 | headers_with_bindings=0 68 | headers_complete=0 69 | 70 | for module in "${modules[@]}"; do 71 | # Convert module name to header name (e.g., "Camera" -> "SDL_camera.h") 72 | module_lower=$(echo "$module" | tr '[:upper:]' '[:lower:]') 73 | header_name="SDL_${module_lower}.h" 74 | header_path="$sdl_dir/$header_name" 75 | 76 | total_headers=$((total_headers + 1)) 77 | 78 | # Run binding checker on individual header 79 | if [[ -f "$header_path" ]]; then 80 | if ! output=$(echo "$header_path" | cabal exec -f-pkgconfig binding-checker 2>&1); then 81 | # If binding checker fails, it's a critical error 82 | echo "Error: Binding checker failed for $header_path" >&2 83 | echo "Output: $output" >&2 84 | exit 1 85 | fi 86 | else 87 | # Header doesn't exist, assume no bindings needed 88 | echo "SDL_${module_lower}:❌ No header" >> "$results_file" 89 | continue 90 | fi 91 | 92 | if echo "$output" | grep -q "No binding file found"; then 93 | echo "SDL_${module_lower}:❌ No bindings" >> "$results_file" 94 | elif echo "$output" | grep -q "✓ All bindings OK"; then 95 | echo "SDL_${module_lower}:✅ Complete" >> "$results_file" 96 | headers_complete=$((headers_complete + 1)) 97 | headers_with_bindings=$((headers_with_bindings + 1)) 98 | elif echo "$output" | grep -q "✗ Found.*broken bindings"; then 99 | count=$(echo "$output" | grep -o "Found [0-9]* broken bindings" | grep -o "[0-9]*" || echo "0") 100 | echo "SDL_${module_lower}:⚠️ $count missing" >> "$results_file" 101 | total_broken=$((total_broken + count)) 102 | headers_with_bindings=$((headers_with_bindings + 1)) 103 | else 104 | echo "SDL_${module_lower}:❓ Unknown" >> "$results_file" 105 | fi 106 | done 107 | 108 | # Calculate statistics 109 | completion_percentage=0 110 | if [[ $headers_with_bindings -gt 0 ]]; then 111 | completion_percentage=$(( (headers_complete * 100) / headers_with_bindings )) 112 | fi 113 | 114 | # Generate timestamp 115 | timestamp=$(date -u +"%Y-%m-%d %H:%M UTC") 116 | 117 | # Generate the binding status section 118 | echo "## 📊 Binding Status" 119 | echo "" 120 | echo "*Last updated: $timestamp*" 121 | echo "" 122 | echo "### Summary" 123 | echo "- **Total Modules**: $total_headers" 124 | echo "- **Modules with Bindings**: $headers_with_bindings" 125 | echo "- **Complete Bindings**: $headers_complete" 126 | echo "- **Missing Functions**: $total_broken" 127 | echo "- **Completion Rate**: ${completion_percentage}%" 128 | echo "" 129 | echo "### Status by Module" 130 | echo "" 131 | echo "| Module | Status |" 132 | echo "|--------|--------|" 133 | 134 | # Sort results and create simple two-column table 135 | sorted_results=$(sort "$results_file") 136 | 137 | while IFS= read -r line; do 138 | module=$(echo "$line" | cut -d: -f1) 139 | status=$(echo "$line" | cut -d: -f2-) 140 | echo "| \`$module\` | $status |" 141 | done <<< "$sorted_results" 142 | 143 | echo "" 144 | echo "### Legend" 145 | echo "- ✅ **Complete**: All functions from the header are bound" 146 | echo "- ⚠️ **X missing**: Header has bindings but X functions are missing" 147 | echo "- ❌ **No bindings**: No Haskell bindings exist for this header" 148 | echo "- ❓ **Unknown**: Status could not be determined" 149 | echo "" 150 | echo "### Notes" 151 | echo "- Status reflects core SDL3 headers (test/internal headers excluded)" 152 | echo "- Missing function details are available in the \`broken/\` directory after running the binding checker" 153 | echo "- Use \`./check-sdl-bindings -i\` for interactive binding status checking" 154 | echo "- Some modules may intentionally have no bindings if not applicable to Haskell" 155 | echo "" 156 | 157 | echo "Binding status generated successfully! Total: $total_headers modules, $headers_complete complete, $total_broken missing functions" >&2 158 | -------------------------------------------------------------------------------- /.github/template.html: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | $title$ 18 | 150 | 151 | 152 |
$body$
153 | 154 | 155 | -------------------------------------------------------------------------------- /.github/update-readme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Update README with SDL3 Binding Status 4 | # ====================================== 5 | # This script generates binding status and inserts it into README.md 6 | 7 | set -e 8 | 9 | # Colors for output 10 | RED='\033[0;31m' 11 | GREEN='\033[0;32m' 12 | YELLOW='\033[1;33m' 13 | BLUE='\033[0;34m' 14 | NC='\033[0m' # No Color 15 | 16 | echo "Updating README.md with current binding status..." 17 | 18 | # Pull latest changes from current branch 19 | echo "Pulling latest changes from current branch..." 20 | git pull origin $(git branch --show-current) 21 | 22 | # Extract SDL commit hash from CI workflow 23 | SDL_COMMIT="" 24 | if [[ -f ".github/workflows/deploy-readme.yml" ]]; then 25 | SDL_COMMIT=$(grep -o 'git checkout [a-f0-9]\{40\}' .github/workflows/deploy-readme.yml | cut -d' ' -f3) 26 | fi 27 | 28 | # Check if README.md exists 29 | if [[ ! -f "README.md" ]]; then 30 | echo -e "${RED}Error: README.md not found${NC}" 31 | exit 1 32 | fi 33 | 34 | # Create backup 35 | cp README.md README.md.backup 36 | echo "Created backup: README.md.backup" 37 | 38 | # Generate binding status 39 | echo "Generating binding status..." 40 | binding_status=$(bash .github/generate-binding-status.sh 2>/dev/null) 41 | 42 | # Add SDL commit info to binding status if available 43 | if [[ -n "$SDL_COMMIT" ]]; then 44 | # Insert SDL commit line after the date line 45 | binding_status=$(echo "$binding_status" | sed "/\*Last updated:/a\\ 46 | \\ 47 | *SDL3 commit: \`$SDL_COMMIT\`*") 48 | fi 49 | 50 | if [[ -z "$binding_status" ]]; then 51 | echo -e "${RED}Error: Failed to generate binding status${NC}" 52 | exit 1 53 | fi 54 | 55 | # Create temporary file for the new README 56 | TEMP_README=$(mktemp) 57 | trap "rm -f $TEMP_README" EXIT 58 | 59 | # Check if binding status section already exists 60 | if grep -q "## 📊 Binding Status" README.md; then 61 | echo "Updating existing binding status section..." 62 | 63 | # Extract content before binding status 64 | sed '/## 📊 Binding Status/,$d' README.md > "$TEMP_README" 65 | 66 | # Add new binding status 67 | echo "$binding_status" >> "$TEMP_README" 68 | 69 | # Find and add content after binding status (if any) 70 | # Look for the next ## section after binding status 71 | in_status=false 72 | found_next=false 73 | while IFS= read -r line; do 74 | if [[ "$line" == "## 📊 Binding Status" ]]; then 75 | in_status=true 76 | continue 77 | elif [[ "$in_status" == true && "$line" =~ ^##[[:space:]] ]]; then 78 | found_next=true 79 | echo "$line" >> "$TEMP_README" 80 | elif [[ "$found_next" == true ]]; then 81 | echo "$line" >> "$TEMP_README" 82 | fi 83 | done < README.md 84 | 85 | else 86 | echo "Adding new binding status section..." 87 | 88 | # Find a good place to insert (after installation, before examples, or at end) 89 | if grep -q "^## " README.md; then 90 | # Find the first occurrence of ## Examples, ## Usage, ## Documentation, or ## Contributing 91 | insert_line=$(grep -n "^## \(Examples\|Usage\|Documentation\|Contributing\|License\)" README.md | head -1 | cut -d: -f1) 92 | 93 | if [[ -n "$insert_line" ]]; then 94 | # Insert before this section 95 | head -n $((insert_line - 1)) README.md > "$TEMP_README" 96 | echo "" >> "$TEMP_README" 97 | echo "$binding_status" >> "$TEMP_README" 98 | echo "" >> "$TEMP_README" 99 | tail -n +$insert_line README.md >> "$TEMP_README" 100 | else 101 | # Append at end 102 | cat README.md > "$TEMP_README" 103 | echo "" >> "$TEMP_README" 104 | echo "$binding_status" >> "$TEMP_README" 105 | fi 106 | else 107 | # No other sections, append at end 108 | cat README.md > "$TEMP_README" 109 | echo "" >> "$TEMP_README" 110 | echo "$binding_status" >> "$TEMP_README" 111 | fi 112 | fi 113 | 114 | # Replace original README with updated version 115 | mv "$TEMP_README" README.md 116 | 117 | echo -e "${GREEN}README.md updated successfully!${NC}" 118 | 119 | # Show what changed 120 | if command -v diff >/dev/null 2>&1; then 121 | echo -e "${BLUE}Changes made:${NC}" 122 | diff README.md.backup README.md || true 123 | else 124 | echo "Updated README.md with binding status" 125 | fi 126 | 127 | # Optional: validate the README still looks good 128 | if command -v wc >/dev/null 2>&1; then 129 | lines=$(wc -l < README.md) 130 | echo "Updated README.md has $lines lines" 131 | fi 132 | 133 | echo -e "${GREEN}README update complete!${NC}" 134 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | dist-* 3 | cabal-dev 4 | *.o 5 | *.hi 6 | *.hie 7 | *.chi 8 | *.chs.h 9 | *.dyn_o 10 | *.dyn_hi 11 | .hpc 12 | .hsenv 13 | .cabal-sandbox/ 14 | cabal.sandbox.config 15 | *.prof 16 | *.aux 17 | *.hp 18 | *.eventlog 19 | .stack-work/ 20 | cabal.project.local 21 | cabal.project.local~ 22 | .HTF/ 23 | .ghc.environment.* 24 | .ccls-cache/* 25 | 26 | # Generated directories 27 | broken/ 28 | 29 | # Custom directories 30 | sdl/ 31 | 32 | # Zed 33 | AGENTS.MD 34 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Revision history for sdl3 2 | 3 | ## 0.1.0.0 -- YYYY-mm-dd 4 | 5 | * First version. Released on an unsuspecting world. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025, Kyle Lukaszek 2 | 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following 12 | disclaimer in the documentation and/or other materials provided 13 | with the distribution. 14 | 15 | * Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived 17 | from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /cbits/helpers.c: -------------------------------------------------------------------------------- 1 | #include "../include/helpers.h" 2 | 3 | void wrapper_SDL_GUIDToString(Uint8 *guid_data, char *pszGUID, int cbGUID) { 4 | SDL_GUID guid; 5 | memcpy(guid.data, guid_data, 16); 6 | SDL_GUIDToString(guid, pszGUID, cbGUID); 7 | } 8 | 9 | void wrapper_SDL_StringToGUID(const char *pchGUID, Uint8 *guid_data) { 10 | SDL_GUID guid = SDL_StringToGUID(pchGUID); 11 | memcpy(guid_data, guid.data, 16); 12 | } 13 | -------------------------------------------------------------------------------- /cbits/stb_image_wrapper.c: -------------------------------------------------------------------------------- 1 | // cbits/stb_image_wrapper.c 2 | #include "../include/helpers.h" 3 | #define STB_IMAGE_IMPLEMENTATION 4 | #define STBI_MALLOC SDL_malloc 5 | #define STBI_REALLOC SDL_realloc 6 | #define STBI_FREE SDL_free 7 | #define STBI_ONLY_HDR 8 | #include "../include/stb_image.h" 9 | 10 | // Wrapper function that Haskell will call 11 | // It takes the full path directly. 12 | float* hs_stbi_loadf_wrapper(const char* fullPath, int* pWidth, int* pHeight, int* pChannelsInFile, int desiredChannels) { 13 | return stbi_loadf(fullPath, pWidth, pHeight, pChannelsInFile, desiredChannels); 14 | } 15 | -------------------------------------------------------------------------------- /examples/AudioExample.hs: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : SDL.Audio 3 | Description : SDL audio functionality 4 | Copyright : (c) Kyle Lukaszek, 2025 5 | License : BSD3 6 | 7 | Plays an 8000Hz tone in F32 format. 8 | 9 | Tested on Linux with Pulse AND Alsa. 10 | Tested on Windows. 11 | 12 | For more details, refer to the official SDL3 documentation: 13 | https://wiki.libsdl.org/SDL3/CategoryAudio 14 | -} 15 | 16 | import Foreign 17 | import Foreign.C 18 | import qualified Data.ByteString as BS 19 | import Data.ByteString.Unsafe (unsafePackCStringLen) 20 | import SDL hiding (sin, round) 21 | import Control.Concurrent (threadDelay) 22 | import Foreign.Marshal.Array (withArray) 23 | import Foreign.Storable (sizeOf) 24 | 25 | -- | Main function to demonstrate SDL audio playback with a 1-second 440 Hz tone 26 | main :: IO () 27 | main = do 28 | -- Initialize SDL with audio support 29 | sdlInit [SDL_INIT_AUDIO] 30 | 31 | -- Define the audio specification: 32-bit float, 1 channel (mono), 8000 Hz 32 | let spec = SDLAudioSpec SDL_AUDIO_F32 1 8000 33 | 34 | -- Open the default playback device stream with the specified spec and no callback 35 | maybeStream <- sdlOpenAudioDeviceStream SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK (Just spec) Nothing 36 | case maybeStream of 37 | Nothing -> putStrLn "Failed to open audio stream" 38 | Just stream -> do 39 | -- Resume the audio stream to start playback 40 | success <- sdlResumeAudioStreamDevice stream 41 | if not success 42 | then putStrLn "Failed to resume audio stream" 43 | else do 44 | -- Generate 8000 samples (1 second at 8000 Hz) of a 440 Hz sine wave with amplitude 0.5 45 | let samples = [0.5 * sin (2 * pi * 440 * fromIntegral i / 8000) | i <- [0..7999]] :: [Float] 46 | 47 | -- Convert samples to a ByteString and feed them into the audio stream 48 | withArray samples $ \ptr -> do 49 | let len = 8000 * sizeOf (undefined :: Float) -- Total byte length (8000 floats * 4 bytes each) 50 | bs <- unsafePackCStringLen (castPtr ptr, len) 51 | successPut <- sdlPutAudioStreamData stream bs 52 | if not successPut 53 | then putStrLn "Failed to put audio data into stream" 54 | else do 55 | -- Wait 5 seconds to ensure the 1-second tone plays fully 56 | threadDelay (5 * 1000000) -- 5 seconds in microseconds 57 | 58 | -- Clean up by destroying the audio stream (also closes the associated device) 59 | sdlDestroyAudioStream stream 60 | sdlLog "Success!" 61 | 62 | sdlQuit 63 | -------------------------------------------------------------------------------- /examples/CPUInfoExample.hs: -------------------------------------------------------------------------------- 1 | import SDL 2 | 3 | -- Really simple test. 4 | 5 | main :: IO () 6 | main = do 7 | cores <- sdlGetNumLogicalCPUCores 8 | hasSSE <- sdlHasSSE 9 | ram <- sdlGetSystemRAM 10 | sdlLog $ "System has " ++ show cores ++ " logical cores" 11 | sdlLog $ "SSE support: " ++ show hasSSE 12 | sdlLog $ "RAM: " ++ show ram ++ " MiB" 13 | -------------------------------------------------------------------------------- /examples/CameraExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad 5 | import Foreign.Marshal.Alloc (alloca) 6 | import Foreign.Storable (peek) 7 | import System.Exit (exitFailure, exitSuccess) 8 | 9 | main :: IO () 10 | main = do 11 | -- Check compiled version 12 | sdlLog $ "Compiled SDL Version: " ++ show sdlVersion 13 | when (sdlVersionAtLeast 3 3 0) $ 14 | sdlLog "Compiled with at least SDL 3.3.0" 15 | 16 | -- Get linked version 17 | linkedVersion <- sdlGetVersion 18 | sdlLog $ "Linked SDL Version: " ++ show linkedVersion 19 | 20 | -- Initialize SDL with camera subsystem 21 | initSuccess <- sdlInit [SDL_INIT_CAMERA] 22 | unless initSuccess $ do 23 | sdlLog "Failed to initialize SDL with camera support!" 24 | err <- sdlGetError 25 | sdlLog $ "Error: " ++ err 26 | exitFailure 27 | 28 | -- Check initialized subsystems 29 | initializedSystems <- sdlWasInit [] 30 | sdlLog "Initialized subsystems:" 31 | mapM_ printSubsystem initializedSystems 32 | 33 | -- List available cameras 34 | sdlLog "Enumerating cameras..." 35 | cameras <- sdlGetCameras 36 | if null cameras 37 | then sdlLog "No cameras found." 38 | else do 39 | sdlLog $ "Found " ++ show (length cameras) ++ " camera(s):" 40 | forM_ cameras $ \camId -> do 41 | mName <- sdlGetCameraName camId 42 | pos <- sdlGetCameraPosition camId 43 | sdlLog $ " - ID: " ++ show camId ++ 44 | ", Name: " ++ maybe "Unknown" id mName ++ 45 | ", Position: " ++ show pos 46 | 47 | -- Open the first camera 48 | let firstCamera = head cameras 49 | sdlLog $ "Opening camera with ID " ++ show firstCamera ++ "..." 50 | mCamera <- sdlOpenCamera firstCamera Nothing 51 | case mCamera of 52 | Nothing -> do 53 | sdlLog "Failed to open camera!" 54 | err <- sdlGetError 55 | sdlLog $ "Error: " ++ err 56 | Just camera -> do 57 | sdlLog "Camera opened successfully." 58 | 59 | -- Check permission state 60 | permState <- sdlGetCameraPermissionState camera 61 | sdlLog $ "Permission state: " ++ 62 | case permState of 63 | 1 -> "Approved" 64 | -1 -> "Denied" 65 | _ -> "Pending" 66 | 67 | -- Get camera format 68 | mFormat <- sdlGetCameraFormat camera 69 | case mFormat of 70 | Nothing -> sdlLog "Failed to get camera format." 71 | Just fmt -> sdlLog $ "Camera format: " ++ show fmt 72 | 73 | -- Close the camera 74 | sdlCloseCamera camera 75 | sdlLog "Camera closed." 76 | 77 | -- Quit SDL 78 | sdlQuit 79 | sdlLog "SDL shutdown complete." 80 | exitSuccess 81 | 82 | -- Helper function to print subsystem names 83 | printSubsystem :: SDLInitFlags -> IO () 84 | printSubsystem flag = sdlLog $ " - " ++ case flag of 85 | SDL_INIT_AUDIO -> "Audio" 86 | SDL_INIT_VIDEO -> "Video" 87 | SDL_INIT_JOYSTICK -> "Joystick" 88 | SDL_INIT_HAPTIC -> "Haptic" 89 | SDL_INIT_GAMEPAD -> "Gamepad" 90 | SDL_INIT_EVENTS -> "Events" 91 | SDL_INIT_SENSOR -> "Sensor" 92 | SDL_INIT_CAMERA -> "Camera" 93 | _ -> "Unknown subsystem" 94 | -------------------------------------------------------------------------------- /examples/ClipboardExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad (when, unless) 5 | import System.Exit (exitFailure, exitSuccess) 6 | 7 | main :: IO () 8 | main = do 9 | -- Initialize SDL with video and events subsystems 10 | initSuccess <- sdlInit [SDL_INIT_VIDEO] 11 | unless initSuccess $ do 12 | sdlLog "Failed to initialize SDL!" 13 | exitFailure 14 | 15 | -- Check initialized subsystems 16 | initializedSystems <- sdlWasInit [] 17 | sdlLog "Initialized subsystems:" 18 | mapM_ printSubsystem initializedSystems 19 | 20 | -- Set some text to the clipboard 21 | success <- sdlSetClipboardText "Hello, Clipboard!" 22 | when success $ sdlLog "Successfully set clipboard text" 23 | 24 | -- Check if clipboard has text 25 | hasText <- sdlHasClipboardText 26 | sdlLog $ "Clipboard has text: " ++ show hasText 27 | 28 | -- Retrieve text from clipboard 29 | clipboardContent <- sdlGetClipboardText 30 | case clipboardContent of 31 | Just text -> sdlLog $ "Clipboard contents: " ++ text 32 | Nothing -> sdlLog "Failed to retrieve clipboard text" 33 | 34 | -- Demonstrate primary selection (on systems that support it) 35 | _ <- sdlSetPrimarySelectionText "Primary Selection Text" 36 | primaryText <- sdlGetPrimarySelectionText 37 | case primaryText of 38 | Just text -> sdlLog $ "Primary selection: " ++ text 39 | Nothing -> sdlLog "Failed to retrieve primary selection" 40 | 41 | -- Get clipboard MIME types 42 | mimeTypes <- sdlGetClipboardMimeTypes 43 | sdlLog "Available MIME types:" 44 | mapM_ sdlLog mimeTypes 45 | 46 | sdlQuit 47 | exitSuccess 48 | 49 | -- Helper function to print subsystem names 50 | printSubsystem :: SDLInitFlags -> IO () 51 | printSubsystem flag = sdlLog $ " - " ++ case flag of 52 | SDL_INIT_AUDIO -> "Audio" 53 | SDL_INIT_VIDEO -> "Video" 54 | SDL_INIT_JOYSTICK -> "Joystick" 55 | SDL_INIT_HAPTIC -> "Haptic" 56 | SDL_INIT_GAMEPAD -> "Gamepad" 57 | SDL_INIT_EVENTS -> "Events" 58 | SDL_INIT_SENSOR -> "Sensor" 59 | SDL_INIT_CAMERA -> "Camera" 60 | _ -> "Unknown subsystem" 61 | -------------------------------------------------------------------------------- /examples/Content/Audio/sound.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Audio/sound.wav -------------------------------------------------------------------------------- /examples/Content/Images/armadillo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/armadillo.png -------------------------------------------------------------------------------- /examples/Content/Images/astc/10x10.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/10x10.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/10x5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/10x5.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/10x6.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/10x6.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/10x8.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/10x8.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/12x10.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/12x10.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/12x12.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/12x12.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/4x4.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/4x4.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/5x4.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/5x4.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/5x5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/5x5.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/6x5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/6x5.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/6x6.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/6x6.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/8x5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/8x5.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/8x6.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/8x6.astc -------------------------------------------------------------------------------- /examples/Content/Images/astc/8x8.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/astc/8x8.astc -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC1.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC1.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC1_SRGB.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC1_SRGB.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC2.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC2.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC2_SRGB.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC2_SRGB.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC3.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC3.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC3_SRGB.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC3_SRGB.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC4.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC4.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC5.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC5.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC6H_S.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC6H_S.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC6H_U.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC6H_U.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC7.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC7.dds -------------------------------------------------------------------------------- /examples/Content/Images/bcn/BC7_SRGB.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/bcn/BC7_SRGB.dds -------------------------------------------------------------------------------- /examples/Content/Images/cube0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube0.bmp -------------------------------------------------------------------------------- /examples/Content/Images/cube0mip1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube0mip1.bmp -------------------------------------------------------------------------------- /examples/Content/Images/cube1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube1.bmp -------------------------------------------------------------------------------- /examples/Content/Images/cube1mip1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube1mip1.bmp -------------------------------------------------------------------------------- /examples/Content/Images/cube2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube2.bmp -------------------------------------------------------------------------------- /examples/Content/Images/cube2mip1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube2mip1.bmp -------------------------------------------------------------------------------- /examples/Content/Images/cube3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube3.bmp -------------------------------------------------------------------------------- /examples/Content/Images/cube3mip1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube3mip1.bmp -------------------------------------------------------------------------------- /examples/Content/Images/cube4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube4.bmp -------------------------------------------------------------------------------- /examples/Content/Images/cube5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/cube5.bmp -------------------------------------------------------------------------------- /examples/Content/Images/latency.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/latency.bmp -------------------------------------------------------------------------------- /examples/Content/Images/memorial.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/memorial.hdr -------------------------------------------------------------------------------- /examples/Content/Images/ravioli.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/ravioli.bmp -------------------------------------------------------------------------------- /examples/Content/Images/ravioli_atlas.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/ravioli_atlas.bmp -------------------------------------------------------------------------------- /examples/Content/Images/ravioli_inverted.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Images/ravioli_inverted.bmp -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/CustomSampling.frag.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/CustomSampling.frag.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/DepthOutline.frag.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/DepthOutline.frag.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/FillTexture.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/FillTexture.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/Fullscreen.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/Fullscreen.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/GradientTexture.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/GradientTexture.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/LinearToSRGB.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/LinearToSRGB.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/LinearToST2084.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/LinearToST2084.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/PositionColor.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/PositionColor.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/PositionColorInstanced.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/PositionColorInstanced.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/PositionColorTransform.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/PositionColorTransform.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/PullSpriteBatch.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/PullSpriteBatch.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/RawTriangle.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/RawTriangle.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/Skybox.frag.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/Skybox.frag.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/Skybox.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/Skybox.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/SolidColor.frag.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/SolidColor.frag.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/SolidColorDepth.frag.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/SolidColorDepth.frag.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/SpriteBatch.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/SpriteBatch.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/TexturedQuad.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/TexturedQuad.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/TexturedQuad.frag.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/TexturedQuad.frag.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/TexturedQuad.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/TexturedQuad.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/TexturedQuadArray.frag.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/TexturedQuadArray.frag.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/TexturedQuadColor.frag.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/TexturedQuadColor.frag.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/TexturedQuadColorWithMatrix.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/TexturedQuadColorWithMatrix.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/TexturedQuadWithMatrix.vert.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/TexturedQuadWithMatrix.vert.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/TexturedQuadWithMultiplyColor.frag.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/TexturedQuadWithMultiplyColor.frag.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/ToneMapACES.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/ToneMapACES.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/ToneMapExtendedReinhardLuminance.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/ToneMapExtendedReinhardLuminance.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/ToneMapHable.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/ToneMapHable.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/DXIL/ToneMapReinhard.comp.dxil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/DXIL/ToneMapReinhard.comp.dxil -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/CustomSampling.frag.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct type_UBO 7 | { 8 | int mode; 9 | }; 10 | 11 | struct main0_out 12 | { 13 | float4 out_var_SV_Target0 [[color(0)]]; 14 | }; 15 | 16 | struct main0_in 17 | { 18 | float2 in_var_TEXCOORD0 [[user(locn0)]]; 19 | }; 20 | 21 | fragment main0_out main0(main0_in in [[stage_in]], constant type_UBO& UBO [[buffer(0)]], texture2d Texture [[texture(0)]]) 22 | { 23 | main0_out out = {}; 24 | float4 _74; 25 | do 26 | { 27 | uint2 _37 = uint2(Texture.get_width(), Texture.get_height()); 28 | int2 _44 = int2(float2(float(_37.x), float(_37.y)) * in.in_var_TEXCOORD0); 29 | float4 _46 = Texture.read(uint2(uint2(_44)), 0u); 30 | if (UBO.mode == 0) 31 | { 32 | _74 = _46; 33 | break; 34 | } 35 | else 36 | { 37 | _74 = ((((_46 * 0.20000000298023223876953125) + (Texture.read(uint2(uint2(_44 + int2(0, 1))), 0u) * 0.20000000298023223876953125)) + (Texture.read(uint2(uint2(_44 + int2(-1, 0))), 0u) * 0.20000000298023223876953125)) + (Texture.read(uint2(uint2(_44 + int2(0, -1))), 0u) * 0.20000000298023223876953125)) + (Texture.read(uint2(uint2(_44 + int2(1, 0))), 0u) * 0.20000000298023223876953125); 38 | break; 39 | } 40 | break; // unreachable workaround 41 | } while(false); 42 | out.out_var_SV_Target0 = _74; 43 | return out; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/DepthOutline.frag.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float4 out_var_SV_Target0 [[color(0)]]; 9 | }; 10 | 11 | struct main0_in 12 | { 13 | float2 in_var_TEXCOORD0 [[user(locn0)]]; 14 | }; 15 | 16 | fragment main0_out main0(main0_in in [[stage_in]], texture2d ColorTexture [[texture(0)]], texture2d DepthTexture [[texture(1)]], sampler ColorSampler [[sampler(0)]], sampler DepthSampler [[sampler(1)]]) 17 | { 18 | main0_out out = {}; 19 | float4 _38 = ColorTexture.sample(ColorSampler, in.in_var_TEXCOORD0); 20 | float4 _42 = DepthTexture.sample(DepthSampler, in.in_var_TEXCOORD0); 21 | float _43 = _42.x; 22 | uint2 _44 = uint2(DepthTexture.get_width(), DepthTexture.get_height()); 23 | float _46 = float(_44.x); 24 | float _48 = float(_44.y); 25 | float2 _50 = float2(1.0 / _46, 0.0); 26 | float2 _58 = float2((-1.0) / _46, 0.0); 27 | float2 _66 = float2(0.0, 1.0 / _48); 28 | float2 _74 = float2(0.0, (-1.0) / _48); 29 | float3 _117 = mix(mix(_38.xyz, float3(0.0), float3(step(0.20000000298023223876953125, precise::max(DepthTexture.sample(DepthSampler, (in.in_var_TEXCOORD0 + (_50 * 2.0))).x - _43, precise::max(DepthTexture.sample(DepthSampler, (in.in_var_TEXCOORD0 + (_58 * 2.0))).x - _43, precise::max(DepthTexture.sample(DepthSampler, (in.in_var_TEXCOORD0 + (_66 * 2.0))).x - _43, DepthTexture.sample(DepthSampler, (in.in_var_TEXCOORD0 + (_74 * 2.0))).x - _43)))))), float3(1.0), float3(step(0.20000000298023223876953125, precise::max(DepthTexture.sample(DepthSampler, (in.in_var_TEXCOORD0 + (_50 * 1.0))).x - _43, precise::max(DepthTexture.sample(DepthSampler, (in.in_var_TEXCOORD0 + (_58 * 1.0))).x - _43, precise::max(DepthTexture.sample(DepthSampler, (in.in_var_TEXCOORD0 + (_66 * 1.0))).x - _43, DepthTexture.sample(DepthSampler, (in.in_var_TEXCOORD0 + (_74 * 1.0))).x - _43)))))); 30 | out.out_var_SV_Target0 = float4(_117, _38.w); 31 | return out; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/FillTexture.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | kernel void main0(texture2d outImage [[texture(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 7 | { 8 | outImage.write(float4(1.0, 1.0, 0.0, 1.0), uint2(uint2(int2(gl_GlobalInvocationID.xy)))); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/Fullscreen.vert.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float2 out_var_TEXCOORD0 [[user(locn0)]]; 9 | float4 gl_Position [[position]]; 10 | }; 11 | 12 | vertex main0_out main0(uint gl_VertexIndex [[vertex_id]]) 13 | { 14 | main0_out out = {}; 15 | float2 _30 = float2(float((gl_VertexIndex << 1u) & 2u), float(gl_VertexIndex & 2u)); 16 | out.out_var_TEXCOORD0 = _30; 17 | out.gl_Position = float4((_30 * float2(2.0, -2.0)) + float2(-1.0, 1.0), 0.0, 1.0); 18 | return out; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/GradientTexture.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct type_UBO 7 | { 8 | float ubo_time; 9 | }; 10 | 11 | kernel void main0(constant type_UBO& UBO [[buffer(0)]], texture2d OutImage [[texture(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 12 | { 13 | uint2 _34 = uint2(OutImage.get_width(), OutImage.get_height()); 14 | float2 _41 = float2(gl_GlobalInvocationID.xy); 15 | OutImage.write(float4(float3(0.5) + (cos((float3(UBO.ubo_time) + (_41 / float2(float(_34.x), float(_34.y))).xyx) + float3(0.0, 2.0, 4.0)) * 0.5), 1.0), uint2(uint2(int2(_41)))); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/LinearToSRGB.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | kernel void main0(texture2d InImage [[texture(0)]], texture2d OutImage [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 7 | { 8 | uint2 _29 = uint2(int2(gl_GlobalInvocationID.xy)); 9 | OutImage.write(float4(powr(abs(InImage.read(uint2(_29), 0u).xyz), float3(0.454545438289642333984375)), 1.0), uint2(_29)); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/LinearToST2084.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | kernel void main0(texture2d InImage [[texture(0)]], texture2d OutImage [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 7 | { 8 | uint2 _53 = uint2(int2(gl_GlobalInvocationID.xy)); 9 | float4 _55 = InImage.read(uint2(_53), 0u); 10 | float3 _61 = powr(abs(((_55.xyz * float3x3(float3(0.6274039745330810546875, 0.329281985759735107421875, 0.043313600122928619384765625), float3(0.06909699738025665283203125, 0.919539988040924072265625, 0.0113612003624439239501953125), float3(0.01639159955084323883056640625, 0.0880132019519805908203125, 0.895595014095306396484375))) * 200.0) * float3(9.9999997473787516355514526367188e-05)), float3(0.1593017578125)); 11 | OutImage.write(float4(powr((float3(0.8359375) + (_61 * 18.8515625)) / (float3(1.0) + (_61 * 18.6875)), float3(78.84375)), _55.w), uint2(_53)); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/PositionColor.vert.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float4 out_var_TEXCOORD0 [[user(locn0)]]; 9 | float4 gl_Position [[position]]; 10 | }; 11 | 12 | struct main0_in 13 | { 14 | float3 in_var_TEXCOORD0 [[attribute(0)]]; 15 | float4 in_var_TEXCOORD1 [[attribute(1)]]; 16 | }; 17 | 18 | vertex main0_out main0(main0_in in [[stage_in]]) 19 | { 20 | main0_out out = {}; 21 | out.out_var_TEXCOORD0 = in.in_var_TEXCOORD1; 22 | out.gl_Position = float4(in.in_var_TEXCOORD0, 1.0); 23 | return out; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/PositionColorInstanced.vert.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float4 out_var_TEXCOORD0 [[user(locn0)]]; 9 | float4 gl_Position [[position]]; 10 | }; 11 | 12 | struct main0_in 13 | { 14 | float3 in_var_TEXCOORD0 [[attribute(0)]]; 15 | float4 in_var_TEXCOORD1 [[attribute(1)]]; 16 | }; 17 | 18 | vertex main0_out main0(main0_in in [[stage_in]], uint gl_InstanceIndex [[instance_id]]) 19 | { 20 | main0_out out = {}; 21 | float3 _30 = (in.in_var_TEXCOORD0 * 0.25) - float3(0.75, 0.75, 0.0); 22 | out.out_var_TEXCOORD0 = in.in_var_TEXCOORD1; 23 | out.gl_Position = float4(_30.x + (float(gl_InstanceIndex % 4u) * 0.5), _30.y + (floor(float(gl_InstanceIndex / 4u)) * 0.5), _30.z, 1.0); 24 | return out; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/PositionColorTransform.vert.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct type_UBO 7 | { 8 | float4x4 transform; 9 | }; 10 | 11 | struct main0_out 12 | { 13 | float4 out_var_TEXCOORD0 [[user(locn0)]]; 14 | float4 gl_Position [[position]]; 15 | }; 16 | 17 | struct main0_in 18 | { 19 | float3 in_var_TEXCOORD0 [[attribute(0)]]; 20 | float4 in_var_TEXCOORD1 [[attribute(1)]]; 21 | }; 22 | 23 | vertex main0_out main0(main0_in in [[stage_in]], constant type_UBO& UBO [[buffer(0)]]) 24 | { 25 | main0_out out = {}; 26 | out.out_var_TEXCOORD0 = in.in_var_TEXCOORD1; 27 | out.gl_Position = UBO.transform * float4(in.in_var_TEXCOORD0, 1.0); 28 | return out; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/PullSpriteBatch.vert.msl: -------------------------------------------------------------------------------- 1 | #pragma clang diagnostic ignored "-Wmissing-prototypes" 2 | #pragma clang diagnostic ignored "-Wmissing-braces" 3 | 4 | #include 5 | #include 6 | 7 | using namespace metal; 8 | 9 | template 10 | struct spvUnsafeArray 11 | { 12 | T elements[Num ? Num : 1]; 13 | 14 | thread T& operator [] (size_t pos) thread 15 | { 16 | return elements[pos]; 17 | } 18 | constexpr const thread T& operator [] (size_t pos) const thread 19 | { 20 | return elements[pos]; 21 | } 22 | 23 | device T& operator [] (size_t pos) device 24 | { 25 | return elements[pos]; 26 | } 27 | constexpr const device T& operator [] (size_t pos) const device 28 | { 29 | return elements[pos]; 30 | } 31 | 32 | constexpr const constant T& operator [] (size_t pos) const constant 33 | { 34 | return elements[pos]; 35 | } 36 | 37 | threadgroup T& operator [] (size_t pos) threadgroup 38 | { 39 | return elements[pos]; 40 | } 41 | constexpr const threadgroup T& operator [] (size_t pos) const threadgroup 42 | { 43 | return elements[pos]; 44 | } 45 | }; 46 | 47 | struct SpriteData 48 | { 49 | packed_float3 Position; 50 | float Rotation; 51 | float2 Scale; 52 | float2 Padding; 53 | float TexU; 54 | float TexV; 55 | float TexW; 56 | float TexH; 57 | float4 Color; 58 | }; 59 | 60 | struct type_StructuredBuffer_SpriteData 61 | { 62 | SpriteData _m0[1]; 63 | }; 64 | 65 | struct type_UniformBlock 66 | { 67 | float4x4 ViewProjectionMatrix; 68 | }; 69 | 70 | constant spvUnsafeArray _46 = spvUnsafeArray({ 0u, 1u, 2u, 3u, 2u, 1u }); 71 | constant spvUnsafeArray _51 = spvUnsafeArray({ float2(0.0), float2(1.0, 0.0), float2(0.0, 1.0), float2(1.0) }); 72 | 73 | struct main0_out 74 | { 75 | float2 out_var_TEXCOORD0 [[user(locn0)]]; 76 | float4 out_var_TEXCOORD1 [[user(locn1)]]; 77 | float4 gl_Position [[position]]; 78 | }; 79 | 80 | vertex main0_out main0(constant type_UniformBlock& UniformBlock [[buffer(0)]], const device type_StructuredBuffer_SpriteData& DataBuffer [[buffer(1)]], uint gl_VertexIndex [[vertex_id]]) 81 | { 82 | main0_out out = {}; 83 | uint _62 = gl_VertexIndex / 6u; 84 | uint _63 = gl_VertexIndex % 6u; 85 | float _82 = DataBuffer._m0[_62].TexU + DataBuffer._m0[_62].TexW; 86 | float _83 = DataBuffer._m0[_62].TexV + DataBuffer._m0[_62].TexH; 87 | spvUnsafeArray _88 = spvUnsafeArray({ float2(DataBuffer._m0[_62].TexU, DataBuffer._m0[_62].TexV), float2(_82, DataBuffer._m0[_62].TexV), float2(DataBuffer._m0[_62].TexU, _83), float2(_82, _83) }); 88 | spvUnsafeArray _60 = _88; 89 | float _89 = cos(DataBuffer._m0[_62].Rotation); 90 | float _90 = sin(DataBuffer._m0[_62].Rotation); 91 | out.out_var_TEXCOORD0 = _60[_46[_63]]; 92 | out.out_var_TEXCOORD1 = DataBuffer._m0[_62].Color; 93 | out.gl_Position = UniformBlock.ViewProjectionMatrix * float4((float2x2(float2(_89, _90), float2(-_90, _89)) * (_51[_46[_63]] * DataBuffer._m0[_62].Scale)) + float2(DataBuffer._m0[_62].Position[0], DataBuffer._m0[_62].Position[1]), DataBuffer._m0[_62].Position[2], 1.0); 94 | return out; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/RawTriangle.vert.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | constant float2 _25 = {}; 7 | constant float4 _26 = {}; 8 | 9 | struct main0_out 10 | { 11 | float4 out_var_TEXCOORD0 [[user(locn0)]]; 12 | float4 gl_Position [[position]]; 13 | }; 14 | 15 | vertex main0_out main0(uint gl_VertexIndex [[vertex_id]]) 16 | { 17 | main0_out out = {}; 18 | float4 _47; 19 | float2 _48; 20 | if (gl_VertexIndex == 0u) 21 | { 22 | _47 = float4(1.0, 0.0, 0.0, 1.0); 23 | _48 = float2(-1.0); 24 | } 25 | else 26 | { 27 | float4 _45; 28 | float2 _46; 29 | if (gl_VertexIndex == 1u) 30 | { 31 | _45 = float4(0.0, 1.0, 0.0, 1.0); 32 | _46 = float2(1.0, -1.0); 33 | } 34 | else 35 | { 36 | bool _40 = gl_VertexIndex == 2u; 37 | _45 = select(_26, float4(0.0, 0.0, 1.0, 1.0), bool4(_40)); 38 | _46 = select(_25, float2(0.0, 1.0), bool2(_40)); 39 | } 40 | _47 = _45; 41 | _48 = _46; 42 | } 43 | out.out_var_TEXCOORD0 = _47; 44 | out.gl_Position = float4(_48, 0.0, 1.0); 45 | return out; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/Skybox.frag.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float4 out_var_SV_Target0 [[color(0)]]; 9 | }; 10 | 11 | struct main0_in 12 | { 13 | float3 in_var_TEXCOORD0 [[user(locn0)]]; 14 | }; 15 | 16 | fragment main0_out main0(main0_in in [[stage_in]], texturecube SkyboxTexture [[texture(0)]], sampler SkyboxSampler [[sampler(0)]]) 17 | { 18 | main0_out out = {}; 19 | out.out_var_SV_Target0 = SkyboxTexture.sample(SkyboxSampler, in.in_var_TEXCOORD0); 20 | return out; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/Skybox.vert.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct type_UniformBlock 7 | { 8 | float4x4 MatrixTransform; 9 | }; 10 | 11 | struct main0_out 12 | { 13 | float3 out_var_TEXCOORD0 [[user(locn0)]]; 14 | float4 gl_Position [[position]]; 15 | }; 16 | 17 | struct main0_in 18 | { 19 | float3 in_var_TEXCOORD0 [[attribute(0)]]; 20 | }; 21 | 22 | vertex main0_out main0(main0_in in [[stage_in]], constant type_UniformBlock& UniformBlock [[buffer(0)]]) 23 | { 24 | main0_out out = {}; 25 | out.out_var_TEXCOORD0 = in.in_var_TEXCOORD0; 26 | out.gl_Position = UniformBlock.MatrixTransform * float4(in.in_var_TEXCOORD0, 1.0); 27 | return out; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/SolidColor.frag.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float4 out_var_SV_Target0 [[color(0)]]; 9 | }; 10 | 11 | struct main0_in 12 | { 13 | float4 in_var_TEXCOORD0 [[user(locn0)]]; 14 | }; 15 | 16 | fragment main0_out main0(main0_in in [[stage_in]]) 17 | { 18 | main0_out out = {}; 19 | out.out_var_SV_Target0 = in.in_var_TEXCOORD0; 20 | return out; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/SolidColorDepth.frag.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct type_UBO 7 | { 8 | float NearPlane; 9 | float FarPlane; 10 | }; 11 | 12 | struct main0_out 13 | { 14 | float4 out_var_SV_Target0 [[color(0)]]; 15 | float gl_FragDepth [[depth(any)]]; 16 | }; 17 | 18 | struct main0_in 19 | { 20 | float4 in_var_TEXCOORD0 [[user(locn0)]]; 21 | }; 22 | 23 | fragment main0_out main0(main0_in in [[stage_in]], constant type_UBO& UBO [[buffer(0)]], float4 gl_FragCoord [[position]]) 24 | { 25 | main0_out out = {}; 26 | out.out_var_SV_Target0 = in.in_var_TEXCOORD0; 27 | out.gl_FragDepth = (((2.0 * UBO.NearPlane) * UBO.FarPlane) / ((UBO.FarPlane + UBO.NearPlane) - (((gl_FragCoord.z * 2.0) - 1.0) * (UBO.FarPlane - UBO.NearPlane)))) / UBO.FarPlane; 28 | return out; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/SpriteBatch.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct SpriteComputeData 7 | { 8 | packed_float3 Position; 9 | float Rotation; 10 | float2 Scale; 11 | float2 Padding; 12 | float TexU; 13 | float TexV; 14 | float TexW; 15 | float TexH; 16 | float4 Color; 17 | }; 18 | 19 | struct type_StructuredBuffer_SpriteComputeData 20 | { 21 | SpriteComputeData _m0[1]; 22 | }; 23 | 24 | struct SpriteVertex 25 | { 26 | float4 Position; 27 | float2 Texcoord; 28 | float4 Color; 29 | }; 30 | 31 | struct type_RWStructuredBuffer_SpriteVertex 32 | { 33 | SpriteVertex _m0[1]; 34 | }; 35 | 36 | kernel void main0(const device type_StructuredBuffer_SpriteComputeData& ComputeBuffer [[buffer(0)]], device type_RWStructuredBuffer_SpriteVertex& VertexBuffer [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 37 | { 38 | float3 _54 = float3(ComputeBuffer._m0[gl_GlobalInvocationID.x].Position); 39 | float _56 = ComputeBuffer._m0[gl_GlobalInvocationID.x].Rotation; 40 | float2 _58 = ComputeBuffer._m0[gl_GlobalInvocationID.x].Scale; 41 | float _60 = ComputeBuffer._m0[gl_GlobalInvocationID.x].TexU; 42 | float _62 = ComputeBuffer._m0[gl_GlobalInvocationID.x].TexV; 43 | float _64 = ComputeBuffer._m0[gl_GlobalInvocationID.x].TexW; 44 | float _66 = ComputeBuffer._m0[gl_GlobalInvocationID.x].TexH; 45 | float4 _68 = ComputeBuffer._m0[gl_GlobalInvocationID.x].Color; 46 | float _74 = cos(_56); 47 | float _75 = sin(_56); 48 | float4x4 _86 = (float4x4(float4(1.0, 0.0, 0.0, 0.0), float4(0.0, 1.0, 0.0, 0.0), float4(0.0, 0.0, 1.0, 0.0), float4(_54, 1.0)) * float4x4(float4(_74, _75, 0.0, 0.0), float4(-_75, _74, 0.0, 0.0), float4(0.0, 0.0, 1.0, 0.0), float4(0.0, 0.0, 0.0, 1.0))) * float4x4(float4(_58.x, 0.0, 0.0, 0.0), float4(0.0, _58.y, 0.0, 0.0), float4(0.0, 0.0, 1.0, 0.0), float4(0.0, 0.0, 0.0, 1.0)); 49 | uint _88 = gl_GlobalInvocationID.x * 4u; 50 | VertexBuffer._m0[_88].Position = _86 * float4(0.0, 0.0, 0.0, 1.0); 51 | uint _91 = _88 + 1u; 52 | VertexBuffer._m0[_91].Position = _86 * float4(1.0, 0.0, 0.0, 1.0); 53 | uint _94 = _88 + 2u; 54 | VertexBuffer._m0[_94].Position = _86 * float4(0.0, 1.0, 0.0, 1.0); 55 | uint _97 = _88 + 3u; 56 | VertexBuffer._m0[_97].Position = _86 * float4(1.0, 1.0, 0.0, 1.0); 57 | VertexBuffer._m0[_88].Texcoord = float2(_60, _62); 58 | float _101 = _60 + _64; 59 | VertexBuffer._m0[_91].Texcoord = float2(_101, _62); 60 | float _104 = _62 + _66; 61 | VertexBuffer._m0[_94].Texcoord = float2(_60, _104); 62 | VertexBuffer._m0[_97].Texcoord = float2(_101, _104); 63 | VertexBuffer._m0[_88].Color = _68; 64 | VertexBuffer._m0[_91].Color = _68; 65 | VertexBuffer._m0[_94].Color = _68; 66 | VertexBuffer._m0[_97].Color = _68; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/TexturedQuad.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct type_UBO 7 | { 8 | float ubo_texcoord_multiplier; 9 | }; 10 | 11 | kernel void main0(constant type_UBO& UBO [[buffer(0)]], texture2d inImage [[texture(0)]], texture2d outImage [[texture(1)]], sampler inImageSampler [[sampler(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 12 | { 13 | uint2 _33 = uint2(inImage.get_width(), inImage.get_height()); 14 | int2 _39 = int2(gl_GlobalInvocationID.xy); 15 | outImage.write(inImage.sample(inImageSampler, ((float2(_39) * UBO.ubo_texcoord_multiplier) / float2(float(_33.x), float(_33.y))), level(0.0)), uint2(uint2(_39))); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/TexturedQuad.frag.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float4 out_var_SV_Target0 [[color(0)]]; 9 | }; 10 | 11 | struct main0_in 12 | { 13 | float2 in_var_TEXCOORD0 [[user(locn0)]]; 14 | }; 15 | 16 | fragment main0_out main0(main0_in in [[stage_in]], texture2d Texture [[texture(0)]], sampler Sampler [[sampler(0)]]) 17 | { 18 | main0_out out = {}; 19 | out.out_var_SV_Target0 = Texture.sample(Sampler, in.in_var_TEXCOORD0); 20 | return out; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/TexturedQuad.vert.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float2 out_var_TEXCOORD0 [[user(locn0)]]; 9 | float4 gl_Position [[position]]; 10 | }; 11 | 12 | struct main0_in 13 | { 14 | float3 in_var_TEXCOORD0 [[attribute(0)]]; 15 | float2 in_var_TEXCOORD1 [[attribute(1)]]; 16 | }; 17 | 18 | vertex main0_out main0(main0_in in [[stage_in]]) 19 | { 20 | main0_out out = {}; 21 | out.out_var_TEXCOORD0 = in.in_var_TEXCOORD1; 22 | out.gl_Position = float4(in.in_var_TEXCOORD0, 1.0); 23 | return out; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/TexturedQuadArray.frag.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float4 out_var_SV_Target0 [[color(0)]]; 9 | }; 10 | 11 | struct main0_in 12 | { 13 | float2 in_var_TEXCOORD0 [[user(locn0)]]; 14 | }; 15 | 16 | fragment main0_out main0(main0_in in [[stage_in]], texture2d_array Texture [[texture(0)]], sampler Sampler [[sampler(0)]]) 17 | { 18 | main0_out out = {}; 19 | float3 _35 = float3(in.in_var_TEXCOORD0, float(uint(int(in.in_var_TEXCOORD0.y > 0.5)))); 20 | out.out_var_SV_Target0 = Texture.sample(Sampler, _35.xy, uint(rint(_35.z))); 21 | return out; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/TexturedQuadColor.frag.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct main0_out 7 | { 8 | float4 out_var_SV_Target0 [[color(0)]]; 9 | }; 10 | 11 | struct main0_in 12 | { 13 | float2 in_var_TEXCOORD0 [[user(locn0)]]; 14 | float4 in_var_TEXCOORD1 [[user(locn1)]]; 15 | }; 16 | 17 | fragment main0_out main0(main0_in in [[stage_in]], texture2d Texture [[texture(0)]], sampler Sampler [[sampler(0)]]) 18 | { 19 | main0_out out = {}; 20 | out.out_var_SV_Target0 = in.in_var_TEXCOORD1 * Texture.sample(Sampler, in.in_var_TEXCOORD0); 21 | return out; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/TexturedQuadColorWithMatrix.vert.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct type_UniformBlock 7 | { 8 | float4x4 MatrixTransform; 9 | }; 10 | 11 | struct main0_out 12 | { 13 | float2 out_var_TEXCOORD0 [[user(locn0)]]; 14 | float4 out_var_TEXCOORD1 [[user(locn1)]]; 15 | float4 gl_Position [[position]]; 16 | }; 17 | 18 | struct main0_in 19 | { 20 | float4 in_var_TEXCOORD0 [[attribute(0)]]; 21 | float2 in_var_TEXCOORD1 [[attribute(1)]]; 22 | float4 in_var_TEXCOORD2 [[attribute(2)]]; 23 | }; 24 | 25 | vertex main0_out main0(main0_in in [[stage_in]], constant type_UniformBlock& UniformBlock [[buffer(0)]]) 26 | { 27 | main0_out out = {}; 28 | out.out_var_TEXCOORD0 = in.in_var_TEXCOORD1; 29 | out.out_var_TEXCOORD1 = in.in_var_TEXCOORD2; 30 | out.gl_Position = UniformBlock.MatrixTransform * in.in_var_TEXCOORD0; 31 | return out; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/TexturedQuadWithMatrix.vert.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct type_UniformBlock 7 | { 8 | float4x4 MatrixTransform; 9 | }; 10 | 11 | struct main0_out 12 | { 13 | float2 out_var_TEXCOORD0 [[user(locn0)]]; 14 | float4 gl_Position [[position]]; 15 | }; 16 | 17 | struct main0_in 18 | { 19 | float4 in_var_TEXCOORD0 [[attribute(0)]]; 20 | float2 in_var_TEXCOORD1 [[attribute(1)]]; 21 | }; 22 | 23 | vertex main0_out main0(main0_in in [[stage_in]], constant type_UniformBlock& UniformBlock [[buffer(0)]]) 24 | { 25 | main0_out out = {}; 26 | out.out_var_TEXCOORD0 = in.in_var_TEXCOORD1; 27 | out.gl_Position = UniformBlock.MatrixTransform * in.in_var_TEXCOORD0; 28 | return out; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/TexturedQuadWithMultiplyColor.frag.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | struct type_UniformBlock 7 | { 8 | float4 MultiplyColor; 9 | }; 10 | 11 | struct main0_out 12 | { 13 | float4 out_var_SV_Target0 [[color(0)]]; 14 | }; 15 | 16 | struct main0_in 17 | { 18 | float2 in_var_TEXCOORD0 [[user(locn0)]]; 19 | }; 20 | 21 | fragment main0_out main0(main0_in in [[stage_in]], constant type_UniformBlock& UniformBlock [[buffer(0)]], texture2d Texture [[texture(0)]], sampler Sampler [[sampler(0)]]) 22 | { 23 | main0_out out = {}; 24 | out.out_var_SV_Target0 = UniformBlock.MultiplyColor * Texture.sample(Sampler, in.in_var_TEXCOORD0); 25 | return out; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/ToneMapACES.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | kernel void main0(texture2d inImage [[texture(0)]], texture2d outImage [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 7 | { 8 | uint2 _62 = uint2(int2(gl_GlobalInvocationID.xy)); 9 | float3 _66 = inImage.read(uint2(_62), 0u).xyz * float3x3(float3(0.59719002246856689453125, 0.354579985141754150390625, 0.048229999840259552001953125), float3(0.075999997556209564208984375, 0.908339977264404296875, 0.0156599991023540496826171875), float3(0.0284000001847743988037109375, 0.13382999598979949951171875, 0.837769985198974609375)); 10 | outImage.write(float4((((_66 * (_66 + float3(0.02457859925925731658935546875))) - float3(9.0537003416102379560470581054688e-05)) / ((_66 * ((_66 * 0.98372900485992431640625) + float3(0.4329510033130645751953125))) + float3(0.23808099329471588134765625))) * float3x3(float3(1.60475003719329833984375, -0.5310800075531005859375, -0.0736699998378753662109375), float3(-0.10208000242710113525390625, 1.108129978179931640625, -0.00604999996721744537353515625), float3(-0.00326999998651444911956787109375, -0.07276000082492828369140625, 1.0760200023651123046875)), 1.0), uint2(_62)); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/ToneMapExtendedReinhardLuminance.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | kernel void main0(texture2d inImage [[texture(0)]], texture2d outImage [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 7 | { 8 | uint2 _31 = uint2(int2(gl_GlobalInvocationID.xy)); 9 | float3 _34 = inImage.read(uint2(_31), 0u).xyz; 10 | float _35 = dot(_34, float3(0.2125999927520751953125, 0.715200006961822509765625, 0.072200000286102294921875)); 11 | outImage.write(float4(_34 * (((_35 * (1.0 + (_35 * 2.2818337583885295316576957702637e-06))) / (1.0 + _35)) / _35), 1.0), uint2(_31)); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/ToneMapHable.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | kernel void main0(texture2d inImage [[texture(0)]], texture2d outImage [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 7 | { 8 | uint2 _40 = uint2(int2(gl_GlobalInvocationID.xy)); 9 | float3 _44 = inImage.read(uint2(_40), 0u).xyz * 2.0; 10 | float3 _45 = _44 * 0.1500000059604644775390625; 11 | outImage.write(float4(((((_44 * (_45 + float3(0.0500000007450580596923828125))) + float3(0.0040000001899898052215576171875)) / ((_44 * (_45 + float3(0.5))) + float3(0.060000002384185791015625))) - float3(0.066666662693023681640625)) * float3(1.3790643215179443359375), 1.0), uint2(_40)); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/MSL/ToneMapReinhard.comp.msl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace metal; 5 | 6 | kernel void main0(texture2d inImage [[texture(0)]], texture2d outImage [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) 7 | { 8 | uint2 _27 = uint2(int2(gl_GlobalInvocationID.xy)); 9 | float3 _30 = inImage.read(uint2(_27), 0u).xyz; 10 | outImage.write(float4(_30 / (float3(1.0) + _30), 1.0), uint2(_27)); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/CustomSampling.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/CustomSampling.frag.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/DepthOutline.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/DepthOutline.frag.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/FillTexture.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/FillTexture.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/Fullscreen.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/Fullscreen.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/GradientTexture.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/GradientTexture.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/LinearToSRGB.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/LinearToSRGB.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/LinearToST2084.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/LinearToST2084.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/PositionColor.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/PositionColor.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/PositionColorInstanced.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/PositionColorInstanced.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/PositionColorTransform.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/PositionColorTransform.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/PullSpriteBatch.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/PullSpriteBatch.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/RawTriangle.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/RawTriangle.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/Skybox.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/Skybox.frag.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/Skybox.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/Skybox.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/SolidColor.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/SolidColor.frag.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/SolidColorDepth.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/SolidColorDepth.frag.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/SpriteBatch.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/SpriteBatch.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/TexturedQuad.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/TexturedQuad.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/TexturedQuad.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/TexturedQuad.frag.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/TexturedQuad.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/TexturedQuad.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/TexturedQuadArray.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/TexturedQuadArray.frag.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/TexturedQuadColor.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/TexturedQuadColor.frag.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/TexturedQuadColorWithMatrix.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/TexturedQuadColorWithMatrix.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/TexturedQuadWithMatrix.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/TexturedQuadWithMatrix.vert.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/TexturedQuadWithMultiplyColor.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/TexturedQuadWithMultiplyColor.frag.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/ToneMapACES.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/ToneMapACES.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/ToneMapExtendedReinhardLuminance.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/ToneMapExtendedReinhardLuminance.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/ToneMapHable.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/ToneMapHable.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Compiled/SPIRV/ToneMapReinhard.comp.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klukaszek/sdl3-hs/3dc7e731321ff3f0b97b35f4ae50dc366b65334a/examples/Content/Shaders/Compiled/SPIRV/ToneMapReinhard.comp.spv -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/CustomSampling.frag.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UBO : register(b0, space3) 2 | { 3 | int mode : packoffset(c0); 4 | }; 5 | 6 | Texture2D Texture : register(t0, space2); 7 | 8 | float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0 9 | { 10 | float w, h; 11 | Texture.GetDimensions(w, h); 12 | int2 texelPos = int2(float2(w, h) * TexCoord); 13 | float4 mainTexel = Texture[texelPos]; 14 | if (mode == 0) 15 | { 16 | return mainTexel; 17 | } 18 | else 19 | { 20 | float4 bottomTexel = Texture[texelPos + int2(0, 1)]; 21 | float4 leftTexel = Texture[texelPos + int2(-1, 0)]; 22 | float4 topTexel = Texture[texelPos + int2(0, -1)]; 23 | float4 rightTexel = Texture[texelPos + int2(1, 0)]; 24 | return ((((mainTexel * 0.2f) + (bottomTexel * 0.2f)) + (leftTexel * 0.20000000298023223876953125f)) + (topTexel * 0.20000000298023223876953125f)) + (rightTexel * 0.2f); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/DepthOutline.frag.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D ColorTexture : register(t0, space2); 2 | SamplerState ColorSampler : register(s0, space2); 3 | 4 | Texture2D DepthTexture : register(t1, space2); 5 | SamplerState DepthSampler : register(s1, space2); 6 | 7 | // Gets the difference between a depth value and adjacent depth pixels 8 | // This is used to detect "edges", where the depth falls off. 9 | float GetDifference(float depth, float2 TexCoord, float distance) 10 | { 11 | float w, h; 12 | DepthTexture.GetDimensions(w, h); 13 | 14 | return 15 | max(DepthTexture.Sample(DepthSampler, TexCoord + float2(1.0 / w, 0) * distance).r - depth, 16 | max(DepthTexture.Sample(DepthSampler, TexCoord + float2(-1.0 / w, 0) * distance).r - depth, 17 | max(DepthTexture.Sample(DepthSampler, TexCoord + float2(0, 1.0 / h) * distance).r - depth, 18 | DepthTexture.Sample(DepthSampler, TexCoord + float2(0, -1.0 / h) * distance).r - depth))); 19 | } 20 | 21 | float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0 22 | { 23 | // get our color & depth value 24 | float4 color = ColorTexture.Sample(ColorSampler, TexCoord); 25 | float depth = DepthTexture.Sample(DepthSampler, TexCoord).r; 26 | 27 | // get the difference between the edges at 1px and 2px away 28 | float edge = step(0.2, GetDifference(depth, TexCoord, 1.0f)); 29 | float edge2 = step(0.2, GetDifference(depth, TexCoord, 2.0f)); 30 | 31 | // turn inner edges black 32 | float3 res = lerp(color.rgb, 0, edge2); 33 | 34 | // turn the outer edges white 35 | res = lerp(res, 1, edge); 36 | 37 | // combine results 38 | return float4(res, color.a); 39 | } 40 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/FillTexture.comp.hlsl: -------------------------------------------------------------------------------- 1 | RWTexture2D outImage : register(u0, space1); 2 | 3 | [numthreads(8, 8, 1)] 4 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 5 | { 6 | int2 coord = int2(GlobalInvocationID.xy); 7 | outImage[coord] = float4(1.0f, 1.0f, 0.0f, 1.0f); 8 | } 9 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/Fullscreen.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct Output 2 | { 3 | float2 TexCoord : TEXCOORD0; 4 | float4 Position : SV_Position; 5 | }; 6 | 7 | Output main(uint VertexIndex : SV_VertexID) 8 | { 9 | Output output; 10 | output.TexCoord = float2(float((VertexIndex << 1) & 2), float(VertexIndex & 2)); 11 | output.Position = float4((output.TexCoord * float2(2.0f, -2.0f)) + float2(-1.0f, 1.0f), 0.0f, 1.0f); 12 | return output; 13 | } 14 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/GradientTexture.comp.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UBO : register(b0, space2) 2 | { 3 | float ubo_time : packoffset(c0); 4 | }; 5 | 6 | RWTexture2D OutImage : register(u0, space1); 7 | 8 | uint2 spvImageSize(RWTexture2D Tex, out uint Param) 9 | { 10 | uint2 ret; 11 | Tex.GetDimensions(ret.x, ret.y); 12 | Param = 0u; 13 | return ret; 14 | } 15 | 16 | [numthreads(8, 8, 1)] 17 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 18 | { 19 | float w, h; 20 | OutImage.GetDimensions(w, h); 21 | float2 size = float2(w, h); 22 | float2 coord = float2(GlobalInvocationID.xy); 23 | float2 uv = coord / size; 24 | 25 | float3 col = 0.5f.xxx + (cos((ubo_time.xxx + uv.xyx) + float3(0.0f, 2.0f, 4.0f)) * 0.5f); 26 | OutImage[int2(coord)] = float4(col, 1.0f); 27 | } 28 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/LinearToSRGB.comp.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D InImage : register(t0, space0); 2 | RWTexture2D OutImage : register(u0, space1); 3 | 4 | float3 LinearToSRGB(float3 color) 5 | { 6 | return pow(abs(color), float(1.0f/2.2f).xxx); 7 | } 8 | 9 | [numthreads(8, 8, 1)] 10 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 11 | { 12 | int2 coord = int2(GlobalInvocationID.xy); 13 | float4 inPixel = InImage[coord]; 14 | float3 param = inPixel.xyz; 15 | float3 outColor = LinearToSRGB(param); 16 | OutImage[coord] = float4(outColor, 1.0f); 17 | } 18 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/LinearToST2084.comp.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D InImage : register(t0, space0); 2 | RWTexture2D OutImage : register(u0, space1); 3 | 4 | float3 NormalizeHDRSceneValue(float3 hdrSceneValue, float paperWhiteNits) 5 | { 6 | return (hdrSceneValue * paperWhiteNits) / 10000.0f.xxx; 7 | } 8 | 9 | float3 LinearToST2084(float3 normalizedLinearValue) 10 | { 11 | return pow((0.8359375f.xxx + (pow(abs(normalizedLinearValue), 0.1593017578125f.xxx) * 18.8515625f)) / (1.0f.xxx + (pow(abs(normalizedLinearValue), 0.1593017578125f.xxx) * 18.6875f)), 78.84375f.xxx); 12 | } 13 | 14 | float4 ConvertToHDR10(float4 hdrSceneValue, float paperWhiteNits) 15 | { 16 | float3 rec2020 = mul(float3x3(float3(0.6274039745330810546875f, 0.329281985759735107421875f, 0.043313600122928619384765625f), float3(0.06909699738025665283203125f, 0.919539988040924072265625f, 0.0113612003624439239501953125f), float3(0.01639159955084323883056640625f, 0.0880132019519805908203125f, 0.895595014095306396484375f)), hdrSceneValue.xyz); 17 | float3 normalizedLinearValue = NormalizeHDRSceneValue(rec2020, paperWhiteNits); 18 | float3 HDR10 = LinearToST2084(normalizedLinearValue); 19 | return float4(HDR10, hdrSceneValue.w); 20 | } 21 | 22 | [numthreads(8, 8, 1)] 23 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 24 | { 25 | int2 coord = int2(GlobalInvocationID.xy); 26 | float4 inPixel = InImage[coord]; 27 | OutImage[coord] = ConvertToHDR10(inPixel, 200.0f); 28 | } 29 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/PositionColor.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct Input 2 | { 3 | float3 Position : TEXCOORD0; 4 | float4 Color : TEXCOORD1; 5 | }; 6 | 7 | struct Output 8 | { 9 | float4 Color : TEXCOORD0; 10 | float4 Position : SV_Position; 11 | }; 12 | 13 | Output main(Input input) 14 | { 15 | Output output; 16 | output.Color = input.Color; 17 | output.Position = float4(input.Position, 1.0f); 18 | return output; 19 | } 20 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/PositionColorInstanced.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct Input 2 | { 3 | float3 Position : TEXCOORD0; 4 | float4 Color : TEXCOORD1; 5 | uint InstanceIndex : SV_InstanceID; 6 | }; 7 | 8 | struct Output 9 | { 10 | float4 Color : TEXCOORD0; 11 | float4 Position : SV_Position; 12 | }; 13 | 14 | Output main(Input input) 15 | { 16 | Output output; 17 | output.Color = input.Color; 18 | float3 pos = (input.Position * 0.25f) - float3(0.75f, 0.75f, 0.0f); 19 | pos.x += (float(input.InstanceIndex % 4) * 0.5f); 20 | pos.y += (floor(float(input.InstanceIndex / 4)) * 0.5f); 21 | output.Position = float4(pos, 1.0f); 22 | return output; 23 | } 24 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/PositionColorTransform.vert.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UBO : register(b0, space1) 2 | { 3 | float4x4 transform : packoffset(c0); 4 | }; 5 | 6 | struct Input 7 | { 8 | float3 Position : TEXCOORD0; 9 | float4 Color : TEXCOORD1; 10 | }; 11 | 12 | struct Output 13 | { 14 | float4 Color : TEXCOORD0; 15 | float4 Position : SV_Position; 16 | }; 17 | 18 | Output main(Input input) 19 | { 20 | Output output; 21 | output.Color = input.Color; 22 | output.Position = mul(transform, float4(input.Position, 1.0f)); 23 | return output; 24 | } 25 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/PullSpriteBatch.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct SpriteData 2 | { 3 | float3 Position; 4 | float Rotation; 5 | float2 Scale; 6 | float2 Padding; 7 | float TexU, TexV, TexW, TexH; 8 | float4 Color; 9 | }; 10 | 11 | struct Output 12 | { 13 | float2 Texcoord : TEXCOORD0; 14 | float4 Color : TEXCOORD1; 15 | float4 Position : SV_Position; 16 | }; 17 | 18 | StructuredBuffer DataBuffer : register(t0, space0); 19 | 20 | cbuffer UniformBlock : register(b0, space1) 21 | { 22 | float4x4 ViewProjectionMatrix : packoffset(c0); 23 | }; 24 | 25 | static const uint triangleIndices[6] = {0, 1, 2, 3, 2, 1}; 26 | static const float2 vertexPos[4] = { 27 | {0.0f, 0.0f}, 28 | {1.0f, 0.0f}, 29 | {0.0f, 1.0f}, 30 | {1.0f, 1.0f} 31 | }; 32 | 33 | Output main(uint id : SV_VertexID) 34 | { 35 | uint spriteIndex = id / 6; 36 | uint vert = triangleIndices[id % 6]; 37 | SpriteData sprite = DataBuffer[spriteIndex]; 38 | 39 | float2 texcoord[4] = { 40 | {sprite.TexU, sprite.TexV }, 41 | {sprite.TexU + sprite.TexW, sprite.TexV }, 42 | {sprite.TexU, sprite.TexV + sprite.TexH}, 43 | {sprite.TexU + sprite.TexW, sprite.TexV + sprite.TexH} 44 | }; 45 | 46 | float c = cos(sprite.Rotation); 47 | float s = sin(sprite.Rotation); 48 | 49 | float2 coord = vertexPos[vert]; 50 | coord *= sprite.Scale; 51 | float2x2 rotation = {c, s, -s, c}; 52 | coord = mul(coord, rotation); 53 | 54 | float3 coordWithDepth = float3(coord + sprite.Position.xy, sprite.Position.z); 55 | 56 | Output output; 57 | 58 | output.Position = mul(ViewProjectionMatrix, float4(coordWithDepth, 1.0f)); 59 | output.Texcoord = texcoord[vert]; 60 | output.Color = sprite.Color; 61 | 62 | return output; 63 | } 64 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/RawTriangle.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct Input 2 | { 3 | uint VertexIndex : SV_VertexID; 4 | }; 5 | 6 | struct Output 7 | { 8 | float4 Color : TEXCOORD0; 9 | float4 Position : SV_Position; 10 | }; 11 | 12 | Output main(Input input) 13 | { 14 | Output output; 15 | float2 pos; 16 | if (input.VertexIndex == 0) 17 | { 18 | pos = (-1.0f).xx; 19 | output.Color = float4(1.0f, 0.0f, 0.0f, 1.0f); 20 | } 21 | else 22 | { 23 | if (input.VertexIndex == 1) 24 | { 25 | pos = float2(1.0f, -1.0f); 26 | output.Color = float4(0.0f, 1.0f, 0.0f, 1.0f); 27 | } 28 | else 29 | { 30 | if (input.VertexIndex == 2) 31 | { 32 | pos = float2(0.0f, 1.0f); 33 | output.Color = float4(0.0f, 0.0f, 1.0f, 1.0f); 34 | } 35 | } 36 | } 37 | output.Position = float4(pos, 0.0f, 1.0f); 38 | return output; 39 | } 40 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/Skybox.frag.hlsl: -------------------------------------------------------------------------------- 1 | TextureCube SkyboxTexture : register(t0, space2); 2 | SamplerState SkyboxSampler : register(s0, space2); 3 | 4 | float4 main(float3 TexCoord : TEXCOORD0) : SV_Target0 5 | { 6 | return SkyboxTexture.Sample(SkyboxSampler, TexCoord); 7 | } 8 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/Skybox.vert.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space1) 2 | { 3 | float4x4 MatrixTransform : packoffset(c0); 4 | }; 5 | 6 | struct SPIRV_Cross_Input 7 | { 8 | float3 inTexCoord : TEXCOORD0; 9 | }; 10 | 11 | struct Output 12 | { 13 | float3 TexCoord : TEXCOORD0; 14 | float4 Position : SV_Position; 15 | }; 16 | 17 | Output main(float3 inTexCoord : TEXCOORD0) 18 | { 19 | Output output; 20 | output.TexCoord = inTexCoord; 21 | output.Position = mul(MatrixTransform, float4(inTexCoord, 1.0)); 22 | return output; 23 | } 24 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/SolidColor.frag.hlsl: -------------------------------------------------------------------------------- 1 | float4 main(float4 Color : TEXCOORD0) : SV_Target0 2 | { 3 | return Color; 4 | } 5 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/SolidColorDepth.frag.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UBO : register(b0, space3) 2 | { 3 | float NearPlane; 4 | float FarPlane; 5 | }; 6 | 7 | struct Output 8 | { 9 | float4 Color : SV_Target0; 10 | float Depth : SV_Depth; 11 | }; 12 | 13 | float LinearizeDepth(float depth, float near, float far) 14 | { 15 | float z = depth * 2.0 - 1.0; 16 | return ((2.0 * near * far) / (far + near - z * (far - near))) / far; 17 | } 18 | 19 | Output main(float4 Color : TEXCOORD0, float4 Position : SV_Position) 20 | { 21 | Output result; 22 | result.Color = Color; 23 | result.Depth = LinearizeDepth(Position.z, NearPlane, FarPlane); 24 | return result; 25 | } 26 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/SpriteBatch.comp.hlsl: -------------------------------------------------------------------------------- 1 | struct SpriteComputeData 2 | { 3 | float3 Position; 4 | float Rotation; 5 | float2 Scale; 6 | float2 Padding; 7 | float TexU, TexV, TexW, TexH; 8 | float4 Color; 9 | }; 10 | 11 | struct SpriteVertex 12 | { 13 | float4 Position; 14 | float2 Texcoord; 15 | float4 Color; 16 | }; 17 | 18 | StructuredBuffer ComputeBuffer : register(t0, space0); 19 | RWStructuredBuffer VertexBuffer : register(u0, space1); 20 | 21 | [numthreads(64, 1, 1)] 22 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 23 | { 24 | uint n = GlobalInvocationID.x; 25 | 26 | SpriteComputeData sprite = ComputeBuffer[n]; 27 | 28 | float4x4 Scale = float4x4( 29 | float4(sprite.Scale.x, 0.0f, 0.0f, 0.0f), 30 | float4(0.0f, sprite.Scale.y, 0.0f, 0.0f), 31 | float4(0.0f, 0.0f, 1.0f, 0.0f), 32 | float4(0.0f, 0.0f, 0.0f, 1.0f) 33 | ); 34 | 35 | float c = cos(sprite.Rotation); 36 | float s = sin(sprite.Rotation); 37 | 38 | float4x4 Rotation = float4x4( 39 | float4( c, s, 0.0f, 0.0f), 40 | float4( -s, c, 0.0f, 0.0f), 41 | float4(0.0f, 0.0f, 1.0f, 0.0f), 42 | float4(0.0f, 0.0f, 0.0f, 1.0f) 43 | ); 44 | 45 | float4x4 Translation = float4x4( 46 | float4(1.0f, 0.0f, 0.0f, 0.0f), 47 | float4(0.0f, 1.0f, 0.0f, 0.0f), 48 | float4(0.0f, 0.0f, 1.0f, 0.0f), 49 | float4(sprite.Position.x, sprite.Position.y, sprite.Position.z, 1.0f) 50 | ); 51 | 52 | float4x4 Model = mul(Scale, mul(Rotation, Translation)); 53 | 54 | float4 topLeft = float4(0.0f, 0.0f, 0.0f, 1.0f); 55 | float4 topRight = float4(1.0f, 0.0f, 0.0f, 1.0f); 56 | float4 bottomLeft = float4(0.0f, 1.0f, 0.0f, 1.0f); 57 | float4 bottomRight = float4(1.0f, 1.0f, 0.0f, 1.0f); 58 | 59 | VertexBuffer[n * 4u] .Position = mul(topLeft, Model); 60 | VertexBuffer[n * 4u + 1].Position = mul(topRight, Model); 61 | VertexBuffer[n * 4u + 2].Position = mul(bottomLeft, Model); 62 | VertexBuffer[n * 4u + 3].Position = mul(bottomRight, Model); 63 | 64 | VertexBuffer[n * 4u] .Texcoord = float2(sprite.TexU, sprite.TexV); 65 | VertexBuffer[n * 4u + 1].Texcoord = float2(sprite.TexU + sprite.TexW, sprite.TexV); 66 | VertexBuffer[n * 4u + 2].Texcoord = float2(sprite.TexU, sprite.TexV + sprite.TexH); 67 | VertexBuffer[n * 4u + 3].Texcoord = float2(sprite.TexU + sprite.TexW, sprite.TexV + sprite.TexH); 68 | 69 | VertexBuffer[n * 4u] .Color = sprite.Color; 70 | VertexBuffer[n * 4u + 1].Color = sprite.Color; 71 | VertexBuffer[n * 4u + 2].Color = sprite.Color; 72 | VertexBuffer[n * 4u + 3].Color = sprite.Color; 73 | } 74 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/TexturedQuad.comp.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UBO : register(b0, space2) 2 | { 3 | float ubo_texcoord_multiplier : packoffset(c0); 4 | }; 5 | 6 | Texture2D inImage : register(t0, space0); 7 | SamplerState inImageSampler : register(s0, space0); 8 | RWTexture2D outImage : register(u0, space1); 9 | 10 | [numthreads(8, 8, 1)] 11 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 12 | { 13 | float w, h; 14 | inImage.GetDimensions(w, h); 15 | int2 coord = int2(GlobalInvocationID.xy); 16 | float2 texcoord = (float2(coord) * ubo_texcoord_multiplier) / float2(w, h); 17 | float4 inPixel = inImage.SampleLevel(inImageSampler, texcoord, 0.0f); 18 | outImage[coord] = inPixel; 19 | } 20 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/TexturedQuad.frag.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D Texture : register(t0, space2); 2 | SamplerState Sampler : register(s0, space2); 3 | 4 | float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0 5 | { 6 | return Texture.Sample(Sampler, TexCoord); 7 | } 8 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/TexturedQuad.vert.hlsl: -------------------------------------------------------------------------------- 1 | struct Input 2 | { 3 | float3 Position : TEXCOORD0; 4 | float2 TexCoord : TEXCOORD1; 5 | }; 6 | 7 | struct Output 8 | { 9 | float2 TexCoord : TEXCOORD0; 10 | float4 Position : SV_Position; 11 | }; 12 | 13 | Output main(Input input) 14 | { 15 | Output output; 16 | output.TexCoord = input.TexCoord; 17 | output.Position = float4(input.Position, 1.0f); 18 | return output; 19 | } 20 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/TexturedQuadArray.frag.hlsl: -------------------------------------------------------------------------------- 1 | Texture2DArray Texture : register(t0, space2); 2 | SamplerState Sampler : register(s0, space2); 3 | 4 | float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0 5 | { 6 | uint arrayIndex = uint(int(TexCoord.y > 0.5f)); 7 | return Texture.Sample(Sampler, float3(TexCoord, float(arrayIndex))); 8 | } 9 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/TexturedQuadColor.frag.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D Texture : register(t0, space2); 2 | SamplerState Sampler : register(s0, space2); 3 | 4 | struct Input 5 | { 6 | float2 TexCoord : TEXCOORD0; 7 | float4 Color : TEXCOORD1; 8 | }; 9 | 10 | float4 main(Input input) : SV_Target0 11 | { 12 | return input.Color * Texture.Sample(Sampler, input.TexCoord); 13 | } 14 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/TexturedQuadColorWithMatrix.vert.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space1) 2 | { 3 | float4x4 MatrixTransform : packoffset(c0); 4 | }; 5 | 6 | struct Input 7 | { 8 | float4 Position : TEXCOORD0; 9 | float2 TexCoord : TEXCOORD1; 10 | float4 Color : TEXCOORD2; 11 | }; 12 | 13 | struct Output 14 | { 15 | float2 TexCoord : TEXCOORD0; 16 | float4 Color : TEXCOORD1; 17 | float4 Position : SV_Position; 18 | }; 19 | 20 | Output main(Input input) 21 | { 22 | Output output; 23 | output.TexCoord = input.TexCoord; 24 | output.Color = input.Color; 25 | output.Position = mul(MatrixTransform, input.Position); 26 | return output; 27 | } 28 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/TexturedQuadWithMatrix.vert.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space1) 2 | { 3 | float4x4 MatrixTransform : packoffset(c0); 4 | }; 5 | 6 | struct Input 7 | { 8 | float4 Position : TEXCOORD0; 9 | float2 TexCoord : TEXCOORD1; 10 | }; 11 | 12 | struct Output 13 | { 14 | float2 TexCoord : TEXCOORD0; 15 | float4 Position : SV_Position; 16 | }; 17 | 18 | Output main(Input input) 19 | { 20 | Output output; 21 | output.TexCoord = input.TexCoord; 22 | output.Position = mul(MatrixTransform, input.Position); 23 | return output; 24 | } 25 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/TexturedQuadWithMultiplyColor.frag.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer UniformBlock : register(b0, space3) 2 | { 3 | float4 MultiplyColor : packoffset(c0); 4 | }; 5 | 6 | Texture2D Texture : register(t0, space2); 7 | SamplerState Sampler : register(s0, space2); 8 | 9 | float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0 10 | { 11 | return MultiplyColor * Texture.Sample(Sampler, TexCoord); 12 | } 13 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/ToneMapACES.comp.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D inImage : register(t0, space0); 2 | RWTexture2D outImage : register(u0, space1); 3 | 4 | float3 rtt_and_odt_fit(float3 v) 5 | { 6 | float3 a = (v * (v + 0.0245786f.xxx)) - 0.000090537f.xxx; 7 | float3 b = (v * ((v * 0.983729f) + 0.4329510f.xxx)) + 0.238081f.xxx; 8 | return a / b; 9 | } 10 | 11 | float3 aces_fitted(float3 v) 12 | { 13 | v = mul(float3x3(float3(0.59719f, 0.35458f, 0.04823f), float3(0.07600f, 0.90834f, 0.01566f), float3(0.02840f, 0.13383f, 0.83777f)), v); 14 | v = rtt_and_odt_fit(v); 15 | return mul(float3x3(float3(1.60475f, -0.53108f, -0.07367f), float3(-0.10208f, 1.10813f, -0.00605f), float3(-0.00327f, -0.07276f, 1.07602f)), v); 16 | } 17 | 18 | [numthreads(8, 8, 1)] 19 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 20 | { 21 | int2 coord = int2(GlobalInvocationID.xy); 22 | float4 inPixel = inImage[coord]; 23 | float3 outColor = aces_fitted(inPixel.xyz); 24 | outImage[coord] = float4(outColor, 1.0f); 25 | } 26 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/ToneMapExtendedReinhardLuminance.comp.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D inImage : register(t0, space0); 2 | RWTexture2D outImage : register(u0, space1); 3 | 4 | float luminance(float3 v) 5 | { 6 | return dot(v, float3(0.2126f, 0.7152f, 0.0722f)); 7 | } 8 | 9 | float3 change_luminance(float3 c_in, float l_out) 10 | { 11 | float l_in = luminance(c_in); 12 | return c_in * (l_out / l_in); 13 | } 14 | 15 | float3 reinhard_extended_luminance(float3 v, float max_white_l) 16 | { 17 | float l_old = luminance(v); 18 | float numerator = l_old * (1.0f + (l_old / (max_white_l * max_white_l))); 19 | float l_new = numerator / (1.0f + l_old); 20 | return change_luminance(v, l_new); 21 | } 22 | 23 | [numthreads(8, 8, 1)] 24 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 25 | { 26 | int2 coord = int2(GlobalInvocationID.xy); 27 | float4 inPixel = inImage[coord]; 28 | float3 outColor = reinhard_extended_luminance(inPixel.xyz, 662.0f); 29 | outImage[coord] = float4(outColor, 1.0f); 30 | } 31 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/ToneMapHable.comp.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D inImage : register(t0, space0); 2 | RWTexture2D outImage : register(u0, space1); 3 | 4 | float3 hable_tonemap_partial(float3 x) 5 | { 6 | float A = 0.15f; 7 | float B = 0.50f; 8 | float C = 0.10f; 9 | float D = 0.20f; 10 | float E = 0.02f; 11 | float F = 0.30f; 12 | return (((x * ((x * A) + (C * B).xxx)) + (D * E).xxx) / ((x * ((x * A) + B.xxx)) + (D * F).xxx)) - (E / F).xxx; 13 | } 14 | 15 | float3 hable_filmic(float3 v) 16 | { 17 | float exposure_bias = 2.0f; 18 | float3 curr = hable_tonemap_partial(v * exposure_bias); 19 | 20 | float3 W = 11.2f.xxx; 21 | float3 white_scale = 1.0f.xxx / hable_tonemap_partial(W); 22 | return curr * white_scale; 23 | } 24 | 25 | [numthreads(8, 8, 1)] 26 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 27 | { 28 | int2 coord = int2(GlobalInvocationID.xy); 29 | float4 inPixel = inImage[coord]; 30 | float3 outColor = hable_filmic(inPixel.xyz); 31 | outImage[coord] = float4(outColor, 1.0f); 32 | } 33 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/ToneMapReinhard.comp.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D inImage : register(t0, space0); 2 | RWTexture2D outImage : register(u0, space1); 3 | 4 | float3 reinhard(float3 v) 5 | { 6 | return v / (1.0f.xxx + v); 7 | } 8 | 9 | [numthreads(8, 8, 1)] 10 | void main(uint3 GlobalInvocationID : SV_DispatchThreadID) 11 | { 12 | int2 coord = int2(GlobalInvocationID.xy); 13 | float4 inPixel = inImage[coord]; 14 | float3 outColor = reinhard(inPixel.xyz); 15 | outImage[coord] = float4(outColor, 1.0f); 16 | } 17 | -------------------------------------------------------------------------------- /examples/Content/Shaders/Source/compile.sh: -------------------------------------------------------------------------------- 1 | # Requires shadercross CLI installed from SDL_shadercross 2 | for filename in *.vert.hlsl; do 3 | if [ -f "$filename" ]; then 4 | shadercross "$filename" -o "../Compiled/SPIRV/${filename/.hlsl/.spv}" 5 | shadercross "$filename" -o "../Compiled/MSL/${filename/.hlsl/.msl}" 6 | shadercross "$filename" -o "../Compiled/DXIL/${filename/.hlsl/.dxil}" 7 | fi 8 | done 9 | 10 | for filename in *.frag.hlsl; do 11 | if [ -f "$filename" ]; then 12 | shadercross "$filename" -o "../Compiled/SPIRV/${filename/.hlsl/.spv}" 13 | shadercross "$filename" -o "../Compiled/MSL/${filename/.hlsl/.msl}" 14 | shadercross "$filename" -o "../Compiled/DXIL/${filename/.hlsl/.dxil}" 15 | fi 16 | done 17 | 18 | for filename in *.comp.hlsl; do 19 | if [ -f "$filename" ]; then 20 | shadercross "$filename" -o "../Compiled/SPIRV/${filename/.hlsl/.spv}" 21 | shadercross "$filename" -o "../Compiled/MSL/${filename/.hlsl/.msl}" 22 | shadercross "$filename" -o "../Compiled/DXIL/${filename/.hlsl/.dxil}" 23 | fi 24 | done 25 | -------------------------------------------------------------------------------- /examples/DialogExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Control.Monad 4 | import Foreign.C.String (CString, peekCString, withCString) 5 | import Foreign.C.Types (CBool(..), CInt(..)) 6 | import Foreign.Marshal.Array (peekArray0, withArrayLen) 7 | import Foreign.Ptr (FunPtr, Ptr, castPtr, nullPtr) 8 | import Foreign.StablePtr (freeStablePtr, newStablePtr) 9 | import SDL 10 | import System.Exit (exitFailure, exitSuccess) 11 | 12 | main :: IO () 13 | main = do 14 | -- Initialize SDL 15 | initSuccess <- sdlInit [SDL_INIT_VIDEO] 16 | unless initSuccess $ do 17 | sdlLog "Failed to initialize SDL!" 18 | exitFailure 19 | 20 | -- Create a window for our dialog 21 | maybeWindow <- sdlCreateWindow 22 | "SDL Dialog Example" 23 | 800 24 | 600 25 | [SDL_WINDOW_RESIZABLE] 26 | 27 | case maybeWindow of 28 | Nothing -> do 29 | sdlLog "Failed to create window!" 30 | sdlQuit 31 | exitFailure 32 | Just window -> do 33 | -- Define some file filters 34 | let filters = 35 | [ SDLDialogFileFilter 36 | { filterName = "Text Files" 37 | , filterPattern = "txt;doc;md" 38 | } 39 | , SDLDialogFileFilter 40 | { filterName = "All Files" 41 | , filterPattern = "*" 42 | } 43 | ] 44 | 45 | -- Create our callback function 46 | let dialogCallback :: Ptr () -> Ptr CString -> CInt -> IO () 47 | dialogCallback userdata filelist filterIndex = do 48 | if filelist == nullPtr 49 | then sdlLog "Dialog was cancelled or error occurred" 50 | else do 51 | -- Get the list of files 52 | files <- peekArray0 nullPtr filelist 53 | fileNames <- mapM peekCString files 54 | sdlLog $ "Selected files (filter index " ++ show filterIndex ++ "):" 55 | mapM_ (sdlLog . (" - " ++)) fileNames 56 | 57 | -- Convert callback to stable pointer for C 58 | callbackPtr <- wrapDialogCallback dialogCallback 59 | 60 | -- Show different types of dialogs 61 | sdlLog "\nShowing Open File Dialog..." 62 | withFilters filters $ \filtersPtr nfilters -> 63 | sdlShowOpenFileDialog 64 | callbackPtr 65 | nullPtr 66 | (Just window) 67 | filtersPtr 68 | (fromIntegral nfilters) 69 | Nothing 70 | True 71 | 72 | sdlLog "\nShowing Save File Dialog..." 73 | withFilters filters $ \filtersPtr nfilters -> 74 | sdlShowSaveFileDialog 75 | callbackPtr 76 | nullPtr 77 | (Just window) 78 | filtersPtr 79 | (fromIntegral nfilters) 80 | Nothing 81 | 82 | sdlLog "\nShowing Folder Dialog..." 83 | sdlShowOpenFolderDialog 84 | callbackPtr 85 | nullPtr 86 | (Just window) 87 | Nothing 88 | False 89 | 90 | -- Show a dialog with custom properties 91 | sdlLog "\nShowing Custom Dialog..." 92 | props <- sdlCreateProperties 93 | 94 | -- Set some custom properties 95 | sdlSetStringProperty props sdlPropFileDialogTitleString "Select a File" 96 | sdlSetStringProperty props sdlPropFileDialogAcceptString "Choose" 97 | sdlSetStringProperty props sdlPropFileDialogCancelString "Never Mind" 98 | 99 | sdlShowFileDialogWithProperties 100 | SDL_FILEDIALOG_OPENFILE 101 | callbackPtr 102 | nullPtr 103 | props 104 | 105 | -- -- Event loop to keep program alive 106 | -- let eventLoop = do 107 | -- sdlPumpEvents -- Process events 108 | -- threadDelay 100000 -- Small delay to prevent CPU spinning 109 | -- -- You might want to add a way to exit the loop 110 | -- -- For example, checking for a quit event or after all dialogs are done 111 | -- eventLoop 112 | 113 | -- -- Run the event loop 114 | -- sdlLog "Running event loop... (Press Ctrl+C to exit)" 115 | -- eventLoop `finally` do 116 | -- -- Cleanup 117 | sdlDestroyProperties props 118 | sdlDestroyWindow window 119 | sdlQuit 120 | exitSuccess 121 | 122 | -- Helper function to manage filter array lifecycle 123 | withFilters :: 124 | [SDLDialogFileFilter] -> 125 | (Ptr SDLDialogFileFilter -> CInt -> IO a) -> 126 | IO a 127 | withFilters filters action = 128 | withArrayLen filters $ \len filtersPtr -> 129 | action filtersPtr (fromIntegral len) 130 | 131 | -- | Type for the dialog callback function 132 | type DialogCallback = Ptr () -> Ptr CString -> CInt -> IO () 133 | 134 | -- | Foreign wrapper for the callback 135 | foreign import ccall "wrapper" 136 | wrapDialogCallback :: DialogCallback -> IO (FunPtr DialogCallback) 137 | -------------------------------------------------------------------------------- /examples/EventsExample.hs: -------------------------------------------------------------------------------- 1 | {-| 2 | Example : SDL.Events 3 | Description : SDL Window and Keyboard Event Example 4 | Copyright : (c) Kyle Lukaszek, 2025 5 | License : BSD3 6 | |-} 7 | 8 | module Main where 9 | 10 | import SDL 11 | import Control.Monad (unless, when) 12 | import System.Exit (exitFailure, exitSuccess) 13 | import Foreign.Ptr (nullPtr) 14 | import Data.IORef 15 | import Data.Word (Word32, Word64) 16 | import Text.Printf (printf) 17 | 18 | main :: IO () 19 | main = do 20 | -- Check compiled version 21 | sdlLog $ "Compiled SDL Version: " ++ show sdlVersion 22 | when (sdlVersionAtLeast 3 3 0) $ sdlLog "Compiled with at least SDL 3.3.0" 23 | 24 | -- Get linked version 25 | linkedVersion <- sdlGetVersion 26 | sdlLog $ "Linked SDL Version: " ++ show linkedVersion 27 | 28 | -- Initialize SDL 29 | initSuccess <- sdlInit [SDL_INIT_VIDEO, SDL_INIT_EVENTS] 30 | unless initSuccess $ do 31 | sdlLog "Failed to initialize SDL!" 32 | exitFailure 33 | 34 | -- Check initialized subsystems 35 | initializedSystems <- sdlWasInit [] 36 | sdlLog "Initialized subsystems:" 37 | mapM_ printSubsystem initializedSystems 38 | 39 | -- Create a window 40 | window <- sdlCreateWindow "SDL3 Haskell Event Loop" 800 600 [SDL_WINDOW_RESIZABLE] 41 | case window of 42 | Nothing -> do 43 | sdlLog "Failed to create window!" 44 | sdlQuit 45 | exitFailure 46 | Just win -> do 47 | sdlLog "Window created successfully!" 48 | 49 | -- Start event loop with initial time 50 | startTime <- sdlGetPerformanceCounter 51 | freq <- sdlGetPerformanceFrequency 52 | deltaTimeRef <- newIORef 0.0 53 | eventLoop win startTime freq deltaTimeRef 54 | 55 | -- Cleanup 56 | sdlDestroyWindow win 57 | sdlLog "Window destroyed." 58 | 59 | sdlLog "Shutting down SDL..." 60 | sdlQuit 61 | sdlLog "Application terminated successfully" 62 | exitSuccess 63 | 64 | -- | Main event loop that tracks FPS and processes events 65 | eventLoop :: SDLWindow -> Word64 -> Word64 -> IORef Double -> IO () 66 | eventLoop window lastTime freq deltaTimeRef = do 67 | currentTime <- sdlGetPerformanceCounter 68 | let deltaTime = fromIntegral (currentTime - lastTime) / fromIntegral freq * 1000.0 69 | 70 | -- Store the new deltaTime 71 | writeIORef deltaTimeRef deltaTime 72 | 73 | -- Event handling 74 | sdlPumpEvents 75 | maybeEvent <- sdlPollEvent 76 | shouldQuit <- case maybeEvent of 77 | Nothing -> return False 78 | Just event -> handleEvent event deltaTimeRef 79 | 80 | unless shouldQuit $ eventLoop window currentTime freq deltaTimeRef 81 | 82 | -- | Handle SDL events 83 | handleEvent :: SDLEvent -> IORef Double -> IO Bool 84 | handleEvent event deltaTimeRef = case event of 85 | SDLEventQuit _ -> do 86 | sdlLog "Quit event received." 87 | return True 88 | SDLEventKeyboard (SDLKeyboardEvent _ _ _ _ scancode _ _ _ down _) | down -> do 89 | deltaTime <- readIORef deltaTimeRef -- Read delta time 90 | sdlLog $ printf "Key event received. Delta Time: %.3f ms" deltaTime 91 | return $ scancode == SDL_SCANCODE_Q 92 | _ -> return False 93 | 94 | -- Helper function to print subsystem names 95 | printSubsystem :: SDLInitFlags -> IO () 96 | printSubsystem flag = sdlLog $ " - " ++ case flag of 97 | SDL_INIT_AUDIO -> "Audio" 98 | SDL_INIT_VIDEO -> "Video" 99 | SDL_INIT_JOYSTICK -> "Joystick" 100 | SDL_INIT_HAPTIC -> "Haptic" 101 | SDL_INIT_GAMEPAD -> "Gamepad" 102 | SDL_INIT_EVENTS -> "Events" 103 | SDL_INIT_SENSOR -> "Sensor" 104 | SDL_INIT_CAMERA -> "Camera" 105 | _ -> "Unknown subsystem" 106 | 107 | -- Function to log the frame time in milliseconds with decimal precision 108 | logFrameTime :: Double -> IO () 109 | logFrameTime frameTime = sdlLog $ printf "Frame time: %.4f ms" frameTime 110 | 111 | -------------------------------------------------------------------------------- /examples/FilesystemExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad (unless, when) 5 | import System.Exit (exitFailure, exitSuccess) 6 | import Foreign.Ptr (nullPtr) 7 | 8 | main :: IO () 9 | main = do 10 | -- Initialize SDL with basic subsystems 11 | initSuccess <- sdlInit [SDL_INIT_VIDEO, SDL_INIT_EVENTS] 12 | unless initSuccess $ do 13 | sdlLog "Failed to initialize SDL!" 14 | exitFailure 15 | 16 | -- Set basic app metadata 17 | appMetadataSuccess <- sdlSetAppMetadata 18 | "SDL Filesystem Demo" 19 | "1.0.0" 20 | "com.example.filesystemdemo" 21 | unless appMetadataSuccess $ do 22 | sdlLog "Failed to set app metadata!" 23 | 24 | -- Get and print the base path 25 | basePath <- sdlGetBasePath 26 | sdlLog $ "Base Path: " ++ maybe "Not available" id basePath 27 | 28 | -- Get and print the preferences path 29 | prefPath <- sdlGetPrefPath "ExampleOrg" "FilesystemDemo" 30 | case prefPath of 31 | Nothing -> sdlLog "Failed to get preferences path!" 32 | Just path -> do 33 | sdlLog $ "Preferences Path: " ++ path 34 | 35 | -- Create a test directory in the preferences path 36 | let testDir = path ++ "test_dir" 37 | dirCreated <- sdlCreateDirectory testDir 38 | sdlLog $ "Created test directory: " ++ show dirCreated 39 | 40 | -- List contents of the preferences path 41 | dirContents <- sdlGlobDirectory path Nothing (SDLGlobFlags 0) 42 | sdlLog "Contents of preferences path:" 43 | case dirContents of 44 | Nothing -> sdlLog " Failed to list directory contents!" 45 | Just contents -> mapM_ (sdlLog . (" - " ++)) contents 46 | 47 | -- Get and print the user's Documents folder 48 | docsPath <- sdlGetUserFolder SDL_FOLDER_DOCUMENTS 49 | sdlLog $ "Documents Path: " ++ maybe "Not available" id docsPath 50 | 51 | -- Clean up and quit 52 | sdlQuit 53 | sdlLog "Application terminated successfully" 54 | exitSuccess 55 | 56 | -- Helper function to print subsystem names 57 | printSubsystem :: SDLInitFlags -> IO () 58 | printSubsystem flag = sdlLog $ " - " ++ case flag of 59 | SDL_INIT_AUDIO -> "Audio" 60 | SDL_INIT_VIDEO -> "Video" 61 | SDL_INIT_JOYSTICK -> "Joystick" 62 | SDL_INIT_HAPTIC -> "Haptic" 63 | SDL_INIT_GAMEPAD -> "Gamepad" 64 | SDL_INIT_EVENTS -> "Events" 65 | SDL_INIT_SENSOR -> "Sensor" 66 | SDL_INIT_CAMERA -> "Camera" 67 | _ -> "Unknown subsystem" 68 | -------------------------------------------------------------------------------- /examples/GUIDExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import SDL.GUID 5 | import Control.Monad 6 | import System.Exit (exitFailure, exitSuccess) 7 | import Foreign.Ptr (nullPtr) 8 | import Data.Word (Word8) 9 | import Data.Maybe (fromMaybe) 10 | 11 | main :: IO () 12 | main = do 13 | -- Basic SDL initialization from your example 14 | sdlLog $ "Compiled SDL Version: " ++ show sdlVersion 15 | when (sdlVersionAtLeast 3 3 0) $ 16 | sdlLog "Compiled with at least SDL 3.3.0" 17 | 18 | linkedVersion <- sdlGetVersion 19 | sdlLog $ "Linked SDL Version: " ++ show linkedVersion 20 | 21 | revision <- sdlGetRevision 22 | sdlLog $ "SDL Revision: " ++ revision 23 | 24 | initSuccess <- sdlInit [SDL_INIT_VIDEO, SDL_INIT_GAMEPAD] 25 | unless initSuccess $ do 26 | sdlLog "Failed to initialize SDL!" 27 | exitFailure 28 | 29 | -- GUID example section 30 | sdlLog "\n=== GUID Example ===" 31 | 32 | -- Create a sample GUID (normally this would come from an SDL input device) 33 | let sampleBytes = take 16 $ cycle [0x12, 0x34, 0x56, 0x78] :: [Word8] 34 | sampleGUID = SDLGUID sampleBytes 35 | 36 | sdlLog "Original GUID bytes:" 37 | print $ unSDLGUID sampleGUID 38 | 39 | -- Convert GUID to string 40 | guidStr <- sdlGUIDToString sampleGUID 41 | sdlLog $ "GUID as string: " ++ guidStr 42 | 43 | -- Convert string back to GUID 44 | guidBack <- sdlStringToGUID guidStr 45 | sdlLog "Converted back to GUID bytes:" 46 | print $ unSDLGUID guidBack 47 | 48 | -- Verify roundtrip conversion 49 | let isMatch = unSDLGUID sampleGUID == unSDLGUID guidBack 50 | sdlLog $ "Roundtrip conversion successful: " ++ show isMatch 51 | 52 | -- Example with an invalid string 53 | sdlLog "\nTesting with invalid GUID string:" 54 | invalidGuid <- sdlStringToGUID "not-a-valid-guid" 55 | sdlLog "Result of invalid string conversion:" 56 | print $ unSDLGUID invalidGuid 57 | 58 | -- Clean up 59 | sdlLog "\nShutting down SDL..." 60 | sdlQuit 61 | 62 | sdlLog "Application terminated successfully" 63 | exitSuccess 64 | 65 | -- Helper function to print subsystem names 66 | printSubsystem :: SDLInitFlags -> IO () 67 | printSubsystem flag = sdlLog $ " - " ++ case flag of 68 | SDL_INIT_AUDIO -> "Audio" 69 | SDL_INIT_VIDEO -> "Video" 70 | SDL_INIT_JOYSTICK -> "Joystick" 71 | SDL_INIT_HAPTIC -> "Haptic" 72 | SDL_INIT_GAMEPAD -> "Gamepad" 73 | SDL_INIT_EVENTS -> "Events" 74 | SDL_INIT_SENSOR -> "Sensor" 75 | SDL_INIT_CAMERA -> "Camera" 76 | _ -> "Unknown subsystem" 77 | -------------------------------------------------------------------------------- /examples/HintsExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad 5 | import Foreign.Marshal.Alloc (alloca, mallocBytes) 6 | import Foreign.Storable (poke, peek) 7 | import System.Exit (exitFailure, exitSuccess) 8 | 9 | -- Check power state 10 | main :: IO () 11 | main = do 12 | -- Check compiled version 13 | sdlLog $ "Compiled SDL Version: " ++ show sdlVersion 14 | when (sdlVersionAtLeast 3 3 0) $ 15 | sdlLog "Compiled with at least SDL 3.3.0" 16 | 17 | -- Get linked version 18 | linkedVersion <- sdlGetVersion 19 | sdlLog $ "Linked SDL Version: " ++ show linkedVersion 20 | 21 | -- Get revision 22 | revision <- sdlGetRevision 23 | sdlLog $ "SDL Revision: " ++ revision 24 | 25 | -- Set a hint before initialization 26 | sdlLog "Setting hint SDL_VIDEO_ALLOW_SCREENSAVER to enable screensaver..." 27 | success <- sdlSetHint sdlHintVideoAllowScreensaver "1" 28 | if success 29 | then sdlLog "Hint set successfully." 30 | else do 31 | sdlLog "Failed to set hint!" 32 | err <- sdlGetError 33 | sdlLog $ "Error: " ++ err 34 | 35 | 36 | -- Initialize SDL with video and events subsystems 37 | initSuccess <- sdlInit [SDL_INIT_VIDEO, SDL_INIT_EVENTS] 38 | unless initSuccess $ do 39 | sdlLog "Failed to initialize SDL!" 40 | exitFailure 41 | 42 | -- Check initialized subsystems 43 | initializedSystems <- sdlWasInit [] 44 | sdlLog "Initialized subsystems:" 45 | mapM_ printSubsystem initializedSystems 46 | 47 | -- Query the hint 48 | mHintValue <- sdlGetHint sdlHintVideoAllowScreensaver 49 | sdlLog $ "SDL_VIDEO_ALLOW_SCREENSAVER value: " ++ maybe "Not set" id mHintValue 50 | 51 | sdlQuit 52 | 53 | -- Helper function to print subsystem names 54 | printSubsystem :: SDLInitFlags -> IO () 55 | printSubsystem flag = sdlLog $ " - " ++ case flag of 56 | SDL_INIT_AUDIO -> "Audio" 57 | SDL_INIT_VIDEO -> "Video" 58 | SDL_INIT_JOYSTICK -> "Joystick" 59 | SDL_INIT_HAPTIC -> "Haptic" 60 | SDL_INIT_GAMEPAD -> "Gamepad" 61 | SDL_INIT_EVENTS -> "Events" 62 | SDL_INIT_SENSOR -> "Sensor" 63 | SDL_INIT_CAMERA -> "Camera" 64 | _ -> "Unknown subsystem" 65 | -------------------------------------------------------------------------------- /examples/InitExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad 5 | import System.Exit (exitFailure, exitSuccess) 6 | import Foreign.Ptr (nullPtr) 7 | 8 | main :: IO () 9 | main = do 10 | -- Check compiled version 11 | sdlLog $ "Compiled SDL Version: " ++ show sdlVersion 12 | when (sdlVersionAtLeast 3 3 0) $ 13 | sdlLog "Compiled with at least SDL 3.3.0" 14 | 15 | -- Get linked version 16 | linkedVersion <- sdlGetVersion 17 | sdlLog $ "Linked SDL Version: " ++ show linkedVersion 18 | 19 | -- Get revision 20 | revision <- sdlGetRevision 21 | sdlLog $ "SDL Revision: " ++ revision 22 | 23 | -- Set some basic metadata about our application 24 | appMetadataSuccess <- sdlSetAppMetadata 25 | "SDL3 Haskell!" 26 | "1.0.0" 27 | "com.example.sdlapp" 28 | 29 | unless appMetadataSuccess $ do 30 | sdlLog "Failed to set app metadata!" 31 | 32 | -- Add some additional metadata 33 | _ <- sdlSetAppMetadataProperty propAppMetadataCreator "Kyle Lukaszek" 34 | _ <- sdlSetAppMetadataProperty propAppMetadataCopyright "Copyright (c) 2025" 35 | _ <- sdlSetAppMetadataProperty propAppMetadataType "Demo" 36 | 37 | -- Print some metadata to verify it was set 38 | name <- sdlGetAppMetadataProperty propAppMetadataName 39 | sdlLog $ "App Name: " ++ maybe "Not set" id name 40 | 41 | -- Initialize SDL with video and events subsystems 42 | initSuccess <- sdlInit [SDL_INIT_VIDEO] 43 | 44 | unless initSuccess $ do 45 | sdlLog "Failed to initialize SDL!" 46 | exitFailure 47 | 48 | -- Check what subsystems are initialized 49 | initializedSystems <- sdlWasInit [] 50 | sdlLog "Initialized subsystems:" 51 | mapM_ printSubsystem initializedSystems 52 | 53 | sdlLog "Would create window here..." 54 | sdlLog "Application running..." 55 | 56 | -- For the main thread callback, use a simpler callback 57 | -- that doesn't try to print to avoid potential issues 58 | isMain <- sdlIsMainThread 59 | sdlLog $ "Are we on the main thread? " ++ show isMain 60 | 61 | -- If we're already on the main thread, running on main thread is redundant 62 | -- but we'll do it for demonstration 63 | if isMain 64 | then sdlLog "Already on main thread, calling directly:" 65 | else sdlLog "Running callback on main thread:" 66 | 67 | -- Use the simpler callback that doesn't do IO operations 68 | _ <- sdlRunOnMainThread (\_ -> pure ()) nullPtr True 69 | sdlLog "Callback completed" 70 | 71 | sdlLog "Shutting down SDL..." 72 | sdlQuit 73 | 74 | sdlLog "Application terminated successfully" 75 | exitSuccess 76 | 77 | -- Helper function to print subsystem names 78 | printSubsystem :: SDLInitFlags -> IO () 79 | printSubsystem flag = sdlLog $ " - " ++ case flag of 80 | SDL_INIT_AUDIO -> "Audio" 81 | SDL_INIT_VIDEO -> "Video" 82 | SDL_INIT_JOYSTICK -> "Joystick" 83 | SDL_INIT_HAPTIC -> "Haptic" 84 | SDL_INIT_GAMEPAD -> "Gamepad" 85 | SDL_INIT_EVENTS -> "Events" 86 | SDL_INIT_SENSOR -> "Sensor" 87 | SDL_INIT_CAMERA -> "Camera" 88 | _ -> "Unknown subsystem" 89 | -------------------------------------------------------------------------------- /examples/LocaleExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Foreign.C.Types (CInt(..)) 5 | import Control.Monad (unless) 6 | 7 | main :: IO () 8 | main = do 9 | -- Initialize SDL 10 | initSuccess <- sdlInit [SDL_INIT_VIDEO] 11 | unless initSuccess $ do 12 | sdlLog "Failed to initialize SDL" 13 | return () 14 | 15 | -- Get preferred locales 16 | locales <- sdlGetPreferredLocales 17 | 18 | -- Print the results 19 | sdlLog "User's preferred locales:" 20 | mapM_ printLocale locales 21 | 22 | -- Clean up 23 | sdlQuit 24 | 25 | -- Helper function to print a locale in a readable format 26 | printLocale :: SDLLocale -> IO () 27 | printLocale (SDLLocale lang country) = do 28 | let countryStr = maybe "" (", " ++) country 29 | sdlLog $ "Language: " ++ lang ++ countryStr 30 | -------------------------------------------------------------------------------- /examples/MessageBoxExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Foreign.C.Types (CInt) 5 | import Control.Monad (unless) 6 | import Data.Bits (zeroBits) 7 | import System.Exit (exitFailure, exitSuccess) 8 | 9 | main :: IO () 10 | main = do 11 | -- Initialize SDL 12 | initSuccess <- sdlInit [SDL_INIT_VIDEO] 13 | unless initSuccess $ do 14 | sdlLog "Failed to initialize SDL!" 15 | exitFailure 16 | 17 | -- Create a window for our dialog 18 | maybeWindow <- sdlCreateWindow 19 | "SDL Dialog Example" 20 | 800 21 | 600 22 | [SDL_WINDOW_RESIZABLE] 23 | 24 | sdlLog "SDL Initialized. Testing message boxes..." 25 | 26 | -- Simple information message box 27 | res1 <- showMessageBox "Info" "This is an information message box." maybeWindow [SDL_MESSAGEBOX_INFORMATION] 28 | sdlLog $ "User clicked: " ++ show res1 29 | 30 | -- Warning message box 31 | res2 <- showMessageBox "Warning" "This is a warning message box." maybeWindow [SDL_MESSAGEBOX_WARNING] 32 | sdlLog $ "User clicked: " ++ show res2 33 | 34 | -- Error message box 35 | res3 <- showMessageBox "Error" "This is an error message box." maybeWindow [SDL_MESSAGEBOX_ERROR] 36 | sdlLog $ "User clicked: " ++ show res3 37 | 38 | -- Message box with custom buttons 39 | res4 <- showCustomMessageBox "Custom" "Choose an option:" maybeWindow [("OK", 1), ("Cancel", 2)] 40 | sdlLog $ "User clicked: " ++ show res4 41 | 42 | -- Shutdown SDL 43 | sdlLog "Shutting down SDL..." 44 | sdlQuit 45 | sdlLog "Test completed." 46 | exitSuccess 47 | 48 | -- Function to show a standard message box 49 | showMessageBox :: String -> String -> Maybe SDLWindow -> [SDLMessageBoxFlags] -> IO (Maybe Int) 50 | showMessageBox title msg window msgType = do 51 | let msgBoxData = SDLMessageBoxData 52 | { messageBoxFlags = msgType 53 | , messageBoxWindow = window 54 | , messageBoxTitle = title 55 | , messageBoxMessage = msg 56 | , messageBoxButtons = [] 57 | , messageBoxColorScheme = Nothing 58 | } 59 | sdlShowMessageBox msgBoxData 60 | 61 | -- Function to show a custom message box with buttons 62 | showCustomMessageBox :: String -> String -> Maybe SDLWindow -> [(String, CInt)] -> IO (Maybe Int) 63 | showCustomMessageBox title msg window buttons = do 64 | let buttonData = [ SDLMessageBoxButtonData zeroBits bid txt | (txt, bid) <- buttons ] 65 | msgBoxData = SDLMessageBoxData 66 | { messageBoxFlags = [SDL_MESSAGEBOX_INFORMATION] 67 | , messageBoxWindow = window 68 | , messageBoxTitle = title 69 | , messageBoxMessage = msg 70 | , messageBoxButtons = buttonData 71 | , messageBoxColorScheme = Nothing 72 | } 73 | sdlShowMessageBox msgBoxData 74 | -------------------------------------------------------------------------------- /examples/PlatformExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad (when) 5 | 6 | main :: IO () 7 | main = do 8 | platform <- sdlGetPlatform 9 | sdlLog $ "Running on platform: " ++ platform 10 | 11 | -- Check compile-time platform constants 12 | when sdlPlatformWindows $ 13 | sdlLog "Compiled for Windows" 14 | 15 | when sdlPlatformLinux $ 16 | sdlLog "Compiled for Linux" 17 | 18 | when sdlPlatformMacOS $ 19 | sdlLog "Compiled for macOS" 20 | -------------------------------------------------------------------------------- /examples/PowerExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad 5 | import Foreign.Marshal.Alloc (alloca, mallocBytes) 6 | import Foreign.Storable (poke, peek) 7 | import System.Exit (exitFailure, exitSuccess) 8 | 9 | -- Check power state 10 | main :: IO () 11 | main = do 12 | -- Check compiled version 13 | sdlLog $ "Compiled SDL Version: " ++ show sdlVersion 14 | when (sdlVersionAtLeast 3 3 0) $ 15 | sdlLog "Compiled with at least SDL 3.3.0" 16 | 17 | -- Get linked version 18 | linkedVersion <- sdlGetVersion 19 | sdlLog $ "Linked SDL Version: " ++ show linkedVersion 20 | 21 | -- Get revision 22 | revision <- sdlGetRevision 23 | sdlLog $ "SDL Revision: " ++ revision 24 | 25 | -- Set a hint before initialization 26 | sdlLog "Setting hint SDL_VIDEO_ALLOW_SCREENSAVER to enable screensaver..." 27 | success <- sdlSetHint sdlHintVideoAllowScreensaver "1" 28 | if success 29 | then sdlLog "Hint set successfully." 30 | else do 31 | sdlLog "Failed to set hint!" 32 | err <- sdlGetError 33 | sdlLog $ "Error: " ++ err 34 | 35 | -- Query the hint 36 | mHintValue <- sdlGetHint sdlHintVideoAllowScreensaver 37 | sdlLog $ "SDL_VIDEO_ALLOW_SCREENSAVER value: " ++ maybe "Not set" id mHintValue 38 | 39 | -- Initialize SDL with video and events subsystems 40 | initSuccess <- sdlInit [SDL_INIT_VIDEO] 41 | unless initSuccess $ do 42 | sdlLog "Failed to initialize SDL!" 43 | exitFailure 44 | 45 | -- Check initialized subsystems 46 | initializedSystems <- sdlWasInit [] 47 | sdlLog "Initialized subsystems:" 48 | mapM_ printSubsystem initializedSystems 49 | 50 | sdlLog "Checking power state..." 51 | alloca $ \secondsPtr -> 52 | alloca $ \percentPtr -> do 53 | mState <- sdlGetPowerInfo (Just secondsPtr) (Just percentPtr) 54 | case mState of 55 | Nothing -> do 56 | sdlLog "Failed to get power info!" 57 | err <- sdlGetError 58 | sdlLog $ "Error: " ++ err 59 | Just state -> do 60 | seconds <- peek secondsPtr 61 | percent <- peek percentPtr 62 | sdlLog $ "Power State: " ++ show state 63 | sdlLog $ "Seconds remaining: " ++ (if seconds == -1 then "Unknown" else show seconds) 64 | sdlLog $ "Percent remaining: " ++ (if percent == -1 then "Unknown" else show percent ++ "%") 65 | 66 | sdlQuit 67 | 68 | -- Helper function to print subsystem names 69 | printSubsystem :: SDLInitFlags -> IO () 70 | printSubsystem flag = sdlLog $ " - " ++ case flag of 71 | SDL_INIT_AUDIO -> "Audio" 72 | SDL_INIT_VIDEO -> "Video" 73 | SDL_INIT_JOYSTICK -> "Joystick" 74 | SDL_INIT_HAPTIC -> "Haptic" 75 | SDL_INIT_GAMEPAD -> "Gamepad" 76 | SDL_INIT_EVENTS -> "Events" 77 | SDL_INIT_SENSOR -> "Sensor" 78 | SDL_INIT_CAMERA -> "Camera" 79 | _ -> "Unknown subsystem" 80 | 81 | -------------------------------------------------------------------------------- /examples/ProcessExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad (unless) 5 | import System.Exit (exitFailure, exitSuccess) 6 | 7 | main :: IO () 8 | main = do 9 | -- Initialize SDL 10 | initSuccess <- sdlInit [] 11 | unless initSuccess $ do 12 | sdlLog "Failed to initialize SDL!" 13 | exitFailure 14 | 15 | -- Create a process to run 'ls' (or 'dir' on Windows) 16 | let args = ["ls", "-l"] -- Use "dir" on Windows 17 | process <- sdlCreateProcess args True -- Pipe stdio 18 | case process of 19 | Nothing -> do 20 | sdlLog "Failed to create process!" 21 | sdlQuit 22 | exitFailure 23 | Just proc -> do 24 | -- Read process output 25 | output <- sdlReadProcess proc 26 | case output of 27 | Nothing -> sdlLog "Failed to read process output!" 28 | Just (out, exitcode) -> do 29 | sdlLog $ "Process output:\n" ++ out 30 | sdlLog $ "Exit code: " ++ show exitcode 31 | 32 | -- Clean up 33 | sdlDestroyProcess proc 34 | 35 | -- Shutdown SDL 36 | sdlQuit 37 | sdlLog "Application terminated successfully" 38 | exitSuccess 39 | -------------------------------------------------------------------------------- /examples/RectExample.hs: -------------------------------------------------------------------------------- 1 | import Foreign.Marshal.Utils (with) 2 | import SDL 3 | 4 | 5 | main :: IO () 6 | main = do 7 | let rect1 = SDLRect 0 0 10 10 8 | rect2 = SDLRect 5 5 10 10 9 | point = SDLPoint 5 5 10 | 11 | sdlLog $ "GamepadType" ++ show SDL_GAMEPAD_TYPE_UNKNOWN 12 | sdlLog $ "Point in rect1: " ++ show (sdlPointInRect point rect1) 13 | sdlLog $ "Rect1 empty: " ++ show (sdlRectEmpty rect1) 14 | sdlLog $ "Rects equal: " ++ show (sdlRectsEqual rect1 rect2) 15 | 16 | -- Cast our rectangles to pointers and pass them to the sdlHasRectIntersection function 17 | intersects <- with rect1 $ \rect1Ptr -> 18 | with rect2 $ \rect2Ptr -> 19 | sdlHasRectIntersection rect1Ptr rect2Ptr 20 | sdlLog $ "Rectangles intersect: " ++ show intersects 21 | -------------------------------------------------------------------------------- /examples/SensorExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad 5 | import System.Exit (exitFailure, exitSuccess) 6 | import Foreign.Ptr (nullPtr) 7 | 8 | main :: IO () 9 | main = do 10 | -- Initialize SDL with sensor subsystem 11 | initSuccess <- sdlInit [SDL_INIT_SENSOR] 12 | 13 | unless initSuccess $ do 14 | sdlLog "Failed to initialize SDL with sensor support!" 15 | exitFailure 16 | 17 | sdlLog "SDL initialized with sensor support" 18 | 19 | -- Get list of available sensors 20 | maybeSensors <- sdlGetSensors 21 | case maybeSensors of 22 | Nothing -> do 23 | sdlLog "No sensors found or error occurred" 24 | cleanupAndExit 25 | Just sensorIds -> do 26 | sdlLog $ "Found " ++ show (length sensorIds) ++ " sensor(s)" 27 | 28 | -- Process each sensor 29 | forM_ sensorIds $ \sensorId -> do 30 | sdlLog $ "\nProcessing sensor ID: " ++ show sensorId 31 | 32 | -- Get sensor name 33 | maybeName <- sdlGetSensorNameForID sensorId 34 | sdlLog $ "Name: " ++ maybe "Unknown" id maybeName 35 | 36 | -- Get sensor type 37 | sensorType <- sdlGetSensorTypeForID sensorId 38 | sdlLog $ "Type: " ++ show sensorType 39 | 40 | -- Open the sensor 41 | maybeSensor <- sdlOpenSensor sensorId 42 | case maybeSensor of 43 | Nothing -> sdlLog "Failed to open sensor" 44 | Just sensor -> do 45 | sdlLog "Successfully opened sensor" 46 | 47 | -- Get some sensor data (assuming 3 values for accel/gyro) 48 | maybeData <- sdlGetSensorData sensor 3 49 | case maybeData of 50 | Nothing -> sdlLog "Failed to get sensor data" 51 | Just values -> do 52 | sdlLog "Sensor data:" 53 | case sensorType of 54 | SDL_SENSOR_ACCEL -> do 55 | sdlLog $ "X acceleration: " ++ show (values !! 0) ++ " m/s²" 56 | sdlLog $ "Y acceleration: " ++ show (values !! 1) ++ " m/s²" 57 | sdlLog $ "Z acceleration: " ++ show (values !! 2) ++ " m/s²" 58 | SDL_SENSOR_GYRO -> do 59 | sdlLog $ "X rotation: " ++ show (values !! 0) ++ " rad/s" 60 | sdlLog $ "Y rotation: " ++ show (values !! 1) ++ " rad/s" 61 | sdlLog $ "Z rotation: " ++ show (values !! 2) ++ " rad/s" 62 | _ -> sdlLog $ "Raw values: " ++ show values 63 | 64 | -- Close the sensor 65 | sdlCloseSensor sensor 66 | sdlLog "Sensor closed" 67 | 68 | cleanupAndExit 69 | 70 | -- Helper function to cleanup and exit 71 | cleanupAndExit :: IO () 72 | cleanupAndExit = do 73 | sdlLog "\nShutting down SDL..." 74 | sdlQuit 75 | sdlLog "Application terminated successfully" 76 | exitSuccess 77 | 78 | -- Helper function to display sensor type 79 | showSensorType :: SDLSensorType -> String 80 | showSensorType t = case t of 81 | SDL_SENSOR_INVALID -> "Invalid" 82 | SDL_SENSOR_UNKNOWN -> "Unknown" 83 | SDL_SENSOR_ACCEL -> "Accelerometer" 84 | SDL_SENSOR_GYRO -> "Gyroscope" 85 | SDL_SENSOR_ACCEL_L -> "Left Joy-Con Accelerometer" 86 | SDL_SENSOR_GYRO_L -> "Left Joy-Con Gyroscope" 87 | SDL_SENSOR_ACCEL_R -> "Right Joy-Con Accelerometer" 88 | SDL_SENSOR_GYRO_R -> "Right Joy-Con Gyroscope" 89 | -------------------------------------------------------------------------------- /examples/StorageExample.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import SDL 4 | import Control.Monad 5 | import System.Exit (exitFailure, exitSuccess) 6 | import Foreign.Ptr (Ptr, nullPtr, castPtr) 7 | import Foreign.C.Types 8 | import Foreign.C.String (CString, withCString, peekCString) 9 | import Foreign.Marshal.Alloc (alloca, mallocBytes) 10 | import Foreign.Marshal.Array (copyArray) 11 | import Foreign.Storable (poke, peek) 12 | import Data.Word (Word64) 13 | 14 | main :: IO () 15 | main = do 16 | -- Check compiled version 17 | sdlLog $ "Compiled SDL Version: " ++ show sdlVersion 18 | when (sdlVersionAtLeast 3 3 0) $ 19 | sdlLog "Compiled with at least SDL 3.3.0" 20 | 21 | -- Get linked version 22 | linkedVersion <- sdlGetVersion 23 | sdlLog $ "Linked SDL Version: " ++ show linkedVersion 24 | 25 | -- Get revision 26 | revision <- sdlGetRevision 27 | sdlLog $ "SDL Revision: " ++ revision 28 | 29 | -- Initialize SDL with video and events subsystems 30 | initSuccess <- sdlInit [SDL_INIT_VIDEO] 31 | unless initSuccess $ do 32 | sdlLog "Failed to initialize SDL!" 33 | exitFailure 34 | 35 | -- Check initialized subsystems 36 | initializedSystems <- sdlWasInit [] 37 | sdlLog "Initialized subsystems:" 38 | mapM_ printSubsystem initializedSystems 39 | 40 | -- Open user storage 41 | sdlLog "Opening user storage..." 42 | mStorage <- sdlOpenUserStorage "example.org" "StorageDemo" 0 43 | case mStorage of 44 | Nothing -> do 45 | sdlLog "Failed to open user storage!" 46 | sdlQuit 47 | exitFailure 48 | Just storage -> do 49 | sdlLog "User storage opened successfully." 50 | 51 | -- Wait for storage to be ready 52 | waitForStorageReady storage 53 | 54 | -- Write a test file 55 | writeTestFile storage 56 | 57 | -- Read the test file back 58 | readTestFile storage 59 | 60 | -- Enumerate directory contents 61 | listDirectory storage 62 | 63 | -- Close storage 64 | sdlLog "Closing storage..." 65 | success <- sdlCloseStorage storage 66 | unless success $ sdlLog "Failed to close storage cleanly!" 67 | 68 | -- Clean up and quit 69 | sdlLog "Shutting down SDL..." 70 | sdlQuit 71 | 72 | sdlLog "Application terminated successfully" 73 | exitSuccess 74 | 75 | -- Helper to wait for storage to be ready 76 | waitForStorageReady :: Ptr SDLStorage -> IO () 77 | waitForStorageReady storage = do 78 | sdlLog "Waiting for storage to be ready..." 79 | let checkReady = do 80 | ready <- sdlStorageReady storage 81 | unless ready $ do 82 | sdlDelay 1 83 | checkReady 84 | checkReady 85 | sdlLog "Storage is ready." 86 | 87 | -- Write a test file 88 | writeTestFile :: Ptr SDLStorage -> IO () 89 | writeTestFile storage = do 90 | sdlLog "Writing test file..." 91 | let content = "Hello, SDL Storage!" 92 | len = fromIntegral (length content) :: Word64 93 | contentPtr <- mallocBytes (fromIntegral len) 94 | withCString content $ \cstr -> do 95 | copyArray contentPtr cstr (fromIntegral len) 96 | success <- sdlWriteStorageFile storage "test.txt" (castPtr contentPtr) len 97 | free contentPtr -- Use Haskell's free for mallocBytes 98 | if success 99 | then sdlLog "Successfully wrote test.txt" 100 | else do 101 | sdlLog "Failed to write test.txt!" 102 | err <- sdlGetError 103 | sdlLog $ "Error: " ++ err 104 | 105 | -- Read the test file back 106 | readTestFile :: Ptr SDLStorage -> IO () 107 | readTestFile storage = do 108 | sdlLog "Reading test file..." 109 | mSize <- sdlGetStorageFileSize storage "test.txt" 110 | case mSize of 111 | Nothing -> do 112 | sdlLog "Failed to get size of test.txt!" 113 | err <- sdlGetError 114 | sdlLog $ "Error: " ++ err 115 | Just size -> do 116 | buffer <- mallocBytes (fromIntegral size) 117 | success <- sdlReadStorageFile storage "test.txt" buffer size 118 | if success 119 | then do 120 | content <- peekCString (castPtr buffer) 121 | sdlLog $ "Read from test.txt: " ++ content 122 | else do 123 | sdlLog "Failed to read test.txt!" 124 | err <- sdlGetError 125 | sdlLog $ "Error: " ++ err 126 | free buffer -- Use Haskell's free for mallocBytes 127 | 128 | -- List directory contents 129 | listDirectory :: Ptr SDLStorage -> IO () 130 | listDirectory storage = do 131 | sdlLog "Listing directory contents..." 132 | let callback :: Ptr () -> CString -> CString -> IO SDLEnumerationResult 133 | callback _ path name = do 134 | pathStr <- peekCString path 135 | nameStr <- peekCString name 136 | sdlLog $ " - " ++ pathStr ++ "/" ++ nameStr 137 | return SDL_ENUM_SUCCESS 138 | success <- sdlEnumerateStorageDirectory storage Nothing callback nullPtr 139 | unless success $ do 140 | sdlLog "Failed to enumerate directory!" 141 | err <- sdlGetError 142 | sdlLog $ "Error: " ++ err 143 | 144 | -- Helper function to print subsystem names 145 | printSubsystem :: SDLInitFlags -> IO () 146 | printSubsystem flag = sdlLog $ " - " ++ case flag of 147 | SDL_INIT_AUDIO -> "Audio" 148 | SDL_INIT_VIDEO -> "Video" 149 | SDL_INIT_JOYSTICK -> "Joystick" 150 | SDL_INIT_HAPTIC -> "Haptic" 151 | SDL_INIT_GAMEPAD -> "Gamepad" 152 | SDL_INIT_EVENTS -> "Events" 153 | SDL_INIT_SENSOR -> "Sensor" 154 | SDL_INIT_CAMERA -> "Camera" 155 | _ -> "Unknown subsystem" 156 | -------------------------------------------------------------------------------- /examples/SystemExample.hsc: -------------------------------------------------------------------------------- 1 | import SDL 2 | import Control.Monad (unless) 3 | import System.Exit (exitFailure) 4 | 5 | main :: IO () 6 | main = do 7 | -- Initialize SDL 8 | initSuccess <- sdlInit [SDL_INIT_VIDEO] 9 | unless initSuccess $ do 10 | sdlLog "Failed to initialize SDL!" 11 | exitFailure 12 | 13 | #ifdef SDL_PLATFORM_ANDROID 14 | -- Check if running on a Chromebook 15 | isChromebook <- sdlIsChromebook 16 | sdlLog $ "Running on Chromebook: " ++ show isChromebook 17 | 18 | -- Show a toast notification 19 | success <- sdlShowAndroidToast "Hello from Haskell!" 1 (-1) 0 0 20 | sdlLog $ "Toast shown: " ++ show success 21 | #endif 22 | 23 | -- Check device type 24 | isTablet <- sdlIsTablet 25 | isTV <- sdlIsTV 26 | sdlLog $ "Device type - Tablet: " ++ show isTablet ++ ", TV: " ++ show isTV 27 | 28 | -- Check sandbox environment 29 | sandbox <- sdlGetSandbox 30 | sdlLog $ "Sandbox environment: " ++ show sandbox 31 | 32 | case sandbox of 33 | SDLSandboxNone -> sdlLog " → Running without sandbox (normal for development)" 34 | SDLSandboxMacOS -> sdlLog " → Running in macOS App Sandbox (Mac App Store app)" 35 | SDLSandboxFlatpak -> sdlLog " → Running in Flatpak sandbox" 36 | SDLSandboxSnap -> sdlLog " → Running in Snap package sandbox" 37 | SDLSandboxUnknownContainer -> sdlLog " → Running in unknown container" 38 | 39 | -- Clean up 40 | sdlQuit 41 | sdlLog "System example completed successfully" 42 | -------------------------------------------------------------------------------- /examples/TimeExample.hs: -------------------------------------------------------------------------------- 1 | import SDL 2 | 3 | main :: IO () 4 | main = do 5 | -- Get current time 6 | maybeTicks <- sdlGetCurrentTime 7 | case maybeTicks of 8 | Just ticks -> do 9 | sdlLog $ "Current ticks: " ++ show ticks 10 | maybeDt <- sdlTimeToDateTime ticks True 11 | sdlLog $ "Local DateTime: " ++ show maybeDt 12 | Nothing -> sdlLog "Failed to get current time" 13 | 14 | -- Get locale preferences 15 | maybePrefs <- sdlGetDateTimeLocalePreferences 16 | sdlLog $ "Locale Preferences: " ++ show maybePrefs 17 | 18 | -- Example date calculation 19 | days <- sdlGetDaysInMonth 2025 3 20 | sdlLog $ "Days in March 2025: " ++ show days 21 | -------------------------------------------------------------------------------- /examples/TimerExample.hs: -------------------------------------------------------------------------------- 1 | import Control.Monad (when) 2 | import Foreign.Ptr (nullPtr) 3 | import SDL 4 | 5 | main :: IO () 6 | main = do 7 | -- Measure elapsed time 8 | start <- sdlGetTicks 9 | sdlDelay 1000 -- Wait 1 second 10 | end <- sdlGetTicks 11 | sdlLog $ "Elapsed time: " ++ show (end - start) ++ " ms" 12 | 13 | -- Add a timer callback 14 | let callback :: SDLTimerCallback 15 | callback _ timerID interval = do 16 | sdlLog $ "Timer " ++ show timerID ++ " fired after " ++ show interval ++ " ms" 17 | return 0 -- Stop the timer after one run 18 | timerID <- sdlAddTimer 500 callback nullPtr 19 | when (timerID /= 0) $ do 20 | sdlLog $ "Timer added with ID: " ++ show timerID 21 | sdlDelay 1000 -- Wait to see the timer fire 22 | sdlRemoveTimer timerID >>= print 23 | -------------------------------------------------------------------------------- /examples/TouchDeviceExample.hs: -------------------------------------------------------------------------------- 1 | import SDL 2 | import Foreign.Ptr (nullPtr) 3 | 4 | main :: IO () 5 | main = do 6 | devices <- sdlGetTouchDevices 7 | sdlLog $ "Touch Devices: " ++ show devices 8 | case devices of 9 | (touchID:_) -> do 10 | name <- sdlGetTouchDeviceName touchID 11 | sdlLog $ "Device Name: " ++ show name 12 | devType <- sdlGetTouchDeviceType touchID 13 | sdlLog $ "Device Type: " ++ show devType 14 | fingers <- sdlGetTouchFingers touchID 15 | sdlLog $ "Active Fingers: " ++ show fingers 16 | _ -> sdlLog "No touch devices found." 17 | -------------------------------------------------------------------------------- /examples/TrayExample.hs: -------------------------------------------------------------------------------- 1 | -- examples/TrayExample.hs 2 | 3 | import Control.Concurrent (threadDelay) 4 | import Control.Monad (unless, when) 5 | import Data.IORef 6 | import Foreign.Ptr (nullPtr) 7 | import Foreign.Storable (peek) 8 | import SDL 9 | import System.Exit (exitFailure, exitSuccess) 10 | 11 | main :: IO () 12 | main = do 13 | -- Check compiled version 14 | sdlLog $ "Compiled SDL Version: " ++ show sdlVersion 15 | when (sdlVersionAtLeast 3 3 0) $ sdlLog "Compiled with at least SDL 3.3.0" 16 | 17 | -- Get linked version 18 | linkedVersion <- sdlGetVersion 19 | sdlLog $ "Linked SDL Version: " ++ show linkedVersion 20 | 21 | -- Initialize SDL with video and events subsystems 22 | initSuccess <- sdlInit [SDL_INIT_VIDEO, SDL_INIT_EVENTS] 23 | unless initSuccess $ do 24 | err <- sdlGetError 25 | sdlLog $ "Failed to initialize SDL: " ++ err 26 | exitFailure 27 | 28 | -- Check what subsystems are initialized 29 | initializedSystems <- sdlWasInit [] 30 | sdlLog "Initialized subsystems:" 31 | mapM_ printSubsystem initializedSystems 32 | 33 | -- Load the tray icon 34 | mSurfacePtr <- sdlLoadBMP "examples/Content/Images/ravioli.bmp" 35 | case mSurfacePtr of 36 | Nothing -> do 37 | err <- sdlGetError 38 | sdlLog $ "Failed to load ravioli.bmp: " ++ err 39 | sdlQuit 40 | exitFailure 41 | Just surfacePtr -> do 42 | -- Inspect the surface 43 | surface <- peek surfacePtr 44 | sdlLog $ "Surface details: " ++ show surface 45 | 46 | -- Create the tray 47 | mTray <- sdlCreateTray (Just surfacePtr) (Just "SDL3 Haskell Tray Example") 48 | case mTray of 49 | Nothing -> do 50 | err <- sdlGetError 51 | sdlLog $ "Failed to create tray: " ++ err 52 | sdlDestroySurface surfacePtr 53 | sdlQuit 54 | exitFailure 55 | Just tray -> do 56 | sdlSetTrayIcon tray (Just surfacePtr) 57 | sdlSetTrayTooltip tray (Just "SDL3 Haskell Tray Example - Use menu to quit") 58 | 59 | -- Create a quit flag that can be shared between callbacks and main loop 60 | quitFlag <- newIORef False 61 | 62 | -- Create a simple menu for the tray 63 | mMenu <- sdlCreateTrayMenu tray 64 | case mMenu of 65 | Nothing -> do 66 | err <- sdlGetError 67 | sdlLog $ "Failed to create tray menu: " ++ err 68 | Just menu -> do 69 | -- Add menu entries 70 | mEntry1 <- sdlInsertTrayEntryAt menu 0 (Just "Hello from Haskell!") SDL_TRAYENTRY_BUTTON 71 | case mEntry1 of 72 | Nothing -> do 73 | err <- sdlGetError 74 | sdlLog $ "Failed to create menu entry 1: " ++ err 75 | Just entry1 -> do 76 | sdlLog "Menu entry 1 created successfully" 77 | sdlSetTrayEntryCallback entry1 (Just (helloCallback, nullPtr)) 78 | 79 | -- Add a separator and quit entry 80 | mEntry2 <- sdlInsertTrayEntryAt menu 1 (Just "Quit Application") SDL_TRAYENTRY_BUTTON 81 | case mEntry2 of 82 | Nothing -> do 83 | err <- sdlGetError 84 | sdlLog $ "Failed to create menu entry 2: " ++ err 85 | Just entry2 -> do 86 | sdlLog "Menu entry 2 created successfully" 87 | -- Pass the quit flag to the callback 88 | sdlSetTrayEntryCallback entry2 (Just (quitCallback quitFlag, nullPtr)) 89 | 90 | -- Update the trays to ensure changes are reflected 91 | sdlUpdateTrays 92 | 93 | sdlLog "Tray created with menu. Try right-clicking the tray icon to see the menu." 94 | sdlLog "Use the 'Quit Application' menu item to exit." 95 | 96 | -- Start simple event loop 97 | eventLoop tray quitFlag 98 | 99 | -- Cleanup 100 | sdlDestroyTray tray 101 | sdlDestroySurface surfacePtr 102 | sdlLog "Tray destroyed." 103 | 104 | sdlLog "Shutting down SDL..." 105 | sdlQuit 106 | sdlLog "Application terminated successfully" 107 | exitSuccess 108 | 109 | -- | Simple event loop that checks for quit flag and SDL quit events 110 | eventLoop :: SDLTray -> IORef Bool -> IO () 111 | eventLoop tray quitFlag = do 112 | -- Check if quit was requested from tray menu 113 | shouldQuit <- readIORef quitFlag 114 | 115 | if shouldQuit 116 | then do 117 | sdlLog "Quit requested from tray menu." 118 | return () 119 | else do 120 | -- Check for SDL quit events (like Ctrl+C) 121 | sdlPumpEvents 122 | maybeEvent <- sdlPollEvent 123 | case maybeEvent of 124 | Just (SDLEventQuit _) -> do 125 | sdlLog "SDL quit event received." 126 | return () 127 | _ -> do 128 | -- Sleep for a short time to avoid busy waiting 129 | threadDelay 100000 -- 100ms 130 | eventLoop tray quitFlag 131 | 132 | -- Simple callback for menu entry clicks 133 | helloCallback :: SDLTrayCallback 134 | helloCallback _ _ = do 135 | sdlLog "Hello menu entry clicked!" 136 | 137 | -- Quit callback for menu entry clicks 138 | quitCallback :: IORef Bool -> SDLTrayCallback 139 | quitCallback quitFlag _ _ = do 140 | sdlLog "Quit menu entry clicked - quitting application!" 141 | writeIORef quitFlag True 142 | 143 | -- Helper function to print subsystem names 144 | printSubsystem :: SDLInitFlags -> IO () 145 | printSubsystem flag = 146 | sdlLog $ 147 | " - " ++ case flag of 148 | SDL_INIT_AUDIO -> "Audio" 149 | SDL_INIT_VIDEO -> "Video" 150 | SDL_INIT_JOYSTICK -> "Joystick" 151 | SDL_INIT_HAPTIC -> "Haptic" 152 | SDL_INIT_GAMEPAD -> "Gamepad" 153 | SDL_INIT_EVENTS -> "Events" 154 | SDL_INIT_SENSOR -> "Sensor" 155 | SDL_INIT_CAMERA -> "Camera" 156 | _ -> "Unknown subsystem" 157 | -------------------------------------------------------------------------------- /hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | cabal: 3 | - path: "./src" 4 | component: "lib:sdl3" 5 | - path: "./examples/AudioExample.hs" 6 | component: "exe:audio" 7 | - path: "./examples/CameraExample.hs" 8 | component: "exe:camera" 9 | - path: "./examples/ClipboardExample.hs" 10 | component: "exe:clipboard" 11 | - path: "./examples/CPUInfoExample.hs" 12 | component: "exe:cpu-info" 13 | - path: "./examples/DialogExample.hs" 14 | component: "exe:dialog" 15 | - path: "./examples/EventsExample.hs" 16 | component: "exe:events" 17 | - path: "./examples/FilesystemExample.hs" 18 | component: "exe:filesystem" 19 | - path: "./examples/GamepadExample.hs" 20 | component: "exe:gamepad" 21 | - path: "./examples/GPUBasicComputeExample.hs" 22 | component: "exe:gpu-basiccompute" 23 | - path: "./examples/GPUClearExample.hs" 24 | component: "exe:gpu-clear" 25 | - path: "./examples/GPUClear3DSliceExample.hs" 26 | component: "exe:gpu-clear3dslice" 27 | - path: "./examples/GPUComputeUniformsExample.hs" 28 | component: "exe:gpu-computeuniforms" 29 | - path: "./examples/GPUCopyConsistencyExample.hs" 30 | component: "exe:gpu-copyconsistency" 31 | - path: "./examples/GPUCopyAndReadbackExample.hs" 32 | component: "exe:gpu-copyreadback" 33 | - path: "./examples/GPUCullExample.hs" 34 | component: "exe:gpu-cull" 35 | - path: "./examples/GPUComputeSamplerExample.hs" 36 | component: "exe:gpu-computesampler" 37 | - path: "./examples/GPUCustomSamplingExample.hs" 38 | component: "exe:gpu-customsampling" 39 | - path: "./examples/GPUDrawIndirectExample.hs" 40 | component: "exe:gpu-drawindirect" 41 | - path: "./examples/GPUInstancedExample.hs" 42 | component: "exe:gpu-instanced" 43 | - path: "./examples/GPUMultiWindowExample.hs" 44 | component: "exe:gpu-multiwindow" 45 | - path: "./examples/GPUStencilExample.hs" 46 | component: "exe:gpu-stencil" 47 | - path: "./examples/GPUAnimatedQuadExample.hs" 48 | component: "exe:gpu-animatedquad" 49 | - path: "./examples/GPUTexturedQuadExample.hs" 50 | component: "exe:gpu-texturedquad" 51 | - path: "./examples/GPUTonemappingExample.hs" 52 | component: "exe:gpu-tonemapping" 53 | - path: "./examples/GPURawTriangleExample.hs" 54 | component: "exe:gpu-triangle" 55 | - path: "./examples/GPUVertexBufferExample.hs" 56 | component: "exe:gpu-vbuf" 57 | - path: "./examples/GUIDExample.hs" 58 | component: "exe:guid" 59 | - path: "./examples/HapticExample.hs" 60 | component: "exe:haptic" 61 | - path: "./examples/HintsExample.hs" 62 | component: "exe:hints" 63 | - path: "./examples/InitExample.hs" 64 | component: "exe:init" 65 | - path: "./examples/LocaleExample.hs" 66 | component: "exe:locale" 67 | - path: "./examples/MessageBoxExample.hs" 68 | component: "exe:messagebox" 69 | - path: "./examples/PlatformExample.hs" 70 | component: "exe:platform" 71 | - path: "./examples/PowerExample.hs" 72 | component: "exe:power" 73 | - path: "./examples/ProcessExample.hs" 74 | component: "exe:process" 75 | - path: "./examples/RectExample.hs" 76 | component: "exe:rect" 77 | - path: "./examples/RenderExample.hs" 78 | component: "exe:render" 79 | - path: "./examples/SensorExample.hs" 80 | component: "exe:sensor" 81 | - path: "./examples/StorageExample.hs" 82 | component: "exe:storage" 83 | - path: "./examples/SystemExample.hs" 84 | component: "exe:system" 85 | - path: "./examples/TimeExample.hs" 86 | component: "exe:time" 87 | - path: "./examples/TimerExample.hs" 88 | component: "exe:timer" 89 | - path: "./examples/TouchDeviceExample.hs" 90 | component: "exe:touch-device" 91 | - path: "./examples/TrayExample.hs" 92 | component: "exe:tray" 93 | - path: "./examples/WAVExample.hs" 94 | component: "exe:wav" 95 | - path: "./test/binding-checker.hs" 96 | component: "exe:binding-checker" 97 | -------------------------------------------------------------------------------- /include/helpers.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void wrapper_SDL_GUIDToString(Uint8 *guid_data, char *pszGUID, int cbGUID); 4 | void wrapper_SDL_StringToGUID(const char *pchGUID, Uint8 *guid_data); 5 | 6 | -------------------------------------------------------------------------------- /src/SDL.hs: -------------------------------------------------------------------------------- 1 | -- Main module 2 | module SDL 3 | ( module SDL.Assert, 4 | module SDL.AsyncIO, 5 | module SDL.Atomic, 6 | module SDL.Audio, 7 | module SDL.Bits, 8 | module SDL.BlendMode, 9 | module SDL.Camera, 10 | module SDL.Clipboard, 11 | module SDL.CPUInfo, 12 | module SDL.Dialog, 13 | module SDL.Endian, 14 | module SDL.Error, 15 | module SDL.Events, 16 | module SDL.Filesystem, 17 | module SDL.Gamepad, 18 | module SDL.GPU, 19 | module SDL.GUID, 20 | module SDL.Haptic, 21 | module SDL.Hidapi, 22 | module SDL.Hints, 23 | module SDL.IOStream, 24 | module SDL.Init, 25 | module SDL.Joystick, 26 | module SDL.Keyboard, 27 | module SDL.Keycode, 28 | module SDL.Locale, 29 | module SDL.LoadSO, 30 | module SDL.Log, 31 | module SDL.MessageBox, 32 | module SDL.Metal, 33 | module SDL.Misc, 34 | module SDL.Mouse, 35 | module SDL.Mutex, 36 | module SDL.Pen, 37 | module SDL.Pixels, 38 | module SDL.Platform, 39 | module SDL.Power, 40 | module SDL.Process, 41 | module SDL.Properties, 42 | module SDL.Rect, 43 | module SDL.Render, 44 | module SDL.Scancode, 45 | module SDL.Sensor, 46 | module SDL.Stdinc, 47 | module SDL.Storage, 48 | module SDL.Surface, 49 | module SDL.System, 50 | module SDL.Thread, 51 | module SDL.Time, 52 | module SDL.Timer, 53 | module SDL.Touch, 54 | module SDL.Tray, 55 | module SDL.Version, 56 | module SDL.Video, 57 | ) 58 | where 59 | 60 | import SDL.Assert 61 | import SDL.AsyncIO 62 | import SDL.Atomic 63 | import SDL.Audio 64 | import SDL.Bits 65 | import SDL.BlendMode 66 | import SDL.CPUInfo 67 | import SDL.Camera 68 | import SDL.Clipboard 69 | import SDL.Dialog 70 | import SDL.Endian 71 | import SDL.Error 72 | import SDL.Events 73 | import SDL.Filesystem 74 | import SDL.GPU 75 | import SDL.GUID 76 | import SDL.Gamepad 77 | import SDL.Haptic 78 | import SDL.Hidapi 79 | import SDL.Hints 80 | import SDL.IOStream 81 | import SDL.Init 82 | import SDL.Joystick 83 | import SDL.Keyboard 84 | import SDL.Keycode 85 | import SDL.LoadSO 86 | import SDL.Locale 87 | import SDL.Log 88 | import SDL.MessageBox 89 | import SDL.Metal 90 | import SDL.Misc 91 | import SDL.Mouse 92 | import SDL.Mutex 93 | import SDL.Pen 94 | import SDL.Pixels 95 | import SDL.Platform 96 | import SDL.Power 97 | import SDL.Process 98 | import SDL.Properties 99 | import SDL.Rect 100 | import SDL.Render 101 | import SDL.Scancode 102 | import SDL.Sensor 103 | import SDL.Stdinc 104 | import SDL.Storage 105 | import SDL.Surface 106 | import SDL.System 107 | import SDL.Thread 108 | import SDL.Time 109 | import SDL.Timer 110 | import SDL.Touch 111 | import SDL.Tray 112 | import SDL.Version 113 | import SDL.Video 114 | -------------------------------------------------------------------------------- /src/SDL/Assert.hsc: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : SDL.Assert 3 | Description : Bindings to SDL assertion functionality 4 | Copyright : (c) Kyle Lukaszek, 2025 5 | License : BSD3 6 | 7 | This module provides Haskell bindings to the SDL assertion functionality. 8 | SDL assertions operate like your usual assert macro, but with additional features. 9 | -} 10 | 11 | module SDL.Assert 12 | ( 13 | -- * Types 14 | SDLAssertState(..) 15 | , SDLAssertData(..) 16 | , SDLAssertionHandler 17 | 18 | -- * Functions 19 | , sdlReportAssertion 20 | , sdlSetAssertionHandler 21 | , sdlGetDefaultAssertionHandler 22 | , sdlGetAssertionHandler 23 | , sdlGetAssertionReport 24 | , sdlResetAssertionReport 25 | 26 | -- * Assertion macros (as functions in Haskell) 27 | , sdlAssert 28 | , sdlAssertRelease 29 | , sdlAssertParanoid 30 | , sdlAssertAlways 31 | , sdlTriggerBreakpoint 32 | 33 | -- * Constants 34 | , sdlAssertLevel 35 | ) where 36 | 37 | import Foreign.Ptr 38 | import Foreign.C.Types 39 | import Foreign.C.String 40 | import Control.Monad 41 | import SDL.Stdinc (SDLBool) 42 | 43 | -- | Possible outcomes from a triggered assertion 44 | data SDLAssertState = 45 | SDL_ASSERTION_RETRY -- ^ Retry the assert immediately 46 | | SDL_ASSERTION_BREAK -- ^ Make the debugger trigger a breakpoint 47 | | SDL_ASSERTION_ABORT -- ^ Terminate the program 48 | | SDL_ASSERTION_IGNORE -- ^ Ignore the assert 49 | | SDL_ASSERTION_ALWAYS_IGNORE -- ^ Ignore the assert from now on 50 | deriving (Eq, Show, Enum) 51 | 52 | -- | Information about an assertion failure 53 | data SDLAssertData = SDLAssertData { 54 | alwaysIgnore :: Bool, -- ^ true if app should always continue when assertion is triggered 55 | triggerCount :: Word, -- ^ Number of times this assertion has been triggered 56 | condition :: String, -- ^ A string of this assert's test code 57 | filename :: String, -- ^ The source file where this assert lives 58 | linenum :: Int, -- ^ The line in `filename` where this assert lives 59 | function :: String, -- ^ The name of the function where this assert lives 60 | next :: Maybe SDLAssertData -- ^ next item in the linked list 61 | } 62 | 63 | -- | Foreign representation of the SDLAssertData structure 64 | data SDLAssertDataFFI 65 | 66 | -- | Callback type for custom assertion handlers 67 | type SDLAssertionHandler = Ptr SDLAssertDataFFI -> Ptr () -> IO CInt 68 | 69 | -- | The level of assertion aggressiveness 70 | sdlAssertLevel :: Int 71 | #ifdef DEBUG 72 | sdlAssertLevel = 2 -- Debug settings 73 | #else 74 | sdlAssertLevel = 1 -- Release settings 75 | #endif 76 | 77 | -- | Report an assertion failure 78 | foreign import ccall unsafe "SDL_ReportAssertion" 79 | sdlReportAssertion :: Ptr SDLAssertDataFFI -> CString -> CString -> CInt -> IO CInt 80 | 81 | -- | Set an application-defined assertion handler 82 | foreign import ccall unsafe "SDL_SetAssertionHandler" 83 | sdlSetAssertionHandler :: FunPtr SDLAssertionHandler -> Ptr () -> IO () 84 | 85 | -- | Get the default assertion handler 86 | foreign import ccall unsafe "SDL_GetDefaultAssertionHandler" 87 | sdlGetDefaultAssertionHandler :: IO (FunPtr SDLAssertionHandler) 88 | 89 | -- | Get the current assertion handler 90 | foreign import ccall unsafe "SDL_GetAssertionHandler" 91 | sdlGetAssertionHandler :: Ptr (Ptr ()) -> IO (FunPtr SDLAssertionHandler) 92 | 93 | -- | Get a list of all assertion failures 94 | foreign import ccall unsafe "SDL_GetAssertionReport" 95 | sdlGetAssertionReport :: IO (Ptr SDLAssertDataFFI) 96 | 97 | -- | Clear the list of all assertion failures 98 | foreign import ccall unsafe "SDL_ResetAssertionReport" 99 | sdlResetAssertionReport :: IO () 100 | 101 | -- | Attempt to tell an attached debugger to pause 102 | foreign import ccall unsafe "SDL_TriggerBreakpoint" 103 | sdlTriggerBreakpoint :: IO () 104 | 105 | -- | Implementation for SDL_assert as a Haskell function 106 | -- 107 | -- The original C macro uses compile-time magic to enable/disable assertions, 108 | -- but in Haskell we need to use runtime checking. 109 | sdlAssert :: Bool -> IO () 110 | #if defined(DEBUG) || (sdlAssertLevel >= 2) 111 | sdlAssert condition = unless condition $ sdlAssertHelper "assertion failed" 112 | #else 113 | sdlAssert _ = return () 114 | #endif 115 | 116 | -- | Implementation for SDL_assert_release as a Haskell function 117 | sdlAssertRelease :: Bool -> IO () 118 | #if (sdlAssertLevel >= 1) 119 | sdlAssertRelease condition = unless condition $ sdlAssertHelper "release assertion failed" 120 | #else 121 | sdlAssertRelease _ = return () 122 | #endif 123 | 124 | -- | Implementation for SDL_assert_paranoid as a Haskell function 125 | sdlAssertParanoid :: Bool -> IO () 126 | #if (sdlAssertLevel >= 3) 127 | sdlAssertParanoid condition = unless condition $ sdlAssertHelper "paranoid assertion failed" 128 | #else 129 | sdlAssertParanoid _ = return () 130 | #endif 131 | 132 | -- | Implementation for SDL_assert_always as a Haskell function 133 | sdlAssertAlways :: Bool -> IO () 134 | sdlAssertAlways condition = unless condition $ sdlAssertHelper "assertion failed" 135 | 136 | -- | Helper function for assertion implementations 137 | sdlAssertHelper :: String -> IO () 138 | sdlAssertHelper msg = do 139 | putStrLn $ "SDL assertion: " ++ msg 140 | sdlTriggerBreakpoint 141 | -------------------------------------------------------------------------------- /src/SDL/AsyncIO.hsc: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : SDL.AsyncIO 3 | Description : Bindings to SDL asynchronous I/O functionality 4 | Copyright : (c) Kyle Lukaszek, 2025 5 | License : BS3 6 | 7 | This module provides Haskell bindings to SDL's asynchronous I/O functionality. 8 | SDL offers a way to perform I/O asynchronously, allowing an app to read 9 | or write files without waiting for data to actually transfer. 10 | -} 11 | 12 | module SDL.AsyncIO 13 | ( 14 | -- * Types 15 | SDLAsyncIO 16 | , SDLAsyncIOTaskType(..) 17 | , SDLAsyncIOResult(..) 18 | , SDLAsyncIOOutcome(..) 19 | , SDLAsyncIOQueue 20 | 21 | -- * Functions 22 | , sdlAsyncIOFromFile 23 | , sdlGetAsyncIOSize 24 | , sdlReadAsyncIO 25 | , sdlWriteAsyncIO 26 | , sdlCloseAsyncIO 27 | , sdlCreateAsyncIOQueue 28 | , sdlDestroyAsyncIOQueue 29 | , sdlGetAsyncIOResult 30 | , sdlWaitAsyncIOResult 31 | , sdlSignalAsyncIOQueue 32 | , sdlLoadFileAsync 33 | ) where 34 | 35 | import Foreign.Ptr 36 | import Foreign.C.Types 37 | import Foreign.C.String 38 | import SDL.Stdinc (SDLBool) 39 | import Data.Word 40 | import Data.Int 41 | 42 | -- | The asynchronous I/O operation structure. 43 | data SDLAsyncIO = SDLAsyncIO 44 | 45 | -- | Types of asynchronous I/O tasks. 46 | data SDLAsyncIOTaskType = 47 | SDL_ASYNCIO_TASK_READ -- ^ A read operation. 48 | | SDL_ASYNCIO_TASK_WRITE -- ^ A write operation. 49 | | SDL_ASYNCIO_TASK_CLOSE -- ^ A close operation. 50 | deriving (Eq, Show, Enum) 51 | 52 | -- | Possible outcomes of an asynchronous I/O task. 53 | data SDLAsyncIOResult = 54 | SDL_ASYNCIO_COMPLETE -- ^ Request was completed without error 55 | | SDL_ASYNCIO_FAILURE -- ^ Request failed for some reason; check SDL_GetError()! 56 | | SDL_ASYNCIO_CANCELED -- ^ Request was canceled before completing. 57 | deriving (Eq, Show, Enum) 58 | 59 | -- | Information about a completed asynchronous I/O request. 60 | data SDLAsyncIOOutcome = SDL_AsyncIOOutcome 61 | { asyncio :: Ptr SDLAsyncIO -- ^ What generated this task. This pointer will be invalid if it was closed! 62 | , taskType :: SDLAsyncIOTaskType -- ^ What sort of task was this? Read, write, etc? 63 | , result :: SDLAsyncIOResult -- ^ The result of the work (success, failure, cancellation). 64 | , buffer :: Ptr () -- ^ Buffer where data was read/written. 65 | , offset :: Word64 -- ^ Offset in the SDL_AsyncIO where data was read/written. 66 | , bytesRequested :: Word64 -- ^ Number of bytes the task was to read/write. 67 | , bytesTransferred :: Word64 -- ^ Actual number of bytes that were read/written. 68 | , userdata :: Ptr () -- ^ Pointer provided by the app when starting the task 69 | } 70 | 71 | -- | A queue of completed asynchronous I/O tasks. 72 | data SDLAsyncIOQueue 73 | 74 | -- Foreign structure for SDL_AsyncIOOutcome 75 | data SDLAsyncIOOutcomeFFI 76 | 77 | -- | Create a new SDL_AsyncIO object for reading from and/or writing to a named file. 78 | foreign import ccall unsafe "SDL_AsyncIOFromFile" 79 | sdlAsyncIOFromFile :: CString -> CString -> IO (Ptr SDLAsyncIO) 80 | 81 | -- | Get the size of the data stream in an SDL_AsyncIO. 82 | foreign import ccall unsafe "SDL_GetAsyncIOSize" 83 | sdlGetAsyncIOSize :: Ptr SDLAsyncIO -> IO Int64 84 | 85 | -- | Start an async read. 86 | foreign import ccall unsafe "SDL_ReadAsyncIO" 87 | sdlReadAsyncIO :: Ptr SDLAsyncIO -> Ptr () -> Word64 -> Word64 -> Ptr SDLAsyncIOQueue -> Ptr () -> IO SDLBool 88 | 89 | -- | Start an async write. 90 | foreign import ccall unsafe "SDL_WriteAsyncIO" 91 | sdlWriteAsyncIO :: Ptr SDLAsyncIO -> Ptr () -> Word64 -> Word64 -> Ptr SDLAsyncIOQueue -> Ptr () -> IO SDLBool 92 | 93 | -- | Close and free any allocated resources for an async I/O object. 94 | foreign import ccall unsafe "SDL_CloseAsyncIO" 95 | sdlCloseAsyncIO :: Ptr SDLAsyncIO -> SDLBool -> Ptr SDLAsyncIOQueue -> Ptr () -> IO SDLBool 96 | 97 | -- | Create a task queue for tracking multiple I/O operations. 98 | foreign import ccall unsafe "SDL_CreateAsyncIOQueue" 99 | sdlCreateAsyncIOQueue :: IO (Ptr SDLAsyncIOQueue) 100 | 101 | -- | Destroy a previously-created async I/O task queue. 102 | foreign import ccall unsafe "SDL_DestroyAsyncIOQueue" 103 | sdlDestroyAsyncIOQueue :: Ptr SDLAsyncIOQueue -> IO () 104 | 105 | -- | Query an async I/O task queue for completed tasks. 106 | foreign import ccall unsafe "SDL_GetAsyncIOResult" 107 | sdlGetAsyncIOResult :: Ptr SDLAsyncIOQueue -> Ptr SDLAsyncIOOutcomeFFI -> IO SDLBool 108 | 109 | -- | Block until an async I/O task queue has a completed task. 110 | foreign import ccall unsafe "SDL_WaitAsyncIOResult" 111 | sdlWaitAsyncIOResult :: Ptr SDLAsyncIOQueue -> Ptr SDLAsyncIOOutcomeFFI -> Int32 -> IO SDLBool 112 | 113 | -- | Wake up any threads that are blocking in SDL_WaitAsyncIOResult(). 114 | foreign import ccall unsafe "SDL_SignalAsyncIOQueue" 115 | sdlSignalAsyncIOQueue :: Ptr SDLAsyncIOQueue -> IO () 116 | 117 | -- | Load all the data from a file path, asynchronously. 118 | foreign import ccall unsafe "SDL_LoadFileAsync" 119 | sdlLoadFileAsync :: CString -> Ptr SDLAsyncIOQueue -> Ptr () -> IO SDLBool 120 | -------------------------------------------------------------------------------- /src/SDL/Bits.hs: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : SDL.Bits 3 | Description : Bit manipulation functions 4 | Copyright : (c) Kyle Lukaszek, 2025 5 | License : BSD3 6 | 7 | Functions for fiddling with bits and bitmasks. 8 | -} 9 | 10 | module SDL.Bits 11 | ( -- * Bit Manipulation Functions 12 | sdlMostSignificantBitIndex32 13 | , sdlHasExactlyOneBitSet32 14 | ) where 15 | 16 | import Data.Word 17 | import Data.Bits 18 | 19 | -- | Get the index of the most significant (set) bit in a 32-bit number. 20 | -- 21 | -- Result is undefined when called with 0. This operation can also be stated 22 | -- as "count leading zeroes" and "log base 2". 23 | -- 24 | -- The function returns -1 if the input value is 0. 25 | -- 26 | -- @since 3.2.0 27 | sdlMostSignificantBitIndex32 :: Word32 -> Int 28 | sdlMostSignificantBitIndex32 0 = -1 29 | sdlMostSignificantBitIndex32 x = go x 0 30 | where 31 | go :: Word32 -> Int -> Int 32 | go 0 _ = -1 33 | go 1 acc = acc 34 | go n acc = go (n `shiftR` 1) (acc + 1) 35 | 36 | -- | Determine if a unsigned 32-bit value has exactly one bit set. 37 | -- 38 | -- If there are no bits set (x is zero), or more than one bit set, this 39 | -- returns False. If any one bit is exclusively set, this returns True. 40 | -- 41 | -- @since 3.2.0 42 | sdlHasExactlyOneBitSet32 :: Word32 -> Bool 43 | sdlHasExactlyOneBitSet32 0 = False 44 | sdlHasExactlyOneBitSet32 x = x .&. (x - 1) == 0 45 | -------------------------------------------------------------------------------- /src/SDL/CPUInfo.hsc: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE ForeignFunctionInterface #-} 3 | 4 | #include 5 | 6 | {-| 7 | Module : SDL.CPUInfo 8 | Description : CPU feature detection for SDL 9 | Copyright : (c) Kyle Lukaszek, 2025 10 | License : BSD3 11 | 12 | This module provides bindings to SDL's CPU information and feature detection functionality. 13 | It allows checking for various SIMD instruction sets and getting information about the system's 14 | CPU configuration. 15 | 16 | The CPU instruction set checks are available on all platforms, though they'll return False 17 | when checking for features that aren't applicable to the current CPU architecture 18 | (e.g., checking for SSE on ARM or NEON on x86). 19 | -} 20 | 21 | module SDL.CPUInfo 22 | ( -- * Constants 23 | sdlCachelineSize 24 | 25 | -- * CPU Information 26 | , sdlGetNumLogicalCPUCores 27 | , sdlGetCPUCacheLineSize 28 | , sdlGetSystemRAM 29 | , sdlGetSIMDAlignment 30 | 31 | -- * CPU Feature Detection 32 | -- ** PowerPC Features 33 | , sdlHasAltiVec 34 | 35 | -- ** x86 Features 36 | , sdlHasMMX 37 | , sdlHasSSE 38 | , sdlHasSSE2 39 | , sdlHasSSE3 40 | , sdlHasSSE41 41 | , sdlHasSSE42 42 | , sdlHasAVX 43 | , sdlHasAVX2 44 | , sdlHasAVX512F 45 | 46 | -- ** ARM Features 47 | , sdlHasARMSIMD 48 | , sdlHasNEON 49 | 50 | -- ** LOONGARCH Features 51 | , sdlHasLSX 52 | , sdlHasLASX 53 | ) where 54 | 55 | import Foreign.C.Types 56 | import Data.Word 57 | import Data.Int 58 | 59 | -- | A guess for the cacheline size used for padding. 60 | -- Most x86 processors have a 64 byte cache line. 61 | -- 64-bit PowerPC processors have a 128 byte cache line. 62 | -- We use the larger value to be generally safe. 63 | sdlCachelineSize :: Int 64 | sdlCachelineSize = #{const SDL_CACHELINE_SIZE} 65 | 66 | -- | Get the number of logical CPU cores available. 67 | foreign import ccall "SDL_GetNumLogicalCPUCores" 68 | sdlGetNumLogicalCPUCores :: IO CInt 69 | 70 | -- | Get the L1 cache line size of the CPU in bytes. 71 | foreign import ccall "SDL_GetCPUCacheLineSize" 72 | sdlGetCPUCacheLineSize :: IO CInt 73 | 74 | -- | Check if the CPU has AltiVec features (PowerPC). 75 | foreign import ccall "SDL_HasAltiVec" 76 | sdlHasAltiVec :: IO Bool 77 | 78 | -- | Check if the CPU has MMX features (x86). 79 | foreign import ccall "SDL_HasMMX" 80 | sdlHasMMX :: IO Bool 81 | 82 | -- | Check if the CPU has SSE features (x86). 83 | foreign import ccall "SDL_HasSSE" 84 | sdlHasSSE :: IO Bool 85 | 86 | -- | Check if the CPU has SSE2 features (x86). 87 | foreign import ccall "SDL_HasSSE2" 88 | sdlHasSSE2 :: IO Bool 89 | 90 | -- | Check if the CPU has SSE3 features (x86). 91 | foreign import ccall "SDL_HasSSE3" 92 | sdlHasSSE3 :: IO Bool 93 | 94 | -- | Check if the CPU has SSE4.1 features (x86). 95 | foreign import ccall "SDL_HasSSE41" 96 | sdlHasSSE41 :: IO Bool 97 | 98 | -- | Check if the CPU has SSE4.2 features (x86). 99 | foreign import ccall "SDL_HasSSE42" 100 | sdlHasSSE42 :: IO Bool 101 | 102 | -- | Check if the CPU has AVX features (x86). 103 | foreign import ccall "SDL_HasAVX" 104 | sdlHasAVX :: IO Bool 105 | 106 | -- | Check if the CPU has AVX2 features (x86). 107 | foreign import ccall "SDL_HasAVX2" 108 | sdlHasAVX2 :: IO Bool 109 | 110 | -- | Check if the CPU has AVX-512F (foundation) features (x86). 111 | foreign import ccall "SDL_HasAVX512F" 112 | sdlHasAVX512F :: IO Bool 113 | 114 | -- | Check if the CPU has ARM SIMD (ARMv6) features. 115 | foreign import ccall "SDL_HasARMSIMD" 116 | sdlHasARMSIMD :: IO Bool 117 | 118 | -- | Check if the CPU has NEON (ARM SIMD) features. 119 | foreign import ccall "SDL_HasNEON" 120 | sdlHasNEON :: IO Bool 121 | 122 | -- | Check if the CPU has LSX (LOONGARCH SIMD) features. 123 | foreign import ccall "SDL_HasLSX" 124 | sdlHasLSX :: IO Bool 125 | 126 | -- | Check if the CPU has LASX (LOONGARCH SIMD) features. 127 | foreign import ccall "SDL_HasLASX" 128 | sdlHasLASX :: IO Bool 129 | 130 | -- | Get the amount of RAM configured in the system in MiB. 131 | foreign import ccall "SDL_GetSystemRAM" 132 | sdlGetSystemRAM :: IO CInt 133 | 134 | -- | Get the alignment needed for SIMD allocations on this system. 135 | foreign import ccall "SDL_GetSIMDAlignment" 136 | sdlGetSIMDAlignment :: IO #{type size_t} 137 | -------------------------------------------------------------------------------- /src/SDL/Endian.hsc: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : SDL.Endian 3 | Description : Byte order conversion functions 4 | Copyright : (c) Kyle Lukaszek, 2025 5 | License : BSD3 6 | 7 | Functions for converting values between different byte orders. 8 | -} 9 | 10 | {-# LANGUAGE CPP #-} 11 | 12 | module SDL.Endian 13 | ( -- * Endianness Constants 14 | sdlLilEndian 15 | , sdlBigEndian 16 | , sdlByteOrder 17 | , sdlFloatWordOrder 18 | -- * Byte Swapping Functions 19 | , sdlSwap16 20 | , sdlSwap32 21 | , sdlSwap64 22 | , sdlSwapFloat 23 | -- * Endian Conversion Macros 24 | , sdlSwap16LE 25 | , sdlSwap32LE 26 | , sdlSwap64LE 27 | , sdlSwapFloatLE 28 | , sdlSwap16BE 29 | , sdlSwap32BE 30 | , sdlSwap64BE 31 | , sdlSwapFloatBE 32 | ) where 33 | 34 | import Foreign.C.Types 35 | import Data.Word 36 | import Data.Bits 37 | import Unsafe.Coerce (unsafeCoerce) 38 | 39 | -- | Represents little-endian byte order 40 | sdlLilEndian :: Int 41 | sdlLilEndian = 1234 42 | 43 | -- | Represents big-endian byte order 44 | sdlBigEndian :: Int 45 | sdlBigEndian = 4321 46 | 47 | {-| 48 | Indicates the byte order of the current system. 49 | Will be either 'sdlLilEndian' or 'sdlBigEndian'. 50 | -} 51 | -- This should be set based on architecture, but for now we'll default to little endian 52 | -- which is the most common 53 | sdlByteOrder :: Int 54 | #if defined(WORDS_BIGENDIAN) 55 | sdlByteOrder = sdlBigEndian 56 | #else 57 | sdlByteOrder = sdlLilEndian 58 | #endif 59 | 60 | {-| 61 | Indicates the floating point word order of the current system. 62 | Will be either 'sdlLilEndian' or 'sdlBigEndian'. 63 | -} 64 | -- Usually this follows the general system byte order 65 | sdlFloatWordOrder :: Int 66 | sdlFloatWordOrder = sdlByteOrder 67 | 68 | -- | Swaps the byte order of a 16-bit integer 69 | sdlSwap16 :: Word16 -> Word16 70 | sdlSwap16 x = (x `shiftL` 8) .|. (x `shiftR` 8) 71 | 72 | -- | Swaps the byte order of a 32-bit integer 73 | sdlSwap32 :: Word32 -> Word32 74 | sdlSwap32 x = 75 | ((x `shiftL` 24) .|. 76 | ((x `shiftL` 8) .&. 0x00FF0000) .|. 77 | ((x `shiftR` 8) .&. 0x0000FF00) .|. 78 | (x `shiftR` 24)) 79 | 80 | -- | Swaps the byte order of a 64-bit integer 81 | sdlSwap64 :: Word64 -> Word64 82 | sdlSwap64 x = 83 | let hi = fromIntegral (x .&. 0xFFFFFFFF) :: Word32 84 | lo = fromIntegral (x `shiftR` 32) :: Word32 85 | swappedHi = sdlSwap32 hi 86 | swappedLo = sdlSwap32 lo 87 | in (fromIntegral swappedHi `shiftL` 32) .|. fromIntegral swappedLo 88 | 89 | -- | Swaps the byte order of a floating point number 90 | sdlSwapFloat :: Float -> Float 91 | sdlSwapFloat x = 92 | let bits = floatToWord x 93 | swapped = sdlSwap32 bits 94 | in wordToFloat swapped 95 | where 96 | floatToWord :: Float -> Word32 97 | floatToWord = unsafeCoerce 98 | 99 | wordToFloat :: Word32 -> Float 100 | wordToFloat = unsafeCoerce 101 | 102 | -- Little endian to native conversion functions 103 | sdlSwap16LE :: Word16 -> Word16 104 | #if defined(WORDS_BIGENDIAN) 105 | sdlSwap16LE = sdlSwap16 106 | #else 107 | sdlSwap16LE x = x 108 | #endif 109 | 110 | sdlSwap32LE :: Word32 -> Word32 111 | #if defined(WORDS_BIGENDIAN) 112 | sdlSwap32LE = sdlSwap32 113 | #else 114 | sdlSwap32LE x = x 115 | #endif 116 | 117 | sdlSwap64LE :: Word64 -> Word64 118 | #if defined(WORDS_BIGENDIAN) 119 | sdlSwap64LE = sdlSwap64 120 | #else 121 | sdlSwap64LE x = x 122 | #endif 123 | 124 | sdlSwapFloatLE :: Float -> Float 125 | #if defined(WORDS_BIGENDIAN) 126 | sdlSwapFloatLE = sdlSwapFloat 127 | #else 128 | sdlSwapFloatLE x = x 129 | #endif 130 | 131 | -- Big endian to native conversion functions 132 | sdlSwap16BE :: Word16 -> Word16 133 | #if defined(WORDS_BIGENDIAN) 134 | sdlSwap16BE x = x 135 | #else 136 | sdlSwap16BE = sdlSwap16 137 | #endif 138 | 139 | sdlSwap32BE :: Word32 -> Word32 140 | #if defined(WORDS_BIGENDIAN) 141 | sdlSwap32BE x = x 142 | #else 143 | sdlSwap32BE = sdlSwap32 144 | #endif 145 | 146 | sdlSwap64BE :: Word64 -> Word64 147 | #if defined(WORDS_BIGENDIAN) 148 | sdlSwap64BE x = x 149 | #else 150 | sdlSwap64BE = sdlSwap64 151 | #endif 152 | 153 | sdlSwapFloatBE :: Float -> Float 154 | #if defined(WORDS_BIGENDIAN) 155 | sdlSwapFloatBE x = x 156 | #else 157 | sdlSwapFloatBE = sdlSwapFloat 158 | #endif 159 | -------------------------------------------------------------------------------- /src/SDL/Error.hs: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : SDL.Error 3 | Description : Simple error message routines for SDL 4 | Copyright : (c) Kyle Lukaszek 5 | License : BSD3 6 | 7 | Simple error message routines for SDL. 8 | 9 | Most apps will interface with these APIs in exactly one function: when almost any SDL function 10 | call reports failure, you can get a human-readable string of the problem from 'sdlGetError'. 11 | 12 | These strings are maintained per-thread, and apps are welcome to set their own errors, which is 13 | popular when building libraries on top of SDL for other apps to consume. These strings are set 14 | by calling 'sdlSetError'. 15 | -} 16 | 17 | module SDL.Error 18 | ( -- * Error Handling Functions 19 | sdlSetError 20 | , sdlSetErrorV 21 | , sdlOutOfMemory 22 | , sdlGetError 23 | , sdlClearError 24 | -- * Internal Error Macros 25 | , sdlUnsupported 26 | , sdlInvalidParamError 27 | ) where 28 | 29 | import Foreign.C.String (CString, withCString, peekCString) 30 | import Foreign.C.Types (CBool(..)) 31 | import Control.Monad (void) 32 | import Data.Bool (bool) 33 | 34 | -- | Set the SDL error message for the current thread. 35 | -- 36 | -- Calling this function will replace any previous error message that was set. 37 | -- 38 | -- This function always returns False, since SDL frequently uses False to signify a failing result. 39 | -- 40 | -- @since 3.2.0 41 | foreign import ccall "SDL_SetError" sdlSetError :: CString -> IO CBool 42 | 43 | -- | Set the SDL error message for the current thread. 44 | -- 45 | -- Calling this function will replace any previous error message that was set. 46 | -- 47 | -- @since 3.2.0 48 | foreign import ccall "SDL_SetErrorV" sdlSetErrorV :: CString -> IO CBool 49 | 50 | -- | Set an error indicating that memory allocation failed. 51 | -- 52 | -- This function does not do any memory allocation. 53 | -- 54 | -- @since 3.2.0 55 | foreign import ccall "SDL_OutOfMemory" sdlOutOfMemory :: IO CBool 56 | 57 | -- | Retrieve a message about the last error that occurred on the current thread. 58 | -- 59 | -- It is possible for multiple errors to occur before calling 'sdlGetError'. 60 | -- Only the last error is returned. 61 | -- 62 | -- The message is only applicable when an SDL function has signaled an error. 63 | -- You must check the return values of SDL function calls to determine when to 64 | -- appropriately call 'sdlGetError'. You should not use the results of 65 | -- 'sdlGetError' to decide if an error has occurred! Sometimes SDL will set 66 | -- an error string even when reporting success. 67 | -- 68 | -- SDL will not clear the error string for successful API calls. You must 69 | -- check return values for failure cases before you can assume the error 70 | -- string applies. 71 | -- 72 | -- Error strings are set per-thread, so an error set in a different thread 73 | -- will not interfere with the current thread's operation. 74 | -- 75 | -- The returned value is a thread-local string which will remain valid until 76 | -- the current thread's error string is changed. The caller should make a copy 77 | -- if the value is needed after the next SDL API call. 78 | -- 79 | -- @since 3.2.0 80 | sdlGetError :: IO String 81 | sdlGetError = do 82 | cstr <- sdlGetErrorRaw 83 | peekCString cstr 84 | 85 | -- | Raw C function for SDL_GetError 86 | foreign import ccall "SDL_GetError" sdlGetErrorRaw :: IO CString 87 | 88 | -- | Clear any previous error message for this thread. 89 | -- 90 | -- @since 3.2.0 91 | sdlClearError :: IO Bool 92 | sdlClearError = fmap cboolToBool sdlClearErrorRaw 93 | where 94 | cboolToBool :: CBool -> Bool 95 | cboolToBool (CBool 0) = False 96 | cboolToBool _ = True 97 | 98 | -- | Raw C function for SDL_ClearError 99 | foreign import ccall "SDL_ClearError" sdlClearErrorRaw :: IO CBool 100 | 101 | -- | A standard error message for unsupported operations. 102 | -- 103 | -- This is a convenience function that sets the error message to 104 | -- "That operation is not supported". 105 | -- 106 | -- @since 3.2.0 107 | sdlUnsupported :: IO Bool 108 | sdlUnsupported = withCString "That operation is not supported" $ \cstr -> do 109 | CBool val <- sdlSetError cstr 110 | return (val /= 0) 111 | 112 | -- | A standard error message for invalid parameters. 113 | -- 114 | -- This is a convenience function that sets the error message to 115 | -- "Parameter 'param' is invalid", where param is the provided string. 116 | -- 117 | -- @since 3.2.0 118 | sdlInvalidParamError :: String -> IO Bool 119 | sdlInvalidParamError param = 120 | withCString ("Parameter '" ++ param ++ "' is invalid") $ \cstr -> do 121 | CBool val <- sdlSetError cstr 122 | return (val /= 0) 123 | -------------------------------------------------------------------------------- /src/SDL/GUID.hsc: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ForeignFunctionInterface #-} 2 | 3 | {-| 4 | Module : SDL.Guid 5 | Description : SDL GUID functions for working with globally unique identifiers 6 | Copyright : Kyle Lukaszek, 2025 7 | License : BSD3 8 | 9 | This module provides bindings to the SDL3 GUID functions, allowing Haskell applications 10 | to work with 128-bit globally unique identifiers (GUIDs) used to identify input devices 11 | across runs of SDL programs on the same platform. 12 | 13 | The GUID functionality allows conversion between binary GUID structures and their 14 | ASCII string representations. 15 | -} 16 | 17 | module SDL.GUID 18 | ( -- * Types 19 | SDLGUID(..) 20 | 21 | -- * GUID Operations 22 | , sdlGUIDToString 23 | , sdlStringToGUID 24 | ) where 25 | 26 | import System.IO 27 | import Foreign 28 | import Foreign.C.Types 29 | import Foreign.C.String 30 | import Data.Word 31 | import Control.Monad 32 | 33 | #include 34 | 35 | -- Define the proper structure for SDL_GUID to match C declaration 36 | data SDL_GUID = SDL_GUID 37 | { guidData :: [Word8] -- 16-byte array 38 | } deriving (Show, Eq) 39 | 40 | -- Create a newtype for easier manipulation in Haskell 41 | newtype SDLGUID = SDLGUID { unSDLGUID :: [Word8] } 42 | deriving (Show, Eq) 43 | 44 | -- Define the storable instance for SDL_GUID to properly handle marshalling 45 | instance Storable SDLGUID where 46 | sizeOf _ = 16 -- Size of the SDL_GUID struct (16 bytes) 47 | alignment _ = alignment (undefined :: Word8) 48 | 49 | peek ptr = do 50 | bytes <- peekArray 16 (castPtr ptr) 51 | return $ SDLGUID bytes 52 | 53 | poke ptr (SDLGUID bytes) = do 54 | pokeArray (castPtr ptr) (take 16 $ bytes ++ repeat 0) 55 | 56 | -- Foreign declarations around wrappers 57 | foreign import ccall safe "wrapper_SDL_GUIDToString" sdlGUIDToStringRaw :: 58 | Ptr Word8 -> CString -> CInt -> IO () 59 | foreign import ccall safe "wrapper_SDL_StringToGUID" sdlStringToGUIDRaw :: 60 | CString -> Ptr Word8 -> IO () 61 | 62 | -- Convert our SDLGUID to string 63 | sdlGUIDToString :: SDLGUID -> IO String 64 | sdlGUIDToString (SDLGUID bytes) = do 65 | let guidBytes = take 16 $ bytes ++ repeat 0 -- Ensure we have exactly 16 bytes 66 | 67 | withArray guidBytes $ \guidPtr -> do 68 | -- Allocate a buffer for the string (33 bytes as specified in the SDL docs) 69 | allocaArray 33 $ \strPtr -> do 70 | -- Call the SDL wrapper function 71 | sdlGUIDToStringRaw guidPtr strPtr 33 72 | -- Convert the result to a Haskell String 73 | peekCString strPtr 74 | 75 | -- Convert a string to our SDLGUID 76 | sdlStringToGUID :: String -> IO SDLGUID 77 | sdlStringToGUID str = do 78 | -- Allocate space for the GUID data (16 bytes) 79 | allocaArray 16 $ \guidPtr -> do 80 | -- Convert our string to C string and call SDL wrapper function 81 | withCString str $ \strPtr -> do 82 | sdlStringToGUIDRaw strPtr guidPtr 83 | -- Read the bytes back 84 | bytes <- peekArray 16 guidPtr 85 | return $ SDLGUID bytes 86 | 87 | -------------------------------------------------------------------------------- /src/SDL/LoadSO.hsc: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ForeignFunctionInterface #-} 2 | {-| 3 | Module : SDL.LoadSO 4 | Description : SDL shared object loading utilities 5 | Copyright : (c) Kyle Lukaszek, 2025 6 | License : BS3 7 | 8 | System-dependent library loading routines for working with shared objects 9 | (DLLs on Windows, shared libraries on Linux, etc.). 10 | -} 11 | 12 | module SDL.LoadSO 13 | ( -- * Types 14 | SDLSharedObject 15 | , SDLFunctionPointer 16 | 17 | -- * Functions 18 | , sdlLoadObject 19 | , sdlLoadFunction 20 | , sdlUnloadObject 21 | ) where 22 | 23 | #include 24 | 25 | import Foreign.C.Types (CInt) 26 | import Foreign.Ptr (Ptr, nullPtr, FunPtr, nullFunPtr) 27 | import Foreign.C.String (CString, withCString) 28 | 29 | -- | Opaque type representing a loaded shared object 30 | data SDLSharedObject 31 | 32 | -- | Type alias for function pointers loaded from shared objects 33 | type SDLFunctionPointer = FunPtr () 34 | 35 | -- | Dynamically load a shared object 36 | foreign import ccall "SDL_LoadObject" 37 | sdlLoadObjectRaw :: CString -> IO (Ptr SDLSharedObject) 38 | 39 | sdlLoadObject :: String -> IO (Maybe (Ptr SDLSharedObject)) 40 | sdlLoadObject sofile = withCString sofile $ \cstr -> do 41 | handle <- sdlLoadObjectRaw cstr 42 | return $ if handle == nullPtr 43 | then Nothing 44 | else Just handle 45 | 46 | -- | Look up a function in a shared object 47 | foreign import ccall "SDL_LoadFunction" 48 | sdlLoadFunctionRaw :: Ptr SDLSharedObject -> CString -> IO SDLFunctionPointer 49 | 50 | sdlLoadFunction :: Ptr SDLSharedObject -> String -> IO (Maybe SDLFunctionPointer) 51 | sdlLoadFunction handle name = withCString name $ \cstr -> do 52 | ptr <- sdlLoadFunctionRaw handle cstr 53 | return $ if ptr == nullFunPtr 54 | then Nothing 55 | else Just ptr 56 | 57 | -- | Unload a shared object 58 | foreign import ccall "SDL_UnloadObject" 59 | sdlUnloadObject :: Ptr SDLSharedObject -> IO () 60 | -------------------------------------------------------------------------------- /src/SDL/Locale.hsc: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ForeignFunctionInterface #-} 2 | {-| 3 | Module : SDL.Locale - SDL Locale 4 | Description : SDL locale services 5 | Copyright : (c) Kyle Lukaszek, 2025 6 | Starting new chunk from module SDL.Log 7 | License : BSD3 8 | Description : Provides access to user's preferred locales (language and country) 9 | -} 10 | 11 | module SDL.Locale 12 | ( -- * Types 13 | SDLLocale(..) 14 | 15 | -- * Functions 16 | , sdlGetPreferredLocales 17 | ) where 18 | 19 | #include 20 | 21 | import Foreign.C.Types (CInt(..)) 22 | import Foreign.Ptr (Ptr, nullPtr) 23 | import Foreign.C.String (peekCString) 24 | import Foreign.Marshal.Alloc (free, alloca) 25 | import Foreign.Storable (Storable(..)) 26 | import Foreign.Marshal.Array (peekArray, advancePtr) 27 | 28 | -- | Represents a locale with language and optional country code 29 | data SDLLocale = SDLLocale 30 | { language :: String -- ^ ISO-639 language code (e.g., "en") 31 | , country :: Maybe String -- ^ ISO-3166 country code (e.g., "US"), or Nothing 32 | } deriving (Eq, Show) 33 | 34 | instance Storable SDLLocale where 35 | sizeOf _ = #size SDL_Locale 36 | alignment _ = #alignment SDL_Locale 37 | peek ptr = do 38 | lang <- peekCString =<< (#peek SDL_Locale, language) ptr 39 | countryPtr <- (#peek SDL_Locale, country) ptr 40 | country <- if countryPtr == nullPtr 41 | then return Nothing 42 | else Just <$> peekCString countryPtr 43 | return $ SDLLocale lang country 44 | poke _ _ = error "SDLLocale.poke not implemented" -- Not needed for this use case 45 | 46 | -- | Get the user's preferred locales 47 | foreign import ccall "SDL_GetPreferredLocales" 48 | sdlGetPreferredLocalesRaw :: Ptr CInt -> IO (Ptr (Ptr SDLLocale)) 49 | 50 | sdlGetPreferredLocales :: IO [SDLLocale] 51 | sdlGetPreferredLocales = alloca $ \countPtr -> do 52 | poke countPtr 0 53 | localePtrs <- sdlGetPreferredLocalesRaw countPtr 54 | if localePtrs == nullPtr 55 | then return [] 56 | else do 57 | count <- peek countPtr 58 | locales <- peekArray (fromIntegral count) localePtrs 59 | mapM peek locales <* free localePtrs 60 | -------------------------------------------------------------------------------- /src/SDL/Metal.hsc: -------------------------------------------------------------------------------- 1 | -- SDL/Metal.hsc 2 | {-# LANGUAGE ForeignFunctionInterface #-} 3 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} -- Keep if SDLMetalView needs it later 4 | 5 | {-| 6 | Module : SDL.Metal 7 | Description : SDL Metal layer and view creation functions 8 | Copyright : Kyle Lukaszek, 2025 9 | License : BSD3 10 | 11 | This module provides bindings to the SDL3 Metal API, allowing Haskell applications 12 | to create Metal layers and views on SDL windows for Apple platforms (macOS, iOS, tvOS). 13 | These functions are useful for specific OS-level integration tasks with Metal. 14 | 15 | Note: On macOS, SDL does not automatically associate a MTLDevice with the CAMetalLayer; 16 | this must be handled in user code. 17 | -} 18 | 19 | module SDL.Metal 20 | ( -- * Types 21 | SDLMetalView(..) 22 | 23 | -- * Metal Support Functions 24 | , sdlMetalCreateView 25 | , sdlMetalDestroyView 26 | , sdlMetalGetLayer 27 | ) where 28 | 29 | import Foreign hiding (void) -- Avoid hiding void from Prelude if Ptr () is okay 30 | import Foreign.C.Types 31 | import SDL.Video (SDLWindow(..)) -- Import the newtype 32 | 33 | #include 34 | 35 | -- | A handle to a CAMetalLayer-backed NSView (macOS) or UIView (iOS/tvOS). 36 | -- Using Ptr () as the C API returns void*. 37 | newtype SDLMetalView = SDLMetalView (Ptr ()) 38 | deriving (Show, Eq) 39 | 40 | -- | Raw C binding for SDL_Metal_CreateView 41 | foreign import ccall unsafe "SDL_Metal_CreateView" 42 | sdlMetalCreateViewRaw :: Ptr SDLWindow -> IO (Ptr ()) -- Use Ptr SDL_Window 43 | 44 | -- | Create a CAMetalLayer-backed NSView/UIView and attach it to the specified window. 45 | -- Returns Nothing if creation fails. 46 | sdlMetalCreateView :: SDLWindow -> IO (Maybe SDLMetalView) 47 | sdlMetalCreateView (SDLWindow windowPtr) = do -- Unpack SDLWindow 48 | view <- sdlMetalCreateViewRaw windowPtr -- Pass unwrapped Ptr SDL_Window 49 | if view == nullPtr 50 | then return Nothing 51 | else return $ Just $ SDLMetalView view 52 | 53 | -- | Raw C binding for SDL_Metal_DestroyView 54 | foreign import ccall unsafe "SDL_Metal_DestroyView" 55 | sdlMetalDestroyViewRaw :: Ptr () -> IO () 56 | 57 | -- | Destroy an existing SDL_MetalView object. 58 | -- Should be called before destroying the associated window if created after window creation. 59 | sdlMetalDestroyView :: SDLMetalView -> IO () 60 | sdlMetalDestroyView (SDLMetalView view) = sdlMetalDestroyViewRaw view 61 | 62 | -- | Raw C binding for SDL_Metal_GetLayer 63 | foreign import ccall unsafe "SDL_Metal_GetLayer" 64 | sdlMetalGetLayerRaw :: Ptr () -> IO (Ptr ()) 65 | 66 | -- | Get a pointer to the backing CAMetalLayer for the given view. 67 | -- Returns Nothing if the layer cannot be retrieved. 68 | sdlMetalGetLayer :: SDLMetalView -> IO (Maybe (Ptr ())) 69 | sdlMetalGetLayer (SDLMetalView view) = do 70 | layer <- sdlMetalGetLayerRaw view 71 | if layer == nullPtr 72 | then return Nothing 73 | else return $ Just layer 74 | -------------------------------------------------------------------------------- /src/SDL/Misc.hsc: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ForeignFunctionInterface #-} 2 | 3 | {-| 4 | Module : SDL.Misc 5 | Description : Miscellaneous SDL functions 6 | Copyright : Kyle Lukaszek, 2025 7 | License : BSD3 8 | 9 | This module provides bindings to SDL3 API functions that don't fit elsewhere, 10 | such as opening URLs in the system browser. 11 | -} 12 | 13 | module SDL.Misc 14 | ( -- * URL Handling 15 | sdlOpenURL 16 | ) where 17 | 18 | import Foreign 19 | import Foreign.C.Types 20 | import Foreign.C.String 21 | import Data.Word 22 | import Data.Int 23 | import Control.Monad 24 | 25 | import SDL.Stdinc 26 | import SDL.Error 27 | 28 | #include 29 | 30 | -- | Open a URL/URI in the browser or other appropriate external application. 31 | foreign import ccall "SDL_OpenURL" sdlOpenURLRaw :: CString -> IO Bool 32 | 33 | -- | Open a URL/URI in the browser or other appropriate external application. 34 | -- This high-level function wraps the SDL_OpenURL C function, converting the 35 | -- Haskell String to a C string and handling errors appropriately. 36 | sdlOpenURL :: String -> IO Bool 37 | sdlOpenURL url = withCString url sdlOpenURLRaw 38 | -------------------------------------------------------------------------------- /src/SDL/Pen.hsc: -------------------------------------------------------------------------------- 1 | -- SDL/Pen.hsc 2 | {-# LANGUAGE ForeignFunctionInterface #-} 3 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 4 | {-# LANGUAGE PatternSynonyms #-} 5 | {-# LANGUAGE DerivingStrategies #-} 6 | 7 | -- | 8 | -- Module : SDL.Pen 9 | -- Description : SDL pen event handling functions 10 | -- Copyright : Kyle Lukaszek, 2025 11 | -- License : BSD3 12 | -- 13 | -- This module provides bindings to the SDL3 pen API, allowing Haskell applications 14 | -- to handle pressure-sensitive pen input (stylus and/or eraser) for devices such as 15 | -- drawing tablets and suitably equipped mobile/tablet devices. 16 | -- 17 | -- To use these functions, SDL must be initialized and the application should handle 18 | -- SDL_EVENT_PEN_* events. 19 | 20 | #include 21 | 22 | module SDL.Pen 23 | ( -- * Types 24 | SDLPenID 25 | , SDLPenInputFlags(..) 26 | , SDLPenAxis(..) 27 | 28 | -- * Constants / Patterns 29 | , pattern SDL_PEN_MOUSEID 30 | , pattern SDL_PEN_TOUCHID 31 | , pattern SDL_PEN_INPUT_DOWN 32 | , pattern SDL_PEN_INPUT_BUTTON_1 33 | , pattern SDL_PEN_INPUT_BUTTON_2 34 | , pattern SDL_PEN_INPUT_BUTTON_3 35 | , pattern SDL_PEN_INPUT_BUTTON_4 36 | , pattern SDL_PEN_INPUT_BUTTON_5 37 | , pattern SDL_PEN_INPUT_ERASER_TIP 38 | , pattern SDL_PEN_AXIS_PRESSURE 39 | , pattern SDL_PEN_AXIS_XTILT 40 | , pattern SDL_PEN_AXIS_YTILT 41 | , pattern SDL_PEN_AXIS_DISTANCE 42 | , pattern SDL_PEN_AXIS_ROTATION 43 | , pattern SDL_PEN_AXIS_SLIDER 44 | , pattern SDL_PEN_AXIS_TANGENTIAL_PRESSURE 45 | , pattern SDL_PEN_AXIS_COUNT 46 | ) where 47 | 48 | import Foreign (Ptr, FunPtr, nullPtr, nullFunPtr) 49 | import Foreign.C.Types (CInt(..)) 50 | import Foreign.Storable (Storable) 51 | import Data.Word (Word32, Word64) 52 | import Data.Bits (Bits, (.|.)) 53 | import SDL.Mouse (SDLMouseID) -- Assuming SDLMouseID is Word32 or similar 54 | import SDL.Touch (SDLTouchID) -- Assuming SDLTouchID is Word64 or similar 55 | 56 | -- | SDL pen instance ID. 57 | -- Zero signifies an invalid/null device. 58 | -- Using a type alias as it's just an identifier. 59 | type SDLPenID = Word32 60 | 61 | -- | Pen input flags as reported in pen events' pen_state field. 62 | -- Wraps a Word32 as the C #defines are flags (bitmasks). 63 | newtype SDLPenInputFlags = SDLPenInputFlags Word32 64 | deriving newtype (Show, Eq, Bits, Num, Storable) -- Added Num for convenience with bitwise OR 65 | 66 | pattern SDL_PEN_INPUT_DOWN :: SDLPenInputFlags 67 | pattern SDL_PEN_INPUT_DOWN = SDLPenInputFlags #{const SDL_PEN_INPUT_DOWN} 68 | pattern SDL_PEN_INPUT_BUTTON_1 :: SDLPenInputFlags 69 | pattern SDL_PEN_INPUT_BUTTON_1 = SDLPenInputFlags #{const SDL_PEN_INPUT_BUTTON_1} 70 | pattern SDL_PEN_INPUT_BUTTON_2 :: SDLPenInputFlags 71 | pattern SDL_PEN_INPUT_BUTTON_2 = SDLPenInputFlags #{const SDL_PEN_INPUT_BUTTON_2} 72 | pattern SDL_PEN_INPUT_BUTTON_3 :: SDLPenInputFlags 73 | pattern SDL_PEN_INPUT_BUTTON_3 = SDLPenInputFlags #{const SDL_PEN_INPUT_BUTTON_3} 74 | pattern SDL_PEN_INPUT_BUTTON_4 :: SDLPenInputFlags 75 | pattern SDL_PEN_INPUT_BUTTON_4 = SDLPenInputFlags #{const SDL_PEN_INPUT_BUTTON_4} 76 | pattern SDL_PEN_INPUT_BUTTON_5 :: SDLPenInputFlags 77 | pattern SDL_PEN_INPUT_BUTTON_5 = SDLPenInputFlags #{const SDL_PEN_INPUT_BUTTON_5} 78 | pattern SDL_PEN_INPUT_ERASER_TIP :: SDLPenInputFlags 79 | pattern SDL_PEN_INPUT_ERASER_TIP = SDLPenInputFlags #{const SDL_PEN_INPUT_ERASER_TIP} 80 | 81 | -- | Pen axis indices for SDL_PenAxisEvent. 82 | -- Wraps CInt as the C type is a standard enum. 83 | newtype SDLPenAxis = SDLPenAxis CInt 84 | deriving newtype (Show, Eq, Ord, Storable, Enum) 85 | 86 | pattern SDL_PEN_AXIS_PRESSURE :: SDLPenAxis 87 | pattern SDL_PEN_AXIS_PRESSURE = SDLPenAxis #{const SDL_PEN_AXIS_PRESSURE} 88 | pattern SDL_PEN_AXIS_XTILT :: SDLPenAxis 89 | pattern SDL_PEN_AXIS_XTILT = SDLPenAxis #{const SDL_PEN_AXIS_XTILT} 90 | pattern SDL_PEN_AXIS_YTILT :: SDLPenAxis 91 | pattern SDL_PEN_AXIS_YTILT = SDLPenAxis #{const SDL_PEN_AXIS_YTILT} 92 | pattern SDL_PEN_AXIS_DISTANCE :: SDLPenAxis 93 | pattern SDL_PEN_AXIS_DISTANCE = SDLPenAxis #{const SDL_PEN_AXIS_DISTANCE} 94 | pattern SDL_PEN_AXIS_ROTATION :: SDLPenAxis 95 | pattern SDL_PEN_AXIS_ROTATION = SDLPenAxis #{const SDL_PEN_AXIS_ROTATION} 96 | pattern SDL_PEN_AXIS_SLIDER :: SDLPenAxis 97 | pattern SDL_PEN_AXIS_SLIDER = SDLPenAxis #{const SDL_PEN_AXIS_SLIDER} 98 | pattern SDL_PEN_AXIS_TANGENTIAL_PRESSURE :: SDLPenAxis 99 | pattern SDL_PEN_AXIS_TANGENTIAL_PRESSURE = SDLPenAxis #{const SDL_PEN_AXIS_TANGENTIAL_PRESSURE} 100 | pattern SDL_PEN_AXIS_COUNT :: SDLPenAxis 101 | pattern SDL_PEN_AXIS_COUNT = SDLPenAxis #{const SDL_PEN_AXIS_COUNT} 102 | 103 | -- | Mouse ID for mouse events simulated with pen input. 104 | pattern SDL_PEN_MOUSEID :: SDLMouseID 105 | pattern SDL_PEN_MOUSEID = #{const SDL_PEN_MOUSEID} 106 | 107 | -- | Touch ID for touch events simulated with pen input. 108 | pattern SDL_PEN_TOUCHID :: SDLTouchID 109 | pattern SDL_PEN_TOUCHID = #{const SDL_PEN_TOUCHID} 110 | -------------------------------------------------------------------------------- /src/SDL/Power.hsc: -------------------------------------------------------------------------------- 1 | -- SDL/Power.hsc 2 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 3 | {-# LANGUAGE PatternSynonyms #-} 4 | {-# LANGUAGE DerivingStrategies #-} 5 | {-# LANGUAGE ForeignFunctionInterface #-} 6 | 7 | -- | 8 | -- Module : SDL.Power 9 | -- Description : Power management functions for SDL3. 10 | -- Copyright : (c) Kyle Lukaszek, 2025 11 | -- License : BSD3 12 | -- 13 | -- This module provides Haskell bindings to the SDL3 power management functionality. 14 | 15 | #include 16 | 17 | module SDL.Power 18 | ( 19 | -- * Types 20 | SDLPowerState(..) 21 | 22 | -- * Patterns / Constants 23 | , pattern SDL_POWERSTATE_ERROR 24 | , pattern SDL_POWERSTATE_UNKNOWN 25 | , pattern SDL_POWERSTATE_ON_BATTERY 26 | , pattern SDL_POWERSTATE_NO_BATTERY 27 | , pattern SDL_POWERSTATE_CHARGING 28 | , pattern SDL_POWERSTATE_CHARGED 29 | 30 | -- * Functions 31 | , sdlGetPowerInfo 32 | ) where 33 | 34 | import Foreign (Ptr, Storable, nullPtr) 35 | import Foreign.C.Types (CInt(..)) 36 | 37 | -- | The basic state for the system's power supply. 38 | newtype SDLPowerState = SDLPowerState CInt 39 | deriving newtype (Eq, Ord, Storable, Enum) -- Deriving common instances 40 | 41 | -- Define pattern synonyms using the C constants 42 | pattern SDL_POWERSTATE_ERROR :: SDLPowerState 43 | pattern SDL_POWERSTATE_ERROR = SDLPowerState (#{const SDL_POWERSTATE_ERROR}) 44 | pattern SDL_POWERSTATE_UNKNOWN :: SDLPowerState 45 | pattern SDL_POWERSTATE_UNKNOWN = SDLPowerState #{const SDL_POWERSTATE_UNKNOWN} 46 | pattern SDL_POWERSTATE_ON_BATTERY :: SDLPowerState 47 | pattern SDL_POWERSTATE_ON_BATTERY = SDLPowerState #{const SDL_POWERSTATE_ON_BATTERY} 48 | pattern SDL_POWERSTATE_NO_BATTERY :: SDLPowerState 49 | pattern SDL_POWERSTATE_NO_BATTERY = SDLPowerState #{const SDL_POWERSTATE_NO_BATTERY} 50 | pattern SDL_POWERSTATE_CHARGING :: SDLPowerState 51 | pattern SDL_POWERSTATE_CHARGING = SDLPowerState #{const SDL_POWERSTATE_CHARGING} 52 | pattern SDL_POWERSTATE_CHARGED :: SDLPowerState 53 | pattern SDL_POWERSTATE_CHARGED = SDLPowerState #{const SDL_POWERSTATE_CHARGED} 54 | 55 | -- Provide a more informative Show instance using patterns 56 | instance Show SDLPowerState where 57 | show ps 58 | | ps == SDL_POWERSTATE_ERROR = "SDL_POWERSTATE_ERROR" 59 | | ps == SDL_POWERSTATE_UNKNOWN = "SDL_POWERSTATE_UNKNOWN" 60 | | ps == SDL_POWERSTATE_ON_BATTERY = "SDL_POWERSTATE_ON_BATTERY" 61 | | ps == SDL_POWERSTATE_NO_BATTERY = "SDL_POWERSTATE_NO_BATTERY" 62 | | ps == SDL_POWERSTATE_CHARGING = "SDL_POWERSTATE_CHARGING" 63 | | ps == SDL_POWERSTATE_CHARGED = "SDL_POWERSTATE_CHARGED" 64 | | otherwise = "SDLPowerState " ++ show n -- Fallback 65 | where (SDLPowerState n) = ps -- Unpack for the fallback case 66 | 67 | -- FFI Import using c_ prefix convention 68 | foreign import ccall unsafe "SDL_GetPowerInfo" 69 | c_sdlGetPowerInfo :: Ptr CInt -> Ptr CInt -> IO CInt -- Return raw CInt 70 | 71 | -- Haskell Wrapper 72 | -- | Get the current power supply details. 73 | -- Returns the power state and optionally fills in seconds and percent of battery life remaining. 74 | -- Passing Nothing for the Ptr arguments means you don't want that value. 75 | -- Returns Nothing if SDL reports an error state. 76 | sdlGetPowerInfo :: Maybe (Ptr CInt) {-^ Pointer to store seconds remaining, or Nothing -} -> 77 | Maybe (Ptr CInt) {-^ Pointer to store percentage remaining, or Nothing -} -> 78 | IO (Maybe SDLPowerState) {-^ Power state, or Nothing on error -} 79 | sdlGetPowerInfo mSecondsPtr mPercentPtr = do 80 | let secPtr = maybe nullPtr id mSecondsPtr 81 | pctPtr = maybe nullPtr id mPercentPtr 82 | stateCInt <- c_sdlGetPowerInfo secPtr pctPtr 83 | let state = toEnum (fromIntegral stateCInt) :: SDLPowerState 84 | return $ if state == SDL_POWERSTATE_ERROR then Nothing else Just state 85 | -------------------------------------------------------------------------------- /src/SDL/Version.hsc: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ForeignFunctionInterface #-} 2 | {-| 3 | Module : SDL.Version 4 | Description : SDL version querying and management 5 | Copyright : (c) Kyle Lukaszek, 2025 6 | License : BSD3 7 | 8 | SDL provides functionality to query the current SDL version, both as headers 9 | the application was compiled against and as a library the application is linked to. 10 | 11 | This module allows you to access the compile-time version of SDL through constants 12 | and macros, as well as retrieve the runtime version and revision of the linked SDL 13 | library. This is particularly useful when linking dynamically to SDL, where the 14 | linked library version might differ from the version used at compile time. 15 | 16 | The version information can be used to ensure compatibility or to log details for 17 | debugging purposes. 18 | -} 19 | 20 | module SDL.Version 21 | ( -- * Version Constants 22 | sdlMajorVersion 23 | , sdlMinorVersion 24 | , sdlMicroVersion 25 | , sdlVersion 26 | , sdlVersionAtLeast 27 | 28 | -- * Version Functions 29 | , sdlGetVersion 30 | , sdlGetRevision 31 | ) where 32 | 33 | #include 34 | 35 | import Foreign.C.Types 36 | import Foreign.C.String (CString, peekCString) 37 | import Data.Word (Word32) 38 | 39 | -- | The current major version of SDL headers (SDL_MAJOR_VERSION). 40 | sdlMajorVersion :: Int 41 | sdlMajorVersion = #const SDL_MAJOR_VERSION 42 | 43 | -- | The current minor version of SDL headers (SDL_MINOR_VERSION). 44 | sdlMinorVersion :: Int 45 | sdlMinorVersion = #const SDL_MINOR_VERSION 46 | 47 | -- | The current micro (patchlevel) version of SDL headers (SDL_MICRO_VERSION). 48 | sdlMicroVersion :: Int 49 | sdlMicroVersion = #const SDL_MICRO_VERSION 50 | 51 | -- | Turns the version numbers into a numeric value (SDL_VERSIONNUM). 52 | -- For example, (1, 2, 3) becomes 1002003. 53 | sdlVersionNum :: Int -> Int -> Int -> Int 54 | sdlVersionNum major minor patch = major * 1000000 + minor * 1000 + patch 55 | 56 | -- | The version number for the current SDL version (SDL_VERSION). 57 | sdlVersion :: Int 58 | sdlVersion = sdlVersionNum sdlMajorVersion sdlMinorVersion sdlMicroVersion 59 | 60 | -- | Evaluates to True if compiled with SDL at least X.Y.Z (SDL_VERSION_ATLEAST). 61 | sdlVersionAtLeast :: Int -> Int -> Int -> Bool 62 | sdlVersionAtLeast x y z = sdlVersion >= sdlVersionNum x y z 63 | 64 | -- | Get the version of SDL that is linked against your program. 65 | -- 66 | -- This function returns the version as a single integer (e.g., 3003000 for 3.3.0). 67 | -- It corresponds to SDL_GetVersion in the C API. 68 | -- 69 | -- Since this function is available since SDL 3.2.0. 70 | foreign import ccall "SDL_GetVersion" 71 | sdlGetVersion :: IO CInt 72 | 73 | -- | Get the code revision of SDL that is linked against your program. 74 | -- 75 | -- Returns an arbitrary string uniquely identifying the exact revision of the SDL library in use. 76 | -- Corresponds to SDL_GetRevision in the C API. 77 | -- 78 | -- Since this function is available since SDL 3.2.0. 79 | foreign import ccall "SDL_GetRevision" 80 | sdlGetRevisionRaw :: IO CString 81 | 82 | -- | Haskell wrapper for SDL_GetRevision to return a String. 83 | sdlGetRevision :: IO String 84 | sdlGetRevision = sdlGetRevisionRaw >>= peekCString 85 | --------------------------------------------------------------------------------